From 14100d55dc822a7eb4f3e499aa9077e7ad17b2a6 Mon Sep 17 00:00:00 2001 From: Mikhailo Seledtsov Date: Mon, 27 Sep 2021 18:06:21 +0000 Subject: [PATCH 001/385] 8274170: Add hooks for custom makefiles to augment jtreg test execution Reviewed-by: erikj --- make/RunTests.gmk | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/make/RunTests.gmk b/make/RunTests.gmk index f1da577de6a..a2c8ea8101e 100644 --- a/make/RunTests.gmk +++ b/make/RunTests.gmk @@ -200,9 +200,10 @@ $(eval $(call SetTestOpt,FAILURE_HANDLER_TIMEOUT,JTREG)) $(eval $(call ParseKeywordVariable, JTREG, \ SINGLE_KEYWORDS := JOBS TIMEOUT_FACTOR FAILURE_HANDLER_TIMEOUT \ TEST_MODE ASSERT VERBOSE RETAIN MAX_MEM RUN_PROBLEM_LISTS \ - RETRY_COUNT MAX_OUTPUT, \ + RETRY_COUNT MAX_OUTPUT $(CUSTOM_JTREG_SINGLE_KEYWORDS), \ STRING_KEYWORDS := OPTIONS JAVA_OPTIONS VM_OPTIONS KEYWORDS \ - EXTRA_PROBLEM_LISTS LAUNCHER_OPTIONS, \ + EXTRA_PROBLEM_LISTS LAUNCHER_OPTIONS \ + $(CUSTOM_JTREG_STRING_KEYWORDS), \ )) ifneq ($(JTREG), ) @@ -832,6 +833,8 @@ define SetupRunJtregTestBody endif endif + $$(eval $$(call SetupRunJtregTestCustom, $1)) + clean-workdir-$1: $$(RM) -r $$($1_TEST_SUPPORT_DIR) -- GitLab From 75404ea25ed5ed77fda41afc6662b1fe7ea2fb43 Mon Sep 17 00:00:00 2001 From: Mikael Vidstedt Date: Mon, 27 Sep 2021 18:07:26 +0000 Subject: [PATCH 002/385] 8267636: Bump minimum boot jdk to JDK 17 Reviewed-by: darcy, erikj, iris --- make/conf/jib-profiles.js | 15 +++------------ make/conf/test-dependencies | 20 ++++++++++---------- make/conf/version-numbers.conf | 2 +- 3 files changed, 14 insertions(+), 23 deletions(-) diff --git a/make/conf/jib-profiles.js b/make/conf/jib-profiles.js index 7ae3fb6012f..34fcf3bf35e 100644 --- a/make/conf/jib-profiles.js +++ b/make/conf/jib-profiles.js @@ -394,13 +394,8 @@ var getJibProfilesCommon = function (input, data) { }; }; - if (input.build_os == 'macosx' && input.build_cpu == 'aarch64') { - common.boot_jdk_version = "17"; - common.boot_jdk_build_number = "24"; - } else { - common.boot_jdk_version = "16"; - common.boot_jdk_build_number = "36"; - } + common.boot_jdk_version = "17"; + common.boot_jdk_build_number = "35"; common.boot_jdk_home = input.get("boot_jdk", "install_path") + "/jdk-" + common.boot_jdk_version + (input.build_os == "macosx" ? ".jdk/Contents/Home" : ""); @@ -1073,11 +1068,7 @@ var getJibProfilesDependencies = function (input, common) { } var boot_jdk_os = input.build_os; if (input.build_os == "macosx") { - if (input.build_cpu == "aarch64") { - boot_jdk_os = "macos"; - } else { - boot_jdk_os = "osx"; - } + boot_jdk_os = "macos"; } var boot_jdk_platform = boot_jdk_os + "-" + input.build_cpu; var boot_jdk_ext = (input.build_os == "windows" ? ".zip" : ".tar.gz") diff --git a/make/conf/test-dependencies b/make/conf/test-dependencies index 4619ab74447..56c21a97eeb 100644 --- a/make/conf/test-dependencies +++ b/make/conf/test-dependencies @@ -25,19 +25,19 @@ # Versions and download locations for dependencies used by pre-submit testing. -BOOT_JDK_VERSION=16 +BOOT_JDK_VERSION=17 JTREG_VERSION=6 JTREG_BUILD=1 GTEST_VERSION=1.8.1 -LINUX_X64_BOOT_JDK_FILENAME=openjdk-16_linux-x64_bin.tar.gz -LINUX_X64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk16/7863447f0ab643c585b9bdebf67c69db/36/GPL/openjdk-16_linux-x64_bin.tar.gz -LINUX_X64_BOOT_JDK_SHA256=e952958f16797ad7dc7cd8b724edd69ec7e0e0434537d80d6b5165193e33b931 +LINUX_X64_BOOT_JDK_FILENAME=openjdk-17_linux-x64_bin.tar.gz +LINUX_X64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk17/0d483333a00540d886896bac774ff48b/35/GPL/openjdk-17_linux-x64_bin.tar.gz +LINUX_X64_BOOT_JDK_SHA256=aef49cc7aa606de2044302e757fa94c8e144818e93487081c4fd319ca858134b -WINDOWS_X64_BOOT_JDK_FILENAME=openjdk-16_windows-x64_bin.zip -WINDOWS_X64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk16/7863447f0ab643c585b9bdebf67c69db/36/GPL/openjdk-16_windows-x64_bin.zip -WINDOWS_X64_BOOT_JDK_SHA256=a78bdeaad186297601edac6772d931224d7af6f682a43372e693c37020bd37d6 +WINDOWS_X64_BOOT_JDK_FILENAME=openjdk-17_windows-x64_bin.zip +WINDOWS_X64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk17/0d483333a00540d886896bac774ff48b/35/GPL/openjdk-17_windows-x64_bin.zip +WINDOWS_X64_BOOT_JDK_SHA256=e88b0df00021c9d266bb435c9a95fdc67d1948cce4518daf85c234907bd393c5 -MACOS_X64_BOOT_JDK_FILENAME=openjdk-16_osx-x64_bin.tar.gz -MACOS_X64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk16/7863447f0ab643c585b9bdebf67c69db/36/GPL/openjdk-16_osx-x64_bin.tar.gz -MACOS_X64_BOOT_JDK_SHA256=16f3e39a31e86f3f51b0b4035a37494a47ed3c4ead760eafc6afd7afdf2ad9f2 +MACOS_X64_BOOT_JDK_FILENAME=openjdk-17_macos-x64_bin.tar.gz +MACOS_X64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk17/0d483333a00540d886896bac774ff48b/35/GPL/openjdk-17_macos-x64_bin.tar.gz +MACOS_X64_BOOT_JDK_SHA256=18e11cf9bbc6f584031e801b11ae05a233c32086f8e1b84eb8a1e9bb8e1f5d90 diff --git a/make/conf/version-numbers.conf b/make/conf/version-numbers.conf index 1a548431182..2d12d668a71 100644 --- a/make/conf/version-numbers.conf +++ b/make/conf/version-numbers.conf @@ -37,6 +37,6 @@ DEFAULT_VERSION_DATE=2022-03-15 DEFAULT_VERSION_CLASSFILE_MAJOR=62 # "`$EXPR $DEFAULT_VERSION_FEATURE + 44`" DEFAULT_VERSION_CLASSFILE_MINOR=0 DEFAULT_VERSION_DOCS_API_SINCE=11 -DEFAULT_ACCEPTABLE_BOOT_VERSIONS="16 17 18" +DEFAULT_ACCEPTABLE_BOOT_VERSIONS="17 18" DEFAULT_JDK_SOURCE_TARGET_VERSION=18 DEFAULT_PROMOTED_VERSION_PRE=ea -- GitLab From 0865120e95f31f3c84282613860e9198a7d3003c Mon Sep 17 00:00:00 2001 From: bobpengxie Date: Mon, 27 Sep 2021 18:16:51 +0000 Subject: [PATCH 003/385] 8274345: make build-test-lib is broken Reviewed-by: erikj --- make/test/BuildTestLib.gmk | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/make/test/BuildTestLib.gmk b/make/test/BuildTestLib.gmk index dff446eed3b..f677d255dda 100644 --- a/make/test/BuildTestLib.gmk +++ b/make/test/BuildTestLib.gmk @@ -36,9 +36,10 @@ TEST_LIB_SUPPORT := $(SUPPORT_OUTPUTDIR)/test/lib $(eval $(call SetupJavaCompilation, BUILD_WB_JAR, \ TARGET_RELEASE := $(TARGET_RELEASE_NEWJDK_UPGRADED), \ - SRC := $(TEST_LIB_SOURCE_DIR)/sun, \ + SRC := $(TEST_LIB_SOURCE_DIR)/sun $(TEST_LIB_SOURCE_DIR)/jdk/test/whitebox/parser, \ BIN := $(TEST_LIB_SUPPORT)/wb_classes, \ JAR := $(TEST_LIB_SUPPORT)/wb.jar, \ + DISABLED_WARNINGS := deprecation removal, \ )) TARGETS += $(BUILD_WB_JAR) @@ -50,7 +51,7 @@ $(eval $(call SetupJavaCompilation, BUILD_TEST_LIB_JAR, \ BIN := $(TEST_LIB_SUPPORT)/test-lib_classes, \ HEADERS := $(TEST_LIB_SUPPORT)/test-lib_headers, \ JAR := $(TEST_LIB_SUPPORT)/test-lib.jar, \ - DISABLED_WARNINGS := try deprecation rawtypes unchecked serial cast, \ + DISABLED_WARNINGS := try deprecation rawtypes unchecked serial cast removal, \ )) TARGETS += $(BUILD_TEST_LIB_JAR) -- GitLab From 5b660f3347917201902d501f371530a97c768977 Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Mon, 27 Sep 2021 19:57:26 +0000 Subject: [PATCH 004/385] 8274392: Suppress more warnings on non-serializable non-transient instance fields in java.sql.rowset Reviewed-by: bpb, lancea --- .../share/classes/com/sun/rowset/CachedRowSetImpl.java | 4 ++++ .../share/classes/com/sun/rowset/FilteredRowSetImpl.java | 3 ++- .../share/classes/com/sun/rowset/JdbcRowSetImpl.java | 6 +++++- .../share/classes/com/sun/rowset/JoinRowSetImpl.java | 1 + .../share/classes/com/sun/rowset/WebRowSetImpl.java | 3 ++- .../classes/com/sun/rowset/internal/CachedRowSetWriter.java | 3 ++- .../classes/com/sun/rowset/internal/SyncResolverImpl.java | 3 ++- 7 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/java.sql.rowset/share/classes/com/sun/rowset/CachedRowSetImpl.java b/src/java.sql.rowset/share/classes/com/sun/rowset/CachedRowSetImpl.java index 24e464262ab..f9d6a0e64eb 100644 --- a/src/java.sql.rowset/share/classes/com/sun/rowset/CachedRowSetImpl.java +++ b/src/java.sql.rowset/share/classes/com/sun/rowset/CachedRowSetImpl.java @@ -60,6 +60,7 @@ public class CachedRowSetImpl extends BaseRowSet implements RowSet, RowSetIntern /** * The SyncProvider used by the CachedRowSet */ + @SuppressWarnings("serial") private SyncProvider provider; /** @@ -68,6 +69,7 @@ public class CachedRowSetImpl extends BaseRowSet implements RowSet, RowSetIntern * reader as part of its implementation. * @serial */ + @SuppressWarnings("serial") private RowSetReader rowSetReader; /** @@ -76,6 +78,7 @@ public class CachedRowSetImpl extends BaseRowSet implements RowSet, RowSetIntern * this writer as part of its implementation. * @serial */ + @SuppressWarnings("serial") private RowSetWriter rowSetWriter; /** @@ -315,6 +318,7 @@ public class CachedRowSetImpl extends BaseRowSet implements RowSet, RowSetIntern /** * The field object for a transactional RowSet writer */ + @SuppressWarnings("serial") private TransactionalWriter tWriter = null; protected transient JdbcRowSetResourceBundle resBundle; diff --git a/src/java.sql.rowset/share/classes/com/sun/rowset/FilteredRowSetImpl.java b/src/java.sql.rowset/share/classes/com/sun/rowset/FilteredRowSetImpl.java index 32ef3cf4081..087a90840e2 100644 --- a/src/java.sql.rowset/share/classes/com/sun/rowset/FilteredRowSetImpl.java +++ b/src/java.sql.rowset/share/classes/com/sun/rowset/FilteredRowSetImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,6 +47,7 @@ import com.sun.rowset.internal.*; public class FilteredRowSetImpl extends WebRowSetImpl implements Serializable, Cloneable, FilteredRowSet { + @SuppressWarnings("serial") private Predicate p; private boolean onInsertRow = false; diff --git a/src/java.sql.rowset/share/classes/com/sun/rowset/JdbcRowSetImpl.java b/src/java.sql.rowset/share/classes/com/sun/rowset/JdbcRowSetImpl.java index fa2b9063164..3d52e970f38 100644 --- a/src/java.sql.rowset/share/classes/com/sun/rowset/JdbcRowSetImpl.java +++ b/src/java.sql.rowset/share/classes/com/sun/rowset/JdbcRowSetImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,6 +48,7 @@ public class JdbcRowSetImpl extends BaseRowSet implements JdbcRowSet, Joinable { * current connection to the database. This field is set * internally when the connection is established. */ + @SuppressWarnings("serial") private Connection conn; /** @@ -56,6 +57,7 @@ public class JdbcRowSetImpl extends BaseRowSet implements JdbcRowSet, Joinable { * {@code execute} creates the {@code PreparedStatement} * object. */ + @SuppressWarnings("serial") private PreparedStatement ps; /** @@ -64,6 +66,7 @@ public class JdbcRowSetImpl extends BaseRowSet implements JdbcRowSet, Joinable { * {@code execute} executes the rowset's command and thereby * creates the rowset's {@code ResultSet} object. */ + @SuppressWarnings("serial") private ResultSet rs; /** @@ -80,6 +83,7 @@ public class JdbcRowSetImpl extends BaseRowSet implements JdbcRowSet, Joinable { * {@code RowSetMetaDataImpl} is formed and which helps in getting * the metadata information. */ + @SuppressWarnings("serial") private ResultSetMetaData resMD; diff --git a/src/java.sql.rowset/share/classes/com/sun/rowset/JoinRowSetImpl.java b/src/java.sql.rowset/share/classes/com/sun/rowset/JoinRowSetImpl.java index f89ffb10099..1be3f0697b4 100644 --- a/src/java.sql.rowset/share/classes/com/sun/rowset/JoinRowSetImpl.java +++ b/src/java.sql.rowset/share/classes/com/sun/rowset/JoinRowSetImpl.java @@ -108,6 +108,7 @@ public class JoinRowSetImpl extends WebRowSetImpl implements JoinRowSet { * object to leverage the properties and methods of a WebRowSet * object. */ + @SuppressWarnings("serial") private WebRowSet wrs; diff --git a/src/java.sql.rowset/share/classes/com/sun/rowset/WebRowSetImpl.java b/src/java.sql.rowset/share/classes/com/sun/rowset/WebRowSetImpl.java index 78e723352c4..a72ed6cdf43 100644 --- a/src/java.sql.rowset/share/classes/com/sun/rowset/WebRowSetImpl.java +++ b/src/java.sql.rowset/share/classes/com/sun/rowset/WebRowSetImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. * 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,7 @@ public class WebRowSetImpl extends CachedRowSetImpl implements WebRowSet { */ private int curPosBfrWrite; + @SuppressWarnings("serial") private SyncProvider provider; /** diff --git a/src/java.sql.rowset/share/classes/com/sun/rowset/internal/CachedRowSetWriter.java b/src/java.sql.rowset/share/classes/com/sun/rowset/internal/CachedRowSetWriter.java index 60f6ad0ff9d..47a8bc7c7c1 100644 --- a/src/java.sql.rowset/share/classes/com/sun/rowset/internal/CachedRowSetWriter.java +++ b/src/java.sql.rowset/share/classes/com/sun/rowset/internal/CachedRowSetWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -165,6 +165,7 @@ public class CachedRowSetWriter implements TransactionalWriter, Serializable { * * @serial */ + @SuppressWarnings("serial") private ResultSetMetaData callerMd; /** diff --git a/src/java.sql.rowset/share/classes/com/sun/rowset/internal/SyncResolverImpl.java b/src/java.sql.rowset/share/classes/com/sun/rowset/internal/SyncResolverImpl.java index db88054d8c3..bde850e9964 100644 --- a/src/java.sql.rowset/share/classes/com/sun/rowset/internal/SyncResolverImpl.java +++ b/src/java.sql.rowset/share/classes/com/sun/rowset/internal/SyncResolverImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -96,6 +96,7 @@ public class SyncResolverImpl extends CachedRowSetImpl implements SyncResolver { * SyncResolver values. Synchronization takes place on a row by * row basis encapsulated as a CahedRowSet. */ + @SuppressWarnings("serial") private CachedRowSet row; private JdbcRowSetResourceBundle resBundle; -- GitLab From c4b52c7378183ab0fb987cc571c1debea450e125 Mon Sep 17 00:00:00 2001 From: Yumin Qi Date: Mon, 27 Sep 2021 21:27:00 +0000 Subject: [PATCH 005/385] 8271303: jcmd VM.cds {static, dynamic}_dump should print more info Reviewed-by: iklam, ccheung --- src/hotspot/share/classfile/vmSymbols.hpp | 2 +- src/hotspot/share/services/diagnosticCommand.cpp | 12 +++++++++--- .../share/classes/jdk/internal/misc/CDS.java | 7 +++++-- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/hotspot/share/classfile/vmSymbols.hpp b/src/hotspot/share/classfile/vmSymbols.hpp index f8dbdc70f11..618b97472dc 100644 --- a/src/hotspot/share/classfile/vmSymbols.hpp +++ b/src/hotspot/share/classfile/vmSymbols.hpp @@ -697,7 +697,7 @@ \ /* CDS */ \ template(dumpSharedArchive, "dumpSharedArchive") \ - template(dumpSharedArchive_signature, "(ZLjava/lang/String;)V") \ + template(dumpSharedArchive_signature, "(ZLjava/lang/String;)Ljava/lang/String;") \ template(generateLambdaFormHolderClasses, "generateLambdaFormHolderClasses") \ template(generateLambdaFormHolderClasses_signature, "([Ljava/lang/String;)[Ljava/lang/Object;") \ template(java_lang_invoke_Invokers_Holder, "java/lang/invoke/Invokers$Holder") \ diff --git a/src/hotspot/share/services/diagnosticCommand.cpp b/src/hotspot/share/services/diagnosticCommand.cpp index 57b55091be5..1b3710cf004 100644 --- a/src/hotspot/share/services/diagnosticCommand.cpp +++ b/src/hotspot/share/services/diagnosticCommand.cpp @@ -964,10 +964,10 @@ void DumpSharedArchiveDCmd::execute(DCmdSource source, TRAPS) { if (strcmp(scmd, "static_dump") == 0) { is_static = JNI_TRUE; - output()->print_cr("Static dump:"); + output()->print("Static dump: "); } else if (strcmp(scmd, "dynamic_dump") == 0) { is_static = JNI_FALSE; - output()->print_cr("Dynamic dump:"); + output()->print("Dynamic dump: "); if (!UseSharedSpaces) { output()->print_cr("Dynamic dump is unsupported when base CDS archive is not loaded"); return; @@ -988,7 +988,7 @@ void DumpSharedArchiveDCmd::execute(DCmdSource source, TRAPS) { } Symbol* cds_name = vmSymbols::jdk_internal_misc_CDS(); Klass* cds_klass = SystemDictionary::resolve_or_fail(cds_name, true /*throw error*/, CHECK); - JavaValue result(T_VOID); + JavaValue result(T_OBJECT); JavaCallArguments args; args.push_int(is_static); args.push_oop(fileh); @@ -997,6 +997,12 @@ void DumpSharedArchiveDCmd::execute(DCmdSource source, TRAPS) { vmSymbols::dumpSharedArchive(), vmSymbols::dumpSharedArchive_signature(), &args, CHECK); + if (!HAS_PENDING_EXCEPTION) { + assert(result.get_type() == T_OBJECT, "Sanity check"); + // result contains the archive name + char* archive_name = java_lang_String::as_utf8_string(result.get_oop()); + output()->print_cr("%s", archive_name); + } } #endif // INCLUDE_CDS diff --git a/src/java.base/share/classes/jdk/internal/misc/CDS.java b/src/java.base/share/classes/jdk/internal/misc/CDS.java index d3f6e4f3dd3..43f6128cc05 100644 --- a/src/java.base/share/classes/jdk/internal/misc/CDS.java +++ b/src/java.base/share/classes/jdk/internal/misc/CDS.java @@ -254,8 +254,9 @@ public class CDS { * called from jcmd VM.cds to dump static or dynamic shared archive * @param isStatic true for dump static archive or false for dynnamic archive. * @param fileName user input archive name, can be null. + * @return The archive name if successfully dumped. */ - private static void dumpSharedArchive(boolean isStatic, String fileName) throws Exception { + private static String dumpSharedArchive(boolean isStatic, String fileName) throws Exception { String cwd = new File("").getAbsolutePath(); // current dir used for printing message. String currentPid = String.valueOf(ProcessHandle.current().pid()); String archiveFileName = fileName != null ? fileName : @@ -333,6 +334,8 @@ public class CDS { throw new RuntimeException("Cannot rename temp file " + tempArchiveFileName + " to archive file" + archiveFileName); } // Everyting goes well, print out the file name. - System.out.println((isStatic ? "Static" : " Dynamic") + " dump to file " + cwd + File.separator + archiveFileName); + String archiveFilePath = new File(archiveFileName).getAbsolutePath(); + System.out.println("The process was attached by jcmd and dumped a " + (isStatic ? "static" : "dynamic") + " archive " + archiveFilePath); + return archiveFilePath; } } -- GitLab From c880b87a205cc9611fe88cb29f506293dfebf946 Mon Sep 17 00:00:00 2001 From: Pavel Rappo Date: Mon, 27 Sep 2021 22:32:49 +0000 Subject: [PATCH 006/385] 8274367: Re-indent stack-trace examples for Throwable.printStackTrace Reviewed-by: mchung, iris, darcy, bpb --- .../share/classes/java/lang/Throwable.java | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/src/java.base/share/classes/java/lang/Throwable.java b/src/java.base/share/classes/java/lang/Throwable.java index 26c584bc865..22ad94e0b4e 100644 --- a/src/java.base/share/classes/java/lang/Throwable.java +++ b/src/java.base/share/classes/java/lang/Throwable.java @@ -608,12 +608,12 @@ public class Throwable implements Serializable { * *
      * Exception in thread "main" java.lang.Exception: Something happened
-     *  at Foo.bar(Foo.java:10)
-     *  at Foo.main(Foo.java:5)
-     *  Suppressed: Resource$CloseFailException: Resource ID = 0
-     *          at Resource.close(Resource.java:26)
-     *          at Foo.bar(Foo.java:9)
-     *          ... 1 more
+     *         at Foo.bar(Foo.java:10)
+     *         at Foo.main(Foo.java:5)
+     *         Suppressed: Resource$CloseFailException: Resource ID = 0
+     *                 at Resource.close(Resource.java:26)
+     *                 at Foo.bar(Foo.java:9)
+     *                 ... 1 more
      * 
* Note that the "... n more" notation is used on suppressed exceptions * just as it is used on causes. Unlike causes, suppressed exceptions are @@ -623,26 +623,26 @@ public class Throwable implements Serializable { * exceptions: *
      * Exception in thread "main" java.lang.Exception: Main block
-     *  at Foo3.main(Foo3.java:7)
-     *  Suppressed: Resource$CloseFailException: Resource ID = 2
-     *          at Resource.close(Resource.java:26)
-     *          at Foo3.main(Foo3.java:5)
-     *  Suppressed: Resource$CloseFailException: Resource ID = 1
-     *          at Resource.close(Resource.java:26)
-     *          at Foo3.main(Foo3.java:5)
+     *         at Foo3.main(Foo3.java:7)
+     *         Suppressed: Resource$CloseFailException: Resource ID = 2
+     *                 at Resource.close(Resource.java:26)
+     *                 at Foo3.main(Foo3.java:5)
+     *         Suppressed: Resource$CloseFailException: Resource ID = 1
+     *                 at Resource.close(Resource.java:26)
+     *                 at Foo3.main(Foo3.java:5)
      * Caused by: java.lang.Exception: I did it
-     *  at Foo3.main(Foo3.java:8)
+     *         at Foo3.main(Foo3.java:8)
      * 
* Likewise, a suppressed exception can have a cause: *
      * Exception in thread "main" java.lang.Exception: Main block
-     *  at Foo4.main(Foo4.java:6)
-     *  Suppressed: Resource2$CloseFailException: Resource ID = 1
-     *          at Resource2.close(Resource2.java:20)
-     *          at Foo4.main(Foo4.java:5)
-     *  Caused by: java.lang.Exception: Rats, you caught me
-     *          at Resource2$CloseFailException.<init>(Resource2.java:45)
-     *          ... 2 more
+     *         at Foo4.main(Foo4.java:6)
+     *         Suppressed: Resource2$CloseFailException: Resource ID = 1
+     *                 at Resource2.close(Resource2.java:20)
+     *                 at Foo4.main(Foo4.java:5)
+     *         Caused by: java.lang.Exception: Rats, you caught me
+     *                 at Resource2$CloseFailException.<init>(Resource2.java:45)
+     *                 ... 2 more
      * 
*/ public void printStackTrace() { -- GitLab From 8876eae42993d4425ba9886dde94b08f6101a257 Mon Sep 17 00:00:00 2001 From: Lin Zang Date: Tue, 28 Sep 2021 02:59:14 +0000 Subject: [PATCH 007/385] 8269685: Optimize HeapHprofBinWriter implementation 8262386: resourcehogs/serviceability/sa/TestHeapDumpForLargeArray.java timed out Reviewed-by: sspitsyn, amenkov --- .../utilities/AbstractHeapGraphWriter.java | 7 +- .../jvm/hotspot/utilities/HeapGXLWriter.java | 5 + .../hotspot/utilities/HeapHprofBinWriter.java | 514 ++++++------------ 3 files changed, 182 insertions(+), 344 deletions(-) diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/AbstractHeapGraphWriter.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/AbstractHeapGraphWriter.java index 608bb336858..4e54f17d27e 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/AbstractHeapGraphWriter.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/AbstractHeapGraphWriter.java @@ -59,7 +59,7 @@ public abstract class AbstractHeapGraphWriter implements HeapGraphWriter { public boolean doObj(Oop oop) { try { - writeHeapRecordPrologue(); + writeHeapRecordPrologue(calculateOopDumpRecordSize(oop)); if (oop instanceof TypeArray) { writePrimitiveArray((TypeArray)oop); } else if (oop instanceof ObjArray) { @@ -127,6 +127,8 @@ public abstract class AbstractHeapGraphWriter implements HeapGraphWriter { } } + abstract protected int calculateOopDumpRecordSize(Oop oop) throws IOException; + protected void writeJavaThreads() throws IOException { Threads threads = VM.getVM().getThreads(); for (int i = 0; i < threads.getNumberOfThreads(); i++) { @@ -420,6 +422,9 @@ public abstract class AbstractHeapGraphWriter implements HeapGraphWriter { protected void writeHeapRecordPrologue() throws IOException { } + protected void writeHeapRecordPrologue(int size) throws IOException { + } + protected void writeHeapRecordEpilogue() throws IOException { } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapGXLWriter.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapGXLWriter.java index a85634ea382..9a4d0cf5274 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapGXLWriter.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapGXLWriter.java @@ -275,6 +275,11 @@ public class HeapGXLWriter extends AbstractHeapGraphWriter { out.println(""); } + @Override + protected int calculateOopDumpRecordSize(Oop oop) throws IOException { + return 0; + } + //-- Internals only below this point // Java identifier to XML NMTOKEN type string diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java index 26f515d1145..ce69cc5049c 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java @@ -409,19 +409,15 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter { // open file stream and create buffered data output stream fos = new FileOutputStream(fileName); - hprofBufferedOut = null; - OutputStream dataOut = fos; + hprofBufferedOut = fos; if (useSegmentedHeapDump) { if (isCompression()) { - dataOut = new GZIPOutputStream(fos) { + hprofBufferedOut = new GZIPOutputStream(fos) { { this.def.setLevel(gzLevel); } }; } - hprofBufferedOut = new SegmentedOutputStream(dataOut); - } else { - hprofBufferedOut = new SegmentedOutputStream(fos, false /* allowSegmented */); } out = new DataOutputStream(hprofBufferedOut); dbg = vm.getDebugger(); @@ -472,47 +468,157 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter { // flush buffer stream. out.flush(); - if (!useSegmentedHeapDump) { - // Fill in final length. fillInHeapRecordLength(); } else { - hprofBufferedOut.finish(); // Write heap segment-end record out.writeByte((byte) HPROF_HEAP_DUMP_END); out.writeInt(0); out.writeInt(0); } - // flush buffer stream and throw it. out.flush(); out.close(); out = null; hprofBufferedOut = null; + currentSegmentStart = 0; } - @Override - protected void writeHeapRecordPrologue() throws IOException { - if (useSegmentedHeapDump) { - hprofBufferedOut.enterSegmentMode(); - } else if (currentSegmentStart == 0) { - // write heap data header - out.writeByte((byte) (HPROF_HEAP_DUMP)); - out.writeInt(0); + protected int calculateOopDumpRecordSize(Oop oop) throws IOException { + if (oop instanceof TypeArray taOop) { + return calculatePrimitiveArrayDumpRecordSize(taOop); + } else if (oop instanceof ObjArray oaOop) { + Klass klass = oop.getKlass(); + ObjArrayKlass oak = (ObjArrayKlass) klass; + Klass bottomType = oak.getBottomKlass(); + if (bottomType instanceof InstanceKlass || + bottomType instanceof TypeArrayKlass) { + return calculateObjectArrayDumpRecordSize(oaOop); + } else { + // Internal object, nothing to write. + return 0; + } + } else if (oop instanceof Instance instance) { + Klass klass = instance.getKlass(); + Symbol name = klass.getName(); + if (name.equals(javaLangClass)) { + return calculateClassInstanceDumpRecordSize(instance); + } + return calculateInstanceDumpRecordSize(instance); + } else { + // not-a-Java-visible oop + return 0; + } + } - // remember position of dump length, we will fixup - // length later - hprof format requires length. - out.flush(); - currentSegmentStart = fos.getChannel().position(); - // write dummy length of 0 and we'll fix it later. - out.writeInt(0); + private int calculateInstanceDumpRecordSize(Instance instance) { + Klass klass = instance.getKlass(); + if (klass.getClassLoaderData() == null) { + // Ignoring this object since the corresponding Klass is not loaded. + // Might be a dormant archive object. + return 0; + } + + ClassData cd = (ClassData) classDataCache.get(klass); + if (Assert.ASSERTS_ENABLED) { + Assert.that(cd != null, "can not get class data for " + klass.getName().asString() + klass.getAddress()); + } + List fields = cd.fields; + return (int) BYTE_SIZE + (int)OBJ_ID_SIZE * 2 + (int)INT_SIZE * 2 + getSizeForFields(fields); + } + + private int calculateClassDumpRecordSize(Klass k) { + // tag + javaMirror + DUMMY_STACK_TRACE_ID + super + int size = (int)BYTE_SIZE + (int)INT_SIZE + (int)OBJ_ID_SIZE * 2; + if (k instanceof InstanceKlass ik) { + List fields = getInstanceFields(ik); + List declaredFields = ik.getImmediateFields(); + List staticFields = new ArrayList<>(); + List instanceFields = new ArrayList<>(); + Iterator itr = null; + // loader + signer + protectionDomain + 2 reserved + fieldSize + cpool entris number + size += OBJ_ID_SIZE * 5 + INT_SIZE + SHORT_SIZE; + for (itr = declaredFields.iterator(); itr.hasNext();) { + Field field = itr.next(); + if (field.isStatic()) { + staticFields.add(field); + } else { + instanceFields.add(field); + } + } + // size of static field descriptors + size += calculateFieldDescriptorsDumpRecordSize(staticFields, ik); + // size of instance field descriptors + size += calculateFieldDescriptorsDumpRecordSize(instanceFields, null); + } else { + size += OBJ_ID_SIZE * 5 + INT_SIZE + SHORT_SIZE * 3; + } + return size; + } + + private int calculateFieldDescriptorsDumpRecordSize(List fields, InstanceKlass ik) { + int size = 0; + size += SHORT_SIZE; + for (Field field : fields) { + size += OBJ_ID_SIZE + BYTE_SIZE; + // ik == null for instance fields + if (ik != null) { + // static field + size += getSizeForField(field); + } } + return size; + } + + private int calculateClassInstanceDumpRecordSize(Instance instance) { + Klass reflectedKlass = java_lang_Class.asKlass(instance); + // Dump instance record only for primitive type Class objects. + // All other Class objects are covered by writeClassDumpRecords. + if (reflectedKlass == null) { + return calculateInstanceDumpRecordSize(instance); + } + return 0; + } + + private int calculateObjectArrayDumpRecordSize(ObjArray array) { + int headerSize = getArrayHeaderSize(true); + final int length = calculateArrayMaxLength(array.getLength(), + headerSize, + OBJ_ID_SIZE, + "Object"); + return headerSize + length * OBJ_ID_SIZE; + } + + private int calculatePrimitiveArrayDumpRecordSize(TypeArray array) throws IOException { + int headerSize = getArrayHeaderSize(false); + TypeArrayKlass tak = (TypeArrayKlass) array.getKlass(); + final int type = (int) tak.getElementType(); + final String typeName = tak.getElementTypeName(); + final long typeSize = getSizeForType(type); + final int length = calculateArrayMaxLength(array.getLength(), + headerSize, + typeSize, + typeName); + return headerSize + (int)typeSize * length; } @Override - protected void writeHeapRecordEpilogue() throws IOException { + protected void writeHeapRecordPrologue(int size) throws IOException { + if (size == 0 || currentSegmentStart > 0) { + return; + } + // write heap data header if (useSegmentedHeapDump) { - hprofBufferedOut.exitSegmentMode(); + out.writeByte((byte)HPROF_HEAP_DUMP_SEGMENT); + out.writeInt(0); + out.writeInt(size); + } else { + out.writeByte((byte)HPROF_HEAP_DUMP); + out.writeInt(0); + // record the current position in file, it will be use for calculating the size of written data + currentSegmentStart = fos.getChannel().position(); + // write dummy zero for length + out.writeInt(0); } } @@ -576,33 +682,19 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter { (2 * (int) BYTE_SIZE + 2 * (int) INT_SIZE + (int) OBJ_ID_SIZE); } - // Check if we need to truncate an array + // Check if we need to truncate an array. + // The limitation is that the size of "heap dump" or "heap dump segment" must be <= MAX_U4_VALUE. private int calculateArrayMaxLength(long originalArrayLength, int headerSize, long typeSize, - String typeName) throws IOException { + String typeName) { long length = originalArrayLength; + long originalLengthInBytes = originalArrayLength * typeSize; - long currentRecordLength = 0; - // There is an U4 slot that contains the data size written in the dump file. - // Need to truncate the array length if the size exceeds the MAX_U4_VALUE. - if (!useSegmentedHeapDump) { - // now get the current position to calculate length - long dumpEnd = fos.getChannel().position(); - // calculate the length of heap data - currentRecordLength = (dumpEnd - currentSegmentStart - 4L); - if (currentRecordLength > 0 && - (currentRecordLength + headerSize + originalLengthInBytes) > MAX_U4_VALUE) { - fillInHeapRecordLength(); - currentSegmentStart = 0; - writeHeapRecordPrologue(); - currentRecordLength = 0; - } - } // Calculate the max bytes we can use. - long maxBytes = (MAX_U4_VALUE - (headerSize + currentRecordLength)); + long maxBytes = MAX_U4_VALUE - headerSize; if (originalLengthInBytes > maxBytes) { length = maxBytes/typeSize; @@ -610,14 +702,6 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter { + " with length " + originalArrayLength + "; truncating to length " + length); } - - // Now the total size of data to dump is known and can be filled to segment header. - // Disable buffer mode to avoid memory consumption and internal buffer copies. - if (useSegmentedHeapDump) { - int size = (int) (length * typeSize + headerSize); - hprofBufferedOut.fillSegmentSizeAndDisableBufferMode(size); - } - return (int) length; } @@ -627,7 +711,7 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter { cldGraph.classesDo(new ClassLoaderDataGraph.ClassVisitor() { public void visit(Klass k) { try { - writeHeapRecordPrologue(); + writeHeapRecordPrologue(calculateClassDumpRecordSize(k)); writeClassDumpRecord(k); writeHeapRecordEpilogue(); } catch (IOException e) { @@ -796,6 +880,8 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter { } protected void writeJavaThread(JavaThread jt, int index) throws IOException { + int size = (int)BYTE_SIZE + (int)OBJ_ID_SIZE + (int)INT_SIZE * 2; + writeHeapRecordPrologue(size); out.writeByte((byte) HPROF_GC_ROOT_THREAD_OBJ); writeObjectID(jt.getThreadObj()); out.writeInt(index); @@ -816,6 +902,8 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter { Oop oop = objectHeap.newOop(oopHandle); // exclude JNI handles hotspot internal objects if (oop != null && isJavaVisible(oop)) { + int size = (int)BYTE_SIZE + (int)OBJ_ID_SIZE + (int)INT_SIZE * 2; + writeHeapRecordPrologue(size); out.writeByte((byte) HPROF_GC_ROOT_JNI_LOCAL); writeObjectID(oop); out.writeInt(threadIndex); @@ -842,6 +930,8 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter { Oop oop = objectHeap.newOop(oopHandle); // exclude JNI handles of hotspot internal objects if (oop != null && isJavaVisible(oop)) { + int size = (int)BYTE_SIZE + (int)OBJ_ID_SIZE * 2; + writeHeapRecordPrologue(size); out.writeByte((byte) HPROF_GC_ROOT_JNI_GLOBAL); writeObjectID(oop); // use JNIHandle address as ID @@ -1221,38 +1311,37 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter { return res; } + // get size in bytes (in stream) required for given field. + private int getSizeForField(Field field) { + char typeCode = (char)field.getSignature().getByteAt(0); + switch (typeCode) { + case JVM_SIGNATURE_BOOLEAN: + case JVM_SIGNATURE_BYTE: + return 1; + case JVM_SIGNATURE_CHAR: + case JVM_SIGNATURE_SHORT: + return 2; + case JVM_SIGNATURE_INT: + case JVM_SIGNATURE_FLOAT: + return 4; + case JVM_SIGNATURE_CLASS: + case JVM_SIGNATURE_ARRAY: + return OBJ_ID_SIZE; + case JVM_SIGNATURE_LONG: + case JVM_SIGNATURE_DOUBLE: + return 8; + default: + throw new RuntimeException("should not reach here"); + } + } + // get size in bytes (in stream) required for given fields. Note // that this is not the same as object size in heap. The size in // heap will include size of padding/alignment bytes as well. private int getSizeForFields(List fields) { int size = 0; - for (Iterator itr = fields.iterator(); itr.hasNext();) { - Field field = itr.next(); - char typeCode = (char) field.getSignature().getByteAt(0); - switch (typeCode) { - case JVM_SIGNATURE_BOOLEAN: - case JVM_SIGNATURE_BYTE: - size++; - break; - case JVM_SIGNATURE_CHAR: - case JVM_SIGNATURE_SHORT: - size += 2; - break; - case JVM_SIGNATURE_INT: - case JVM_SIGNATURE_FLOAT: - size += 4; - break; - case JVM_SIGNATURE_CLASS: - case JVM_SIGNATURE_ARRAY: - size += OBJ_ID_SIZE; - break; - case JVM_SIGNATURE_LONG: - case JVM_SIGNATURE_DOUBLE: - size += 8; - break; - default: - throw new RuntimeException("should not reach here"); - } + for (Field field : fields) { + size += getSizeForField(field); } return size; } @@ -1276,7 +1365,7 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter { private DataOutputStream out; private FileOutputStream fos; - private SegmentedOutputStream hprofBufferedOut; + private OutputStream hprofBufferedOut; private Debugger dbg; private ObjectHeap objectHeap; private ArrayList KlassMap; @@ -1319,265 +1408,4 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter { } private Map classDataCache = new HashMap<>(); - - /** - * The class implements a buffered output stream for segmented data dump. - * It is used inside HeapHprofBinWritter only for heap dump. - * Because the current implementation of segmented heap dump needs to update - * the segment size at segment header, and because it is hard to modify the - * compressed data after they are written to file, this class first saves the - * uncompressed data into an internal buffer, and then writes through to the - * GZIPOutputStream when the whole segmented data are ready and the size is updated. - * If the data to be written are larger than internal buffer, or the internal buffer - * is full, the internal buffer will be extend to a larger one. - * This class defines a switch to turn on/off the segmented mode. If turned off, - * it behaves the same as BufferedOutputStream. - * */ - private class SegmentedOutputStream extends BufferedOutputStream { - /** - * Creates a new buffered output stream to support segmented heap dump data. - * - * @param out the underlying output stream. - * @param allowSegmented whether allow segmental dump. - */ - public SegmentedOutputStream(OutputStream out, boolean allowSegmented) { - super(out, 8192); - segmentMode = false; - bufferMode = true; - this.allowSegmented = allowSegmented; - segmentBuffer = new byte[SEGMENT_BUFFER_SIZE]; - segmentWritten = 0; - } - - /** - * Creates a new buffered output stream to support segmented heap dump data. - * - * @param out the underlying output stream. - */ - public SegmentedOutputStream(OutputStream out) { - this(out, true); - } - - /** - * Writes the specified byte to this buffered output stream. - * - * @param b the byte to be written. - * @throws IOException if an I/O error occurs. - */ - @Override - public synchronized void write(int b) throws IOException { - if (segmentMode && bufferMode) { - if (segmentWritten == 0) { - // At the begining of the segment. - writeSegmentHeader(); - } else if (segmentWritten == segmentBuffer.length) { - // Internal buffer is full, extend a larger one. - int newSize = segmentBuffer.length + SEGMENT_BUFFER_INC_SIZE; - byte newBuf[] = new byte[newSize]; - System.arraycopy(segmentBuffer, 0, newBuf, 0, segmentWritten); - segmentBuffer = newBuf; - } - segmentBuffer[segmentWritten++] = (byte)b; - return; - } - super.write(b); - } - - /** - * Writes {@code len} bytes from the specified byte array - * starting at offset {@code off} to this output stream. - * - * @param b the data. - * @param off the start offset in the data. - * @param len the number of bytes to write. - * @throws IOException if an I/O error occurs. - */ - @Override - public synchronized void write(byte b[], int off, int len) throws IOException { - if (segmentMode && bufferMode) { - if (segmentWritten == 0) { - writeSegmentHeader(); - } - // Data size is larger than segment buffer length, extend segment buffer. - if (segmentWritten + len > segmentBuffer.length) { - int newSize = segmentBuffer.length + Math.max(SEGMENT_BUFFER_INC_SIZE, len); - byte newBuf[] = new byte[newSize]; - System.arraycopy(segmentBuffer, 0, newBuf, 0, segmentWritten); - segmentBuffer = newBuf; - } - System.arraycopy(b, off, segmentBuffer, segmentWritten, len); - segmentWritten += len; - return; - } - super.write(b, off, len); - } - - /** - * Flushes this buffered output stream. This forces any buffered - * output bytes to be written out to the underlying output stream. - * - * @throws IOException if an I/O error occurs. - * @see java.io.FilterOutputStream#out - */ - @Override - public synchronized void flush() throws IOException { - if (segmentMode && bufferMode) { - // The case that nothing has been written in segment. - if (segmentWritten == 0) return; - // There must be more data than just header size written for non-empty segment. - assert segmentWritten > SEGMENT_HEADER_SIZE - : "invalid header in segmented mode"; - - if (segmentWritten > (segmentBuffer.length)) { - throw new RuntimeException("Heap segment size overflow."); - } - - if (segmentWritten > SEGMENT_HEADER_SIZE) { - fillSegmentSize(segmentWritten - SEGMENT_HEADER_SIZE); - super.write(segmentBuffer, 0, segmentWritten); - super.flush(); - segmentWritten = 0; - } - return; - } - super.flush(); - } - - /** - * Enters segmented mode, flush buffered data and set flag. - */ - public void enterSegmentMode() throws IOException { - if (allowSegmented && !segmentMode && segmentWritten == 0) { - super.flush(); - segmentMode = true; - segmentWritten = 0; - } - } - - /** - * Before finish, flush all data in buffer. - */ - public void finish() throws IOException { - if (allowSegmented && segmentMode) { - flush(); - assert segmentWritten == 0; - segmentMode = false; - bufferMode = true; - } - } - - /** - * Exits segmented mode, flush segmented data. - * @param force flush data regardless whether the buffer is full - */ - public void exitSegmentMode() throws IOException { - if (!bufferMode) { - // no data in internal buffer. - assert segmentWritten == 0; - bufferMode = true; - } - if (allowSegmented && segmentMode && shouldFlush()) { - flush(); - assert segmentWritten == 0; - segmentMode = false; - } - } - - /** - * Fill segment size and disable bufferMode - * @param size size of data to be written - */ - public void fillSegmentSizeAndDisableBufferMode(int size) throws IOException { - assert segmentMode == true; - assert bufferMode == true; - if (segmentWritten != 0) { - // flush previous written data and clear the internal buffer. - flush(); - } - // disable buffer mode to write data through to underlying file. - bufferMode = false; - writeSegmentHeader(size); - } - - /** - * Check whether the data should be flush based on data saved in - * segmentBuffer. - * This method is used to control the segments number and the memory usage. - * If segment is too small, there will be lots segments in final dump file. - * If it is too large, lots of memory is used in RAM. - */ - private boolean shouldFlush() { - // flushes data if not in bufferMode. - if (!bufferMode) return true; - // return true if data in segmentBuffer has been extended. - return segmentWritten > SEGMENT_BUFFER_SIZE; - } - - /** - * Writes the segment header with given data size. - */ - private void writeSegmentHeader(int size) throws IOException { - assert segmentWritten == 0 : "initializing non empty segment"; - byte flag = (byte)HPROF_HEAP_DUMP_SEGMENT; - if (!bufferMode) { - super.write(flag); - } else { - segmentBuffer[segmentWritten++] = flag; - } - // write the timestamp (dummy value 0). - writeInteger(0); - // write the segment data size. - writeInteger(size); - } - - /** - * Writes the segment header with dummy length of 0. - */ - private void writeSegmentHeader() throws IOException { - writeSegmentHeader(0); - } - - /** - * Fills the segmented data size into the header. - */ - private void fillSegmentSize(int size) { - assert bufferMode == true; - byte[] lenBytes = genByteArrayFromInt(size); - System.arraycopy(lenBytes, 0, segmentBuffer, 5, 4); - } - - /** - * Writes an {@code int} to the internal segment buffer - * {@code written} is incremented by {@code 4}. - */ - private final void writeInteger(int value) throws IOException { - byte[] intBytes = genByteArrayFromInt(value); - if (bufferMode) { - System.arraycopy(intBytes, 0, segmentBuffer, segmentWritten, 4); - segmentWritten += 4; - } else { - super.write(intBytes, 0, 4); - } - } - - // The buffer size for segmentBuffer. - // Since it is hard to calculate and fill the data size of an segment in compressed - // data, making the segmented data stored in this buffer could help rewrite the data - // size before the segmented data are written to underlying GZIPOutputStream. - private static final int SEGMENT_BUFFER_SIZE = 1 << 20; - // Buffer size used to extend the segment buffer. - private static final int SEGMENT_BUFFER_INC_SIZE = 1 << 10; - // Headers: - // 1 byte for HPROF_HEAP_DUMP_SEGMENT - // 4 bytes for timestamp - // 4 bytes for size - private static final int SEGMENT_HEADER_SIZE = 9; - // Segment support. - private boolean segmentMode; - private boolean allowSegmented; - // Write data directly to underlying stream. Don't use internal buffer. - private boolean bufferMode; - private byte segmentBuffer[]; - private int segmentWritten; - } } -- GitLab From 633eab23f0c5cadac06e37b9d6eeef5696ca3d22 Mon Sep 17 00:00:00 2001 From: Jaikiran Pai Date: Tue, 28 Sep 2021 04:54:58 +0000 Subject: [PATCH 008/385] 8174819: java/nio/file/WatchService/LotsOfEvents.java fails intermittently Reviewed-by: alanb --- .../java/nio/file/WatchService/LotsOfEvents.java | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/test/jdk/java/nio/file/WatchService/LotsOfEvents.java b/test/jdk/java/nio/file/WatchService/LotsOfEvents.java index d882adae4db..bf2b7b81274 100644 --- a/test/jdk/java/nio/file/WatchService/LotsOfEvents.java +++ b/test/jdk/java/nio/file/WatchService/LotsOfEvents.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2021, Oracle and/or its affiliates. All rights reserved. * 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,7 +22,7 @@ */ /* @test - * @bug 6907760 6929532 + * @bug 6907760 6929532 8174819 * @summary Tests WatchService behavior when lots of events are pending (use -Dseed=X to set PRNG seed) * @library .. * @library /test/lib @@ -37,6 +37,8 @@ import java.nio.file.*; import static java.nio.file.StandardWatchEventKinds.*; import java.util.*; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + import jdk.test.lib.RandomFactory; public class LotsOfEvents { @@ -106,6 +108,7 @@ public class LotsOfEvents { boolean gotOverflow = false; while (key != null) { List> events = key.pollEvents(); + System.out.println("Polling retrieved " + events.size() + " event(s)"); for (WatchEvent event: events) { WatchEvent.Kind kind = event.kind(); if (kind == expectedKind) { @@ -123,7 +126,7 @@ public class LotsOfEvents { } if (!key.reset()) throw new RuntimeException("Key is no longer valid"); - key = watcher.poll(2, TimeUnit.SECONDS); + key = watcher.poll(15, TimeUnit.SECONDS); } // check that all expected events were received or there was an overflow @@ -131,6 +134,8 @@ public class LotsOfEvents { System.err.printf("Test directory %s contains %d files%n", dir, Files.list(dir).count()); + // the additional polling here is just for diagnostics and doesn't + // change the test result (which is a failed test) long timeBeforePoll = System.nanoTime(); key = watcher.poll(15, TimeUnit.SECONDS); long timeAfterPoll = System.nanoTime(); @@ -140,6 +145,11 @@ public class LotsOfEvents { List> events = key.pollEvents(); System.err.printf("Retrieved key with %d events after %d ns%n", events.size(), timeAfterPoll - timeBeforePoll); + // count for each kind of event + Map countPerEventType = events.stream() + .collect(Collectors.groupingBy(WatchEvent::kind, Collectors.counting())); + countPerEventType.forEach((kind, num) + -> System.err.println(num + " events of type " + kind)); } throw new RuntimeException("Insufficient " -- GitLab From ddc262746aea99050b9a6484f51c7ddb8f4bc991 Mon Sep 17 00:00:00 2001 From: Jaikiran Pai Date: Tue, 28 Sep 2021 05:00:27 +0000 Subject: [PATCH 009/385] 8273790: Potential cyclic dependencies between Gregorian and CalendarSystem Reviewed-by: naoto, yyang, rriggs --- .../sun/util/calendar/CalendarSystem.java | 10 +- .../calendar/CalendarSystemDeadLockTest.java | 177 ++++++++++++++++++ 2 files changed, 183 insertions(+), 4 deletions(-) create mode 100644 test/jdk/sun/util/calendar/CalendarSystemDeadLockTest.java diff --git a/src/java.base/share/classes/sun/util/calendar/CalendarSystem.java b/src/java.base/share/classes/sun/util/calendar/CalendarSystem.java index 71c7212c644..91a689f5f03 100644 --- a/src/java.base/share/classes/sun/util/calendar/CalendarSystem.java +++ b/src/java.base/share/classes/sun/util/calendar/CalendarSystem.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -111,7 +111,9 @@ public abstract class CalendarSystem { } } - private static final Gregorian GREGORIAN_INSTANCE = new Gregorian(); + private static final class GregorianHolder { + private static final Gregorian GREGORIAN_INSTANCE = new Gregorian(); + } /** * Returns the singleton instance of the Gregorian @@ -120,7 +122,7 @@ public abstract class CalendarSystem { * @return the Gregorian instance */ public static Gregorian getGregorianCalendar() { - return GREGORIAN_INSTANCE; + return GregorianHolder.GREGORIAN_INSTANCE; } /** @@ -135,7 +137,7 @@ public abstract class CalendarSystem { */ public static CalendarSystem forName(String calendarName) { if ("gregorian".equals(calendarName)) { - return GREGORIAN_INSTANCE; + return GregorianHolder.GREGORIAN_INSTANCE; } if (!initialized) { diff --git a/test/jdk/sun/util/calendar/CalendarSystemDeadLockTest.java b/test/jdk/sun/util/calendar/CalendarSystemDeadLockTest.java new file mode 100644 index 00000000000..c40f78f7ade --- /dev/null +++ b/test/jdk/sun/util/calendar/CalendarSystemDeadLockTest.java @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +/** + * @test + * @bug 8273790 + * @summary Verify that concurrent classloading of sun.util.calendar.Gregorian and + * sun.util.calendar.CalendarSystem doesn't lead to a deadlock + * @modules java.base/sun.util.calendar:open + * @run main/othervm CalendarSystemDeadLockTest + * @run main/othervm CalendarSystemDeadLockTest + * @run main/othervm CalendarSystemDeadLockTest + * @run main/othervm CalendarSystemDeadLockTest + * @run main/othervm CalendarSystemDeadLockTest + */ +public class CalendarSystemDeadLockTest { + + public static void main(final String[] args) throws Exception { + testConcurrentClassLoad(); + } + + /** + * Loads {@code sun.util.calendar.Gregorian} and {@code sun.util.calendar.CalendarSystem} + * and invokes {@code sun.util.calendar.CalendarSystem#getGregorianCalendar()} concurrently + * in a thread of their own and expects the classloading of both those classes + * to succeed. Additionally, after these tasks are done, calls the + * sun.util.calendar.CalendarSystem#getGregorianCalendar() and expects it to return a singleton + * instance + */ + private static void testConcurrentClassLoad() throws Exception { + final int numTasks = 7; + final CountDownLatch taskTriggerLatch = new CountDownLatch(numTasks); + final List> tasks = new ArrayList<>(); + // add the sun.util.calendar.Gregorian and sun.util.calendar.CalendarSystem for classloading. + // there are main 2 classes which had a cyclic call in their static init + tasks.add(new ClassLoadTask("sun.util.calendar.Gregorian", taskTriggerLatch)); + tasks.add(new ClassLoadTask("sun.util.calendar.CalendarSystem", taskTriggerLatch)); + // add a few other classes for classloading, those which call CalendarSystem#getGregorianCalendar() + // or CalendarSystem#forName() during their static init + tasks.add(new ClassLoadTask("java.util.GregorianCalendar", taskTriggerLatch)); + tasks.add(new ClassLoadTask("java.util.Date", taskTriggerLatch)); + tasks.add(new ClassLoadTask("java.util.JapaneseImperialCalendar", taskTriggerLatch)); + // add a couple of tasks which directly invoke sun.util.calendar.CalendarSystem#getGregorianCalendar() + tasks.add(new GetGregorianCalTask(taskTriggerLatch)); + tasks.add(new GetGregorianCalTask(taskTriggerLatch)); + // before triggering the tests make sure we have created the correct number of tasks + // the countdown latch uses/expects + if (numTasks != tasks.size()) { + throw new RuntimeException("Test setup failure - unexpected number of tasks " + tasks.size() + + ", expected " + numTasks); + } + final ExecutorService executor = Executors.newFixedThreadPool(tasks.size()); + try { + final Future[] results = new Future[tasks.size()]; + // submit + int i = 0; + for (final Callable task : tasks) { + results[i++] = executor.submit(task); + } + // wait for completion + for (i = 0; i < tasks.size(); i++) { + results[i].get(); + } + } finally { + executor.shutdownNow(); + } + // check that the sun.util.calendar.CalendarSystem#getGregorianCalendar() does indeed return + // a proper instance + final Object gCal = callCalSystemGetGregorianCal(); + if (gCal == null) { + throw new RuntimeException("sun.util.calendar.CalendarSystem#getGregorianCalendar()" + + " unexpectedly returned null"); + } + // now verify that each call to getGregorianCalendar(), either in the tasks or here, returned the exact + // same instance + if (GetGregorianCalTask.instances.size() != 2) { + throw new RuntimeException("Unexpected number of results from call " + + "to sun.util.calendar.CalendarSystem#getGregorianCalendar()"); + } + // intentional identity check since sun.util.calendar.CalendarSystem#getGregorianCalendar() is + // expected to return a singleton instance + if ((gCal != GetGregorianCalTask.instances.get(0)) || (gCal != GetGregorianCalTask.instances.get(1))) { + throw new RuntimeException("sun.util.calendar.CalendarSystem#getGregorianCalendar()" + + " returned different instances"); + } + } + + /** + * Reflectively calls sun.util.calendar.CalendarSystem#getGregorianCalendar() and returns + * the result + */ + private static Object callCalSystemGetGregorianCal() throws Exception { + final Class k = Class.forName("sun.util.calendar.CalendarSystem"); + return k.getDeclaredMethod("getGregorianCalendar").invoke(null); + } + + private static class ClassLoadTask implements Callable> { + private final String className; + private final CountDownLatch latch; + + private ClassLoadTask(final String className, final CountDownLatch latch) { + this.className = className; + this.latch = latch; + } + + @Override + public Class call() { + System.out.println(Thread.currentThread().getName() + " loading " + this.className); + try { + // let the other tasks know we are ready to trigger our work + latch.countDown(); + // wait for the other task to let us know they are ready to trigger their work too + latch.await(); + return Class.forName(this.className); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + } + + private static class GetGregorianCalTask implements Callable { + // keeps track of the instances returned by calls to sun.util.calendar.CalendarSystem#getGregorianCalendar() + // by this task + private static final List instances = Collections.synchronizedList(new ArrayList<>()); + private final CountDownLatch latch; + + private GetGregorianCalTask(final CountDownLatch latch) { + this.latch = latch; + } + + @Override + public Object call() { + System.out.println(Thread.currentThread().getName() + + " calling sun.util.calendar.CalendarSystem#getGregorianCalendar()"); + try { + // let the other tasks know we are ready to trigger our work + latch.countDown(); + // wait for the other task to let us know they are ready to trigger their work too + latch.await(); + final Object inst = callCalSystemGetGregorianCal(); + instances.add(inst); + return inst; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + } +} -- GitLab From af50772d39a063652895e79d474da6ebb992cae0 Mon Sep 17 00:00:00 2001 From: Jaikiran Pai Date: Tue, 28 Sep 2021 05:17:31 +0000 Subject: [PATCH 010/385] 8231640: (prop) Canonical property storage Reviewed-by: rriggs, smarks, dfuchs, ihse --- .../share/classes/java/util/Properties.java | 69 ++- .../jdk/internal/util/StaticProperty.java | 14 + .../util/Properties/PropertiesStoreTest.java | 275 ++++++++++ .../Properties/StoreReproducibilityTest.java | 494 ++++++++++++++++++ 4 files changed, 837 insertions(+), 15 deletions(-) create mode 100644 test/jdk/java/util/Properties/PropertiesStoreTest.java create mode 100644 test/jdk/java/util/Properties/StoreReproducibilityTest.java diff --git a/src/java.base/share/classes/java/util/Properties.java b/src/java.base/share/classes/java/util/Properties.java index 06999bc7bf3..789710d6a76 100644 --- a/src/java.base/share/classes/java/util/Properties.java +++ b/src/java.base/share/classes/java/util/Properties.java @@ -46,6 +46,7 @@ import java.util.function.BiConsumer; import java.util.function.BiFunction; import java.util.function.Function; +import jdk.internal.util.StaticProperty; import sun.nio.cs.ISO_8859_1; import sun.nio.cs.UTF_8; @@ -807,17 +808,25 @@ public class Properties extends Hashtable { * If the comments argument is not null, then an ASCII {@code #} * character, the comments string, and a line separator are first written * to the output stream. Thus, the {@code comments} can serve as an - * identifying comment. Any one of a line feed ('\n'), a carriage - * return ('\r'), or a carriage return followed immediately by a line feed - * in comments is replaced by a line separator generated by the {@code Writer} - * and if the next character in comments is not character {@code #} or - * character {@code !} then an ASCII {@code #} is written out - * after that line separator. + * identifying comment. Any one of a line feed ({@code \n}), a carriage + * return ({@code \r}), or a carriage return followed immediately by a line feed + * ({@code \r\n}) in comments is replaced by a + * {@link System#lineSeparator() line separator} and if the next + * character in comments is not character {@code #} or character {@code !} then + * an ASCII {@code #} is written out after that line separator. *

- * Next, a comment line is always written, consisting of an ASCII - * {@code #} character, the current date and time (as if produced - * by the {@code toString} method of {@code Date} for the - * current time), and a line separator as generated by the {@code Writer}. + * If the {@systemProperty java.properties.date} is set on the command line + * and is non-empty (as determined by {@link String#isEmpty() String.isEmpty}), + * a comment line is written as follows. + * First, a {@code #} character is written, followed by the contents + * of the property, followed by a line separator. Any line terminator characters + * in the value of the system property are treated the same way as noted above + * for the comments argument. + * If the system property is not set or is empty, a comment line is written + * as follows. + * First, a {@code #} character is written, followed by the current date and time + * formatted as if by the {@link Date#toString() Date.toString} method, + * followed by a line separator. *

* Then every entry in this {@code Properties} table is * written out, one per line. For each entry the key string is @@ -833,6 +842,10 @@ public class Properties extends Hashtable { * After the entries have been written, the output stream is flushed. * The output stream remains open after this method returns. * + * @implSpec The keys and elements are written in the natural sort order + * of the keys in the {@code entrySet()} unless {@code entrySet()} is + * overridden by a subclass to return a different value than {@code super.entrySet()}. + * * @param writer an output character stream writer. * @param comments a description of the property list. * @throws IOException if writing this property list to the specified @@ -903,12 +916,25 @@ public class Properties extends Hashtable { if (comments != null) { writeComments(bw, comments); } - bw.write("#" + new Date().toString()); - bw.newLine(); + writeDateComment(bw); + synchronized (this) { - for (Map.Entry e : entrySet()) { - String key = (String)e.getKey(); - String val = (String)e.getValue(); + @SuppressWarnings("unchecked") + Collection> entries = (Set>) (Set) entrySet(); + // entrySet() can be overridden by subclasses. Here we check to see if + // the returned instance type is the one returned by the Properties.entrySet() + // implementation. If yes, then we sort those entries in the natural order + // of their key. Else, we consider that the subclassed implementation may + // potentially have returned a differently ordered entries and so we just + // use the iteration order of the returned instance. + if (entries instanceof Collections.SynchronizedSet ss + && ss.c instanceof EntrySet) { + entries = new ArrayList<>(entries); + ((List>) entries).sort(Map.Entry.comparingByKey()); + } + for (Map.Entry e : entries) { + String key = e.getKey(); + String val = e.getValue(); key = saveConvert(key, true, escUnicode); /* No need to escape embedded and trailing spaces for value, hence * pass false to flag. @@ -921,6 +947,19 @@ public class Properties extends Hashtable { bw.flush(); } + private static void writeDateComment(BufferedWriter bw) throws IOException { + // value of java.properties.date system property isn't sensitive + // and so doesn't need any security manager checks to make the value accessible + // to the callers + String sysPropVal = StaticProperty.javaPropertiesDate(); + if (sysPropVal != null && !sysPropVal.isEmpty()) { + writeComments(bw, sysPropVal); + } else { + bw.write("#" + new Date()); + bw.newLine(); + } + } + /** * Loads all of the properties represented by the XML document on the * specified input stream into this properties table. diff --git a/src/java.base/share/classes/jdk/internal/util/StaticProperty.java b/src/java.base/share/classes/jdk/internal/util/StaticProperty.java index 011cb148af1..092f99e6b54 100644 --- a/src/java.base/share/classes/jdk/internal/util/StaticProperty.java +++ b/src/java.base/share/classes/jdk/internal/util/StaticProperty.java @@ -51,6 +51,7 @@ public final class StaticProperty { private static final String JAVA_IO_TMPDIR; private static final String NATIVE_ENCODING; private static final String FILE_ENCODING; + private static final String JAVA_PROPERTIES_DATE; private StaticProperty() {} @@ -67,6 +68,7 @@ public final class StaticProperty { JDK_SERIAL_FILTER_FACTORY = getProperty(props, "jdk.serialFilterFactory", null); NATIVE_ENCODING = getProperty(props, "native.encoding"); FILE_ENCODING = getProperty(props, "file.encoding"); + JAVA_PROPERTIES_DATE = getProperty(props, "java.properties.date", null); } private static String getProperty(Properties props, String key) { @@ -227,4 +229,16 @@ public final class StaticProperty { public static String fileEncoding() { return FILE_ENCODING; } + + /** + * Return the {@code java.properties.date} system property. + * + * {@link SecurityManager#checkPropertyAccess} is NOT checked + * in this method. + * + * @return the {@code java.properties.date} system property + */ + public static String javaPropertiesDate() { + return JAVA_PROPERTIES_DATE; + } } diff --git a/test/jdk/java/util/Properties/PropertiesStoreTest.java b/test/jdk/java/util/Properties/PropertiesStoreTest.java new file mode 100644 index 00000000000..da2be3b7cb5 --- /dev/null +++ b/test/jdk/java/util/Properties/PropertiesStoreTest.java @@ -0,0 +1,275 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import org.testng.Assert; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Writer; +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.TreeSet; + +/* + * @test + * @summary tests the order in which the Properties.store() method writes out the properties + * @bug 8231640 + * @run testng PropertiesStoreTest + */ +public class PropertiesStoreTest { + + private static final String DATE_FORMAT_PATTERN = "EEE MMM dd HH:mm:ss zzz uuuu"; + + @DataProvider(name = "propsProvider") + private Object[][] createProps() { + final Properties simple = new Properties(); + simple.setProperty("1", "one"); + simple.setProperty("2", "two"); + simple.setProperty("10", "ten"); + simple.setProperty("02", "zero-two"); + simple.setProperty("3", "three"); + simple.setProperty("0", "zero"); + simple.setProperty("00", "zero-zero"); + simple.setProperty("0", "zero-again"); + + final Properties specialChars = new Properties(); + // some special chars + simple.setProperty(" 1", "space-one"); + simple.setProperty("\t 3 7 \n", "tab-space-three-space-seven-space-newline"); + // add some simple chars + simple.setProperty("3", "three"); + simple.setProperty("0", "zero"); + + final Properties overrideCallsSuper = new OverridesEntrySetCallsSuper(); + overrideCallsSuper.putAll(simple); + + final OverridesEntrySet overridesEntrySet = new OverridesEntrySet(); + overridesEntrySet.putAll(simple); + + final Properties doesNotOverrideEntrySet = new DoesNotOverrideEntrySet(); + doesNotOverrideEntrySet.putAll(simple); + + return new Object[][]{ + {simple, naturalOrder(simple)}, + {specialChars, naturalOrder(specialChars)}, + {overrideCallsSuper, naturalOrder(overrideCallsSuper)}, + {overridesEntrySet, overridesEntrySet.expectedKeyOrder()}, + {doesNotOverrideEntrySet, naturalOrder(doesNotOverrideEntrySet)} + }; + } + + /** + * Tests that the {@link Properties#store(Writer, String)} API writes out the properties + * in the expected order + */ + @Test(dataProvider = "propsProvider") + public void testStoreWriterKeyOrder(final Properties props, final String[] expectedOrder) throws Exception { + // Properties.store(...) to a temp file + final Path tmpFile = Files.createTempFile("8231640", "props"); + try (final Writer writer = Files.newBufferedWriter(tmpFile)) { + props.store(writer, null); + } + testStoreKeyOrder(props, tmpFile, expectedOrder); + } + + /** + * Tests that the {@link Properties#store(OutputStream, String)} API writes out the properties + * in the expected order + */ + @Test(dataProvider = "propsProvider") + public void testStoreOutputStreamKeyOrder(final Properties props, final String[] expectedOrder) throws Exception { + // Properties.store(...) to a temp file + final Path tmpFile = Files.createTempFile("8231640", "props"); + try (final OutputStream os = Files.newOutputStream(tmpFile)) { + props.store(os, null); + } + testStoreKeyOrder(props, tmpFile, expectedOrder); + } + + /** + * {@link Properties#load(InputStream) Loads a Properties instance} from the passed + * {@code Path} and then verifies that: + * - the loaded properties instance "equals" the passed (original) "props" instance + * - the order in which the properties appear in the file represented by the path + * is the same as the passed "expectedOrder" + */ + private void testStoreKeyOrder(final Properties props, final Path storedProps, + final String[] expectedOrder) throws Exception { + // Properties.load(...) from that stored file and verify that the loaded + // Properties has expected content + final Properties loaded = new Properties(); + try (final InputStream is = Files.newInputStream(storedProps)) { + loaded.load(is); + } + Assert.assertEquals(loaded, props, "Unexpected properties loaded from stored state"); + + // now read lines from the stored file and keep track of the order in which the keys were + // found in that file. Compare that order with the expected store order of the keys. + final List actualOrder; + try (final BufferedReader reader = Files.newBufferedReader(storedProps)) { + actualOrder = readInOrder(reader); + } + Assert.assertEquals(actualOrder.size(), expectedOrder.length, + "Unexpected number of keys read from stored properties"); + if (!Arrays.equals(actualOrder.toArray(new String[0]), expectedOrder)) { + Assert.fail("Unexpected order of stored property keys. Expected order: " + Arrays.toString(expectedOrder) + + ", found order: " + actualOrder); + } + } + + /** + * Tests that {@link Properties#store(Writer, String)} writes out a proper date comment + */ + @Test + public void testStoreWriterDateComment() throws Exception { + final Properties props = new Properties(); + props.setProperty("a", "b"); + final Path tmpFile = Files.createTempFile("8231640", "props"); + try (final Writer writer = Files.newBufferedWriter(tmpFile)) { + props.store(writer, null); + } + testDateComment(tmpFile); + } + + /** + * Tests that {@link Properties#store(OutputStream, String)} writes out a proper date comment + */ + @Test + public void testStoreOutputStreamDateComment() throws Exception { + final Properties props = new Properties(); + props.setProperty("a", "b"); + final Path tmpFile = Files.createTempFile("8231640", "props"); + try (final Writer writer = Files.newBufferedWriter(tmpFile)) { + props.store(writer, null); + } + testDateComment(tmpFile); + } + + /** + * Reads each line in the {@code file} and verifies that there is only one comment line + * and that comment line can be parsed into a {@link java.util.Date} + */ + private void testDateComment(Path file) throws Exception { + String comment = null; + try (final BufferedReader reader = Files.newBufferedReader(file)) { + String line = null; + while ((line = reader.readLine()) != null) { + if (line.startsWith("#")) { + if (comment != null) { + Assert.fail("More than one comment line found in the stored properties file " + file); + } + comment = line.substring(1); + } + } + } + if (comment == null) { + Assert.fail("No comment line found in the stored properties file " + file); + } + try { + DateTimeFormatter.ofPattern(DATE_FORMAT_PATTERN).parse(comment); + } catch (DateTimeParseException pe) { + Assert.fail("Unexpected date comment: " + comment, pe); + } + } + + // returns the property keys in their natural order + private static String[] naturalOrder(final Properties props) { + return new TreeSet<>(props.stringPropertyNames()).toArray(new String[0]); + } + + // reads each non-comment line and keeps track of the order in which the property key lines + // were read + private static List readInOrder(final BufferedReader reader) throws IOException { + final List readKeys = new ArrayList<>(); + String line; + while ((line = reader.readLine()) != null) { + if (line.startsWith("#")) { + continue; + } + final String key = line.substring(0, line.indexOf("=")); + // the Properties.store(...) APIs write out the keys in a specific format for certain + // special characters. Our test uses some of the keys which have those special characters. + // Here we handle such special character conversion (for only those characters that this test uses). + // replace the backslash character followed by the t character with the tab character + String replacedKey = key.replace("\\t", "\t"); + // replace the backslash character followed by the n character with the newline character + replacedKey = replacedKey.replace("\\n", "\n"); + // replace backslash character followed by the space character with the space character + replacedKey = replacedKey.replace("\\ ", " "); + readKeys.add(replacedKey); + } + return readKeys; + } + + // Extends java.util.Properties and overrides entrySet() to return a reverse + // sorted entries set + private static class OverridesEntrySet extends Properties { + @Override + @SuppressWarnings("unchecked") + public Set> entrySet() { + // return a reverse sorted entries set + var entries = super.entrySet(); + Comparator> comparator = Map.Entry.comparingByKey(Comparator.reverseOrder()); + TreeSet> reverseSorted = new TreeSet<>(comparator); + reverseSorted.addAll((Set) entries); + return (Set) reverseSorted; + } + + String[] expectedKeyOrder() { + // returns in reverse order of the property keys' natural ordering + var keys = new ArrayList<>(stringPropertyNames()); + keys.sort(Comparator.reverseOrder()); + return keys.toArray(new String[0]); + } + } + + // Extends java.util.Properties and overrides entrySet() to just return "super.entrySet()" + private static class OverridesEntrySetCallsSuper extends Properties { + @Override + public Set> entrySet() { + return super.entrySet(); + } + } + + // Extends java.util.Properties but doesn't override entrySet() method + private static class DoesNotOverrideEntrySet extends Properties { + + @Override + public String toString() { + return "DoesNotOverrideEntrySet - " + super.toString(); + } + } +} diff --git a/test/jdk/java/util/Properties/StoreReproducibilityTest.java b/test/jdk/java/util/Properties/StoreReproducibilityTest.java new file mode 100644 index 00000000000..5f865c29328 --- /dev/null +++ b/test/jdk/java/util/Properties/StoreReproducibilityTest.java @@ -0,0 +1,494 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +import java.io.BufferedReader; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.Instant; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.Locale; +import java.util.Properties; +import java.util.TimeZone; + +/* + * @test + * @summary Tests that the Properties.store() APIs generate output that is reproducible + * @bug 8231640 + * @library /test/lib + * @run driver StoreReproducibilityTest + */ +public class StoreReproducibilityTest { + + private static final String DATE_FORMAT_PATTERN = "EEE MMM dd HH:mm:ss zzz uuuu"; + private static final String SYS_PROP_JAVA_PROPERTIES_DATE = "java.properties.date"; + private static final DateTimeFormatter reproducibleDateTimeFormatter = DateTimeFormatter.ofPattern(DATE_FORMAT_PATTERN) + .withLocale(Locale.ROOT).withZone(ZoneOffset.UTC); + + public static void main(final String[] args) throws Exception { + // no security manager enabled + testWithoutSecurityManager(); + // security manager enabled and security policy explicitly allows + // read permissions on java.properties.date system property + testWithSecMgrExplicitPermission(); + // security manager enabled and no explicit permission on java.properties.date system property + testWithSecMgrNoSpecificPermission(); + // free form non-date value for java.properties.date system property + testNonDateSysPropValue(); + // blank value for java.properties.date system property + testBlankSysPropValue(); + // empty value for java.properties.date system property + testEmptySysPropValue(); + // value for java.properties.date system property contains line terminator characters + testMultiLineSysPropValue(); + // value for java.properties.date system property contains backslash character + testBackSlashInSysPropValue(); + } + + /** + * Launches a Java program which is responsible for using Properties.store() to write out the + * properties to a file. The launched Java program is passed a value for the + * {@code java.properties.date} system property and the date comment written out + * to the file is expected to use this value. + * The program is launched multiple times with the same value for {@code java.properties.date} + * and the output written by each run of this program is verified to be exactly the same. + * Additionally, the date comment that's written out is verified to be the expected date that + * corresponds to the passed {@code java.properties.date}. + * The launched Java program is run without any security manager + */ + private static void testWithoutSecurityManager() throws Exception { + final List storedFiles = new ArrayList<>(); + final String sysPropVal = reproducibleDateTimeFormatter.format(Instant.ofEpochSecond(243535322)); + for (int i = 0; i < 5; i++) { + final Path tmpFile = Files.createTempFile("8231640", ".props"); + storedFiles.add(tmpFile); + final ProcessBuilder processBuilder = ProcessTools.createJavaProcessBuilder( + "-D" + SYS_PROP_JAVA_PROPERTIES_DATE + "=" + sysPropVal, + StoreTest.class.getName(), + tmpFile.toString(), + i % 2 == 0 ? "--use-outputstream" : "--use-writer"); + executeJavaProcess(processBuilder); + assertExpectedComment(tmpFile, sysPropVal); + if (!StoreTest.propsToStore.equals(loadProperties(tmpFile))) { + throw new RuntimeException("Unexpected properties stored in " + tmpFile); + } + } + assertAllFileContentsAreSame(storedFiles, sysPropVal); + } + + /** + * Launches a Java program which is responsible for using Properties.store() to write out the + * properties to a file. The launched Java program is passed a value for the + * {@code java.properties.date} system property and the date comment written out to the file + * is expected to use this value. + * The launched Java program is run with the default security manager and is granted + * a {@code read} permission on {@code java.properties.date}. + * The program is launched multiple times with the same value for {@code java.properties.date} + * and the output written by each run of this program is verified to be exactly the same. + * Additionally, the date comment that's written out is verified to be the expected date that + * corresponds to the passed {@code java.properties.date}. + */ + private static void testWithSecMgrExplicitPermission() throws Exception { + final Path policyFile = Files.createTempFile("8231640", ".policy"); + Files.write(policyFile, Collections.singleton(""" + grant { + // test writes/stores to a file, so FilePermission + permission java.io.FilePermission "<>", "read,write"; + // explicitly grant read permission on java.properties.date system property + // to verify store() APIs work fine + permission java.util.PropertyPermission "java.properties.date", "read"; + }; + """)); + final List storedFiles = new ArrayList<>(); + final String sysPropVal = reproducibleDateTimeFormatter.format(Instant.ofEpochSecond(1234342423)); + for (int i = 0; i < 5; i++) { + final Path tmpFile = Files.createTempFile("8231640", ".props"); + storedFiles.add(tmpFile); + final ProcessBuilder processBuilder = ProcessTools.createJavaProcessBuilder( + "-D" + SYS_PROP_JAVA_PROPERTIES_DATE + "=" + sysPropVal, + "-Djava.security.manager", + "-Djava.security.policy=" + policyFile.toString(), + StoreTest.class.getName(), + tmpFile.toString(), + i % 2 == 0 ? "--use-outputstream" : "--use-writer"); + executeJavaProcess(processBuilder); + assertExpectedComment(tmpFile, sysPropVal); + if (!StoreTest.propsToStore.equals(loadProperties(tmpFile))) { + throw new RuntimeException("Unexpected properties stored in " + tmpFile); + } + } + assertAllFileContentsAreSame(storedFiles, sysPropVal); + } + + /** + * Launches a Java program which is responsible for using Properties.store() to write out the + * properties to a file. The launched Java program is passed a value for the + * {@code java.properties.date} system property and the date comment written out to the file + * is expected to use this value. + * The launched Java program is run with the default security manager and is NOT granted + * any explicit permission for {@code java.properties.date} system property. + * The program is launched multiple times with the same value for {@code java.properties.date} + * and the output written by each run of this program is verified to be exactly the same. + * Additionally, the date comment that's written out is verified to be the expected date that + * corresponds to the passed {@code java.properties.date}. + */ + private static void testWithSecMgrNoSpecificPermission() throws Exception { + final Path policyFile = Files.createTempFile("8231640", ".policy"); + Files.write(policyFile, Collections.singleton(""" + grant { + // test writes/stores to a file, so FilePermission + permission java.io.FilePermission "<>", "read,write"; + // no other grants, not even "read" java.properties.date system property. + // test should still work fine and the date comment should correspond to the value of + // java.properties.date system property. + }; + """)); + final List storedFiles = new ArrayList<>(); + final String sysPropVal = reproducibleDateTimeFormatter.format(Instant.ofEpochSecond(1234342423)); + for (int i = 0; i < 5; i++) { + final Path tmpFile = Files.createTempFile("8231640", ".props"); + storedFiles.add(tmpFile); + final ProcessBuilder processBuilder = ProcessTools.createJavaProcessBuilder( + "-D" + SYS_PROP_JAVA_PROPERTIES_DATE + "=" + sysPropVal, + "-Djava.security.manager", + "-Djava.security.policy=" + policyFile.toString(), + StoreTest.class.getName(), + tmpFile.toString(), + i % 2 == 0 ? "--use-outputstream" : "--use-writer"); + executeJavaProcess(processBuilder); + assertExpectedComment(tmpFile, sysPropVal); + if (!StoreTest.propsToStore.equals(loadProperties(tmpFile))) { + throw new RuntimeException("Unexpected properties stored in " + tmpFile); + } + } + assertAllFileContentsAreSame(storedFiles, sysPropVal); + } + + /** + * Launches a Java program which is responsible for using Properties.store() to write out the + * properties to a file. The launched Java program is passed a {@link String#isBlank() blank} value + * for the {@code java.properties.date} system property. + * It is expected and verified in this test that such a value for the system property + * will cause a comment line to be written out with only whitespaces. + * The launched program is expected to complete without any errors. + */ + private static void testBlankSysPropValue() throws Exception { + final List storedFiles = new ArrayList<>(); + final String sysPropVal = " \t"; + for (int i = 0; i < 2; i++) { + final Path tmpFile = Files.createTempFile("8231640", ".props"); + storedFiles.add(tmpFile); + final ProcessBuilder processBuilder = ProcessTools.createJavaProcessBuilder( + "-D" + SYS_PROP_JAVA_PROPERTIES_DATE + "=" + sysPropVal, + StoreTest.class.getName(), + tmpFile.toString(), + i % 2 == 0 ? "--use-outputstream" : "--use-writer"); + executeJavaProcess(processBuilder); + if (!StoreTest.propsToStore.equals(loadProperties(tmpFile))) { + throw new RuntimeException("Unexpected properties stored in " + tmpFile); + } + String blankCommentLine = findNthComment(tmpFile, 2); + if (blankCommentLine == null) { + throw new RuntimeException("Comment line representing the value of " + + SYS_PROP_JAVA_PROPERTIES_DATE + " system property is missing in file " + tmpFile); + } + if (!blankCommentLine.isBlank()) { + throw new RuntimeException("Expected comment line to be blank but was " + blankCommentLine); + } + } + assertAllFileContentsAreSame(storedFiles, sysPropVal); + } + + /** + * Launches a Java program which is responsible for using Properties.store() to write out the + * properties to a file. The launched Java program is passed a {@link String#isEmpty() empty} value + * for the {@code java.properties.date} system property. + * It is expected and verified in this test that such a value for the system property + * will cause the current date and time to be written out as a comment. + * The launched program is expected to complete without any errors. + */ + private static void testEmptySysPropValue() throws Exception { + for (int i = 0; i < 2; i++) { + final Path tmpFile = Files.createTempFile("8231640", ".props"); + final ProcessBuilder processBuilder = ProcessTools.createJavaProcessBuilder( + "-D" + SYS_PROP_JAVA_PROPERTIES_DATE + "=" + "", + StoreTest.class.getName(), + tmpFile.toString(), + i % 2 == 0 ? "--use-outputstream" : "--use-writer"); + Date launchedAt = new Date(); + // wait for a second before launching so that we can then expect + // the date written out by the store() APIs to be "after" this launch date + Thread.sleep(1000); + executeJavaProcess(processBuilder); + if (!StoreTest.propsToStore.equals(loadProperties(tmpFile))) { + throw new RuntimeException("Unexpected properties stored in " + tmpFile); + } + assertCurrentDate(tmpFile, launchedAt); + } + } + + /** + * Launches a Java program which is responsible for using Properties.store() to write out the + * properties to a file. The launched Java program is passed the {@code java.properties.date} + * system property with a value that doesn't represent a formatted date. + * It is expected and verified in this test that such a value for the system property + * will cause the comment to use that value verbatim. The launched program is expected to complete + * without any errors. + */ + private static void testNonDateSysPropValue() throws Exception { + final String sysPropVal = "foo-bar"; + final List storedFiles = new ArrayList<>(); + for (int i = 0; i < 2; i++) { + final Path tmpFile = Files.createTempFile("8231640", ".props"); + storedFiles.add(tmpFile); + final ProcessBuilder processBuilder = ProcessTools.createJavaProcessBuilder( + "-D" + SYS_PROP_JAVA_PROPERTIES_DATE + "=" + sysPropVal, + StoreTest.class.getName(), + tmpFile.toString(), + i % 2 == 0 ? "--use-outputstream" : "--use-writer"); + executeJavaProcess(processBuilder); + if (!StoreTest.propsToStore.equals(loadProperties(tmpFile))) { + throw new RuntimeException("Unexpected properties stored in " + tmpFile); + } + assertExpectedComment(tmpFile, sysPropVal); + } + assertAllFileContentsAreSame(storedFiles, sysPropVal); + } + + /** + * Launches a Java program which is responsible for using Properties.store() to write out the + * properties to a file. The launched Java program is passed the {@code java.properties.date} + * system property with a value that has line terminator characters. + * It is expected and verified in this test that such a value for the system property + * will cause the comment written out to be multiple separate comments. The launched program is expected + * to complete without any errors. + */ + private static void testMultiLineSysPropValue() throws Exception { + final String[] sysPropVals = {"hello-world\nc=d", "hello-world\rc=d", "hello-world\r\nc=d"}; + for (final String sysPropVal : sysPropVals) { + final List storedFiles = new ArrayList<>(); + for (int i = 0; i < 2; i++) { + final Path tmpFile = Files.createTempFile("8231640", ".props"); + storedFiles.add(tmpFile); + final ProcessBuilder processBuilder = ProcessTools.createJavaProcessBuilder( + "-D" + SYS_PROP_JAVA_PROPERTIES_DATE + "=" + sysPropVal, + StoreTest.class.getName(), + tmpFile.toString(), + i % 2 == 0 ? "--use-outputstream" : "--use-writer"); + executeJavaProcess(processBuilder); + if (!StoreTest.propsToStore.equals(loadProperties(tmpFile))) { + throw new RuntimeException("Unexpected properties stored in " + tmpFile); + } + // verify this results in 2 separate comment lines in the stored file + String commentLine1 = findNthComment(tmpFile, 2); + String commentLine2 = findNthComment(tmpFile, 3); + if (commentLine1 == null || commentLine2 == null) { + throw new RuntimeException("Did not find the expected multi-line comments in " + tmpFile); + } + if (!commentLine1.equals("hello-world")) { + throw new RuntimeException("Unexpected comment line " + commentLine1 + " in " + tmpFile); + } + if (!commentLine2.equals("c=d")) { + throw new RuntimeException("Unexpected comment line " + commentLine2 + " in " + tmpFile); + } + } + assertAllFileContentsAreSame(storedFiles, sysPropVal); + } + } + + /** + * Launches a Java program which is responsible for using Properties.store() to write out the + * properties to a file. The launched Java program is passed the {@code java.properties.date} + * system property with a value that has backslash character. + * It is expected and verified in this test that such a value for the system property + * will not cause any malformed comments or introduce any new properties in the stored content. + * The launched program is expected to complete without any errors. + */ + private static void testBackSlashInSysPropValue() throws Exception { + final String[] sysPropVals = {"\\hello-world", "hello-world\\", "hello-world\\c=d", + "newline-plus-backslash\\\nc=d"}; + for (final String sysPropVal : sysPropVals) { + final List storedFiles = new ArrayList<>(); + for (int i = 0; i < 2; i++) { + final Path tmpFile = Files.createTempFile("8231640", ".props"); + storedFiles.add(tmpFile); + final ProcessBuilder processBuilder = ProcessTools.createJavaProcessBuilder( + "-D" + SYS_PROP_JAVA_PROPERTIES_DATE + "=" + sysPropVal, + StoreTest.class.getName(), + tmpFile.toString(), + i % 2 == 0 ? "--use-outputstream" : "--use-writer"); + executeJavaProcess(processBuilder); + if (!StoreTest.propsToStore.equals(loadProperties(tmpFile))) { + throw new RuntimeException("Unexpected properties stored in " + tmpFile); + } + String commentLine1 = findNthComment(tmpFile, 2); + if (commentLine1 == null) { + throw new RuntimeException("Did not find the expected comment line in " + tmpFile); + } + if (sysPropVal.contains("newline-plus-backslash")) { + if (!commentLine1.equals("newline-plus-backslash\\")) { + throw new RuntimeException("Unexpected comment line " + commentLine1 + " in " + tmpFile); + } + // we expect this specific system property value to be written out into 2 separate comment lines + String commentLine2 = findNthComment(tmpFile, 3); + if (commentLine2 == null) { + throw new RuntimeException(sysPropVal + " was expected to be split into 2 comment line, " + + "but wasn't, in " + tmpFile); + } + if (!commentLine2.equals("c=d")) { + throw new RuntimeException("Unexpected comment line " + commentLine2 + " in " + tmpFile); + } + } else { + if (!commentLine1.equals(sysPropVal)) { + throw new RuntimeException("Unexpected comment line " + commentLine1 + " in " + tmpFile); + } + } + } + assertAllFileContentsAreSame(storedFiles, sysPropVal); + } + } + + // launches the java process and waits for it to exit. throws an exception if exit value is non-zero + private static void executeJavaProcess(ProcessBuilder pb) throws Exception { + final OutputAnalyzer outputAnalyzer = ProcessTools.executeProcess(pb); + try { + outputAnalyzer.shouldHaveExitValue(0); + } finally { + // print out any stdout/err that was generated in the launched program + outputAnalyzer.reportDiagnosticSummary(); + } + } + + // Properties.load() from the passed file and return the loaded Properties instance + private static Properties loadProperties(final Path file) throws IOException { + final Properties props = new Properties(); + props.load(Files.newBufferedReader(file)); + return props; + } + + /** + * Verifies that the comment in the {@code destFile} is same as {@code expectedComment}, + * instead of the default date comment. + */ + private static void assertExpectedComment(final Path destFile, + final String expectedComment) throws Exception { + final String actualComment = findNthComment(destFile, 2); + if (actualComment == null) { + throw new RuntimeException("Comment \"" + expectedComment + "\" not found in stored properties " + destFile); + } + if (!expectedComment.equals(actualComment)) { + throw new RuntimeException("Expected comment \"" + expectedComment + "\" but found \"" + actualComment + "\" " + + "in stored properties " + destFile); + } + } + + /** + * Verifies that the date comment in the {@code destFile} can be parsed using the + * "EEE MMM dd HH:mm:ss zzz uuuu" format and the time represented by it is {@link Date#after(Date) after} + * the passed {@code date} + */ + private static void assertCurrentDate(final Path destFile, final Date date) throws Exception { + final String dateComment = findNthComment(destFile, 2); + if (dateComment == null) { + throw new RuntimeException("Date comment not found in stored properties " + destFile); + } + System.out.println("Found date comment " + dateComment + " in file " + destFile); + final Date parsedDate; + try { + Instant instant = Instant.from(DateTimeFormatter.ofPattern(DATE_FORMAT_PATTERN).parse(dateComment)); + parsedDate = new Date(instant.toEpochMilli()); + } catch (DateTimeParseException pe) { + throw new RuntimeException("Unexpected date " + dateComment + " in stored properties " + destFile); + } + if (!parsedDate.after(date)) { + throw new RuntimeException("Expected date comment " + dateComment + " to be after " + date + + " but was " + parsedDate); + } + } + + // returns the "Nth" comment from the file. Comment index starts from 1. + private static String findNthComment(Path file, int commentIndex) throws IOException { + List comments = new ArrayList<>(); + try (final BufferedReader reader = Files.newBufferedReader(file)) { + String line = null; + while ((line = reader.readLine()) != null) { + if (line.startsWith("#")) { + comments.add(line.substring(1)); + if (comments.size() == commentIndex) { + return comments.get(commentIndex - 1); + } + } + } + } + return null; + } + + // verifies the byte equality of the contents in each of the files + private static void assertAllFileContentsAreSame(final List files, + final String sysPropVal) throws Exception { + final byte[] file1Contents = Files.readAllBytes(files.get(0)); + for (int i = 1; i < files.size(); i++) { + final byte[] otherFileContents = Files.readAllBytes(files.get(i)); + if (!Arrays.equals(file1Contents, otherFileContents)) { + throw new RuntimeException("Properties.store() did not generate reproducible content when " + + SYS_PROP_JAVA_PROPERTIES_DATE + " was set to " + sysPropVal); + } + } + } + + static class StoreTest { + private static final Properties propsToStore = new Properties(); + + static { + propsToStore.setProperty("a", "b"); + } + + /** + * Uses Properties.store() APIs to store the properties into file + */ + public static void main(final String[] args) throws Exception { + final Path destFile = Path.of(args[0]); + final String comment = "some user specified comment"; + System.out.println("Current default timezone is " + TimeZone.getDefault()); + if (args[1].equals("--use-outputstream")) { + try (var os = Files.newOutputStream(destFile)) { + propsToStore.store(os, comment); + } + } else { + try (var br = Files.newBufferedWriter(destFile)) { + propsToStore.store(br, comment); + } + } + } + } +} -- GitLab From 3eca9c36a63595baee0659ac818fd5bedc528db1 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Tue, 28 Sep 2021 05:56:34 +0000 Subject: [PATCH 011/385] 8264707: HotSpot Style Guide should permit use of lambda Reviewed-by: stefank, dholmes, coleenp, iklam, sjohanss, eosterlund, iveresov, kvn --- doc/hotspot-style.html | 121 +++++++++++++++++- doc/hotspot-style.md | 280 +++++++++++++++++++++++++++++++++++++++-- 2 files changed, 388 insertions(+), 13 deletions(-) diff --git a/doc/hotspot-style.html b/doc/hotspot-style.html index 8f421de54f0..fe72cbbdf80 100644 --- a/doc/hotspot-style.html +++ b/doc/hotspot-style.html @@ -50,6 +50,7 @@

  • nullptr
  • <atomic>
  • Uniform Initialization
  • +
  • Local Function Objects
  • Additional Permitted Features
  • Excluded Features
  • Undecided Features
  • @@ -254,8 +255,7 @@ while ( test_foo(args...) ) { // No, excess spaces around control

    Function argument deduction. This is always permitted, and indeed encouraged. It is nearly always better to allow the type of a function template argument to be deduced rather than explicitly specified.

  • auto variable declarations (n1984)
    For local variables, this can be used to make the code clearer by eliminating type information that is obvious or irrelevant. Excessive use can make code much harder to understand.

  • Function return type deduction (n3638)
    Only use if the function body has a very small number of return statements, and generally relatively little other code.

  • -
  • Generic lambdas. Lambdas are not (yet) permitted.

  • -
  • Lambda init captures. Lambdas are not (yet) permitted.

  • +
  • Also see lambda expressions.

  • Expression SFINAE

    Substitution Failure Is Not An Error (SFINAE) is a template metaprogramming technique that makes use of template parameter substitution failures to make compile-time decisions.

    @@ -288,6 +288,121 @@ while ( test_foo(args...) ) { // No, excess spaces around controlaggregate initialization

    Although related, the use of std::initializer_list remains forbidden, as part of the avoidance of the C++ Standard Library in HotSpot code.

    +

    Local Function Objects

    +
      +
    • Local function objects, including lambda expressions, may be used.
    • +
    • Lambda expressions must only be used as a downward value.
    • +
    • Prefer [&] as the capture list of a lambda expression.
    • +
    • Return type deduction for lambda expressions is permitted, and indeed encouraged.
    • +
    • An empty parameter list for a lambda expression may be elided.
    • +
    • A lambda expression must not be mutable.
    • +
    • Generic lambda expressions are permitted.
    • +
    • Lambda expressions should be relatively simple.
    • +
    • Anonymous lambda expressions should not overly clutter the enclosing expression.
    • +
    • An anonymous lambda expression must not be directly invoked.
    • +
    • Bind expressions are forbidden.
    • +
    +

    Single-use function objects can be defined locally within a function, directly at the point of use. This is an alternative to having a function or function object class defined at class or namespace scope.

    +

    This usage was somewhat limited by C++03, which does not permit such a class to be used as a template parameter. That restriction was removed by C++11 (n2657). Use of this feature is permitted.

    +

    Many HotSpot protocols involve "function-like" objects that involve some named member function rather than a call operator. For example, a function that performs some action on all threads might be written as

    +
    void do_something() {
    +  struct DoSomething : public ThreadClosure {
    +    virtual void do_thread(Thread* t) {
    +      ... do something with t ...
    +    }
    +  } closure;
    +  Threads::threads_do(&closure);
    +}
    +

    HotSpot code has historically usually placed the DoSomething class at namespace (or sometimes class) scope. This separates the function's code from its use, often to the detriment of readability. It requires giving the class a globally unique name (if at namespace scope). It also loses the information that the class is intended for use in exactly one place, and does not have any subclasses. (However, the latter can now be indicated by declaring it final.) Often, for simplicity, a local class will skip things like access control and accessor functions, giving the enclosing function direct access to the implementation and eliminating some boilerplate that might be provided if the class is in some outer (more accessible) scope. On the other hand, if there is a lot of surrounding code in the function body or the local class is of significant size, defining it locally can increase clutter and reduce readability.

    +

    C++11 added lambda expressions as a new way to write a function object. Simple lambda expressions can be significantly more concise than a function object, eliminating a lot of boiler-plate. On the other hand, a complex lambda expression may not provide much, if any, readability benefit compared to an ordinary function object. Also, while a lambda can encapsulate a call to a "function-like" object, it cannot be used in place of such.

    +

    A common use for local functions is as one-use RAII objects. The amount of boilerplate for a function object class (local or not) makes such usage somewhat clumsy and verbose. But with the help of a small amount of supporting utility code, lambdas work particularly well for this use case.

    +

    Another use for local functions is partial application. Again here, lambdas are typically much simpler and less verbose than function object classes.

    +

    Because of these benefits, lambda expressions are permitted in HotSpot code, with some restrictions and usage guidance. An anonymous lambda is one which is passed directly as an argument. A named lambda is the value of a variable, which is its name.

    +

    Lambda expressions should only be passed downward. In particular, a lambda should not be returned from a function or stored in a global variable, whether directly or as the value of a member of some other object. Lambda capture is syntactically subtle (by design), and propagating a lambda in such ways can easily pass references to captured values to places where they are no longer valid. In particular, members of the enclosing this object are effectively captured by reference, even if the default capture is by-value. For such uses-cases a function object class should be used to make the desired value capturing and propagation explicit.

    +

    Limiting the capture list to [&] (implicitly capture by reference) is a simplifying restriction that still provides good support for HotSpot usage, while reducing the cases a reader must recognize and understand.

    +
      +
    • Many common lambda uses require reference capture. Not permitting it would substantially reduce the utility of lambdas.

    • +
    • Referential transparency. Implicit reference capture makes variable references in the lambda body have the same meaning they would have in the enclosing code. There isn't a semantic barrier across which the meaning of a variable changes.

    • +
    • Explicit reference capture introduces significant clutter, especially when lambda expressions are relatively small and simple, as they should be in HotSpot code.

    • +
    • There are a number of reasons why by-value capture might be used, but for the most part they don't apply to HotSpot code, given other usage restrictions.

      +
        +
      • A primary use-case for by-value capture is to support escaping uses, where values captured by-reference might become invalid. That use-case doesn't apply if only downward lambdas are used.

      • +
      • By-value capture can also make a lambda-local copy for mutation, which requires making the lambda mutable; see below.

      • +
      • By-value capture might be viewed as an optimization, avoiding any overhead for reference capture of cheap to copy values. But the compiler can often eliminate any such overhead.

      • +
      • By-value capture by a non-mutable lambda makes the captured values const, preventing any modification by the lambda and making the captured value unaffected by modifications to the outer variable. But this only applies to captured auto variables, not member variables, and is inconsistent with referential transparency.

      • +
    • +
    • Non-capturing lambdas (with an empty capture list - []) have limited utility. There are cases where no captures are required (pure functions, for example), but if the function is small and simple then that's obvious anyway.

    • +
    • Capture initializers (a C++14 feature - N3649) are not permitted. Capture initializers inherently increase the complexity of the capture list, and provide little benefit over an additional in-scope local variable.

    • +
    +

    The use of mutable lambda expressions is forbidden because there don't seem to be many, if any, good use-cases for them in HotSpot. A lambda expression needs to be mutable in order to modify a by-value captured value. But with only downward lambdas, such usage seems likely to be rare and complicated. It is better to use a function object class in any such cases that arise, rather than requiring all HotSpot developers to understand this relatively obscure feature.

    +

    While it is possible to directly invoke an anonymous lambda expression, that feature should not be used, as such a form can be confusing to readers. Instead, name the lambda and call it by name.

    +

    Some reasons to prefer a named lambda instead of an anonymous lambda are

    +
      +
    • The body contains non-trivial control flow or declarations or other nested constructs.

    • +
    • Its role in an argument list is hard to guess without examining the function declaration. Give it a name that indicates its purpose.

    • +
    • It has an unusual capture list.

    • +
    • It has a complex explicit return type or parameter types.

    • +
    +

    Lambda expressions, and particularly anonymous lambda expressions, should be simple and compact. One-liners are good. Anonymous lambdas should usually be limited to a couple lines of body code. More complex lambdas should be named. A named lambda should not clutter the enclosing function and make it long and complex; do continue to break up large functions via the use of separate helper functions.

    +

    An anonymous lambda expression should either be a one-liner in a one-line expression, or isolated in its own set of lines. Don't place part of a lambda expression on the same line as other arguments to a function. The body of a multi-line lambda argument should be indented from the start of the capture list, as if that were the start of an ordinary function definition. The body of a multi-line named lambda should be indented one step from the variable's indentation.

    +

    Some examples:

    +
      +
    1. foo([&] { ++counter; });
    2. +
    3. foo(x, [&] { ++counter; });
    4. +
    5. foo([&] { if (predicate) ++counter; });
    6. +
    7. foo([&] { auto tmp = process(x); tmp.f(); return tmp.g(); })
    8. +
    9. Separate one-line lambda from other arguments:

      +
      foo(c.begin(), c.end(),
      +    [&] (const X& x) { do_something(x); return x.value(); });
    10. +
    11. Indentation for multi-line lambda:

      +
      c.do_entries([&] (const X& x) {
      +               do_something(x, a);
      +               do_something1(x, b);
      +               do_something2(x, c);
      +             });
    12. +
    13. Separate multi-line lambda from other arguments:

      +
      foo(c.begin(), c.end(),
      +    [&] (const X& x) {
      +      do_something(x, a);
      +      do_something1(x, b);
      +      do_something2(x, c);
      +    });
    14. +
    15. Multi-line named lambda:

      +
      auto do_entry = [&] (const X& x) {
      +  do_something(x, a);
      +  do_something1(x, b);
      +  do_something2(x, c);
      +};
    16. +
    +

    Item 4, and especially items 6 and 7, are pushing the simplicity limits for anonymous lambdas. Item 6 might be better written using a named lambda:

    +
    c.do_entries(do_entry);
    +

    Note that C++11 also added bind expressions as a way to write a function object for partial application, using std::bind and related facilities from the Standard Library. std::bind generalizes and replaces some of the binders from C++03. Bind expressions are not permitted in HotSpot code. They don't provide enough benefit over lambdas or local function classes in the cases where bind expressions are applicable to warrant the introduction of yet another mechanism in this space into HotSpot code.

    +

    References:

    +
      +
    • Local and unnamed types as template parameters (n2657)
    • +
    • New wording for C++0x lambdas (n2927)
    • +
    • Generalized lambda capture (init-capture) (N3648)
    • +
    • Generic (polymorphic) lambda expressions (N3649)
    • +
    +

    References from C++17

    +
      +
    • Wording for constexpr lambda (p0170r1)
    • +
    • Lambda capture of *this by Value (p0018r3)
    • +
    +

    References from C++20

    +
      +
    • Allow lambda capture [=, this] (p0409r2)
    • +
    • Familiar template syntax for generic lambdas (p0428r2)
    • +
    • Simplifying implicit lambda capture (p0588r1)
    • +
    • Default constructible and assignable stateless lambdas (p0624r2)
    • +
    • Lambdas in unevaluated contexts (p0315r4)
    • +
    • Allow pack expansion in lambda init-capture (p0780r2) (p2095r0)
    • +
    • Deprecate implicit capture of this via [=] (p0806r2)
    • +
    +

    References from C++23

    +
      +
    • Make () more optional for lambdas (p1102r2)
    • +

    Additional Permitted Features

    • constexpr (n2235) (n3652)

    • @@ -305,7 +420,6 @@ while ( test_foo(args...) ) { // No, excess spaces around control

      Dynamic initialization and destruction with concurrency (n2660)

    • final virtual specifiers for classes and virtual functions (n2928), (n3206), (n3272)

    • override virtual specifiers for virtual functions (n2928), (n3206), (n3272)

    • -
    • Local and unnamed types as template parameters (n2657)

    • Range-based for loops (n2930) (range-for)

    Excluded Features

    @@ -337,7 +451,6 @@ while ( test_foo(args...) ) { // No, excess spaces around control

    Member initializers and aggregates (n3653)

  • [[noreturn]] attribute (n2761)

  • Rvalue references and move semantics

  • -
  • Lambdas

  • diff --git a/doc/hotspot-style.md b/doc/hotspot-style.md index f02954347ed..6d167cad9d6 100644 --- a/doc/hotspot-style.md +++ b/doc/hotspot-style.md @@ -596,9 +596,7 @@ use can make code much harder to understand. Only use if the function body has a very small number of `return` statements, and generally relatively little other code. -* Generic lambdas. Lambdas are not (yet) permitted. - -* Lambda init captures. Lambdas are not (yet) permitted. +* Also see [lambda expressions](#lambdaexpressions). ### Expression SFINAE @@ -703,6 +701,273 @@ Some relevant sections from cppreference.com: Although related, the use of `std::initializer_list` remains forbidden, as part of the avoidance of the C++ Standard Library in HotSpot code. +### Local Function Objects + +* Local function objects, including lambda expressions, may be used. +* Lambda expressions must only be used as a downward value. +* Prefer `[&]` as the capture list of a lambda expression. +* Return type deduction for lambda expressions is permitted, and indeed encouraged. +* An empty parameter list for a lambda expression may be elided. +* A lambda expression must not be `mutable`. +* Generic lambda expressions are permitted. +* Lambda expressions should be relatively simple. +* Anonymous lambda expressions should not overly clutter the enclosing expression. +* An anonymous lambda expression must not be directly invoked. +* Bind expressions are forbidden. + +Single-use function objects can be defined locally within a function, +directly at the point of use. This is an alternative to having a function +or function object class defined at class or namespace scope. + +This usage was somewhat limited by C++03, which does not permit such a class +to be used as a template parameter. That restriction was removed by C++11 +([n2657]). Use of this feature is permitted. + +Many HotSpot protocols involve "function-like" objects that involve some +named member function rather than a call operator. For example, a function +that performs some action on all threads might be written as + +``` +void do_something() { + struct DoSomething : public ThreadClosure { + virtual void do_thread(Thread* t) { + ... do something with t ... + } + } closure; + Threads::threads_do(&closure); +} +``` + +HotSpot code has historically usually placed the DoSomething class at +namespace (or sometimes class) scope. This separates the function's code +from its use, often to the detriment of readability. It requires giving the +class a globally unique name (if at namespace scope). It also loses the +information that the class is intended for use in exactly one place, and +does not have any subclasses. (However, the latter can now be indicated by +declaring it `final`.) Often, for simplicity, a local class will skip +things like access control and accessor functions, giving the enclosing +function direct access to the implementation and eliminating some +boilerplate that might be provided if the class is in some outer (more +accessible) scope. On the other hand, if there is a lot of surrounding code +in the function body or the local class is of significant size, defining it +locally can increase clutter and reduce readability. + + +C++11 added _lambda expressions_ as a new way to write a function object. +Simple lambda expressions can be significantly more concise than a function +object, eliminating a lot of boiler-plate. On the other hand, a complex +lambda expression may not provide much, if any, readability benefit compared +to an ordinary function object. Also, while a lambda can encapsulate a call +to a "function-like" object, it cannot be used in place of such. + +A common use for local functions is as one-use [RAII] objects. The amount +of boilerplate for a function object class (local or not) makes such usage +somewhat clumsy and verbose. But with the help of a small amount of +supporting utility code, lambdas work particularly well for this use case. + +Another use for local functions is [partial application][PARTIALAPP]. Again +here, lambdas are typically much simpler and less verbose than function +object classes. + +Because of these benefits, lambda expressions are permitted in HotSpot code, +with some restrictions and usage guidance. An anonymous lambda is one which +is passed directly as an argument. A named lambda is the value of a +variable, which is its name. + +Lambda expressions should only be passed downward. In particular, a lambda +should not be returned from a function or stored in a global variable, +whether directly or as the value of a member of some other object. Lambda +capture is syntactically subtle (by design), and propagating a lambda in +such ways can easily pass references to captured values to places where they +are no longer valid. In particular, members of the enclosing `this` object +are effectively captured by reference, even if the default capture is +by-value. For such uses-cases a function object class should be used to +make the desired value capturing and propagation explicit. + +Limiting the capture list to `[&]` (implicitly capture by reference) is a +simplifying restriction that still provides good support for HotSpot usage, +while reducing the cases a reader must recognize and understand. + +* Many common lambda uses require reference capture. Not permitting it +would substantially reduce the utility of lambdas. + +* Referential transparency. Implicit reference capture makes variable +references in the lambda body have the same meaning they would have in the +enclosing code. There isn't a semantic barrier across which the meaning of +a variable changes. + +* Explicit reference capture introduces significant clutter, especially when +lambda expressions are relatively small and simple, as they should be in +HotSpot code. + +* There are a number of reasons why by-value capture might be used, but for +the most part they don't apply to HotSpot code, given other usage restrictions. + + * A primary use-case for by-value capture is to support escaping uses, + where values captured by-reference might become invalid. That use-case + doesn't apply if only downward lambdas are used. + + * By-value capture can also make a lambda-local copy for mutation, which + requires making the lambda `mutable`; see below. + + * By-value capture might be viewed as an optimization, avoiding any + overhead for reference capture of cheap to copy values. But the + compiler can often eliminate any such overhead. + + * By-value capture by a non-`mutable` lambda makes the captured values + const, preventing any modification by the lambda and making the captured + value unaffected by modifications to the outer variable. But this only + applies to captured auto variables, not member variables, and is + inconsistent with referential transparency. + +* Non-capturing lambdas (with an empty capture list - `[]`) have limited +utility. There are cases where no captures are required (pure functions, +for example), but if the function is small and simple then that's obvious +anyway. + +* Capture initializers (a C++14 feature - [N3649]) are not permitted. +Capture initializers inherently increase the complexity of the capture list, +and provide little benefit over an additional in-scope local variable. + +The use of `mutable` lambda expressions is forbidden because there don't +seem to be many, if any, good use-cases for them in HotSpot. A lambda +expression needs to be mutable in order to modify a by-value captured value. +But with only downward lambdas, such usage seems likely to be rare and +complicated. It is better to use a function object class in any such cases +that arise, rather than requiring all HotSpot developers to understand this +relatively obscure feature. + +While it is possible to directly invoke an anonymous lambda expression, that +feature should not be used, as such a form can be confusing to readers. +Instead, name the lambda and call it by name. + +Some reasons to prefer a named lambda instead of an anonymous lambda are + +* The body contains non-trivial control flow or declarations or other nested +constructs. + +* Its role in an argument list is hard to guess without examining the +function declaration. Give it a name that indicates its purpose. + +* It has an unusual capture list. + +* It has a complex explicit return type or parameter types. + +Lambda expressions, and particularly anonymous lambda expressions, should be +simple and compact. One-liners are good. Anonymous lambdas should usually +be limited to a couple lines of body code. More complex lambdas should be +named. A named lambda should not clutter the enclosing function and make it +long and complex; do continue to break up large functions via the use of +separate helper functions. + +An anonymous lambda expression should either be a one-liner in a one-line +expression, or isolated in its own set of lines. Don't place part of a +lambda expression on the same line as other arguments to a function. The +body of a multi-line lambda argument should be indented from the start of +the capture list, as if that were the start of an ordinary function +definition. The body of a multi-line named lambda should be indented one +step from the variable's indentation. + +Some examples: + +1. `foo([&] { ++counter; });` +2. `foo(x, [&] { ++counter; });` +3. `foo([&] { if (predicate) ++counter; });` +4. `foo([&] { auto tmp = process(x); tmp.f(); return tmp.g(); })` +5. Separate one-line lambda from other arguments: + + ``` + foo(c.begin(), c.end(), + [&] (const X& x) { do_something(x); return x.value(); }); + ``` +6. Indentation for multi-line lambda: + + ``` + c.do_entries([&] (const X& x) { + do_something(x, a); + do_something1(x, b); + do_something2(x, c); + }); + ``` +7. Separate multi-line lambda from other arguments: + + ``` + foo(c.begin(), c.end(), + [&] (const X& x) { + do_something(x, a); + do_something1(x, b); + do_something2(x, c); + }); + ``` +8. Multi-line named lambda: + + ``` + auto do_entry = [&] (const X& x) { + do_something(x, a); + do_something1(x, b); + do_something2(x, c); + }; + ``` + +Item 4, and especially items 6 and 7, are pushing the simplicity limits for +anonymous lambdas. Item 6 might be better written using a named lambda: +``` +c.do_entries(do_entry); +``` + +Note that C++11 also added _bind expressions_ as a way to write a function +object for partial application, using `std::bind` and related facilities +from the Standard Library. `std::bind` generalizes and replaces some of the +binders from C++03. Bind expressions are not permitted in HotSpot code. +They don't provide enough benefit over lambdas or local function classes in +the cases where bind expressions are applicable to warrant the introduction +of yet another mechanism in this space into HotSpot code. + +References: + +* Local and unnamed types as template parameters ([n2657]) +* New wording for C++0x lambdas ([n2927]) +* Generalized lambda capture (init-capture) ([N3648]) +* Generic (polymorphic) lambda expressions ([N3649]) + +[n2657]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2657.htm +[n2927]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2927.pdf +[N3648]: https://isocpp.org/files/papers/N3648.html +[N3649]: https://isocpp.org/files/papers/N3649.html + +References from C++17 + +* Wording for constexpr lambda ([p0170r1]) +* Lambda capture of *this by Value ([p0018r3]) + +[p0170r1]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0170r1.pdf +[p0018r3]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0018r3.html + +References from C++20 + +* Allow lambda capture [=, this] ([p0409r2]) +* Familiar template syntax for generic lambdas ([p0428r2]) +* Simplifying implicit lambda capture ([p0588r1]) +* Default constructible and assignable stateless lambdas ([p0624r2]) +* Lambdas in unevaluated contexts ([p0315r4]) +* Allow pack expansion in lambda init-capture ([p0780r2]) ([p2095r0]) +* Deprecate implicit capture of this via [=] ([p0806r2]) + +[p0409r2]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0409r2.html +[p0428r2]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0428r2.pdf +[p0588r1]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0588r1.html +[p0624r2]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0624r2.pdf +[p0315r4]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0315r4.pdf +[p0780r2]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0780r2.html +[p2095r0]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p2095r0.html +[p0806r2]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0806r2.html + +References from C++23 + +* Make () more optional for lambdas ([p1102r2]) + +[p1102r2]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p1102r2.html + ### Additional Permitted Features * `constexpr` @@ -757,9 +1022,6 @@ part of the avoidance of the C++ Standard Library in HotSpot code. ([n3206](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3206.htm)), ([n3272](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3272.htm)) -* Local and unnamed types as template parameters -([n2657](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2657.htm)) - * Range-based `for` loops ([n2930](http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2009/n2930.html)) ([range-for](https://en.cppreference.com/w/cpp/language/range-for)) @@ -837,9 +1099,6 @@ features that have not yet been discussed. * Rvalue references and move semantics -* Lambdas - - [ADL]: https://en.cppreference.com/w/cpp/language/adl "Argument Dependent Lookup" @@ -854,3 +1113,6 @@ features that have not yet been discussed. [SFINAE]: https://en.cppreference.com/w/cpp/language/sfinae "Substitution Failure Is Not An Error" + +[PARTIALAPP]: https://en.wikipedia.org/wiki/Partial_application + "Partial Application" -- GitLab From 6a573b888d4d3322b9165562f85e1b7b781a5ff1 Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Tue, 28 Sep 2021 06:23:47 +0000 Subject: [PATCH 012/385] 8273508: Support archived heap objects in SerialGC Reviewed-by: tschatzl, ccheung --- src/hotspot/share/cds/filemap.cpp | 22 ++-- src/hotspot/share/cds/filemap.hpp | 2 +- src/hotspot/share/cds/heapShared.cpp | 55 +++++--- src/hotspot/share/cds/heapShared.hpp | 4 +- src/hotspot/share/cds/metaspaceShared.cpp | 2 +- src/hotspot/share/gc/serial/serialHeap.cpp | 11 ++ src/hotspot/share/gc/serial/serialHeap.hpp | 7 +- .../share/gc/serial/tenuredGeneration.cpp | 12 ++ .../share/gc/serial/tenuredGeneration.hpp | 2 + src/hotspot/share/gc/shared/collectedHeap.hpp | 1 + test/hotspot/jtreg/TEST.groups | 3 +- .../cds/appcds/TestSerialGCWithCDS.java | 122 ++++++++++++++++++ .../cacheObject/HeapFragmentationTest.java | 1 + 13 files changed, 211 insertions(+), 33 deletions(-) create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/TestSerialGCWithCDS.java diff --git a/src/hotspot/share/cds/filemap.cpp b/src/hotspot/share/cds/filemap.cpp index acd6ad2552f..9ba4e6ef2bb 100644 --- a/src/hotspot/share/cds/filemap.cpp +++ b/src/hotspot/share/cds/filemap.cpp @@ -1597,15 +1597,17 @@ MapArchiveResult FileMapInfo::map_regions(int regions[], int num_regions, char* return MAP_ARCHIVE_SUCCESS; } -bool FileMapInfo::read_region(int i, char* base, size_t size) { +bool FileMapInfo::read_region(int i, char* base, size_t size, bool do_commit) { FileMapRegion* si = space_at(i); - log_info(cds)("Commit %s region #%d at base " INTPTR_FORMAT " top " INTPTR_FORMAT " (%s)%s", - is_static() ? "static " : "dynamic", i, p2i(base), p2i(base + size), - shared_region_name[i], si->allow_exec() ? " exec" : ""); - if (!os::commit_memory(base, size, si->allow_exec())) { - log_error(cds)("Failed to commit %s region #%d (%s)", is_static() ? "static " : "dynamic", - i, shared_region_name[i]); - return false; + if (do_commit) { + log_info(cds)("Commit %s region #%d at base " INTPTR_FORMAT " top " INTPTR_FORMAT " (%s)%s", + is_static() ? "static " : "dynamic", i, p2i(base), p2i(base + size), + shared_region_name[i], si->allow_exec() ? " exec" : ""); + if (!os::commit_memory(base, size, si->allow_exec())) { + log_error(cds)("Failed to commit %s region #%d (%s)", is_static() ? "static " : "dynamic", + i, shared_region_name[i]); + return false; + } } if (lseek(_fd, (long)si->file_offset(), SEEK_SET) != (int)si->file_offset() || read_bytes(base, size) != size) { @@ -1646,7 +1648,7 @@ MapArchiveResult FileMapInfo::map_region(int i, intx addr_delta, char* mapped_ba // that covers all the FileMapRegions to ensure all regions can be mapped. However, Windows // can't mmap into a ReservedSpace, so we just os::read() the data. We're going to patch all the // regions anyway, so there's no benefit for mmap anyway. - if (!read_region(i, requested_addr, size)) { + if (!read_region(i, requested_addr, size, /* do_commit = */ true)) { log_info(cds)("Failed to read %s shared space into reserved space at " INTPTR_FORMAT, shared_region_name[i], p2i(requested_addr)); return MAP_ARCHIVE_OTHER_FAILURE; // oom or I/O error. @@ -1817,7 +1819,7 @@ void FileMapInfo::map_or_load_heap_regions() { } else if (HeapShared::can_load()) { success = HeapShared::load_heap_regions(this); } else { - log_info(cds)("Cannot use CDS heap data. UseG1GC or UseEpsilonGC are required."); + log_info(cds)("Cannot use CDS heap data. UseEpsilonGC, UseG1GC or UseSerialGC are required."); } } diff --git a/src/hotspot/share/cds/filemap.hpp b/src/hotspot/share/cds/filemap.hpp index bf6a724f2fb..2fa528e6927 100644 --- a/src/hotspot/share/cds/filemap.hpp +++ b/src/hotspot/share/cds/filemap.hpp @@ -477,7 +477,7 @@ public: int first_region_idx) NOT_CDS_JAVA_HEAP_RETURN; bool has_heap_regions() NOT_CDS_JAVA_HEAP_RETURN_(false); MemRegion get_heap_regions_range_with_current_oop_encoding_mode() NOT_CDS_JAVA_HEAP_RETURN_(MemRegion()); - bool read_region(int i, char* base, size_t size); + bool read_region(int i, char* base, size_t size, bool do_commit); char* map_bitmap_region(); void unmap_region(int i); bool verify_region_checksum(int i); diff --git a/src/hotspot/share/cds/heapShared.cpp b/src/hotspot/share/cds/heapShared.cpp index 821e6594faa..7d88f802f90 100644 --- a/src/hotspot/share/cds/heapShared.cpp +++ b/src/hotspot/share/cds/heapShared.cpp @@ -1586,7 +1586,7 @@ class PatchLoadedRegionPointers: public BitMapClosure { }; int HeapShared::init_loaded_regions(FileMapInfo* mapinfo, LoadedArchiveHeapRegion* loaded_regions, - uintptr_t* buffer_ret) { + MemRegion& archive_space) { size_t total_bytes = 0; int num_loaded_regions = 0; for (int i = MetaspaceShared::first_archive_heap_region; @@ -1604,12 +1604,16 @@ int HeapShared::init_loaded_regions(FileMapInfo* mapinfo, LoadedArchiveHeapRegio } assert(is_aligned(total_bytes, HeapWordSize), "must be"); - uintptr_t buffer = (uintptr_t) - Universe::heap()->allocate_loaded_archive_space(total_bytes / HeapWordSize); - _loaded_heap_bottom = buffer; - _loaded_heap_top = buffer + total_bytes; + size_t word_size = total_bytes / HeapWordSize; + HeapWord* buffer = Universe::heap()->allocate_loaded_archive_space(word_size); + if (buffer == nullptr) { + return 0; + } + + archive_space = MemRegion(buffer, word_size); + _loaded_heap_bottom = (uintptr_t)archive_space.start(); + _loaded_heap_top = _loaded_heap_bottom + total_bytes; - *buffer_ret = buffer; return num_loaded_regions; } @@ -1638,15 +1642,17 @@ bool HeapShared::load_regions(FileMapInfo* mapinfo, LoadedArchiveHeapRegion* loa LoadedArchiveHeapRegion* ri = &loaded_regions[i]; FileMapRegion* r = mapinfo->space_at(ri->_region_index); - if (!mapinfo->read_region(ri->_region_index, (char*)load_address, r->used())) { + if (!mapinfo->read_region(ri->_region_index, (char*)load_address, r->used(), /* do_commit = */ false)) { // There's no easy way to free the buffer, so we will fill it with zero later // in fill_failed_loaded_region(), and it will eventually be GC'ed. log_warning(cds)("Loading of heap region %d has failed. Archived objects are disabled", i); _loading_failed = true; return false; } - log_info(cds)("Loaded heap region #%d at base " INTPTR_FORMAT " size = " SIZE_FORMAT_W(8) " bytes, delta = " INTX_FORMAT, - ri->_region_index, load_address, ri->_region_size, ri->_runtime_offset); + log_info(cds)("Loaded heap region #%d at base " INTPTR_FORMAT " top " INTPTR_FORMAT + " size " SIZE_FORMAT_W(6) " delta " INTX_FORMAT, + ri->_region_index, load_address, load_address + ri->_region_size, + ri->_region_size, ri->_runtime_offset); uintptr_t oopmap = bitmap_base + r->oopmap_offset(); BitMapView bm((BitMap::bm_word_t*)oopmap, r->oopmap_size_in_bits()); @@ -1675,10 +1681,14 @@ bool HeapShared::load_heap_regions(FileMapInfo* mapinfo) { LoadedArchiveHeapRegion loaded_regions[MetaspaceShared::max_num_heap_regions]; memset(loaded_regions, 0, sizeof(loaded_regions)); - uintptr_t buffer; - int num_loaded_regions = init_loaded_regions(mapinfo, loaded_regions, &buffer); - sort_loaded_regions(loaded_regions, num_loaded_regions, buffer); - if (!load_regions(mapinfo, loaded_regions, num_loaded_regions, buffer)) { + MemRegion archive_space; + int num_loaded_regions = init_loaded_regions(mapinfo, loaded_regions, archive_space); + if (num_loaded_regions <= 0) { + return false; + } + sort_loaded_regions(loaded_regions, num_loaded_regions, (uintptr_t)archive_space.start()); + if (!load_regions(mapinfo, loaded_regions, num_loaded_regions, (uintptr_t)archive_space.start())) { + assert(_loading_failed, "must be"); return false; } @@ -1711,7 +1721,15 @@ class VerifyLoadedHeapEmbeddedPointers: public BasicOopIterateClosure { } }; -void HeapShared::verify_loaded_heap() { +void HeapShared::finish_initialization() { + if (is_loaded()) { + HeapWord* bottom = (HeapWord*)_loaded_heap_bottom; + HeapWord* top = (HeapWord*)_loaded_heap_top; + + MemRegion archive_space = MemRegion(bottom, top); + Universe::heap()->complete_loaded_archive_space(archive_space); + } + if (VerifyArchivedFields <= 0 || !is_loaded()) { return; } @@ -1739,9 +1757,12 @@ void HeapShared::verify_loaded_heap() { void HeapShared::fill_failed_loaded_region() { assert(_loading_failed, "must be"); - HeapWord* bottom = (HeapWord*)_loaded_heap_bottom; - HeapWord* top = (HeapWord*)_loaded_heap_top; - Universe::heap()->fill_with_objects(bottom, top - bottom); + if (_loaded_heap_bottom != 0) { + assert(_loaded_heap_top != 0, "must be"); + HeapWord* bottom = (HeapWord*)_loaded_heap_bottom; + HeapWord* top = (HeapWord*)_loaded_heap_top; + Universe::heap()->fill_with_objects(bottom, top - bottom); + } } #endif // INCLUDE_CDS_JAVA_HEAP diff --git a/src/hotspot/share/cds/heapShared.hpp b/src/hotspot/share/cds/heapShared.hpp index 2809825a204..0a673c51e86 100644 --- a/src/hotspot/share/cds/heapShared.hpp +++ b/src/hotspot/share/cds/heapShared.hpp @@ -170,7 +170,7 @@ public: // Can this VM load the objects from archived heap regions into the heap at start-up? static bool can_load() NOT_CDS_JAVA_HEAP_RETURN_(false); - static void verify_loaded_heap() NOT_CDS_JAVA_HEAP_RETURN; + static void finish_initialization() NOT_CDS_JAVA_HEAP_RETURN; static bool is_loaded() { CDS_JAVA_HEAP_ONLY(return _is_loaded;) NOT_CDS_JAVA_HEAP(return false;) @@ -346,7 +346,7 @@ private: static void init_archived_fields_for(Klass* k, const ArchivedKlassSubGraphInfoRecord* record); static int init_loaded_regions(FileMapInfo* mapinfo, LoadedArchiveHeapRegion* loaded_regions, - uintptr_t* buffer_ret); + MemRegion& archive_space); static void sort_loaded_regions(LoadedArchiveHeapRegion* loaded_regions, int num_loaded_regions, uintptr_t buffer); static bool load_regions(FileMapInfo* mapinfo, LoadedArchiveHeapRegion* loaded_regions, diff --git a/src/hotspot/share/cds/metaspaceShared.cpp b/src/hotspot/share/cds/metaspaceShared.cpp index a884cbd0c00..741e9cd680f 100644 --- a/src/hotspot/share/cds/metaspaceShared.cpp +++ b/src/hotspot/share/cds/metaspaceShared.cpp @@ -1434,7 +1434,7 @@ void MetaspaceShared::initialize_shared_spaces() { // Finish up archived heap initialization. These must be // done after ReadClosure. static_mapinfo->patch_heap_embedded_pointers(); - HeapShared::verify_loaded_heap(); + HeapShared::finish_initialization(); // Close the mapinfo file static_mapinfo->close(); diff --git a/src/hotspot/share/gc/serial/serialHeap.cpp b/src/hotspot/share/gc/serial/serialHeap.cpp index 19ca138d8d1..0c506cd8d59 100644 --- a/src/hotspot/share/gc/serial/serialHeap.cpp +++ b/src/hotspot/share/gc/serial/serialHeap.cpp @@ -30,6 +30,7 @@ #include "gc/shared/strongRootsScope.hpp" #include "gc/shared/suspendibleThreadSet.hpp" #include "memory/universe.hpp" +#include "runtime/mutexLocker.hpp" #include "services/memoryManager.hpp" SerialHeap* SerialHeap::heap() { @@ -112,3 +113,13 @@ void SerialHeap::safepoint_synchronize_end() { SuspendibleThreadSet::desynchronize(); } } + +HeapWord* SerialHeap::allocate_loaded_archive_space(size_t word_size) { + MutexLocker ml(Heap_lock); + return old_gen()->allocate(word_size, false /* is_tlab */); +} + +void SerialHeap::complete_loaded_archive_space(MemRegion archive_space) { + assert(old_gen()->used_region().contains(archive_space), "Archive space not contained in old gen"); + old_gen()->complete_loaded_archive_space(archive_space); +} diff --git a/src/hotspot/share/gc/serial/serialHeap.hpp b/src/hotspot/share/gc/serial/serialHeap.hpp index 8e79f21971c..208a997ad5f 100644 --- a/src/hotspot/share/gc/serial/serialHeap.hpp +++ b/src/hotspot/share/gc/serial/serialHeap.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -83,6 +83,11 @@ public: virtual void safepoint_synchronize_begin(); virtual void safepoint_synchronize_end(); + + // Support for loading objects from CDS archive into the heap + bool can_load_archived_objects() const { return true; } + HeapWord* allocate_loaded_archive_space(size_t size); + void complete_loaded_archive_space(MemRegion archive_space); }; #endif // SHARE_GC_SERIAL_SERIALHEAP_HPP diff --git a/src/hotspot/share/gc/serial/tenuredGeneration.cpp b/src/hotspot/share/gc/serial/tenuredGeneration.cpp index 6eeb548ce6d..1aec978b382 100644 --- a/src/hotspot/share/gc/serial/tenuredGeneration.cpp +++ b/src/hotspot/share/gc/serial/tenuredGeneration.cpp @@ -219,6 +219,18 @@ void TenuredGeneration::object_iterate(ObjectClosure* blk) { _the_space->object_iterate(blk); } +void TenuredGeneration::complete_loaded_archive_space(MemRegion archive_space) { + // Create the BOT for the archive space. + TenuredSpace* space = (TenuredSpace*)_the_space; + space->initialize_threshold(); + HeapWord* start = archive_space.start(); + while (start < archive_space.end()) { + size_t word_size = _the_space->block_size(start); + space->alloc_block(start, start + word_size); + start += word_size; + } +} + void TenuredGeneration::save_marks() { _the_space->set_saved_mark(); } diff --git a/src/hotspot/share/gc/serial/tenuredGeneration.hpp b/src/hotspot/share/gc/serial/tenuredGeneration.hpp index eb60c775df1..44153320f6c 100644 --- a/src/hotspot/share/gc/serial/tenuredGeneration.hpp +++ b/src/hotspot/share/gc/serial/tenuredGeneration.hpp @@ -74,6 +74,8 @@ class TenuredGeneration: public CardGeneration { // Iteration void object_iterate(ObjectClosure* blk); + void complete_loaded_archive_space(MemRegion archive_space); + virtual inline HeapWord* allocate(size_t word_size, bool is_tlab); virtual inline HeapWord* par_allocate(size_t word_size, bool is_tlab); diff --git a/src/hotspot/share/gc/shared/collectedHeap.hpp b/src/hotspot/share/gc/shared/collectedHeap.hpp index 12a58dfa98a..6e78724c133 100644 --- a/src/hotspot/share/gc/shared/collectedHeap.hpp +++ b/src/hotspot/share/gc/shared/collectedHeap.hpp @@ -485,6 +485,7 @@ class CollectedHeap : public CHeapObj { // (usually as a snapshot of the old generation). virtual bool can_load_archived_objects() const { return false; } virtual HeapWord* allocate_loaded_archive_space(size_t size) { return NULL; } + virtual void complete_loaded_archive_space(MemRegion archive_space) { } virtual bool is_oop(oop object) const; // Non product verification and debugging. diff --git a/test/hotspot/jtreg/TEST.groups b/test/hotspot/jtreg/TEST.groups index 27c4f67fc27..d0b34218f6b 100644 --- a/test/hotspot/jtreg/TEST.groups +++ b/test/hotspot/jtreg/TEST.groups @@ -367,8 +367,9 @@ hotspot_appcds_dynamic = \ -runtime/cds/appcds/SharedArchiveConsistency.java \ -runtime/cds/appcds/StaticArchiveWithLambda.java \ -runtime/cds/appcds/TestCombinedCompressedFlags.java \ - -runtime/cds/appcds/TestZGCWithCDS.java \ -runtime/cds/appcds/TestEpsilonGCWithCDS.java \ + -runtime/cds/appcds/TestSerialGCWithCDS.java \ + -runtime/cds/appcds/TestZGCWithCDS.java \ -runtime/cds/appcds/UnusedCPDuringDump.java \ -runtime/cds/appcds/VerifierTest_1B.java diff --git a/test/hotspot/jtreg/runtime/cds/appcds/TestSerialGCWithCDS.java b/test/hotspot/jtreg/runtime/cds/appcds/TestSerialGCWithCDS.java new file mode 100644 index 00000000000..a7c8a87961c --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/TestSerialGCWithCDS.java @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 Loading CDS archived heap objects into SerialGC + * @bug 8234679 + * @requires vm.cds + * @requires vm.gc.Serial + * @requires vm.gc.G1 + * + * @comment don't run this test if any -XX::+Use???GC options are specified, since they will + * interfere with the the test. + * @requires vm.gc == null + * + * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds + * @compile test-classes/Hello.java + * @run driver TestSerialGCWithCDS + */ + +import jdk.test.lib.Platform; +import jdk.test.lib.process.OutputAnalyzer; + +public class TestSerialGCWithCDS { + public final static String HELLO = "Hello World"; + static String helloJar; + + public static void main(String... args) throws Exception { + helloJar = JarBuilder.build("hello", "Hello"); + + // Check if we can use SerialGC during dump time, or run time, or both. + test(false, true); + test(true, false); + test(true, true); + + // We usually have 2 heap regions. To increase test coverage, we can have 3 heap regions + // by using "-Xmx256m -XX:ObjectAlignmentInBytes=64" + if (Platform.is64bit()) test(false, true, true); + } + + final static String G1 = "-XX:+UseG1GC"; + final static String Serial = "-XX:+UseSerialGC"; + + static void test(boolean dumpWithSerial, boolean execWithSerial) throws Exception { + test(dumpWithSerial, execWithSerial, false); + } + + static void test(boolean dumpWithSerial, boolean execWithSerial, boolean useSmallRegions) throws Exception { + String dumpGC = dumpWithSerial ? Serial : G1; + String execGC = execWithSerial ? Serial : G1; + String small1 = useSmallRegions ? "-Xmx256m" : "-showversion"; + String small2 = useSmallRegions ? "-XX:ObjectAlignmentInBytes=64" : "-showversion"; + OutputAnalyzer out; + + System.out.println("0. Dump with " + dumpGC); + out = TestCommon.dump(helloJar, + new String[] {"Hello"}, + dumpGC, + small1, + small2, + "-Xlog:cds"); + out.shouldContain("Dumping shared data to file:"); + out.shouldHaveExitValue(0); + + System.out.println("1. Exec with " + execGC); + out = TestCommon.exec(helloJar, + execGC, + small1, + small2, + "-Xlog:cds", + "Hello"); + out.shouldContain(HELLO); + out.shouldHaveExitValue(0); + + int n = 2; + if (dumpWithSerial == false && execWithSerial == true) { + // We dumped with G1, so we have an archived heap. At exec time, try to load them into + // a small SerialGC heap that may be too small. + String[] sizes = { + "4m", // usually this will success load the archived heap + "2m", // usually this will fail to loade th archived heap, but app can launch + "1m" // usually this will cause VM launch to fail with "Too small maximum heap" + }; + for (String sz : sizes) { + String xmx = "-Xmx" + sz; + System.out.println("=======\n" + n + ". Exec with " + execGC + " " + xmx); + out = TestCommon.exec(helloJar, + execGC, + small1, + small2, + xmx, + "-Xlog:cds", + "Hello"); + if (out.getExitValue() == 0) { + out.shouldContain(HELLO); + } else { + out.shouldContain("Too small maximum heap"); + } + n++; + } + } + } +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/cacheObject/HeapFragmentationTest.java b/test/hotspot/jtreg/runtime/cds/appcds/cacheObject/HeapFragmentationTest.java index ca1df0c9487..baecace9549 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/cacheObject/HeapFragmentationTest.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/cacheObject/HeapFragmentationTest.java @@ -28,6 +28,7 @@ * @bug 8214455 * @requires vm.cds.write.archived.java.heap * @requires (sun.arch.data.model == "64" & os.maxMemory > 4g) + * @requires vm.gc == "null" * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds * @build HeapFragmentationApp * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar HeapFragmentationApp.jar HeapFragmentationApp -- GitLab From 961dcffc862a4830fbf26791835a98c12d4b513e Mon Sep 17 00:00:00 2001 From: Alexander Scherbatiy Date: Tue, 28 Sep 2021 09:26:51 +0000 Subject: [PATCH 013/385] 8273581: Change the mechanism by which JDK loads the platform-specific FontManager class Reviewed-by: prr, psadhukhan, azvegint, aivanov, serb --- .../classes/sun/font/PlatformFontInfo.java | 37 +++++++++++ .../classes/sun/font/FontManagerFactory.java | 63 ++++--------------- .../classes/sun/font/PlatformFontInfo.java | 39 ++++++++++++ .../unix/native/libawt/awt/awt_LoadLibrary.c | 28 +-------- .../classes/sun/font/PlatformFontInfo.java | 39 ++++++++++++ .../font/CheckFontManagerSystemProperty.java | 46 ++++++++++++++ 6 files changed, 175 insertions(+), 77 deletions(-) create mode 100644 src/java.desktop/macosx/classes/sun/font/PlatformFontInfo.java create mode 100644 src/java.desktop/unix/classes/sun/font/PlatformFontInfo.java create mode 100644 src/java.desktop/windows/classes/sun/font/PlatformFontInfo.java create mode 100644 test/jdk/sun/awt/font/CheckFontManagerSystemProperty.java diff --git a/src/java.desktop/macosx/classes/sun/font/PlatformFontInfo.java b/src/java.desktop/macosx/classes/sun/font/PlatformFontInfo.java new file mode 100644 index 00000000000..b0ac181a884 --- /dev/null +++ b/src/java.desktop/macosx/classes/sun/font/PlatformFontInfo.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.font; + +final class PlatformFontInfo { + + /** + * The method is only to be called via the + * {@code FontManagerFactory.getInstance()} factory method. + */ + static FontManager createFontManager() { + return new CFontManager(); + } +} diff --git a/src/java.desktop/share/classes/sun/font/FontManagerFactory.java b/src/java.desktop/share/classes/sun/font/FontManagerFactory.java index fb8aa81f994..fa634c68e0c 100644 --- a/src/java.desktop/share/classes/sun/font/FontManagerFactory.java +++ b/src/java.desktop/share/classes/sun/font/FontManagerFactory.java @@ -25,72 +25,33 @@ package sun.font; -import java.awt.AWTError; -import java.awt.Font; -import java.awt.GraphicsEnvironment; -import java.awt.Toolkit; -import java.security.AccessController; -import java.security.PrivilegedAction; - -import sun.security.action.GetPropertyAction; - - /** * Factory class used to retrieve a valid FontManager instance for the current * platform. * - * A default implementation is given for Linux, Solaris and Windows. - * You can alter the behaviour of the {@link #getInstance()} method by setting - * the {@code sun.font.fontmanager} property. For example: - * {@code sun.font.fontmanager=sun.awt.X11FontManager} + * A default implementation is given for Linux, Mac OS and Windows. */ public final class FontManagerFactory { /** Our singleton instance. */ - private static FontManager instance = null; - - private static final String DEFAULT_CLASS; - static { - if (FontUtilities.isWindows) { - DEFAULT_CLASS = "sun.awt.Win32FontManager"; - } else if (FontUtilities.isMacOSX) { - DEFAULT_CLASS = "sun.font.CFontManager"; - } else { - DEFAULT_CLASS = "sun.awt.X11FontManager"; - } - } + private static volatile FontManager instance; /** * Get a valid FontManager implementation for the current platform. * * @return a valid FontManager instance for the current platform */ - @SuppressWarnings("removal") - public static synchronized FontManager getInstance() { - - if (instance != null) { - return instance; - } - - AccessController.doPrivileged(new PrivilegedAction() { - - public Object run() { - try { - String fmClassName = - System.getProperty("sun.font.fontmanager", - DEFAULT_CLASS); - ClassLoader cl = ClassLoader.getSystemClassLoader(); - Class fmClass = Class.forName(fmClassName, true, cl); - instance = - (FontManager) fmClass.getDeclaredConstructor().newInstance(); - } catch (ReflectiveOperationException ex) { - throw new InternalError(ex); - + public static FontManager getInstance() { + + FontManager result = instance; + if (result == null) { + synchronized (FontManagerFactory.class) { + result = instance; + if (result == null) { + instance = result = PlatformFontInfo.createFontManager(); } - return null; } - }); - - return instance; + } + return result; } } diff --git a/src/java.desktop/unix/classes/sun/font/PlatformFontInfo.java b/src/java.desktop/unix/classes/sun/font/PlatformFontInfo.java new file mode 100644 index 00000000000..db25b731bb6 --- /dev/null +++ b/src/java.desktop/unix/classes/sun/font/PlatformFontInfo.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.font; + +import sun.awt.X11FontManager; + +final class PlatformFontInfo { + + /** + * The method is only to be called via the + * {@code FontManagerFactory.getInstance()} factory method. + */ + static FontManager createFontManager() { + return new X11FontManager(); + } +} diff --git a/src/java.desktop/unix/native/libawt/awt/awt_LoadLibrary.c b/src/java.desktop/unix/native/libawt/awt/awt_LoadLibrary.c index fbd6ce9d14d..b2dedca351c 100644 --- a/src/java.desktop/unix/native/libawt/awt/awt_LoadLibrary.c +++ b/src/java.desktop/unix/native/libawt/awt/awt_LoadLibrary.c @@ -109,8 +109,6 @@ AWT_OnLoad(JavaVM *vm, void *reserved) struct utsname name; JNIEnv *env = (JNIEnv *)JNU_GetEnv(vm, JNI_VERSION_1_2); void *v; - jstring fmanager = NULL; - jstring fmProp = NULL; if (awtHandle != NULL) { /* Avoid several loading attempts */ @@ -126,29 +124,15 @@ AWT_OnLoad(JavaVM *vm, void *reserved) p = strrchr(buf, '/'); #endif /* - * The code below is responsible for: - * 1. Loading appropriate awt library, i.e. libawt_xawt or libawt_headless - * 2. Set the "sun.font.fontmanager" system property. + * The code below is responsible for + * loading appropriate awt library, i.e. libawt_xawt or libawt_headless */ - fmProp = (*env)->NewStringUTF(env, "sun.font.fontmanager"); - CHECK_EXCEPTION_FATAL(env, "Could not allocate font manager property"); - #ifdef MACOSX - fmanager = (*env)->NewStringUTF(env, "sun.font.CFontManager"); tk = LWAWT_PATH; #else - fmanager = (*env)->NewStringUTF(env, "sun.awt.X11FontManager"); tk = XAWT_PATH; #endif - CHECK_EXCEPTION_FATAL(env, "Could not allocate font manager name"); - - if (fmanager && fmProp) { - JNU_CallStaticMethodByName(env, NULL, "java/lang/System", "setProperty", - "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", - fmProp, fmanager); - CHECK_EXCEPTION_FATAL(env, "Could not allocate set properties"); - } #ifndef MACOSX if (AWTIsHeadless()) { @@ -161,14 +145,6 @@ AWT_OnLoad(JavaVM *vm, void *reserved) strncpy(p, tk, MAXPATHLEN-len-1); #endif - if (fmProp) { - (*env)->DeleteLocalRef(env, fmProp); - } - if (fmanager) { - (*env)->DeleteLocalRef(env, fmanager); - } - - #ifndef STATIC_BUILD jstring jbuf = JNU_NewStringPlatform(env, buf); CHECK_EXCEPTION_FATAL(env, "Could not allocate library name"); diff --git a/src/java.desktop/windows/classes/sun/font/PlatformFontInfo.java b/src/java.desktop/windows/classes/sun/font/PlatformFontInfo.java new file mode 100644 index 00000000000..ca3a21a2137 --- /dev/null +++ b/src/java.desktop/windows/classes/sun/font/PlatformFontInfo.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.font; + +import sun.awt.Win32FontManager; + +final class PlatformFontInfo { + + /** + * The method is only to be called via the + * {@code FontManagerFactory.getInstance()} factory method. + */ + static FontManager createFontManager() { + return new Win32FontManager(); + } +} diff --git a/test/jdk/sun/awt/font/CheckFontManagerSystemProperty.java b/test/jdk/sun/awt/font/CheckFontManagerSystemProperty.java new file mode 100644 index 00000000000..197c5784c5d --- /dev/null +++ b/test/jdk/sun/awt/font/CheckFontManagerSystemProperty.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Toolkit; + +/** + * @test + * @bug 8273581 + * @summary verify the "sun.font.fontmanager" system property is not set + * @run main/othervm -Djava.awt.headless=true CheckFontManagerSystemProperty + */ + +public class CheckFontManagerSystemProperty { + + public static void main(String[] args) { + // force AWT library loading + Toolkit toolkit = Toolkit.getDefaultToolkit(); + if (toolkit == null) { + throw new RuntimeException("Toolkit not found!"); + } + String tkProp = System.getProperty("sun.font.fontmanager"); + if (tkProp != null) { + throw new RuntimeException("tkProp = " + tkProp); + } + } +} -- GitLab From 79865cd797737f22cd4efe7e9c03ddbb86095e64 Mon Sep 17 00:00:00 2001 From: Tongbao Zhang Date: Tue, 28 Sep 2021 12:32:39 +0000 Subject: [PATCH 014/385] 8274259: G1: assert(check_alignment(result)) failed: address not aligned: 0x00000008baadbabe after JDK-8270009 Reviewed-by: tschatzl, sjohanss --- src/hotspot/share/gc/g1/g1CollectedHeap.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index f59485f3407..78f93cf1dcd 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp @@ -2752,6 +2752,7 @@ void G1CollectedHeap::verify_before_young_collection(G1HeapVerifier::G1VerifyTyp return; } Ticks start = Ticks::now(); + _verifier->prepare_for_verify(); _verifier->verify_region_sets_optional(); _verifier->verify_dirty_young_regions(); if (VerifyRememberedSets) { -- GitLab From be4037374520917d5a0ed54eebb3d5d6d100d429 Mon Sep 17 00:00:00 2001 From: Artem Semenov Date: Tue, 28 Sep 2021 16:08:30 +0000 Subject: [PATCH 015/385] 8274381: missing CAccessibility definitions in JNI code Reviewed-by: pbansal, ant, kizune --- .../macosx/native/libawt_lwawt/awt/JavaAccessibilityUtilities.m | 1 + .../native/libawt_lwawt/awt/a11y/CommonComponentAccessibility.m | 1 + 2 files changed, 2 insertions(+) diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/JavaAccessibilityUtilities.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/JavaAccessibilityUtilities.m index 662c8b0287b..005d26954c2 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/JavaAccessibilityUtilities.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/JavaAccessibilityUtilities.m @@ -51,6 +51,7 @@ static jclass sjc_CAccessibility = NULL; NSSize getAxComponentSize(JNIEnv *env, jobject axComponent, jobject component) { + GET_CACCESSIBILITY_CLASS_RETURN(NSZeroSize); DECLARE_CLASS_RETURN(jc_Dimension, "java/awt/Dimension", NSZeroSize); DECLARE_FIELD_RETURN(jf_width, jc_Dimension, "width", "I", NSZeroSize); DECLARE_FIELD_RETURN(jf_height, jc_Dimension, "height", "I", NSZeroSize); diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/CommonComponentAccessibility.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/CommonComponentAccessibility.m index 9fe7ce4e520..c18ef863be7 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/CommonComponentAccessibility.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/CommonComponentAccessibility.m @@ -1081,6 +1081,7 @@ static jobject sAccessibilityClass = NULL; { JNIEnv* env = [ThreadUtilities getJNIEnv]; + GET_CACCESSIBILITY_CLASS_RETURN(nil); DECLARE_CLASS_RETURN(jc_Container, "java/awt/Container", nil); DECLARE_STATIC_METHOD_RETURN(jm_accessibilityHitTest, sjc_CAccessibility, "accessibilityHitTest", "(Ljava/awt/Container;FF)Ljavax/accessibility/Accessible;", nil); -- GitLab From b36881fa3b3f37400d4f2c0bca3192d88179f2ff Mon Sep 17 00:00:00 2001 From: Artem Semenov Date: Tue, 28 Sep 2021 16:40:47 +0000 Subject: [PATCH 016/385] 8274383: JNI call of getAccessibleSelection on a wrong thread Reviewed-by: kizune, ant --- .../awt/a11y/ComboBoxAccessibility.m | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ComboBoxAccessibility.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ComboBoxAccessibility.m index 63c00414d66..0fd70eb8151 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ComboBoxAccessibility.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/ComboBoxAccessibility.m @@ -35,6 +35,12 @@ static jmethodID sjm_getAccessibleName = NULL; GET_STATIC_METHOD_RETURN(sjm_getAccessibleName, sjc_CAccessibility, "getAccessibleName", \ "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljava/lang/String;", ret); +static jmethodID sjm_getAccessibleSelection = NULL; +#define GET_ACCESSIBLESELECTION_METHOD_RETURN(ret) \ + GET_CACCESSIBILITY_CLASS_RETURN(ret); \ + GET_STATIC_METHOD_RETURN(sjm_getAccessibleSelection, sjc_CAccessibility, "getAccessibleSelection", \ + "(Ljavax/accessibility/AccessibleContext;Ljava/awt/Component;)Ljavax/accessibility/AccessibleSelection;", ret); + @implementation ComboBoxAccessibility // NSAccessibilityElement protocol methods @@ -43,15 +49,21 @@ static jmethodID sjm_getAccessibleName = NULL; JNIEnv *env = [ThreadUtilities getJNIEnv]; jobject axContext = [self axContextWithEnv:env]; if (axContext == NULL) return nil; - jclass axContextClass = (*env)->GetObjectClass(env, axContext); - DECLARE_METHOD_RETURN(jm_getAccessibleSelection, axContextClass, "getAccessibleSelection", "(I)Ljavax/accessibility/Accessible;", nil); - jobject axSelectedChild = (*env)->CallObjectMethod(env, axContext, jm_getAccessibleSelection, 0); + GET_ACCESSIBLESELECTION_METHOD_RETURN(nil); + jobject axSelection = (*env)->CallStaticObjectMethod(env, sjc_CAccessibility, sjm_getAccessibleSelection, axContext, self->fComponent); + CHECK_EXCEPTION(); + if (axSelection == NULL) { + return nil; + } + jclass axSelectionClass = (*env)->GetObjectClass(env, axSelection); + DECLARE_METHOD_RETURN(jm_getAccessibleSelection, axSelectionClass, "getAccessibleSelection", "(I)Ljavax/accessibility/Accessible;", nil); + jobject axSelectedChild = (*env)->CallObjectMethod(env, axSelection, jm_getAccessibleSelection, 0); CHECK_EXCEPTION(); + (*env)->DeleteLocalRef(env, axSelection); (*env)->DeleteLocalRef(env, axContext); if (axSelectedChild == NULL) { return nil; } - GET_CACCESSIBILITY_CLASS_RETURN(nil); GET_ACCESSIBLENAME_METHOD_RETURN(nil); jobject childName = (*env)->CallStaticObjectMethod(env, sjc_CAccessibility, sjm_getAccessibleName, axSelectedChild, fComponent); CHECK_EXCEPTION(); -- GitLab From 94f5e807c91674cf79e543a66cff1819206a790b Mon Sep 17 00:00:00 2001 From: Sergey Tsypanov Date: Tue, 28 Sep 2021 17:18:55 +0000 Subject: [PATCH 017/385] 8274276: Cache normalizedBase URL in URLClassPath.FileLoader Reviewed-by: dfuchs --- .../share/classes/jdk/internal/loader/URLClassPath.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/java.base/share/classes/jdk/internal/loader/URLClassPath.java b/src/java.base/share/classes/jdk/internal/loader/URLClassPath.java index 62c78980206..5ee7fdcdd55 100644 --- a/src/java.base/share/classes/jdk/internal/loader/URLClassPath.java +++ b/src/java.base/share/classes/jdk/internal/loader/URLClassPath.java @@ -597,7 +597,7 @@ public class URLClassPath { /* * Returns the base URL for this Loader. */ - URL getBaseURL() { + final URL getBaseURL() { return base; } @@ -1199,7 +1199,8 @@ public class URLClassPath { */ private static class FileLoader extends Loader { /* Canonicalized File */ - private File dir; + private final File dir; + private final URL normalizedBase; /* * Creates a new FileLoader for the specified URL with a file protocol. @@ -1209,6 +1210,7 @@ public class URLClassPath { String path = url.getFile().replace('/', File.separatorChar); path = ParseUtil.decode(path); dir = (new File(path)).getCanonicalFile(); + normalizedBase = new URL(getBaseURL(), "."); } /* @@ -1227,7 +1229,6 @@ public class URLClassPath { Resource getResource(final String name, boolean check) { final URL url; try { - URL normalizedBase = new URL(getBaseURL(), "."); url = new URL(getBaseURL(), ParseUtil.encodePath(name, false)); if (url.getFile().startsWith(normalizedBase.getFile()) == false) { -- GitLab From 6f4cefbcbaad38dcacd4e047c6c232a0a7a2c19c Mon Sep 17 00:00:00 2001 From: Andrey Turbanov Date: Tue, 28 Sep 2021 17:22:27 +0000 Subject: [PATCH 018/385] 8274394: Use Optional.isEmpty instead of !Optional.isPresent in jdk.jlink Reviewed-by: alanb, mchung --- .../jdk/tools/jlink/builder/DefaultImageBuilder.java | 6 +++--- .../share/classes/jdk/tools/jlink/internal/JlinkTask.java | 4 ++-- .../jdk/tools/jlink/internal/ResourcePoolManager.java | 2 +- .../tools/jlink/internal/plugins/LegalNoticeFilePlugin.java | 2 +- src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/builder/DefaultImageBuilder.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/builder/DefaultImageBuilder.java index b1c0caef51b..9edbcc4e0bb 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/builder/DefaultImageBuilder.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/builder/DefaultImageBuilder.java @@ -281,7 +281,7 @@ public final class DefaultImageBuilder implements ImageBuilder { if (mainClassName == null) { String path = "/" + module + "/module-info.class"; Optional res = imageContent.findEntry(path); - if (!res.isPresent()) { + if (res.isEmpty()) { throw new IOException("module-info.class not found for " + module + " module"); } ByteArrayInputStream stream = new ByteArrayInputStream(res.get().contentBytes()); @@ -293,8 +293,8 @@ public final class DefaultImageBuilder implements ImageBuilder { if (mainClassName != null) { // make sure main class exists! - if (!imageContent.findEntry("/" + module + "/" + - mainClassName.replace('.', '/') + ".class").isPresent()) { + if (imageContent.findEntry("/" + module + "/" + + mainClassName.replace('.', '/') + ".class").isEmpty()) { throw new IllegalArgumentException(module + " does not have main class: " + mainClassName); } diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java index c3340320bf5..d90e4cf38e4 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java @@ -397,7 +397,7 @@ public class JlinkTask { } ModuleFinder finder = newModuleFinder(options.modulePath, options.limitMods, roots); - if (!finder.find("java.base").isPresent()) { + if (finder.find("java.base").isEmpty()) { Path defModPath = getDefaultModulePath(); if (defModPath != null) { options.modulePath.add(defModPath); @@ -517,7 +517,7 @@ public class JlinkTask { private static Path toPathLocation(ResolvedModule m) { Optional ouri = m.reference().location(); - if (!ouri.isPresent()) + if (ouri.isEmpty()) throw new InternalError(m + " does not have a location"); URI uri = ouri.get(); return Paths.get(uri); diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolManager.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolManager.java index 5a5768dfde4..d7125d103d1 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolManager.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolManager.java @@ -54,7 +54,7 @@ public class ResourcePoolManager { static Attributes readModuleAttributes(ResourcePoolModule mod) { String p = "/" + mod.name() + "/module-info.class"; Optional content = mod.findEntry(p); - if (!content.isPresent()) { + if (content.isEmpty()) { throw new PluginException("module-info.class not found for " + mod.name() + " module"); } diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/LegalNoticeFilePlugin.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/LegalNoticeFilePlugin.java index 5b6c23a6563..3911e94b360 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/LegalNoticeFilePlugin.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/LegalNoticeFilePlugin.java @@ -111,7 +111,7 @@ public final class LegalNoticeFilePlugin extends AbstractPlugin { .filter(e -> e.linkedTarget() == null) .filter(e -> Arrays.equals(e.contentBytes(), entry.contentBytes())) .findFirst(); - if (!otarget.isPresent()) { + if (otarget.isEmpty()) { if (errorIfNotSameContent) { // all legal notices of the same file name are expected // to contain the same content diff --git a/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java b/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java index 316afdbd659..bcf6a2463b3 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java @@ -890,7 +890,7 @@ public class JmodTask { // filter modules resolved from the system module finder this.modules = config.modules().stream() .map(ResolvedModule::name) - .filter(mn -> roots.contains(mn) && !system.find(mn).isPresent()) + .filter(mn -> roots.contains(mn) && system.find(mn).isEmpty()) .collect(Collectors.toSet()); this.hashesBuilder = new ModuleHashesBuilder(config, modules); -- GitLab From c57a6c62baecde0bc10bfca89e0616b0c1fbb714 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20Steen=20M=C3=B8ller?= Date: Tue, 28 Sep 2021 18:22:15 +0000 Subject: [PATCH 019/385] 8274265: Suspicious string concatenation in logTestUtils.inline.hpp Reviewed-by: clanger, mbaesken --- test/hotspot/gtest/logging/logTestUtils.inline.hpp | 2 +- test/hotspot/gtest/logging/test_logFileOutput.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/hotspot/gtest/logging/logTestUtils.inline.hpp b/test/hotspot/gtest/logging/logTestUtils.inline.hpp index e7f9f1daf89..4295c6a000f 100644 --- a/test/hotspot/gtest/logging/logTestUtils.inline.hpp +++ b/test/hotspot/gtest/logging/logTestUtils.inline.hpp @@ -32,7 +32,7 @@ #define LOG_TEST_STRING_LITERAL "a (hopefully) unique log message for testing" static const char* invalid_selection_substr[] = { - "=", "+", " ", "+=", "+=*", "*+", " +", "**", "++", ".", ",", ",," ",+", + "=", "+", " ", "+=", "+=*", "*+", " +", "**", "++", ".", ",", ",,", ",+", " *", "all+", "all*", "+all", "+all=Warning", "==Info", "=InfoWarning", "BadTag+", "logging++", "logging*+", ",=", "gc+gc+" }; diff --git a/test/hotspot/gtest/logging/test_logFileOutput.cpp b/test/hotspot/gtest/logging/test_logFileOutput.cpp index 20e3d07e894..eb5a848d316 100644 --- a/test/hotspot/gtest/logging/test_logFileOutput.cpp +++ b/test/hotspot/gtest/logging/test_logFileOutput.cpp @@ -74,7 +74,7 @@ TEST_VM(LogFileOutput, parse_invalid) { "filecount= 2", "filesize=2 ", "filecount=ab", "filesize=0xz", "filecount=1MB", "filesize=99bytes", - "filesize=9999999999999999999999999" + "filesize=9999999999999999999999999", "filecount=9999999999999999999999999" }; -- GitLab From b7425b63f6b69ba8709664377b4e037176ab6139 Mon Sep 17 00:00:00 2001 From: Alexey Ivanov Date: Tue, 28 Sep 2021 19:15:33 +0000 Subject: [PATCH 020/385] 8239502: [TEST_BUG] Test javax/swing/text/FlowView/6318524/bug6318524.java never fails Reviewed-by: serb --- .../text/FlowView/6318524/bug6318524.java | 194 ++++++++++++++++++ 1 file changed, 194 insertions(+) create mode 100644 test/jdk/javax/swing/text/FlowView/6318524/bug6318524.java diff --git a/test/jdk/javax/swing/text/FlowView/6318524/bug6318524.java b/test/jdk/javax/swing/text/FlowView/6318524/bug6318524.java new file mode 100644 index 00000000000..7445f0a3756 --- /dev/null +++ b/test/jdk/javax/swing/text/FlowView/6318524/bug6318524.java @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Dimension; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Rectangle; +import java.awt.Shape; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.util.Arrays; +import java.util.List; +import javax.imageio.ImageIO; +import javax.swing.JFrame; +import javax.swing.JTextPane; +import javax.swing.SwingUtilities; +import javax.swing.text.BadLocationException; +import javax.swing.text.Caret; +import javax.swing.text.Document; +import javax.swing.text.Position; +import javax.swing.text.SimpleAttributeSet; +import javax.swing.text.StyleConstants; +import javax.swing.text.View; + +import static java.awt.image.BufferedImage.TYPE_INT_RGB; + +/* + * @test + * @bug 6318524 8239502 + * @summary Tests that children of ParagraphView do not mess up their parents + * @run main bug6318524 + */ +/* + * Test parameters: + * -show: Show frame for visual inspection + * -save: Save the start image after the first paragraph is justified, + * and the last image before it's checked that the first paragraph + * remains justified + * -saveAll: Save images for all the intermediate steps + */ +public class bug6318524 { + private static final String LONG_WORD = "consequences"; + private static final String TEXT = "Justified: " + + LONG_WORD + " " + LONG_WORD; + private static final int REPEAT_COUNT = 18; + + private static JTextPane textPane; + private static Dimension bounds; + + private static int step = 0; + + private static Shape firstLineEndsAt; + + public static void main(String[] args) throws Throwable { + List argList = Arrays.asList(args); + + // Show frame for visual inspection + final boolean showFrame = argList.contains("-show"); + // Save images for all the intermediate steps + final boolean saveAllImages = argList.contains("-saveAll"); + // Save the start and last image only + final boolean saveImage = saveAllImages || argList.contains("-save"); + + SwingUtilities.invokeAndWait(() -> { + createUI(showFrame); + paintToImage(step++, saveAllImages); + makeLineJustified(); + paintToImage(step++, saveImage); + + firstLineEndsAt = getEndOfFirstLine(); + + moveCursorToStart(); + pressEnter(saveAllImages); + + paintToImage(step++, saveImage); + checkLineJustified(); + }); + } + + private static void createUI(boolean showFrame) { + textPane = new JTextPane(); + textPane.setText(TEXT); + + FontMetrics fm = textPane.getFontMetrics(textPane.getFont()); + int textWidth = fm.stringWidth(LONG_WORD); + int textHeight = fm.getHeight(); + bounds = new Dimension(2 * textWidth, + (REPEAT_COUNT + 3) * textHeight); + textPane.setPreferredSize(bounds); + textPane.setSize(bounds); + + if (showFrame) { + JFrame frame = new JFrame("bug6318524"); + frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + + frame.getContentPane().add(textPane); + + frame.pack(); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + } + + private static void makeLineJustified() { + SimpleAttributeSet sas = new SimpleAttributeSet(); + StyleConstants.setAlignment(sas, StyleConstants.ALIGN_JUSTIFIED); + textPane.setParagraphAttributes(sas, false); + } + + private static void moveCursorToStart() { + // Move cursor to the beginning + Caret caret = textPane.getCaret(); + caret.setDot(0); + } + + private static void pressEnter(boolean saveImages) { + Document doc = textPane.getDocument(); + try { + for (int i = 0; i < REPEAT_COUNT; i++) { + // Add a new paragraph at the beginning + doc.insertString(0, "\n", null); + // Paint the textPane after each change + paintToImage(step++, saveImages); + } + } catch (BadLocationException e) { + throw new RuntimeException(e); + } + } + + private static void checkLineJustified() { + Shape newPosition = getEndOfFirstLine(); + if (((Rectangle) firstLineEndsAt).x != ((Rectangle) newPosition).x) { + System.err.println("Old: " + firstLineEndsAt); + System.err.println("New: " + newPosition); + throw new RuntimeException("The first line of the paragraph is not justified"); + } + } + + private static Shape getEndOfFirstLine() { + try { + final View rootView = textPane.getUI().getRootView(textPane); + final View boxView = rootView.getView(0); + final View paragraphView = boxView.getView(boxView.getViewCount() - 1); + assert paragraphView.getViewCount() == 2; + final View rowView = paragraphView.getView(0); + return rowView.getView(0) + .modelToView(rowView.getEndOffset() - 1, + textPane.getBounds(), + Position.Bias.Backward); + } catch (BadLocationException e) { + throw new RuntimeException(e); + } + } + + private static void paintToImage(final int step, boolean saveImage) { + BufferedImage im = new BufferedImage(bounds.width, bounds.height, + TYPE_INT_RGB); + Graphics g = im.getGraphics(); + textPane.paint(g); + g.dispose(); + if (saveImage) { + saveImage(im, String.format("%02d.png", step)); + } + } + + private static void saveImage(BufferedImage image, String fileName) { + try { + ImageIO.write(image, "png", new File(fileName)); + } catch (IOException e) { + throw new RuntimeException(e); + } + } +} -- GitLab From 67e52a3078b0e7e522297c6008f5ac3792937c6a Mon Sep 17 00:00:00 2001 From: Alexey Ivanov Date: Tue, 28 Sep 2021 19:16:58 +0000 Subject: [PATCH 021/385] 8273634: [TEST_BUG] Improve javax/swing/text/ParagraphView/6364882/bug6364882.java Reviewed-by: serb --- .../ParagraphView/6364882/bug6364882.java | 239 ++++++++++++++++++ 1 file changed, 239 insertions(+) create mode 100644 test/jdk/javax/swing/text/ParagraphView/6364882/bug6364882.java diff --git a/test/jdk/javax/swing/text/ParagraphView/6364882/bug6364882.java b/test/jdk/javax/swing/text/ParagraphView/6364882/bug6364882.java new file mode 100644 index 00000000000..bd05d8402ad --- /dev/null +++ b/test/jdk/javax/swing/text/ParagraphView/6364882/bug6364882.java @@ -0,0 +1,239 @@ +/* + * Copyright (c) 2006, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Rectangle; +import java.awt.Shape; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import javax.imageio.ImageIO; +import javax.swing.JEditorPane; +import javax.swing.JFrame; +import javax.swing.SwingUtilities; +import javax.swing.text.AbstractDocument; +import javax.swing.text.BadLocationException; +import javax.swing.text.Position; +import javax.swing.text.View; +import javax.swing.text.html.HTMLEditorKit; + +import static java.awt.image.BufferedImage.TYPE_INT_RGB; + +/* + * @test + * @bug 6364882 8273634 + * @summary tests if broken and last lines in paragraph are not justified + * @run main bug6364882 + */ +public class bug6364882 { + private static final String TEXT = + "

    " + + "should be justified should be justified should be justified " + + "should be justified should be justified should be justified " + + "should be justified should be justified should be justified " + + "should be justified should be justified should be justified " + + "should be justified should be justified should be justified " + + "should be justified should be justified should be justified " + + "
    " + + "should not be justified
    " + + "should not be justified" + + ""; + + private static final int WIDTH = 580; + private static final int HEIGHT = 600; + + public static final String IMAGE_FILENAME = "editorPane.png"; + + private static JEditorPane editorPane; + + private static volatile List errors; + + public static void main(String[] args) throws Exception { + List argList = Arrays.asList(args); + // Show frame for visual inspection + final boolean showFrame = argList.contains("-show"); + // Save the rendered image even if the test passes + // If the test fails, the image is always saved + final boolean saveImage = argList.contains("-save"); + + SwingUtilities.invokeAndWait(() -> { + createUI(showFrame); + + BufferedImage image = paintToImage(); + errors = checkJustification(); + + if (errors.size() > 0 || saveImage) { + saveImage(image); + dumpViews(); + } + }); + + if (errors != null && errors.size() > 0) { + String message = "Test failed: " + errors.size() + " error(s)"; + System.err.println(message); + for (Error e : errors) { + e.printStackTrace(); + } + throw new RuntimeException(message + " - " + errors.get(0).getMessage()); + } + + System.out.println("Test passed"); + } + + private static void createUI(boolean showFrame) { + editorPane = new JEditorPane(); + editorPane.setEditorKit(new HTMLEditorKit()); + ((AbstractDocument) editorPane.getDocument()).setAsynchronousLoadPriority(-1); + editorPane.setText(TEXT); + + editorPane.setSize(WIDTH, HEIGHT); + + if (showFrame) { + JFrame frame = new JFrame("bug6364882"); + frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + + frame.getContentPane().add(editorPane); + + frame.setSize(WIDTH, HEIGHT); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + } + + private static List checkJustification() { + final List errors = new ArrayList<>(15); + try { + final View rootView = editorPane.getUI().getRootView(editorPane); + final View blockView = rootView.getView(0); + assert blockView.getViewCount() == 2 + : "blockView doesn't have 2 child views"; + final View bodyView = blockView.getView(1); + final View paragraphView = bodyView.getView(0); + // Expected to have 6 rows in the paragraph + assert paragraphView.getViewCount() == 6 + : "paragraph doesn't have 6 rows of text"; + + final Rectangle bounds = editorPane.getBounds(); + + // Three rows should be justified + final int oneX = getEndOfLineX(paragraphView.getView(0), bounds); + if (oneX < bounds.width - 15) { + errors.add(new Error("Text is not justified at line " + 0 + ": " + + oneX + " < " + (bounds.width - 15))); + } + for (int i = 1; i < 2; i++) { + int lineX = getEndOfLineX(paragraphView.getView(i), + bounds); + if (oneX != lineX) { + errors.add(new Error("Text is not justified at line " + i + + ": " + oneX + " != " + lineX)); + } + } + + // Fourth row should not be justified + final int fourX = getEndOfLineX(paragraphView.getView(3), bounds); + if (oneX == fourX) { + errors.add(new Error("Fourth line is justified: " + + oneX + " vs " + fourX)); + } + if (fourX > (bounds.width - bounds.width / 4)) { + errors.add(new Error("Fourth line is justified: " + + fourX + " > " + + (bounds.width - bounds.width / 4))); + } + + // Fifth and sixth lines should not be justified + final int fiveX = getEndOfLineX(paragraphView.getView(4), bounds); + if (oneX == fiveX) { + errors.add(new Error("Fifth line is justified: " + + oneX + "==" + fiveX)); + } + if (fiveX > bounds.width / 2) { + errors.add(new Error("Fifth line is justified: " + + fiveX + " > " + (bounds.width / 2))); + } + if (fiveX > fourX) { + errors.add(new Error("Fifth line is justified: " + + fiveX + " > " + fourX)); + } + final int sixX = getEndOfLineX(paragraphView.getView(5), bounds); + if (fiveX != sixX) { + errors.add(new Error("Fifth and sixth lines aren't of the " + + "same width: " + fiveX + " != " + sixX)); + } + + return errors; + } catch (BadLocationException e) { + throw new RuntimeException(e); + } + } + + private static int getEndOfLineX(final View rowView, + final Rectangle bounds) + throws BadLocationException { + final View inlineView = rowView.getView(0); + Shape loc = inlineView.modelToView(inlineView.getEndOffset() - 1, + bounds, + Position.Bias.Backward); + return loc instanceof Rectangle + ? ((Rectangle) loc).x + : loc.getBounds().x; + } + + private static BufferedImage paintToImage() { + Dimension bounds = editorPane.getSize(); + BufferedImage im = new BufferedImage(bounds.width, bounds.height, + TYPE_INT_RGB); + Graphics g = im.getGraphics(); + editorPane.paint(g); + g.dispose(); + return im; + } + + private static void saveImage(BufferedImage image) { + try { + ImageIO.write(image, "png", new File(IMAGE_FILENAME)); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private static void dumpViews() { + final View view = editorPane.getUI().getRootView(editorPane); + dumpViews(view, ""); + } + + private static void dumpViews(final View view, final String indent) { + System.out.println(indent + view.getClass().getName() + ": " + + view.getStartOffset() + ", " + view.getEndOffset() + + "; span: " + view.getPreferredSpan(View.X_AXIS)); + final String nestedIndent = indent + " "; + for (int i = 0; i < view.getViewCount(); i++) { + dumpViews(view.getView(i), nestedIndent); + } + } +} -- GitLab From 6a477bda856d051904551995539e6c6bab1fa7da Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Tue, 28 Sep 2021 21:02:19 +0000 Subject: [PATCH 022/385] 8274415: Suppress warnings on non-serializable non-transient instance fields in java.xml Reviewed-by: joehw --- .../internal/xsltc/compiler/util/TypeCheckError.java | 2 ++ .../com/sun/org/apache/xerces/internal/dom/AttrImpl.java | 3 ++- .../sun/org/apache/xerces/internal/dom/DocumentImpl.java | 3 ++- .../org/apache/xerces/internal/dom/NamedNodeMapImpl.java | 3 ++- .../org/apache/xerces/internal/dom/PSVIAttrNSImpl.java | 7 ++++++- .../apache/xerces/internal/dom/PSVIElementNSImpl.java | 9 ++++++++- .../sun/org/apache/xerces/internal/dom/ParentNode.java | 4 +++- .../internal/impl/io/MalformedByteSequenceException.java | 1 + .../impl/xs/traversers/XSDComplexTypeTraverser.java | 3 ++- .../sun/org/apache/xml/internal/utils/ObjectPool.java | 3 ++- .../org/apache/xml/internal/utils/SAXSourceLocator.java | 1 + .../com/sun/org/apache/xpath/internal/Expression.java | 3 ++- .../com/sun/org/apache/xpath/internal/NodeSetDTM.java | 1 + .../sun/org/apache/xpath/internal/XPathException.java | 3 ++- .../sun/org/apache/xpath/internal/axes/AxesWalker.java | 4 +++- .../sun/org/apache/xpath/internal/axes/IteratorPool.java | 4 +++- .../org/apache/xpath/internal/axes/LocPathIterator.java | 3 ++- .../apache/xpath/internal/axes/MatchPatternIterator.java | 3 ++- .../sun/org/apache/xpath/internal/axes/NodeSequence.java | 5 ++++- .../org/apache/xpath/internal/axes/OneStepIterator.java | 1 + .../apache/xpath/internal/axes/ReverseAxesWalker.java | 1 + .../apache/xpath/internal/functions/FuncExtFunction.java | 4 +++- .../apache/xpath/internal/objects/XNodeSetForDOM.java | 1 + .../sun/org/apache/xpath/internal/objects/XObject.java | 3 ++- .../org/apache/xpath/internal/objects/XRTreeFrag.java | 2 ++ .../classes/javax/xml/stream/XMLStreamException.java | 3 ++- .../javax/xml/transform/TransformerException.java | 1 + 27 files changed, 63 insertions(+), 18 deletions(-) diff --git a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/util/TypeCheckError.java b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/util/TypeCheckError.java index dd34d69a6de..b1805bd96bb 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/util/TypeCheckError.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/util/TypeCheckError.java @@ -29,7 +29,9 @@ import com.sun.org.apache.xalan.internal.xsltc.compiler.SyntaxTreeNode; */ public class TypeCheckError extends Exception { static final long serialVersionUID = 3246224233917854640L; + @SuppressWarnings("serial") // Type of field is not Serializable ErrorMsg _error = null; + @SuppressWarnings("serial") // Type of field is not Serializable SyntaxTreeNode _node = null; public TypeCheckError(SyntaxTreeNode node) { diff --git a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/dom/AttrImpl.java b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/dom/AttrImpl.java index 9804314f49f..4ba34d4183e 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/dom/AttrImpl.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/dom/AttrImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -132,6 +132,7 @@ public class AttrImpl // /** This can either be a String or the first child node. */ + @SuppressWarnings("serial") // Type of field is not Serializable protected Object value = null; /** Attribute name. */ diff --git a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/dom/DocumentImpl.java b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/dom/DocumentImpl.java index f7467cbcf83..9b7938ca5b2 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/dom/DocumentImpl.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/dom/DocumentImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -507,6 +507,7 @@ public class DocumentImpl private static final long serialVersionUID = -8426757059492421631L; String type; + @SuppressWarnings("serial") // Type of field is not Serializable EventListener listener; boolean useCapture; diff --git a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/dom/NamedNodeMapImpl.java b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/dom/NamedNodeMapImpl.java index 27086ee5bed..306aefc2432 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/dom/NamedNodeMapImpl.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/dom/NamedNodeMapImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -79,6 +79,7 @@ public class NamedNodeMapImpl protected final static short HASDEFAULTS = 0x1<<2; /** Nodes. */ + @SuppressWarnings("serial") // Type of field is not Serializable protected List nodes; protected NodeImpl ownerNode; // the node this map belongs to diff --git a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/dom/PSVIAttrNSImpl.java b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/dom/PSVIAttrNSImpl.java index 8b4ffaca0f8..576037e1012 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/dom/PSVIAttrNSImpl.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/dom/PSVIAttrNSImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -60,9 +60,11 @@ public class PSVIAttrNSImpl extends AttrNSImpl implements AttributePSVI { } /** attribute declaration */ + @SuppressWarnings("serial") // Type of field is not Serializable protected XSAttributeDeclaration fDeclaration = null; /** type of attribute, simpleType */ + @SuppressWarnings("serial") // Type of field is not Serializable protected XSTypeDefinition fTypeDecl = null; /** If this attribute was explicitly given a @@ -70,6 +72,7 @@ public class PSVIAttrNSImpl extends AttrNSImpl implements AttributePSVI { protected boolean fSpecified = true; /** Schema value */ + @SuppressWarnings("serial") // Type of field is not Serializable protected ValidatedInfo fValue = new ValidatedInfo(); /** validation attempted: none, partial, full */ @@ -79,9 +82,11 @@ public class PSVIAttrNSImpl extends AttrNSImpl implements AttributePSVI { protected short fValidity = AttributePSVI.VALIDITY_NOTKNOWN; /** error codes */ + @SuppressWarnings("serial") // Type of field is not Serializable protected StringList fErrorCodes = null; /** error messages */ + @SuppressWarnings("serial") // Type of field is not Serializable protected StringList fErrorMessages = null; /** validation context: could be QName or XPath expression*/ diff --git a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/dom/PSVIElementNSImpl.java b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/dom/PSVIElementNSImpl.java index d6e60641b39..9aef985fed9 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/dom/PSVIElementNSImpl.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/dom/PSVIElementNSImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -60,9 +60,11 @@ public class PSVIElementNSImpl extends ElementNSImpl implements ElementPSVI { } /** element declaration */ + @SuppressWarnings("serial") // Type of field is not Serializable protected XSElementDeclaration fDeclaration = null; /** type of element, could be xsi:type */ + @SuppressWarnings("serial") // Type of field is not Serializable protected XSTypeDefinition fTypeDecl = null; /** true if clause 3.2 of Element Locally Valid (Element) (3.3.4) @@ -75,9 +77,11 @@ public class PSVIElementNSImpl extends ElementNSImpl implements ElementPSVI { protected boolean fSpecified = true; /** Schema value */ + @SuppressWarnings("serial") // Type of field is not Serializable protected ValidatedInfo fValue = new ValidatedInfo(); /** http://www.w3.org/TR/xmlschema-1/#e-notation*/ + @SuppressWarnings("serial") // Type of field is not Serializable protected XSNotationDeclaration fNotation = null; /** validation attempted: none, partial, full */ @@ -87,15 +91,18 @@ public class PSVIElementNSImpl extends ElementNSImpl implements ElementPSVI { protected short fValidity = ElementPSVI.VALIDITY_NOTKNOWN; /** error codes */ + @SuppressWarnings("serial") // Type of field is not Serializable protected StringList fErrorCodes = null; /** error messages */ + @SuppressWarnings("serial") // Type of field is not Serializable protected StringList fErrorMessages = null; /** validation context: could be QName or XPath expression*/ protected String fValidationContext = null; /** the schema information property */ + @SuppressWarnings("serial") // Type of field is not Serializable protected XSModel fSchemaInformation = null; // diff --git a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/dom/ParentNode.java b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/dom/ParentNode.java index 342b4b7ea3e..0ca7f13e8aa 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/dom/ParentNode.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/dom/ParentNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -1024,7 +1024,9 @@ public abstract class ParentNode /** Serialization version. */ private static final long serialVersionUID = 3258126977134310455L; + @SuppressWarnings("serial") // Type of field is not Serializable Object fData; + @SuppressWarnings("serial") // Type of field is not Serializable UserDataHandler fHandler; UserDataRecord(Object data, UserDataHandler handler) { fData = data; diff --git a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/io/MalformedByteSequenceException.java b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/io/MalformedByteSequenceException.java index 50e51c5dbf7..fb5bd19de63 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/io/MalformedByteSequenceException.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/io/MalformedByteSequenceException.java @@ -45,6 +45,7 @@ public class MalformedByteSequenceException extends CharConversionException { // /** message formatter **/ + @SuppressWarnings("serial") // Type of field is not Serializable private MessageFormatter fFormatter; /** locale for error message **/ diff --git a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xs/traversers/XSDComplexTypeTraverser.java b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xs/traversers/XSDComplexTypeTraverser.java index fb059b0b51a..3011e7db9d3 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xs/traversers/XSDComplexTypeTraverser.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xs/traversers/XSDComplexTypeTraverser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -132,6 +132,7 @@ class XSDComplexTypeTraverser extends XSDAbstractParticleTraverser { private static final long serialVersionUID = 6802729912091130335L; Object[] errorSubstText=null; + @SuppressWarnings("serial") // Type of field is not Serializable Element errorElem = null; ComplexTypeRecoverableError() { super(); diff --git a/src/java.xml/share/classes/com/sun/org/apache/xml/internal/utils/ObjectPool.java b/src/java.xml/share/classes/com/sun/org/apache/xml/internal/utils/ObjectPool.java index 05944643e28..c6897b0fc0d 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xml/internal/utils/ObjectPool.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xml/internal/utils/ObjectPool.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -43,6 +43,7 @@ public class ObjectPool implements java.io.Serializable /** Stack of given objects this points to. * @serial */ + @SuppressWarnings("serial") // Type of field is not Serializable private final List freeStack; /** diff --git a/src/java.xml/share/classes/com/sun/org/apache/xml/internal/utils/SAXSourceLocator.java b/src/java.xml/share/classes/com/sun/org/apache/xml/internal/utils/SAXSourceLocator.java index d0b4c4a3fe3..13100dc1344 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xml/internal/utils/SAXSourceLocator.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xml/internal/utils/SAXSourceLocator.java @@ -41,6 +41,7 @@ public class SAXSourceLocator extends LocatorImpl /** The SAX Locator object. * @serial */ + @SuppressWarnings("serial") // Type of field is not Serializable Locator m_locator; /** diff --git a/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/Expression.java b/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/Expression.java index 558f97b29be..5219aab3049 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/Expression.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/Expression.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -52,6 +52,7 @@ public abstract class Expression implements java.io.Serializable, ExpressionNode * messages. May be null. * @serial */ + @SuppressWarnings("serial") // Type of field is not Serializable private ExpressionNode m_parent; /** diff --git a/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/NodeSetDTM.java b/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/NodeSetDTM.java index 03a802c8a62..6b0c1bde1b5 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/NodeSetDTM.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/NodeSetDTM.java @@ -358,6 +358,7 @@ public class NodeSetDTM extends NodeVector } /* An instance of the DTMManager. */ + @SuppressWarnings("serial") // Type of field is not Serializable DTMManager m_manager; /** diff --git a/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/XPathException.java b/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/XPathException.java index ed38487c1c1..ef6aff4b398 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/XPathException.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/XPathException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -39,6 +39,7 @@ public class XPathException extends TransformerException /** The home of the expression that caused the error. * @serial */ + @SuppressWarnings("serial") // Type of field is not Serializable Object m_styleNode = null; /** diff --git a/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/axes/AxesWalker.java b/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/axes/AxesWalker.java index 55d39a5c759..4467faf108c 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/axes/AxesWalker.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/axes/AxesWalker.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -463,6 +463,7 @@ public class AxesWalker extends PredicatedNodeTest * from multiple documents. * Never, ever, access this value without going through getDTM(int node). */ + @SuppressWarnings("serial") // Type of field is not Serializable private DTM m_dtm; /** @@ -587,5 +588,6 @@ public class AxesWalker extends PredicatedNodeTest protected int m_axis = -1; /** The DTM inner traversal class, that corresponds to the super axis. */ + @SuppressWarnings("serial") // Type of field is not Serializable protected DTMAxisTraverser m_traverser; } diff --git a/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/axes/IteratorPool.java b/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/axes/IteratorPool.java index c22ae764ad9..b3b0a93ac22 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/axes/IteratorPool.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/axes/IteratorPool.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -37,11 +37,13 @@ public final class IteratorPool implements java.io.Serializable /** * Type of objects in this pool. */ + @SuppressWarnings("serial") // Type of field is not Serializable private final DTMIterator m_orig; /** * Stack of given objects this points to. */ + @SuppressWarnings("serial") // Type of field is not Serializable private final List m_freeStack; /** diff --git a/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/axes/LocPathIterator.java b/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/axes/LocPathIterator.java index d8b22840157..bbb8e34659f 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/axes/LocPathIterator.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/axes/LocPathIterator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -978,6 +978,7 @@ public abstract class LocPathIterator extends PredicatedNodeTest * clear that this is needed. * @serial */ + @SuppressWarnings("serial") // Type of field is not Serializable private PrefixResolver m_prefixResolver; /** diff --git a/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/axes/MatchPatternIterator.java b/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/axes/MatchPatternIterator.java index 1eb8955de77..9a080fd1849 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/axes/MatchPatternIterator.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/axes/MatchPatternIterator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -52,6 +52,7 @@ public class MatchPatternIterator extends LocPathIterator protected int m_superAxis = -1; /** The DTM inner traversal class, that corresponds to the super axis. */ + @SuppressWarnings("serial") // Type of field is not Serializable protected DTMAxisTraverser m_traverser; /** DEBUG flag for diagnostic dumps. */ diff --git a/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/axes/NodeSequence.java b/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/axes/NodeSequence.java index ee88a63d443..41fc7612d5c 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/axes/NodeSequence.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/axes/NodeSequence.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -58,6 +58,7 @@ public class NodeSequence extends XObject *

    * Multiple NodeSequence objects may share the same cache. */ + @SuppressWarnings("serial") // Type of field is not Serializable private IteratorCache m_cache; /** @@ -128,6 +129,7 @@ public class NodeSequence extends XObject /** * The functional iterator that fetches nodes. */ + @SuppressWarnings("serial") // Type of field is not Serializable protected DTMIterator m_iter; /** @@ -152,6 +154,7 @@ public class NodeSequence extends XObject * The DTMManager to use if we're using a NodeVector only. * We may well want to do away with this, and store it in the NodeVector. */ + @SuppressWarnings("serial") // Type of field is not Serializable protected DTMManager m_dtmMgr; // ==== Constructors ==== diff --git a/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/axes/OneStepIterator.java b/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/axes/OneStepIterator.java index de78d2354da..4e6e7a374e9 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/axes/OneStepIterator.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/axes/OneStepIterator.java @@ -43,6 +43,7 @@ public class OneStepIterator extends ChildTestIterator protected int m_axis = -1; /** The DTM inner traversal class, that corresponds to the super axis. */ + @SuppressWarnings("serial") // Type of field is not Serializable protected DTMAxisIterator m_iterator; /** diff --git a/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/axes/ReverseAxesWalker.java b/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/axes/ReverseAxesWalker.java index da4944f6a22..6aa735dc937 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/axes/ReverseAxesWalker.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/axes/ReverseAxesWalker.java @@ -244,5 +244,6 @@ public class ReverseAxesWalker extends AxesWalker } /** The DTM inner traversal class, that corresponds to the super axis. */ + @SuppressWarnings("serial") // Type of field is not Serializable protected DTMAxisIterator m_iterator; } diff --git a/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/functions/FuncExtFunction.java b/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/functions/FuncExtFunction.java index 8f41b8ce39e..ac1fd12745f 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/functions/FuncExtFunction.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/functions/FuncExtFunction.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -64,6 +64,7 @@ public class FuncExtFunction extends Function * order to allow caching of the method. * @serial */ + @SuppressWarnings("serial") // Type of field is not Serializable Object m_methodKey; /** @@ -71,6 +72,7 @@ public class FuncExtFunction extends Function * function. * @serial */ + @SuppressWarnings("serial") // Type of field is not Serializable List m_argVec = new ArrayList<>(); /** diff --git a/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/objects/XNodeSetForDOM.java b/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/objects/XNodeSetForDOM.java index a3bfea65fc9..8bb23510ed8 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/objects/XNodeSetForDOM.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/objects/XNodeSetForDOM.java @@ -36,6 +36,7 @@ import org.w3c.dom.traversal.NodeIterator; public class XNodeSetForDOM extends XNodeSet { static final long serialVersionUID = -8396190713754624640L; + @SuppressWarnings("serial") // Type of field is not Serializable Object m_origObj; public XNodeSetForDOM(Node node, DTMManager dtmMgr) diff --git a/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/objects/XObject.java b/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/objects/XObject.java index 1106ebdea4d..ea5328fe272 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/objects/XObject.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/objects/XObject.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -54,6 +54,7 @@ public class XObject extends Expression implements Serializable, Cloneable * The java object which this object wraps. * @serial */ + @SuppressWarnings("serial") // Type of field is not Serializable protected Object m_obj; // This may be NULL!!! /** diff --git a/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/objects/XRTreeFrag.java b/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/objects/XRTreeFrag.java index 852aad55e07..f256be27346 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/objects/XRTreeFrag.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/objects/XRTreeFrag.java @@ -39,6 +39,7 @@ import org.w3c.dom.NodeList; public class XRTreeFrag extends XObject implements Cloneable { static final long serialVersionUID = -3201553822254911567L; + @SuppressWarnings("serial") // Type of field is not Serializable private DTMXRTreeFrag m_DTMXRTreeFrag; private int m_dtmRoot = DTM.NULL; protected boolean m_allowRelease = false; @@ -169,6 +170,7 @@ public class XRTreeFrag extends XObject implements Cloneable return true; } + @SuppressWarnings("serial") // Type of field is not Serializable private XMLString m_xmlStr = null; /** diff --git a/src/java.xml/share/classes/javax/xml/stream/XMLStreamException.java b/src/java.xml/share/classes/javax/xml/stream/XMLStreamException.java index 5a229ed1ea2..1b39aebd5bf 100644 --- a/src/java.xml/share/classes/javax/xml/stream/XMLStreamException.java +++ b/src/java.xml/share/classes/javax/xml/stream/XMLStreamException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,6 +45,7 @@ public class XMLStreamException extends Exception { /** * The location of the error. */ + @SuppressWarnings("serial") // Type of field is not Serializable protected Location location; /** diff --git a/src/java.xml/share/classes/javax/xml/transform/TransformerException.java b/src/java.xml/share/classes/javax/xml/transform/TransformerException.java index eb85c0eeb97..ecb7488fb4b 100644 --- a/src/java.xml/share/classes/javax/xml/transform/TransformerException.java +++ b/src/java.xml/share/classes/javax/xml/transform/TransformerException.java @@ -48,6 +48,7 @@ public class TransformerException extends Exception { private static final long serialVersionUID = 975798773772956428L; /** Field locator specifies where the error occurred */ + @SuppressWarnings("serial") // Type of field is not Serializable SourceLocator locator; /** -- GitLab From 2072bc77b4541c283adaa7eb51a38adcaf711fff Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Tue, 28 Sep 2021 21:21:53 +0000 Subject: [PATCH 023/385] 8274391: Suppress more warnings on non-serializable non-transient instance fields in java.util.concurrent Reviewed-by: lancea, bpb, alanb, iris --- .../share/classes/java/util/concurrent/ForkJoinPool.java | 1 + .../share/classes/java/util/concurrent/ForkJoinTask.java | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java b/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java index 51b16304506..f6b8f10d87f 100644 --- a/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java +++ b/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java @@ -2778,6 +2778,7 @@ public class ForkJoinPool extends AbstractExecutorService { @SuppressWarnings("serial") // Conditionally serializable volatile E result; final AtomicInteger count; // in case all throw + @SuppressWarnings("serial") final ForkJoinPool pool; // to check shutdown while collecting InvokeAnyRoot(int n, ForkJoinPool p) { pool = p; diff --git a/src/java.base/share/classes/java/util/concurrent/ForkJoinTask.java b/src/java.base/share/classes/java/util/concurrent/ForkJoinTask.java index fc1bd07ea74..0fe3d12aaf3 100644 --- a/src/java.base/share/classes/java/util/concurrent/ForkJoinTask.java +++ b/src/java.base/share/classes/java/util/concurrent/ForkJoinTask.java @@ -1444,8 +1444,8 @@ public abstract class ForkJoinTask implements Future, Serializable { implements RunnableFuture { @SuppressWarnings("serial") // Conditionally serializable final Callable callable; - @SuppressWarnings("serial") // Conditionally serializable transient volatile Thread runner; + @SuppressWarnings("serial") // Conditionally serializable T result; AdaptedInterruptibleCallable(Callable callable) { if (callable == null) throw new NullPointerException(); -- GitLab From e49e5b5a7ed9e493380fb73100057898c707b31b Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Tue, 28 Sep 2021 21:38:40 +0000 Subject: [PATCH 024/385] 8273972: Multi-core choke point in CMM engine (LCMSTransform.doTransform) Reviewed-by: prr --- .../classes/sun/java2d/cmm/lcms/LCMS.java | 2 +- .../sun/java2d/cmm/lcms/LCMSTransform.java | 71 +++++---- src/java.desktop/share/native/liblcms/LCMS.c | 12 +- .../MTPerLineTransformValidation.java | 146 ++++++++++++++++++ .../ColorConvertOp/MTTransformValidation.java | 143 +++++++++++++++++ 5 files changed, 333 insertions(+), 41 deletions(-) create mode 100644 test/jdk/sun/java2d/cmm/ColorConvertOp/MTPerLineTransformValidation.java create mode 100644 test/jdk/sun/java2d/cmm/ColorConvertOp/MTTransformValidation.java diff --git a/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMS.java b/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMS.java index 405f9490179..edf13447a40 100644 --- a/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMS.java +++ b/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMS.java @@ -148,7 +148,7 @@ final class LCMS implements PCMM { } /* methods invoked from LCMSTransform */ - public static native void colorConvert(LCMSTransform trans, + public static native void colorConvert(long trans, LCMSImageLayout src, LCMSImageLayout dest); diff --git a/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java b/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java index 04174d3892f..9c27476a8c9 100644 --- a/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java +++ b/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java @@ -44,18 +44,30 @@ import java.awt.image.DataBuffer; import java.awt.image.Raster; import java.awt.image.SampleModel; import java.awt.image.WritableRaster; +import java.lang.ref.Reference; import sun.java2d.cmm.ColorTransform; import static sun.java2d.cmm.lcms.LCMSImageLayout.ImageLayoutException; final class LCMSTransform implements ColorTransform { - long ID; - private int inFormatter = 0; - private boolean isInIntPacked = false; - private int outFormatter = 0; - private boolean isOutIntPacked = false; + private final static class NativeTransform { + private long ID; + private int inFormatter; + private boolean isInIntPacked; + private int outFormatter; + private boolean isOutIntPacked; + + private boolean match(LCMSImageLayout in, LCMSImageLayout out) { + return inFormatter == in.pixelType + && isInIntPacked == in.isIntPacked + && outFormatter == out.pixelType + && isOutIntPacked == out.isIntPacked; + } + } + + private volatile NativeTransform transform; ICC_Profile[] profiles; LCMSProfile[] lcmsProfiles; int renderType; @@ -64,8 +76,6 @@ final class LCMSTransform implements ColorTransform { private int numInComponents = -1; private int numOutComponents = -1; - private Object disposerReferent = new Object(); - public LCMSTransform(ICC_Profile profile, int renderType, int transformType) { @@ -122,31 +132,32 @@ final class LCMSTransform implements ColorTransform { return numOutComponents; } - private synchronized void doTransform(LCMSImageLayout in, - LCMSImageLayout out) { - // update native transfrom if needed - if (ID == 0L || - inFormatter != in.pixelType || isInIntPacked != in.isIntPacked || - outFormatter != out.pixelType || isOutIntPacked != out.isIntPacked) - { - - if (ID != 0L) { - // Disposer will destroy forgotten transform - disposerReferent = new Object(); + private void doTransform(LCMSImageLayout in, LCMSImageLayout out) { + NativeTransform tfm = transform; + // update native transform if needed + if (tfm == null || !tfm.match(in, out)) { + synchronized (this) { + tfm = transform; + if (tfm == null || !tfm.match(in, out)) { + tfm = new NativeTransform(); + tfm.inFormatter = in.pixelType; + tfm.isInIntPacked = in.isIntPacked; + + tfm.outFormatter = out.pixelType; + tfm.isOutIntPacked = out.isIntPacked; + + tfm.ID = LCMS.createTransform(lcmsProfiles, renderType, + tfm.inFormatter, + tfm.isInIntPacked, + tfm.outFormatter, + tfm.isOutIntPacked, tfm); + // Disposer will destroy forgotten transform + transform = tfm; + } } - inFormatter = in.pixelType; - isInIntPacked = in.isIntPacked; - - outFormatter = out.pixelType; - isOutIntPacked = out.isIntPacked; - - ID = LCMS.createTransform(lcmsProfiles, renderType, - inFormatter, isInIntPacked, - outFormatter, isOutIntPacked, - disposerReferent); } - - LCMS.colorConvert(this, in, out); + LCMS.colorConvert(tfm.ID, in, out); + Reference.reachabilityFence(tfm); // prevent deallocation of "tfm.ID" } /** diff --git a/src/java.desktop/share/native/liblcms/LCMS.c b/src/java.desktop/share/native/liblcms/LCMS.c index a9e7778dacf..a0a8fe78239 100644 --- a/src/java.desktop/share/native/liblcms/LCMS.c +++ b/src/java.desktop/share/native/liblcms/LCMS.c @@ -71,7 +71,6 @@ typedef union { } TagSignature_t, *TagSignature_p; static jfieldID Trans_renderType_fID; -static jfieldID Trans_ID_fID; static jfieldID IL_isIntPacked_fID; static jfieldID IL_dataType_fID; static jfieldID IL_pixelType_fID; @@ -510,9 +509,9 @@ void releaseILData (JNIEnv *env, void* pData, jint dataType, * Signature: (Lsun/java2d/cmm/lcms/LCMSTransform;Lsun/java2d/cmm/lcms/LCMSImageLayout;Lsun/java2d/cmm/lcms/LCMSImageLayout;)V */ JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_colorConvert - (JNIEnv *env, jclass cls, jobject trans, jobject src, jobject dst) + (JNIEnv *env, jclass cls, jlong ID, jobject src, jobject dst) { - cmsHTRANSFORM sTrans = NULL; + cmsHTRANSFORM sTrans = jlong_to_ptr(ID); int srcDType, dstDType; int srcOffset, srcNextRowOffset, dstOffset, dstNextRowOffset; int width, height, i; @@ -533,8 +532,6 @@ JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_colorConvert srcAtOnce = (*env)->GetBooleanField(env, src, IL_imageAtOnce_fID); dstAtOnce = (*env)->GetBooleanField(env, dst, IL_imageAtOnce_fID); - sTrans = jlong_to_ptr((*env)->GetLongField (env, trans, Trans_ID_fID)); - if (sTrans == NULL) { J2dRlsTraceLn(J2D_TRACE_ERROR, "LCMS_colorConvert: transform == NULL"); JNU_ThrowByName(env, "java/awt/color/CMMException", @@ -626,11 +623,6 @@ JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_initLCMS if (Trans_renderType_fID == NULL) { return; } - Trans_ID_fID = (*env)->GetFieldID (env, Trans, "ID", "J"); - if (Trans_ID_fID == NULL) { - return; - } - IL_isIntPacked_fID = (*env)->GetFieldID (env, IL, "isIntPacked", "Z"); if (IL_isIntPacked_fID == NULL) { return; diff --git a/test/jdk/sun/java2d/cmm/ColorConvertOp/MTPerLineTransformValidation.java b/test/jdk/sun/java2d/cmm/ColorConvertOp/MTPerLineTransformValidation.java new file mode 100644 index 00000000000..821bd0acaa7 --- /dev/null +++ b/test/jdk/sun/java2d/cmm/ColorConvertOp/MTPerLineTransformValidation.java @@ -0,0 +1,146 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.color.ColorSpace; +import java.awt.image.BufferedImage; +import java.awt.image.ColorConvertOp; + +/** + * @test + * @bug 8273972 + * @summary Verifies that ColorConvertOp works fine if shared between threads + * @run main/othervm/timeout=600 MTTransformValidation + */ +public final class MTPerLineTransformValidation { + + private volatile static BufferedImage[] lines; + + public static final int SIZE = 255; + private static volatile boolean failed = false; + + private static final int[] spaces = { + ColorSpace.CS_CIEXYZ, ColorSpace.CS_GRAY, ColorSpace.CS_LINEAR_RGB, + ColorSpace.CS_PYCC, ColorSpace.CS_sRGB + }; + + private static final int[] types = new int[]{ + BufferedImage.TYPE_INT_RGB, BufferedImage.TYPE_INT_ARGB, + BufferedImage.TYPE_INT_ARGB_PRE, BufferedImage.TYPE_INT_BGR, + BufferedImage.TYPE_3BYTE_BGR, BufferedImage.TYPE_4BYTE_ABGR, + BufferedImage.TYPE_4BYTE_ABGR_PRE, + BufferedImage.TYPE_USHORT_565_RGB, + BufferedImage.TYPE_USHORT_555_RGB, BufferedImage.TYPE_BYTE_GRAY, + BufferedImage.TYPE_USHORT_GRAY, BufferedImage.TYPE_BYTE_BINARY, + BufferedImage.TYPE_BYTE_INDEXED + }; + + /** + * For all possible combinations of color spaces and image types, convert + * the source image using one shared ColorConvertOp per line on the + * different threads. The result is validated against images converted on + * one thread only. + */ + public static void main(String[] args) throws Exception { + for (int srcCS : spaces) { + for (int dstCS : spaces) { + if(srcCS != dstCS) { + for (int type : types) { + checkTypes(ColorSpace.getInstance(srcCS), + ColorSpace.getInstance(dstCS), type); + } + } + } + } + } + + private static void checkTypes(ColorSpace srcCS, ColorSpace dstCS, int type) + throws Exception { + lines = new BufferedImage[SIZE]; + ColorConvertOp goldOp = new ColorConvertOp(srcCS, dstCS, null); + BufferedImage src = createSrc(type); + BufferedImage gold = goldOp.filter(src, null); + + // we do not share the goldOp since it is already initialized and used + // for the whole image, instead we will create a separate sharedOp and + // use it for each line of a different threads + ColorConvertOp sharedOp = new ColorConvertOp(srcCS, dstCS, null); + Thread[] threads = new Thread[SIZE]; + for (int y = 0; y < SIZE; ++y) { + BufferedImage line = src.getSubimage(0, y, SIZE, 1); + threads[y] = test(sharedOp, line, y); + } + + for (Thread t: threads) { + t.start(); + } + for (Thread t: threads) { + t.join(); + } + for (int y = 0; y < SIZE; ++y) { + validate(gold, lines[y], y); + } + if (failed) { + throw new RuntimeException("Unexpected exception"); + } + } + + private static Thread test(ColorConvertOp sharedOp, + BufferedImage line, int y){ + return new Thread(() -> { + try { + BufferedImage image = sharedOp.filter(line, null); + lines[y] = image; + } catch (Throwable t) { + t.printStackTrace(); + failed = true; + } + }); + } + + private static BufferedImage createSrc(int type) { + BufferedImage img = new BufferedImage(SIZE, SIZE, type); + fill(img); + return img; + } + + private static void fill(BufferedImage image) { + for (int i = 0; i < SIZE; i++) { + for (int j = 0; j < SIZE; j++) { + image.setRGB(i, j, + (i << 24) | (i << 16) | (j << 8) | ((i + j) >> 1)); + } + } + } + + private static void validate(BufferedImage full, BufferedImage line, int y) { + for (int i = 0; i < SIZE; i++) { + int rgb1 = full.getRGB(i, y); + int rgb2 = line.getRGB(i, 0); + if (rgb1 != rgb2) { + System.err.println("rgb1 = " + Integer.toHexString(rgb1)); + System.err.println("rgb2 = " + Integer.toHexString(rgb2)); + throw new RuntimeException(); + } + } + } +} diff --git a/test/jdk/sun/java2d/cmm/ColorConvertOp/MTTransformValidation.java b/test/jdk/sun/java2d/cmm/ColorConvertOp/MTTransformValidation.java new file mode 100644 index 00000000000..bc6bdb0649b --- /dev/null +++ b/test/jdk/sun/java2d/cmm/ColorConvertOp/MTTransformValidation.java @@ -0,0 +1,143 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.color.ColorSpace; +import java.awt.image.BufferedImage; +import java.awt.image.ColorConvertOp; +import java.util.concurrent.CountDownLatch; + +/** + * @test + * @bug 8273972 + * @summary Verifies that ColorConvertOp works fine if shared between threads + * @run main/othervm/timeout=600 MTTransformValidation + */ +public final class MTTransformValidation { + + public static final int SIZE = 255; + private static volatile boolean failed = false; + + private static final int[] spaces = { + ColorSpace.CS_CIEXYZ, ColorSpace.CS_GRAY, ColorSpace.CS_LINEAR_RGB, + ColorSpace.CS_PYCC, ColorSpace.CS_sRGB + }; + + private static final int[] types = new int[]{ + BufferedImage.TYPE_INT_RGB, BufferedImage.TYPE_INT_ARGB, + BufferedImage.TYPE_INT_ARGB_PRE, BufferedImage.TYPE_INT_BGR, + BufferedImage.TYPE_3BYTE_BGR, BufferedImage.TYPE_4BYTE_ABGR, + BufferedImage.TYPE_4BYTE_ABGR_PRE, + BufferedImage.TYPE_USHORT_565_RGB, + BufferedImage.TYPE_USHORT_555_RGB, BufferedImage.TYPE_BYTE_GRAY, + BufferedImage.TYPE_USHORT_GRAY, BufferedImage.TYPE_BYTE_BINARY, + BufferedImage.TYPE_BYTE_INDEXED + }; + + /** + * For all possible combinations of color spaces and image types, convert + * the source image using one shared ColorConvertOp. The result is validated + * against images converted on one thread only. + */ + public static void main(String[] args) throws Exception { + for (int srcCS : spaces) { + for (int dstCS : spaces) { + if(srcCS != dstCS) { + for (int type : types) { + checkTypes(ColorSpace.getInstance(srcCS), + ColorSpace.getInstance(dstCS), type); + } + } + } + } + } + + private static void checkTypes(ColorSpace srcCS, ColorSpace dstCS, int type) + throws Exception { + ColorConvertOp goldOp = new ColorConvertOp(srcCS, dstCS, null); + BufferedImage gold = goldOp.filter(createSrc(type), null); + // we do not share the goldOp since it is already initialized, but + // instead we will trigger initialization/usage of the new sharedOp on + // different threads at once + ColorConvertOp sharedOp = new ColorConvertOp(srcCS, dstCS, null); + test(gold, sharedOp, type); + + if (failed) { + throw new RuntimeException("Unexpected exception"); + } + } + + private static void test(BufferedImage gold, ColorConvertOp sharedOp, + int type) throws Exception { + Thread[] ts = new Thread[7]; + CountDownLatch latch = new CountDownLatch(ts.length); + for (int i = 0; i < ts.length; i++) { + ts[i] = new Thread(() -> { + BufferedImage local = createSrc(type); + latch.countDown(); + try { + latch.await(); + BufferedImage image = sharedOp.filter(local, null); + validate(image, gold); + } catch (Throwable t) { + t.printStackTrace(); + failed = true; + } + }); + } + for (Thread t : ts) { + t.start(); + } + for (Thread t : ts) { + t.join(); + } + } + + private static BufferedImage createSrc(int type) { + BufferedImage img = new BufferedImage(SIZE, SIZE, type); + fill(img); + return img; + } + + private static void fill(BufferedImage image) { + for (int i = 0; i < SIZE; i++) { + for (int j = 0; j < SIZE; j++) { + image.setRGB(i, j, + (i << 24) | (i << 16) | (j << 8) | ((i + j) >> 1)); + } + } + } + + private static void validate(BufferedImage img1, BufferedImage img2) { + for (int i = 0; i < SIZE; i++) { + for (int j = 0; j < SIZE; j++) { + int rgb1 = img1.getRGB(i, j); + int rgb2 = img2.getRGB(i, j); + if (rgb1 != rgb2) { + System.err.println("rgb1 = " + Integer.toHexString(rgb1)); + System.err.println("rgb2 = " + Integer.toHexString(rgb2)); + throw new RuntimeException(); + } + } + } + } +} -- GitLab From d8a278f3948e9a5c881e64cce0a588e31246a4b5 Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Tue, 28 Sep 2021 21:48:33 +0000 Subject: [PATCH 025/385] 8274396: Suppress more warnings on non-serializable non-transient instance fields in client libs Reviewed-by: bpb, naoto, serb, iris --- .../share/classes/com/sun/beans/editors/FontEditor.java | 1 + src/java.desktop/share/classes/sun/awt/im/CompositionArea.java | 3 +++ .../share/classes/sun/awt/im/InputMethodJFrame.java | 1 + .../share/classes/sun/awt/im/SimpleInputMethodWindow.java | 1 + .../share/classes/sun/print/PrinterJobWrapper.java | 1 + 5 files changed, 7 insertions(+) diff --git a/src/java.desktop/share/classes/com/sun/beans/editors/FontEditor.java b/src/java.desktop/share/classes/com/sun/beans/editors/FontEditor.java index ae711c0103a..cf2fdd26307 100644 --- a/src/java.desktop/share/classes/com/sun/beans/editors/FontEditor.java +++ b/src/java.desktop/share/classes/com/sun/beans/editors/FontEditor.java @@ -220,6 +220,7 @@ public class FontEditor extends Panel implements java.beans.PropertyEditor { } private Font font; + @SuppressWarnings("serial") // Type of field is not Serializable private Toolkit toolkit; private String sampleText = "Abcde..."; diff --git a/src/java.desktop/share/classes/sun/awt/im/CompositionArea.java b/src/java.desktop/share/classes/sun/awt/im/CompositionArea.java index 26c88337f89..85fb5794dc5 100644 --- a/src/java.desktop/share/classes/sun/awt/im/CompositionArea.java +++ b/src/java.desktop/share/classes/sun/awt/im/CompositionArea.java @@ -61,9 +61,12 @@ import javax.swing.border.LineBorder; // This class is final due to the 6607310 fix. Refer to the CR for details. public final class CompositionArea extends JPanel implements InputMethodListener { + @SuppressWarnings("serial") // Type of field is not Serializable private CompositionAreaHandler handler; + @SuppressWarnings("serial") // Type of field is not Serializable private TextLayout composedTextLayout; + @SuppressWarnings("serial") // Type of field is not Serializable private TextHitInfo caret = null; private JFrame compositionWindow; private static final int TEXT_ORIGIN_X = 5; diff --git a/src/java.desktop/share/classes/sun/awt/im/InputMethodJFrame.java b/src/java.desktop/share/classes/sun/awt/im/InputMethodJFrame.java index 9043bd162be..63d8442f7ed 100644 --- a/src/java.desktop/share/classes/sun/awt/im/InputMethodJFrame.java +++ b/src/java.desktop/share/classes/sun/awt/im/InputMethodJFrame.java @@ -40,6 +40,7 @@ public class InputMethodJFrame extends JFrame implements InputMethodWindow { + @SuppressWarnings("serial") // Type of field is not Serializable InputContext inputContext = null; /** diff --git a/src/java.desktop/share/classes/sun/awt/im/SimpleInputMethodWindow.java b/src/java.desktop/share/classes/sun/awt/im/SimpleInputMethodWindow.java index cea5ec97ce9..18c93d11a1d 100644 --- a/src/java.desktop/share/classes/sun/awt/im/SimpleInputMethodWindow.java +++ b/src/java.desktop/share/classes/sun/awt/im/SimpleInputMethodWindow.java @@ -38,6 +38,7 @@ public class SimpleInputMethodWindow extends Frame implements InputMethodWindow { + @SuppressWarnings("serial") // Type of field is not Serializable InputContext inputContext = null; /** diff --git a/src/java.desktop/share/classes/sun/print/PrinterJobWrapper.java b/src/java.desktop/share/classes/sun/print/PrinterJobWrapper.java index c01286a3338..970c9283b3a 100644 --- a/src/java.desktop/share/classes/sun/print/PrinterJobWrapper.java +++ b/src/java.desktop/share/classes/sun/print/PrinterJobWrapper.java @@ -39,6 +39,7 @@ public class PrinterJobWrapper implements PrintRequestAttribute { @Serial private static final long serialVersionUID = -8792124426995707237L; + @SuppressWarnings("serial") // Type of field is not Serializable private PrinterJob job; public PrinterJobWrapper(PrinterJob job) { -- GitLab From 1a29b1e95e448bbef93373a25ba93a5591faed49 Mon Sep 17 00:00:00 2001 From: Andrey Turbanov Date: Tue, 28 Sep 2021 23:01:57 +0000 Subject: [PATCH 026/385] 8274016: Replace 'for' cycles with iterator with enhanced-for in java.desktop Reviewed-by: serb --- .../plugins/common/SimpleRenderedImage.java | 9 +---- .../plugins/jpeg/JFIFMarkerSegment.java | 13 ++----- .../imageio/plugins/jpeg/JPEGImageReader.java | 5 ++- .../imageio/plugins/jpeg/JPEGImageWriter.java | 5 +-- .../imageio/plugins/jpeg/JPEGMetadata.java | 36 +++++-------------- .../java/awt/DefaultKeyboardFocusManager.java | 18 ++++------ .../java/awt/KeyboardFocusManager.java | 8 ++--- .../share/classes/java/beans/MetaData.java | 8 ++--- .../beans/beancontext/BeanContextSupport.java | 26 +++++++------- .../classes/javax/swing/RepaintManager.java | 3 +- .../share/classes/sun/awt/SunToolkit.java | 4 +-- .../unix/classes/sun/awt/X11/XToolkit.java | 4 +-- .../unix/classes/sun/awt/X11/XWindowPeer.java | 8 ++--- 13 files changed, 45 insertions(+), 102 deletions(-) diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SimpleRenderedImage.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SimpleRenderedImage.java index 997d01e3973..cca9129376d 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SimpleRenderedImage.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SimpleRenderedImage.java @@ -34,7 +34,6 @@ import java.awt.image.WritableRaster; import java.util.ArrayList; import java.util.Enumeration; import java.util.Hashtable; -import java.util.Iterator; import java.util.Vector; public abstract class SimpleRenderedImage implements RenderedImage { @@ -282,13 +281,7 @@ public abstract class SimpleRenderedImage implements RenderedImage { return null; } - // Copy the strings from the Vector over to a String array. - String[] prefixNames = new String[names.size()]; - int count = 0; - for (Iterator it = names.iterator(); it.hasNext(); ) { - prefixNames[count++] = it.next(); - } - + String[] prefixNames = names.toArray(new String[0]); return prefixNames; } diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JFIFMarkerSegment.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JFIFMarkerSegment.java index e944847ed57..c573c5e313c 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JFIFMarkerSegment.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JFIFMarkerSegment.java @@ -41,7 +41,6 @@ import java.awt.image.WritableRaster; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.ArrayList; -import java.util.Iterator; import java.util.List; import javax.imageio.IIOException; @@ -159,9 +158,7 @@ class JFIFMarkerSegment extends MarkerSegment { JFIFMarkerSegment newGuy = (JFIFMarkerSegment) super.clone(); if (!extSegments.isEmpty()) { // Clone the list with a deep copy newGuy.extSegments = new ArrayList<>(); - for (Iterator iter = - extSegments.iterator(); iter.hasNext();) { - JFIFExtensionMarkerSegment jfxx = iter.next(); + for (JFIFExtensionMarkerSegment jfxx : extSegments) { newGuy.extSegments.add((JFIFExtensionMarkerSegment) jfxx.clone()); } } @@ -231,9 +228,7 @@ class JFIFMarkerSegment extends MarkerSegment { if (!extSegments.isEmpty()) { IIOMetadataNode JFXXnode = new IIOMetadataNode("JFXX"); node.appendChild(JFXXnode); - for (Iterator iter = - extSegments.iterator(); iter.hasNext();) { - JFIFExtensionMarkerSegment seg = iter.next(); + for (JFIFExtensionMarkerSegment seg : extSegments) { JFXXnode.appendChild(seg.getNativeNode()); } } @@ -635,9 +630,7 @@ class JFIFMarkerSegment extends MarkerSegment { System.out.print("Thumbnail Height: "); System.out.println(thumbHeight); if (!extSegments.isEmpty()) { - for (Iterator iter = - extSegments.iterator(); iter.hasNext();) { - JFIFExtensionMarkerSegment extSegment = iter.next(); + for (JFIFExtensionMarkerSegment extSegment : extSegments) { extSegment.print(); } } diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java index 11eed2e94e0..ab15bdfc6b8 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java @@ -1275,9 +1275,8 @@ public class JPEGImageReader extends ImageReader { // and set knownPassCount if (imageIndex == imageMetadataIndex) { // We have metadata knownPassCount = 0; - for (Iterator iter = - imageMetadata.markerSequence.iterator(); iter.hasNext();) { - if (iter.next() instanceof SOSMarkerSegment) { + for (MarkerSegment markerSegment : imageMetadata.markerSequence) { + if (markerSegment instanceof SOSMarkerSegment) { knownPassCount++; } } diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriter.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriter.java index 720e970903f..31acae628a1 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriter.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriter.java @@ -41,7 +41,6 @@ import java.awt.image.RenderedImage; import java.awt.image.WritableRaster; import java.io.IOException; import java.util.ArrayList; -import java.util.Iterator; import java.util.List; import javax.imageio.IIOException; @@ -1382,9 +1381,7 @@ public class JPEGImageWriter extends ImageWriter { List segments = new ArrayList<>(); int SCAN_SIZE = 9; int MAX_COMPS_PER_SCAN = 4; - for (Iterator iter = metadata.markerSequence.iterator(); - iter.hasNext();) { - MarkerSegment seg = iter.next(); + for (MarkerSegment seg : metadata.markerSequence) { if (seg instanceof SOSMarkerSegment) { segments.add((SOSMarkerSegment) seg); } diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGMetadata.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGMetadata.java index 477897ec2ba..ece1df86fcf 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGMetadata.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGMetadata.java @@ -1711,9 +1711,7 @@ public class JPEGMetadata extends IIOMetadata implements Cloneable { } if (idsDiffer) { // update the ids in each SOS marker segment - for (Iterator iter = markerSequence.iterator(); - iter.hasNext();) { - MarkerSegment seg = iter.next(); + for (MarkerSegment seg : markerSequence) { if (seg instanceof SOSMarkerSegment) { SOSMarkerSegment target = (SOSMarkerSegment) seg; for (int i = 0; i < target.componentSpecs.length; i++) { @@ -1766,9 +1764,7 @@ public class JPEGMetadata extends IIOMetadata implements Cloneable { if (updateQtables) { List tableSegments = new ArrayList<>(); - for (Iterator iter = markerSequence.iterator(); - iter.hasNext();) { - MarkerSegment seg = iter.next(); + for (MarkerSegment seg : markerSequence) { if (seg instanceof DQTMarkerSegment) { tableSegments.add((DQTMarkerSegment) seg); } @@ -1784,12 +1780,8 @@ public class JPEGMetadata extends IIOMetadata implements Cloneable { // Find the table with selector 1. boolean found = false; - for (Iterator iter = tableSegments.iterator(); - iter.hasNext();) { - DQTMarkerSegment testdqt = iter.next(); - for (Iterator tabiter = - testdqt.tables.iterator(); tabiter.hasNext();) { - DQTMarkerSegment.Qtable tab = tabiter.next(); + for (DQTMarkerSegment testdqt : tableSegments) { + for (DQTMarkerSegment.Qtable tab : testdqt.tables) { if (tab.tableID == 1) { found = true; } @@ -1798,12 +1790,8 @@ public class JPEGMetadata extends IIOMetadata implements Cloneable { if (!found) { // find the table with selector 0. There should be one. DQTMarkerSegment.Qtable table0 = null; - for (Iterator iter = - tableSegments.iterator(); iter.hasNext();) { - DQTMarkerSegment testdqt = iter.next(); - for (Iterator tabiter = - testdqt.tables.iterator(); tabiter.hasNext();) { - DQTMarkerSegment.Qtable tab = tabiter.next(); + for (DQTMarkerSegment testdqt : tableSegments) { + for (DQTMarkerSegment.Qtable tab : testdqt.tables) { if (tab.tableID == 0) { table0 = tab; } @@ -1821,9 +1809,7 @@ public class JPEGMetadata extends IIOMetadata implements Cloneable { if (updateHtables) { List tableSegments = new ArrayList<>(); - for (Iterator iter = markerSequence.iterator(); - iter.hasNext();) { - MarkerSegment seg = iter.next(); + for (MarkerSegment seg : markerSequence) { if (seg instanceof DHTMarkerSegment) { tableSegments.add((DHTMarkerSegment) seg); } @@ -1838,12 +1824,8 @@ public class JPEGMetadata extends IIOMetadata implements Cloneable { // find a table with selector 1. AC/DC is irrelevant boolean found = false; - for (Iterator iter = tableSegments.iterator(); - iter.hasNext();) { - DHTMarkerSegment testdht = iter.next(); - for (Iterator tabiter = - testdht.tables.iterator(); tabiter.hasNext();) { - DHTMarkerSegment.Htable tab = tabiter.next(); + for (DHTMarkerSegment testdht : tableSegments) { + for (DHTMarkerSegment.Htable tab : testdht.tables) { if (tab.tableID == 1) { found = true; } diff --git a/src/java.desktop/share/classes/java/awt/DefaultKeyboardFocusManager.java b/src/java.desktop/share/classes/java/awt/DefaultKeyboardFocusManager.java index 16218b866fa..c95443429e2 100644 --- a/src/java.desktop/share/classes/java/awt/DefaultKeyboardFocusManager.java +++ b/src/java.desktop/share/classes/java/awt/DefaultKeyboardFocusManager.java @@ -1078,8 +1078,8 @@ public class DefaultKeyboardFocusManager extends KeyboardFocusManager { * @since 1.5 */ private boolean hasMarker(Component comp) { - for (Iterator iter = typeAheadMarkers.iterator(); iter.hasNext(); ) { - if (iter.next().untilFocused == comp) { + for (TypeAheadMarker typeAheadMarker : typeAheadMarkers) { + if (typeAheadMarker.untilFocused == comp) { return true; } } @@ -1137,15 +1137,11 @@ public class DefaultKeyboardFocusManager extends KeyboardFocusManager { java.util.List dispatchers = getKeyEventDispatchers(); if (dispatchers != null) { - for (java.util.Iterator iter = dispatchers.iterator(); - iter.hasNext(); ) - { - if (iter.next(). - dispatchKeyEvent(ke)) - { - return true; - } - } + for (KeyEventDispatcher dispatcher : dispatchers) { + if (dispatcher.dispatchKeyEvent(ke)) { + return true; + } + } } return dispatchKeyEvent(ke); } diff --git a/src/java.desktop/share/classes/java/awt/KeyboardFocusManager.java b/src/java.desktop/share/classes/java/awt/KeyboardFocusManager.java index d29d5d9e408..62a86ced4b4 100644 --- a/src/java.desktop/share/classes/java/awt/KeyboardFocusManager.java +++ b/src/java.desktop/share/classes/java/awt/KeyboardFocusManager.java @@ -2977,13 +2977,9 @@ public abstract class KeyboardFocusManager if (hwFocusRequest != null) { heavyweightRequests.removeFirst(); if (hwFocusRequest.lightweightRequests != null) { - for (Iterator lwIter = hwFocusRequest.lightweightRequests. - iterator(); - lwIter.hasNext(); ) - { + for (LightweightFocusRequest lwFocusRequest : hwFocusRequest.lightweightRequests) { manager.dequeueKeyEvents - (-1, lwIter.next(). - component); + (-1, lwFocusRequest.component); } } } diff --git a/src/java.desktop/share/classes/java/beans/MetaData.java b/src/java.desktop/share/classes/java/beans/MetaData.java index e2dbb6ff66f..52237b15792 100644 --- a/src/java.desktop/share/classes/java/beans/MetaData.java +++ b/src/java.desktop/share/classes/java/beans/MetaData.java @@ -28,13 +28,9 @@ import com.sun.beans.finder.PrimitiveWrapperMap; import java.awt.AWTKeyStroke; import java.awt.BorderLayout; -import java.awt.Dimension; import java.awt.Color; import java.awt.Font; -import java.awt.GridBagConstraints; import java.awt.Insets; -import java.awt.Point; -import java.awt.Rectangle; import java.awt.event.KeyEvent; import java.awt.font.TextAttribute; @@ -521,8 +517,8 @@ static class java_util_Collection_PersistenceDelegate extends DefaultPersistence if (newO.size() != 0) { invokeStatement(oldInstance, "clear", new Object[]{}, out); } - for (Iterator i = oldO.iterator(); i.hasNext();) { - invokeStatement(oldInstance, "add", new Object[]{i.next()}, out); + for (Object o : oldO) { + invokeStatement(oldInstance, "add", new Object[]{o}, out); } } } diff --git a/src/java.desktop/share/classes/java/beans/beancontext/BeanContextSupport.java b/src/java.desktop/share/classes/java/beans/beancontext/BeanContextSupport.java index 9989bec6381..58e05f77084 100644 --- a/src/java.desktop/share/classes/java/beans/beancontext/BeanContextSupport.java +++ b/src/java.desktop/share/classes/java/beans/beancontext/BeanContextSupport.java @@ -771,17 +771,15 @@ public class BeanContextSupport extends BeanContextChildSupport } synchronized(children) { - for (Iterator i = children.keySet().iterator(); i.hasNext();) { - Object c = i.next(); - + for (Object c : children.keySet()) { try { - return ((Visibility)c).needsGui(); - } catch (ClassCastException cce) { - // do nothing ... - } + return ((Visibility)c).needsGui(); + } catch (ClassCastException cce) { + // do nothing ... + } - if (c instanceof Container || c instanceof Component) - return true; + if (c instanceof Container || c instanceof Component) + return true; } } @@ -798,11 +796,11 @@ public class BeanContextSupport extends BeanContextChildSupport // lets also tell the Children that can that they may not use their GUI's synchronized(children) { - for (Iterator i = children.keySet().iterator(); i.hasNext();) { - Visibility v = getChildVisibility(i.next()); + for (Object c : children.keySet()) { + Visibility v = getChildVisibility(c); if (v != null) v.dontUseGui(); - } + } } } } @@ -817,8 +815,8 @@ public class BeanContextSupport extends BeanContextChildSupport // lets also tell the Children that can that they may use their GUI's synchronized(children) { - for (Iterator i = children.keySet().iterator(); i.hasNext();) { - Visibility v = getChildVisibility(i.next()); + for (Object c : children.keySet()) { + Visibility v = getChildVisibility(c); if (v != null) v.okToUseGui(); } diff --git a/src/java.desktop/share/classes/javax/swing/RepaintManager.java b/src/java.desktop/share/classes/javax/swing/RepaintManager.java index f4d16c4e102..88684226d95 100644 --- a/src/java.desktop/share/classes/javax/swing/RepaintManager.java +++ b/src/java.desktop/share/classes/javax/swing/RepaintManager.java @@ -799,8 +799,7 @@ public class RepaintManager Set windows = new HashSet(); Set dirtyComps = dirtyComponents.keySet(); - for (Iterator it = dirtyComps.iterator(); it.hasNext();) { - Component dirty = it.next(); + for (Component dirty : dirtyComps) { Window window = dirty instanceof Window ? (Window)dirty : SwingUtilities.getWindowAncestor(dirty); diff --git a/src/java.desktop/share/classes/sun/awt/SunToolkit.java b/src/java.desktop/share/classes/sun/awt/SunToolkit.java index 195c246b2ff..a46a68786bf 100644 --- a/src/java.desktop/share/classes/sun/awt/SunToolkit.java +++ b/src/java.desktop/share/classes/sun/awt/SunToolkit.java @@ -82,7 +82,6 @@ import java.net.URL; import java.security.AccessController; import java.util.ArrayList; import java.util.Collections; -import java.util.Iterator; import java.util.Locale; import java.util.Map; import java.util.Vector; @@ -946,13 +945,12 @@ public abstract class SunToolkit extends Toolkit int bestHeight = 0; double bestSimilarity = 3; //Impossibly high value double bestScaleFactor = 0; - for (Iterator i = multiResAndnormalImages.iterator();i.hasNext();) { + for (Image im : multiResAndnormalImages) { //Iterate imageList looking for best matching image. //'Similarity' measure is defined as good scale factor and small insets. //best possible similarity is 0 (no scale, no insets). //It's found while the experiments that good-looking result is achieved //with scale factors x1, x3/4, x2/3, xN, x1/N. - Image im = i.next(); if (im == null) { continue; } diff --git a/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java b/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java index 8d5586741f2..c5c7a964e81 100644 --- a/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java +++ b/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java @@ -1992,9 +1992,7 @@ public final class XToolkit extends UNIXToolkit implements Runnable { while (time.compareTo(currentTime) <= 0) { java.util.List tasks = timeoutTasks.remove(time); - for (Iterator iter = tasks.iterator(); iter.hasNext();) { - Runnable task = iter.next(); - + for (Runnable task : tasks) { if (timeoutTaskLog.isLoggable(PlatformLogger.Level.FINER)) { timeoutTaskLog.finer("XToolkit.callTimeoutTasks(): current time={0}" + "; about to run task={1}", Long.valueOf(currentTime), task); diff --git a/src/java.desktop/unix/classes/sun/awt/X11/XWindowPeer.java b/src/java.desktop/unix/classes/sun/awt/X11/XWindowPeer.java index 04ce7926b32..3a79e785be6 100644 --- a/src/java.desktop/unix/classes/sun/awt/X11/XWindowPeer.java +++ b/src/java.desktop/unix/classes/sun/awt/X11/XWindowPeer.java @@ -51,7 +51,6 @@ import java.security.AccessController; import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.HashSet; -import java.util.Iterator; import java.util.Set; import java.util.Vector; import java.util.concurrent.atomic.AtomicBoolean; @@ -306,8 +305,7 @@ class XWindowPeer extends XPanelPeer implements WindowPeer, if (iconImages.size() != 0) { //read icon images from target winAttr.iconsInherited = false; - for (Iterator i = iconImages.iterator(); i.hasNext(); ) { - Image image = i.next(); + for (Image image : iconImages) { if (image == null) { if (log.isLoggable(PlatformLogger.Level.FINEST)) { log.finest("XWindowPeer.updateIconImages: Skipping the image passed into Java because it's null."); @@ -403,8 +401,8 @@ class XWindowPeer extends XPanelPeer implements WindowPeer, static void dumpIcons(java.util.List icons) { if (iconLog.isLoggable(PlatformLogger.Level.FINEST)) { iconLog.finest(">>> Sizes of icon images:"); - for (Iterator i = icons.iterator(); i.hasNext(); ) { - iconLog.finest(" {0}", i.next()); + for (IconInfo icon : icons) { + iconLog.finest(" {0}", icon); } } } -- GitLab From 53b25bce878bc291f3a217da7c26fd3097f18cfd Mon Sep 17 00:00:00 2001 From: Scott Gibbons Date: Tue, 28 Sep 2021 23:03:01 +0000 Subject: [PATCH 027/385] 8273459: Update code segment alignment to 64 bytes Reviewed-by: kvn, sviswanathan --- src/hotspot/cpu/x86/macroAssembler_x86.cpp | 9 +++++++ src/hotspot/cpu/x86/macroAssembler_x86.hpp | 1 + src/hotspot/cpu/x86/stubGenerator_x86_32.cpp | 6 ++--- src/hotspot/cpu/x86/stubGenerator_x86_64.cpp | 28 ++++++++++---------- 4 files changed, 27 insertions(+), 17 deletions(-) diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp index b573adc3acd..a13b2b0da30 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp @@ -1170,7 +1170,16 @@ void MacroAssembler::addpd(XMMRegister dst, AddressLiteral src) { } } +// See 8273459. Function for ensuring 64-byte alignment, intended for stubs only. +// Stub code is generated once and never copied. +// NMethods can't use this because they get copied and we can't force alignment > 32 bytes. +void MacroAssembler::align64() { + align(64, (unsigned long long) pc()); +} + void MacroAssembler::align(int modulus) { + // 8273459: Ensure alignment is possible with current segment alignment + assert(modulus <= CodeEntryAlignment, "Alignment must be <= CodeEntryAlignment"); align(modulus, offset()); } diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.hpp b/src/hotspot/cpu/x86/macroAssembler_x86.hpp index b44f59a9ce3..8bbfca6ea18 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.hpp @@ -194,6 +194,7 @@ class MacroAssembler: public Assembler { void incrementq(AddressLiteral dst); // Alignment + void align64(); void align(int modulus); void align(int modulus, int target); diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_32.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_32.cpp index f289ad0a7a7..654066ac872 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_32.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_32.cpp @@ -2998,7 +2998,7 @@ class StubGenerator: public StubCodeGenerator { } address generate_upper_word_mask() { - __ align(64); + __ align64(); StubCodeMark mark(this, "StubRoutines", "upper_word_mask"); address start = __ pc(); __ emit_data(0x00000000, relocInfo::none, 0); @@ -3009,7 +3009,7 @@ class StubGenerator: public StubCodeGenerator { } address generate_shuffle_byte_flip_mask() { - __ align(64); + __ align64(); StubCodeMark mark(this, "StubRoutines", "shuffle_byte_flip_mask"); address start = __ pc(); __ emit_data(0x0c0d0e0f, relocInfo::none, 0); @@ -3068,7 +3068,7 @@ class StubGenerator: public StubCodeGenerator { } address generate_pshuffle_byte_flip_mask() { - __ align(64); + __ align64(); StubCodeMark mark(this, "StubRoutines", "pshuffle_byte_flip_mask"); address start = __ pc(); __ emit_data(0x00010203, relocInfo::none, 0); diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp index 6ce1ea56479..f5d3023009e 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp @@ -4194,7 +4194,7 @@ class StubGenerator: public StubCodeGenerator { } address generate_upper_word_mask() { - __ align(64); + __ align64(); StubCodeMark mark(this, "StubRoutines", "upper_word_mask"); address start = __ pc(); __ emit_data64(0x0000000000000000, relocInfo::none); @@ -4203,7 +4203,7 @@ class StubGenerator: public StubCodeGenerator { } address generate_shuffle_byte_flip_mask() { - __ align(64); + __ align64(); StubCodeMark mark(this, "StubRoutines", "shuffle_byte_flip_mask"); address start = __ pc(); __ emit_data64(0x08090a0b0c0d0e0f, relocInfo::none); @@ -4248,7 +4248,7 @@ class StubGenerator: public StubCodeGenerator { } address generate_pshuffle_byte_flip_mask() { - __ align(64); + __ align64(); StubCodeMark mark(this, "StubRoutines", "pshuffle_byte_flip_mask"); address start = __ pc(); __ emit_data64(0x0405060700010203, relocInfo::none); @@ -4464,7 +4464,7 @@ class StubGenerator: public StubCodeGenerator { // This mask is used for incrementing counter value(linc0, linc4, etc.) address counter_mask_addr() { - __ align(64); + __ align64(); StubCodeMark mark(this, "StubRoutines", "counter_mask_addr"); address start = __ pc(); __ emit_data64(0x08090a0b0c0d0e0f, relocInfo::none);//lbswapmask @@ -5383,7 +5383,7 @@ address generate_avx_ghash_processBlocks() { address base64_shuffle_addr() { - __ align(64, (unsigned long long)__ pc()); + __ align64(); StubCodeMark mark(this, "StubRoutines", "shuffle_base64"); address start = __ pc(); assert(((unsigned long long)start & 0x3f) == 0, @@ -5443,7 +5443,7 @@ address generate_avx_ghash_processBlocks() { address base64_encoding_table_addr() { - __ align(64, (unsigned long long)__ pc()); + __ align64(); StubCodeMark mark(this, "StubRoutines", "encoding_table_base64"); address start = __ pc(); assert(((unsigned long long)start & 0x3f) == 0, "Alignment problem (0x%08llx)", (unsigned long long)start); @@ -5850,7 +5850,7 @@ address generate_avx_ghash_processBlocks() { // base64 AVX512vbmi tables address base64_vbmi_lookup_lo_addr() { - __ align(64, (unsigned long long) __ pc()); + __ align64(); StubCodeMark mark(this, "StubRoutines", "lookup_lo_base64"); address start = __ pc(); assert(((unsigned long long)start & 0x3f) == 0, @@ -5867,7 +5867,7 @@ address generate_avx_ghash_processBlocks() { } address base64_vbmi_lookup_hi_addr() { - __ align(64, (unsigned long long) __ pc()); + __ align64(); StubCodeMark mark(this, "StubRoutines", "lookup_hi_base64"); address start = __ pc(); assert(((unsigned long long)start & 0x3f) == 0, @@ -5883,7 +5883,7 @@ address generate_avx_ghash_processBlocks() { return start; } address base64_vbmi_lookup_lo_url_addr() { - __ align(64, (unsigned long long) __ pc()); + __ align64(); StubCodeMark mark(this, "StubRoutines", "lookup_lo_base64url"); address start = __ pc(); assert(((unsigned long long)start & 0x3f) == 0, @@ -5900,7 +5900,7 @@ address generate_avx_ghash_processBlocks() { } address base64_vbmi_lookup_hi_url_addr() { - __ align(64, (unsigned long long) __ pc()); + __ align64(); StubCodeMark mark(this, "StubRoutines", "lookup_hi_base64url"); address start = __ pc(); assert(((unsigned long long)start & 0x3f) == 0, @@ -5917,7 +5917,7 @@ address generate_avx_ghash_processBlocks() { } address base64_vbmi_pack_vec_addr() { - __ align(64, (unsigned long long) __ pc()); + __ align64(); StubCodeMark mark(this, "StubRoutines", "pack_vec_base64"); address start = __ pc(); assert(((unsigned long long)start & 0x3f) == 0, @@ -5934,7 +5934,7 @@ address generate_avx_ghash_processBlocks() { } address base64_vbmi_join_0_1_addr() { - __ align(64, (unsigned long long) __ pc()); + __ align64(); StubCodeMark mark(this, "StubRoutines", "join_0_1_base64"); address start = __ pc(); assert(((unsigned long long)start & 0x3f) == 0, @@ -5951,7 +5951,7 @@ address generate_avx_ghash_processBlocks() { } address base64_vbmi_join_1_2_addr() { - __ align(64, (unsigned long long) __ pc()); + __ align64(); StubCodeMark mark(this, "StubRoutines", "join_1_2_base64"); address start = __ pc(); assert(((unsigned long long)start & 0x3f) == 0, @@ -5968,7 +5968,7 @@ address generate_avx_ghash_processBlocks() { } address base64_vbmi_join_2_3_addr() { - __ align(64, (unsigned long long) __ pc()); + __ align64(); StubCodeMark mark(this, "StubRoutines", "join_2_3_base64"); address start = __ pc(); assert(((unsigned long long)start & 0x3f) == 0, -- GitLab From 2657bcbd9965d8af83f4063e3602c409735493d1 Mon Sep 17 00:00:00 2001 From: David Holmes Date: Tue, 28 Sep 2021 23:24:23 +0000 Subject: [PATCH 028/385] 8274136: -XX:+ExitOnOutOfMemoryError calls exit while threads are running Reviewed-by: stuefe, hseigel --- src/hotspot/os/posix/os_posix.cpp | 4 ++++ src/hotspot/os/windows/os_windows.cpp | 8 ++++++-- src/hotspot/share/runtime/os.hpp | 6 +++++- src/hotspot/share/utilities/debug.cpp | 2 +- 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/hotspot/os/posix/os_posix.cpp b/src/hotspot/os/posix/os_posix.cpp index cf4d7f3d139..24522c2649f 100644 --- a/src/hotspot/os/posix/os_posix.cpp +++ b/src/hotspot/os/posix/os_posix.cpp @@ -732,6 +732,10 @@ void os::exit(int num) { ::exit(num); } +void os::_exit(int num) { + ::_exit(num); +} + // Builds a platform dependent Agent_OnLoad_ function name // which is used to find statically linked in agents. // Parameters: diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp index e6881fa8465..01158d84cb1 100644 --- a/src/hotspot/os/windows/os_windows.cpp +++ b/src/hotspot/os/windows/os_windows.cpp @@ -4159,8 +4159,8 @@ int os::win32::exit_process_or_thread(Ept what, int exit_code) { _endthreadex((unsigned)exit_code); } else if (what == EPT_PROCESS) { ::exit(exit_code); - } else { - _exit(exit_code); + } else { // EPT_PROCESS_DIE + ::_exit(exit_code); } // Should not reach here @@ -4763,6 +4763,10 @@ void os::exit(int num) { win32::exit_process_or_thread(win32::EPT_PROCESS, num); } +void os::_exit(int num) { + win32::exit_process_or_thread(win32::EPT_PROCESS_DIE, num); +} + // Is a (classpath) directory empty? bool os::dir_is_empty(const char* path) { errno_t err; diff --git a/src/hotspot/share/runtime/os.hpp b/src/hotspot/share/runtime/os.hpp index cb26598132e..c70a6b39821 100644 --- a/src/hotspot/share/runtime/os.hpp +++ b/src/hotspot/share/runtime/os.hpp @@ -520,9 +520,13 @@ class os: AllStatic { // child process (ignored on AIX, which always uses vfork). static int fork_and_exec(const char *cmd, bool prefer_vfork = false); - // Call ::exit() on all platforms but Windows + // Call ::exit() on all platforms static void exit(int num); + // Call ::_exit() on all platforms. Similar semantics to die() except we never + // want a core dump. + static void _exit(int num); + // Terminate the VM, but don't exit the process static void shutdown(); diff --git a/src/hotspot/share/utilities/debug.cpp b/src/hotspot/share/utilities/debug.cpp index 0cc83bd9e40..778d1a1b4a4 100644 --- a/src/hotspot/share/utilities/debug.cpp +++ b/src/hotspot/share/utilities/debug.cpp @@ -366,7 +366,7 @@ void report_java_out_of_memory(const char* message) { if (ExitOnOutOfMemoryError) { tty->print_cr("Terminating due to java.lang.OutOfMemoryError: %s", message); - os::exit(3); + os::_exit(3); // quick exit with no cleanup hooks run } } } -- GitLab From 5b0c9ccc495b6bf8061c161d48f73238c7167bc0 Mon Sep 17 00:00:00 2001 From: Jonathan Gibbons Date: Tue, 28 Sep 2021 23:53:49 +0000 Subject: [PATCH 029/385] 8274172: Convert JavadocTester to use NIO Reviewed-by: prappo --- .../doclet/testDocFileDir/TestDocFileDir.java | 13 +- .../doclet/testMetadata/TestMetadata.java | 12 +- .../testRelativeLinks/TestRelativeLinks.java | 7 +- .../testSearchScript/TestSearchScript.java | 11 +- .../TestSingletonLists.java | 2 +- .../doclet/testStylesheet/TestStylesheet.java | 2 +- .../lib/javadoc/tester/JavadocTester.java | 196 +++++++----------- test/langtools/tools/lib/toolbox/ToolBox.java | 49 ++++- 8 files changed, 152 insertions(+), 140 deletions(-) diff --git a/test/langtools/jdk/javadoc/doclet/testDocFileDir/TestDocFileDir.java b/test/langtools/jdk/javadoc/doclet/testDocFileDir/TestDocFileDir.java index 70660a4340e..d2f9e98fa9c 100644 --- a/test/langtools/jdk/javadoc/doclet/testDocFileDir/TestDocFileDir.java +++ b/test/langtools/jdk/javadoc/doclet/testDocFileDir/TestDocFileDir.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2021, Oracle and/or its affiliates. All rights reserved. * 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,13 +28,14 @@ * get overwritten when the sourcepath is equal to the destination * directory. * Also test that -docfilessubdirs and -excludedocfilessubdir both work. - * @library ../../lib + * @library /tools/lib ../../lib * @modules jdk.javadoc/jdk.javadoc.internal.tool - * @build javadoc.tester.* + * @build toolbox.ToolBox javadoc.tester.* * @run main TestDocFileDir */ import javadoc.tester.JavadocTester; +import toolbox.ToolBox; public class TestDocFileDir extends JavadocTester { @@ -43,10 +44,12 @@ public class TestDocFileDir extends JavadocTester { tester.runTests(); } + ToolBox tb = new ToolBox(); + // Output dir = "", Input dir = "" @Test public void test1() { - copyDir(testSrc("pkg"), "."); + tb.copyDir(testSrc("pkg"), "pkg"); setOutputDirectoryCheck(DirectoryCheck.NO_HTML_FILES); javadoc("pkg/C.java"); checkExit(Exit.OK); @@ -58,7 +61,7 @@ public class TestDocFileDir extends JavadocTester { @Test public void test2() { String outdir = "out2"; - copyDir(testSrc("pkg"), outdir); + tb.copyDir(testSrc("pkg"), outdir + "/pkg"); setOutputDirectoryCheck(DirectoryCheck.NO_HTML_FILES); javadoc("-d", outdir, "-sourcepath", "blah" + PS + outdir + PS + "blah", diff --git a/test/langtools/jdk/javadoc/doclet/testMetadata/TestMetadata.java b/test/langtools/jdk/javadoc/doclet/testMetadata/TestMetadata.java index 46e48f64907..040d2d1c78c 100644 --- a/test/langtools/jdk/javadoc/doclet/testMetadata/TestMetadata.java +++ b/test/langtools/jdk/javadoc/doclet/testMetadata/TestMetadata.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -165,9 +165,8 @@ public class TestMetadata extends JavadocTester { ); void checkBodyClasses() throws IOException { - Path outputDirPath = outputDir.toPath(); - for (Path p : tb.findFiles(".html", outputDirPath)) { - checkBodyClass(outputDirPath.relativize(p)); + for (Path p : tb.findFiles(".html", outputDir)) { + checkBodyClass(outputDir.relativize(p)); } } @@ -231,9 +230,8 @@ public class TestMetadata extends JavadocTester { ); void checkMetadata() throws IOException { - Path outputDirPath = outputDir.toPath(); - for (Path p : tb.findFiles(".html", outputDirPath)) { - checkMetadata(outputDirPath.relativize(p)); + for (Path p : tb.findFiles(".html", outputDir)) { + checkMetadata(outputDir.relativize(p)); } } diff --git a/test/langtools/jdk/javadoc/doclet/testRelativeLinks/TestRelativeLinks.java b/test/langtools/jdk/javadoc/doclet/testRelativeLinks/TestRelativeLinks.java index 30ef9ec4d6f..c0619aeaf0d 100644 --- a/test/langtools/jdk/javadoc/doclet/testRelativeLinks/TestRelativeLinks.java +++ b/test/langtools/jdk/javadoc/doclet/testRelativeLinks/TestRelativeLinks.java @@ -35,6 +35,9 @@ import java.io.File; import java.io.FileOutputStream; import java.io.IOException; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Path; import javadoc.tester.JavadocTester; @@ -200,9 +203,9 @@ public class TestRelativeLinks extends JavadocTester { } private void touch(String file) { - File f = new File(outputDir, file); + Path f = outputDir.resolve(file); out.println("touch " + f); - try (FileOutputStream fos = new FileOutputStream(f)) { + try (OutputStream fos = Files.newOutputStream(f)) { } catch (IOException e) { checking("Touch file"); failed("Error creating file: " + e); diff --git a/test/langtools/jdk/javadoc/doclet/testSearchScript/TestSearchScript.java b/test/langtools/jdk/javadoc/doclet/testSearchScript/TestSearchScript.java index 8c5e77c3c15..ad92d3f0e65 100644 --- a/test/langtools/jdk/javadoc/doclet/testSearchScript/TestSearchScript.java +++ b/test/langtools/jdk/javadoc/doclet/testSearchScript/TestSearchScript.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,10 +41,9 @@ import javax.script.ScriptContext; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileReader; import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.List; import jtreg.SkippedException; @@ -71,9 +70,9 @@ public class TestSearchScript extends JavadocTester { // see https://github.com/graalvm/graaljs/blob/master/docs/user/ScriptEngine.md Bindings bindings = engine.getBindings(ScriptContext.ENGINE_SCOPE); bindings.put("polyglot.js.nashorn-compat", true); - engine.eval(new BufferedReader(new FileReader(new File(testSrc, "javadoc-search.js")))); + engine.eval(Files.newBufferedReader(Path.of(testSrc).resolve("javadoc-search.js"))); Invocable inv = (Invocable) engine; - inv.invokeFunction("loadIndexFiles", outputDir.getAbsolutePath()); + inv.invokeFunction("loadIndexFiles", outputDir.toAbsolutePath().toString()); return inv; } diff --git a/test/langtools/jdk/javadoc/doclet/testSingletonLists/TestSingletonLists.java b/test/langtools/jdk/javadoc/doclet/testSingletonLists/TestSingletonLists.java index 409d77573c3..0df4f1e25c0 100644 --- a/test/langtools/jdk/javadoc/doclet/testSingletonLists/TestSingletonLists.java +++ b/test/langtools/jdk/javadoc/doclet/testSingletonLists/TestSingletonLists.java @@ -206,7 +206,7 @@ public class TestSingletonLists extends JavadocTester { checking("Check lists"); ListChecker c = new ListChecker(out, this::readFile); try { - c.checkDirectory(outputDir.toPath()); + c.checkDirectory(outputDir); c.report(); int errors = c.getErrorCount(); if (errors == 0) { diff --git a/test/langtools/jdk/javadoc/doclet/testStylesheet/TestStylesheet.java b/test/langtools/jdk/javadoc/doclet/testStylesheet/TestStylesheet.java index 0e2643a22fb..95d5fd0267c 100644 --- a/test/langtools/jdk/javadoc/doclet/testStylesheet/TestStylesheet.java +++ b/test/langtools/jdk/javadoc/doclet/testStylesheet/TestStylesheet.java @@ -381,7 +381,7 @@ public class TestStylesheet extends JavadocTester { checking("Check CSS class names"); CSSClassChecker c = new CSSClassChecker(out, this::readFile, styles); try { - c.checkDirectory(outputDir.toPath()); + c.checkDirectory(outputDir); c.report(); int errors = c.getErrorCount(); if (errors == 0) { diff --git a/test/langtools/jdk/javadoc/lib/javadoc/tester/JavadocTester.java b/test/langtools/jdk/javadoc/lib/javadoc/tester/JavadocTester.java index 1cf6098e862..79b20ff7e9e 100644 --- a/test/langtools/jdk/javadoc/lib/javadoc/tester/JavadocTester.java +++ b/test/langtools/jdk/javadoc/lib/javadoc/tester/JavadocTester.java @@ -25,10 +25,7 @@ package javadoc.tester; import java.io.BufferedWriter; import java.io.ByteArrayOutputStream; -import java.io.File; import java.io.FileNotFoundException; -import java.io.FileWriter; -import java.io.FilenameFilter; import java.io.IOException; import java.io.PrintStream; import java.io.PrintWriter; @@ -41,13 +38,18 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.nio.charset.Charset; import java.nio.charset.UnsupportedCharsetException; +import java.nio.file.DirectoryStream; +import java.nio.file.FileVisitResult; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.Comparator; import java.util.EnumMap; import java.util.HashMap; import java.util.List; @@ -157,7 +159,7 @@ public abstract class JavadocTester { } /** The output directory used in the most recent call of javadoc. */ - protected File outputDir; + protected Path outputDir; /** The output charset used in the most recent call of javadoc. */ protected Charset charset = Charset.defaultCharset(); @@ -169,7 +171,7 @@ public abstract class JavadocTester { private final Map outputMap = new EnumMap<>(Output.class); /** A cache of file content, to avoid reading files unnecessarily. */ - private final Map> fileContentCache = new HashMap<>(); + private final Map> fileContentCache = new HashMap<>(); /** The charset used for files in the fileContentCache. */ private Charset fileContentCacheCharset = null; @@ -185,7 +187,7 @@ public abstract class JavadocTester { * @return the full path of the specified file */ public static String testSrc(String path) { - return new File(testSrc, path).getPath(); + return Path.of(testSrc).resolve(path).toString(); } /** @@ -195,35 +197,40 @@ public abstract class JavadocTester { /** * Check that the directory is empty. */ - EMPTY((file, name) -> true), + EMPTY(p -> true), /** * Check that the directory does not contain any HTML files, * such as may have been generated by a prior run of javadoc * using this directory. * For now, the check is only performed on the top level directory. */ - NO_HTML_FILES((file, name) -> name.endsWith(".html")), + NO_HTML_FILES(p -> p.getFileName().toString().endsWith(".html")), /** * No check is performed on the directory contents. */ - NONE(null) { @Override void check(File dir) { } }; + NONE(null) { @Override void check(Path dir) { } }; /** The filter used to detect that files should not be present. */ - FilenameFilter filter; + DirectoryStream.Filter filter; - DirectoryCheck(FilenameFilter f) { + DirectoryCheck(DirectoryStream.Filter f) { filter = f; } - void check(File dir) { - if (dir.isDirectory()) { - String[] contents = dir.list(filter); - if (contents == null) - throw new Error("cannot list directory: " + dir); - if (contents.length > 0) { - System.err.println("Found extraneous files in dir:" + dir.getAbsolutePath()); - for (String x : contents) { - System.err.println(x); + void check(Path dir) { + if (Files.isDirectory(dir)) { + List contents = new ArrayList<>(); + try (var ds = Files.newDirectoryStream(dir, filter)) { + for (Path p : ds) { + contents.add(p); + } + } catch (IOException e) { + throw new Error("cannot list directory: " + dir + "; " + e, e); + } + if (!contents.isEmpty()) { + System.err.println("Found extraneous files in dir:" + dir.toAbsolutePath()); + for (Path p : contents) { + System.err.println(p); } throw new Error("directory has unexpected content: " + dir); } @@ -316,13 +323,13 @@ public abstract class JavadocTester { out.println("Running javadoc (run "+ javadocRunNum + ")..."); } - outputDir = new File("."); + outputDir = Path.of("."); String charsetArg = null; String docencodingArg = null; String encodingArg = null; for (int i = 0; i < args.length - 2; i++) { switch (args[i]) { - case "-d" -> outputDir = new File(args[++i]); + case "-d" -> outputDir = Path.of(args[++i]); case "-charset" -> charsetArg = args[++i]; case "-docencoding" -> docencodingArg = args[++i]; case "-encoding" -> encodingArg = args[++i]; @@ -377,7 +384,7 @@ public abstract class JavadocTester { } }); - if (exitCode == Exit.OK.code && outputDir.exists()) { + if (exitCode == Exit.OK.code && Files.exists(outputDir)) { if (automaticCheckLinks) { checkLinks(); } @@ -502,8 +509,8 @@ public abstract class JavadocTester { public void checkOutput(String path, boolean expectedFound, String... strings) { // Read contents of file try { - String fileString = readFile(outputDir, path); - checkOutput(new File(outputDir, path).getPath(), fileString, expectedFound, strings); + String fileString = readFile(outputDir, Path.of(path)); + checkOutput(outputDir.resolve(path).toString(), fileString, expectedFound, strings); } catch (Error e) { checking("Read file"); failed("Error reading file: " + e); @@ -594,7 +601,7 @@ public abstract class JavadocTester { checking("Check accessibility"); A11yChecker c = new A11yChecker(out, this::readFile); try { - c.checkDirectory(outputDir.toPath()); + c.checkDirectory(outputDir); c.report(); int errors = c.getErrorCount(); if (errors == 0) { @@ -616,7 +623,7 @@ public abstract class JavadocTester { checking("Check links"); LinkChecker c = new LinkChecker(out, this::readFile); try { - c.checkDirectory(outputDir.toPath()); + c.checkDirectory(outputDir); c.report(); int errors = c.getErrorCount(); if (errors == 0) { @@ -641,8 +648,8 @@ public abstract class JavadocTester { ShowHeadings s = new ShowHeadings(out, this::readFile); for (String p : paths) { try { - File f = new File(outputDir, p); - s.checkFiles(List.of(f.toPath()), false, Collections.emptySet()); + Path f = outputDir.resolve(p); + s.checkFiles(List.of(f), false, Collections.emptySet()); } catch (IOException e) { checking("Read file"); failed("Error reading file: " + e); @@ -691,8 +698,8 @@ public abstract class JavadocTester { for (String path: paths) { // log.logCheckFile(path, expectedFound); checking("checkFile"); - File file = new File(outputDir, path); - boolean isFound = file.exists(); + Path file = outputDir.resolve(path); + boolean isFound = Files.exists(file); if (isFound == expectedFound) { passed(file, "file " + (isFound ? "found:" : "not found:") + "\n"); } else { @@ -708,7 +715,7 @@ public abstract class JavadocTester { * @param strings the strings whose order to check */ public void checkOrder(String path, String... strings) { - File file = new File(outputDir, path); + Path file = outputDir.resolve(path); String fileString = readOutputFile(path); int prevIndex = -1; for (String s : strings) { @@ -736,7 +743,7 @@ public abstract class JavadocTester { * @param strings ensure each are unique */ public void checkUnique(String path, String... strings) { - File file = new File(outputDir, path); + Path file = outputDir.resolve(path); String fileString = readOutputFile(path); for (String s : strings) { int currentIndex = fileString.indexOf(s); @@ -762,58 +769,13 @@ public abstract class JavadocTester { * @param files the set of files to be compared */ public void diff(String baseDir1, String baseDir2, String... files) { - File bd1 = new File(baseDir1); - File bd2 = new File(baseDir2); + Path bd1 = Path.of(baseDir1); + Path bd2 = Path.of(baseDir2); for (String file : files) { - diff(bd1, bd2, file); + diff(bd1, bd2, Path.of(file)); } } - /** - * Copies a directory from one place to another. - * - * @param targetDir the directory to copy. - * @param destDir the destination to copy the directory to. - */ - // TODO: convert to using java.nio.Files.walkFileTree - public void copyDir(String targetDir, String destDir) { - try { - File targetDirObj = new File(targetDir); - File destDirParentObj = new File(destDir); - File destDirObj = new File(destDirParentObj, targetDirObj.getName()); - if (! destDirParentObj.exists()) { - destDirParentObj.mkdir(); - } - if (! destDirObj.exists()) { - destDirObj.mkdir(); - } - String[] files = targetDirObj.list(); - for (String file : files) { - File srcFile = new File(targetDirObj, file); - File destFile = new File(destDirObj, file); - if (srcFile.isFile()) { - out.println("Copying " + srcFile + " to " + destFile); - copyFile(destFile, srcFile); - } else if(srcFile.isDirectory()) { - copyDir(srcFile.getAbsolutePath(), destDirObj.getAbsolutePath()); - } - } - } catch (IOException exc) { - throw new Error("Could not copy " + targetDir + " to " + destDir); - } - } - - /** - * Copies a file. - * - * @param destfile the destination file - * @param srcfile the source file - * @throws IOException - */ - public void copyFile(File destfile, File srcfile) throws IOException { - Files.copy(srcfile.toPath(), destfile.toPath()); - } - /** * Read a file from the output directory. * @@ -821,27 +783,27 @@ public abstract class JavadocTester { * @return the file in string format */ public String readOutputFile(String fileName) throws Error { - return readFile(outputDir, fileName); + return readFile(outputDir, Path.of(fileName)); } protected String readFile(String fileName) throws Error { - return readFile(outputDir, fileName); + return readFile(outputDir, Path.of(fileName)); } protected String readFile(String baseDir, String fileName) throws Error { - return readFile(new File(baseDir), fileName); + return readFile(Path.of(baseDir), Path.of(fileName)); } protected String readFile(Path file) { - File baseDir; - if (file.startsWith(outputDir.toPath())) { + Path baseDir; + if (file.startsWith(outputDir)) { baseDir = outputDir; } else if (file.startsWith(currDir)) { - baseDir = currDir.toFile(); + baseDir = currDir; } else { - baseDir = file.getParent().toFile(); + baseDir = file.getParent(); } - String fileName = baseDir.toPath().relativize(file).toString(); + Path fileName = baseDir.relativize(file); return readFile(baseDir, fileName); } @@ -852,20 +814,20 @@ public abstract class JavadocTester { * @param fileName the name of the file to read * @return the file in string format */ - private String readFile(File baseDir, String fileName) throws Error { + private String readFile(Path baseDir, Path fileName) throws Error { if (!Objects.equals(fileContentCacheCharset, charset)) { fileContentCache.clear(); fileContentCacheCharset = charset; } try { - File file = new File(baseDir, fileName); + Path file = baseDir.resolve(fileName); SoftReference ref = fileContentCache.get(file); String content = (ref == null) ? null : ref.get(); if (content != null) return content; // charset defaults to a value inferred from latest javadoc run - content = new String(Files.readAllBytes(file.toPath()), charset); + content = new String(Files.readAllBytes(file), charset); fileContentCache.put(file, new SoftReference<>(content)); return content; } catch (FileNotFoundException e) { @@ -897,7 +859,7 @@ public abstract class JavadocTester { * @param file the file that was the focus of the check * @param message a short description of the outcome */ - protected void passed(File file, String message) { + protected void passed(Path file, String message) { passed(file + ": " + message); } @@ -922,7 +884,7 @@ public abstract class JavadocTester { * @param file the file that was the focus of the check * @param message a short description of the outcome */ - protected void failed(File file, String message) { + protected void failed(Path file, String message) { failed(file + ": " + message); } @@ -1002,10 +964,10 @@ public abstract class JavadocTester { * @param baseDir2 the directory in which to locate the second file * @param file the file to compare in the two base directories */ - private void diff(File baseDir1, File baseDir2, String file) { + private void diff(Path baseDir1, Path baseDir2, Path file) { String file1Contents = readFile(baseDir1, file); String file2Contents = readFile(baseDir2, file); - checking("diff " + new File(baseDir1, file) + ", " + new File(baseDir2, file)); + checking("diff " + baseDir1.resolve(file) + ", " + baseDir2.resolve(file)); if (file1Contents.trim().compareTo(file2Contents.trim()) == 0) { passed("files are equal"); } else { @@ -1068,44 +1030,46 @@ public abstract class JavadocTester { private static final int SUFFIX = 20; private static final int MAX = PREFIX + SUFFIX; List tests = new ArrayList<>(); - String outDir; - String rootDir = rootDir(); - - static String rootDir() { - File f = new File(".").getAbsoluteFile(); - while (!new File(f, ".hg").exists()) - f = f.getParentFile(); - return f.getPath(); + Path outDir; + Path rootDir = rootDir(); + + static Path rootDir() { + Path f = Path.of(".").toAbsolutePath(); + while (f != null && !Files.exists(f.resolve(".git"))) + f = f.getParent(); + return f; } - void setOutDir(File outDir) { - this.outDir = outDir.getPath(); + void setOutDir(Path outDir) { + this.outDir = outDir; } void logCheckFile(String file, boolean positive) { // Strip the outdir because that will typically not be the same - if (file.startsWith(outDir + "/")) - file = file.substring(outDir.length() + 1); - tests.add(file + " " + positive); + Path p = Path.of(file); + if (p.startsWith(outDir)) + p = p.relativize(outDir); + tests.add(p + " " + positive); } void logCheckOutput(String file, boolean positive, String text) { // Compress the string to be displayed in the log file - String simpleText = text.replaceAll("\\s+", " ").replace(rootDir, "[ROOT]"); + String simpleText = text.replaceAll("\\s+", " ").replace(rootDir.toString(), "[ROOT]"); if (simpleText.length() > MAX) simpleText = simpleText.substring(0, PREFIX) + "..." + simpleText.substring(simpleText.length() - SUFFIX); // Strip the outdir because that will typically not be the same - if (file.startsWith(outDir + "/")) - file = file.substring(outDir.length() + 1); + Path p = Path.of(file); + if (p.startsWith(outDir)) + p = p.relativize(outDir); // The use of text.hashCode ensure that all of "text" is taken into account - tests.add(file + " " + positive + " " + text.hashCode() + " " + simpleText); + tests.add(p + " " + positive + " " + text.hashCode() + " " + simpleText); } void write() { // sort the log entries because the subtests may not be executed in the same order - tests.sort((a, b) -> a.compareTo(b)); - try (BufferedWriter bw = new BufferedWriter(new FileWriter("tester.log"))) { + tests.sort(Comparator.naturalOrder()); + try (var bw = Files.newBufferedWriter(Path.of("tester.log"))) { for (String t: tests) { bw.write(t); bw.newLine(); @@ -1116,6 +1080,4 @@ public abstract class JavadocTester { } } - // Support classes for checkLinks - } \ No newline at end of file diff --git a/test/langtools/tools/lib/toolbox/ToolBox.java b/test/langtools/tools/lib/toolbox/ToolBox.java index 4332c3418a0..9dbb26e1448 100644 --- a/test/langtools/tools/lib/toolbox/ToolBox.java +++ b/test/langtools/tools/lib/toolbox/ToolBox.java @@ -34,6 +34,8 @@ import java.io.StringWriter; import java.io.Writer; import java.net.URI; import java.nio.charset.Charset; +import java.nio.file.FileAlreadyExistsException; +import java.nio.file.FileVisitOption; import java.nio.file.FileVisitResult; import java.nio.file.Files; import java.nio.file.Path; @@ -46,6 +48,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Deque; +import java.util.EnumSet; import java.util.HashMap; import java.util.LinkedList; import java.util.List; @@ -249,7 +252,51 @@ public class ToolBox { } /** - * Creates one of more directories. + * Copies the contents of a directory to another directory. + *

    Similar to the shell command: {@code rsync fromDir/ toDir/}. + * + * @param fromDir the directory containing the files to be copied + * @param toDir the destination to which to copy the files + */ + public void copyDir(String fromDir, String toDir) { + copyDir(Path.of(fromDir), Path.of(toDir)); + } + + /** + * Copies the contents of a directory to another directory. + * The destination direction should not already exist. + *

    Similar to the shell command: {@code rsync fromDir/ toDir/}. + * + * @param fromDir the directory containing the files to be copied + * @param toDir the destination to which to copy the files + */ + public void copyDir(Path fromDir, Path toDir) { + try { + if (toDir.getParent() != null) { + Files.createDirectories(toDir.getParent()); + } + Files.walkFileTree(fromDir, new SimpleFileVisitor() { + @Override + public FileVisitResult preVisitDirectory(Path fromSubdir, BasicFileAttributes attrs) + throws IOException { + Files.copy(fromSubdir, toDir.resolve(fromDir.relativize(fromSubdir))); + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult visitFile(Path fromFile, BasicFileAttributes attrs) + throws IOException { + Files.copy(fromFile, toDir.resolve(fromDir.relativize(fromFile))); + return FileVisitResult.CONTINUE; + } + }); + } catch (IOException e) { + throw new Error("Could not copy " + fromDir + " to " + toDir + ": " + e, e); + } + } + + /** + * Creates one or more directories. * For each of the series of paths, a directory will be created, * including any necessary parent directories. *

    Similar to the shell command: {@code mkdir -p paths}. -- GitLab From 756d22c3563ac92e74bb68d5eecb86d4fbab2c6b Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Wed, 29 Sep 2021 05:41:34 +0000 Subject: [PATCH 030/385] 8274130: C2: MulNode::Ideal chained transformations may act on wrong nodes Reviewed-by: thartmann, kvn --- src/hotspot/share/opto/mulnode.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/hotspot/share/opto/mulnode.cpp b/src/hotspot/share/opto/mulnode.cpp index 38a9d9b96f8..5d6cebb7d56 100644 --- a/src/hotspot/share/opto/mulnode.cpp +++ b/src/hotspot/share/opto/mulnode.cpp @@ -59,9 +59,9 @@ Node* MulNode::Identity(PhaseGVN* phase) { // We also canonicalize the Node, moving constants to the right input, // and flatten expressions (so that 1+x+2 becomes x+3). Node *MulNode::Ideal(PhaseGVN *phase, bool can_reshape) { - const Type *t1 = phase->type( in(1) ); - const Type *t2 = phase->type( in(2) ); - Node *progress = NULL; // Progress flag + Node* in1 = in(1); + Node* in2 = in(2); + Node* progress = NULL; // Progress flag // This code is used by And nodes too, but some conversions are // only valid for the actual Mul nodes. @@ -70,8 +70,6 @@ Node *MulNode::Ideal(PhaseGVN *phase, bool can_reshape) { (op == Op_MulF) || (op == Op_MulD); // Convert "(-a)*(-b)" into "a*b". - Node *in1 = in(1); - Node *in2 = in(2); if (real_mul && in1->is_Sub() && in2->is_Sub()) { if (phase->type(in1->in(1))->is_zero_type() && phase->type(in2->in(1))->is_zero_type()) { @@ -82,6 +80,8 @@ Node *MulNode::Ideal(PhaseGVN *phase, bool can_reshape) { igvn->_worklist.push(in1); igvn->_worklist.push(in2); } + in1 = in(1); + in2 = in(2); progress = this; } } @@ -104,10 +104,15 @@ Node *MulNode::Ideal(PhaseGVN *phase, bool can_reshape) { igvn->_worklist.push(in1); igvn->_worklist.push(in2); } + in1 = in(1); + in2 = in(2); progress = this; } } + const Type* t1 = phase->type(in1); + const Type* t2 = phase->type(in2); + // We are OK if right is a constant, or right is a load and // left is a non-constant. if( !(t2->singleton() || -- GitLab From c4d115701d102c33af937ca25dda8ac50117ac6b Mon Sep 17 00:00:00 2001 From: Martin Doerr Date: Wed, 29 Sep 2021 09:54:59 +0000 Subject: [PATCH 031/385] 8271855: [TESTBUG] Wrong weakCompareAndSet assumption in UnsafeIntrinsicsTest Reviewed-by: goetz, thartmann --- .../gcbarriers/UnsafeIntrinsicsTest.java | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/test/hotspot/jtreg/compiler/gcbarriers/UnsafeIntrinsicsTest.java b/test/hotspot/jtreg/compiler/gcbarriers/UnsafeIntrinsicsTest.java index b96e5ce54de..321f60ea8b7 100644 --- a/test/hotspot/jtreg/compiler/gcbarriers/UnsafeIntrinsicsTest.java +++ b/test/hotspot/jtreg/compiler/gcbarriers/UnsafeIntrinsicsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. * 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 id=Z * @key randomness - * @bug 8059022 + * @bug 8059022 8271855 * @modules java.base/jdk.internal.misc:+open * @summary Validate barriers after Unsafe getReference, CAS and swap (GetAndSet) * @requires vm.gc.Z @@ -301,7 +301,7 @@ class Runner implements Runnable { private Node mergeImplCAS(Node startNode, Node expectedNext, Node head) { // CAS - should always be true within a single thread - no other thread can have overwritten if (!UNSAFE.compareAndSetReference(startNode, offset, expectedNext, head)) { - throw new Error("CAS should always succeed on thread local objects, check you barrier implementation"); + throw new Error("CAS should always succeed on thread local objects, check your barrier implementation"); } return expectedNext; // continue on old circle } @@ -309,7 +309,7 @@ class Runner implements Runnable { private Node mergeImplCASFail(Node startNode, Node expectedNext, Node head) { // Force a fail if (UNSAFE.compareAndSetReference(startNode, offset, "fail", head)) { - throw new Error("This CAS should always fail, check you barrier implementation"); + throw new Error("This CAS should always fail, check your barrier implementation"); } if (startNode.next() != expectedNext) { throw new Error("Shouldn't have changed"); @@ -318,9 +318,15 @@ class Runner implements Runnable { } private Node mergeImplWeakCAS(Node startNode, Node expectedNext, Node head) { - // Weak CAS - should always be true within a single thread - no other thread can have overwritten - if (!UNSAFE.weakCompareAndSetReference(startNode, offset, expectedNext, head)) { - throw new Error("Weak CAS should always succeed on thread local objects, check you barrier implementation"); + // Weak CAS - should almost always be true within a single thread - no other thread can have overwritten + // Spurious failures are allowed. So, we retry a couple of times on failure. + boolean ok = false; + for (int i = 0; i < 3; ++i) { + ok = UNSAFE.weakCompareAndSetReference(startNode, offset, expectedNext, head); + if (ok) break; + } + if (!ok) { + throw new Error("Weak CAS should almost always succeed on thread local objects, check your barrier implementation"); } return expectedNext; // continue on old circle } @@ -328,7 +334,7 @@ class Runner implements Runnable { private Node mergeImplWeakCASFail(Node startNode, Node expectedNext, Node head) { // Force a fail if (UNSAFE.weakCompareAndSetReference(startNode, offset, "fail", head)) { - throw new Error("This weak CAS should always fail, check you barrier implementation"); + throw new Error("This weak CAS should always fail, check your barrier implementation"); } if (startNode.next() != expectedNext) { throw new Error("Shouldn't have changed"); @@ -340,7 +346,7 @@ class Runner implements Runnable { // CmpX - should always be true within a single thread - no other thread can have overwritten Object res = UNSAFE.compareAndExchangeReference(startNode, offset, expectedNext, head); if (!res.equals(expectedNext)) { - throw new Error("Fail CmpX should always succeed on thread local objects, check you barrier implementation"); + throw new Error("Fail CmpX should always succeed on thread local objects, check your barrier implementation"); } return expectedNext; // continue on old circle } -- GitLab From aaa36cc0069043e34b47e89769eb9eba39e5362a Mon Sep 17 00:00:00 2001 From: Claes Redestad Date: Wed, 29 Sep 2021 12:58:14 +0000 Subject: [PATCH 032/385] 8274242: Implement fast-path for ASCII-compatible CharsetEncoders on x86 Reviewed-by: naoto, thartmann --- src/hotspot/cpu/aarch64/aarch64.ad | 1 + src/hotspot/cpu/aarch64/matcher_aarch64.hpp | 3 + src/hotspot/cpu/arm/matcher_arm.hpp | 3 + src/hotspot/cpu/ppc/matcher_ppc.hpp | 2 + src/hotspot/cpu/ppc/ppc.ad | 1 + src/hotspot/cpu/s390/matcher_s390.hpp | 3 + src/hotspot/cpu/s390/s390.ad | 1 + src/hotspot/cpu/x86/macroAssembler_x86.cpp | 30 +- src/hotspot/cpu/x86/macroAssembler_x86.hpp | 2 +- src/hotspot/cpu/x86/matcher_x86.hpp | 3 + src/hotspot/cpu/x86/x86_32.ad | 21 +- src/hotspot/cpu/x86/x86_64.ad | 22 +- src/hotspot/share/classfile/vmIntrinsics.cpp | 1 + src/hotspot/share/classfile/vmIntrinsics.hpp | 3 + src/hotspot/share/opto/c2compiler.cpp | 3 + src/hotspot/share/opto/intrinsicnode.hpp | 8 +- src/hotspot/share/opto/library_call.cpp | 10 +- src/hotspot/share/opto/library_call.hpp | 2 +- .../share/classes/java/lang/StringCoding.java | 16 +- .../share/classes/java/lang/System.java | 4 + .../jdk/internal/access/JavaLangAccess.java | 9 + .../share/classes/sun/nio/cs/CESU_8.java | 22 +- .../share/classes/sun/nio/cs/SingleByte.java | 12 +- .../share/classes/sun/nio/cs/US_ASCII.java | 8 +- .../share/classes/sun/nio/cs/UTF_8.java | 26 +- .../jtreg/compiler/codegen/Test6896617.java | 346 ------------------ .../string/TestEncodeIntrinsics.java | 249 +++++++++++++ .../bench/java/nio/CharsetEncodeDecode.java | 8 +- 28 files changed, 428 insertions(+), 391 deletions(-) delete mode 100644 test/hotspot/jtreg/compiler/codegen/Test6896617.java create mode 100644 test/hotspot/jtreg/compiler/intrinsics/string/TestEncodeIntrinsics.java diff --git a/src/hotspot/cpu/aarch64/aarch64.ad b/src/hotspot/cpu/aarch64/aarch64.ad index 6fcbb24536d..e701e0a3a60 100644 --- a/src/hotspot/cpu/aarch64/aarch64.ad +++ b/src/hotspot/cpu/aarch64/aarch64.ad @@ -16864,6 +16864,7 @@ instruct encode_iso_array(iRegP_R2 src, iRegP_R1 dst, iRegI_R3 len, vRegD_V2 Vtmp3, vRegD_V3 Vtmp4, iRegI_R0 result, rFlagsReg cr) %{ + predicate(!((EncodeISOArrayNode*)n)->is_ascii()); match(Set result (EncodeISOArray src (Binary dst len))); effect(USE_KILL src, USE_KILL dst, USE_KILL len, KILL Vtmp1, KILL Vtmp2, KILL Vtmp3, KILL Vtmp4, KILL cr); diff --git a/src/hotspot/cpu/aarch64/matcher_aarch64.hpp b/src/hotspot/cpu/aarch64/matcher_aarch64.hpp index e5bee7990a6..9252ff12725 100644 --- a/src/hotspot/cpu/aarch64/matcher_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/matcher_aarch64.hpp @@ -163,4 +163,7 @@ return true; } + // Implements a variant of EncodeISOArrayNode that encode ASCII only + static const bool supports_encode_ascii_array = false; + #endif // CPU_AARCH64_MATCHER_AARCH64_HPP diff --git a/src/hotspot/cpu/arm/matcher_arm.hpp b/src/hotspot/cpu/arm/matcher_arm.hpp index b7a9a3f5042..6254f4b3399 100644 --- a/src/hotspot/cpu/arm/matcher_arm.hpp +++ b/src/hotspot/cpu/arm/matcher_arm.hpp @@ -155,4 +155,7 @@ return false; } + // Implements a variant of EncodeISOArrayNode that encode ASCII only + static const bool supports_encode_ascii_array = false; + #endif // CPU_ARM_MATCHER_ARM_HPP diff --git a/src/hotspot/cpu/ppc/matcher_ppc.hpp b/src/hotspot/cpu/ppc/matcher_ppc.hpp index df1672b3048..877f0be33c4 100644 --- a/src/hotspot/cpu/ppc/matcher_ppc.hpp +++ b/src/hotspot/cpu/ppc/matcher_ppc.hpp @@ -164,5 +164,7 @@ return VM_Version::has_fcfids(); } + // Implements a variant of EncodeISOArrayNode that encode ASCII only + static const bool supports_encode_ascii_array = false; #endif // CPU_PPC_MATCHER_PPC_HPP diff --git a/src/hotspot/cpu/ppc/ppc.ad b/src/hotspot/cpu/ppc/ppc.ad index 9a883c72310..ddb6e04918a 100644 --- a/src/hotspot/cpu/ppc/ppc.ad +++ b/src/hotspot/cpu/ppc/ppc.ad @@ -12789,6 +12789,7 @@ instruct has_negatives(rarg1RegP ary1, iRegIsrc len, iRegIdst result, iRegLdst t // encode char[] to byte[] in ISO_8859_1 instruct encode_iso_array(rarg1RegP src, rarg2RegP dst, iRegIsrc len, iRegIdst result, iRegLdst tmp1, iRegLdst tmp2, iRegLdst tmp3, iRegLdst tmp4, iRegLdst tmp5, regCTR ctr, flagsRegCR0 cr0) %{ + predicate(!((EncodeISOArrayNode*)n)->is_ascii()); match(Set result (EncodeISOArray src (Binary dst len))); effect(TEMP_DEF result, TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, TEMP tmp5, USE_KILL src, USE_KILL dst, KILL ctr, KILL cr0); diff --git a/src/hotspot/cpu/s390/matcher_s390.hpp b/src/hotspot/cpu/s390/matcher_s390.hpp index 7577a7b2666..09cb819a641 100644 --- a/src/hotspot/cpu/s390/matcher_s390.hpp +++ b/src/hotspot/cpu/s390/matcher_s390.hpp @@ -152,4 +152,7 @@ return true; } + // Implements a variant of EncodeISOArrayNode that encode ASCII only + static const bool supports_encode_ascii_array = false; + #endif // CPU_S390_MATCHER_S390_HPP diff --git a/src/hotspot/cpu/s390/s390.ad b/src/hotspot/cpu/s390/s390.ad index cd22b795886..63004f8e263 100644 --- a/src/hotspot/cpu/s390/s390.ad +++ b/src/hotspot/cpu/s390/s390.ad @@ -10282,6 +10282,7 @@ instruct has_negatives(rarg5RegP ary1, iRegI len, iRegI result, roddRegI oddReg, // encode char[] to byte[] in ISO_8859_1 instruct encode_iso_array(iRegP src, iRegP dst, iRegI result, iRegI len, iRegI tmp, flagsReg cr) %{ + predicate(!((EncodeISOArrayNode*)n)->is_ascii()); match(Set result (EncodeISOArray src (Binary dst len))); effect(TEMP_DEF result, TEMP tmp, KILL cr); // R0, R1 are killed, too. ins_cost(300); diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp index a13b2b0da30..bf56eddbdee 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp @@ -5423,7 +5423,7 @@ void MacroAssembler::generate_fill(BasicType t, bool aligned, BIND(L_exit); } -// encode char[] to byte[] in ISO_8859_1 +// encode char[] to byte[] in ISO_8859_1 or ASCII //@IntrinsicCandidate //private static int implEncodeISOArray(byte[] sa, int sp, //byte[] da, int dp, int len) { @@ -5436,10 +5436,23 @@ void MacroAssembler::generate_fill(BasicType t, bool aligned, // } // return i; //} + // + //@IntrinsicCandidate + //private static int implEncodeAsciiArray(char[] sa, int sp, + // byte[] da, int dp, int len) { + // int i = 0; + // for (; i < len; i++) { + // char c = sa[sp++]; + // if (c >= '\u0080') + // break; + // da[dp++] = (byte)c; + // } + // return i; + //} void MacroAssembler::encode_iso_array(Register src, Register dst, Register len, XMMRegister tmp1Reg, XMMRegister tmp2Reg, XMMRegister tmp3Reg, XMMRegister tmp4Reg, - Register tmp5, Register result) { + Register tmp5, Register result, bool ascii) { // rsi: src // rdi: dst @@ -5450,6 +5463,9 @@ void MacroAssembler::encode_iso_array(Register src, Register dst, Register len, assert_different_registers(src, dst, len, tmp5, result); Label L_done, L_copy_1_char, L_copy_1_char_exit; + int mask = ascii ? 0xff80ff80 : 0xff00ff00; + int short_mask = ascii ? 0xff80 : 0xff00; + // set result xorl(result, result); // check for zero length @@ -5469,7 +5485,7 @@ void MacroAssembler::encode_iso_array(Register src, Register dst, Register len, if (UseAVX >= 2) { Label L_chars_32_check, L_copy_32_chars, L_copy_32_chars_exit; - movl(tmp5, 0xff00ff00); // create mask to test for Unicode chars in vector + movl(tmp5, mask); // create mask to test for Unicode or non-ASCII chars in vector movdl(tmp1Reg, tmp5); vpbroadcastd(tmp1Reg, tmp1Reg, Assembler::AVX_256bit); jmp(L_chars_32_check); @@ -5478,7 +5494,7 @@ void MacroAssembler::encode_iso_array(Register src, Register dst, Register len, vmovdqu(tmp3Reg, Address(src, len, Address::times_2, -64)); vmovdqu(tmp4Reg, Address(src, len, Address::times_2, -32)); vpor(tmp2Reg, tmp3Reg, tmp4Reg, /* vector_len */ 1); - vptest(tmp2Reg, tmp1Reg); // check for Unicode chars in vector + vptest(tmp2Reg, tmp1Reg); // check for Unicode or non-ASCII chars in vector jccb(Assembler::notZero, L_copy_32_chars_exit); vpackuswb(tmp3Reg, tmp3Reg, tmp4Reg, /* vector_len */ 1); vpermq(tmp4Reg, tmp3Reg, 0xD8, /* vector_len */ 1); @@ -5493,7 +5509,7 @@ void MacroAssembler::encode_iso_array(Register src, Register dst, Register len, jccb(Assembler::greater, L_copy_16_chars_exit); } else if (UseSSE42Intrinsics) { - movl(tmp5, 0xff00ff00); // create mask to test for Unicode chars in vector + movl(tmp5, mask); // create mask to test for Unicode or non-ASCII chars in vector movdl(tmp1Reg, tmp5); pshufd(tmp1Reg, tmp1Reg, 0); jmpb(L_chars_16_check); @@ -5517,7 +5533,7 @@ void MacroAssembler::encode_iso_array(Register src, Register dst, Register len, movdqu(tmp4Reg, Address(src, len, Address::times_2, -16)); por(tmp2Reg, tmp4Reg); } - ptest(tmp2Reg, tmp1Reg); // check for Unicode chars in vector + ptest(tmp2Reg, tmp1Reg); // check for Unicode or non-ASCII chars in vector jccb(Assembler::notZero, L_copy_16_chars_exit); packuswb(tmp3Reg, tmp4Reg); } @@ -5555,7 +5571,7 @@ void MacroAssembler::encode_iso_array(Register src, Register dst, Register len, bind(L_copy_1_char); load_unsigned_short(tmp5, Address(src, len, Address::times_2, 0)); - testl(tmp5, 0xff00); // check if Unicode char + testl(tmp5, short_mask); // check if Unicode or non-ASCII char jccb(Assembler::notZero, L_copy_1_char_exit); movb(Address(dst, len, Address::times_1, 0), tmp5); addptr(len, 1); diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.hpp b/src/hotspot/cpu/x86/macroAssembler_x86.hpp index 8bbfca6ea18..c28f7c43b8b 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.hpp @@ -1725,7 +1725,7 @@ public: void encode_iso_array(Register src, Register dst, Register len, XMMRegister tmp1, XMMRegister tmp2, XMMRegister tmp3, - XMMRegister tmp4, Register tmp5, Register result); + XMMRegister tmp4, Register tmp5, Register result, bool ascii); #ifdef _LP64 void add2_with_carry(Register dest_hi, Register dest_lo, Register src1, Register src2); diff --git a/src/hotspot/cpu/x86/matcher_x86.hpp b/src/hotspot/cpu/x86/matcher_x86.hpp index 510395f121f..2dcd1e6e7a9 100644 --- a/src/hotspot/cpu/x86/matcher_x86.hpp +++ b/src/hotspot/cpu/x86/matcher_x86.hpp @@ -195,4 +195,7 @@ return true; } + // Implements a variant of EncodeISOArrayNode that encode ASCII only + static const bool supports_encode_ascii_array = true; + #endif // CPU_X86_MATCHER_X86_HPP diff --git a/src/hotspot/cpu/x86/x86_32.ad b/src/hotspot/cpu/x86/x86_32.ad index 7fb9e4e66a0..18d213cc31a 100644 --- a/src/hotspot/cpu/x86/x86_32.ad +++ b/src/hotspot/cpu/x86/x86_32.ad @@ -12199,18 +12199,35 @@ instruct string_inflate_evex(Universe dummy, eSIRegP src, eDIRegP dst, eDXRegI l instruct encode_iso_array(eSIRegP src, eDIRegP dst, eDXRegI len, regD tmp1, regD tmp2, regD tmp3, regD tmp4, eCXRegI tmp5, eAXRegI result, eFlagsReg cr) %{ + predicate(!((EncodeISOArrayNode*)n)->is_ascii()); match(Set result (EncodeISOArray src (Binary dst len))); effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, USE_KILL src, USE_KILL dst, USE_KILL len, KILL tmp5, KILL cr); - format %{ "Encode array $src,$dst,$len -> $result // KILL ECX, EDX, $tmp1, $tmp2, $tmp3, $tmp4, ESI, EDI " %} + format %{ "Encode iso array $src,$dst,$len -> $result // KILL ECX, EDX, $tmp1, $tmp2, $tmp3, $tmp4, ESI, EDI " %} ins_encode %{ __ encode_iso_array($src$$Register, $dst$$Register, $len$$Register, $tmp1$$XMMRegister, $tmp2$$XMMRegister, $tmp3$$XMMRegister, - $tmp4$$XMMRegister, $tmp5$$Register, $result$$Register); + $tmp4$$XMMRegister, $tmp5$$Register, $result$$Register, false); %} ins_pipe( pipe_slow ); %} +// encode char[] to byte[] in ASCII +instruct encode_ascii_array(eSIRegP src, eDIRegP dst, eDXRegI len, + regD tmp1, regD tmp2, regD tmp3, regD tmp4, + eCXRegI tmp5, eAXRegI result, eFlagsReg cr) %{ + predicate(((EncodeISOArrayNode*)n)->is_ascii()); + match(Set result (EncodeISOArray src (Binary dst len))); + effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, USE_KILL src, USE_KILL dst, USE_KILL len, KILL tmp5, KILL cr); + + format %{ "Encode ascii array $src,$dst,$len -> $result // KILL ECX, EDX, $tmp1, $tmp2, $tmp3, $tmp4, ESI, EDI " %} + ins_encode %{ + __ encode_iso_array($src$$Register, $dst$$Register, $len$$Register, + $tmp1$$XMMRegister, $tmp2$$XMMRegister, $tmp3$$XMMRegister, + $tmp4$$XMMRegister, $tmp5$$Register, $result$$Register, true); + %} + ins_pipe( pipe_slow ); +%} //----------Control Flow Instructions------------------------------------------ // Signed compare Instructions diff --git a/src/hotspot/cpu/x86/x86_64.ad b/src/hotspot/cpu/x86/x86_64.ad index ad6c36c51d7..14671c39640 100644 --- a/src/hotspot/cpu/x86/x86_64.ad +++ b/src/hotspot/cpu/x86/x86_64.ad @@ -11770,14 +11770,32 @@ instruct string_inflate_evex(Universe dummy, rsi_RegP src, rdi_RegP dst, rdx_Reg instruct encode_iso_array(rsi_RegP src, rdi_RegP dst, rdx_RegI len, legRegD tmp1, legRegD tmp2, legRegD tmp3, legRegD tmp4, rcx_RegI tmp5, rax_RegI result, rFlagsReg cr) %{ + predicate(!((EncodeISOArrayNode*)n)->is_ascii()); match(Set result (EncodeISOArray src (Binary dst len))); effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, USE_KILL src, USE_KILL dst, USE_KILL len, KILL tmp5, KILL cr); - format %{ "Encode array $src,$dst,$len -> $result // KILL RCX, RDX, $tmp1, $tmp2, $tmp3, $tmp4, RSI, RDI " %} + format %{ "Encode iso array $src,$dst,$len -> $result // KILL RCX, RDX, $tmp1, $tmp2, $tmp3, $tmp4, RSI, RDI " %} ins_encode %{ __ encode_iso_array($src$$Register, $dst$$Register, $len$$Register, $tmp1$$XMMRegister, $tmp2$$XMMRegister, $tmp3$$XMMRegister, - $tmp4$$XMMRegister, $tmp5$$Register, $result$$Register); + $tmp4$$XMMRegister, $tmp5$$Register, $result$$Register, false); + %} + ins_pipe( pipe_slow ); +%} + +// encode char[] to byte[] in ASCII +instruct encode_ascii_array(rsi_RegP src, rdi_RegP dst, rdx_RegI len, + legRegD tmp1, legRegD tmp2, legRegD tmp3, legRegD tmp4, + rcx_RegI tmp5, rax_RegI result, rFlagsReg cr) %{ + predicate(((EncodeISOArrayNode*)n)->is_ascii()); + match(Set result (EncodeISOArray src (Binary dst len))); + effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, USE_KILL src, USE_KILL dst, USE_KILL len, KILL tmp5, KILL cr); + + format %{ "Encode ascii array $src,$dst,$len -> $result // KILL RCX, RDX, $tmp1, $tmp2, $tmp3, $tmp4, RSI, RDI " %} + ins_encode %{ + __ encode_iso_array($src$$Register, $dst$$Register, $len$$Register, + $tmp1$$XMMRegister, $tmp2$$XMMRegister, $tmp3$$XMMRegister, + $tmp4$$XMMRegister, $tmp5$$Register, $result$$Register, true); %} ins_pipe( pipe_slow ); %} diff --git a/src/hotspot/share/classfile/vmIntrinsics.cpp b/src/hotspot/share/classfile/vmIntrinsics.cpp index 205ba8969cb..c15e1154b13 100644 --- a/src/hotspot/share/classfile/vmIntrinsics.cpp +++ b/src/hotspot/share/classfile/vmIntrinsics.cpp @@ -505,6 +505,7 @@ bool vmIntrinsics::disabled_by_jvm_flags(vmIntrinsics::ID id) { if (!SpecialArraysEquals) return true; break; case vmIntrinsics::_encodeISOArray: + case vmIntrinsics::_encodeAsciiArray: case vmIntrinsics::_encodeByteISOArray: if (!SpecialEncodeISOArray) return true; break; diff --git a/src/hotspot/share/classfile/vmIntrinsics.hpp b/src/hotspot/share/classfile/vmIntrinsics.hpp index 2a4f54880c9..31f0b1fb13c 100644 --- a/src/hotspot/share/classfile/vmIntrinsics.hpp +++ b/src/hotspot/share/classfile/vmIntrinsics.hpp @@ -353,6 +353,9 @@ class methodHandle; \ do_intrinsic(_encodeByteISOArray, java_lang_StringCoding, encodeISOArray_name, indexOfI_signature, F_S) \ \ + do_intrinsic(_encodeAsciiArray, java_lang_StringCoding, encodeAsciiArray_name, encodeISOArray_signature, F_S) \ + do_name( encodeAsciiArray_name, "implEncodeAsciiArray") \ + \ do_class(java_math_BigInteger, "java/math/BigInteger") \ do_intrinsic(_multiplyToLen, java_math_BigInteger, multiplyToLen_name, multiplyToLen_signature, F_S) \ do_name( multiplyToLen_name, "implMultiplyToLen") \ diff --git a/src/hotspot/share/opto/c2compiler.cpp b/src/hotspot/share/opto/c2compiler.cpp index d5a59a413af..c5949ed57f4 100644 --- a/src/hotspot/share/opto/c2compiler.cpp +++ b/src/hotspot/share/opto/c2compiler.cpp @@ -216,6 +216,9 @@ bool C2Compiler::is_intrinsic_supported(const methodHandle& method, bool is_virt case vmIntrinsics::_copyMemory: if (StubRoutines::unsafe_arraycopy() == NULL) return false; break; + case vmIntrinsics::_encodeAsciiArray: + if (!Matcher::match_rule_supported(Op_EncodeISOArray) || !Matcher::supports_encode_ascii_array) return false; + break; case vmIntrinsics::_encodeISOArray: case vmIntrinsics::_encodeByteISOArray: if (!Matcher::match_rule_supported(Op_EncodeISOArray)) return false; diff --git a/src/hotspot/share/opto/intrinsicnode.hpp b/src/hotspot/share/opto/intrinsicnode.hpp index 3d6e9a38d12..ab8a834bb28 100644 --- a/src/hotspot/share/opto/intrinsicnode.hpp +++ b/src/hotspot/share/opto/intrinsicnode.hpp @@ -168,10 +168,14 @@ class HasNegativesNode: public StrIntrinsicNode { //------------------------------EncodeISOArray-------------------------------- -// encode char[] to byte[] in ISO_8859_1 +// encode char[] to byte[] in ISO_8859_1 or ASCII class EncodeISOArrayNode: public Node { + bool ascii; public: - EncodeISOArrayNode(Node* control, Node* arymem, Node* s1, Node* s2, Node* c): Node(control, arymem, s1, s2, c) {}; + EncodeISOArrayNode(Node* control, Node* arymem, Node* s1, Node* s2, Node* c, bool ascii) + : Node(control, arymem, s1, s2, c), ascii(ascii) {} + + bool is_ascii() { return ascii; } virtual int Opcode() const; virtual bool depends_only_on_test() const { return false; } virtual const Type* bottom_type() const { return TypeInt::INT; } diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index 0ac5bf6d502..139a6c87dd0 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -591,7 +591,9 @@ bool LibraryCallKit::try_to_inline(int predicate) { case vmIntrinsics::_encodeISOArray: case vmIntrinsics::_encodeByteISOArray: - return inline_encodeISOArray(); + return inline_encodeISOArray(false); + case vmIntrinsics::_encodeAsciiArray: + return inline_encodeISOArray(true); case vmIntrinsics::_updateCRC32: return inline_updateCRC32(); @@ -4882,8 +4884,8 @@ LibraryCallKit::tightly_coupled_allocation(Node* ptr) { } //-------------inline_encodeISOArray----------------------------------- -// encode char[] to byte[] in ISO_8859_1 -bool LibraryCallKit::inline_encodeISOArray() { +// encode char[] to byte[] in ISO_8859_1 or ASCII +bool LibraryCallKit::inline_encodeISOArray(bool ascii) { assert(callee()->signature()->size() == 5, "encodeISOArray has 5 parameters"); // no receiver since it is static method Node *src = argument(0); @@ -4918,7 +4920,7 @@ bool LibraryCallKit::inline_encodeISOArray() { // 'dst_start' points to dst array + scaled offset const TypeAryPtr* mtype = TypeAryPtr::BYTES; - Node* enc = new EncodeISOArrayNode(control(), memory(mtype), src_start, dst_start, length); + Node* enc = new EncodeISOArrayNode(control(), memory(mtype), src_start, dst_start, length, ascii); enc = _gvn.transform(enc); Node* res_mem = _gvn.transform(new SCMemProjNode(enc)); set_memory(res_mem, mtype); diff --git a/src/hotspot/share/opto/library_call.hpp b/src/hotspot/share/opto/library_call.hpp index adb1cb06c95..b3010f1cb5b 100644 --- a/src/hotspot/share/opto/library_call.hpp +++ b/src/hotspot/share/opto/library_call.hpp @@ -285,7 +285,7 @@ class LibraryCallKit : public GraphKit { Node* get_state_from_digest_object(Node *digestBase_object, const char* state_type); Node* get_digest_length_from_digest_object(Node *digestBase_object); Node* inline_digestBase_implCompressMB_predicate(int predicate); - bool inline_encodeISOArray(); + bool inline_encodeISOArray(bool ascii); bool inline_updateCRC32(); bool inline_updateBytesCRC32(); bool inline_updateByteBufferCRC32(); diff --git a/src/java.base/share/classes/java/lang/StringCoding.java b/src/java.base/share/classes/java/lang/StringCoding.java index c8d69167543..ec81c379579 100644 --- a/src/java.base/share/classes/java/lang/StringCoding.java +++ b/src/java.base/share/classes/java/lang/StringCoding.java @@ -46,7 +46,7 @@ class StringCoding { @IntrinsicCandidate public static int implEncodeISOArray(byte[] sa, int sp, - byte[] da, int dp, int len) { + byte[] da, int dp, int len) { int i = 0; for (; i < len; i++) { char c = StringUTF16.getChar(sa, sp++); @@ -57,4 +57,18 @@ class StringCoding { return i; } + @IntrinsicCandidate + public static int implEncodeAsciiArray(char[] sa, int sp, + byte[] da, int dp, int len) + { + int i = 0; + for (; i < len; i++) { + char c = sa[sp++]; + if (c >= '\u0080') + break; + da[dp++] = (byte)c; + } + return i; + } + } diff --git a/src/java.base/share/classes/java/lang/System.java b/src/java.base/share/classes/java/lang/System.java index edb636bfe21..c843858712f 100644 --- a/src/java.base/share/classes/java/lang/System.java +++ b/src/java.base/share/classes/java/lang/System.java @@ -2419,6 +2419,10 @@ public final class System { return String.decodeASCII(src, srcOff, dst, dstOff, len); } + public int encodeASCII(char[] src, int srcOff, byte[] dst, int dstOff, int len) { + return StringCoding.implEncodeAsciiArray(src, srcOff, dst, dstOff, len); + } + public void setCause(Throwable t, Throwable cause) { t.setCause(cause); } diff --git a/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java b/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java index f6fe5f61131..b68490ad7a3 100644 --- a/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java +++ b/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java @@ -356,6 +356,15 @@ public interface JavaLangAccess { */ int decodeASCII(byte[] src, int srcOff, char[] dst, int dstOff, int len); + /** + * Encodes ASCII codepoints as possible from the source array into + * the destination byte array, assuming that the encoding is ASCII + * compatible + * + * @return the number of bytes successfully encoded, or 0 if none + */ + int encodeASCII(char[] src, int srcOff, byte[] dst, int dstOff, int len); + /** * Set the cause of Throwable * @param cause set t's cause to new value diff --git a/src/java.base/share/classes/sun/nio/cs/CESU_8.java b/src/java.base/share/classes/sun/nio/cs/CESU_8.java index b3dcebf5323..f1fc69703c2 100644 --- a/src/java.base/share/classes/sun/nio/cs/CESU_8.java +++ b/src/java.base/share/classes/sun/nio/cs/CESU_8.java @@ -76,11 +76,11 @@ class CESU_8 extends Unicode dst.position(dp - dst.arrayOffset()); } + private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess(); + private static class Decoder extends CharsetDecoder implements ArrayDecoder { - private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess(); - private Decoder(Charset cs) { super(cs, 1.0f, 1.0f); } @@ -434,7 +434,6 @@ class CESU_8 extends Unicode } private Surrogate.Parser sgp; - private char[] c2; private CoderResult encodeArrayLoop(CharBuffer src, ByteBuffer dst) { @@ -445,11 +444,12 @@ class CESU_8 extends Unicode byte[] da = dst.array(); int dp = dst.arrayOffset() + dst.position(); int dl = dst.arrayOffset() + dst.limit(); - int dlASCII = dp + Math.min(sl - sp, dl - dp); - // ASCII only loop - while (dp < dlASCII && sa[sp] < '\u0080') - da[dp++] = (byte) sa[sp++]; + // Handle ASCII-only prefix + int n = JLA.encodeASCII(sa, sp, da, dp, Math.min(sl - sp, dl - dp)); + sp += n; + dp += n; + while (sp < sl) { char c = sa[sp]; if (c < 0x80) { @@ -549,11 +549,11 @@ class CESU_8 extends Unicode public int encode(char[] sa, int sp, int len, byte[] da) { int sl = sp + len; int dp = 0; - int dlASCII = dp + Math.min(len, da.length); - // ASCII only optimized loop - while (dp < dlASCII && sa[sp] < '\u0080') - da[dp++] = (byte) sa[sp++]; + // Handle ASCII-only prefix + int n = JLA.encodeASCII(sa, sp, da, dp, Math.min(len, da.length)); + sp += n; + dp += n; while (sp < sl) { char c = sa[sp++]; diff --git a/src/java.base/share/classes/sun/nio/cs/SingleByte.java b/src/java.base/share/classes/sun/nio/cs/SingleByte.java index 88f89548444..748659b323f 100644 --- a/src/java.base/share/classes/sun/nio/cs/SingleByte.java +++ b/src/java.base/share/classes/sun/nio/cs/SingleByte.java @@ -49,11 +49,11 @@ public class SingleByte return cr; } + private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess(); + public static final class Decoder extends CharsetDecoder implements ArrayDecoder { - private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess(); - private final char[] b2c; private final boolean isASCIICompatible; private final boolean isLatin1Decodable; @@ -214,8 +214,14 @@ public class SingleByte byte[] da = dst.array(); int dp = dst.arrayOffset() + dst.position(); int dl = dst.arrayOffset() + dst.limit(); - int len = Math.min(dl - dp, sl - sp); + int len = Math.min(dl - dp, sl - sp); + if (isASCIICompatible) { + int n = JLA.encodeASCII(sa, sp, da, dp, len); + sp += n; + dp += n; + len -= n; + } while (len-- > 0) { char c = sa[sp]; int b = encode(c); diff --git a/src/java.base/share/classes/sun/nio/cs/US_ASCII.java b/src/java.base/share/classes/sun/nio/cs/US_ASCII.java index 04aeceb43d3..8ff79d497fb 100644 --- a/src/java.base/share/classes/sun/nio/cs/US_ASCII.java +++ b/src/java.base/share/classes/sun/nio/cs/US_ASCII.java @@ -61,9 +61,9 @@ public class US_ASCII return new Encoder(this); } - private static class Decoder extends CharsetDecoder { + private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess(); - private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess(); + private static class Decoder extends CharsetDecoder { private Decoder(Charset cs) { super(cs, 1.0f, 1.0f); @@ -159,6 +159,10 @@ public class US_ASCII assert (dp <= dl); dp = (dp <= dl ? dp : dl); + int n = JLA.encodeASCII(sa, sp, da, dp, Math.min(sl - sp, dl - dp)); + sp += n; + dp += n; + try { while (sp < sl) { char c = sa[sp]; diff --git a/src/java.base/share/classes/sun/nio/cs/UTF_8.java b/src/java.base/share/classes/sun/nio/cs/UTF_8.java index 1a7d8c4d1e1..a27b4690f59 100644 --- a/src/java.base/share/classes/sun/nio/cs/UTF_8.java +++ b/src/java.base/share/classes/sun/nio/cs/UTF_8.java @@ -83,9 +83,9 @@ public final class UTF_8 extends Unicode { dst.position(dp - dst.arrayOffset()); } - private static class Decoder extends CharsetDecoder { + private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess(); - private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess(); + private static class Decoder extends CharsetDecoder { private Decoder(Charset cs) { super(cs, 1.0f, 1.0f); @@ -443,8 +443,7 @@ public final class UTF_8 extends Unicode { private Surrogate.Parser sgp; private CoderResult encodeArrayLoop(CharBuffer src, - ByteBuffer dst) - { + ByteBuffer dst) { char[] sa = src.array(); int sp = src.arrayOffset() + src.position(); int sl = src.arrayOffset() + src.limit(); @@ -452,11 +451,22 @@ public final class UTF_8 extends Unicode { byte[] da = dst.array(); int dp = dst.arrayOffset() + dst.position(); int dl = dst.arrayOffset() + dst.limit(); - int dlASCII = dp + Math.min(sl - sp, dl - dp); - // ASCII only loop - while (dp < dlASCII && sa[sp] < '\u0080') - da[dp++] = (byte) sa[sp++]; + // Handle ASCII-only prefix + int n = JLA.encodeASCII(sa, sp, da, dp, Math.min(sl - sp, dl - dp)); + sp += n; + dp += n; + + if (sp < sl) { + return encodeArrayLoopSlow(src, sa, sp, sl, dst, da, dp, dl); + } else { + updatePositions(src, sp, dst, dp); + return CoderResult.UNDERFLOW; + } + } + + private CoderResult encodeArrayLoopSlow(CharBuffer src, char[] sa, int sp, int sl, + ByteBuffer dst, byte[] da, int dp, int dl) { while (sp < sl) { char c = sa[sp]; if (c < 0x80) { diff --git a/test/hotspot/jtreg/compiler/codegen/Test6896617.java b/test/hotspot/jtreg/compiler/codegen/Test6896617.java deleted file mode 100644 index eddaa3231ea..00000000000 --- a/test/hotspot/jtreg/compiler/codegen/Test6896617.java +++ /dev/null @@ -1,346 +0,0 @@ -/* - * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * 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 - * @key randomness - * @bug 6896617 - * @summary Optimize sun.nio.cs.ISO_8859_1$Encode.encodeArrayLoop() with SSE instructions on x86 - * @library /test/lib - * @modules java.base/jdk.internal.misc - * java.base/sun.nio.cs - * java.management - * - * @ignore 8193479 - * @run main/othervm/timeout=1200 -Xbatch -Xmx256m compiler.codegen.Test6896617 - */ - -package compiler.codegen; - -import jdk.test.lib.Utils; - -import java.nio.ByteBuffer; -import java.nio.CharBuffer; -import java.nio.charset.Charset; -import java.nio.charset.CharsetDecoder; -import java.nio.charset.CharsetEncoder; -import java.nio.charset.CodingErrorAction; -import java.util.Arrays; -import java.util.Random; - -public class Test6896617 { - final static int SIZE = 256; - - public static void main(String[] args) { - String csn = "ISO-8859-1"; - Charset cs = Charset.forName(csn); - CharsetEncoder enc = cs.newEncoder(); - enc.onMalformedInput(CodingErrorAction.REPLACE) - .onUnmappableCharacter(CodingErrorAction.REPLACE); - CharsetDecoder dec = cs.newDecoder(); - dec.onMalformedInput(CodingErrorAction.REPLACE) - .onUnmappableCharacter(CodingErrorAction.REPLACE); - - byte repl = (byte)'?'; - enc.replaceWith(new byte[] { repl }); - - // Use internal API for tests. - sun.nio.cs.ArrayEncoder arrenc = (sun.nio.cs.ArrayEncoder)enc; - sun.nio.cs.ArrayDecoder arrdec = (sun.nio.cs.ArrayDecoder)dec; - - // Populate char[] with chars which can be encoded by ISO_8859_1 (<= 0xFF) - Random rnd = Utils.getRandomInstance(); - int maxchar = 0xFF; - char[] a = new char[SIZE]; - byte[] b = new byte[SIZE]; - char[] at = new char[SIZE]; - byte[] bt = new byte[SIZE]; - for (int i = 0; i < SIZE; i++) { - char c = (char) rnd.nextInt(maxchar); - if (!enc.canEncode(c)) { - System.out.printf("Something wrong: can't encode c=%03x\n", (int)c); - System.exit(97); - } - a[i] = c; - b[i] = (byte)c; - at[i] = (char)-1; - bt[i] = (byte)-1; - } - if (arrenc.encode(a, 0, SIZE, bt) != SIZE || !Arrays.equals(b, bt)) { - System.out.println("Something wrong: ArrayEncoder.encode failed"); - System.exit(97); - } - if (arrdec.decode(b, 0, SIZE, at) != SIZE || !Arrays.equals(a, at)) { - System.out.println("Something wrong: ArrayDecoder.decode failed"); - System.exit(97); - } - for (int i = 0; i < SIZE; i++) { - at[i] = (char)-1; - bt[i] = (byte)-1; - } - - ByteBuffer bb = ByteBuffer.wrap(b); - CharBuffer ba = CharBuffer.wrap(a); - ByteBuffer bbt = ByteBuffer.wrap(bt); - CharBuffer bat = CharBuffer.wrap(at); - if (!enc.encode(ba, bbt, true).isUnderflow() || !Arrays.equals(b, bt)) { - System.out.println("Something wrong: Encoder.encode failed"); - System.exit(97); - } - if (!dec.decode(bb, bat, true).isUnderflow() || !Arrays.equals(a, at)) { - System.out.println("Something wrong: Decoder.decode failed"); - System.exit(97); - } - for (int i = 0; i < SIZE; i++) { - at[i] = (char)-1; - bt[i] = (byte)-1; - } - - // Warm up - boolean failed = false; - int result = 0; - for (int i = 0; i < 10000; i++) { - result += arrenc.encode(a, 0, SIZE, bt); - result -= arrdec.decode(b, 0, SIZE, at); - } - for (int i = 0; i < 10000; i++) { - result += arrenc.encode(a, 0, SIZE, bt); - result -= arrdec.decode(b, 0, SIZE, at); - } - for (int i = 0; i < 10000; i++) { - result += arrenc.encode(a, 0, SIZE, bt); - result -= arrdec.decode(b, 0, SIZE, at); - } - if (result != 0 || !Arrays.equals(b, bt) || !Arrays.equals(a, at)) { - failed = true; - System.out.println("Failed: ArrayEncoder.encode char[" + SIZE + "] and ArrayDecoder.decode byte[" + SIZE + "]"); - } - for (int i = 0; i < SIZE; i++) { - at[i] = (char)-1; - bt[i] = (byte)-1; - } - - boolean is_underflow = true; - for (int i = 0; i < 10000; i++) { - ba.clear(); bb.clear(); bat.clear(); bbt.clear(); - boolean enc_res = enc.encode(ba, bbt, true).isUnderflow(); - boolean dec_res = dec.decode(bb, bat, true).isUnderflow(); - is_underflow = is_underflow && enc_res && dec_res; - } - for (int i = 0; i < SIZE; i++) { - at[i] = (char)-1; - bt[i] = (byte)-1; - } - for (int i = 0; i < 10000; i++) { - ba.clear(); bb.clear(); bat.clear(); bbt.clear(); - boolean enc_res = enc.encode(ba, bbt, true).isUnderflow(); - boolean dec_res = dec.decode(bb, bat, true).isUnderflow(); - is_underflow = is_underflow && enc_res && dec_res; - } - for (int i = 0; i < SIZE; i++) { - at[i] = (char)-1; - bt[i] = (byte)-1; - } - for (int i = 0; i < 10000; i++) { - ba.clear(); bb.clear(); bat.clear(); bbt.clear(); - boolean enc_res = enc.encode(ba, bbt, true).isUnderflow(); - boolean dec_res = dec.decode(bb, bat, true).isUnderflow(); - is_underflow = is_underflow && enc_res && dec_res; - } - if (!is_underflow || !Arrays.equals(b, bt) || !Arrays.equals(a, at)) { - failed = true; - System.out.println("Failed: Encoder.encode char[" + SIZE + "] and Decoder.decode byte[" + SIZE + "]"); - } - - // Test encoder with different source and destination sizes - System.out.println("Testing different source and destination sizes"); - for (int i = 1; i <= SIZE; i++) { - for (int j = 1; j <= SIZE; j++) { - bt = new byte[j]; - // very source's SIZE - result = arrenc.encode(a, 0, i, bt); - int l = Math.min(i, j); - if (result != l) { - failed = true; - System.out.println("Failed: encode char[" + i + "] to byte[" + j + "]: result = " + result + ", expected " + l); - } - for (int k = 0; k < l; k++) { - if (bt[k] != b[k]) { - failed = true; - System.out.println("Failed: encoded byte[" + k + "] (" + bt[k] + ") != " + b[k]); - } - } - // very source's offset - int sz = SIZE - i + 1; - result = arrenc.encode(a, i-1, sz, bt); - l = Math.min(sz, j); - if (result != l) { - failed = true; - System.out.println("Failed: encode char[" + sz + "] to byte[" + j + "]: result = " + result + ", expected " + l); - } - for (int k = 0; k < l; k++) { - if (bt[k] != b[i+k-1]) { - failed = true; - System.out.println("Failed: encoded byte[" + k + "] (" + bt[k] + ") != " + b[i+k-1]); - } - } - } - } - - // Test encoder with char > 0xFF - System.out.println("Testing big char"); - - byte orig = (byte)'A'; - bt = new byte[SIZE]; - for (int i = 1; i <= SIZE; i++) { - for (int j = 0; j < i; j++) { - a[j] += 0x100; - // make sure to replace a different byte - bt[j] = orig; - result = arrenc.encode(a, 0, i, bt); - if (result != i) { - failed = true; - System.out.println("Failed: encode char[" + i + "] to byte[" + i + "]: result = " + result + ", expected " + i); - } - if (bt[j] != repl) { - failed = true; - System.out.println("Failed: encoded replace byte[" + j + "] (" + bt[j] + ") != " + repl); - } - bt[j] = b[j]; // Restore to compare whole array - for (int k = 0; k < i; k++) { - if (bt[k] != b[k]) { - failed = true; - System.out.println("Failed: encoded byte[" + k + "] (" + bt[k] + ") != " + b[k]); - } - } - a[j] -= 0x100; // Restore - } - } - - // Test sun.nio.cs.ISO_8859_1$Encode.encodeArrayLoop() performance. - - int itrs = Integer.getInteger("iterations", 1000000); - int size = Integer.getInteger("size", 256); - a = new char[size]; - b = new byte[size]; - bt = new byte[size]; - for (int i = 0; i < size; i++) { - char c = (char) rnd.nextInt(maxchar); - if (!enc.canEncode(c)) { - System.out.printf("Something wrong: can't encode c=%03x\n", (int)c); - System.exit(97); - } - a[i] = c; - b[i] = (byte)-1; - bt[i] = (byte)c; - } - ba = CharBuffer.wrap(a); - bb = ByteBuffer.wrap(b); - boolean enc_res = enc.encode(ba, bb, true).isUnderflow(); - if (!enc_res || !Arrays.equals(b, bt)) { - failed = true; - System.out.println("Failed 1: Encoder.encode char[" + size + "]"); - } - for (int i = 0; i < size; i++) { - b[i] = (byte)-1; - } - - // Make sure to recompile method if needed before performance run. - for (int i = 0; i < 10000; i++) { - ba.clear(); bb.clear(); - enc_res = enc_res && enc.encode(ba, bb, true).isUnderflow(); - } - for (int i = 0; i < size; i++) { - b[i] = (byte)-1; - } - for (int i = 0; i < 10000; i++) { - ba.clear(); bb.clear(); - enc_res = enc_res && enc.encode(ba, bb, true).isUnderflow(); - } - if (!enc_res || !Arrays.equals(b, bt)) { - failed = true; - System.out.println("Failed 2: Encoder.encode char[" + size + "]"); - } - for (int i = 0; i < size; i++) { - b[i] = (byte)-1; - } - - System.out.println("Testing ISO_8859_1$Encode.encodeArrayLoop() performance"); - long start = System.currentTimeMillis(); - for (int i = 0; i < itrs; i++) { - ba.clear(); bb.clear(); - enc_res = enc_res && enc.encode(ba, bb, true).isUnderflow(); - } - long end = System.currentTimeMillis(); - if (!enc_res || !Arrays.equals(b, bt)) { - failed = true; - System.out.println("Failed 3: Encoder.encode char[" + size + "]"); - } else { - System.out.println("size: " + size + " time: " + (end - start)); - } - - // Test sun.nio.cs.ISO_8859_1$Encode.encode() performance. - - // Make sure to recompile method if needed before performance run. - result = 0; - for (int i = 0; i < size; i++) { - b[i] = (byte)-1; - } - for (int i = 0; i < 10000; i++) { - result += arrenc.encode(a, 0, size, b); - } - for (int i = 0; i < size; i++) { - b[i] = (byte)-1; - } - for (int i = 0; i < 10000; i++) { - result += arrenc.encode(a, 0, size, b); - } - if (result != size*20000 || !Arrays.equals(b, bt)) { - failed = true; - System.out.println("Failed 1: ArrayEncoder.encode char[" + SIZE + "]"); - } - for (int i = 0; i < size; i++) { - b[i] = (byte)-1; - } - - System.out.println("Testing ISO_8859_1$Encode.encode() performance"); - result = 0; - start = System.currentTimeMillis(); - for (int i = 0; i < itrs; i++) { - result += arrenc.encode(a, 0, size, b); - } - end = System.currentTimeMillis(); - if (!Arrays.equals(b, bt)) { - failed = true; - System.out.println("Failed 2: ArrayEncoder.encode char[" + size + "]"); - } else { - System.out.println("size: " + size + " time: " + (end - start)); - } - - if (failed) { - System.out.println("FAILED"); - System.exit(97); - } - System.out.println("PASSED"); - } -} diff --git a/test/hotspot/jtreg/compiler/intrinsics/string/TestEncodeIntrinsics.java b/test/hotspot/jtreg/compiler/intrinsics/string/TestEncodeIntrinsics.java new file mode 100644 index 00000000000..38a516e7521 --- /dev/null +++ b/test/hotspot/jtreg/compiler/intrinsics/string/TestEncodeIntrinsics.java @@ -0,0 +1,249 @@ +/* + * Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 + * @key randomness + * @bug 6896617 8274242 + * @summary Verify potentially intrinsified encoders behave well before and after compilation + * @library /test/lib + * + * @run main/othervm/timeout=1200 --add-opens=java.base/sun.nio.cs=ALL-UNNAMED -Xbatch -Xmx256m compiler.intrinsics.string.TestEncodeIntrinsics + */ + +package compiler.intrinsics.string; + +import jdk.test.lib.Utils; + +import java.lang.reflect.Method; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.Charset; +import java.nio.charset.CharsetDecoder; +import java.nio.charset.CharsetEncoder; +import java.nio.charset.CodingErrorAction; +import java.util.Arrays; +import java.util.Random; + +public class TestEncodeIntrinsics { + final static int SIZE = 256; + + public static void main(String[] args) { + + test("ISO-8859-1", false); + test("UTF-8", true); + test("US-ASCII", true); + test("CESU-8", true); + } + + private static void test(String csn, boolean asciiOnly) { + try { + System.out.println("Testing " + csn); + Charset cs = Charset.forName(csn); + CharsetEncoder enc = cs.newEncoder(); + enc.onMalformedInput(CodingErrorAction.REPLACE) + .onUnmappableCharacter(CodingErrorAction.REPLACE); + CharsetDecoder dec = cs.newDecoder(); + dec.onMalformedInput(CodingErrorAction.REPLACE) + .onUnmappableCharacter(CodingErrorAction.REPLACE); + + byte repl = (byte) '?'; + enc.replaceWith(new byte[]{repl}); + + // Populate char[] with chars which can be encoded by ISO_8859_1 (<= 0xFF) + // - or ASCII (<= 0x7F) if requested + Random rnd = Utils.getRandomInstance(); + int maxchar = asciiOnly ? 0x7F : 0xFF; + char[] a = new char[SIZE]; + byte[] b = new byte[SIZE]; + char[] at = new char[SIZE]; + byte[] bt = new byte[SIZE]; + for (int i = 0; i < SIZE; i++) { + char c = (char) rnd.nextInt(maxchar); + if (!enc.canEncode(c)) { + System.out.printf("Something wrong: can't encode c=%03x\n", (int) c); + System.exit(97); + } + a[i] = c; + b[i] = (byte) c; + at[i] = (char) -1; + bt[i] = (byte) -1; + } + + Method encodeArray = null; + if (csn.equals("ISO-8859-1")) { + // Use internal API for tests + encodeArray = enc.getClass().getDeclaredMethod("encodeISOArray", + char[].class, int.class, byte[].class, int.class, int.class); + encodeArray.setAccessible(true); + if ((int) encodeArray.invoke(enc, a, 0, bt, 0, SIZE) != SIZE || !Arrays.equals(b, bt)) { + System.out.println("Something wrong: ArrayEncoder.encode failed"); + System.exit(97); + } + for (int i = 0; i < SIZE; i++) { + at[i] = (char) -1; + } + } + + ByteBuffer bb = ByteBuffer.wrap(b); + CharBuffer ba = CharBuffer.wrap(a); + ByteBuffer bbt = ByteBuffer.wrap(bt); + CharBuffer bat = CharBuffer.wrap(at); + if (!enc.encode(ba, bbt, true).isUnderflow() || !Arrays.equals(b, bt)) { + System.out.println("Something wrong: Encoder.encode failed"); + System.exit(97); + } + if (!dec.decode(bb, bat, true).isUnderflow() || !Arrays.equals(a, at)) { + System.out.println("Something wrong: Decoder.decode failed (a == at: " + !Arrays.equals(a, at) + ")"); + System.exit(97); + } + for (int i = 0; i < SIZE; i++) { + at[i] = (char) -1; + bt[i] = (byte) -1; + } + + // Warm up + boolean failed = false; + + if (csn.equals("ISO-8859-1")) { + for (int i = 0; i < 10000; i++) { + failed |= (int) encodeArray.invoke(enc, a, 0, bt, 0, SIZE) != SIZE; + } + for (int i = 0; i < 10000; i++) { + failed |= (int) encodeArray.invoke(enc, a, 0, bt, 0, SIZE) != SIZE; + } + for (int i = 0; i < 10000; i++) { + failed |= (int) encodeArray.invoke(enc, a, 0, bt, 0, SIZE) != SIZE; + } + if (failed || !Arrays.equals(b, bt)) { + failed = true; + System.out.println("Failed: ISO_8859_1$Encoder.encode char[" + SIZE + "]"); + } + } + + for (int i = 0; i < SIZE; i++) { + at[i] = (char) -1; + bt[i] = (byte) -1; + } + + boolean is_underflow = true; + for (int i = 0; i < 10000; i++) { + ba.clear(); + bb.clear(); + bat.clear(); + bbt.clear(); + boolean enc_res = enc.encode(ba, bbt, true).isUnderflow(); + boolean dec_res = dec.decode(bb, bat, true).isUnderflow(); + is_underflow = is_underflow && enc_res && dec_res; + } + for (int i = 0; i < SIZE; i++) { + at[i] = (char) -1; + bt[i] = (byte) -1; + } + for (int i = 0; i < 10000; i++) { + ba.clear(); + bb.clear(); + bat.clear(); + bbt.clear(); + boolean enc_res = enc.encode(ba, bbt, true).isUnderflow(); + boolean dec_res = dec.decode(bb, bat, true).isUnderflow(); + is_underflow = is_underflow && enc_res && dec_res; + } + for (int i = 0; i < SIZE; i++) { + at[i] = (char) -1; + bt[i] = (byte) -1; + } + for (int i = 0; i < 10000; i++) { + ba.clear(); + bb.clear(); + bat.clear(); + bbt.clear(); + boolean enc_res = enc.encode(ba, bbt, true).isUnderflow(); + boolean dec_res = dec.decode(bb, bat, true).isUnderflow(); + is_underflow = is_underflow && enc_res && dec_res; + } + if (!is_underflow) { + failed = true; + System.out.println("Failed: got a non-underflow"); + } + if (!Arrays.equals(b, bt)) { + failed = true; + System.out.println("Failed: b != bt"); + } + if (!Arrays.equals(a, at)) { + failed = true; + System.out.println("Failed: a != at"); + } + + // Test encoder with chars outside of the range the intrinsic deals with + System.out.println("Testing big char"); + + bt = new byte[SIZE + 10]; // add some spare room to deal with encoding multi-byte + ba = CharBuffer.wrap(a); + bbt = ByteBuffer.wrap(bt); + for (int i = 1; i <= SIZE; i++) { + for (int j = 0; j < i; j++) { + char bigChar = (char)((asciiOnly ? 0x7F : 0xFF) + 1 + rnd.nextInt(0x100)); + char aOrig = a[j]; + a[j] = bigChar; + // make sure to replace with a different byte + bt[j] = (byte)(bt[j] + 1); + ba.clear(); + ba.limit(i); + bbt.clear(); + if (!enc.encode(ba, bbt, true).isUnderflow()) { + failed = true; + System.out.println("Failed: encode char[" + i + "] to byte[" + i + "]: expected underflow"); + } + if (bt[j] == b[j] && b[j] != repl) { // b[j] can be equal to repl; ignore + failed = true; + System.out.println("Failed: different byte expected at pos bt[" + j + "]"); + } + if (!enc.canEncode(bigChar) && bt[j] != repl) { + failed = true; + System.out.println("Failed: encoded replace byte[" + j + "] (" + bt[j] + ") != " + repl); + } + + // Check that all bytes prior to the replaced one was encoded properly + for (int k = 0; k < j; k++) { + if (bt[k] != b[k]) { + failed = true; + System.out.println("Failed: encoded byte[" + k + "] (" + bt[k] + ") != " + b[k]); + } + } + a[j] = aOrig; // Restore + } + } + + if (failed) { + System.out.println("FAILED"); + System.exit(97); + } + System.out.println("PASSED"); + } catch (Exception e) { + e.printStackTrace(); + System.out.println("FAILED"); + System.exit(97); + } + } +} diff --git a/test/micro/org/openjdk/bench/java/nio/CharsetEncodeDecode.java b/test/micro/org/openjdk/bench/java/nio/CharsetEncodeDecode.java index 51ad531e685..6e129a5466e 100644 --- a/test/micro/org/openjdk/bench/java/nio/CharsetEncodeDecode.java +++ b/test/micro/org/openjdk/bench/java/nio/CharsetEncodeDecode.java @@ -24,12 +24,15 @@ package org.openjdk.bench.java.nio; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; import org.openjdk.jmh.annotations.Mode; import org.openjdk.jmh.annotations.OutputTimeUnit; import org.openjdk.jmh.annotations.Param; import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; import java.nio.ByteBuffer; import java.nio.CharBuffer; @@ -45,8 +48,11 @@ import java.util.concurrent.TimeUnit; * char and byte arrays. */ @BenchmarkMode(Mode.AverageTime) +@Warmup(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) +@Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) @OutputTimeUnit(TimeUnit.MICROSECONDS) @State(Scope.Thread) +@Fork(3) public class CharsetEncodeDecode { private byte[] BYTES; @@ -55,7 +61,7 @@ public class CharsetEncodeDecode { private CharsetEncoder encoder; private CharsetDecoder decoder; - @Param({"BIG5", "ISO-8859-15", "ASCII", "UTF-16"}) + @Param({"UTF-8", "BIG5", "ISO-8859-15", "ASCII", "UTF-16"}) private String type; @Param("16384") -- GitLab From 1dc8fa9902cf2cfa3556ccffb15244115f594966 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Wed, 29 Sep 2021 13:59:58 +0000 Subject: [PATCH 033/385] 8274340: [BACKOUT] JDK-8271880: Tighten condition for excluding regions from collecting cards with cross-references Reviewed-by: kbarrett, ayang --- src/hotspot/share/gc/g1/g1CollectedHeap.cpp | 1 - src/hotspot/share/gc/g1/g1CollectedHeap.hpp | 1 - .../share/gc/g1/g1CollectedHeap.inline.hpp | 4 - src/hotspot/share/gc/g1/g1EvacFailure.cpp | 76 ++++++++++++++++++- src/hotspot/share/gc/g1/g1EvacFailure.hpp | 4 +- src/hotspot/share/gc/g1/g1HeapRegionAttr.hpp | 14 +--- src/hotspot/share/gc/g1/g1OopClosures.hpp | 4 +- .../share/gc/g1/g1ParScanThreadState.cpp | 23 +----- .../share/gc/g1/g1ParScanThreadState.hpp | 2 +- .../gc/g1/g1ParScanThreadState.inline.hpp | 25 ++---- src/hotspot/share/gc/g1/g1YoungCollector.cpp | 30 +------- src/hotspot/share/gc/g1/g1YoungCollector.hpp | 1 + .../gc/g1/g1YoungGCPostEvacuateTasks.cpp | 6 +- .../gc/g1/g1YoungGCPostEvacuateTasks.hpp | 1 + 14 files changed, 95 insertions(+), 97 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index 78f93cf1dcd..1e8e36d8aa3 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp @@ -3277,7 +3277,6 @@ HeapRegion* G1CollectedHeap::new_gc_alloc_region(size_t word_size, G1HeapRegionA new_alloc_region->set_survivor(); _survivor.add(new_alloc_region); _verifier->check_bitmaps("Survivor Region Allocation", new_alloc_region); - register_new_survivor_region_with_region_attr(new_alloc_region); } else { new_alloc_region->set_old(); _verifier->check_bitmaps("Old Region Allocation", new_alloc_region); diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp index 55c271f10c6..a89faf4c1fc 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp @@ -605,7 +605,6 @@ public: void register_young_region_with_region_attr(HeapRegion* r) { _region_attr.set_in_young(r->hrm_index()); } - inline void register_new_survivor_region_with_region_attr(HeapRegion* r); inline void register_region_with_region_attr(HeapRegion* r); inline void register_old_region_with_region_attr(HeapRegion* r); inline void register_optional_region_with_region_attr(HeapRegion* r); diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp b/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp index 0fef0a94449..4de285b980f 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp @@ -184,10 +184,6 @@ void G1CollectedHeap::register_humongous_region_with_region_attr(uint index) { _region_attr.set_humongous(index, region_at(index)->rem_set()->is_tracked()); } -void G1CollectedHeap::register_new_survivor_region_with_region_attr(HeapRegion* r) { - _region_attr.set_new_survivor_region(r->hrm_index()); -} - void G1CollectedHeap::register_region_with_region_attr(HeapRegion* r) { _region_attr.set_has_remset(r->hrm_index(), r->rem_set()->is_tracked()); } diff --git a/src/hotspot/share/gc/g1/g1EvacFailure.cpp b/src/hotspot/share/gc/g1/g1EvacFailure.cpp index d3b9b24bdd8..b7b564abe49 100644 --- a/src/hotspot/share/gc/g1/g1EvacFailure.cpp +++ b/src/hotspot/share/gc/g1/g1EvacFailure.cpp @@ -30,6 +30,7 @@ #include "gc/g1/g1EvacFailureRegions.hpp" #include "gc/g1/g1HeapVerifier.hpp" #include "gc/g1/g1OopClosures.inline.hpp" +#include "gc/g1/g1RedirtyCardsQueue.hpp" #include "gc/g1/heapRegion.hpp" #include "gc/g1/heapRegionRemSet.inline.hpp" #include "gc/shared/preservedMarks.inline.hpp" @@ -37,23 +38,65 @@ #include "oops/compressedOops.inline.hpp" #include "oops/oop.inline.hpp" +class UpdateLogBuffersDeferred : public BasicOopIterateClosure { +private: + G1CollectedHeap* _g1h; + G1RedirtyCardsLocalQueueSet* _rdc_local_qset; + G1CardTable* _ct; + + // Remember the last enqueued card to avoid enqueuing the same card over and over; + // since we only ever handle a card once, this is sufficient. + size_t _last_enqueued_card; + +public: + UpdateLogBuffersDeferred(G1RedirtyCardsLocalQueueSet* rdc_local_qset) : + _g1h(G1CollectedHeap::heap()), + _rdc_local_qset(rdc_local_qset), + _ct(_g1h->card_table()), + _last_enqueued_card(SIZE_MAX) {} + + virtual void do_oop(narrowOop* p) { do_oop_work(p); } + virtual void do_oop( oop* p) { do_oop_work(p); } + template void do_oop_work(T* p) { + assert(_g1h->heap_region_containing(p)->is_in_reserved(p), "paranoia"); + assert(!_g1h->heap_region_containing(p)->is_survivor(), "Unexpected evac failure in survivor region"); + + T const o = RawAccess<>::oop_load(p); + if (CompressedOops::is_null(o)) { + return; + } + + if (HeapRegion::is_in_same_region(p, CompressedOops::decode(o))) { + return; + } + size_t card_index = _ct->index_for(p); + if (card_index != _last_enqueued_card) { + _rdc_local_qset->enqueue(_ct->byte_for_index(card_index)); + _last_enqueued_card = card_index; + } + } +}; + class RemoveSelfForwardPtrObjClosure: public ObjectClosure { G1CollectedHeap* _g1h; G1ConcurrentMark* _cm; HeapRegion* _hr; size_t _marked_bytes; + UpdateLogBuffersDeferred* _log_buffer_cl; bool _during_concurrent_start; uint _worker_id; HeapWord* _last_forwarded_object_end; public: RemoveSelfForwardPtrObjClosure(HeapRegion* hr, + UpdateLogBuffersDeferred* log_buffer_cl, bool during_concurrent_start, uint worker_id) : _g1h(G1CollectedHeap::heap()), _cm(_g1h->concurrent_mark()), _hr(hr), _marked_bytes(0), + _log_buffer_cl(log_buffer_cl), _during_concurrent_start(during_concurrent_start), _worker_id(worker_id), _last_forwarded_object_end(hr->bottom()) { } @@ -98,6 +141,20 @@ public: _marked_bytes += (obj_size * HeapWordSize); PreservedMarks::init_forwarded_mark(obj); + // While we were processing RSet buffers during the collection, + // we actually didn't scan any cards on the collection set, + // since we didn't want to update remembered sets with entries + // that point into the collection set, given that live objects + // from the collection set are about to move and such entries + // will be stale very soon. + // This change also dealt with a reliability issue which + // involved scanning a card in the collection set and coming + // across an array that was being chunked and looking malformed. + // The problem is that, if evacuation fails, we might have + // remembered set entries missing given that we skipped cards on + // the collection set. So, we'll recreate such entries now. + obj->oop_iterate(_log_buffer_cl); + HeapWord* obj_end = obj_addr + obj_size; _last_forwarded_object_end = obj_end; _hr->alloc_block_in_bot(obj_addr, obj_end); @@ -146,22 +203,33 @@ class RemoveSelfForwardPtrHRClosure: public HeapRegionClosure { G1CollectedHeap* _g1h; uint _worker_id; + G1RedirtyCardsLocalQueueSet _rdc_local_qset; + UpdateLogBuffersDeferred _log_buffer_cl; + uint volatile* _num_failed_regions; G1EvacFailureRegions* _evac_failure_regions; public: - RemoveSelfForwardPtrHRClosure(uint worker_id, + RemoveSelfForwardPtrHRClosure(G1RedirtyCardsQueueSet* rdcqs, + uint worker_id, uint volatile* num_failed_regions, G1EvacFailureRegions* evac_failure_regions) : _g1h(G1CollectedHeap::heap()), _worker_id(worker_id), + _rdc_local_qset(rdcqs), + _log_buffer_cl(&_rdc_local_qset), _num_failed_regions(num_failed_regions), _evac_failure_regions(evac_failure_regions) { } + ~RemoveSelfForwardPtrHRClosure() { + _rdc_local_qset.flush(); + } + size_t remove_self_forward_ptr_by_walking_hr(HeapRegion* hr, bool during_concurrent_start) { RemoveSelfForwardPtrObjClosure rspc(hr, + &_log_buffer_cl, during_concurrent_start, _worker_id); hr->object_iterate(&rspc); @@ -200,15 +268,17 @@ public: } }; -G1ParRemoveSelfForwardPtrsTask::G1ParRemoveSelfForwardPtrsTask(G1EvacFailureRegions* evac_failure_regions) : +G1ParRemoveSelfForwardPtrsTask::G1ParRemoveSelfForwardPtrsTask(G1RedirtyCardsQueueSet* rdcqs, + G1EvacFailureRegions* evac_failure_regions) : AbstractGangTask("G1 Remove Self-forwarding Pointers"), _g1h(G1CollectedHeap::heap()), + _rdcqs(rdcqs), _hrclaimer(_g1h->workers()->active_workers()), _evac_failure_regions(evac_failure_regions), _num_failed_regions(0) { } void G1ParRemoveSelfForwardPtrsTask::work(uint worker_id) { - RemoveSelfForwardPtrHRClosure rsfp_cl(worker_id, &_num_failed_regions, _evac_failure_regions); + RemoveSelfForwardPtrHRClosure rsfp_cl(_rdcqs, worker_id, &_num_failed_regions, _evac_failure_regions); // Iterate through all regions that failed evacuation during the entire collection. _evac_failure_regions->par_iterate(&rsfp_cl, &_hrclaimer, worker_id); diff --git a/src/hotspot/share/gc/g1/g1EvacFailure.hpp b/src/hotspot/share/gc/g1/g1EvacFailure.hpp index b0387a3a24f..cd587ac839d 100644 --- a/src/hotspot/share/gc/g1/g1EvacFailure.hpp +++ b/src/hotspot/share/gc/g1/g1EvacFailure.hpp @@ -32,19 +32,21 @@ class G1CollectedHeap; class G1EvacFailureRegions; +class G1RedirtyCardsQueueSet; // Task to fixup self-forwarding pointers // installed as a result of an evacuation failure. class G1ParRemoveSelfForwardPtrsTask: public AbstractGangTask { protected: G1CollectedHeap* _g1h; + G1RedirtyCardsQueueSet* _rdcqs; HeapRegionClaimer _hrclaimer; G1EvacFailureRegions* _evac_failure_regions; uint volatile _num_failed_regions; public: - G1ParRemoveSelfForwardPtrsTask(G1EvacFailureRegions* evac_failure_regions); + G1ParRemoveSelfForwardPtrsTask(G1RedirtyCardsQueueSet* rdcqs, G1EvacFailureRegions* evac_failure_regions); void work(uint worker_id); diff --git a/src/hotspot/share/gc/g1/g1HeapRegionAttr.hpp b/src/hotspot/share/gc/g1/g1HeapRegionAttr.hpp index 3bb7c02b88d..2d8ae1fae40 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionAttr.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionAttr.hpp @@ -57,9 +57,8 @@ public: // // The other values are used for objects in regions requiring various special handling, // eager reclamation of humongous objects or optional regions. - static const region_type_t Optional = -4; // The region is optional not in the current collection set. - static const region_type_t Humongous = -3; // The region is a humongous candidate not in the current collection set. - static const region_type_t NewSurvivor = -2; // The region is a new (ly allocated) survivor region. + static const region_type_t Optional = -3; // The region is optional not in the current collection set. + static const region_type_t Humongous = -2; // The region is a humongous candidate not in the current collection set. static const region_type_t NotInCSet = -1; // The region is not in the collection set. static const region_type_t Young = 0; // The region is in the collection set and a young region. static const region_type_t Old = 1; // The region is in the collection set and an old region. @@ -77,7 +76,6 @@ public: switch (type()) { case Optional: return "Optional"; case Humongous: return "Humongous"; - case NewSurvivor: return "NewSurvivor"; case NotInCSet: return "NotInCSet"; case Young: return "Young"; case Old: return "Old"; @@ -87,7 +85,6 @@ public: bool needs_remset_update() const { return _needs_remset_update != 0; } - void set_new_survivor() { _type = NewSurvivor; } void set_old() { _type = Old; } void clear_humongous() { assert(is_humongous() || !is_in_cset(), "must be"); @@ -99,7 +96,6 @@ public: bool is_in_cset() const { return type() >= Young; } bool is_humongous() const { return type() == Humongous; } - bool is_new_survivor() const { return type() == NewSurvivor; } bool is_young() const { return type() == Young; } bool is_old() const { return type() == Old; } bool is_optional() const { return type() == Optional; } @@ -132,12 +128,6 @@ class G1HeapRegionAttrBiasedMappedArray : public G1BiasedMappedArrayset_new_survivor(); - } - void set_humongous(uintptr_t index, bool needs_remset_update) { assert(get_by_index(index).is_default(), "Region attributes at index " INTPTR_FORMAT " should be default but is %s", index, get_by_index(index).get_type_str()); diff --git a/src/hotspot/share/gc/g1/g1OopClosures.hpp b/src/hotspot/share/gc/g1/g1OopClosures.hpp index 9f0c4a23a55..d8fff5721da 100644 --- a/src/hotspot/share/gc/g1/g1OopClosures.hpp +++ b/src/hotspot/share/gc/g1/g1OopClosures.hpp @@ -116,9 +116,9 @@ class G1SkipCardEnqueueSetter : public StackObj { G1ScanEvacuatedObjClosure* _closure; public: - G1SkipCardEnqueueSetter(G1ScanEvacuatedObjClosure* closure, bool skip_card_enqueue) : _closure(closure) { + G1SkipCardEnqueueSetter(G1ScanEvacuatedObjClosure* closure, bool new_value) : _closure(closure) { assert(_closure->_skip_card_enqueue == G1ScanEvacuatedObjClosure::Uninitialized, "Must not be set"); - _closure->_skip_card_enqueue = skip_card_enqueue ? G1ScanEvacuatedObjClosure::True : G1ScanEvacuatedObjClosure::False; + _closure->_skip_card_enqueue = new_value ? G1ScanEvacuatedObjClosure::True : G1ScanEvacuatedObjClosure::False; } ~G1SkipCardEnqueueSetter() { diff --git a/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp b/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp index 92772cc2db7..03540a95671 100644 --- a/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp +++ b/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp @@ -235,8 +235,8 @@ void G1ParScanThreadState::do_partial_array(PartialArrayScanTask task) { push_on_queue(ScannerTask(PartialArrayScanTask(from_obj))); } - G1HeapRegionAttr dest_attr = _g1h->region_attr(to_array); - G1SkipCardEnqueueSetter x(&_scanner, dest_attr.is_new_survivor()); + HeapRegion* hr = _g1h->heap_region_containing(to_array); + G1SkipCardEnqueueSetter x(&_scanner, hr->is_young()); // Process claimed task. The length of to_array is not correct, but // fortunately the iteration ignores the length field and just relies // on start/end. @@ -268,11 +268,6 @@ void G1ParScanThreadState::start_partial_objarray(G1HeapRegionAttr dest_attr, push_on_queue(ScannerTask(PartialArrayScanTask(from_obj))); } - // Skip the card enqueue iff the object (to_array) is in survivor region. - // However, HeapRegion::is_survivor() is too expensive here. - // Instead, we use dest_attr.is_young() because the two values are always - // equal: successfully allocated young regions must be survivor regions. - assert(dest_attr.is_young() == _g1h->heap_region_containing(to_array)->is_survivor(), "must be"); G1SkipCardEnqueueSetter x(&_scanner, dest_attr.is_young()); // Process the initial chunk. No need to process the type in the // klass, as it will already be handled by processing the built-in @@ -524,11 +519,6 @@ oop G1ParScanThreadState::do_copy_to_survivor_space(G1HeapRegionAttr const regio _string_dedup_requests.add(old); } - // Skip the card enqueue iff the object (obj) is in survivor region. - // However, HeapRegion::is_survivor() is too expensive here. - // Instead, we use dest_attr.is_young() because the two values are always - // equal: successfully allocated young regions must be survivor regions. - assert(dest_attr.is_young() == _g1h->heap_region_containing(obj)->is_survivor(), "must be"); G1SkipCardEnqueueSetter x(&_scanner, dest_attr.is_young()); obj->oop_iterate_backwards(&_scanner, klass); return obj; @@ -615,14 +605,7 @@ oop G1ParScanThreadState::handle_evacuation_failure_par(oop old, markWord m, siz _preserved_marks->push_if_necessary(old, m); _evacuation_failed_info.register_copy_failure(word_sz); - // For iterating objects that failed evacuation currently we can reuse the - // existing closure to scan evacuated objects because: - // - for objects referring into the collection set we do not need to gather - // cards at this time. The regions they are in will be unconditionally turned - // to old regions without remembered sets. - // - since we are iterating from a collection set region (i.e. never a Survivor - // region), we always need to gather cards for this case. - G1SkipCardEnqueueSetter x(&_scanner, false /* skip_card_enqueue */); + G1SkipCardEnqueueSetter x(&_scanner, r->is_young()); old->oop_iterate_backwards(&_scanner); return old; diff --git a/src/hotspot/share/gc/g1/g1ParScanThreadState.hpp b/src/hotspot/share/gc/g1/g1ParScanThreadState.hpp index 0ecc11f50a5..ea4fb10f5bd 100644 --- a/src/hotspot/share/gc/g1/g1ParScanThreadState.hpp +++ b/src/hotspot/share/gc/g1/g1ParScanThreadState.hpp @@ -134,7 +134,7 @@ public: // Apply the post barrier to the given reference field. Enqueues the card of p // if the barrier does not filter out the reference for some reason (e.g. - // p and q are in the same region, p is in survivor, p is in collection set) + // p and q are in the same region, p is in survivor) // To be called during GC if nothing particular about p and obj are known. template void write_ref_field_post(T* p, oop obj); diff --git a/src/hotspot/share/gc/g1/g1ParScanThreadState.inline.hpp b/src/hotspot/share/gc/g1/g1ParScanThreadState.inline.hpp index a3634737103..1184919dbf2 100644 --- a/src/hotspot/share/gc/g1/g1ParScanThreadState.inline.hpp +++ b/src/hotspot/share/gc/g1/g1ParScanThreadState.inline.hpp @@ -97,34 +97,19 @@ G1OopStarChunkedList* G1ParScanThreadState::oops_into_optional_region(const Heap } template void G1ParScanThreadState::write_ref_field_post(T* p, oop obj) { - assert(obj != nullptr, "Must be"); + assert(obj != NULL, "Must be"); if (HeapRegion::is_in_same_region(p, obj)) { return; } - G1HeapRegionAttr from_attr = _g1h->region_attr(p); - // If this is a reference from (current) survivor regions, we do not need - // to track references from it. - if (from_attr.is_new_survivor()) { - return; - } - G1HeapRegionAttr dest_attr = _g1h->region_attr(obj); - // References to the current collection set are references to objects that failed - // evacuation. Currently these regions are always relabelled as old without - // remembered sets, so skip them. - assert(dest_attr.is_in_cset() == (obj->forwardee() == obj), - "Only evac-failed objects must be in the collection set here but " PTR_FORMAT " is not", p2i(obj)); - if (dest_attr.is_in_cset()) { - return; + HeapRegion* from = _g1h->heap_region_containing(p); + if (!from->is_young()) { + enqueue_card_if_tracked(_g1h->region_attr(obj), p, obj); } - enqueue_card_if_tracked(dest_attr, p, obj); } template void G1ParScanThreadState::enqueue_card_if_tracked(G1HeapRegionAttr region_attr, T* p, oop o) { assert(!HeapRegion::is_in_same_region(p, o), "Should have filtered out cross-region references already."); - assert(!_g1h->heap_region_containing(p)->is_survivor(), "Should have filtered out from-newly allocated survivor references already."); - // We relabel all regions that failed evacuation as old gen without remembered, - // and so pre-filter them out in the caller. - assert(!_g1h->heap_region_containing(o)->in_collection_set(), "Should not try to enqueue reference into collection set region"); + assert(!_g1h->heap_region_containing(p)->is_young(), "Should have filtered out from-young references already."); #ifdef ASSERT HeapRegion* const hr_obj = _g1h->heap_region_containing(o); diff --git a/src/hotspot/share/gc/g1/g1YoungCollector.cpp b/src/hotspot/share/gc/g1/g1YoungCollector.cpp index e1c0fcd16df..13296026a34 100644 --- a/src/hotspot/share/gc/g1/g1YoungCollector.cpp +++ b/src/hotspot/share/gc/g1/g1YoungCollector.cpp @@ -25,7 +25,6 @@ #include "precompiled.hpp" #include "classfile/classLoaderDataGraph.inline.hpp" -#include "classfile/javaClasses.inline.hpp" #include "compiler/oopMap.hpp" #include "gc/g1/g1Allocator.hpp" #include "gc/g1/g1CardSetMemory.hpp" @@ -912,33 +911,6 @@ class G1STWRefProcProxyTask : public RefProcProxyTask { TaskTerminator _terminator; G1ScannerTasksQueueSet& _task_queues; - // Special closure for enqueuing discovered fields: during enqueue the card table - // may not be in shape to properly handle normal barrier calls (e.g. card marks - // in regions that failed evacuation, scribbling of various values by card table - // scan code). Additionally the regular barrier enqueues into the "global" - // DCQS, but during GC we need these to-be-refined entries in the GC local queue - // so that after clearing the card table, the redirty cards phase will properly - // mark all dirty cards to be picked up by refinement. - class G1EnqueueDiscoveredFieldClosure : public EnqueueDiscoveredFieldClosure { - G1CollectedHeap* _g1h; - G1ParScanThreadState* _pss; - - public: - G1EnqueueDiscoveredFieldClosure(G1CollectedHeap* g1h, G1ParScanThreadState* pss) : _g1h(g1h), _pss(pss) { } - - void enqueue(oop reference, oop value) override { - HeapWord* discovered_addr = java_lang_ref_Reference::discovered_addr_raw(reference); - - // Store the value first, whatever it is. - RawAccess<>::oop_store(discovered_addr, value); - - if (value == nullptr) { - return; - } - _pss->write_ref_field_post(discovered_addr, value); - } - }; - public: G1STWRefProcProxyTask(uint max_workers, G1CollectedHeap& g1h, G1ParScanThreadStateSet& pss, G1ScannerTasksQueueSet& task_queues) : RefProcProxyTask("G1STWRefProcProxyTask", max_workers), @@ -956,7 +928,7 @@ public: G1STWIsAliveClosure is_alive(&_g1h); G1CopyingKeepAliveClosure keep_alive(&_g1h, pss); - G1EnqueueDiscoveredFieldClosure enqueue(&_g1h, pss); + BarrierEnqueueDiscoveredFieldClosure enqueue; G1ParEvacuateFollowersClosure complete_gc(&_g1h, pss, &_task_queues, _tm == RefProcThreadModel::Single ? nullptr : &_terminator, G1GCPhaseTimes::ObjCopy); _rp_task->rp_work(worker_id, &is_alive, &keep_alive, &enqueue, &complete_gc); diff --git a/src/hotspot/share/gc/g1/g1YoungCollector.hpp b/src/hotspot/share/gc/g1/g1YoungCollector.hpp index cc6370f1957..94a5e1c091e 100644 --- a/src/hotspot/share/gc/g1/g1YoungCollector.hpp +++ b/src/hotspot/share/gc/g1/g1YoungCollector.hpp @@ -142,6 +142,7 @@ class G1YoungCollector { #endif // TASKQUEUE_STATS public: + G1YoungCollector(GCCause::Cause gc_cause, double target_pause_time_ms); void collect(); diff --git a/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp b/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp index 88c9cba3c60..727c4538610 100644 --- a/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp +++ b/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp @@ -102,9 +102,9 @@ class G1PostEvacuateCollectionSetCleanupTask1::RemoveSelfForwardPtrsTask : publi G1EvacFailureRegions* _evac_failure_regions; public: - RemoveSelfForwardPtrsTask(G1EvacFailureRegions* evac_failure_regions) : + RemoveSelfForwardPtrsTask(G1RedirtyCardsQueueSet* rdcqs, G1EvacFailureRegions* evac_failure_regions) : G1AbstractSubTask(G1GCPhaseTimes::RemoveSelfForwardingPtr), - _task(evac_failure_regions), + _task(rdcqs, evac_failure_regions), _evac_failure_regions(evac_failure_regions) { } ~RemoveSelfForwardPtrsTask() { @@ -135,7 +135,7 @@ G1PostEvacuateCollectionSetCleanupTask1::G1PostEvacuateCollectionSetCleanupTask1 add_serial_task(new SampleCollectionSetCandidatesTask()); } if (evacuation_failed) { - add_parallel_task(new RemoveSelfForwardPtrsTask(evac_failure_regions)); + add_parallel_task(new RemoveSelfForwardPtrsTask(per_thread_states->rdcqs(), evac_failure_regions)); } add_parallel_task(G1CollectedHeap::heap()->rem_set()->create_cleanup_after_scan_heap_roots_task()); } diff --git a/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.hpp b/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.hpp index 6613438e19b..0201dc3a738 100644 --- a/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.hpp +++ b/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.hpp @@ -34,6 +34,7 @@ class G1CollectedHeap; class G1EvacFailureRegions; class G1EvacInfo; class G1ParScanThreadStateSet; +class G1RedirtyCardsQueueSet; // First set of post evacuate collection set tasks containing ("s" means serial): // - Merge PSS (s) -- GitLab From 980c50dc607e60e12879bd6fb7ff4034469e88d8 Mon Sep 17 00:00:00 2001 From: Roland Westrelin Date: Wed, 29 Sep 2021 14:51:33 +0000 Subject: [PATCH 034/385] 8272562: C2: assert(false) failed: Bad graph detected in build_loop_late Reviewed-by: chagedorn, kvn --- src/hotspot/share/opto/loopopts.cpp | 3 +- .../TestSunkCastOnUnreachablePath.java | 53 +++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 test/hotspot/jtreg/compiler/loopopts/TestSunkCastOnUnreachablePath.java diff --git a/src/hotspot/share/opto/loopopts.cpp b/src/hotspot/share/opto/loopopts.cpp index 3073ac1a307..4379a6c744b 100644 --- a/src/hotspot/share/opto/loopopts.cpp +++ b/src/hotspot/share/opto/loopopts.cpp @@ -1445,7 +1445,8 @@ void PhaseIdealLoop::try_sink_out_of_loop(Node* n) { !n->is_MergeMem() && !n->is_CMove() && !is_raw_to_oop_cast && // don't extend live ranges of raw oops - n->Opcode() != Op_Opaque4) { + n->Opcode() != Op_Opaque4 && + !n->is_Type()) { Node *n_ctrl = get_ctrl(n); IdealLoopTree *n_loop = get_loop(n_ctrl); diff --git a/test/hotspot/jtreg/compiler/loopopts/TestSunkCastOnUnreachablePath.java b/test/hotspot/jtreg/compiler/loopopts/TestSunkCastOnUnreachablePath.java new file mode 100644 index 00000000000..def5182f7fb --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/TestSunkCastOnUnreachablePath.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2021, 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 8272562 + * @summary C2: assert(false) failed: Bad graph detected in build_loop_late + * + * @run main/othervm -XX:CompileOnly=TestSunkCastOnUnreachablePath -XX:-TieredCompilation -Xbatch TestSunkCastOnUnreachablePath + * + */ + +public class TestSunkCastOnUnreachablePath { + + public static void main(String[] strArr) { + for (int i = 0; i < 1000; i++) { + vMeth(); + } + } + + static int vMeth() { + int i2 = 3, iArr1[] = new int[200]; + + for (int i9 = 3; i9 < 100; i9++) { + try { + int i10 = (iArr1[i9 - 1]); + i2 = (i10 / i9); + } catch (ArithmeticException a_e) { + } + } + return i2; + } +} -- GitLab From edd9d1c97b7fb50e76abc05d298c9d55db39cc1b Mon Sep 17 00:00:00 2001 From: Weijun Wang Date: Wed, 29 Sep 2021 15:37:16 +0000 Subject: [PATCH 035/385] 8274330: Incorrect encoding of the DistributionPointName object in IssuingDistributionPointExtension Reviewed-by: ascarpino --- .../IssuingDistributionPointExtension.java | 5 +- ...ingDistributionPointExtensionEncoding.java | 49 +++++++++++++++++++ 2 files changed, 52 insertions(+), 2 deletions(-) create mode 100644 test/jdk/sun/security/x509/Extensions/IssuingDistributionPointExtensionEncoding.java diff --git a/src/java.base/share/classes/sun/security/x509/IssuingDistributionPointExtension.java b/src/java.base/share/classes/sun/security/x509/IssuingDistributionPointExtension.java index bc0df11a8a2..d810cf012ae 100644 --- a/src/java.base/share/classes/sun/security/x509/IssuingDistributionPointExtension.java +++ b/src/java.base/share/classes/sun/security/x509/IssuingDistributionPointExtension.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -393,7 +393,8 @@ public class IssuingDistributionPointExtension extends Extension if (distributionPoint != null) { DerOutputStream tmp = new DerOutputStream(); distributionPoint.encode(tmp); - tagged.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT, true, + // DistributionPointName is CHOICE. Do not writeImplicit. + tagged.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, TAG_DISTRIBUTION_POINT), tmp); } diff --git a/test/jdk/sun/security/x509/Extensions/IssuingDistributionPointExtensionEncoding.java b/test/jdk/sun/security/x509/Extensions/IssuingDistributionPointExtensionEncoding.java new file mode 100644 index 00000000000..6ba6ed4b9e9 --- /dev/null +++ b/test/jdk/sun/security/x509/Extensions/IssuingDistributionPointExtensionEncoding.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 Incorrect encoding of the DistributionPointName object + * in IssuingDistributionPointExtension + * @bug 8274330 + * @modules java.base/sun.security.x509 + */ + +import sun.security.x509.DistributionPointName; +import sun.security.x509.GeneralName; +import sun.security.x509.GeneralNames; +import sun.security.x509.IssuingDistributionPointExtension; +import sun.security.x509.URIName; + +public class IssuingDistributionPointExtensionEncoding { + public static void main(String [] args) throws Exception { + var names = new GeneralNames(); + names.add(new GeneralName(new URIName("http://here"))); + // write one + var ext = new IssuingDistributionPointExtension( + new DistributionPointName(names), + null, true, false, false, false); + // read it + new IssuingDistributionPointExtension(true, ext.getValue()); + } +} -- GitLab From b1b66965f1ec6eae547cc4f70f8271bd39ded6da Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Wed, 29 Sep 2021 16:57:40 +0000 Subject: [PATCH 036/385] 8274453: (sctp) com/sun/nio/sctp/SctpChannel/CloseDescriptors.java test should be resilient to lsof warnings Reviewed-by: dfuchs --- test/jdk/com/sun/nio/sctp/SctpChannel/CloseDescriptors.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/jdk/com/sun/nio/sctp/SctpChannel/CloseDescriptors.java b/test/jdk/com/sun/nio/sctp/SctpChannel/CloseDescriptors.java index 35e5bcbcc09..c8ed8a881f6 100644 --- a/test/jdk/com/sun/nio/sctp/SctpChannel/CloseDescriptors.java +++ b/test/jdk/com/sun/nio/sctp/SctpChannel/CloseDescriptors.java @@ -120,7 +120,7 @@ public class CloseDescriptors { private static boolean check() throws Exception { long myPid = ProcessHandle.current().pid(); ProcessBuilder pb = new ProcessBuilder( - "lsof", "-U", "-a", "-p", Long.toString(myPid)); + "lsof", "-U", "-a", "-w", "-p", Long.toString(myPid)); pb.redirectErrorStream(true); Process p = pb.start(); p.waitFor(); -- GitLab From 97b28742b4d3083cadbe4dc10b625ec9fb944353 Mon Sep 17 00:00:00 2001 From: Pavel Rappo Date: Wed, 29 Sep 2021 17:09:08 +0000 Subject: [PATCH 037/385] 8274509: Remove stray * and stylistic . from doc comments Reviewed-by: alanb, dfuchs, lancea, iris, bpb --- src/java.base/share/classes/java/nio/file/Files.java | 2 +- src/java.base/share/classes/java/nio/file/Path.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/java.base/share/classes/java/nio/file/Files.java b/src/java.base/share/classes/java/nio/file/Files.java index d78773db475..01f01e2679a 100644 --- a/src/java.base/share/classes/java/nio/file/Files.java +++ b/src/java.base/share/classes/java/nio/file/Files.java @@ -3110,7 +3110,7 @@ public final class Files { * @throws DirectoryNotEmptyException * the {@code REPLACE_EXISTING} option is specified but the file * cannot be replaced because it is a non-empty directory - * (optional specific exception) * + * (optional specific exception) * @throws UnsupportedOperationException * if {@code options} contains a copy option that is not supported * @throws SecurityException diff --git a/src/java.base/share/classes/java/nio/file/Path.java b/src/java.base/share/classes/java/nio/file/Path.java index d9d2cfb32a5..d7446f53c2b 100644 --- a/src/java.base/share/classes/java/nio/file/Path.java +++ b/src/java.base/share/classes/java/nio/file/Path.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -911,7 +911,7 @@ public interface Path * {@code getName(index)}, where {@code index} ranges from zero to * {@code getNameCount() - 1}, inclusive. * - * @return an iterator over the name elements of this path. + * @return an iterator over the name elements of this path */ @Override default Iterator iterator() { -- GitLab From 79cebe2c1b1e7f43377633b62c970528cac0a786 Mon Sep 17 00:00:00 2001 From: Andrey Turbanov Date: Wed, 29 Sep 2021 18:22:40 +0000 Subject: [PATCH 038/385] 8274050: Unnecessary Vector usage in javax.crypto Reviewed-by: valeriep --- .../javax/crypto/CryptoPermissions.java | 26 ++++++++----------- .../javax/crypto/CryptoPolicyParser.java | 25 ++++++++---------- 2 files changed, 22 insertions(+), 29 deletions(-) diff --git a/src/java.base/share/classes/javax/crypto/CryptoPermissions.java b/src/java.base/share/classes/javax/crypto/CryptoPermissions.java index ced2e2bd88b..703b2b67863 100644 --- a/src/java.base/share/classes/javax/crypto/CryptoPermissions.java +++ b/src/java.base/share/classes/javax/crypto/CryptoPermissions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,9 +26,9 @@ package javax.crypto; import java.security.*; +import java.util.ArrayList; import java.util.Enumeration; import java.util.Hashtable; -import java.util.Vector; import java.util.NoSuchElementException; import java.util.concurrent.ConcurrentHashMap; import java.io.Serializable; @@ -307,7 +307,7 @@ implements Serializable { */ private CryptoPermission[] getMinimum(PermissionCollection thisPc, PermissionCollection thatPc) { - Vector permVector = new Vector<>(2); + ArrayList permList = new ArrayList<>(2); Enumeration thisPcPermissions = thisPc.elements(); @@ -334,18 +334,16 @@ implements Serializable { (CryptoPermission)thatPcPermissions.nextElement(); if (thatCp.implies(thisCp)) { - permVector.addElement(thisCp); + permList.add(thisCp); break; } if (thisCp.implies(thatCp)) { - permVector.addElement(thatCp); + permList.add(thatCp); } } } - CryptoPermission[] ret = new CryptoPermission[permVector.size()]; - permVector.copyInto(ret); - return ret; + return permList.toArray(new CryptoPermission[0]); } /** @@ -363,7 +361,7 @@ implements Serializable { */ private CryptoPermission[] getMinimum(int maxKeySize, PermissionCollection pc) { - Vector permVector = new Vector<>(1); + ArrayList permList = new ArrayList<>(1); Enumeration enum_ = pc.elements(); @@ -371,16 +369,16 @@ implements Serializable { CryptoPermission cp = (CryptoPermission)enum_.nextElement(); if (cp.getMaxKeySize() <= maxKeySize) { - permVector.addElement(cp); + permList.add(cp); } else { if (cp.getCheckParam()) { - permVector.addElement( + permList.add( new CryptoPermission(cp.getAlgorithm(), maxKeySize, cp.getAlgorithmParameterSpec(), cp.getExemptionMechanism())); } else { - permVector.addElement( + permList.add( new CryptoPermission(cp.getAlgorithm(), maxKeySize, cp.getExemptionMechanism())); @@ -388,9 +386,7 @@ implements Serializable { } } - CryptoPermission[] ret = new CryptoPermission[permVector.size()]; - permVector.copyInto(ret); - return ret; + return permList.toArray(new CryptoPermission[0]); } /** diff --git a/src/java.base/share/classes/javax/crypto/CryptoPolicyParser.java b/src/java.base/share/classes/javax/crypto/CryptoPolicyParser.java index 9cc8bc48e80..5ccaa814315 100644 --- a/src/java.base/share/classes/javax/crypto/CryptoPolicyParser.java +++ b/src/java.base/share/classes/javax/crypto/CryptoPolicyParser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved. * 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,6 +26,7 @@ package javax.crypto; import java.io.*; +import java.util.ArrayList; import java.util.Enumeration; import java.util.Hashtable; import java.util.Vector; @@ -254,15 +255,15 @@ final class CryptoPolicyParser { // AlgorithmParameterSpec class name. String algParamSpecClassName = match("quoted string"); - Vector paramsV = new Vector<>(1); + ArrayList paramsV = new ArrayList<>(1); while (peek(",")) { match(","); if (peek("number")) { - paramsV.addElement(match()); + paramsV.add(match()); } else { if (peek("*")) { match("*"); - paramsV.addElement(Integer.MAX_VALUE); + paramsV.add(Integer.MAX_VALUE); } else { throw new ParsingException(st.lineno(), "Expecting an integer"); @@ -270,8 +271,7 @@ final class CryptoPolicyParser { } } - Integer[] params = new Integer[paramsV.size()]; - paramsV.copyInto(params); + Integer[] params = paramsV.toArray(new Integer[0]); e.checkParam = true; e.algParamSpec = getInstance(algParamSpecClassName, params); @@ -458,7 +458,7 @@ final class CryptoPolicyParser { } CryptoPermission[] getPermissions() { - Vector result = new Vector<>(); + ArrayList result = new ArrayList<>(); Enumeration grantEnum = grantEntries.elements(); while (grantEnum.hasMoreElements()) { @@ -469,16 +469,16 @@ final class CryptoPolicyParser { CryptoPermissionEntry pe = permEnum.nextElement(); if (pe.cryptoPermission.equals( "javax.crypto.CryptoAllPermission")) { - result.addElement(CryptoAllPermission.INSTANCE); + result.add(CryptoAllPermission.INSTANCE); } else { if (pe.checkParam) { - result.addElement(new CryptoPermission( + result.add(new CryptoPermission( pe.alg, pe.maxKeySize, pe.algParamSpec, pe.exemptionMechanism)); } else { - result.addElement(new CryptoPermission( + result.add(new CryptoPermission( pe.alg, pe.maxKeySize, pe.exemptionMechanism)); @@ -487,10 +487,7 @@ final class CryptoPolicyParser { } } - CryptoPermission[] ret = new CryptoPermission[result.size()]; - result.copyInto(ret); - - return ret; + return result.toArray(new CryptoPermission[0]); } private boolean isConsistent(String alg, String exemptionMechanism, -- GitLab From 97385d4f166fbd63a7c91d2ee28b5ed75cb02518 Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Wed, 29 Sep 2021 23:02:20 +0000 Subject: [PATCH 039/385] 8274405: Suppress warnings on non-serializable non-transient instance fields in javac and javadoc Reviewed-by: prappo, jjg --- .../share/classes/com/sun/source/util/DocTreePath.java | 3 ++- .../share/classes/com/sun/source/util/TreePath.java | 1 + .../share/classes/com/sun/tools/javac/tree/TreeInfo.java | 1 + .../share/classes/com/sun/tools/sjavac/pubapi/PubApi.java | 3 ++- .../classes/com/sun/tools/sjavac/pubapi/PubApiTypeParam.java | 3 ++- .../share/classes/com/sun/tools/sjavac/pubapi/PubMethod.java | 3 ++- .../share/classes/com/sun/tools/sjavac/pubapi/PubType.java | 3 ++- .../share/classes/com/sun/tools/sjavac/pubapi/PubVar.java | 3 ++- .../com/sun/tools/sjavac/server/CompilationSubResult.java | 3 ++- .../internal/doclets/toolkit/util/DocFileIOException.java | 3 ++- .../internal/doclets/toolkit/util/ResourceIOException.java | 3 ++- .../classes/jdk/javadoc/internal/tool/OptionException.java | 3 ++- 12 files changed, 22 insertions(+), 10 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/source/util/DocTreePath.java b/src/jdk.compiler/share/classes/com/sun/source/util/DocTreePath.java index 3a66838729f..8b6467e1204 100644 --- a/src/jdk.compiler/share/classes/com/sun/source/util/DocTreePath.java +++ b/src/jdk.compiler/share/classes/com/sun/source/util/DocTreePath.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -64,6 +64,7 @@ public class DocTreePath implements Iterable { class Result extends Error { static final long serialVersionUID = -5942088234594905625L; + @SuppressWarnings("serial") // Type of field is not Serializable DocTreePath path; Result(DocTreePath path) { this.path = path; diff --git a/src/jdk.compiler/share/classes/com/sun/source/util/TreePath.java b/src/jdk.compiler/share/classes/com/sun/source/util/TreePath.java index 4dea9914516..63183d66db2 100644 --- a/src/jdk.compiler/share/classes/com/sun/source/util/TreePath.java +++ b/src/jdk.compiler/share/classes/com/sun/source/util/TreePath.java @@ -63,6 +63,7 @@ public class TreePath implements Iterable { class Result extends Error { static final long serialVersionUID = -5942088234594905625L; + @SuppressWarnings("serial") // Type of field is not Serializable TreePath path; Result(TreePath path) { this.path = path; 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 4c6cfb45a14..ee25802ca86 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 @@ -805,6 +805,7 @@ public class TreeInfo { public static List pathFor(final JCTree node, final JCCompilationUnit unit) { class Result extends Error { static final long serialVersionUID = -5942088234594905625L; + @SuppressWarnings("serial") // List not statically Serilizable List path; Result(List path) { this.path = path; diff --git a/src/jdk.compiler/share/classes/com/sun/tools/sjavac/pubapi/PubApi.java b/src/jdk.compiler/share/classes/com/sun/tools/sjavac/pubapi/PubApi.java index c44b07902e6..777fc0a1a3b 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/sjavac/pubapi/PubApi.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/sjavac/pubapi/PubApi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -49,6 +49,7 @@ import javax.lang.model.element.Modifier; import com.sun.tools.javac.util.Assert; import com.sun.tools.javac.util.StringUtils; +@SuppressWarnings("serial") // Types of instance fields are not Serializable public class PubApi implements Serializable { private static final long serialVersionUID = 5926627347801986850L; diff --git a/src/jdk.compiler/share/classes/com/sun/tools/sjavac/pubapi/PubApiTypeParam.java b/src/jdk.compiler/share/classes/com/sun/tools/sjavac/pubapi/PubApiTypeParam.java index 863d068d859..d2e07dd9471 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/sjavac/pubapi/PubApiTypeParam.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/sjavac/pubapi/PubApiTypeParam.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,7 @@ import java.io.Serializable; import java.util.List; import java.util.stream.Collectors; +@SuppressWarnings("serial") // Types of instance fields are not Serializable public class PubApiTypeParam implements Serializable { private static final long serialVersionUID = 8899204612014329162L; diff --git a/src/jdk.compiler/share/classes/com/sun/tools/sjavac/pubapi/PubMethod.java b/src/jdk.compiler/share/classes/com/sun/tools/sjavac/pubapi/PubMethod.java index 193b369ddee..3dd64ff7d58 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/sjavac/pubapi/PubMethod.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/sjavac/pubapi/PubMethod.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,7 @@ import java.util.stream.Collectors; import javax.lang.model.element.Modifier; +@SuppressWarnings("serial") // Types of instance fields are not Serializable public class PubMethod implements Serializable { private static final long serialVersionUID = -7813050194553446243L; diff --git a/src/jdk.compiler/share/classes/com/sun/tools/sjavac/pubapi/PubType.java b/src/jdk.compiler/share/classes/com/sun/tools/sjavac/pubapi/PubType.java index 40fe4abe9bd..0c87f8a35d5 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/sjavac/pubapi/PubType.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/sjavac/pubapi/PubType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,6 +30,7 @@ import java.util.Set; import javax.lang.model.element.Modifier; +@SuppressWarnings("serial") // Types of instance fields are not Serializable public class PubType implements Serializable { private static final long serialVersionUID = -7423416049253889793L; diff --git a/src/jdk.compiler/share/classes/com/sun/tools/sjavac/pubapi/PubVar.java b/src/jdk.compiler/share/classes/com/sun/tools/sjavac/pubapi/PubVar.java index bc898fa744c..50e1d3c88b3 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/sjavac/pubapi/PubVar.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/sjavac/pubapi/PubVar.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. * 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,6 +31,7 @@ import java.util.Set; import javax.lang.model.element.Modifier; +@SuppressWarnings("serial") // Types of instance fields are not Serializable public class PubVar implements Serializable { private static final long serialVersionUID = 5806536061153374575L; diff --git a/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/CompilationSubResult.java b/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/CompilationSubResult.java index 5a60aa2bef7..d8b24a86d44 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/CompilationSubResult.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/CompilationSubResult.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,6 +41,7 @@ import com.sun.tools.sjavac.pubapi.PubApi; * This code and its internal interfaces are subject to change or * deletion without notice. */ +@SuppressWarnings("serial") // Types of instance fields are not Serializable public class CompilationSubResult implements Serializable { static final long serialVersionUID = 46739181113L; diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/DocFileIOException.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/DocFileIOException.java index 7cd2811a702..3eee4fc77b4 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/DocFileIOException.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/DocFileIOException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -57,6 +57,7 @@ public class DocFileIOException extends DocletException { /** * The file that was in use when the exception occurred. */ + @SuppressWarnings("serial") // Type of field is not Serializable public final DocFile fileName; /** diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/ResourceIOException.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/ResourceIOException.java index 402850a2133..14a7d7062b2 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/ResourceIOException.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/ResourceIOException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. * 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,6 +46,7 @@ public class ResourceIOException extends DocletException { /** * The resource that was in use when the exception occurred. */ + @SuppressWarnings("serial") // Type of field is not Serializable public final DocPath resource; private static final long serialVersionUID = 1L; diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/OptionException.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/OptionException.java index 3a9bf89299b..145e7d188c7 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/OptionException.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/OptionException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,6 +43,7 @@ class OptionException extends Exception { public final Result result; public final String message; + @SuppressWarnings("serial") // Type of field is not Serializable public final Runnable m; /** -- GitLab From 355356c405adb9287b786b0b045c2eb974d2ffca Mon Sep 17 00:00:00 2001 From: Andrey Turbanov Date: Wed, 29 Sep 2021 23:08:23 +0000 Subject: [PATCH 040/385] 8273435: Remove redundant zero-length check in ClassDesc.of Reviewed-by: rriggs --- src/java.base/share/classes/java/lang/constant/ClassDesc.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/java.base/share/classes/java/lang/constant/ClassDesc.java b/src/java.base/share/classes/java/lang/constant/ClassDesc.java index 435d992fa50..14923594c0e 100644 --- a/src/java.base/share/classes/java/lang/constant/ClassDesc.java +++ b/src/java.base/share/classes/java/lang/constant/ClassDesc.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -99,7 +99,7 @@ public sealed interface ClassDesc } validateMemberName(requireNonNull(className), false); return ofDescriptor("L" + binaryToInternal(packageName) + - (packageName.length() > 0 ? "/" : "") + className + ";"); + "/" + className + ";"); } /** -- GitLab From f8415a9b2f610ed431e6948c8174f6d982e5b31f Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Thu, 30 Sep 2021 06:54:13 +0000 Subject: [PATCH 041/385] 8274523: java/lang/management/MemoryMXBean/MemoryTest.java test should handle Shenandoah Reviewed-by: mchung, cjplummer --- test/jdk/java/lang/management/MemoryMXBean/MemoryTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/jdk/java/lang/management/MemoryMXBean/MemoryTest.java b/test/jdk/java/lang/management/MemoryMXBean/MemoryTest.java index d60b2e46593..a0828dc63bd 100644 --- a/test/jdk/java/lang/management/MemoryMXBean/MemoryTest.java +++ b/test/jdk/java/lang/management/MemoryMXBean/MemoryTest.java @@ -26,7 +26,7 @@ * @bug 4530538 * @summary Basic unit test of MemoryMXBean.getMemoryPools() and * MemoryMXBean.getMemoryManager(). - * @requires vm.gc != "Z" + * @requires vm.gc != "Z" & vm.gc != "Shenandoah" * @author Mandy Chung * * @modules jdk.management @@ -38,7 +38,7 @@ * @bug 4530538 * @summary Basic unit test of MemoryMXBean.getMemoryPools() and * MemoryMXBean.getMemoryManager(). - * @requires vm.gc == "Z" + * @requires vm.gc == "Z" | vm.gc == "Shenandoah" * @author Mandy Chung * * @modules jdk.management -- GitLab From c0533ef2d8e526aaec0eebe862f4bbefc159ea37 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Thu, 30 Sep 2021 06:55:24 +0000 Subject: [PATCH 042/385] 8274522: java/lang/management/ManagementFactory/MXBeanException.java test fails with Shenandoah Reviewed-by: alanb, mchung --- .../java/lang/management/ManagementFactory/MXBeanException.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/jdk/java/lang/management/ManagementFactory/MXBeanException.java b/test/jdk/java/lang/management/ManagementFactory/MXBeanException.java index 6e9d1526387..1788a1c0b2a 100644 --- a/test/jdk/java/lang/management/ManagementFactory/MXBeanException.java +++ b/test/jdk/java/lang/management/ManagementFactory/MXBeanException.java @@ -27,7 +27,7 @@ * @summary Check if a RuntimeException is wrapped by RuntimeMBeanException * only once. * - * @requires vm.gc != "Z" + * @requires vm.gc != "Z" & vm.gc != "Shenandoah" * @author Mandy Chung * * @build MXBeanException -- GitLab From dfc557cbea342b2991f9d129235470ac789b50a2 Mon Sep 17 00:00:00 2001 From: Christian Hagedorn Date: Thu, 30 Sep 2021 08:29:43 +0000 Subject: [PATCH 043/385] 8274406: RunThese30M.java failed "assert(!LCA_orig->dominates(pred_block) || early->dominates(pred_block)) failed: early is high enough" Reviewed-by: kvn, thartmann --- src/hotspot/share/opto/loopopts.cpp | 4 ++-- .../jtreg/compiler/loopopts/TestSinkingDivisorLostPin.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/hotspot/share/opto/loopopts.cpp b/src/hotspot/share/opto/loopopts.cpp index 4379a6c744b..fe117797e3f 100644 --- a/src/hotspot/share/opto/loopopts.cpp +++ b/src/hotspot/share/opto/loopopts.cpp @@ -1455,8 +1455,8 @@ void PhaseIdealLoop::try_sink_out_of_loop(Node* n) { if (n_loop != loop_ctrl && n_loop->is_member(loop_ctrl)) { // n has a control input inside a loop but get_ctrl() is member of an outer loop. This could happen, for example, // for Div nodes inside a loop (control input inside loop) without a use except for an UCT (outside the loop). - // Rewire control of n to get_ctrl(n) to move it out of the loop, regardless if its input(s) are later sunk or not. - _igvn.replace_input_of(n, 0, n_ctrl); + // Rewire control of n to right outside of the loop, regardless if its input(s) are later sunk or not. + _igvn.replace_input_of(n, 0, place_outside_loop(n_ctrl, loop_ctrl)); } } if (n_loop != _ltree_root && n->outcnt() > 1) { diff --git a/test/hotspot/jtreg/compiler/loopopts/TestSinkingDivisorLostPin.java b/test/hotspot/jtreg/compiler/loopopts/TestSinkingDivisorLostPin.java index 1ee487654cd..d2c2a60abde 100644 --- a/test/hotspot/jtreg/compiler/loopopts/TestSinkingDivisorLostPin.java +++ b/test/hotspot/jtreg/compiler/loopopts/TestSinkingDivisorLostPin.java @@ -29,9 +29,9 @@ * @summary Sinking a data node used as divisor of a DivI node into a zero check UCT loses its pin outside the loop due to * optimizing the CastII node away, resulting in a div by zero crash (SIGFPE) due to letting the DivI node floating * back inside the loop. - * @run main/othervm -Xcomp -XX:CompileCommand=compileonly,compiler.loopopts.TestSinkingDivisorLostPin -XX:-TieredCompilation + * @run main/othervm -Xcomp -XX:CompileCommand=compileonly,compiler.loopopts.TestSinkingDivisorLostPin::* -XX:-TieredCompilation * -XX:+UnlockDiagnosticVMOptions -XX:+StressGCM -XX:StressSeed=4177789702 compiler.loopopts.TestSinkingDivisorLostPin - * @run main/othervm -Xcomp -XX:CompileCommand=compileonly,compiler.loopopts.TestSinkingDivisorLostPin -XX:-TieredCompilation + * @run main/othervm -Xcomp -XX:CompileCommand=compileonly,compiler.loopopts.TestSinkingDivisorLostPin::* -XX:-TieredCompilation * -XX:+UnlockDiagnosticVMOptions -XX:+StressGCM compiler.loopopts.TestSinkingDivisorLostPin */ -- GitLab From a8210c53e7af1cb558251fcb420de1b8a5461b25 Mon Sep 17 00:00:00 2001 From: Martin Doerr Date: Thu, 30 Sep 2021 08:41:03 +0000 Subject: [PATCH 044/385] 8274401: C2: GraphKit::load_array_element bypasses Access API Reviewed-by: kvn, goetz, thartmann --- src/hotspot/share/opto/graphKit.cpp | 7 ++++--- src/hotspot/share/opto/graphKit.hpp | 2 +- src/hotspot/share/opto/library_call.cpp | 2 +- src/hotspot/share/opto/stringopts.cpp | 2 +- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/hotspot/share/opto/graphKit.cpp b/src/hotspot/share/opto/graphKit.cpp index 40d4e690b00..cafbc0aaa7c 100644 --- a/src/hotspot/share/opto/graphKit.cpp +++ b/src/hotspot/share/opto/graphKit.cpp @@ -1748,14 +1748,15 @@ Node* GraphKit::array_element_address(Node* ary, Node* idx, BasicType elembt, } //-------------------------load_array_element------------------------- -Node* GraphKit::load_array_element(Node* ctl, Node* ary, Node* idx, const TypeAryPtr* arytype) { +Node* GraphKit::load_array_element(Node* ary, Node* idx, const TypeAryPtr* arytype, bool set_ctrl) { const Type* elemtype = arytype->elem(); BasicType elembt = elemtype->array_element_basic_type(); Node* adr = array_element_address(ary, idx, elembt, arytype->size()); if (elembt == T_NARROWOOP) { elembt = T_OBJECT; // To satisfy switch in LoadNode::make() } - Node* ld = make_load(ctl, adr, elemtype, elembt, arytype, MemNode::unordered); + Node* ld = access_load_at(ary, adr, arytype, elemtype, elembt, + IN_HEAP | IS_ARRAY | (set_ctrl ? C2_CONTROL_DEPENDENT_LOAD : 0)); return ld; } @@ -4258,7 +4259,7 @@ void GraphKit::inflate_string_slow(Node* src, Node* dst, Node* start, Node* coun record_for_igvn(mem); set_control(head); set_memory(mem, TypeAryPtr::BYTES); - Node* ch = load_array_element(control(), src, i_byte, TypeAryPtr::BYTES); + Node* ch = load_array_element(src, i_byte, TypeAryPtr::BYTES, /* set_ctrl */ true); Node* st = store_to_memory(control(), array_element_address(dst, i_char, T_BYTE), AndI(ch, intcon(0xff)), T_CHAR, TypeAryPtr::BYTES, MemNode::unordered, false, false, true /* mismatched */); diff --git a/src/hotspot/share/opto/graphKit.hpp b/src/hotspot/share/opto/graphKit.hpp index d2a6dd8d6c8..7b1ae9455e4 100644 --- a/src/hotspot/share/opto/graphKit.hpp +++ b/src/hotspot/share/opto/graphKit.hpp @@ -660,7 +660,7 @@ class GraphKit : public Phase { Node* ctrl = NULL); // Return a load of array element at idx. - Node* load_array_element(Node* ctl, Node* ary, Node* idx, const TypeAryPtr* arytype); + Node* load_array_element(Node* ary, Node* idx, const TypeAryPtr* arytype, bool set_ctrl); //---------------- Dtrace support -------------------- void make_dtrace_method_entry_exit(ciMethod* method, bool is_entry); diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index 139a6c87dd0..7c8b8bae6aa 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -6205,7 +6205,7 @@ Node * LibraryCallKit::get_key_start_from_aescrypt_object(Node *aescrypt_object) if (objSessionK == NULL) { return (Node *) NULL; } - Node* objAESCryptKey = load_array_element(control(), objSessionK, intcon(0), TypeAryPtr::OOPS); + Node* objAESCryptKey = load_array_element(objSessionK, intcon(0), TypeAryPtr::OOPS, /* set_ctrl */ true); #else Node* objAESCryptKey = load_field_from_object(aescrypt_object, "K", "[I"); #endif // PPC64 diff --git a/src/hotspot/share/opto/stringopts.cpp b/src/hotspot/share/opto/stringopts.cpp index 809a446f52b..16507d97811 100644 --- a/src/hotspot/share/opto/stringopts.cpp +++ b/src/hotspot/share/opto/stringopts.cpp @@ -1244,7 +1244,7 @@ Node* PhaseStringOpts::int_stringSize(GraphKit& kit, Node* arg) { kit.set_control(loop); Node* sizeTable = fetch_static_field(kit, size_table_field); - Node* value = kit.load_array_element(NULL, sizeTable, index, TypeAryPtr::INTS); + Node* value = kit.load_array_element(sizeTable, index, TypeAryPtr::INTS, /* set_ctrl */ false); C->record_for_igvn(value); Node* limit = __ CmpI(phi, value); Node* limitb = __ Bool(limit, BoolTest::le); -- GitLab From 94e31e5ca51d1c4c253cf7ac5acd950d10c22267 Mon Sep 17 00:00:00 2001 From: Severin Gehwolf Date: Thu, 30 Sep 2021 08:53:31 +0000 Subject: [PATCH 045/385] 8274506: TestPids.java and TestPidsLimit.java fail with podman run as root Reviewed-by: mbaesken, cjplummer --- test/hotspot/jtreg/containers/docker/TestPids.java | 7 ++++++- test/jdk/jdk/internal/platform/docker/TestPidsLimit.java | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/test/hotspot/jtreg/containers/docker/TestPids.java b/test/hotspot/jtreg/containers/docker/TestPids.java index 5c1993b8a5e..5ae0f4a9f61 100644 --- a/test/hotspot/jtreg/containers/docker/TestPids.java +++ b/test/hotspot/jtreg/containers/docker/TestPids.java @@ -40,11 +40,15 @@ import jdk.test.lib.containers.docker.Common; import jdk.test.lib.containers.docker.DockerRunOptions; import jdk.test.lib.containers.docker.DockerTestUtils; import jdk.test.lib.Asserts; +import jdk.test.lib.Container; import jdk.test.lib.Platform; import jdk.test.lib.Utils; public class TestPids { private static final String imageName = Common.imageName("pids"); + private static final boolean IS_PODMAN = Container.ENGINE_COMMAND.contains("podman"); + private static final int UNLIMITED_PIDS_PODMAN = 0; + private static final int UNLIMITED_PIDS_DOCKER = -1; static final String warning_kernel_no_pids_support = "WARNING: Your kernel does not support pids limit capabilities"; @@ -139,7 +143,8 @@ public class TestPids { DockerRunOptions opts = commonOpts(); if (value.equals("Unlimited")) { - opts.addDockerOpts("--pids-limit=-1"); + int unlimited = IS_PODMAN ? UNLIMITED_PIDS_PODMAN : UNLIMITED_PIDS_DOCKER; + opts.addDockerOpts("--pids-limit=" + unlimited); } else { opts.addDockerOpts("--pids-limit="+value); } diff --git a/test/jdk/jdk/internal/platform/docker/TestPidsLimit.java b/test/jdk/jdk/internal/platform/docker/TestPidsLimit.java index 99ef9d0cf8c..6c6ff76fa99 100644 --- a/test/jdk/jdk/internal/platform/docker/TestPidsLimit.java +++ b/test/jdk/jdk/internal/platform/docker/TestPidsLimit.java @@ -39,9 +39,13 @@ import jdk.test.lib.containers.docker.DockerRunOptions; import jdk.test.lib.containers.docker.DockerTestUtils; import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.Asserts; +import jdk.test.lib.Container; public class TestPidsLimit { private static final String imageName = Common.imageName("pids"); + private static final boolean IS_PODMAN = Container.ENGINE_COMMAND.contains("podman"); + private static final int UNLIMITED_PIDS_PODMAN = 0; + private static final int UNLIMITED_PIDS_DOCKER = -1; public static void main(String[] args) throws Exception { if (!DockerTestUtils.canTestDocker()) { @@ -107,7 +111,8 @@ public class TestPidsLimit { Common.logNewTestCase("testPidsLimit (limit: " + pidsLimit + ")"); DockerRunOptions opts = Common.newOptsShowSettings(imageName); if (pidsLimit.equals("Unlimited")) { - opts.addDockerOpts("--pids-limit=-1"); + int unlimited = IS_PODMAN ? UNLIMITED_PIDS_PODMAN : UNLIMITED_PIDS_DOCKER; + opts.addDockerOpts("--pids-limit=" + unlimited); } else { opts.addDockerOpts("--pids-limit="+pidsLimit); } -- GitLab From 2f955d6f5ba15fc2c06eaf683d1ffa3ade97521b Mon Sep 17 00:00:00 2001 From: Mahendra Chhipa Date: Thu, 30 Sep 2021 11:29:20 +0000 Subject: [PATCH 046/385] 8273142: Remove dependancy of TestHttpServer, HttpTransaction, HttpCallback from open/test/jdk/sun/net/www/protocol/http/ tests Reviewed-by: michaelm --- .../sun/net/www/protocol/http/B6296310.java | 49 ++++++++----- .../www/protocol/http/RelativeRedirect.java | 72 ++++++++++++------- .../protocol/http/ResponseCacheStream.java | 68 +++++++++++------- .../http/SetChunkedStreamingMode.java | 70 +++++++++--------- 4 files changed, 155 insertions(+), 104 deletions(-) diff --git a/test/jdk/sun/net/www/protocol/http/B6296310.java b/test/jdk/sun/net/www/protocol/http/B6296310.java index 26d0c70ad24..dbb3ead18c5 100644 --- a/test/jdk/sun/net/www/protocol/http/B6296310.java +++ b/test/jdk/sun/net/www/protocol/http/B6296310.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. * 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,17 +24,30 @@ /* * @test * @bug 6296310 - * @modules java.base/sun.net.www - * @library ../../httptest/ - * @build HttpCallback TestHttpServer HttpTransaction + * @library /test/lib * @run main/othervm B6296310 * @run main/othervm -Djava.net.preferIPv6Addresses=true B6296310 * @summary REGRESSION: AppletClassLoader.getResourceAsStream() behaviour is wrong in some cases */ -import java.net.*; -import java.io.*; -import java.util.*; +import java.io.IOException; +import java.io.OutputStream; +import java.net.CacheRequest; +import java.net.CacheResponse; +import java.net.HttpURLConnection; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Proxy; +import java.net.ResponseCache; +import java.net.URI; +import java.net.URL; +import java.net.URLConnection; +import java.util.Map; +import java.util.concurrent.Executors; + +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import com.sun.net.httpserver.HttpServer; /* * http server returns 200 and content-length=0 @@ -44,7 +57,7 @@ import java.util.*; public class B6296310 { static SimpleHttpTransaction httpTrans; - static TestHttpServer server; + static HttpServer server; public static void main(String[] args) throws Exception { @@ -56,31 +69,35 @@ public class B6296310 public static void startHttpServer() throws IOException { httpTrans = new SimpleHttpTransaction(); InetAddress loopback = InetAddress.getLoopbackAddress(); - server = new TestHttpServer(httpTrans, 1, 10, loopback, 0); + server = HttpServer.create(new InetSocketAddress(loopback, 0), 10); + server.createContext("/", httpTrans); + server.setExecutor(Executors.newSingleThreadExecutor()); + server.start(); } public static void makeHttpCall() throws IOException { try { - System.out.println("http server listen on: " + server.getLocalPort()); + System.out.println("http server listen on: " + server.getAddress().getPort()); URL url = new URL("http" , InetAddress.getLoopbackAddress().getHostAddress(), - server.getLocalPort(), "/"); + server.getAddress().getPort(), "/"); HttpURLConnection uc = (HttpURLConnection)url.openConnection(Proxy.NO_PROXY); System.out.println(uc.getResponseCode()); } finally { - server.terminate(); + server.stop(1); } } } -class SimpleHttpTransaction implements HttpCallback +class SimpleHttpTransaction implements HttpHandler { /* * Our http server which simply retruns a file with no content */ - public void request(HttpTransaction trans) { + @Override + public void handle(HttpExchange trans) { try { - trans.setResponseEntityBody(""); - trans.sendResponse(200, "OK"); + trans.sendResponseHeaders(200, 0); + trans.close(); } catch (Exception e) { e.printStackTrace(); } diff --git a/test/jdk/sun/net/www/protocol/http/RelativeRedirect.java b/test/jdk/sun/net/www/protocol/http/RelativeRedirect.java index 193f25fb1f2..61723197469 100644 --- a/test/jdk/sun/net/www/protocol/http/RelativeRedirect.java +++ b/test/jdk/sun/net/www/protocol/http/RelativeRedirect.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2021, Oracle and/or its affiliates. All rights reserved. * 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,20 +24,32 @@ /** * @test * @bug 4726087 - * @modules java.base/sun.net.www - * @library ../../httptest/ - * @build HttpCallback TestHttpServer ClosedChannelList HttpTransaction - * @run main RelativeRedirect + * @library /test/lib + * @run main/othervm RelativeRedirect * @run main/othervm -Djava.net.preferIPv6Addresses=true RelativeRedirect * @summary URLConnection cannot handle redirects */ -import java.io.*; -import java.net.*; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintWriter; +import java.net.Authenticator; +import java.net.HttpURLConnection; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.PasswordAuthentication; +import java.net.Proxy; +import java.net.URL; +import java.util.concurrent.Executors; -public class RelativeRedirect implements HttpCallback { +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import com.sun.net.httpserver.HttpServer; + +public class RelativeRedirect implements HttpHandler { static int count = 0; - static TestHttpServer server; + static HttpServer server; + static class MyAuthenticator extends Authenticator { public MyAuthenticator () { @@ -50,26 +62,29 @@ public class RelativeRedirect implements HttpCallback { } } - void firstReply (HttpTransaction req) throws IOException { - req.addResponseHeader ("Connection", "close"); - req.addResponseHeader ("Location", "/redirect/file.html"); - req.sendResponse (302, "Moved Permamently"); - req.orderlyClose(); + void firstReply(HttpExchange req) throws IOException { + req.getResponseHeaders().set("Connection", "close"); + req.getResponseHeaders().set("Location", "/redirect/file.html"); + req.sendResponseHeaders(302, -1); } - void secondReply (HttpTransaction req) throws IOException { + void secondReply (HttpExchange req) throws IOException { if (req.getRequestURI().toString().equals("/redirect/file.html") && - req.getRequestHeader("Host").equals(authority(server.getLocalPort()))) { - req.setResponseEntityBody ("Hello ."); - req.sendResponse (200, "Ok"); + req.getRequestHeaders().get("Host").get(0).equals(authority(server.getAddress().getPort()))) { + req.sendResponseHeaders(200, 0); + try(PrintWriter pw = new PrintWriter(req.getResponseBody())) { + pw.print("Hello ."); + } } else { - req.setResponseEntityBody (req.getRequestURI().toString()); - req.sendResponse (400, "Bad request"); + req.sendResponseHeaders(400, 0); + try(PrintWriter pw = new PrintWriter(req.getResponseBody())) { + pw.print(req.getRequestURI().toString()); + } } - req.orderlyClose(); - } - public void request (HttpTransaction req) { + + @Override + public void handle (HttpExchange req) { try { switch (count) { case 0: @@ -101,9 +116,12 @@ public class RelativeRedirect implements HttpCallback { MyAuthenticator auth = new MyAuthenticator (); Authenticator.setDefault (auth); try { - server = new TestHttpServer (new RelativeRedirect(), 1, 10, loopback, 0); - System.out.println ("Server: listening on port: " + server.getLocalPort()); - URL url = new URL("http://" + authority(server.getLocalPort())); + server = HttpServer.create(new InetSocketAddress(loopback, 0), 10); + server.createContext("/", new RelativeRedirect()); + server.setExecutor(Executors.newSingleThreadExecutor()); + server.start(); + System.out.println ("Server: listening on port: " + server.getAddress().getPort()); + URL url = new URL("http://" + authority(server.getAddress().getPort())); System.out.println ("client opening connection to: " + url); HttpURLConnection urlc = (HttpURLConnection)url.openConnection (Proxy.NO_PROXY); InputStream is = urlc.getInputStream (); @@ -112,7 +130,7 @@ public class RelativeRedirect implements HttpCallback { throw new RuntimeException(e); } finally { if (server != null) { - server.terminate(); + server.stop(1); } } } diff --git a/test/jdk/sun/net/www/protocol/http/ResponseCacheStream.java b/test/jdk/sun/net/www/protocol/http/ResponseCacheStream.java index 89a7f8afc4a..841279fa76d 100644 --- a/test/jdk/sun/net/www/protocol/http/ResponseCacheStream.java +++ b/test/jdk/sun/net/www/protocol/http/ResponseCacheStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. * 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,33 +25,48 @@ * @test * @bug 6262486 * @library /test/lib - * @modules java.base/sun.net.www - * @library ../../httptest/ - * @build HttpCallback TestHttpServer ClosedChannelList HttpTransaction * @run main/othervm -Dhttp.keepAlive=false ResponseCacheStream * @summary COMPATIBILITY: jagex_com - Monkey Puzzle applet fails to load */ -import java.net.*; -import java.io.*; -import java.util.*; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.net.CacheRequest; +import java.net.CacheResponse; +import java.net.HttpURLConnection; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.ResponseCache; +import java.net.URI; +import java.net.URL; +import java.net.URLConnection; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Executors; + +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import com.sun.net.httpserver.HttpServer; import jdk.test.lib.net.URIBuilder; -public class ResponseCacheStream implements HttpCallback { +public class ResponseCacheStream implements HttpHandler { - void okReply (HttpTransaction req) throws IOException { - req.setResponseEntityBody ("Hello, This is the response body. Let's make it as long as possible since we need to test the cache mechanism."); - req.sendResponse (200, "Ok"); - System.out.println ("Server: sent response"); - req.orderlyClose(); + void okReply (HttpExchange req) throws IOException { + req.sendResponseHeaders(200, 0); + try(PrintWriter pw = new PrintWriter(req.getResponseBody())) { + pw.print("Hello, This is the response body. Let's make it as long as possible since we need to test the cache mechanism."); + } + System.out.println ("Server: sent response"); } - public void request (HttpTransaction req) { - try { - okReply (req); - } catch (IOException e) { - e.printStackTrace(); - } + + @Override + public void handle(HttpExchange exchange) throws IOException { + okReply(exchange); + exchange.close(); } static class MyCacheRequest extends CacheRequest { @@ -94,19 +109,22 @@ public class ResponseCacheStream implements HttpCallback { } } - static TestHttpServer server; + static HttpServer server; public static void main(String[] args) throws Exception { MyResponseCache cache = new MyResponseCache(); try { InetAddress loopback = InetAddress.getLoopbackAddress(); ResponseCache.setDefault(cache); - server = new TestHttpServer (new ResponseCacheStream(), loopback, 0); - System.out.println ("Server: listening on port: " + server.getLocalPort()); + server = HttpServer.create(new InetSocketAddress(loopback, 0), 10); + server.createContext("/", new ResponseCacheStream()); + server.setExecutor(Executors.newSingleThreadExecutor()); + server.start(); + System.out.println("Server: listening on port: " + server.getAddress().getPort()); URL url = URIBuilder.newBuilder() .scheme("http") .loopback() - .port(server.getLocalPort()) + .port(server.getAddress().getPort()) .path("/") .toURL(); System.out.println ("Client: connecting to " + url); @@ -149,10 +167,10 @@ public class ResponseCacheStream implements HttpCallback { } } catch (Exception e) { if (server != null) { - server.terminate(); + server.stop(1); } throw e; } - server.terminate(); + server.stop(1); } } diff --git a/test/jdk/sun/net/www/protocol/http/SetChunkedStreamingMode.java b/test/jdk/sun/net/www/protocol/http/SetChunkedStreamingMode.java index bda2e404108..2d6ef48db56 100644 --- a/test/jdk/sun/net/www/protocol/http/SetChunkedStreamingMode.java +++ b/test/jdk/sun/net/www/protocol/http/SetChunkedStreamingMode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2021, Oracle and/or its affiliates. All rights reserved. * 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,56 +24,54 @@ /** * @test * @bug 5049976 - * @modules java.base/sun.net.www - * @library ../../httptest/ * @library /test/lib - * @build HttpCallback TestHttpServer ClosedChannelList HttpTransaction - * @run main SetChunkedStreamingMode + * @run main/othervm SetChunkedStreamingMode * @summary Unspecified NPE is thrown when streaming output mode is enabled */ -import java.io.*; -import java.net.*; -import jdk.test.lib.net.URIBuilder; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintWriter; +import java.net.HttpURLConnection; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.URL; +import java.util.concurrent.Executors; -public class SetChunkedStreamingMode implements HttpCallback { +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import com.sun.net.httpserver.HttpServer; +import jdk.test.lib.net.URIBuilder; - void okReply (HttpTransaction req) throws IOException { - req.setResponseEntityBody ("Hello ."); - req.sendResponse (200, "Ok"); - System.out.println ("Server: sent response"); - req.orderlyClose(); - } +public class SetChunkedStreamingMode implements HttpHandler { - public void request (HttpTransaction req) { - try { - okReply (req); - } catch (IOException e) { - e.printStackTrace(); + void okReply (HttpExchange req) throws IOException { + req.sendResponseHeaders(200, 0); + try(PrintWriter pw = new PrintWriter(req.getResponseBody())) { + pw.print("Hello ."); } + System.out.println ("Server: sent response"); } - static void read (InputStream is) throws IOException { - int c; - System.out.println ("reading"); - while ((c=is.read()) != -1) { - System.out.write (c); - } - System.out.println (""); - System.out.println ("finished reading"); + @Override + public void handle(HttpExchange exchange) throws IOException { + okReply(exchange); } - static TestHttpServer server; + static HttpServer server; public static void main (String[] args) throws Exception { try { - server = new TestHttpServer(new SetChunkedStreamingMode(), 1, 10, - InetAddress.getLoopbackAddress(), 0); - System.out.println ("Server: listening on port: " + server.getLocalPort()); + InetAddress loopback = InetAddress.getLoopbackAddress(); + server = HttpServer.create(new InetSocketAddress(loopback, 0), 10); + server.createContext("/", new SetChunkedStreamingMode()); + server.setExecutor(Executors.newSingleThreadExecutor()); + server.start(); + System.out.println ("Server: listening on port: " + server.getAddress().getPort()); URL url = URIBuilder.newBuilder() .scheme("http") .loopback() - .port(server.getLocalPort()) + .port(server.getAddress().getPort()) .path("/") .toURL(); System.out.println ("Client: connecting to " + url); @@ -84,15 +82,15 @@ public class SetChunkedStreamingMode implements HttpCallback { InputStream is = urlc.getInputStream(); } catch (Exception e) { if (server != null) { - server.terminate(); + server.stop(1); } throw e; } - server.terminate(); + server.stop(1); } public static void except (String s) { - server.terminate(); + server.stop(1); throw new RuntimeException (s); } } -- GitLab From bb95dda0ac5032e4df582f2903dcbbbbaef9e8c4 Mon Sep 17 00:00:00 2001 From: Masanori Yano Date: Thu, 30 Sep 2021 11:33:21 +0000 Subject: [PATCH 047/385] 8248001: javadoc generates invalid HTML pages whose ftp:// links are broken Reviewed-by: hannesw --- .../formats/html/HtmlDocletWriter.java | 3 +- .../TestHrefInDocComment.java | 4 +- .../doclet/testHrefInDocComment/pkg/J1.java | 75 +++++++++++++++++++ 3 files changed, 79 insertions(+), 3 deletions(-) create mode 100644 test/langtools/jdk/javadoc/doclet/testHrefInDocComment/pkg/J1.java 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 bca521bfe34..c3da4f5a81e 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 @@ -1829,7 +1829,8 @@ public class HtmlDocletWriter { if (lower.startsWith("mailto:") || lower.startsWith("http:") || lower.startsWith("https:") - || lower.startsWith("file:")) { + || lower.startsWith("file:") + || lower.startsWith("ftp:")) { return text; } if (text.startsWith("#")) { diff --git a/test/langtools/jdk/javadoc/doclet/testHrefInDocComment/TestHrefInDocComment.java b/test/langtools/jdk/javadoc/doclet/testHrefInDocComment/TestHrefInDocComment.java index 79f37f213ff..5af53e19048 100644 --- a/test/langtools/jdk/javadoc/doclet/testHrefInDocComment/TestHrefInDocComment.java +++ b/test/langtools/jdk/javadoc/doclet/testHrefInDocComment/TestHrefInDocComment.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 4638015 + * @bug 4638015 8248001 * @summary Determine if Hrefs are processed properly when they * appear in doc comments. * @library ../../lib diff --git a/test/langtools/jdk/javadoc/doclet/testHrefInDocComment/pkg/J1.java b/test/langtools/jdk/javadoc/doclet/testHrefInDocComment/pkg/J1.java new file mode 100644 index 00000000000..9be939f37b1 --- /dev/null +++ b/test/langtools/jdk/javadoc/doclet/testHrefInDocComment/pkg/J1.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 pkg; + +/** + *This class has various functions, + * see FTP Site, + * file service for further information + *various functions + *

      + *
    • function1
    • + *
    • function2
    • + *
    • function3
    • + *
    + *special methods + *
      + *
    • method1
    • + *
    • method2
    • + *
    • method3
    • + *
    + */ +public class J1 { + /** + *fields. + */ + protected Object field1; + + /** + *Creates an instance which has various functions. + */ + public J1(){ + } + + /** + *This is aspecial method. + *@param p1 arg1 + */ + public void method1(int p1){ + } + + /** + *See FTP Site for more information. + *@param p1 arg1 + */ + public void method2(int p1){ + } + + /** + *See file service for more information. + *@param p1 arg1 + */ + public void method3(int p1){ + } +} -- GitLab From bfd616347126a802c641326a6be5a14c4cd7af90 Mon Sep 17 00:00:00 2001 From: Lin Zang Date: Thu, 30 Sep 2021 14:44:59 +0000 Subject: [PATCH 048/385] 8274196: Crashes in VM_HeapDumper::work after JDK-8252842 8274245: sun/tools/jmap/BasicJMapTest.java Mutex rank failures Reviewed-by: coleenp, pliden, cjplummer --- src/hotspot/share/services/heapDumper.cpp | 18 +++++++++--------- test/hotspot/jtreg/ProblemList-zgc.txt | 3 --- test/jdk/ProblemList.txt | 5 ----- 3 files changed, 9 insertions(+), 17 deletions(-) diff --git a/src/hotspot/share/services/heapDumper.cpp b/src/hotspot/share/services/heapDumper.cpp index ac40f0704e8..14fe68acd8a 100644 --- a/src/hotspot/share/services/heapDumper.cpp +++ b/src/hotspot/share/services/heapDumper.cpp @@ -748,7 +748,7 @@ class ParDumpWriter : public AbstractDumpWriter { static void before_work() { assert(_lock == NULL, "ParDumpWriter lock must be initialized only once"); - _lock = new (std::nothrow) PaddedMonitor(Mutex::leaf, "Parallel HProf writer lock", Mutex::_safepoint_check_never); + _lock = new (std::nothrow) PaddedMonitor(Mutex::leaf, "ParallelHProfWriter_lock", Mutex::_safepoint_check_always); } static void after_work() { @@ -1626,7 +1626,7 @@ class JNIGlobalsDumper : public OopClosure { }; void JNIGlobalsDumper::do_oop(oop* obj_p) { - oop o = *obj_p; + oop o = NativeAccess::oop_load(obj_p); // ignore these if (o == NULL) return; @@ -1814,8 +1814,8 @@ class DumperController : public CHeapObj { public: DumperController(uint number) : _started(false), - _lock(new (std::nothrow) PaddedMonitor(Mutex::leaf, "Dumper Controller lock", - Mutex::_safepoint_check_never)), + _lock(new (std::nothrow) PaddedMonitor(Mutex::leaf, "DumperController_lock", + Mutex::_safepoint_check_always)), _dumper_number(number), _complete_number(0) { } @@ -1910,11 +1910,11 @@ class VM_HeapDumper : public VM_GC_Operation, public AbstractGangTask { _num_writer_threads = 1; _num_dumper_threads = num_total - _num_writer_threads; } - // Number of dumper threads that only iterate heap. - uint _heap_only_dumper_threads = _num_dumper_threads - 1 /* VMDumper thread */; // Prepare parallel writer. if (_num_dumper_threads > 1) { ParDumpWriter::before_work(); + // Number of dumper threads that only iterate heap. + uint _heap_only_dumper_threads = _num_dumper_threads - 1 /* VMDumper thread */; _dumper_controller = new (std::nothrow) DumperController(_heap_only_dumper_threads); _poi = Universe::heap()->parallel_object_iterator(_num_dumper_threads); } @@ -2252,6 +2252,9 @@ void VM_HeapDumper::doit() { WorkGang* gang = ch->safepoint_workers(); if (gang == NULL) { + // Use serial dump, set dumper threads and writer threads number to 1. + _num_dumper_threads=1; + _num_writer_threads=1; work(0); } else { prepare_parallel_dump(gang->active_workers()); @@ -2315,7 +2318,6 @@ void VM_HeapDumper::work(uint worker_id) { // technically not jni roots, but global roots // for things like preallocated throwable backtraces Universe::vm_global()->oops_do(&jni_dumper); - // HPROF_GC_ROOT_STICKY_CLASS // These should be classes in the NULL class loader data, and not all classes // if !ClassUnloading @@ -2353,10 +2355,8 @@ void VM_HeapDumper::work(uint worker_id) { _dumper_controller->wait_all_dumpers_complete(); // clear internal buffer; pw.finish_dump_segment(true); - // refresh the global_writer's buffer and position; writer()->refresh(); - } else { pw.finish_dump_segment(true); _dumper_controller->dumper_complete(); diff --git a/test/hotspot/jtreg/ProblemList-zgc.txt b/test/hotspot/jtreg/ProblemList-zgc.txt index f5f67b7bd34..1032c144e59 100644 --- a/test/hotspot/jtreg/ProblemList-zgc.txt +++ b/test/hotspot/jtreg/ProblemList-zgc.txt @@ -44,6 +44,3 @@ serviceability/sa/TestJmapCoreMetaspace.java 8268722,8268636 serviceability/sa/TestJhsdbJstackMixed.java 8248912 generic-all serviceability/sa/ClhsdbPstack.java#process 8248912 generic-all serviceability/sa/ClhsdbPstack.java#core 8248912 generic-all - -serviceability/dcmd/gc/HeapDumpAllTest.java 8274196 generic-all -serviceability/dcmd/gc/HeapDumpTest.java 8274196 generic-all diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 5eef678fd8a..300127bec0a 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -818,11 +818,6 @@ sun/tools/jstat/jstatLineCounts2.sh 8268211 linux-aa sun/tools/jstat/jstatLineCounts3.sh 8268211 linux-aarch64 sun/tools/jstat/jstatLineCounts4.sh 8268211 linux-aarch64 -sun/tools/jmap/BasicJMapTest.java#G1 8274245 generic-all -sun/tools/jmap/BasicJMapTest.java#Parallel 8274245 generic-all -sun/tools/jmap/BasicJMapTest.java#Serial 8274245 generic-all -sun/tools/jmap/BasicJMapTest.java#Z 8274245 generic-all - ############################################################################ # jdk_other -- GitLab From 3e0d7c33d41a93496bfa6a47d1508e415930adf9 Mon Sep 17 00:00:00 2001 From: Alex Kasko Date: Thu, 30 Sep 2021 15:21:18 +0000 Subject: [PATCH 049/385] 8270290: NTLM authentication fails if HEAD request is used Reviewed-by: dfuchs, michaelm --- .../www/protocol/http/HttpURLConnection.java | 2 +- .../net/www/protocol/http/NTLMHeadTest.java | 306 ++++++++++++++++++ 2 files changed, 307 insertions(+), 1 deletion(-) create mode 100644 test/jdk/sun/net/www/protocol/http/NTLMHeadTest.java diff --git a/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java b/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java index 6280cc1c826..cba385f04fa 100644 --- a/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java +++ b/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java @@ -2961,7 +2961,7 @@ public class HttpURLConnection extends java.net.HttpURLConnection { /* must save before calling close */ reuseClient = http; InputStream is = http.getInputStream(); - if (!method.equals("HEAD")) { + if (!method.equals("HEAD") || tunnelState == TunnelState.SETUP) { try { /* we want to read the rest of the response without using the * hurry mechanism, because that would close the connection diff --git a/test/jdk/sun/net/www/protocol/http/NTLMHeadTest.java b/test/jdk/sun/net/www/protocol/http/NTLMHeadTest.java new file mode 100644 index 00000000000..c68c9a399f6 --- /dev/null +++ b/test/jdk/sun/net/www/protocol/http/NTLMHeadTest.java @@ -0,0 +1,306 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 8270290 + * @modules java.base/sun.net.www + * @library /test/lib + * @run main/othervm NTLMHeadTest SERVER + * @run main/othervm NTLMHeadTest PROXY + * @run main/othervm NTLMHeadTest TUNNEL + * @summary test for the incorrect logic in reading (and discarding) HTTP + * response body when processing NTLMSSP_CHALLENGE response + * (to CONNECT request) from proxy server. When this response is received + * by client, reset() is called on the connection to read and discard the + * response body. This code path was broken when initial client request + * uses HEAD method and HTTPS resource, in this case CONNECT is sent to + * proxy server (to establish TLS tunnel) and response body is not read + * from a socket (because initial method on client connection is HEAD). + * This does not cause problems with the majority of proxy servers because + * InputStream opened over the response socket is buffered with 8kb buffer + * size. Problem is only reproducible if the response size (headers + + * body) is larger than 8kb. The code path with HTTPS tunneling is checked + * with TUNNEL argument. Additional checks for HEAD handling are included + * for direct server (SERVER) and HTTP proxying (PROXY) code paths, in + * these (non-tunnel) cases client must NOT attempt to read response data + * (to not block on socket read) because HEAD is sent to server and + * NTLMSSP_CHALLENGE response includes Content-Length, but does not + * include the body. + */ + +import java.net.*; +import java.io.*; +import java.util.*; +import sun.net.www.MessageHeader; +import jdk.test.lib.net.URIBuilder; + +public class NTLMHeadTest { + + enum Mode { SERVER, PROXY, TUNNEL } + + static final int BODY_LEN = 8192; + + static final String RESP_SERVER_AUTH = + "HTTP/1.1 401 Unauthorized\r\n" + + "WWW-Authenticate: NTLM\r\n" + + "Connection: close\r\n" + + "Content-Length: " + BODY_LEN + "\r\n" + + "\r\n"; + + static final String RESP_SERVER_NTLM = + "HTTP/1.1 401 Unauthorized\r\n" + + "WWW-Authenticate: NTLM TlRMTVNTUAACAAAAAAAAACgAAAABggAAU3J2Tm9uY2UAAAAAAAAAAA==\r\n" + + "Connection: Keep-Alive\r\n" + + "Content-Length: " + BODY_LEN + "\r\n" + + "\r\n"; + + static final String RESP_SERVER_OR_PROXY_DEST = + "HTTP/1.1 200 OK\r\n" + + "Connection: close\r\n" + + "Content-Length: 42\r\n" + + "\r\n"; + + static final String RESP_PROXY_AUTH = + "HTTP/1.1 407 Proxy Authentication Required\r\n" + + "Proxy-Authenticate: NTLM\r\n" + + "Proxy-Connection: close\r\n" + + "Connection: close\r\n" + + "Content-Length: " + BODY_LEN + "\r\n" + + "\r\n"; + + static final String RESP_PROXY_NTLM = + "HTTP/1.1 407 Proxy Authentication Required\r\n" + + "Proxy-Authenticate: NTLM TlRMTVNTUAACAAAAAAAAACgAAAABggAAU3J2Tm9uY2UAAAAAAAAAAA==\r\n" + + "Proxy-Connection: Keep-Alive\r\n" + + "Connection: Keep-Alive\r\n" + + "Content-Length: " + BODY_LEN + "\r\n" + + "\r\n"; + + static final String RESP_TUNNEL_AUTH = + "HTTP/1.1 407 Proxy Authentication Required\r\n" + + "Proxy-Authenticate: NTLM\r\n" + + "Proxy-Connection: close\r\n" + + "Connection: close\r\n" + + "Content-Length: " + BODY_LEN + "\r\n" + + "\r\n" + + generateBody(BODY_LEN); + + static final String RESP_TUNNEL_NTLM = + "HTTP/1.1 407 Proxy Authentication Required\r\n" + + "Proxy-Authenticate: NTLM TlRMTVNTUAACAAAAAAAAACgAAAABggAAU3J2Tm9uY2UAAAAAAAAAAA==\r\n" + + "Proxy-Connection: Keep-Alive\r\n" + + "Connection: Keep-Alive\r\n" + + "Content-Length: " + BODY_LEN + "\r\n" + + "\r\n" + + generateBody(BODY_LEN); + + static final String RESP_TUNNEL_ESTABLISHED = + "HTTP/1.1 200 Connection Established\r\n\r\n"; + + public static void main(String[] args) throws Exception { + Authenticator.setDefault(new TestAuthenticator()); + if (1 != args.length) { + throw new IllegalArgumentException("Mode value must be specified, one of: [SERVER, PROXY, TUNNEL]"); + } + Mode mode = Mode.valueOf(args[0]); + System.out.println("Running with mode: " + mode); + switch (mode) { + case SERVER: testSever(); return; + case PROXY: testProxy(); return; + case TUNNEL: testTunnel(); return; + default: throw new IllegalArgumentException("Invalid mode: " + mode); + } + } + + static void testSever() throws Exception { + try (NTLMServer server = startServer(new ServerSocket(0, 0, InetAddress.getLoopbackAddress()), Mode.SERVER)) { + URL url = URIBuilder.newBuilder() + .scheme("http") + .loopback() + .port(server.getLocalPort()) + .path("/") + .toURLUnchecked(); + HttpURLConnection uc = (HttpURLConnection) url.openConnection(); + uc.setRequestMethod("HEAD"); + uc.getInputStream().readAllBytes(); + } + } + + static void testProxy() throws Exception { + InetAddress loopback = InetAddress.getLoopbackAddress(); + try (NTLMServer server = startServer(new ServerSocket(0, 0, loopback), Mode.PROXY)) { + SocketAddress proxyAddr = new InetSocketAddress(loopback, server.getLocalPort()); + Proxy proxy = new Proxy(java.net.Proxy.Type.HTTP, proxyAddr); + URL url = URIBuilder.newBuilder() + .scheme("http") + .loopback() + .port(8080) + .path("/") + .toURLUnchecked(); + HttpURLConnection uc = (HttpURLConnection) url.openConnection(proxy); + uc.setRequestMethod("HEAD"); + uc.getInputStream().readAllBytes(); + } + } + + static void testTunnel() throws Exception { + InetAddress loopback = InetAddress.getLoopbackAddress(); + try (NTLMServer server = startServer(new ServerSocket(0, 0, loopback), Mode.TUNNEL)) { + SocketAddress proxyAddr = new InetSocketAddress(loopback, server.getLocalPort()); + Proxy proxy = new Proxy(java.net.Proxy.Type.HTTP, proxyAddr); + URL url = URIBuilder.newBuilder() + .scheme("https") + .loopback() + .port(8443) + .path("/") + .toURLUnchecked(); + HttpURLConnection uc = (HttpURLConnection) url.openConnection(proxy); + uc.setRequestMethod("HEAD"); + try { + uc.getInputStream().readAllBytes(); + } catch (IOException e) { + // can be SocketException or SSLHandshakeException + // Tunnel established and closed by server + System.out.println("Tunnel established successfully"); + } catch (NoSuchElementException e) { + System.err.println("Error: cannot read 200 response code"); + throw e; + } + } + } + + static class NTLMServer extends Thread implements AutoCloseable { + final ServerSocket ss; + final Mode mode; + volatile boolean closed; + + NTLMServer(ServerSocket serverSS, Mode mode) { + super(); + setDaemon(true); + this.ss = serverSS; + this.mode = mode; + } + + int getLocalPort() { return ss.getLocalPort(); } + + @Override + public void run() { + boolean doing2ndStageNTLM = false; + while (!closed) { + try { + Socket s = ss.accept(); + InputStream is = s.getInputStream(); + OutputStream os = s.getOutputStream(); + switch(mode) { + case SERVER: + doServer(is, os, doing2ndStageNTLM); + break; + case PROXY: + doProxy(is, os, doing2ndStageNTLM); + break; + case TUNNEL: + doTunnel(is, os, doing2ndStageNTLM); + break; + default: throw new IllegalArgumentException(); + } + if (!doing2ndStageNTLM) { + doing2ndStageNTLM = true; + } else { + os.close(); + } + } catch (IOException ioe) { + if (!closed) { + ioe.printStackTrace(); + } + } + } + } + + @Override + public void close() { + if (closed) return; + synchronized(this) { + if (closed) return; + closed = true; + } + try { ss.close(); } catch (IOException x) { }; + } + } + + static NTLMServer startServer(ServerSocket serverSS, Mode mode) { + NTLMServer server = new NTLMServer(serverSS, mode); + server.start(); + return server; + } + + static String generateBody(int length) { + StringBuilder sb = new StringBuilder(); + for(int i = 0; i < length; i++) { + sb.append(i % 10); + } + return sb.toString(); + } + + static void doServer(InputStream is, OutputStream os, boolean doing2ndStageNTLM) throws IOException { + if (!doing2ndStageNTLM) { + new MessageHeader(is); + os.write(RESP_SERVER_AUTH.getBytes("ASCII")); + } else { + new MessageHeader(is); + os.write(RESP_SERVER_NTLM.getBytes("ASCII")); + new MessageHeader(is); + os.write(RESP_SERVER_OR_PROXY_DEST.getBytes("ASCII")); + } + } + + static void doProxy(InputStream is, OutputStream os, boolean doing2ndStageNTLM) throws IOException { + if (!doing2ndStageNTLM) { + new MessageHeader(is); + os.write(RESP_PROXY_AUTH.getBytes("ASCII")); + } else { + new MessageHeader(is); + os.write(RESP_PROXY_NTLM.getBytes("ASCII")); + new MessageHeader(is); + os.write(RESP_SERVER_OR_PROXY_DEST.getBytes("ASCII")); + } + } + + static void doTunnel(InputStream is, OutputStream os, boolean doing2ndStageNTLM) throws IOException { + if (!doing2ndStageNTLM) { + new MessageHeader(is); + os.write(RESP_TUNNEL_AUTH.getBytes("ASCII")); + } else { + new MessageHeader(is); + os.write(RESP_TUNNEL_NTLM.getBytes("ASCII")); + new MessageHeader(is); + os.write(RESP_TUNNEL_ESTABLISHED.getBytes("ASCII")); + } + } + + static class TestAuthenticator extends java.net.Authenticator { + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication("test", "secret".toCharArray()); + } + } +} -- GitLab From 9180d9a2f990e71ca6ac9c14e55a21f7372929ac Mon Sep 17 00:00:00 2001 From: Severin Gehwolf Date: Thu, 30 Sep 2021 15:23:44 +0000 Subject: [PATCH 050/385] 8273216: JCMD does not work across container boundaries with Podman Reviewed-by: mseledtsov, hseigel --- .../jtreg/containers/docker/TestJcmd.java | 115 +++++++++++++++--- 1 file changed, 101 insertions(+), 14 deletions(-) diff --git a/test/hotspot/jtreg/containers/docker/TestJcmd.java b/test/hotspot/jtreg/containers/docker/TestJcmd.java index 7b850eb004b..c0dfb3d01d3 100644 --- a/test/hotspot/jtreg/containers/docker/TestJcmd.java +++ b/test/hotspot/jtreg/containers/docker/TestJcmd.java @@ -55,23 +55,22 @@ public class TestJcmd { private static final String IMAGE_NAME = Common.imageName("jcmd"); private static final int TIME_TO_RUN_CONTAINER_PROCESS = (int) (10 * Utils.TIMEOUT_FACTOR); // seconds private static final String CONTAINER_NAME = "test-container"; + private static final boolean IS_PODMAN = Container.ENGINE_COMMAND.contains("podman"); + private static final String ROOT_UID = "0"; public static void main(String[] args) throws Exception { DockerTestUtils.canTestDocker(); - // See JDK-8273216 for details - if (Container.ENGINE_COMMAND.equals("podman")) { - throw new SkippedException("JCMD does not work across container boundaries when using Podman"); + // podman versions below 3.3.1 hava a bug where cross-container testing with correct + // permissions fails. See JDK-8273216 + if (IS_PODMAN && PodmanVersion.VERSION_3_3_1.compareTo(getPodmanVersion()) > 0) { + throw new SkippedException("Podman version too old for this test. Expected >= 3.3.1"); } // Need to create a custom dockerfile where user name and id, as well as group name and id // of the JVM running in container must match the ones from the inspecting JCMD process. - String uid = getId("-u"); - String gid = getId("-g"); - String userName = getId("-un"); - String groupName = getId("-gn"); - String content = generateCustomDockerfile(uid, gid, userName, groupName); + String content = generateCustomDockerfile(); DockerTestUtils.buildJdkContainerImage(IMAGE_NAME, content); try { @@ -135,17 +134,26 @@ public class TestJcmd { // Need to make sure that user name+id and group name+id are created for the image, and // match the host system. This is necessary to allow proper permission/access for JCMD. - private static String generateCustomDockerfile(String uid, String gid, - String userName, String groupName) throws Exception { + // For podman --userns=keep-id is sufficient. + private static String generateCustomDockerfile() throws Exception { StringBuilder sb = new StringBuilder(); sb.append(String.format("FROM %s:%s\n", DockerfileConfig.getBaseImageName(), DockerfileConfig.getBaseImageVersion())); sb.append("COPY /jdk /jdk\n"); sb.append("ENV JAVA_HOME=/jdk\n"); - sb.append(String.format("RUN groupadd --gid %s %s \n", gid, groupName)); - sb.append(String.format("RUN useradd --uid %s --gid %s %s \n", uid, gid, userName)); - sb.append(String.format("USER %s \n", userName)); + if (!IS_PODMAN) { // only needed for docker + String uid = getId("-u"); + String gid = getId("-g"); + String userName = getId("-un"); + String groupName = getId("-gn"); + // Only needed when run as regular user. UID == 0 should already exist + if (!ROOT_UID.equals(uid)) { + sb.append(String.format("RUN groupadd --gid %s %s \n", gid, groupName)); + sb.append(String.format("RUN useradd --uid %s --gid %s %s \n", uid, gid, userName)); + sb.append(String.format("USER %s \n", userName)); + } + } sb.append("CMD [\"/bin/bash\"]\n"); @@ -155,12 +163,17 @@ public class TestJcmd { private static Process startObservedContainer() throws Exception { DockerRunOptions opts = new DockerRunOptions(IMAGE_NAME, "/jdk/bin/java", "EventGeneratorLoop"); - opts.addDockerOpts("--volume", Utils.TEST_CLASSES + ":/test-classes/") + opts.addDockerOpts("--volume", Utils.TEST_CLASSES + ":/test-classes/:z") .addJavaOpts("-cp", "/test-classes/") .addDockerOpts("--cap-add=SYS_PTRACE") .addDockerOpts("--name", CONTAINER_NAME) .addClassOptions("" + TIME_TO_RUN_CONTAINER_PROCESS); + if (IS_PODMAN) { + // map the current userid to the one in the target namespace + opts.addDockerOpts("--userns=keep-id"); + } + // avoid large Xmx opts.appendTestJavaOptions = false; @@ -190,4 +203,78 @@ public class TestJcmd { System.out.println("getId() " + param + " returning: " + result); return result; } + + // pre: IS_PODMAN == true + private static String getPodmanVersionStr() { + if (!IS_PODMAN) { + return null; + } + try { + ProcessBuilder pb = new ProcessBuilder(Container.ENGINE_COMMAND, "--version"); + OutputAnalyzer out = new OutputAnalyzer(pb.start()) + .shouldHaveExitValue(0); + String result = out.asLines().get(0); + System.out.println(Container.ENGINE_COMMAND + " --version returning: " + result); + return result; + } catch (Exception e) { + System.out.println(Container.ENGINE_COMMAND + " --version command failed. Returning null"); + return null; + } + } + + private static PodmanVersion getPodmanVersion() { + return PodmanVersion.fromVersionString(getPodmanVersionStr()); + } + + private static class PodmanVersion implements Comparable { + private static final PodmanVersion DEFAULT = new PodmanVersion(0, 0, 0); + private static final PodmanVersion VERSION_3_3_1 = new PodmanVersion(3, 3, 1); + private final int major; + private final int minor; + private final int micro; + + private PodmanVersion(int major, int minor, int micro) { + this.major = major; + this.minor = minor; + this.micro = micro; + } + + @Override + public int compareTo(PodmanVersion other) { + if (this.major > other.major) { + return 1; + } else if (this.major < other.major) { + return -1; + } else { // equal major + if (this.minor > other.minor) { + return 1; + } else if (this.minor < other.minor) { + return -1; + } else { // equal majors and minors + if (this.micro > other.micro) { + return 1; + } else if (this.micro < other.micro) { + return -1; + } else { + // equal majors, minors, micro + return 0; + } + } + } + } + + private static PodmanVersion fromVersionString(String version) { + try { + // Example 'podman version 3.2.1' + String versNums = version.split("\\s+", 3)[2]; + String[] numbers = versNums.split("\\.", 3); + return new PodmanVersion(Integer.parseInt(numbers[0]), + Integer.parseInt(numbers[1]), + Integer.parseInt(numbers[2])); + } catch (Exception e) { + System.out.println("Failed to parse podman version: " + version); + return DEFAULT; + } + } + } } -- GitLab From c57ed22e779e7efc8ff7f3c7ec08ce2cb1a738cb Mon Sep 17 00:00:00 2001 From: Bradford Wetmore Date: Thu, 30 Sep 2021 15:46:29 +0000 Subject: [PATCH 051/385] 8274528: Add comment to explain an HKDF optimization in SSLSecretDerivation Reviewed-by: jnimeh --- .../sun/security/ssl/SSLSecretDerivation.java | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/java.base/share/classes/sun/security/ssl/SSLSecretDerivation.java b/src/java.base/share/classes/sun/security/ssl/SSLSecretDerivation.java index bdbf7f8dba4..a7ba9a5e566 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLSecretDerivation.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLSecretDerivation.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,6 +34,15 @@ import javax.net.ssl.SSLHandshakeException; import sun.security.ssl.CipherSuite.HashAlg; final class SSLSecretDerivation implements SSLKeyDerivation { + + /* + * Performance optimization: + * + * Derive-Secret(Secret, Label, Messages) = + * HKDF-Expand-Label(..., Transcript-Hash(""), ...); + * + * Hardcode tha Transcript-Hash("") result and skip a digest operation. + */ private static final byte[] sha256EmptyDigest = new byte[] { (byte)0xE3, (byte)0xB0, (byte)0xC4, (byte)0x42, (byte)0x98, (byte)0xFC, (byte)0x1C, (byte)0x14, @@ -45,6 +54,7 @@ final class SSLSecretDerivation implements SSLKeyDerivation { (byte)0x78, (byte)0x52, (byte)0xB8, (byte)0x55 }; + // See above. private static final byte[] sha384EmptyDigest = new byte[] { (byte)0x38, (byte)0xB0, (byte)0x60, (byte)0xA7, (byte)0x51, (byte)0xAC, (byte)0x96, (byte)0x38, @@ -68,7 +78,6 @@ final class SSLSecretDerivation implements SSLKeyDerivation { HandshakeContext context, SecretKey secret) { this.secret = secret; this.hashAlg = context.negotiatedCipherSuite.hashAlg; - String hkdfAlg = "HKDF-Expand/Hmac" + hashAlg.name.replace("-", ""); context.handshakeHash.update(); this.transcriptHash = context.handshakeHash.digest(); } @@ -141,7 +150,7 @@ final class SSLSecretDerivation implements SSLKeyDerivation { private final byte[] label; - private SecretSchedule(String label) { + SecretSchedule(String label) { this.label = ("tls13 " + label).getBytes(); } } -- GitLab From f08180f35f18263e33d96b6d1f06e5129328f01a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20=C3=96sterlund?= Date: Thu, 30 Sep 2021 15:52:36 +0000 Subject: [PATCH 052/385] 8274501: c2i entry barriers read int as long on AArch64 Reviewed-by: shade, kbarrett, aph --- .../cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.cpp index bc3fc6355d0..a4a2b142039 100644 --- a/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.cpp @@ -276,7 +276,7 @@ void BarrierSetAssembler::c2i_entry_barrier(MacroAssembler* masm) { __ load_method_holder_cld(rscratch1, rmethod); // Is it a strong CLD? - __ ldr(rscratch2, Address(rscratch1, ClassLoaderData::keep_alive_offset())); + __ ldrw(rscratch2, Address(rscratch1, ClassLoaderData::keep_alive_offset())); __ cbnz(rscratch2, method_live); // Is it a weak but alive CLD? -- GitLab From 9573022978bfeff55b51fa6f30027f59a0783d31 Mon Sep 17 00:00:00 2001 From: Patricio Chilano Mateo Date: Thu, 30 Sep 2021 16:02:14 +0000 Subject: [PATCH 053/385] 8253197: vmTestbase/nsk/jvmti/StopThread/stopthrd007/TestDescription.java fails with "ERROR: DebuggeeSleepingThread: ThreadDeath lost" Reviewed-by: dholmes, cjplummer, sspitsyn --- .../vmTestbase/nsk/jvmti/StopThread/stopthrd007.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/StopThread/stopthrd007.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/StopThread/stopthrd007.java index f93efda9d8c..61df040bcd4 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/StopThread/stopthrd007.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/StopThread/stopthrd007.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -170,8 +170,8 @@ class stopthrd007ThreadRunning extends Thread { } public void run() { - stopthrd007.startingBarrier.unlock(); try { + stopthrd007.startingBarrier.unlock(); int i = 0; int n = 1000; while (flag) { @@ -216,8 +216,8 @@ class stopthrd007ThreadWaiting extends Thread { } public synchronized void run() { - stopthrd007.startingBarrier.unlock(); try { + stopthrd007.startingBarrier.unlock(); wait(timeout); status = 1; } catch (ThreadDeath t) { @@ -249,8 +249,8 @@ class stopthrd007ThreadSleeping extends Thread { } public void run() { - stopthrd007.startingBarrier.unlock(); try { + stopthrd007.startingBarrier.unlock(); sleep(timeout); status = 1; } catch (ThreadDeath t) { -- GitLab From 8215b2eb61bd89c4041420e1c5c673603d6b2119 Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Thu, 30 Sep 2021 16:58:53 +0000 Subject: [PATCH 054/385] 8274398: Suppress more warnings on non-serializable non-transient instance fields in management libs Reviewed-by: sspitsyn --- .../share/classes/javax/management/loading/MLet.java | 3 +++ .../share/classes/com/sun/tools/jdi/ConnectorImpl.java | 3 ++- src/jdk.jdi/share/classes/com/sun/tools/jdi/EventSetImpl.java | 4 +++- src/jdk.jdi/share/classes/com/sun/tools/jdi/VMAction.java | 3 ++- .../classes/sun/management/jmxremote/SingleEntryRegistry.java | 3 ++- .../internal/GarbageCollectionNotifInfoCompositeData.java | 1 + .../com/sun/management/internal/GcInfoCompositeData.java | 2 ++ .../com/sun/management/internal/VMOptionCompositeData.java | 3 ++- 8 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/java.management/share/classes/javax/management/loading/MLet.java b/src/java.management/share/classes/javax/management/loading/MLet.java index 30445034613..4adf762c693 100644 --- a/src/java.management/share/classes/javax/management/loading/MLet.java +++ b/src/java.management/share/classes/javax/management/loading/MLet.java @@ -184,6 +184,7 @@ public class MLet extends java.net.URLClassLoader * The reference to the MBean server. * @serial */ + @SuppressWarnings("serial") // Type of field is not Serializable private MBeanServer server = null; @@ -192,6 +193,7 @@ public class MLet extends java.net.URLClassLoader * class found at the specified URL. * @serial */ + @SuppressWarnings("serial") // Type of field is not Serializable private List mletList = new ArrayList(); @@ -228,6 +230,7 @@ public class MLet extends java.net.URLClassLoader /** * objects maps from primitive classes to primitive object classes. */ + @SuppressWarnings("serial") // Type of field is not Serializable private Map> primitiveClasses = new HashMap>(8) ; { diff --git a/src/jdk.jdi/share/classes/com/sun/tools/jdi/ConnectorImpl.java b/src/jdk.jdi/share/classes/com/sun/tools/jdi/ConnectorImpl.java index f3984659e54..cadec74b2a0 100644 --- a/src/jdk.jdi/share/classes/com/sun/tools/jdi/ConnectorImpl.java +++ b/src/jdk.jdi/share/classes/com/sun/tools/jdi/ConnectorImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -398,6 +398,7 @@ abstract class ConnectorImpl implements Connector { class SelectedArgumentImpl extends ConnectorImpl.ArgumentImpl implements Connector.SelectedArgument { private static final long serialVersionUID = -5689584530908382517L; + @SuppressWarnings("serial") // Type of field is not Serializable private final List choices; SelectedArgumentImpl(String name, String label, String description, diff --git a/src/jdk.jdi/share/classes/com/sun/tools/jdi/EventSetImpl.java b/src/jdk.jdi/share/classes/com/sun/tools/jdi/EventSetImpl.java index 846d7343823..19e8b45c491 100644 --- a/src/jdk.jdi/share/classes/com/sun/tools/jdi/EventSetImpl.java +++ b/src/jdk.jdi/share/classes/com/sun/tools/jdi/EventSetImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -85,7 +85,9 @@ enum EventDestination {UNKNOWN_EVENT, INTERNAL_EVENT, CLIENT_EVENT}; */ public class EventSetImpl extends ArrayList implements EventSet { private static final long serialVersionUID = -4857338819787924570L; + @SuppressWarnings("serial") // Type of field is not Serializable private VirtualMachineImpl vm; // we implement Mirror + @SuppressWarnings("serial") // Type of field is not Serializable private Packet pkt; private byte suspendPolicy; private EventSetImpl internalEventSet; diff --git a/src/jdk.jdi/share/classes/com/sun/tools/jdi/VMAction.java b/src/jdk.jdi/share/classes/com/sun/tools/jdi/VMAction.java index 60bbd380830..73bf2eb8bdc 100644 --- a/src/jdk.jdi/share/classes/com/sun/tools/jdi/VMAction.java +++ b/src/jdk.jdi/share/classes/com/sun/tools/jdi/VMAction.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,6 +43,7 @@ class VMAction extends EventObject { static final int VM_NOT_SUSPENDED = 2; int id; + @SuppressWarnings("serial") // Type of field is not Serializable ThreadReference resumingThread; VMAction(VirtualMachine vm, int id) { diff --git a/src/jdk.management.agent/share/classes/sun/management/jmxremote/SingleEntryRegistry.java b/src/jdk.management.agent/share/classes/sun/management/jmxremote/SingleEntryRegistry.java index 098f2a51a7b..9e520adfe6b 100644 --- a/src/jdk.management.agent/share/classes/sun/management/jmxremote/SingleEntryRegistry.java +++ b/src/jdk.management.agent/share/classes/sun/management/jmxremote/SingleEntryRegistry.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -103,6 +103,7 @@ public class SingleEntryRegistry extends RegistryImpl { } private final String name; + @SuppressWarnings("serial") // Type of field is not Serializable private final Remote object; private static final long serialVersionUID = -4897238949499730950L; diff --git a/src/jdk.management/share/classes/com/sun/management/internal/GarbageCollectionNotifInfoCompositeData.java b/src/jdk.management/share/classes/com/sun/management/internal/GarbageCollectionNotifInfoCompositeData.java index 3e24b1c0496..98285f34ddb 100644 --- a/src/jdk.management/share/classes/com/sun/management/internal/GarbageCollectionNotifInfoCompositeData.java +++ b/src/jdk.management/share/classes/com/sun/management/internal/GarbageCollectionNotifInfoCompositeData.java @@ -47,6 +47,7 @@ import sun.management.Util; * construction of a CompositeData use in the local case. */ public class GarbageCollectionNotifInfoCompositeData extends LazyCompositeData { + @SuppressWarnings("serial") // Type of field is not Serializable private final GarbageCollectionNotificationInfo gcNotifInfo; public GarbageCollectionNotifInfoCompositeData(GarbageCollectionNotificationInfo info) { diff --git a/src/jdk.management/share/classes/com/sun/management/internal/GcInfoCompositeData.java b/src/jdk.management/share/classes/com/sun/management/internal/GcInfoCompositeData.java index c681391ce1d..fdf64ebaeb2 100644 --- a/src/jdk.management/share/classes/com/sun/management/internal/GcInfoCompositeData.java +++ b/src/jdk.management/share/classes/com/sun/management/internal/GcInfoCompositeData.java @@ -51,7 +51,9 @@ import sun.management.Util; * construction of a CompositeData use in the local case. */ public class GcInfoCompositeData extends LazyCompositeData { + @SuppressWarnings("serial") // Type of field is not Serializable private final GcInfo info; + @SuppressWarnings("serial") // Type of field is not Serializable private final GcInfoBuilder builder; private final Object[] gcExtItemValues; diff --git a/src/jdk.management/share/classes/com/sun/management/internal/VMOptionCompositeData.java b/src/jdk.management/share/classes/com/sun/management/internal/VMOptionCompositeData.java index 9ca81a4d6ea..2ddb0049874 100644 --- a/src/jdk.management/share/classes/com/sun/management/internal/VMOptionCompositeData.java +++ b/src/jdk.management/share/classes/com/sun/management/internal/VMOptionCompositeData.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,6 +40,7 @@ import sun.management.MappedMXBeanType; * construction of a CompositeData use in the local case. */ public class VMOptionCompositeData extends LazyCompositeData { + @SuppressWarnings("serial") // Type of field is not Serializable private final VMOption option; private VMOptionCompositeData(VMOption option) { -- GitLab From 7326481143c1321700cbf2caa9e068c5077e22c4 Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Thu, 30 Sep 2021 17:39:05 +0000 Subject: [PATCH 055/385] 8274393: Suppress more warnings on non-serializable non-transient instance fields in security libs Reviewed-by: weijun --- .../classes/com/sun/crypto/provider/PBKDF2KeyImpl.java | 2 ++ .../signature/MissingResourceFailureException.java | 1 + .../javax/xml/crypto/URIReferenceException.java | 1 + .../share/classes/sun/security/pkcs11/P11Key.java | 8 ++++++++ .../share/classes/sun/security/pkcs11/SunPKCS11.java | 7 +++++++ .../share/classes/sun/security/pkcs11/Token.java | 10 ++++++++++ .../classes/sun/security/ec/ECPrivateKeyImpl.java | 1 + .../share/classes/sun/security/ec/ECPublicKeyImpl.java | 5 ++++- .../classes/sun/security/ec/XDHPrivateKeyImpl.java | 1 + .../classes/sun/security/ec/XDHPublicKeyImpl.java | 3 ++- .../sun/security/ec/ed/EdDSAPrivateKeyImpl.java | 1 + .../classes/sun/security/ec/ed/EdDSAPublicKeyImpl.java | 4 +++- 12 files changed, 41 insertions(+), 3 deletions(-) diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PBKDF2KeyImpl.java b/src/java.base/share/classes/com/sun/crypto/provider/PBKDF2KeyImpl.java index 1588385d653..56477a1ac13 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/PBKDF2KeyImpl.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/PBKDF2KeyImpl.java @@ -64,6 +64,8 @@ final class PBKDF2KeyImpl implements javax.crypto.interfaces.PBEKey { private int iterCount; private byte[] key; + @SuppressWarnings("serial") // Type of field is not Serializable; + // see writeReplace method private Mac prf; private static byte[] getPasswordBytes(char[] passwd) { diff --git a/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/signature/MissingResourceFailureException.java b/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/signature/MissingResourceFailureException.java index 73f458be39d..a4e7093c609 100644 --- a/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/signature/MissingResourceFailureException.java +++ b/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/signature/MissingResourceFailureException.java @@ -37,6 +37,7 @@ public class MissingResourceFailureException extends XMLSignatureException { private static final long serialVersionUID = 1L; /** Field uninitializedReference */ + @SuppressWarnings("serial") // Type of field is not Serializable private Reference uninitializedReference; /** diff --git a/src/java.xml.crypto/share/classes/javax/xml/crypto/URIReferenceException.java b/src/java.xml.crypto/share/classes/javax/xml/crypto/URIReferenceException.java index 44d85a087c1..df56fd3105a 100644 --- a/src/java.xml.crypto/share/classes/javax/xml/crypto/URIReferenceException.java +++ b/src/java.xml.crypto/share/classes/javax/xml/crypto/URIReferenceException.java @@ -61,6 +61,7 @@ public class URIReferenceException extends Exception { * The {@code URIReference} that was being dereferenced * when the exception was thrown, or {@code null} if not specified. */ + @SuppressWarnings("serial") // Type of field is not Serializable private URIReference uriReference; /** diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Key.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Key.java index 9b69072280e..638bd208aa6 100644 --- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Key.java +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Key.java @@ -90,6 +90,7 @@ abstract class P11Key implements Key, Length { // flags indicating whether the key is a token object, sensitive, extractable final boolean tokenObject, sensitive, extractable; + @SuppressWarnings("serial") // Type of field is not Serializable private final NativeKeyHolder keyIDHolder; private static final boolean DISABLE_NATIVE_KEYS_EXTRACTION; @@ -723,6 +724,7 @@ abstract class P11Key implements Key, Length { private static final long serialVersionUID = 5989753793316396637L; private BigInteger y; + @SuppressWarnings("serial") // Type of field is not Serializable private DSAParams params; private byte[] encoded; P11DSAPublicKey(Session session, long keyID, String algorithm, @@ -786,6 +788,7 @@ abstract class P11Key implements Key, Length { private static final long serialVersionUID = 3119629997181999389L; private BigInteger x; + @SuppressWarnings("serial") // Type of field is not Serializable private DSAParams params; private byte[] encoded; P11DSAPrivateKey(Session session, long keyID, String algorithm, @@ -840,6 +843,7 @@ abstract class P11Key implements Key, Length { private static final long serialVersionUID = -1698576167364928838L; private BigInteger x; + @SuppressWarnings("serial") // Type of field is not Serializable private DHParameterSpec params; private byte[] encoded; P11DHPrivateKey(Session session, long keyID, String algorithm, @@ -922,6 +926,7 @@ abstract class P11Key implements Key, Length { static final long serialVersionUID = -598383872153843657L; private BigInteger y; + @SuppressWarnings("serial") // Type of field is not Serializable private DHParameterSpec params; private byte[] encoded; P11DHPublicKey(Session session, long keyID, String algorithm, @@ -1009,6 +1014,7 @@ abstract class P11Key implements Key, Length { private static final long serialVersionUID = -7786054399510515515L; private BigInteger s; + @SuppressWarnings("serial") // Type of field is not Serializable private ECParameterSpec params; private byte[] encoded; P11ECPrivateKey(Session session, long keyID, String algorithm, @@ -1064,7 +1070,9 @@ abstract class P11Key implements Key, Length { implements ECPublicKey { private static final long serialVersionUID = -6371481375154806089L; + @SuppressWarnings("serial") // Type of field is not Serializable private ECPoint w; + @SuppressWarnings("serial") // Type of field is not Serializable private ECParameterSpec params; private byte[] encoded; P11ECPublicKey(Session session, long keyID, String algorithm, diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/SunPKCS11.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/SunPKCS11.java index 112b639aa96..a825bea16ec 100644 --- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/SunPKCS11.java +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/SunPKCS11.java @@ -66,25 +66,32 @@ public final class SunPKCS11 extends AuthProvider { static final Debug debug = Debug.getInstance("sunpkcs11"); // the PKCS11 object through which we make the native calls + @SuppressWarnings("serial") // Type of field is not Serializable; + // see writeReplace final PKCS11 p11; // configuration information + @SuppressWarnings("serial") // Type of field is not Serializable final Config config; // id of the PKCS#11 slot we are using final long slotID; + @SuppressWarnings("serial") // Type of field is not Serializable private CallbackHandler pHandler; + @SuppressWarnings("serial") // Type of field is not Serializable private final Object LOCK_HANDLER = new Object(); final boolean removable; + @SuppressWarnings("serial") // Type of field is not Serializable final Secmod.Module nssModule; final boolean nssUseSecmodTrust; private volatile Token token; + @SuppressWarnings("serial") // Type of field is not Serializable private TokenPoller poller; static NativeResourceCleaner cleaner; diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/Token.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/Token.java index 9858a5faedf..3c1e674a822 100644 --- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/Token.java +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/Token.java @@ -58,16 +58,21 @@ class Token implements Serializable { final SunPKCS11 provider; + @SuppressWarnings("serial") // Type of field is not Serializable final PKCS11 p11; + @SuppressWarnings("serial") // Type of field is not Serializable final Config config; + @SuppressWarnings("serial") // Type of field is not Serializable final CK_TOKEN_INFO tokenInfo; // session manager to pool sessions + @SuppressWarnings("serial") // Type of field is not Serializable final SessionManager sessionManager; // template manager to customize the attributes used when creating objects + @SuppressWarnings("serial") // Type of field is not Serializable private final TemplateManager templateManager; // flag indicating whether we need to explicitly cancel operations @@ -76,16 +81,20 @@ class Token implements Serializable { final boolean explicitCancel; // translation cache for secret keys + @SuppressWarnings("serial") // Type of field is not Serializable final KeyCache secretCache; // translation cache for asymmetric keys (public and private) + @SuppressWarnings("serial") // Type of field is not Serializable final KeyCache privateCache; // cached instances of the various key factories, initialized on demand + @SuppressWarnings("serial") // Type of field is not Serializable private volatile P11KeyFactory rsaFactory, dsaFactory, dhFactory, ecFactory; // table which maps mechanisms to the corresponding cached // MechanismInfo objects + @SuppressWarnings("serial") // Type of field is not Serializable private final Map mechInfoMap; // single SecureRandomSpi instance we use per token @@ -94,6 +103,7 @@ class Token implements Serializable { // single KeyStoreSpi instance we use per provider // initialized on demand + @SuppressWarnings("serial") // Type of field is not Serializable private volatile P11KeyStore keyStore; // whether this token is a removable token diff --git a/src/jdk.crypto.ec/share/classes/sun/security/ec/ECPrivateKeyImpl.java b/src/jdk.crypto.ec/share/classes/sun/security/ec/ECPrivateKeyImpl.java index bf940a73100..f95beaa9c1c 100644 --- a/src/jdk.crypto.ec/share/classes/sun/security/ec/ECPrivateKeyImpl.java +++ b/src/jdk.crypto.ec/share/classes/sun/security/ec/ECPrivateKeyImpl.java @@ -66,6 +66,7 @@ public final class ECPrivateKeyImpl extends PKCS8Key implements ECPrivateKey { private BigInteger s; // private value private byte[] arrayS; // private value as a little-endian array + @SuppressWarnings("serial") // Type of field is not Serializable private ECParameterSpec params; /** diff --git a/src/jdk.crypto.ec/share/classes/sun/security/ec/ECPublicKeyImpl.java b/src/jdk.crypto.ec/share/classes/sun/security/ec/ECPublicKeyImpl.java index bc403026c4d..b7cf40df8a3 100644 --- a/src/jdk.crypto.ec/share/classes/sun/security/ec/ECPublicKeyImpl.java +++ b/src/jdk.crypto.ec/share/classes/sun/security/ec/ECPublicKeyImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2021, Oracle and/or its affiliates. All rights reserved. * 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,10 @@ public final class ECPublicKeyImpl extends X509Key implements ECPublicKey { private static final long serialVersionUID = -2462037275160462289L; + @SuppressWarnings("serial") // Type of field is not + // Serializable;see writeReplace private ECPoint w; + @SuppressWarnings("serial") // Type of field is not Serializable private ECParameterSpec params; /** diff --git a/src/jdk.crypto.ec/share/classes/sun/security/ec/XDHPrivateKeyImpl.java b/src/jdk.crypto.ec/share/classes/sun/security/ec/XDHPrivateKeyImpl.java index beeda53006f..50802c60eb2 100644 --- a/src/jdk.crypto.ec/share/classes/sun/security/ec/XDHPrivateKeyImpl.java +++ b/src/jdk.crypto.ec/share/classes/sun/security/ec/XDHPrivateKeyImpl.java @@ -39,6 +39,7 @@ public final class XDHPrivateKeyImpl extends PKCS8Key implements XECPrivateKey { private static final long serialVersionUID = 1L; + @SuppressWarnings("serial") // Type of field is not Serializable private final AlgorithmParameterSpec paramSpec; private byte[] k; diff --git a/src/jdk.crypto.ec/share/classes/sun/security/ec/XDHPublicKeyImpl.java b/src/jdk.crypto.ec/share/classes/sun/security/ec/XDHPublicKeyImpl.java index 0b9b6d93c04..e109a5eba5d 100644 --- a/src/jdk.crypto.ec/share/classes/sun/security/ec/XDHPublicKeyImpl.java +++ b/src/jdk.crypto.ec/share/classes/sun/security/ec/XDHPublicKeyImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,6 +43,7 @@ public final class XDHPublicKeyImpl extends X509Key implements XECPublicKey { private static final long serialVersionUID = 1L; private final BigInteger u; + @SuppressWarnings("serial") // Type of field is not Serializable private final NamedParameterSpec paramSpec; XDHPublicKeyImpl(XECParameters params, BigInteger u) diff --git a/src/jdk.crypto.ec/share/classes/sun/security/ec/ed/EdDSAPrivateKeyImpl.java b/src/jdk.crypto.ec/share/classes/sun/security/ec/ed/EdDSAPrivateKeyImpl.java index a4f769e55f6..bf04bf73758 100644 --- a/src/jdk.crypto.ec/share/classes/sun/security/ec/ed/EdDSAPrivateKeyImpl.java +++ b/src/jdk.crypto.ec/share/classes/sun/security/ec/ed/EdDSAPrivateKeyImpl.java @@ -41,6 +41,7 @@ public final class EdDSAPrivateKeyImpl private static final long serialVersionUID = 1L; + @SuppressWarnings("serial") // Type of field is not Serializable private final NamedParameterSpec paramSpec; private byte[] h; diff --git a/src/jdk.crypto.ec/share/classes/sun/security/ec/ed/EdDSAPublicKeyImpl.java b/src/jdk.crypto.ec/share/classes/sun/security/ec/ed/EdDSAPublicKeyImpl.java index ebc51e9a821..c1cba3a1fb1 100644 --- a/src/jdk.crypto.ec/share/classes/sun/security/ec/ed/EdDSAPublicKeyImpl.java +++ b/src/jdk.crypto.ec/share/classes/sun/security/ec/ed/EdDSAPublicKeyImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,7 +41,9 @@ public final class EdDSAPublicKeyImpl extends X509Key implements EdECPublicKey { private static final long serialVersionUID = 1L; + @SuppressWarnings("serial") // Type of field is not Serializable private final EdECPoint point; + @SuppressWarnings("serial") // Type of field is not Serializable private final NamedParameterSpec paramSpec; public EdDSAPublicKeyImpl(EdDSAParameters params, EdECPoint point) -- GitLab From a8edd1b360d4e5f35aff371a91fda42eeb00d395 Mon Sep 17 00:00:00 2001 From: Jie Fu Date: Thu, 30 Sep 2021 23:11:56 +0000 Subject: [PATCH 056/385] 8274527: Minimal VM build fails after JDK-8273459 Reviewed-by: kvn --- src/hotspot/cpu/x86/macroAssembler_x86.cpp | 6 +++- src/hotspot/cpu/x86/macroAssembler_x86.hpp | 1 + .../cpu/x86/macroAssembler_x86_adler.cpp | 4 +-- src/hotspot/cpu/x86/stubGenerator_x86_64.cpp | 28 +++++++++---------- 4 files changed, 22 insertions(+), 17 deletions(-) diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp index bf56eddbdee..072e7962b8b 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp @@ -1177,6 +1177,10 @@ void MacroAssembler::align64() { align(64, (unsigned long long) pc()); } +void MacroAssembler::align32() { + align(32, (unsigned long long) pc()); +} + void MacroAssembler::align(int modulus) { // 8273459: Ensure alignment is possible with current segment alignment assert(modulus <= CodeEntryAlignment, "Alignment must be <= CodeEntryAlignment"); @@ -6905,7 +6909,7 @@ void MacroAssembler::kernel_crc32(Register crc, Register buf, Register len, Regi // 128 bits per each of 4 parallel streams. movdqu(xmm0, ExternalAddress(StubRoutines::x86::crc_by128_masks_addr() + 32)); - align(32); + align32(); BIND(L_fold_512b_loop); fold_128bit_crc32(xmm1, xmm0, xmm5, buf, 0); fold_128bit_crc32(xmm2, xmm0, xmm5, buf, 16); diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.hpp b/src/hotspot/cpu/x86/macroAssembler_x86.hpp index c28f7c43b8b..9b9e85643b8 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.hpp @@ -194,6 +194,7 @@ class MacroAssembler: public Assembler { void incrementq(AddressLiteral dst); // Alignment + void align32(); void align64(); void align(int modulus); void align(int modulus, int target); diff --git a/src/hotspot/cpu/x86/macroAssembler_x86_adler.cpp b/src/hotspot/cpu/x86/macroAssembler_x86_adler.cpp index 7e77dc899c2..12e0e5ee7d3 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86_adler.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86_adler.cpp @@ -80,7 +80,7 @@ void MacroAssembler::updateBytesAdler32(Register init_d, Register data, Register cmpptr(data, end); jcc(Assembler::aboveEqual, SKIP_LOOP_1A); - align(32); + align32(); bind(SLOOP1A); vbroadcastf128(ydata, Address(data, 0), Assembler::AVX_256bit); addptr(data, CHUNKSIZE); @@ -178,7 +178,7 @@ void MacroAssembler::updateBytesAdler32(Register init_d, Register data, Register movdl(rax, xb); addl(b_d, rax); - align(32); + align32(); bind(FINAL_LOOP); movzbl(rax, Address(data, 0)); //movzx eax, byte[data] addl(a_d, rax); diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp index f5d3023009e..70fd2e67da1 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp @@ -1484,7 +1484,7 @@ class StubGenerator: public StubCodeGenerator { __ subq(temp1, loop_size[shift]); // Main loop with aligned copy block size of 192 bytes at 32 byte granularity. - __ align(32); + __ align32(); __ BIND(L_main_loop); __ copy64_avx(to, from, temp4, xmm1, false, shift, 0); __ copy64_avx(to, from, temp4, xmm1, false, shift, 64); @@ -1551,7 +1551,7 @@ class StubGenerator: public StubCodeGenerator { // Main loop with aligned copy block size of 192 bytes at // 64 byte copy granularity. - __ align(32); + __ align32(); __ BIND(L_main_loop_64bytes); __ copy64_avx(to, from, temp4, xmm1, false, shift, 0 , true); __ copy64_avx(to, from, temp4, xmm1, false, shift, 64, true); @@ -1691,7 +1691,7 @@ class StubGenerator: public StubCodeGenerator { __ BIND(L_main_pre_loop); // Main loop with aligned copy block size of 192 bytes at 32 byte granularity. - __ align(32); + __ align32(); __ BIND(L_main_loop); __ copy64_avx(to, from, temp1, xmm1, true, shift, -64); __ copy64_avx(to, from, temp1, xmm1, true, shift, -128); @@ -1724,7 +1724,7 @@ class StubGenerator: public StubCodeGenerator { // Main loop with aligned copy block size of 192 bytes at // 64 byte copy granularity. - __ align(32); + __ align32(); __ BIND(L_main_loop_64bytes); __ copy64_avx(to, from, temp1, xmm1, true, shift, -64 , true); __ copy64_avx(to, from, temp1, xmm1, true, shift, -128, true); @@ -4274,7 +4274,7 @@ class StubGenerator: public StubCodeGenerator { //Mask for byte-swapping a couple of qwords in an XMM register using (v)pshufb. address generate_pshuffle_byte_flip_mask_sha512() { - __ align(32); + __ align32(); StubCodeMark mark(this, "StubRoutines", "pshuffle_byte_flip_mask_sha512"); address start = __ pc(); if (VM_Version::supports_avx2()) { @@ -5401,7 +5401,7 @@ address generate_avx_ghash_processBlocks() { address base64_avx2_shuffle_addr() { - __ align(32); + __ align32(); StubCodeMark mark(this, "StubRoutines", "avx2_shuffle_base64"); address start = __ pc(); __ emit_data64(0x0809070805060405, relocInfo::none); @@ -5413,7 +5413,7 @@ address generate_avx_ghash_processBlocks() { address base64_avx2_input_mask_addr() { - __ align(32); + __ align32(); StubCodeMark mark(this, "StubRoutines", "avx2_input_mask_base64"); address start = __ pc(); __ emit_data64(0x8000000000000000, relocInfo::none); @@ -5425,7 +5425,7 @@ address generate_avx_ghash_processBlocks() { address base64_avx2_lut_addr() { - __ align(32); + __ align32(); StubCodeMark mark(this, "StubRoutines", "avx2_lut_base64"); address start = __ pc(); __ emit_data64(0xfcfcfcfcfcfc4741, relocInfo::none); @@ -5530,7 +5530,7 @@ address generate_avx_ghash_processBlocks() { __ evmovdquq(xmm2, Address(encode_table, 0), Assembler::AVX_512bit); __ evpbroadcastq(xmm1, rax, Assembler::AVX_512bit); - __ align(32); + __ align32(); __ BIND(L_vbmiLoop); __ vpermb(xmm0, xmm3, Address(source, start_offset), Assembler::AVX_512bit); @@ -5730,7 +5730,7 @@ address generate_avx_ghash_processBlocks() { __ cmpl(length, 31); __ jcc(Assembler::belowEqual, L_process3); - __ align(32); + __ align32(); __ BIND(L_32byteLoop); // Get next 32 bytes @@ -6177,7 +6177,7 @@ address generate_avx_ghash_processBlocks() { __ evmovdquq(join12, ExternalAddress(StubRoutines::x86::base64_vbmi_join_1_2_addr()), Assembler::AVX_512bit, r13); __ evmovdquq(join23, ExternalAddress(StubRoutines::x86::base64_vbmi_join_2_3_addr()), Assembler::AVX_512bit, r13); - __ align(32); + __ align32(); __ BIND(L_process256); // Grab input data __ evmovdquq(input0, Address(source, start_offset, Address::times_1, 0x00), Assembler::AVX_512bit); @@ -6259,7 +6259,7 @@ address generate_avx_ghash_processBlocks() { __ cmpl(length, 63); __ jcc(Assembler::lessEqual, L_finalBit); - __ align(32); + __ align32(); __ BIND(L_process64Loop); // Handle first 64-byte block @@ -6395,7 +6395,7 @@ address generate_avx_ghash_processBlocks() { __ shrq(rax, 1); __ jmp(L_donePadding); - __ align(32); + __ align32(); __ BIND(L_bruteForce); } // End of if(avx512_vbmi) @@ -6439,7 +6439,7 @@ address generate_avx_ghash_processBlocks() { __ jmp(L_bottomLoop); - __ align(32); + __ align32(); __ BIND(L_forceLoop); __ shll(byte1, 18); __ shll(byte2, 12); -- GitLab From 2e690ba8bda30902f1188cabad63fb60f4eb828f Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Fri, 1 Oct 2021 00:25:35 +0000 Subject: [PATCH 057/385] 8274322: Problems with oopDesc construction Reviewed-by: dholmes, stefank --- src/hotspot/share/oops/instanceOop.hpp | 6 +++++- src/hotspot/share/oops/markWord.hpp | 5 ++++- src/hotspot/share/oops/objArrayOop.hpp | 6 +++++- src/hotspot/share/oops/oop.hpp | 16 ++++++++++++++++ src/hotspot/share/oops/typeArrayOop.hpp | 6 +++++- 5 files changed, 35 insertions(+), 4 deletions(-) diff --git a/src/hotspot/share/oops/instanceOop.hpp b/src/hotspot/share/oops/instanceOop.hpp index 005cf5a9e88..8de3b1a742c 100644 --- a/src/hotspot/share/oops/instanceOop.hpp +++ b/src/hotspot/share/oops/instanceOop.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. * 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,6 +26,7 @@ #define SHARE_OOPS_INSTANCEOOP_HPP #include "oops/oop.hpp" +#include // An instanceOop is an instance of a Java Class // Evaluating "new HashTable()" will create an instanceOop. @@ -44,4 +45,7 @@ class instanceOopDesc : public oopDesc { } }; +// See similar requirement for oopDesc. +static_assert(std::is_trivially_default_constructible::value, "required"); + #endif // SHARE_OOPS_INSTANCEOOP_HPP diff --git a/src/hotspot/share/oops/markWord.hpp b/src/hotspot/share/oops/markWord.hpp index 62adf95971a..febfa7015a7 100644 --- a/src/hotspot/share/oops/markWord.hpp +++ b/src/hotspot/share/oops/markWord.hpp @@ -73,10 +73,13 @@ class markWord { public: explicit markWord(uintptr_t value) : _value(value) {} - markWord() { /* uninitialized */} + markWord() = default; // Doesn't initialize _value. // It is critical for performance that this class be trivially // destructable, copyable, and assignable. + ~markWord() = default; + markWord(const markWord&) = default; + markWord& operator=(const markWord&) = default; static markWord from_pointer(void* ptr) { return markWord((uintptr_t)ptr); diff --git a/src/hotspot/share/oops/objArrayOop.hpp b/src/hotspot/share/oops/objArrayOop.hpp index 5952c058ef5..3ebf1736455 100644 --- a/src/hotspot/share/oops/objArrayOop.hpp +++ b/src/hotspot/share/oops/objArrayOop.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,7 @@ #include "oops/arrayOop.hpp" #include "utilities/align.hpp" +#include class Klass; @@ -109,4 +110,7 @@ public: void oop_iterate_range(OopClosureType* blk, int start, int end); }; +// See similar requirement for oopDesc. +static_assert(std::is_trivially_default_constructible::value, "required"); + #endif // SHARE_OOPS_OBJARRAYOOP_HPP diff --git a/src/hotspot/share/oops/oop.hpp b/src/hotspot/share/oops/oop.hpp index b30e7a2cb66..7a7608051a1 100644 --- a/src/hotspot/share/oops/oop.hpp +++ b/src/hotspot/share/oops/oop.hpp @@ -31,7 +31,9 @@ #include "oops/markWord.hpp" #include "oops/metadata.hpp" #include "runtime/atomic.hpp" +#include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" +#include // oopDesc is the top baseclass for objects classes. The {name}Desc classes describe // the format of Java objects so the fields can be accessed from C++. @@ -57,7 +59,14 @@ class oopDesc { narrowKlass _compressed_klass; } _metadata; + // There may be ordering constraints on the initialization of fields that + // make use of the C++ copy/assign incorrect. + NONCOPYABLE(oopDesc); + public: + // Must be trivial; see verifying static assert after the class. + oopDesc() = default; + inline markWord mark() const; inline markWord mark_acquire() const; inline markWord* mark_addr() const; @@ -311,4 +320,11 @@ class oopDesc { DEBUG_ONLY(bool get_UseG1GC();) }; +// An oopDesc is not initialized via a constructor. Space is allocated in +// the Java heap, and static functions provided here on HeapWord* are used +// to fill in certain parts of that memory. The allocated memory is then +// treated as referring to an oopDesc. For that to be valid, the oopDesc +// class must have a trivial default constructor (C++14 3.8/1). +static_assert(std::is_trivially_default_constructible::value, "required"); + #endif // SHARE_OOPS_OOP_HPP diff --git a/src/hotspot/share/oops/typeArrayOop.hpp b/src/hotspot/share/oops/typeArrayOop.hpp index 2af7be778a4..83f385fe5ac 100644 --- a/src/hotspot/share/oops/typeArrayOop.hpp +++ b/src/hotspot/share/oops/typeArrayOop.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,7 @@ #include "oops/arrayOop.hpp" #include "oops/typeArrayKlass.hpp" +#include // A typeArrayOop is an array containing basic types (non oop elements). // It is used for arrays of {characters, singles, doubles, bytes, shorts, integers, longs} @@ -134,4 +135,7 @@ private: inline int object_size(const TypeArrayKlass* tk) const; }; +// See similar requirement for oopDesc. +static_assert(std::is_trivially_default_constructible::value, "required"); + #endif // SHARE_OOPS_TYPEARRAYOOP_HPP -- GitLab From 5e4b514e6e7e1b9f51fac1983b6c12a988f7f5a8 Mon Sep 17 00:00:00 2001 From: Martin Doerr Date: Fri, 1 Oct 2021 08:20:51 +0000 Subject: [PATCH 058/385] 8274550: c2i entry barriers read int as long on PPC Reviewed-by: eosterlund, shade --- src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.cpp b/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.cpp index 800b34e4ba7..f60d1811823 100644 --- a/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.cpp @@ -178,7 +178,7 @@ void BarrierSetAssembler::c2i_entry_barrier(MacroAssembler *masm, Register tmp1, __ ld(tmp1_class_loader_data, in_bytes(InstanceKlass::class_loader_data_offset()), tmp1); // Fast path: If class loader is strong, the holder cannot be unloaded. - __ ld(tmp2, in_bytes(ClassLoaderData::keep_alive_offset()), tmp1_class_loader_data); + __ lwz(tmp2, in_bytes(ClassLoaderData::keep_alive_offset()), tmp1_class_loader_data); __ cmpdi(CCR0, tmp2, 0); __ bne(CCR0, skip_barrier); -- GitLab From b7b78ff1f380d19214dbca48455772bc87cc137d Mon Sep 17 00:00:00 2001 From: Ao Qi Date: Fri, 1 Oct 2021 08:52:04 +0000 Subject: [PATCH 059/385] 8274561: sun/net/ftp/TestFtpTimeValue.java timed out on slow machines Reviewed-by: jiefu, dfuchs --- test/jdk/sun/net/ftp/TestFtpTimeValue.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/jdk/sun/net/ftp/TestFtpTimeValue.java b/test/jdk/sun/net/ftp/TestFtpTimeValue.java index e51837db238..b6120e0288e 100644 --- a/test/jdk/sun/net/ftp/TestFtpTimeValue.java +++ b/test/jdk/sun/net/ftp/TestFtpTimeValue.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -116,7 +116,7 @@ public class TestFtpTimeValue { public void handleClient(Socket client) throws IOException { String str; - client.setSoTimeout(2000); + client.setSoTimeout(10000); BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream())); PrintWriter out = new PrintWriter(client.getOutputStream(), true); out.println("220 FTP serverSocket is ready."); -- GitLab From 18870284084aaaf729640de0105ce21e253546b9 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Fri, 1 Oct 2021 08:53:04 +0000 Subject: [PATCH 060/385] 8269113: Javac throws when compiling switch (null) Co-authored-by: Guoxiong Li Reviewed-by: vromero --- .../sun/tools/javac/comp/TransPatterns.java | 5 +-- .../tools/javac/patterns/SwitchErrors.java | 8 ++++- .../tools/javac/patterns/SwitchErrors.out | 3 +- .../tools/javac/patterns/Switches.java | 32 ++++++++++++++++++- 4 files changed, 43 insertions(+), 5 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java index 8edb987155b..fda59d6ddaa 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java @@ -277,9 +277,10 @@ public class TransPatterns extends TreeTranslator { List cases, boolean hasTotalPattern, boolean patternSwitch) { - Type seltype = selector.type; - if (patternSwitch) { + Type seltype = selector.type.hasTag(BOT) + ? syms.objectType + : selector.type; Assert.check(preview.isEnabled()); Assert.check(preview.usesPreview(env.toplevel.sourcefile)); diff --git a/test/langtools/tools/javac/patterns/SwitchErrors.java b/test/langtools/tools/javac/patterns/SwitchErrors.java index 3ca7b703ebd..ddeca570d3a 100644 --- a/test/langtools/tools/javac/patterns/SwitchErrors.java +++ b/test/langtools/tools/javac/patterns/SwitchErrors.java @@ -1,6 +1,6 @@ /* * @test /nodynamiccopyright/ - * @bug 8262891 8269146 + * @bug 8262891 8269146 8269113 * @summary Verify errors related to pattern switches. * @compile/fail/ref=SwitchErrors.out --enable-preview -source ${jdk.version} -XDrawDiagnostics -XDshould-stop.at=FLOW SwitchErrors.java */ @@ -222,4 +222,10 @@ public class SwitchErrors { case null: break; } } + void referenceTypeTotalForNull() { + switch (null) { + case String s: break; + case CharSequence cs: break; + } + } } diff --git a/test/langtools/tools/javac/patterns/SwitchErrors.out b/test/langtools/tools/javac/patterns/SwitchErrors.out index 5cd3bf81bc6..ba5f2338d06 100644 --- a/test/langtools/tools/javac/patterns/SwitchErrors.out +++ b/test/langtools/tools/javac/patterns/SwitchErrors.out @@ -36,6 +36,7 @@ SwitchErrors.java:200:24: compiler.err.flows.through.to.pattern SwitchErrors.java:209:29: compiler.err.total.pattern.and.default SwitchErrors.java:216:42: compiler.err.flows.through.from.pattern SwitchErrors.java:216:45: compiler.err.flows.through.from.pattern +SwitchErrors.java:228:18: compiler.err.duplicate.total.pattern SwitchErrors.java:9:9: compiler.err.not.exhaustive.statement SwitchErrors.java:15:9: compiler.err.not.exhaustive.statement SwitchErrors.java:21:9: compiler.err.not.exhaustive.statement @@ -50,4 +51,4 @@ SwitchErrors.java:164:9: compiler.err.not.exhaustive.statement SwitchErrors.java:221:9: compiler.err.not.exhaustive.statement - compiler.note.preview.filename: SwitchErrors.java, DEFAULT - compiler.note.preview.recompile -50 errors +51 errors diff --git a/test/langtools/tools/javac/patterns/Switches.java b/test/langtools/tools/javac/patterns/Switches.java index d9c626d9d58..cf9858e7d0a 100644 --- a/test/langtools/tools/javac/patterns/Switches.java +++ b/test/langtools/tools/javac/patterns/Switches.java @@ -28,7 +28,7 @@ import java.util.function.Function; /* * @test - * @bug 8262891 8268333 8268896 8269802 8269808 8270151 + * @bug 8262891 8268333 8268896 8269802 8269808 8270151 8269113 * @summary Check behavior of pattern switches. * @compile --enable-preview -source ${jdk.version} Switches.java * @run main/othervm --enable-preview Switches @@ -71,6 +71,7 @@ public class Switches { runFallThrough(this::testFallThrough2Expression); npeTest(this::npeTestStatement); npeTest(this::npeTestExpression); + npeTest(this::switchOverNullNPE); exhaustiveStatementSane(""); exhaustiveStatementSane(null); exhaustiveStatementSane2(null); @@ -81,6 +82,9 @@ public class Switches { switchNestingTest(this::switchNestingExpressionStatement); switchNestingTest(this::switchNestingExpressionExpression); switchNestingTest(this::switchNestingIfSwitch); + assertEquals(2, switchOverNull1()); + assertEquals(2, switchOverNull2()); + assertEquals(2, switchOverNull3()); } void run(Function mapper) { @@ -573,6 +577,32 @@ public class Switches { return f.apply(o1, o2); } + private void switchOverNullNPE(I i) { + int r = switch (null) { + default -> 1; + }; + } + + private int switchOverNull1() { + return switch (null) { + case Object o -> 2; + }; + } + + private int switchOverNull2() { + return switch (null) { + case null -> 2; + default -> 1; + }; + } + + private int switchOverNull3() { + return switch (null) { + case null -> 2; + case Object o -> 1; + }; + } + //verify that for cases like: //case ConstantClassClash -> //ConstantClassClash is interpreted as a field, not as a class -- GitLab From 292d7bb1d5d311b517b2cd6d0f6dc77e35b3f649 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Fri, 1 Oct 2021 08:54:18 +0000 Subject: [PATCH 061/385] 8274363: Transitively sealed classes not considered exhaustive in switches Reviewed-by: vromero --- .../com/sun/tools/javac/comp/Flow.java | 31 ++++++++--- .../tools/javac/patterns/Exhaustiveness.java | 51 ++++++++++++++----- 2 files changed, 64 insertions(+), 18 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java index 26bb918679f..d14756759b7 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java @@ -207,6 +207,7 @@ public class Flow { private final JCDiagnostic.Factory diags; private Env attrEnv; private Lint lint; + private final DeferredCompletionFailureHandler dcfh; private final boolean allowEffectivelyFinalInInnerClasses; public static Flow instance(Context context) { @@ -331,6 +332,7 @@ public class Flow { lint = Lint.instance(context); rs = Resolve.instance(context); diags = JCDiagnostic.Factory.instance(context); + dcfh = DeferredCompletionFailureHandler.instance(context); Source source = Source.instance(context); allowEffectivelyFinalInInnerClasses = Feature.EFFECTIVELY_FINAL_IN_INNER_CLASSES.allowedInSource(source); } @@ -770,12 +772,9 @@ public class Flow { case TYP -> { for (Type sup : types.directSupertypes(sym.type)) { - if (sup.tsym.kind == TYP && sup.tsym.isAbstract() && sup.tsym.isSealed()) { - boolean hasAll = ((ClassSymbol) sup.tsym).permitted - .stream() - .allMatch(covered::contains); - - if (hasAll && covered.add(sup.tsym)) { + if (sup.tsym.kind == TYP) { + if (isTransitivelyCovered(sup.tsym, covered) && + covered.add(sup.tsym)) { todo = todo.prepend(sup.tsym); } } @@ -785,6 +784,26 @@ public class Flow { } } + private boolean isTransitivelyCovered(Symbol sealed, Set covered) { + DeferredCompletionFailureHandler.Handler prevHandler = + dcfh.setHandler(dcfh.speculativeCodeHandler); + try { + if (covered.stream().anyMatch(c -> sealed.isSubClass(c, types))) + return true; + if (sealed.kind == TYP && sealed.isAbstract() && sealed.isSealed()) { + return ((ClassSymbol) sealed).permitted + .stream() + .allMatch(s -> isTransitivelyCovered(s, covered)); + } + return false; + } catch (CompletionFailure cf) { + //safe to ignore, the symbol will be un-completed when the speculative handler is removed. + return false; + } finally { + dcfh.setHandler(prevHandler); + } + } + private boolean isExhaustive(Type seltype, Set covered) { transitiveCovers(covered); return switch (seltype.getTag()) { diff --git a/test/langtools/tools/javac/patterns/Exhaustiveness.java b/test/langtools/tools/javac/patterns/Exhaustiveness.java index 444b63c2647..9728fd83f48 100644 --- a/test/langtools/tools/javac/patterns/Exhaustiveness.java +++ b/test/langtools/tools/javac/patterns/Exhaustiveness.java @@ -23,7 +23,7 @@ /** * @test - * @bug 8262891 8268871 + * @bug 8262891 8268871 8274363 * @summary Check exhaustiveness of switches over sealed types. * @library /tools/lib * @modules jdk.compiler/com.sun.tools.javac.api @@ -775,23 +775,50 @@ public class Exhaustiveness extends TestRunner { "1 error"); } + @Test + public void testTransitiveSealed(Path base) throws Exception { + doTest(base, + new String[0], + """ + package test; + public class Test { + sealed interface A {} + sealed interface B1 extends A {} + sealed interface B2 extends A {} + sealed interface C extends A {} + final class D1 implements B1, C {} + final class D2 implements B2, C {} + + void test(A arg) { + int i = switch (arg) { + case B1 b1 -> 1; + case B2 b2 -> 2; + }; + } + } + """); + } + private void doTest(Path base, String[] libraryCode, String testCode, String... expectedErrors) throws IOException { Path current = base.resolve("."); - Path libSrc = current.resolve("lib-src"); - for (String code : libraryCode) { - tb.writeJavaFiles(libSrc, code); - } - Path libClasses = current.resolve("libClasses"); Files.createDirectories(libClasses); - new JavacTask(tb) - .options("--enable-preview", - "-source", JAVA_VERSION) - .outdir(libClasses) - .files(tb.findJavaFiles(libSrc)) - .run(); + if (libraryCode.length != 0) { + Path libSrc = current.resolve("lib-src"); + + for (String code : libraryCode) { + tb.writeJavaFiles(libSrc, code); + } + + new JavacTask(tb) + .options("--enable-preview", + "-source", JAVA_VERSION) + .outdir(libClasses) + .files(tb.findJavaFiles(libSrc)) + .run(); + } Path src = current.resolve("src"); tb.writeJavaFiles(src, testCode); -- GitLab From cc14c6f076356731f78aea4e890027f4e2a91642 Mon Sep 17 00:00:00 2001 From: Aleksei Efimov Date: Fri, 1 Oct 2021 09:48:09 +0000 Subject: [PATCH 062/385] 8274227: Remove "impl.prefix" jdk system property usage from InetAddress Reviewed-by: alanb, dfuchs --- .../classes/java/net/Inet4AddressImpl.java | 4 +- .../classes/java/net/Inet6AddressImpl.java | 4 +- .../share/classes/java/net/InetAddress.java | 49 +------------------ .../classes/java/net/InetAddressImpl.java | 4 +- 4 files changed, 8 insertions(+), 53 deletions(-) diff --git a/src/java.base/share/classes/java/net/Inet4AddressImpl.java b/src/java.base/share/classes/java/net/Inet4AddressImpl.java index 04c3273be55..4cbe28f998b 100644 --- a/src/java.base/share/classes/java/net/Inet4AddressImpl.java +++ b/src/java.base/share/classes/java/net/Inet4AddressImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,7 @@ import java.io.IOException; * * @since 1.4 */ -class Inet4AddressImpl implements InetAddressImpl { +final class Inet4AddressImpl implements InetAddressImpl { public native String getLocalHostName() throws UnknownHostException; public native InetAddress[] lookupAllHostAddr(String hostname) throws UnknownHostException; diff --git a/src/java.base/share/classes/java/net/Inet6AddressImpl.java b/src/java.base/share/classes/java/net/Inet6AddressImpl.java index fa03fca7bf3..f956a50e311 100644 --- a/src/java.base/share/classes/java/net/Inet6AddressImpl.java +++ b/src/java.base/share/classes/java/net/Inet6AddressImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2021, Oracle and/or its affiliates. All rights reserved. * 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,7 +44,7 @@ import static java.net.InetAddress.PREFER_SYSTEM_VALUE; * * @since 1.4 */ -class Inet6AddressImpl implements InetAddressImpl { +final class Inet6AddressImpl implements InetAddressImpl { public native String getLocalHostName() throws UnknownHostException; diff --git a/src/java.base/share/classes/java/net/InetAddress.java b/src/java.base/share/classes/java/net/InetAddress.java index a0189aa6ae9..b43c88e4f0e 100644 --- a/src/java.base/share/classes/java/net/InetAddress.java +++ b/src/java.base/share/classes/java/net/InetAddress.java @@ -1668,51 +1668,6 @@ public class InetAddress implements java.io.Serializable { return impl.anyLocalAddress(); } - /* - * Load and instantiate an underlying impl class - */ - static InetAddressImpl loadImpl(String implName) { - Object impl = null; - - /* - * Property "impl.prefix" will be prepended to the classname - * of the implementation object we instantiate, to which we - * delegate the real work (like native methods). This - * property can vary across implementations of the java. - * classes. The default is an empty String "". - */ - String prefix = GetPropertyAction.privilegedGetProperty("impl.prefix", ""); - try { - @SuppressWarnings("deprecation") - Object tmp = Class.forName("java.net." + prefix + implName).newInstance(); - impl = tmp; - } catch (ClassNotFoundException e) { - System.err.println("Class not found: java.net." + prefix + - implName + ":\ncheck impl.prefix property " + - "in your properties file."); - } catch (InstantiationException e) { - System.err.println("Could not instantiate: java.net." + prefix + - implName + ":\ncheck impl.prefix property " + - "in your properties file."); - } catch (IllegalAccessException e) { - System.err.println("Cannot access class: java.net." + prefix + - implName + ":\ncheck impl.prefix property " + - "in your properties file."); - } - - if (impl == null) { - try { - @SuppressWarnings("deprecation") - Object tmp = Class.forName(implName).newInstance(); - impl = tmp; - } catch (Exception e) { - throw new Error("System property impl.prefix incorrect"); - } - } - - return (InetAddressImpl) impl; - } - /** * Initializes an empty InetAddress. */ @@ -1793,8 +1748,8 @@ public class InetAddress implements java.io.Serializable { class InetAddressImplFactory { static InetAddressImpl create() { - return InetAddress.loadImpl(isIPv6Supported() ? - "Inet6AddressImpl" : "Inet4AddressImpl"); + return isIPv6Supported() ? + new Inet6AddressImpl() : new Inet4AddressImpl(); } static native boolean isIPv6Supported(); diff --git a/src/java.base/share/classes/java/net/InetAddressImpl.java b/src/java.base/share/classes/java/net/InetAddressImpl.java index bb67962d844..a2f8ea01052 100644 --- a/src/java.base/share/classes/java/net/InetAddressImpl.java +++ b/src/java.base/share/classes/java/net/InetAddressImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,7 @@ import java.io.IOException; * * @since 1.4 */ -interface InetAddressImpl { +sealed interface InetAddressImpl permits Inet4AddressImpl, Inet6AddressImpl { String getLocalHostName() throws UnknownHostException; InetAddress[] -- GitLab From c05dc268acaf87236f30cf700ea3ac778e3b20e5 Mon Sep 17 00:00:00 2001 From: Ekaterina Vergizova Date: Fri, 1 Oct 2021 12:53:08 +0000 Subject: [PATCH 063/385] 8274435: EXCEPTION_ACCESS_VIOLATION in BFSClosure::closure_impl Reviewed-by: stefank --- src/hotspot/share/jfr/leakprofiler/chains/bitset.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/jfr/leakprofiler/chains/bitset.cpp b/src/hotspot/share/jfr/leakprofiler/chains/bitset.cpp index 359de35d04a..7616d615a45 100644 --- a/src/hotspot/share/jfr/leakprofiler/chains/bitset.cpp +++ b/src/hotspot/share/jfr/leakprofiler/chains/bitset.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,7 +33,7 @@ BitSet::BitSet() : _bitmap_fragments(32), _fragment_list(NULL), _last_fragment_bits(NULL), - _last_fragment_granule(0) { + _last_fragment_granule(UINTPTR_MAX) { } BitSet::~BitSet() { -- GitLab From 3d7671b65e8491f3b1fcac8b96401401f783c9f4 Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Fri, 1 Oct 2021 15:30:55 +0000 Subject: [PATCH 064/385] 8274562: (fs) UserDefinedFileAttributeView doesn't correctly determine if supported when using OverlayFS Reviewed-by: alanb --- src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c b/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c index 9df8be1e62c..ad36e6a19b4 100644 --- a/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c +++ b/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c @@ -317,7 +317,7 @@ Java_sun_nio_fs_UnixNativeDispatcher_init(JNIEnv* env, jclass this) /* supports extended attributes */ -#ifdef _SYS_XATTR_H_ +#if defined(_SYS_XATTR_H) || defined(_SYS_XATTR_H_) capabilities |= sun_nio_fs_UnixNativeDispatcher_SUPPORTS_XATTR; #endif @@ -1330,4 +1330,4 @@ Java_sun_nio_fs_UnixNativeDispatcher_flistxattr(JNIEnv* env, jclass clazz, if (res == (size_t)-1) throwUnixException(env, errno); return (jint)res; -} \ No newline at end of file +} -- GitLab From 05d38604a2c620dcaf8682f02dae2fddab8e0c0b Mon Sep 17 00:00:00 2001 From: Pavel Rappo Date: Fri, 1 Oct 2021 16:15:48 +0000 Subject: [PATCH 065/385] 8274605: Fix predicate guarantees on returned values in (Doc)SourcePositions Reviewed-by: jlahoda, jjg --- .../sun/source/util/DocSourcePositions.java | 20 +++++++++---------- .../com/sun/source/util/SourcePositions.java | 20 +++++++++---------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/source/util/DocSourcePositions.java b/src/jdk.compiler/share/classes/com/sun/source/util/DocSourcePositions.java index a0bd1878293..520943c464d 100644 --- a/src/jdk.compiler/share/classes/com/sun/source/util/DocSourcePositions.java +++ b/src/jdk.compiler/share/classes/com/sun/source/util/DocSourcePositions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -49,9 +49,9 @@ public interface DocSourcePositions extends SourcePositions { * is for any sub-tree of this tree, the following must hold: * *

    - * {@code tree.getStartPosition() <= subtree.getStartPosition()} or
    - * {@code tree.getStartPosition() == NOPOS} or
    - * {@code subtree.getStartPosition() == NOPOS} + * {@code getStartPosition(file, comment, tree) <= getStartPosition(file, comment, subtree)} or
    + * {@code getStartPosition(file, comment, tree) == NOPOS} or
    + * {@code getStartPosition(file, comment, subtree) == NOPOS} *

    * * @param file compilation unit in which to find tree @@ -73,17 +73,17 @@ public interface DocSourcePositions extends SourcePositions { * that is for any sub-tree of this tree, the following must hold: * *

    - * {@code tree.getEndPosition() >= subtree.getEndPosition()} or
    - * {@code tree.getEndPosition() == NOPOS} or
    - * {@code subtree.getEndPosition() == NOPOS} + * {@code getEndPosition(file, comment, tree) >= getEndPosition(file, comment, subtree)} or
    + * {@code getEndPosition(file, comment, tree) == NOPOS} or
    + * {@code getEndPosition(file, comment, subtree) == NOPOS} *

    * * In addition, the following must hold: * *

    - * {@code tree.getStartPosition() <= tree.getEndPosition()} or
    - * {@code tree.getStartPosition() == NOPOS} or
    - * {@code tree.getEndPosition() == NOPOS} + * {@code getStartPosition(file, comment, tree) <= getEndPosition(file, comment, tree)} or
    + * {@code getStartPosition(file, comment, tree) == NOPOS} or
    + * {@code getEndPosition(file, comment, tree) == NOPOS} *

    * * @param file compilation unit in which to find tree diff --git a/src/jdk.compiler/share/classes/com/sun/source/util/SourcePositions.java b/src/jdk.compiler/share/classes/com/sun/source/util/SourcePositions.java index 1deaf6e7171..b6112fd32e6 100644 --- a/src/jdk.compiler/share/classes/com/sun/source/util/SourcePositions.java +++ b/src/jdk.compiler/share/classes/com/sun/source/util/SourcePositions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,9 +45,9 @@ public interface SourcePositions { * is for any sub-tree of this tree, the following must hold: * *

    - * {@code tree.getStartPosition() <= subtree.getStartPosition()} or
    - * {@code tree.getStartPosition() == NOPOS} or
    - * {@code subtree.getStartPosition() == NOPOS} + * {@code getStartPosition(file, tree) <= getStartPosition(file, subtree)} or
    + * {@code getStartPosition(file, tree) == NOPOS} or
    + * {@code getStartPosition(file, subtree) == NOPOS} *

    * * @param file CompilationUnit in which to find tree @@ -64,17 +64,17 @@ public interface SourcePositions { * that is for any sub-tree of this tree, the following must hold: * *

    - * {@code tree.getEndPosition() >= subtree.getEndPosition()} or
    - * {@code tree.getEndPosition() == NOPOS} or
    - * {@code subtree.getEndPosition() == NOPOS} + * {@code getEndPosition(file, tree) >= getEndPosition(file, subtree)} or
    + * {@code getEndPosition(file, tree) == NOPOS} or
    + * {@code getEndPosition(file, subtree) == NOPOS} *

    * * In addition, the following must hold: * *

    - * {@code tree.getStartPosition() <= tree.getEndPosition()} or
    - * {@code tree.getStartPosition() == NOPOS} or
    - * {@code tree.getEndPosition() == NOPOS} + * {@code getStartPosition(file, tree) <= getEndPosition(file, tree)} or
    + * {@code getStartPosition(file, tree) == NOPOS} or
    + * {@code getEndPosition(file, tree) == NOPOS} *

    * * @param file CompilationUnit in which to find tree -- GitLab From bb4500d0d227cbb238bd6c862e143f864106a31a Mon Sep 17 00:00:00 2001 From: Alexey Ivanov Date: Fri, 1 Oct 2021 18:41:51 +0000 Subject: [PATCH 066/385] 8274465: Fix javax/swing/text/ParagraphView/6364882/bug6364882.java failures Reviewed-by: jiefu, serb --- .../ParagraphView/6364882/bug6364882.java | 101 ++++++++++-------- 1 file changed, 57 insertions(+), 44 deletions(-) diff --git a/test/jdk/javax/swing/text/ParagraphView/6364882/bug6364882.java b/test/jdk/javax/swing/text/ParagraphView/6364882/bug6364882.java index bd05d8402ad..f100d959933 100644 --- a/test/jdk/javax/swing/text/ParagraphView/6364882/bug6364882.java +++ b/test/jdk/javax/swing/text/ParagraphView/6364882/bug6364882.java @@ -64,7 +64,7 @@ public class bug6364882 { + ""; private static final int WIDTH = 580; - private static final int HEIGHT = 600; + private static final int HEIGHT = 300; public static final String IMAGE_FILENAME = "editorPane.png"; @@ -84,11 +84,18 @@ public class bug6364882 { createUI(showFrame); BufferedImage image = paintToImage(); - errors = checkJustification(); - if (errors.size() > 0 || saveImage) { - saveImage(image); - dumpViews(); + boolean exceptionThrown = false; + try { + errors = checkJustification(); + } catch (Throwable t) { + exceptionThrown = true; + throw t; + } finally { + if (exceptionThrown || errors.size() > 0 || saveImage) { + saveImage(image); + dumpViews(); + } } }); @@ -133,57 +140,62 @@ public class bug6364882 { : "blockView doesn't have 2 child views"; final View bodyView = blockView.getView(1); final View paragraphView = bodyView.getView(0); - // Expected to have 6 rows in the paragraph - assert paragraphView.getViewCount() == 6 - : "paragraph doesn't have 6 rows of text"; - final Rectangle bounds = editorPane.getBounds(); + final int rowCount = paragraphView.getViewCount(); + if (rowCount < 4) { + errors.add(new Error("Less than 4 lines of text: no justified lines")); + return errors; + } - // Three rows should be justified - final int oneX = getEndOfLineX(paragraphView.getView(0), bounds); - if (oneX < bounds.width - 15) { - errors.add(new Error("Text is not justified at line " + 0 + ": " - + oneX + " < " + (bounds.width - 15))); + final Rectangle bounds = editorPane.getBounds(); + final int rightMargin = bounds.width - 15; + + // First lines should be justified + int lineNo = 0; + final int oneX = getEndOfLineX(paragraphView.getView(lineNo++), bounds); + if (oneX < rightMargin) { + errors.add(new Error("Text is not justified at line " + lineNo + ": " + + oneX + " < " + rightMargin)); } - for (int i = 1; i < 2; i++) { - int lineX = getEndOfLineX(paragraphView.getView(i), + // Justified lines should have the same width + while (lineNo < rowCount - 3) { + int lineX = getEndOfLineX(paragraphView.getView(lineNo++), bounds); if (oneX != lineX) { - errors.add(new Error("Text is not justified at line " + i + errors.add(new Error("Text is not justified at line " + lineNo + ": " + oneX + " != " + lineX)); } } - // Fourth row should not be justified - final int fourX = getEndOfLineX(paragraphView.getView(3), bounds); - if (oneX == fourX) { - errors.add(new Error("Fourth line is justified: " - + oneX + " vs " + fourX)); + // The last line of the wrapped text, before the first
    , + // should not be justified + final int twoX = getEndOfLineX(paragraphView.getView(lineNo++), bounds); + if (oneX == twoX) { + errors.add(new Error("Line " + lineNo + " is justified: " + + oneX + " vs " + twoX)); } - if (fourX > (bounds.width - bounds.width / 4)) { - errors.add(new Error("Fourth line is justified: " - + fourX + " > " - + (bounds.width - bounds.width / 4))); + if (twoX > rightMargin) { + errors.add(new Error("Line " + lineNo + " is justified: " + + twoX + " > " + rightMargin)); } - // Fifth and sixth lines should not be justified - final int fiveX = getEndOfLineX(paragraphView.getView(4), bounds); - if (oneX == fiveX) { - errors.add(new Error("Fifth line is justified: " - + oneX + "==" + fiveX)); + // The next two lines are created by line break
    + // They should not be justified and should be of the same width + final int threeX = getEndOfLineX(paragraphView.getView(lineNo++), bounds); + if (oneX == threeX) { + errors.add(new Error("Line " + lineNo + " is justified: " + + oneX + " == " + threeX)); } - if (fiveX > bounds.width / 2) { - errors.add(new Error("Fifth line is justified: " - + fiveX + " > " + (bounds.width / 2))); + if (threeX > bounds.width / 2) { + errors.add(new Error("Line " + lineNo + " is justified: " + + threeX + " > " + (bounds.width / 2))); } - if (fiveX > fourX) { - errors.add(new Error("Fifth line is justified: " - + fiveX + " > " + fourX)); - } - final int sixX = getEndOfLineX(paragraphView.getView(5), bounds); - if (fiveX != sixX) { - errors.add(new Error("Fifth and sixth lines aren't of the " - + "same width: " + fiveX + " != " + sixX)); + + final int lastX = getEndOfLineX(paragraphView.getView(lineNo), bounds); + if (threeX != lastX) { + errors.add(new Error("Line " + lineNo + " and " + (lineNo + 1) + + " have different width: " + + threeX + " != " + lastX)); } return errors; @@ -218,7 +230,8 @@ public class bug6364882 { try { ImageIO.write(image, "png", new File(IMAGE_FILENAME)); } catch (IOException e) { - throw new RuntimeException(e); + // Don't propagate the exception + e.printStackTrace(); } } @@ -228,7 +241,7 @@ public class bug6364882 { } private static void dumpViews(final View view, final String indent) { - System.out.println(indent + view.getClass().getName() + ": " + System.err.println(indent + view.getClass().getName() + ": " + view.getStartOffset() + ", " + view.getEndOffset() + "; span: " + view.getPreferredSpan(View.X_AXIS)); final String nestedIndent = indent + " "; -- GitLab From 0786d8b7b367e3aa3ffa54a3e339572938378dca Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Fri, 1 Oct 2021 20:15:44 +0000 Subject: [PATCH 067/385] 8268435: (ch) ChannelInputStream could override readAllBytes Reviewed-by: alanb, lancea --- .../classes/java/io/FileInputStream.java | 2 +- .../sun/nio/ch/ChannelInputStream.java | 111 ++++++- .../nio/channels/Channels/ReadXBytes.java | 310 ++++++++++++++++++ 3 files changed, 412 insertions(+), 11 deletions(-) create mode 100644 test/jdk/java/nio/channels/Channels/ReadXBytes.java diff --git a/src/java.base/share/classes/java/io/FileInputStream.java b/src/java.base/share/classes/java/io/FileInputStream.java index 8f65ad6238c..c7b547d12a0 100644 --- a/src/java.base/share/classes/java/io/FileInputStream.java +++ b/src/java.base/share/classes/java/io/FileInputStream.java @@ -339,7 +339,7 @@ public class FileInputStream extends InputStream int n; do { n = read(buf, nread, remaining); - if (n > 0 ) { + if (n > 0) { nread += n; remaining -= n; } else if (n == 0) { diff --git a/src/java.base/share/classes/sun/nio/ch/ChannelInputStream.java b/src/java.base/share/classes/sun/nio/ch/ChannelInputStream.java index 4bfb14f401a..b11a4e00ea8 100644 --- a/src/java.base/share/classes/sun/nio/ch/ChannelInputStream.java +++ b/src/java.base/share/classes/sun/nio/ch/ChannelInputStream.java @@ -25,11 +25,18 @@ package sun.nio.ch; -import java.io.*; -import java.nio.*; -import java.nio.channels.*; -import java.nio.channels.spi.*; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.channels.IllegalBlockingModeException; +import java.nio.channels.ReadableByteChannel; +import java.nio.channels.SeekableByteChannel; +import java.nio.channels.SelectableChannel; +import java.util.Arrays; import java.util.Objects; +import jdk.internal.util.ArraysSupport; /** * This class is defined here rather than in java.nio.channels.Channels @@ -43,13 +50,13 @@ import java.util.Objects; public class ChannelInputStream extends InputStream { + private static final int DEFAULT_BUFFER_SIZE = 8192; public static int read(ReadableByteChannel ch, ByteBuffer bb, boolean block) throws IOException { - if (ch instanceof SelectableChannel) { - SelectableChannel sc = (SelectableChannel)ch; + if (ch instanceof SelectableChannel sc) { synchronized (sc.blockingLock()) { boolean bm = sc.isBlocking(); if (!bm) @@ -107,10 +114,95 @@ public class ChannelInputStream return ChannelInputStream.read(ch, bb, true); } + @Override + public byte[] readAllBytes() throws IOException { + if (!(ch instanceof SeekableByteChannel sbc)) + return super.readAllBytes(); + + long length = sbc.size(); + long position = sbc.position(); + long size = length - position; + + if (length <= 0 || size <= 0) + return super.readAllBytes(); + + if (size > (long) Integer.MAX_VALUE) { + String msg = + String.format("Required array size too large: %d = %d - %d", + size, length, position); + throw new OutOfMemoryError(msg); + } + + int capacity = (int)size; + byte[] buf = new byte[capacity]; + + int nread = 0; + int n; + for (;;) { + // read to EOF which may read more or less than initial size, e.g., + // file is truncated while we are reading + while ((n = read(buf, nread, capacity - nread)) > 0) + nread += n; + + // if last call to read() returned -1, we are done; otherwise, + // try to read one more byte and if that fails we're done too + if (n < 0 || (n = read()) < 0) + break; + + // one more byte was read; need to allocate a larger buffer + capacity = Math.max(ArraysSupport.newLength(capacity, + 1, // min growth + capacity), // pref growth + DEFAULT_BUFFER_SIZE); + buf = Arrays.copyOf(buf, capacity); + buf[nread++] = (byte)n; + } + return (capacity == nread) ? buf : Arrays.copyOf(buf, nread); + } + + @Override + public byte[] readNBytes(int len) throws IOException { + if (len < 0) + throw new IllegalArgumentException("len < 0"); + if (len == 0) + return new byte[0]; + + if (!(ch instanceof SeekableByteChannel sbc)) + return super.readAllBytes(); + + long length = sbc.size(); + long position = sbc.position(); + long size = length - position; + + if (length <= 0 || size <= 0) + return super.readNBytes(len); + + int capacity = (int)Math.min(len, size); + byte[] buf = new byte[capacity]; + + int remaining = capacity; + int nread = 0; + int n; + do { + n = read(buf, nread, remaining); + if (n > 0) { + nread += n; + remaining -= n; + } else if (n == 0) { + // Block until a byte is read or EOF is detected + byte b = (byte)read(); + if (b == -1 ) + break; + buf[nread++] = b; + remaining--; + } + } while (n >= 0 && remaining > 0); + return (capacity == nread) ? buf : Arrays.copyOf(buf, nread); + } + public int available() throws IOException { // special case where the channel is to a file - if (ch instanceof SeekableByteChannel) { - SeekableByteChannel sbc = (SeekableByteChannel)ch; + if (ch instanceof SeekableByteChannel sbc) { long rem = Math.max(0, sbc.size() - sbc.position()); return (rem > Integer.MAX_VALUE) ? Integer.MAX_VALUE : (int)rem; } @@ -119,8 +211,7 @@ public class ChannelInputStream public synchronized long skip(long n) throws IOException { // special case where the channel is to a file - if (ch instanceof SeekableByteChannel) { - SeekableByteChannel sbc = (SeekableByteChannel)ch; + if (ch instanceof SeekableByteChannel sbc) { long pos = sbc.position(); long newPos; if (n > 0) { diff --git a/test/jdk/java/nio/channels/Channels/ReadXBytes.java b/test/jdk/java/nio/channels/Channels/ReadXBytes.java new file mode 100644 index 00000000000..8dd303acd5b --- /dev/null +++ b/test/jdk/java/nio/channels/Channels/ReadXBytes.java @@ -0,0 +1,310 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 8268435 + * @summary Verify ChannelInputStream methods readAllBytes and readNBytes + * @library .. + * @library /test/lib + * @build jdk.test.lib.RandomFactory + * @modules java.base/jdk.internal.util + * @run testng/othervm -Xmx8G ReadXBytes + * @key randomness + */ +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.nio.channels.Channels; +import java.nio.channels.FileChannel; +import java.nio.file.Files; +import java.nio.file.Path; +import static java.nio.file.StandardOpenOption.READ; +import java.util.Random; +import jdk.internal.util.ArraysSupport; + +import jdk.test.lib.RandomFactory; + +import org.testng.Assert; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertThrows; +import static org.testng.Assert.assertTrue; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +public class ReadXBytes { + + private static final Random RAND = RandomFactory.getRandom(); + + // The largest source from which to read all bytes + private static final int BIG_LENGTH = ArraysSupport.SOFT_MAX_ARRAY_LENGTH; + + // A length greater than a 32-bit integer can accommodate + private static final long HUGE_LENGTH = Integer.MAX_VALUE + 27L; + + // --- Framework --- + + // Creates a temporary file of a specified length with undefined content + static Path createFile(long length) throws IOException { + File file = File.createTempFile("foo", ".bar"); + file.deleteOnExit(); + try (RandomAccessFile raf = new RandomAccessFile(file, "rw")) { + raf.setLength(length); + } + return file.toPath(); + } + + // Creates a temporary file of a specified length with random content + static Path createFileWithRandomContent(long length) throws IOException { + Path file = createFile(length); + try (RandomAccessFile raf = new RandomAccessFile(file.toFile(), "rw")) { + long written = 0L; + int bufLength = Math.min(32768, (int)Math.min(length, BIG_LENGTH)); + byte[] buf = new byte[bufLength]; + while (written < length) { + RAND.nextBytes(buf); + int len = (int)Math.min(bufLength, length - written); + raf.write(buf, 0, len); + written += len; + } + } + return file; + } + + // Creates a file of a specified length + @FunctionalInterface + interface FileCreator { + Path create(long length) throws IOException; + } + + // Performs a test for checking edge cases + @FunctionalInterface + interface EdgeTest { + void test(long length, InputStream source) throws IOException; + } + + // Performs a test for evaluating correctness of content + @FunctionalInterface + interface DataTest { + void test(long length, InputStream source, InputStream reference) + throws IOException; + } + + // Construct for testing zero length, EOF, and IAE + public void edgeTest(long length, FileCreator c, EdgeTest f) + throws IOException { + Path file = c.create(length); + try (FileChannel fc = FileChannel.open(file, READ); + InputStream cis = Channels.newInputStream(fc)) { + f.test(length, cis); + } finally { + Files.delete(file); + } + } + + // Construct for testing correctness of content + public void dataTest(long length, FileCreator c, DataTest f) + throws IOException { + Path file = c.create(length); + try (FileInputStream fis = new FileInputStream(file.toFile()); + FileChannel fc = FileChannel.open(file, READ); + InputStream cis = Channels.newInputStream(fc)) { + f.test(length, cis, fis); + } finally { + Files.delete(file); + } + } + + // --- readAllBytes tests --- + + // Verifies readAllBytes() behavior for an empty file + @Test + public void readAllBytesFromEmptyFile() throws IOException { + edgeTest(0L, (length) -> createFile(length), + (length, cis) -> { + byte[] bytes = cis.readAllBytes(); + assertNotNull(bytes); + assertEquals(bytes.length, 0L); + } + ); + } + + // Verifies readAllBytes() behavior at EOF + @Test + public void readAllBytesAtEOF() throws IOException { + edgeTest(RAND.nextInt(Short.MAX_VALUE), (length) -> createFile(length), + (length, cis) -> { + cis.skipNBytes(length); + byte[] bytes = cis.readAllBytes(); + assertNotNull(bytes); + assertEquals(bytes.length, 0); + } + ); + } + + // Verifies readAllBytes() behavior for a maximal length source + @Test + public void readAllBytesFromMaxLengthFile() throws IOException { + dataTest(BIG_LENGTH, (length) -> createFileWithRandomContent(length), + (length, cis, fis) -> { + byte[] cisBytes = cis.readAllBytes(); + assertNotNull(cisBytes); + assertEquals(cisBytes.length, (long)length); + byte[] fisBytes = fis.readAllBytes(); + assertEquals(cisBytes, fisBytes); + } + ); + } + + // Verifies readAllBytes() throws OOME if the source is too large + @Test + public void readAllBytesFromBeyondMaxLengthFile() throws IOException { + dataTest(HUGE_LENGTH, (length) -> createFile(length), + (length, cis, fis) -> { + assertThrows(OutOfMemoryError.class, + () -> {cis.readAllBytes();}); + } + ); + } + + // Provides an array of lengths + @DataProvider + public Object[][] lengthProvider() throws IOException { + return new Object[][] { + {1 + RAND.nextInt(1)}, + {1 + RAND.nextInt(Byte.MAX_VALUE)}, + {1 + RAND.nextInt(Short.MAX_VALUE)}, + {1 + RAND.nextInt(1_000_000)}, + {1 + RAND.nextInt(BIG_LENGTH)} + }; + } + + // Verifies readAllBytes() accuracy for random lengths and initial positions + @Test(dataProvider = "lengthProvider") + public void readAllBytes(int len) throws IOException { + dataTest(len, (length) -> createFileWithRandomContent(length), + (length, cis, fis) -> { + long position = RAND.nextInt(Math.toIntExact(length)); + cis.skipNBytes(position); + byte[] cisBytes = cis.readAllBytes(); + assertNotNull(cisBytes); + assertEquals(cisBytes.length, length - position); + fis.skipNBytes(position); + byte[] fisBytes = fis.readAllBytes(); + assertEquals(cisBytes, fisBytes); + } + ); + } + + // --- readNBytes tests --- + + // Verifies readNBytes() behavior for a negative length + @Test + public void readNBytesWithNegativeLength() throws IOException { + edgeTest(0L, (length) -> createFile(length), + (length, cis) -> { + assertThrows(IllegalArgumentException.class, + () -> {cis.readNBytes(-1);}); + } + ); + } + + // Verifies readNBytes() for an empty file + @Test + public void readNBytesFromEmptyFile() throws IOException { + edgeTest(0L, (length) -> createFile(length), + (length, cis) -> { + byte[] bytes = cis.readNBytes(1); + assertNotNull(bytes); + assertEquals(bytes.length, 0); + } + ); + } + + // Verifies readNBytes() behavior at EOF + @Test + public void readNBytesAtEOF() throws IOException { + edgeTest(RAND.nextInt(Short.MAX_VALUE), (length) -> createFile(length), + (length, cis) -> { + cis.skipNBytes(length); + byte[] bytes = cis.readNBytes(1); + assertNotNull(bytes); + assertEquals(bytes.length, 0); + } + ); + } + + // Verifies readNBytes() behavior for a maximal length source + @Test + public void readNBytesFromMaxLengthFile() throws IOException { + dataTest(BIG_LENGTH, (length) -> createFileWithRandomContent(length), + (length, cis, fis) -> { + byte[] cisBytes = cis.readNBytes(BIG_LENGTH); + assertNotNull(cisBytes); + assertEquals(cisBytes.length, (long)length); + byte[] fisBytes = fis.readNBytes(BIG_LENGTH); + assertEquals(cisBytes, fisBytes); + } + ); + } + + // Verifies readNBytes() beyond the maximum length source + @Test + public void readNBytesFromBeyondMaxLengthFile() throws IOException { + dataTest(HUGE_LENGTH, (length) -> createFileWithRandomContent(length), + (length, cis, fis) -> { + assertTrue(BIG_LENGTH < length, length + " >= " + HUGE_LENGTH); + int n = Math.toIntExact(length - BIG_LENGTH); + cis.skipNBytes(BIG_LENGTH); + byte[] cisBytes = cis.readNBytes(n); + assertNotNull(cisBytes); + assertEquals(cisBytes.length, n); + fis.skipNBytes(BIG_LENGTH); + byte[] fisBytes = fis.readNBytes(n); + assertEquals(cisBytes, fisBytes); + } + ); + } + + // Verifies readNBytes() accuracy for random lengths and initial positions + @Test(dataProvider = "lengthProvider") + public void readNBytes(int len) throws IOException { + dataTest(len, (length) -> createFileWithRandomContent(length), + (length, cis, fis) -> { + int ilen = Math.toIntExact(len); + int position = RAND.nextInt(ilen); + int n = RAND.nextInt(ilen - position); + cis.skipNBytes(position); + byte[] cisBytes = cis.readNBytes(n); + assertNotNull(cisBytes); + assertEquals(cisBytes.length, n); + fis.skipNBytes(position); + byte[] fisBytes = fis.readNBytes(n); + assertEquals(cisBytes, fisBytes); + } + ); + } +} -- GitLab From 9ca6bf0d22ac39d4ee29c756903038f09087ca12 Mon Sep 17 00:00:00 2001 From: Andrey Turbanov Date: Sat, 2 Oct 2021 03:06:29 +0000 Subject: [PATCH 068/385] 8274505: Too weak variable type leads to unnecessary cast in java.desktop Reviewed-by: serb, kizune, pbansal --- .../com/sun/media/sound/SoftSynthesizer.java | 7 ++--- .../javax/swing/JFormattedTextField.java | 8 ++--- .../share/classes/javax/swing/JRootPane.java | 9 ++---- .../share/classes/javax/swing/JTree.java | 19 ++++++------ .../javax/swing/plaf/synth/SynthParser.java | 7 ++--- .../javax/swing/text/html/AccessibleHTML.java | 20 +++++-------- .../javax/swing/text/html/HTMLDocument.java | 7 ++--- .../javax/swing/text/html/HTMLEditorKit.java | 30 ++++++++----------- .../javax/swing/text/rtf/RTFGenerator.java | 15 +++++----- .../share/classes/sun/awt/SunToolkit.java | 4 +-- .../share/classes/sun/java2d/Disposer.java | 8 ++--- 11 files changed, 56 insertions(+), 78 deletions(-) diff --git a/src/java.desktop/share/classes/com/sun/media/sound/SoftSynthesizer.java b/src/java.desktop/share/classes/com/sun/media/sound/SoftSynthesizer.java index 70b8b622df9..1c8ff218077 100644 --- a/src/java.desktop/share/classes/com/sun/media/sound/SoftSynthesizer.java +++ b/src/java.desktop/share/classes/com/sun/media/sound/SoftSynthesizer.java @@ -289,12 +289,11 @@ public final class SoftSynthesizer implements AudioSynthesizer, c.current_instrument = null; c.current_director = null; } - for (Instrument instrument : instruments) { + for (ModelInstrument instrument : instruments) { String pat = patchToString(instrument.getPatch()); - SoftInstrument softins - = new SoftInstrument((ModelInstrument) instrument); + SoftInstrument softins = new SoftInstrument(instrument); inslist.put(pat, softins); - loadedlist.put(pat, (ModelInstrument) instrument); + loadedlist.put(pat, instrument); } } diff --git a/src/java.desktop/share/classes/javax/swing/JFormattedTextField.java b/src/java.desktop/share/classes/javax/swing/JFormattedTextField.java index 9ee465e3744..51516f79c99 100644 --- a/src/java.desktop/share/classes/javax/swing/JFormattedTextField.java +++ b/src/java.desktop/share/classes/javax/swing/JFormattedTextField.java @@ -868,11 +868,11 @@ public class JFormattedTextField extends JTextField { return new DefaultFormatterFactory(new DateFormatter()); } if (type instanceof Number) { - AbstractFormatter displayFormatter = new NumberFormatter(); - ((NumberFormatter)displayFormatter).setValueClass(type.getClass()); - AbstractFormatter editFormatter = new NumberFormatter( + NumberFormatter displayFormatter = new NumberFormatter(); + displayFormatter.setValueClass(type.getClass()); + NumberFormatter editFormatter = new NumberFormatter( new DecimalFormat("#.#")); - ((NumberFormatter)editFormatter).setValueClass(type.getClass()); + editFormatter.setValueClass(type.getClass()); return new DefaultFormatterFactory(displayFormatter, displayFormatter,editFormatter); diff --git a/src/java.desktop/share/classes/javax/swing/JRootPane.java b/src/java.desktop/share/classes/javax/swing/JRootPane.java index e3eb7ac75a4..dcc6d6bb4ef 100644 --- a/src/java.desktop/share/classes/javax/swing/JRootPane.java +++ b/src/java.desktop/share/classes/javax/swing/JRootPane.java @@ -24,18 +24,13 @@ */ package javax.swing; -import java.applet.Applet; import java.awt.*; -import java.awt.event.*; import java.beans.*; import java.security.AccessController; import javax.accessibility.*; import javax.swing.plaf.RootPaneUI; -import java.util.Vector; import java.io.Serializable; -import javax.swing.border.*; -import sun.awt.AWTAccessor; import sun.security.action.GetBooleanAction; @@ -511,10 +506,10 @@ public class JRootPane extends JComponent implements Accessible { * @return the default glassPane */ protected Component createGlassPane() { - JComponent c = new JPanel(); + JPanel c = new JPanel(); c.setName(this.getName()+".glassPane"); c.setVisible(false); - ((JPanel)c).setOpaque(false); + c.setOpaque(false); return c; } diff --git a/src/java.desktop/share/classes/javax/swing/JTree.java b/src/java.desktop/share/classes/javax/swing/JTree.java index f1ba5b9d3d3..e48c1b29333 100644 --- a/src/java.desktop/share/classes/javax/swing/JTree.java +++ b/src/java.desktop/share/classes/javax/swing/JTree.java @@ -2033,7 +2033,7 @@ public class JTree extends JComponent implements Scrollable, Accessible Enumeration toggledPaths = expandedState.keys(); Vector elements = null; TreePath path; - Object value; + Boolean value; if(toggledPaths != null) { while(toggledPaths.hasMoreElements()) { @@ -2042,8 +2042,7 @@ public class JTree extends JComponent implements Scrollable, Accessible // Add the path if it is expanded, a descendant of parent, // and it is visible (all parents expanded). This is rather // expensive! - if(path != parent && value != null && - ((Boolean)value).booleanValue() && + if (path != parent && value != null && value && parent.isDescendant(path) && isVisible(path)) { if (elements == null) { elements = new Vector(); @@ -2081,11 +2080,11 @@ public class JTree extends JComponent implements Scrollable, Accessible if(path == null) return false; - Object value; + Boolean value; do{ value = expandedState.get(path); - if(value == null || !((Boolean)value).booleanValue()) + if (value == null || !value) return false; } while( (path=path.getParentPath())!=null ); @@ -2109,7 +2108,7 @@ public class JTree extends JComponent implements Scrollable, Accessible if(path != null) { Boolean value = expandedState.get(path); - return (value != null && value.booleanValue()); + return (value != null && value); } } return false; @@ -3729,9 +3728,9 @@ public class JTree extends JComponent implements Scrollable, Accessible } if(!state) { // collapse last path. - Object cValue = expandedState.get(path); + Boolean cValue = expandedState.get(path); - if(cValue != null && ((Boolean)cValue).booleanValue()) { + if (cValue != null && cValue) { try { fireTreeWillCollapse(path); } @@ -3753,9 +3752,9 @@ public class JTree extends JComponent implements Scrollable, Accessible } else { // Expand last path. - Object cValue = expandedState.get(path); + Boolean cValue = expandedState.get(path); - if(cValue == null || !((Boolean)cValue).booleanValue()) { + if (cValue == null || !cValue) { try { fireTreeWillExpand(path); } diff --git a/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthParser.java b/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthParser.java index e053fe3d54c..4c212bc1ad8 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthParser.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthParser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1024,10 +1024,7 @@ class SynthParser extends DefaultHandler { painter, direction); - for (Object infoObject: painters) { - ParsedSynthStyle.PainterInfo info; - info = (ParsedSynthStyle.PainterInfo) infoObject; - + for (ParsedSynthStyle.PainterInfo info: painters) { if (painterInfo.equalsPainter(info)) { info.addPainter(painter); return; diff --git a/src/java.desktop/share/classes/javax/swing/text/html/AccessibleHTML.java b/src/java.desktop/share/classes/javax/swing/text/html/AccessibleHTML.java index 3e090982cec..a756cb2a02f 100644 --- a/src/java.desktop/share/classes/javax/swing/text/html/AccessibleHTML.java +++ b/src/java.desktop/share/classes/javax/swing/text/html/AccessibleHTML.java @@ -317,14 +317,12 @@ class AccessibleHTML implements Accessible { */ public AccessibleStateSet getAccessibleStateSet() { AccessibleStateSet states = new AccessibleStateSet(); - Component comp = getTextComponent(); + JTextComponent comp = getTextComponent(); if (comp.isEnabled()) { states.add(AccessibleState.ENABLED); } - if (comp instanceof JTextComponent && - ((JTextComponent)comp).isEditable()) { - + if (comp.isEditable()) { states.add(AccessibleState.EDITABLE); states.add(AccessibleState.FOCUSABLE); } @@ -742,11 +740,9 @@ class AccessibleHTML implements Accessible { * @see AccessibleStateSet */ public boolean isFocusTraversable() { - Component comp = getTextComponent(); - if (comp instanceof JTextComponent) { - if (((JTextComponent)comp).isEditable()) { - return true; - } + JTextComponent comp = getTextComponent(); + if (comp != null && comp.isEditable()) { + return true; } return false; } @@ -763,8 +759,8 @@ class AccessibleHTML implements Accessible { return; } - Component comp = getTextComponent(); - if (comp instanceof JTextComponent) { + JTextComponent comp = getTextComponent(); + if (comp != null) { comp.requestFocusInWindow(); @@ -772,7 +768,7 @@ class AccessibleHTML implements Accessible { if (elementInfo.validateIfNecessary()) { // set the caret position to the start of this component Element elem = elementInfo.getElement(); - ((JTextComponent)comp).setCaretPosition(elem.getStartOffset()); + comp.setCaretPosition(elem.getStartOffset()); // fire a AccessibleState.FOCUSED property change event AccessibleContext ac = editor.getAccessibleContext(); diff --git a/src/java.desktop/share/classes/javax/swing/text/html/HTMLDocument.java b/src/java.desktop/share/classes/javax/swing/text/html/HTMLDocument.java index 4063d2d7a75..bf9ebcfe651 100644 --- a/src/java.desktop/share/classes/javax/swing/text/html/HTMLDocument.java +++ b/src/java.desktop/share/classes/javax/swing/text/html/HTMLDocument.java @@ -4195,7 +4195,7 @@ public class HTMLDocument extends DefaultStyledDocument { try { if (offset == 0 || !getText(offset - 1, 1).equals("\n")) { // Need to insert a newline. - AttributeSet newAttrs = null; + SimpleAttributeSet newAttrs = null; boolean joinP = true; if (offset != 0) { @@ -4229,9 +4229,8 @@ public class HTMLDocument extends DefaultStyledDocument { // sure and set the name (otherwise it will be // inherited). newAttrs = new SimpleAttributeSet(); - ((SimpleAttributeSet)newAttrs).addAttribute - (StyleConstants.NameAttribute, - HTML.Tag.CONTENT); + newAttrs.addAttribute(StyleConstants.NameAttribute, + HTML.Tag.CONTENT); } ElementSpec es = new ElementSpec(newAttrs, ElementSpec.ContentType, NEWLINE, 0, diff --git a/src/java.desktop/share/classes/javax/swing/text/html/HTMLEditorKit.java b/src/java.desktop/share/classes/javax/swing/text/html/HTMLEditorKit.java index 53e0aedf3a5..46a311c05a2 100644 --- a/src/java.desktop/share/classes/javax/swing/text/html/HTMLEditorKit.java +++ b/src/java.desktop/share/classes/javax/swing/text/html/HTMLEditorKit.java @@ -61,7 +61,6 @@ import javax.accessibility.Accessible; import javax.accessibility.AccessibleAction; import javax.accessibility.AccessibleContext; import javax.swing.Action; -import javax.swing.JComponent; import javax.swing.JEditorPane; import javax.swing.JViewport; import javax.swing.SizeRequirements; @@ -848,13 +847,12 @@ public class HTMLEditorKit extends StyledEditorKit implements Accessible { Rectangle bounds; TextUI ui = html.getUI(); try { - Shape lBounds = ui.modelToView(html, offset, + Rectangle lBounds = ui.modelToView(html, offset, Position.Bias.Forward); - Shape rBounds = ui.modelToView(html, offset + 1, + Rectangle rBounds = ui.modelToView(html, offset + 1, Position.Bias.Backward); - bounds = lBounds.getBounds(); - bounds.add((rBounds instanceof Rectangle) ? - (Rectangle)rBounds : rBounds.getBounds()); + bounds = lBounds; + bounds.add(rBounds); } catch (BadLocationException ble) { bounds = null; } @@ -885,18 +883,14 @@ public class HTMLEditorKit extends StyledEditorKit implements Accessible { if (e != null && offset > 0 && e.getStartOffset() == offset) { try { TextUI ui = editor.getUI(); - Shape s1 = ui.modelToView(editor, offset, - Position.Bias.Forward); - if (s1 == null) { + Rectangle r1 = ui.modelToView(editor, offset, + Position.Bias.Forward); + if (r1 == null) { return false; } - Rectangle r1 = (s1 instanceof Rectangle) ? (Rectangle)s1 : - s1.getBounds(); - Shape s2 = ui.modelToView(editor, e.getEndOffset(), - Position.Bias.Backward); - if (s2 != null) { - Rectangle r2 = (s2 instanceof Rectangle) ? (Rectangle)s2 : - s2.getBounds(); + Rectangle r2 = ui.modelToView(editor, e.getEndOffset(), + Position.Bias.Backward); + if (r2 != null) { r1.add(r2); } return r1.contains(x, y); @@ -1517,9 +1511,9 @@ public class HTMLEditorKit extends StyledEditorKit implements Accessible { //if parent == null unregister component listener if (parent == null) { if (cachedViewPort != null) { - Object cachedObject; + JViewport cachedObject; if ((cachedObject = cachedViewPort.get()) != null) { - ((JComponent)cachedObject).removeComponentListener(this); + cachedObject.removeComponentListener(this); } cachedViewPort = null; } diff --git a/src/java.desktop/share/classes/javax/swing/text/rtf/RTFGenerator.java b/src/java.desktop/share/classes/javax/swing/text/rtf/RTFGenerator.java index 25f39ae58f8..46a7ce7efb9 100644 --- a/src/java.desktop/share/classes/javax/swing/text/rtf/RTFGenerator.java +++ b/src/java.desktop/share/classes/javax/swing/text/rtf/RTFGenerator.java @@ -27,7 +27,6 @@ package javax.swing.text.rtf; import java.lang.*; import java.util.*; import java.awt.Color; -import java.awt.Font; import java.io.OutputStream; import java.io.IOException; @@ -515,13 +514,13 @@ void updateSectionAttributes(MutableAttributeSet current, { if (emitStyleChanges) { Object oldStyle = current.getAttribute("sectionStyle"); - Object newStyle = findStyleNumber(newAttributes, Constants.STSection); + Integer newStyle = findStyleNumber(newAttributes, Constants.STSection); if (oldStyle != newStyle) { if (oldStyle != null) { resetSectionAttributes(current); } if (newStyle != null) { - writeControlWord("ds", ((Integer)newStyle).intValue()); + writeControlWord("ds", newStyle); current.addAttribute("sectionStyle", newStyle); } else { current.removeAttribute("sectionStyle"); @@ -554,8 +553,8 @@ void updateParagraphAttributes(MutableAttributeSet current, boolean emitStyleChanges) throws IOException { - Object parm; - Object oldStyle, newStyle; + Object oldStyle; + Integer newStyle; /* The only way to get rid of tabs or styles is with the \pard keyword, emitted by resetParagraphAttributes(). Ideally we should avoid @@ -587,7 +586,7 @@ void updateParagraphAttributes(MutableAttributeSet current, } if (oldStyle != newStyle && newStyle != null) { - writeControlWord("s", ((Integer)newStyle).intValue()); + writeControlWord("s", newStyle); current.addAttribute("paragraphStyle", newStyle); } @@ -706,14 +705,14 @@ void updateCharacterAttributes(MutableAttributeSet current, if (updateStyleChanges) { Object oldStyle = current.getAttribute("characterStyle"); - Object newStyle = findStyleNumber(newAttributes, + Integer newStyle = findStyleNumber(newAttributes, Constants.STCharacter); if (oldStyle != newStyle) { if (oldStyle != null) { resetCharacterAttributes(current); } if (newStyle != null) { - writeControlWord("cs", ((Integer)newStyle).intValue()); + writeControlWord("cs", newStyle.intValue()); current.addAttribute("characterStyle", newStyle); } else { current.removeAttribute("characterStyle"); diff --git a/src/java.desktop/share/classes/sun/awt/SunToolkit.java b/src/java.desktop/share/classes/sun/awt/SunToolkit.java index a46a68786bf..bfe9daeff48 100644 --- a/src/java.desktop/share/classes/sun/awt/SunToolkit.java +++ b/src/java.desktop/share/classes/sun/awt/SunToolkit.java @@ -1803,8 +1803,8 @@ public abstract class SunToolkit extends Toolkit if (useSystemAAFontSettings()) { Toolkit tk = Toolkit.getDefaultToolkit(); if (tk instanceof SunToolkit) { - Object map = ((SunToolkit)tk).getDesktopAAHints(); - return (RenderingHints)map; + RenderingHints map = ((SunToolkit)tk).getDesktopAAHints(); + return map; } else { /* Headless Toolkit */ return null; } diff --git a/src/java.desktop/share/classes/sun/java2d/Disposer.java b/src/java.desktop/share/classes/sun/java2d/Disposer.java index 1581364331f..6f359f7f87a 100644 --- a/src/java.desktop/share/classes/sun/java2d/Disposer.java +++ b/src/java.desktop/share/classes/sun/java2d/Disposer.java @@ -142,8 +142,8 @@ public class Disposer implements Runnable { public void run() { while (true) { try { - Object obj = queue.remove(); - ((Reference)obj).clear(); + Reference obj = queue.remove(); + obj.clear(); DisposerRecord rec = records.remove(obj); rec.dispose(); obj = null; @@ -200,7 +200,7 @@ public class Disposer implements Runnable { if (pollingQueue) { return; } - Object obj; + Reference obj; pollingQueue = true; int freed = 0; int deferred = 0; @@ -208,7 +208,7 @@ public class Disposer implements Runnable { while ( freed < 10000 && deferred < 100 && (obj = queue.poll()) != null ) { freed++; - ((Reference)obj).clear(); + obj.clear(); DisposerRecord rec = records.remove(obj); if (rec instanceof PollDisposable) { rec.dispose(); -- GitLab From 7957994273e20d541b8f2a873781be7fedf712f1 Mon Sep 17 00:00:00 2001 From: Robbin Ehn Date: Mon, 4 Oct 2021 06:47:27 +0000 Subject: [PATCH 069/385] 8273695: Safepoint deadlock on VMOperation_lock Reviewed-by: dcubed, pchilanomate, eosterlund --- .../share/runtime/safepointMechanism.hpp | 3 -- .../runtime/safepointMechanism.inline.hpp | 32 +++++++++++-------- .../share/runtime/stackWatermarkSet.cpp | 9 ++++++ .../share/runtime/stackWatermarkSet.hpp | 3 ++ test/hotspot/jtreg/ProblemList.txt | 5 --- 5 files changed, 30 insertions(+), 22 deletions(-) diff --git a/src/hotspot/share/runtime/safepointMechanism.hpp b/src/hotspot/share/runtime/safepointMechanism.hpp index 69e1b848893..46cac5e4a61 100644 --- a/src/hotspot/share/runtime/safepointMechanism.hpp +++ b/src/hotspot/share/runtime/safepointMechanism.hpp @@ -45,15 +45,12 @@ class SafepointMechanism : public AllStatic { static address _polling_page; - static inline void disarm_local_poll(JavaThread* thread); static inline bool global_poll(); static void process(JavaThread *thread, bool allow_suspend); - static inline bool should_process_no_suspend(JavaThread* thread); - static void default_initialize(); static void pd_initialize() NOT_AIX({ default_initialize(); }); diff --git a/src/hotspot/share/runtime/safepointMechanism.inline.hpp b/src/hotspot/share/runtime/safepointMechanism.inline.hpp index 7256cf0e5e4..9439672157f 100644 --- a/src/hotspot/share/runtime/safepointMechanism.inline.hpp +++ b/src/hotspot/share/runtime/safepointMechanism.inline.hpp @@ -30,6 +30,7 @@ #include "runtime/atomic.hpp" #include "runtime/handshake.hpp" #include "runtime/safepoint.hpp" +#include "runtime/stackWatermarkSet.hpp" #include "runtime/thread.inline.hpp" // Caller is responsible for using a memory barrier if needed. @@ -62,26 +63,29 @@ bool SafepointMechanism::global_poll() { return (SafepointSynchronize::_state != SafepointSynchronize::_not_synchronized); } -bool SafepointMechanism::should_process_no_suspend(JavaThread* thread) { - if (global_poll() || thread->handshake_state()->has_a_non_suspend_operation()) { - return true; - } else { - // We ignore suspend requests if any and just check before returning if we need - // to fix the thread's oops and first few frames due to a possible safepoint. - StackWatermarkSet::on_safepoint(thread); - update_poll_values(thread); - OrderAccess::cross_modify_fence(); - return false; - } -} - bool SafepointMechanism::should_process(JavaThread* thread, bool allow_suspend) { if (!local_poll_armed(thread)) { return false; } else if (allow_suspend) { return true; } - return should_process_no_suspend(thread); + // We are armed but we should ignore suspend operations. + if (global_poll() || // Safepoint + thread->handshake_state()->has_a_non_suspend_operation() || // Non-suspend handshake + !StackWatermarkSet::processing_started(thread)) { // StackWatermark processing is not started + return true; + } + + // It has boiled down to two possibilities: + // 1: We have nothing to process, this just a disarm poll. + // 2: We have a suspend handshake, which cannot be processed. + // We update the poll value in case of a disarm, to reduce false positives. + update_poll_values(thread); + + // We are now about to avoid processing and thus no cross modify fence will be executed. + // In case a safepoint happened, while being blocked, we execute it here. + OrderAccess::cross_modify_fence(); + return false; } void SafepointMechanism::process_if_requested(JavaThread* thread, bool allow_suspend) { diff --git a/src/hotspot/share/runtime/stackWatermarkSet.cpp b/src/hotspot/share/runtime/stackWatermarkSet.cpp index 26e8a628f86..dace3fee966 100644 --- a/src/hotspot/share/runtime/stackWatermarkSet.cpp +++ b/src/hotspot/share/runtime/stackWatermarkSet.cpp @@ -128,6 +128,15 @@ void StackWatermarkSet::start_processing(JavaThread* jt, StackWatermarkKind kind // will always update the poll values when waking up from a safepoint. } +bool StackWatermarkSet::processing_started(JavaThread* jt) { + for (StackWatermark* current = head(jt); current != NULL; current = current->next()) { + if (!current->processing_started()) { + return false; + } + } + return true; +} + void StackWatermarkSet::finish_processing(JavaThread* jt, void* context, StackWatermarkKind kind) { StackWatermark* watermark = get(jt, kind); if (watermark != NULL) { diff --git a/src/hotspot/share/runtime/stackWatermarkSet.hpp b/src/hotspot/share/runtime/stackWatermarkSet.hpp index 78cfc7f2827..11c27abb85e 100644 --- a/src/hotspot/share/runtime/stackWatermarkSet.hpp +++ b/src/hotspot/share/runtime/stackWatermarkSet.hpp @@ -79,6 +79,9 @@ public: // Called to ensure that processing of the thread is started static void start_processing(JavaThread* jt, StackWatermarkKind kind); + // Returns true if all StackWatermarks have been started. + static bool processing_started(JavaThread* jt); + // Called to finish the processing of a thread static void finish_processing(JavaThread* jt, void* context, StackWatermarkKind kind); diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index 088f7a08104..988426e23ec 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -85,11 +85,6 @@ gc/stress/gclocker/TestGCLockerWithParallel.java 8180622 generic-all gc/stress/gclocker/TestGCLockerWithG1.java 8180622 generic-all gc/stress/TestJNIBlockFullGC/TestJNIBlockFullGC.java 8192647 generic-all gc/metaspace/CompressedClassSpaceSizeInJmapHeap.java 8241293 macosx-x64 -gc/stringdedup/TestStringDeduplicationAgeThreshold.java#Z 8273695 generic-all -gc/stringdedup/TestStringDeduplicationPrintOptions.java#Z 8273695 generic-all -gc/stringdedup/TestStringDeduplicationInterned.java#Z 8273695 generic-all -gc/stringdedup/TestStringDeduplicationTableResize.java#Z 8273695 generic-all -gc/stringdedup/TestStringDeduplicationYoungGC.java#Z 8273695 generic-all ############################################################################# -- GitLab From 32811026ce5ecb1d27d835eac33de9ccbd51fcbf Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Mon, 4 Oct 2021 06:49:10 +0000 Subject: [PATCH 070/385] 8268084: [macos] Disabled JMenuItem arrow is not disabled Reviewed-by: serb, jdv --- .../com/apple/laf/AquaImageFactory.java | 17 +- .../aqua/JMenuItemDisableArrowButtonTest.java | 178 ++++++++++++++++++ 2 files changed, 194 insertions(+), 1 deletion(-) create mode 100644 test/jdk/javax/swing/plaf/aqua/JMenuItemDisableArrowButtonTest.java diff --git a/src/java.desktop/macosx/classes/com/apple/laf/AquaImageFactory.java b/src/java.desktop/macosx/classes/com/apple/laf/AquaImageFactory.java index ad069ca73b3..68ccd218086 100644 --- a/src/java.desktop/macosx/classes/com/apple/laf/AquaImageFactory.java +++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaImageFactory.java @@ -48,6 +48,7 @@ import com.apple.laf.AquaUtils.RecyclableObject; import com.apple.laf.AquaUtils.RecyclableSingleton; import sun.awt.image.MultiResolutionCachedImage; import sun.lwawt.macosx.CImage; +import sun.swing.ImageIconUIResource; public class AquaImageFactory { public static IconUIResource getConfirmImageIcon() { @@ -231,14 +232,28 @@ public class AquaImageFactory { @SuppressWarnings("serial") // Superclass is not serializable across versions static class InvertableImageIcon extends ImageIcon implements InvertableIcon, UIResource { Icon invertedImage; + private Icon disabledIcon; public InvertableImageIcon(final Image image) { super(image); } + @Override + public void paintIcon(Component c, Graphics g, int x, int y) { + if (!c.isEnabled()) { + if (disabledIcon == null) { + disabledIcon = new ImageIcon(GrayFilter. + createDisabledImage(((ImageIcon)this).getImage())); + } + disabledIcon.paintIcon(c, g, x, y); + } else { + super.paintIcon(c, g, x, y); + } + } + @Override public Icon getInvertedIcon() { if (invertedImage != null) return invertedImage; - return invertedImage = new IconUIResource(new ImageIcon(AquaUtils.generateLightenedImage(getImage(), 100))); + return invertedImage = new InvertableImageIcon(AquaUtils.generateLightenedImage(getImage(), 100)); } } diff --git a/test/jdk/javax/swing/plaf/aqua/JMenuItemDisableArrowButtonTest.java b/test/jdk/javax/swing/plaf/aqua/JMenuItemDisableArrowButtonTest.java new file mode 100644 index 00000000000..d64dbd32a0f --- /dev/null +++ b/test/jdk/javax/swing/plaf/aqua/JMenuItemDisableArrowButtonTest.java @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 + * @requires (os.family == "mac") + * @bug 8268084 + * @summary Verifies disabled JMenuItem arrow and check is disabled + * @run main/manual JMenuItemDisableArrowButtonTest + */ +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.awt.Color; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.GridBagConstraints; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JCheckBoxMenuItem; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JTextArea; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; + +public class JMenuItemDisableArrowButtonTest { + + private static JFrame frame; + private static volatile CountDownLatch countDownLatch; + private static volatile boolean testResult; + + private static final String INSTRUCTIONS = "INSTRUCTIONS:\n\n" + + "Click on \"SubMenuTest\" menu.\n " + + "If in 1st menuitem\n" + + "arrow icon is disabled along with \"Submenu\" menuitem\n" + + "and in 2nd menuitem\n" + + " If selected arrow icon is disabled along with \"Submenu\" menuitem\n" + + "and in 3rd menuitem\n" + + "If checkmark icon is disabled along with \"Submenu\" CheckBox menuitem\n" + + "then press Pass \n" + + "otherwise if arrow or checkmark icon is not disabled, press Fail."; + + public static void main(String args[]) throws Exception{ + countDownLatch = new CountDownLatch(1); + + SwingUtilities.invokeAndWait(JMenuItemDisableArrowButtonTest::createUI); + countDownLatch.await(5, TimeUnit.MINUTES); + + if (!testResult) { + throw new RuntimeException( + "Disabled JMenuItem arrow or checkmark icon is not disabled!"); + } + } + + private static void createUI() { + try { + UIManager.setLookAndFeel("com.apple.laf.AquaLookAndFeel"); + } catch (Exception e) { + throw new RuntimeException("Cannot initialize Aqua L&F"); + } + + JFrame mainFrame = new JFrame(); + GridBagLayout layout = new GridBagLayout(); + JPanel mainControlPanel = new JPanel(layout); + JPanel resultButtonPanel = new JPanel(layout); + + GridBagConstraints gbc = new GridBagConstraints(); + + gbc.gridx = 0; + gbc.gridy = 0; + gbc.insets = new Insets(5, 15, 5, 15); + gbc.fill = GridBagConstraints.HORIZONTAL; + mainControlPanel.add(createComponent(), gbc); + + JTextArea instructionTextArea = new JTextArea(); + instructionTextArea.setText(INSTRUCTIONS); + instructionTextArea.setEditable(false); + instructionTextArea.setBackground(Color.white); + + gbc.gridx = 0; + gbc.gridy = 1; + gbc.fill = GridBagConstraints.HORIZONTAL; + mainControlPanel.add(instructionTextArea, gbc); + + JButton passButton = new JButton("Pass"); + passButton.setActionCommand("Pass"); + passButton.addActionListener((ActionEvent e) -> { + testResult = true; + mainFrame.dispose(); + countDownLatch.countDown(); + + }); + + JButton failButton = new JButton("Fail"); + failButton.setActionCommand("Fail"); + failButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + mainFrame.dispose(); + countDownLatch.countDown(); + } + }); + + gbc.gridx = 0; + gbc.gridy = 0; + + resultButtonPanel.add(passButton, gbc); + gbc.gridx = 1; + gbc.gridy = 0; + resultButtonPanel.add(failButton, gbc); + + gbc.gridx = 0; + gbc.gridy = 2; + mainControlPanel.add(resultButtonPanel, gbc); + + mainFrame.add(mainControlPanel); + mainFrame.pack(); + + mainFrame.addWindowListener(new WindowAdapter() { + + @Override + public void windowClosing(WindowEvent e) { + mainFrame.dispose(); + countDownLatch.countDown(); + } + }); + mainFrame.setLocationRelativeTo(null); + mainFrame.setVisible(true); + } + + private static JComponent createComponent() { + final JMenuBar menuBar = new JMenuBar(); + JMenu subMenuTestmenu = new JMenu("SubMenuTest"); + JMenu disabledSubmenu = new JMenu("Submenu"); + disabledSubmenu.setEnabled(false); + + JMenu disabledSubmenu1 = new JMenu("Submenu"); + disabledSubmenu1.setSelected(true); + disabledSubmenu1.setEnabled(false); + subMenuTestmenu.add(disabledSubmenu); + subMenuTestmenu.add(disabledSubmenu1); + + JCheckBoxMenuItem myItem = new JCheckBoxMenuItem("Submenu"); + myItem.setSelected(true); + myItem.setEnabled(false); + subMenuTestmenu.add(myItem); + + menuBar.add(subMenuTestmenu); + return menuBar; + } +} + -- GitLab From 6726c592ed01b112f5eb85d8f1e4406b25c8df2b Mon Sep 17 00:00:00 2001 From: Andrey Turbanov Date: Mon, 4 Oct 2021 10:27:20 +0000 Subject: [PATCH 071/385] 8274634: Use String.equals instead of String.compareTo in java.desktop Reviewed-by: serb, pbansal --- .../classes/sun/lwawt/macosx/CAccessible.java | 18 +++++++++--------- .../share/classes/javax/swing/JList.java | 4 ++-- .../share/classes/javax/swing/JTable.java | 8 ++++---- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessible.java b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessible.java index 72bfa8d541e..3a66e456956 100644 --- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessible.java +++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessible.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -115,19 +115,19 @@ class CAccessible extends CFRetainedResource implements Accessible { if ( ptr != 0 ) { Object newValue = e.getNewValue(); Object oldValue = e.getOldValue(); - if (name.compareTo(ACCESSIBLE_CARET_PROPERTY) == 0) { + if (name.equals(ACCESSIBLE_CARET_PROPERTY)) { selectedTextChanged(ptr); - } else if (name.compareTo(ACCESSIBLE_TEXT_PROPERTY) == 0) { + } else if (name.equals(ACCESSIBLE_TEXT_PROPERTY)) { valueChanged(ptr); - } else if (name.compareTo(ACCESSIBLE_SELECTION_PROPERTY) == 0) { + } else if (name.equals(ACCESSIBLE_SELECTION_PROPERTY)) { selectionChanged(ptr); - } else if (name.compareTo(ACCESSIBLE_TABLE_MODEL_CHANGED) == 0) { + } else if (name.equals(ACCESSIBLE_TABLE_MODEL_CHANGED)) { valueChanged(ptr); - } else if (name.compareTo(ACCESSIBLE_ACTIVE_DESCENDANT_PROPERTY) == 0 ) { + } else if (name.equals(ACCESSIBLE_ACTIVE_DESCENDANT_PROPERTY)) { if (newValue instanceof AccessibleContext) { activeDescendant = (AccessibleContext)newValue; } - } else if (name.compareTo(ACCESSIBLE_STATE_PROPERTY) == 0) { + } else if (name.equals(ACCESSIBLE_STATE_PROPERTY)) { AccessibleContext thisAC = accessible.getAccessibleContext(); AccessibleRole thisRole = thisAC.getAccessibleRole(); Accessible parentAccessible = thisAC.getAccessibleParent(); @@ -167,12 +167,12 @@ class CAccessible extends CFRetainedResource implements Accessible { if (thisRole == AccessibleRole.CHECK_BOX) { valueChanged(ptr); } - } else if (name.compareTo(ACCESSIBLE_NAME_PROPERTY) == 0) { + } else if (name.equals(ACCESSIBLE_NAME_PROPERTY)) { //for now trigger only for JTabbedPane. if (e.getSource() instanceof JTabbedPane) { titleChanged(ptr); } - } else if (name.compareTo(ACCESSIBLE_VALUE_PROPERTY) == 0) { + } else if (name.equals(ACCESSIBLE_VALUE_PROPERTY)) { AccessibleRole thisRole = accessible.getAccessibleContext() .getAccessibleRole(); if (thisRole == AccessibleRole.SLIDER || diff --git a/src/java.desktop/share/classes/javax/swing/JList.java b/src/java.desktop/share/classes/javax/swing/JList.java index 83b6cbed553..7932209974b 100644 --- a/src/java.desktop/share/classes/javax/swing/JList.java +++ b/src/java.desktop/share/classes/javax/swing/JList.java @@ -2947,7 +2947,7 @@ public class JList extends JComponent implements Scrollable, Accessible Object newValue = e.getNewValue(); // re-set listData listeners - if (name.compareTo("model") == 0) { + if (name.equals("model")) { if (oldValue != null && oldValue instanceof ListModel) { ((ListModel) oldValue).removeListDataListener(this); @@ -2957,7 +2957,7 @@ public class JList extends JComponent implements Scrollable, Accessible } // re-set listSelectionModel listeners - } else if (name.compareTo("selectionModel") == 0) { + } else if (name.equals("selectionModel")) { if (oldValue != null && oldValue instanceof ListSelectionModel) { ((ListSelectionModel) oldValue).removeListSelectionListener(this); diff --git a/src/java.desktop/share/classes/javax/swing/JTable.java b/src/java.desktop/share/classes/javax/swing/JTable.java index b4d3037e572..4b3e02f860f 100644 --- a/src/java.desktop/share/classes/javax/swing/JTable.java +++ b/src/java.desktop/share/classes/javax/swing/JTable.java @@ -6756,7 +6756,7 @@ public class JTable extends JComponent implements TableModelListener, Scrollable Object newValue = e.getNewValue(); // re-set tableModel listeners - if (name.compareTo("model") == 0) { + if (name.equals("model")) { if (oldValue != null && oldValue instanceof TableModel) { ((TableModel) oldValue).removeTableModelListener(this); @@ -6766,7 +6766,7 @@ public class JTable extends JComponent implements TableModelListener, Scrollable } // re-set selectionModel listeners - } else if (name.compareTo("selectionModel") == 0) { + } else if (name.equals("selectionModel")) { Object source = e.getSource(); if (source == JTable.this) { // row selection model @@ -6797,7 +6797,7 @@ public class JTable extends JComponent implements TableModelListener, Scrollable // re-set columnModel listeners // and column's selection property listener as well - } else if (name.compareTo("columnModel") == 0) { + } else if (name.equals("columnModel")) { if (oldValue != null && oldValue instanceof TableColumnModel) { TableColumnModel tcm = (TableColumnModel) oldValue; @@ -6811,7 +6811,7 @@ public class JTable extends JComponent implements TableModelListener, Scrollable } // re-se cellEditor listeners - } else if (name.compareTo("tableCellEditor") == 0) { + } else if (name.equals("tableCellEditor")) { if (oldValue != null && oldValue instanceof TableCellEditor) { ((TableCellEditor) oldValue).removeCellEditorListener(this); -- GitLab From 0828273b898cca5368344e75f1c3f4c3a29dde80 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Mon, 4 Oct 2021 12:22:55 +0000 Subject: [PATCH 072/385] 8274521: jdk/jfr/event/gc/detailed/TestGCLockerEvent.java fails when other GC is selected Reviewed-by: kbarrett, tschatzl --- test/jdk/jdk/jfr/event/gc/detailed/TestGCLockerEvent.java | 1 + 1 file changed, 1 insertion(+) diff --git a/test/jdk/jdk/jfr/event/gc/detailed/TestGCLockerEvent.java b/test/jdk/jdk/jfr/event/gc/detailed/TestGCLockerEvent.java index c79fa7fbb31..2f5c21b7a9b 100644 --- a/test/jdk/jdk/jfr/event/gc/detailed/TestGCLockerEvent.java +++ b/test/jdk/jdk/jfr/event/gc/detailed/TestGCLockerEvent.java @@ -26,6 +26,7 @@ * @test TestGCLockerEvent * @key jfr * @requires vm.hasJFR + * @requires vm.gc.G1 * @library /test/lib * @build sun.hotspot.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox -- GitLab From 47bfc8aa9367ff852ea5d901f1fa3c6ef316913e Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Mon, 4 Oct 2021 12:35:58 +0000 Subject: [PATCH 073/385] 8274563: jfr/event/oldobject/TestClassLoaderLeak.java fails when GC cycles are not happening Reviewed-by: egahlin --- test/jdk/jdk/jfr/event/oldobject/TestClassLoaderLeak.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/jdk/jdk/jfr/event/oldobject/TestClassLoaderLeak.java b/test/jdk/jdk/jfr/event/oldobject/TestClassLoaderLeak.java index d43275c645c..0101cffc9bc 100644 --- a/test/jdk/jdk/jfr/event/oldobject/TestClassLoaderLeak.java +++ b/test/jdk/jdk/jfr/event/oldobject/TestClassLoaderLeak.java @@ -40,10 +40,9 @@ import jdk.test.lib.jfr.Events; * @test * @key jfr * @requires vm.hasJFR - * @requires vm.gc != "Serial" * @library /test/lib /test/jdk * @modules jdk.jfr/jdk.jfr.internal.test - * @run main/othervm -XX:TLABSize=2k jdk.jfr.event.oldobject.TestClassLoaderLeak + * @run main/othervm -XX:TLABSize=2k -Xmx128m jdk.jfr.event.oldobject.TestClassLoaderLeak */ public class TestClassLoaderLeak { -- GitLab From 7eb0372e55f23275b12470593adc97f1b79bc965 Mon Sep 17 00:00:00 2001 From: Alex Kasko Date: Mon, 4 Oct 2021 12:38:34 +0000 Subject: [PATCH 074/385] 8274606: Fix jaxp/javax/xml/jaxp/unittest/transform/SurrogateTest.java test Reviewed-by: joehw, shade --- .../jaxp/unittest/transform/SurrogateTest.java | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/test/jaxp/javax/xml/jaxp/unittest/transform/SurrogateTest.java b/test/jaxp/javax/xml/jaxp/unittest/transform/SurrogateTest.java index 9eb358fef71..2c740471eed 100644 --- a/test/jaxp/javax/xml/jaxp/unittest/transform/SurrogateTest.java +++ b/test/jaxp/javax/xml/jaxp/unittest/transform/SurrogateTest.java @@ -26,8 +26,9 @@ package transform; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; -import java.io.FileReader; import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; @@ -43,7 +44,7 @@ import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; import static jaxp.library.JAXPTestUtilities.compareWithGold; -import static jaxp.library.JAXPTestUtilities.compareStringWithGold; +import static jaxp.library.JAXPTestUtilities.compareLinesWithGold; import org.testng.Assert; import org.testng.annotations.Listeners; import org.testng.annotations.Test; @@ -64,10 +65,11 @@ public class SurrogateTest { public void toHTMLTest() throws Exception { String out = "SurrogateTest1out.html"; String expected = TEST_SRC + File.separator + "SurrogateTest1.html"; + String xml = TEST_SRC + File.separator + "SurrogateTest1.xml"; String xsl = TEST_SRC + File.separator + "SurrogateTest1.xsl"; try (FileInputStream tFis = new FileInputStream(xsl); - InputStream fis = this.getClass().getResourceAsStream("SurrogateTest1.xml"); + InputStream fis = new FileInputStream(xml); FileOutputStream fos = new FileOutputStream(out)) { Source tSrc = new StreamSource(tFis); @@ -79,7 +81,7 @@ public class SurrogateTest { Result res = new StreamResult(fos); t.transform(src, res); } - compareWithGold(expected, out); + Assert.assertTrue(compareWithGold(expected, out)); } @Test @@ -90,15 +92,15 @@ public class SurrogateTest { SAXParser sp = spf.newSAXParser(); TestHandler th = new TestHandler(); sp.parse(xmlFile, th); - compareStringWithGold(TEST_SRC + File.separator + "SurrogateTest2.txt", th.sb.toString()); + Assert.assertTrue(compareLinesWithGold(TEST_SRC + File.separator + "SurrogateTest2.txt", th.lines)); } private static class TestHandler extends DefaultHandler { - private StringBuilder sb = new StringBuilder(); + private List lines = new ArrayList<>(); @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { - sb.append( localName + "@attr:" + attributes.getValue("attr") + '\n'); + lines.add( localName + "@attr:" + attributes.getValue("attr")); } } } -- GitLab From f2404d60de2b58c590bf885f5cce50c289073673 Mon Sep 17 00:00:00 2001 From: Naoto Sato Date: Mon, 4 Oct 2021 15:06:48 +0000 Subject: [PATCH 075/385] 8274658: ISO 4217 Amendment 170 Update Reviewed-by: lancea, iris --- make/data/currency/CurrencyData.properties | 4 ++-- .../classes/sun/util/resources/CurrencyNames.properties | 4 +++- test/jdk/java/util/Currency/ValidateISO4217.java | 6 +++--- test/jdk/java/util/Currency/tablea1.txt | 6 +++--- test/jdk/sun/text/resources/LocaleData | 3 ++- test/jdk/sun/text/resources/LocaleDataTest.java | 4 ++-- 6 files changed, 15 insertions(+), 12 deletions(-) diff --git a/make/data/currency/CurrencyData.properties b/make/data/currency/CurrencyData.properties index 1a92ef5b867..236e544feaf 100644 --- a/make/data/currency/CurrencyData.properties +++ b/make/data/currency/CurrencyData.properties @@ -32,7 +32,7 @@ formatVersion=3 # Version of the currency code information in this class. # It is a serial number that accompanies with each amendment. -dataVersion=169 +dataVersion=170 # List of all valid ISO 4217 currency codes. # To ensure compatibility, do not remove codes. @@ -54,7 +54,7 @@ all=ADP020-AED784-AFA004-AFN971-ALL008-AMD051-ANG532-AOA973-ARS032-ATS040-AUD036 SBD090-SCR690-SDD736-SDG938-SEK752-SGD702-SHP654-SIT705-SKK703-SLL694-SOS706-\ SRD968-SRG740-SSP728-STD678-STN930-SVC222-SYP760-SZL748-THB764-TJS972-TMM795-TMT934-TND788-TOP776-\ TPE626-TRL792-TRY949-TTD780-TWD901-TZS834-UAH980-UGX800-USD840-USN997-USS998-UYI940-\ - UYU858-UZS860-VEB862-VEF937-VES928-VND704-VUV548-WST882-XAF950-XAG961-XAU959-XBA955-\ + UYU858-UZS860-VEB862-VED926-VEF937-VES928-VND704-VUV548-WST882-XAF950-XAG961-XAU959-XBA955-\ XBB956-XBC957-XBD958-XCD951-XDR960-XFO000-XFU000-XOF952-XPD964-XPF953-\ XPT962-XSU994-XTS963-XUA965-XXX999-YER886-YUM891-ZAR710-ZMK894-ZMW967-ZWD716-ZWL932-\ ZWN942-ZWR935 diff --git a/src/java.base/share/classes/sun/util/resources/CurrencyNames.properties b/src/java.base/share/classes/sun/util/resources/CurrencyNames.properties index 238186bf219..9f1867d2cd1 100644 --- a/src/java.base/share/classes/sun/util/resources/CurrencyNames.properties +++ b/src/java.base/share/classes/sun/util/resources/CurrencyNames.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -251,6 +251,7 @@ USS=USS UYU=UYU UZS=UZS VEB=VEB +VED=VED VEF=VEF VES=VES VND=VND @@ -474,6 +475,7 @@ uss=US Dollar (Same day) uyu=Uruguayan Peso uzs=Uzbekistan Som veb=Venezuelan Bol\u00edvar (1871-2008) +ved=Venezuelan Bol\u00edvar Soberano vef=Venezuelan Bol\u00edvar ves=Venezuelan Bol\u00edvar Soberano vnd=Vietnamese Dong diff --git a/test/jdk/java/util/Currency/ValidateISO4217.java b/test/jdk/java/util/Currency/ValidateISO4217.java index 1ef635e7cab..40bb55cfd1f 100644 --- a/test/jdk/java/util/Currency/ValidateISO4217.java +++ b/test/jdk/java/util/Currency/ValidateISO4217.java @@ -24,7 +24,7 @@ * @test * @bug 4691089 4819436 4942982 5104960 6544471 6627549 7066203 7195759 * 8039317 8074350 8074351 8145952 8187946 8193552 8202026 8204269 - * 8208746 8209775 8264792 + * 8208746 8209775 8264792 8274658 * @summary Validate ISO 4217 data for Currency class. * @modules java.base/java.util:open * jdk.localedata @@ -97,11 +97,11 @@ public class ValidateISO4217 { {"XK", "EUR", "978", "2"}, // Kosovo }; - /* Codes that are obsolete, do not have related country */ + /* Codes that are obsolete, do not have related country, extra currency */ static final String otherCodes = "ADP-AFA-ATS-AYM-AZM-BEF-BGL-BOV-BYB-BYR-CHE-CHW-CLF-COU-CUC-CYP-" + "DEM-EEK-ESP-FIM-FRF-GHC-GRD-GWP-IEP-ITL-LTL-LUF-LVL-MGF-MRO-MTL-MXV-MZM-NLG-" - + "PTE-ROL-RUR-SDD-SIT-SKK-SRG-STD-TMM-TPE-TRL-VEF-UYI-USN-USS-VEB-" + + "PTE-ROL-RUR-SDD-SIT-SKK-SRG-STD-TMM-TPE-TRL-VEF-UYI-USN-USS-VEB-VED-" + "XAG-XAU-XBA-XBB-XBC-XBD-XDR-XFO-XFU-XPD-XPT-XSU-XTS-XUA-XXX-" + "YUM-ZMK-ZWD-ZWN-ZWR"; diff --git a/test/jdk/java/util/Currency/tablea1.txt b/test/jdk/java/util/Currency/tablea1.txt index c38e6f8dd86..7716863419f 100644 --- a/test/jdk/java/util/Currency/tablea1.txt +++ b/test/jdk/java/util/Currency/tablea1.txt @@ -1,12 +1,12 @@ # # -# Amendments up until ISO 4217 AMENDMENT NUMBER 169 -# (As of 27 Aug 2018) +# Amendments up until ISO 4217 AMENDMENT NUMBER 170 +# (As of 1 Oct 2021) # # Version FILEVERSION=3 -DATAVERSION=169 +DATAVERSION=170 # ISO 4217 currency data AF AFN 971 2 diff --git a/test/jdk/sun/text/resources/LocaleData b/test/jdk/sun/text/resources/LocaleData index bf81b210a71..ba176097825 100644 --- a/test/jdk/sun/text/resources/LocaleData +++ b/test/jdk/sun/text/resources/LocaleData @@ -8319,7 +8319,8 @@ CurrencyNames//azn=Azerbaijan Manat # bug #8193552 CurrencyNames//mru=Mauritanian Ouguiya -# bug #8208746 +# bug #8208746, #8274658 +CurrencyNames//ved=Venezuelan Bol\u00edvar Soberano CurrencyNames//ves=Venezuelan Bol\u00edvar Soberano # bug #8206879 diff --git a/test/jdk/sun/text/resources/LocaleDataTest.java b/test/jdk/sun/text/resources/LocaleDataTest.java index 9ab1d66f41b..1d2ddd03a82 100644 --- a/test/jdk/sun/text/resources/LocaleDataTest.java +++ b/test/jdk/sun/text/resources/LocaleDataTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,7 +40,7 @@ * 8145136 8145952 8164784 8037111 8081643 7037368 8178872 8185841 8190918 * 8187946 8195478 8181157 8179071 8193552 8202026 8204269 8202537 8208746 * 8209775 8221432 8227127 8230284 8231273 8233579 8234288 8250665 8255086 - * 8251317 + * 8251317 8274658 * @summary Verify locale data * @modules java.base/sun.util.resources * @modules jdk.localedata -- GitLab From f63c4a832a1aea451f47aaf86d5361e970c6a28f Mon Sep 17 00:00:00 2001 From: Weijun Wang Date: Mon, 4 Oct 2021 15:30:44 +0000 Subject: [PATCH 076/385] 8274471: Verification of OCSP Response signed with RSASSA-PSS fails Reviewed-by: hchao, jnimeh --- .../sun/security/provider/certpath/OCSP.java | 18 ++++---- .../provider/certpath/OCSPResponse.java | 9 ++-- .../sun/security/util/SignatureUtil.java | 28 +++++-------- .../sun/security/x509/AlgorithmId.java | 2 +- .../sun/security/x509/X509CRLImpl.java | 10 +---- .../sun/security/x509/X509CertImpl.java | 8 +--- .../testlibrary/CertificateBuilder.java | 42 +++++++------------ .../testlibrary/SimpleOCSPServer.java | 14 +++---- .../net/ssl/Stapling/HttpsUrlConnClient.java | 20 +++++---- 9 files changed, 65 insertions(+), 86 deletions(-) diff --git a/src/java.base/share/classes/sun/security/provider/certpath/OCSP.java b/src/java.base/share/classes/sun/security/provider/certpath/OCSP.java index 2b07e69dcfd..65788b16490 100644 --- a/src/java.base/share/classes/sun/security/provider/certpath/OCSP.java +++ b/src/java.base/share/classes/sun/security/provider/certpath/OCSP.java @@ -35,7 +35,6 @@ import java.security.cert.CertPathValidatorException; import java.security.cert.CertPathValidatorException.BasicReason; import java.security.cert.CRLReason; import java.security.cert.Extension; -import java.security.cert.TrustAnchor; import java.security.cert.X509Certificate; import java.util.Base64; import java.util.Date; @@ -46,7 +45,6 @@ import sun.security.action.GetIntegerAction; import sun.security.util.Debug; import sun.security.util.Event; import sun.security.util.IOUtils; -import sun.security.validator.Validator; import sun.security.x509.AccessDescription; import sun.security.x509.AuthorityInfoAccessExtension; import sun.security.x509.GeneralName; @@ -166,22 +164,26 @@ public final class OCSP { List extensions) throws IOException { OCSPRequest request = new OCSPRequest(certIds, extensions); byte[] bytes = request.encodeBytes(); + String responder = responderURI.toString(); if (debug != null) { - debug.println("connecting to OCSP service at: " + responderURI); + debug.println("connecting to OCSP service at: " + responder); } Event.report(Event.ReporterCategory.CRLCHECK, "event.ocsp.check", - responderURI.toString()); + responder); URL url; HttpURLConnection con = null; try { - String encodedGetReq = responderURI.toString() + "/" + - URLEncoder.encode(Base64.getEncoder().encodeToString(bytes), - UTF_8); + StringBuilder encodedGetReq = new StringBuilder(responder); + if (!responder.endsWith("/")) { + encodedGetReq.append("/"); + } + encodedGetReq.append(URLEncoder.encode( + Base64.getEncoder().encodeToString(bytes), UTF_8)); if (encodedGetReq.length() <= 255) { - url = new URL(encodedGetReq); + url = new URL(encodedGetReq.toString()); con = (HttpURLConnection)url.openConnection(); con.setDoOutput(true); con.setDoInput(true); diff --git a/src/java.base/share/classes/sun/security/provider/certpath/OCSPResponse.java b/src/java.base/share/classes/sun/security/provider/certpath/OCSPResponse.java index c1336719139..e6b9c2b4992 100644 --- a/src/java.base/share/classes/sun/security/provider/certpath/OCSPResponse.java +++ b/src/java.base/share/classes/sun/security/provider/certpath/OCSPResponse.java @@ -638,7 +638,10 @@ public final class OCSPResponse { try { Signature respSignature = Signature.getInstance(sigAlgId.getName()); - respSignature.initVerify(cert.getPublicKey()); + SignatureUtil.initVerifyWithParam(respSignature, + cert.getPublicKey(), + SignatureUtil.getParamSpec(sigAlgId.getName(), + sigAlgId.getEncodedParams())); respSignature.update(tbsResponseData); if (respSignature.verify(signature)) { @@ -654,8 +657,8 @@ public final class OCSPResponse { } return false; } - } catch (InvalidKeyException | NoSuchAlgorithmException | - SignatureException e) + } catch (InvalidAlgorithmParameterException | InvalidKeyException + | NoSuchAlgorithmException | SignatureException e) { throw new CertPathValidatorException(e); } diff --git a/src/java.base/share/classes/sun/security/util/SignatureUtil.java b/src/java.base/share/classes/sun/security/util/SignatureUtil.java index f65dff6d314..6ad35d12386 100644 --- a/src/java.base/share/classes/sun/security/util/SignatureUtil.java +++ b/src/java.base/share/classes/sun/security/util/SignatureUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -170,8 +170,7 @@ public class SignatureUtil { // for verification with the specified key and params (may be null) public static void initVerifyWithParam(Signature s, PublicKey key, AlgorithmParameterSpec params) - throws ProviderException, InvalidAlgorithmParameterException, - InvalidKeyException { + throws InvalidAlgorithmParameterException, InvalidKeyException { SharedSecrets.getJavaSecuritySignatureAccess().initVerify(s, key, params); } @@ -180,8 +179,7 @@ public class SignatureUtil { public static void initVerifyWithParam(Signature s, java.security.cert.Certificate cert, AlgorithmParameterSpec params) - throws ProviderException, InvalidAlgorithmParameterException, - InvalidKeyException { + throws InvalidAlgorithmParameterException, InvalidKeyException { SharedSecrets.getJavaSecuritySignatureAccess().initVerify(s, cert, params); } @@ -189,8 +187,7 @@ public class SignatureUtil { // for signing with the specified key and params (may be null) public static void initSignWithParam(Signature s, PrivateKey key, AlgorithmParameterSpec params, SecureRandom sr) - throws ProviderException, InvalidAlgorithmParameterException, - InvalidKeyException { + throws InvalidAlgorithmParameterException, InvalidKeyException { SharedSecrets.getJavaSecuritySignatureAccess().initSign(s, key, params, sr); } @@ -342,10 +339,10 @@ public class SignatureUtil { * Create a Signature that has been initialized with proper key and params. * * @param sigAlg signature algorithms - * @param key public or private key + * @param key private key * @param provider (optional) provider */ - public static Signature fromKey(String sigAlg, Key key, String provider) + public static Signature fromKey(String sigAlg, PrivateKey key, String provider) throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeyException{ Signature sigEngine = (provider == null || provider.isEmpty()) @@ -358,10 +355,10 @@ public class SignatureUtil { * Create a Signature that has been initialized with proper key and params. * * @param sigAlg signature algorithms - * @param key public or private key + * @param key private key * @param provider (optional) provider */ - public static Signature fromKey(String sigAlg, Key key, Provider provider) + public static Signature fromKey(String sigAlg, PrivateKey key, Provider provider) throws NoSuchAlgorithmException, InvalidKeyException{ Signature sigEngine = (provider == null) ? Signature.getInstance(sigAlg) @@ -369,17 +366,12 @@ public class SignatureUtil { return autoInitInternal(sigAlg, key, sigEngine); } - private static Signature autoInitInternal(String alg, Key key, Signature s) + private static Signature autoInitInternal(String alg, PrivateKey key, Signature s) throws InvalidKeyException { AlgorithmParameterSpec params = SignatureUtil .getDefaultParamSpec(alg, key); try { - if (key instanceof PrivateKey) { - SignatureUtil.initSignWithParam(s, (PrivateKey) key, params, - null); - } else { - SignatureUtil.initVerifyWithParam(s, (PublicKey) key, params); - } + SignatureUtil.initSignWithParam(s, key, params, null); } catch (InvalidAlgorithmParameterException e) { throw new AssertionError("Should not happen", e); } diff --git a/src/java.base/share/classes/sun/security/x509/AlgorithmId.java b/src/java.base/share/classes/sun/security/x509/AlgorithmId.java index 0ce9effddf2..627fb503ba9 100644 --- a/src/java.base/share/classes/sun/security/x509/AlgorithmId.java +++ b/src/java.base/share/classes/sun/security/x509/AlgorithmId.java @@ -312,7 +312,7 @@ public class AlgorithmId implements Serializable, DerEncoder { * * @return DER encoded parameters, or null not present. */ - public byte[] getEncodedParams() throws IOException { + public byte[] getEncodedParams() { return (encodedParams == null || algid.toString().equals(KnownOIDs.SpecifiedSHA2withECDSA.value())) ? null diff --git a/src/java.base/share/classes/sun/security/x509/X509CRLImpl.java b/src/java.base/share/classes/sun/security/x509/X509CRLImpl.java index 124231e961a..1523cde227d 100644 --- a/src/java.base/share/classes/sun/security/x509/X509CRLImpl.java +++ b/src/java.base/share/classes/sun/security/x509/X509CRLImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -820,13 +820,7 @@ public class X509CRLImpl extends X509CRL implements DerEncoder { * null if no parameters are present. */ public byte[] getSigAlgParams() { - if (sigAlgId == null) - return null; - try { - return sigAlgId.getEncodedParams(); - } catch (IOException e) { - return null; - } + return sigAlgId == null ? null : sigAlgId.getEncodedParams(); } /** diff --git a/src/java.base/share/classes/sun/security/x509/X509CertImpl.java b/src/java.base/share/classes/sun/security/x509/X509CertImpl.java index b22091f1e62..b658a94b8d6 100644 --- a/src/java.base/share/classes/sun/security/x509/X509CertImpl.java +++ b/src/java.base/share/classes/sun/security/x509/X509CertImpl.java @@ -1030,13 +1030,7 @@ public class X509CertImpl extends X509Certificate implements DerEncoder { * null if no parameters are present. */ public byte[] getSigAlgParams() { - if (algId == null) - return null; - try { - return algId.getEncodedParams(); - } catch (IOException e) { - return null; - } + return algId == null ? null : algId.getEncodedParams(); } /** diff --git a/test/jdk/java/security/testlibrary/CertificateBuilder.java b/test/jdk/java/security/testlibrary/CertificateBuilder.java index b2c39b8ab5b..5a91592a0fc 100644 --- a/test/jdk/java/security/testlibrary/CertificateBuilder.java +++ b/test/jdk/java/security/testlibrary/CertificateBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,6 +38,7 @@ import java.math.BigInteger; import sun.security.util.DerOutputStream; import sun.security.util.DerValue; import sun.security.util.ObjectIdentifier; +import sun.security.util.SignatureUtil; import sun.security.x509.AccessDescription; import sun.security.x509.AlgorithmId; import sun.security.x509.AuthorityInfoAccessExtension; @@ -364,8 +365,7 @@ public class CertificateBuilder { throws IOException, CertificateException, NoSuchAlgorithmException { // TODO: add some basic checks (key usage, basic constraints maybe) - AlgorithmId signAlg = AlgorithmId.get(algName); - byte[] encodedCert = encodeTopLevel(issuerCert, issuerKey, signAlg); + byte[] encodedCert = encodeTopLevel(issuerCert, issuerKey, algName); ByteArrayInputStream bais = new ByteArrayInputStream(encodedCert); return (X509Certificate)factory.generateCertificate(bais); } @@ -392,18 +392,24 @@ public class CertificateBuilder { * @throws IOException if an encoding error occurs. */ private byte[] encodeTopLevel(X509Certificate issuerCert, - PrivateKey issuerKey, AlgorithmId signAlg) - throws CertificateException, IOException { + PrivateKey issuerKey, String algName) + throws CertificateException, IOException, NoSuchAlgorithmException { + + AlgorithmId signAlg = AlgorithmId.get(algName); DerOutputStream outerSeq = new DerOutputStream(); DerOutputStream topLevelItems = new DerOutputStream(); - tbsCertBytes = encodeTbsCert(issuerCert, signAlg); - topLevelItems.write(tbsCertBytes); try { - signatureBytes = signCert(issuerKey, signAlg); + Signature sig = SignatureUtil.fromKey(signAlg.getName(), issuerKey, (Provider)null); + // Rewrite signAlg, RSASSA-PSS needs some parameters. + signAlg = SignatureUtil.fromSignature(sig, issuerKey); + tbsCertBytes = encodeTbsCert(issuerCert, signAlg); + sig.update(tbsCertBytes); + signatureBytes = sig.sign(); } catch (GeneralSecurityException ge) { throw new CertificateException(ge); } + topLevelItems.write(tbsCertBytes); signAlg.derEncode(topLevelItems); topLevelItems.putBitString(signatureBytes); outerSeq.write(DerValue.tag_Sequence, topLevelItems); @@ -518,22 +524,4 @@ public class CertificateBuilder { (byte)3), extSequence); } - /** - * Digitally sign the X.509 certificate. - * - * @param issuerKey The private key of the issuing authority - * @param signAlg The signature algorithm object - * - * @return The digital signature bytes. - * - * @throws GeneralSecurityException If any errors occur during the - * digital signature process. - */ - private byte[] signCert(PrivateKey issuerKey, AlgorithmId signAlg) - throws GeneralSecurityException { - Signature sig = Signature.getInstance(signAlg.getName()); - sig.initSign(issuerKey); - sig.update(tbsCertBytes); - return sig.sign(); - } - } +} diff --git a/test/jdk/java/security/testlibrary/SimpleOCSPServer.java b/test/jdk/java/security/testlibrary/SimpleOCSPServer.java index 6f6c58089a3..6326570fc17 100644 --- a/test/jdk/java/security/testlibrary/SimpleOCSPServer.java +++ b/test/jdk/java/security/testlibrary/SimpleOCSPServer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -174,8 +174,7 @@ public class SimpleOCSPServer { issuerAlias + " not found"); } } - - sigAlgId = AlgorithmId.get("Sha256withRSA"); + sigAlgId = AlgorithmId.get(SignatureUtil.getDefaultSigAlgForKey(signerKey)); respId = new ResponderId(signerCert.getSubjectX500Principal()); listenAddress = addr; listenPort = port; @@ -1348,13 +1347,14 @@ public class SimpleOCSPServer { basicORItemStream.write(tbsResponseBytes); try { - sigAlgId.derEncode(basicORItemStream); - // Create the signature - Signature sig = Signature.getInstance(sigAlgId.getName()); - sig.initSign(signerKey); + Signature sig = SignatureUtil.fromKey( + sigAlgId.getName(), signerKey, (Provider)null); sig.update(tbsResponseBytes); signature = sig.sign(); + // Rewrite signAlg, RSASSA-PSS needs some parameters. + sigAlgId = SignatureUtil.fromSignature(sig, signerKey); + sigAlgId.derEncode(basicORItemStream); basicORItemStream.putBitString(signature); } catch (GeneralSecurityException exc) { err(exc); diff --git a/test/jdk/javax/net/ssl/Stapling/HttpsUrlConnClient.java b/test/jdk/javax/net/ssl/Stapling/HttpsUrlConnClient.java index 646182ec41d..8fedde9b985 100644 --- a/test/jdk/javax/net/ssl/Stapling/HttpsUrlConnClient.java +++ b/test/jdk/javax/net/ssl/Stapling/HttpsUrlConnClient.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,8 @@ * @summary OCSP Stapling for TLS * @library ../../../../java/security/testlibrary * @build CertificateBuilder SimpleOCSPServer - * @run main/othervm HttpsUrlConnClient + * @run main/othervm HttpsUrlConnClient RSA SHA256withRSA + * @run main/othervm HttpsUrlConnClient RSASSA-PSS RSASSA-PSS */ import java.io.*; @@ -60,7 +61,6 @@ import java.util.concurrent.TimeUnit; import sun.security.testlibrary.SimpleOCSPServer; import sun.security.testlibrary.CertificateBuilder; -import sun.security.validator.ValidatorException; public class HttpsUrlConnClient { @@ -73,6 +73,9 @@ public class HttpsUrlConnClient { static final byte[] LINESEP = { 10 }; static final Base64.Encoder B64E = Base64.getMimeEncoder(64, LINESEP); + static String SIGALG; + static String KEYALG; + // Turn on TLS debugging static boolean debug = true; @@ -137,6 +140,9 @@ public class HttpsUrlConnClient { System.setProperty("javax.net.ssl.trustStore", ""); System.setProperty("javax.net.ssl.trustStorePassword", ""); + KEYALG = args[0]; + SIGALG = args[1]; + // Create the PKI we will use for the test and start the OCSP servers createPKI(); utcDateFmt.setTimeZone(TimeZone.getTimeZone("GMT")); @@ -514,7 +520,7 @@ public class HttpsUrlConnClient { */ private static void createPKI() throws Exception { CertificateBuilder cbld = new CertificateBuilder(); - KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA"); + KeyPairGenerator keyGen = KeyPairGenerator.getInstance(KEYALG); keyGen.initialize(2048); KeyStore.Builder keyStoreBuilder = KeyStore.Builder.newInstance("PKCS12", null, @@ -540,7 +546,7 @@ public class HttpsUrlConnClient { addCommonCAExts(cbld); // Make our Root CA Cert! X509Certificate rootCert = cbld.build(null, rootCaKP.getPrivate(), - "SHA256withRSA"); + SIGALG); log("Root CA Created:\n" + certInfo(rootCert)); // Now build a keystore and add the keys and cert @@ -582,7 +588,7 @@ public class HttpsUrlConnClient { cbld.addAIAExt(Collections.singletonList(rootRespURI)); // Make our Intermediate CA Cert! X509Certificate intCaCert = cbld.build(rootCert, rootCaKP.getPrivate(), - "SHA256withRSA"); + SIGALG); log("Intermediate CA Created:\n" + certInfo(intCaCert)); // Provide intermediate CA cert revocation info to the Root CA @@ -644,7 +650,7 @@ public class HttpsUrlConnClient { cbld.addAIAExt(Collections.singletonList(intCaRespURI)); // Make our SSL Server Cert! X509Certificate sslCert = cbld.build(intCaCert, intCaKP.getPrivate(), - "SHA256withRSA"); + SIGALG); log("SSL Certificate Created:\n" + certInfo(sslCert)); // Provide SSL server cert revocation info to the Intermeidate CA -- GitLab From 139a8334cbc0c8e1a7a708efe18bd488d28292fd Mon Sep 17 00:00:00 2001 From: Adam Sotona Date: Mon, 4 Oct 2021 15:48:09 +0000 Subject: [PATCH 077/385] 8268869: java in source-file mode suggests javac-only Xlint flags Reviewed-by: jjg --- .../com/sun/tools/javac/launcher/Main.java | 3 +- .../javac/launcher/SourceLauncherTest.java | 34 ++++++++++++++++++- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/launcher/Main.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/launcher/Main.java index 48c1b5a3e3e..428b3a4a51e 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/launcher/Main.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/launcher/Main.java @@ -352,7 +352,8 @@ public class Main { // add implicit options javacOpts.add("-proc:none"); javacOpts.add("-Xdiags:verbose"); - + javacOpts.add("-Xlint:deprecation"); + javacOpts.add("-Xlint:unchecked"); return javacOpts; } diff --git a/test/langtools/tools/javac/launcher/SourceLauncherTest.java b/test/langtools/tools/javac/launcher/SourceLauncherTest.java index 1f622e0fefc..7507a6d9c27 100644 --- a/test/langtools/tools/javac/launcher/SourceLauncherTest.java +++ b/test/langtools/tools/javac/launcher/SourceLauncherTest.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8192920 8204588 8246774 + * @bug 8192920 8204588 8246774 8248843 8268869 * @summary Test source launcher * @library /tools/lib * @modules jdk.compiler/com.sun.tools.javac.api @@ -598,6 +598,38 @@ public class SourceLauncherTest extends TestRunner { "error: compilation failed"); } + @Test + public void testNoRecompileWithSuggestions(Path base) throws IOException { + tb.writeJavaFiles(base, + "class NoRecompile {\n" + + " void use(String s) {}\n" + + " void test() {\n" + + " use(1);\n" + + " }\n" + + " void test(T t, Object o) {\n" + + " T t1 = (T) o;\n" + + " }\n" + + " static class Generic {\n" + + " T t;\n" + + " void raw(Generic raw) {\n" + + " raw.t = \"\";\n" + + " }\n" + + " }\n" + + " void deprecation() {\n" + + " Thread.currentThread().stop();\n" + + " }\n" + + " void preview(Object o) {\n" + + " if (o instanceof String s) {\n" + + " System.out.println(s);\n" + + " }\n" + + " }\n" + + "}"); + Result r = run(base.resolve("NoRecompile.java"), Collections.emptyList(), Collections.emptyList()); + if (r.stdErr.contains("recompile with")) { + error("Unexpected recompile suggestions in error output: " + r.stdErr); + } + } + void testError(Path file, String expectStdErr, String expectFault) throws IOException { Result r = run(file, Collections.emptyList(), List.of("1", "2", "3")); checkEmpty("stdout", r.stdOut); -- GitLab From 6f727d831d8f8fb9b44f4c6bdbdd6ae44316a5d8 Mon Sep 17 00:00:00 2001 From: Jonathan Gibbons Date: Mon, 4 Oct 2021 16:58:23 +0000 Subject: [PATCH 078/385] 8274666: rename HtmlStyle.descfrmTypeLabel to be less cryptic Reviewed-by: hannesw --- .../internal/doclets/formats/html/Contents.java | 8 ++++---- .../doclets/formats/html/MethodWriterImpl.java | 12 ++++++------ .../doclets/formats/html/PropertyWriterImpl.java | 12 ++++++------ .../doclets/formats/html/markup/HtmlStyle.java | 3 +-- .../doclets/toolkit/resources/stylesheet.css | 2 +- .../doclet/testInterface/TestInterface.java | 2 +- .../doclet/testOptions/custom-stylesheet.css | 2 +- .../TestOverriddenMethodDocCopy.java | 2 +- .../testOverriddenMethods/TestOverrideMethods.java | 14 +++++++------- .../testPrivateClasses/TestPrivateClasses.java | 2 +- .../doclet/testReturnTag/TestReturnTag.java | 2 +- 11 files changed, 30 insertions(+), 31 deletions(-) diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Contents.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Contents.java index c2c59012fa8..a78cd2ff5ea 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Contents.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Contents.java @@ -81,8 +81,8 @@ public class Contents { public final Content deprecatedLabel; public final Content deprecatedPhrase; public final Content deprecatedForRemovalPhrase; - public final Content descfrmClassLabel; - public final Content descfrmInterfaceLabel; + public final Content descriptionFromClassLabel; + public final Content descriptionFromInterfaceLabel; public final Content descriptionLabel; public final Content detailLabel; public final Content enclosingClassLabel; @@ -227,8 +227,8 @@ public class Contents { deprecatedLabel = getContent("doclet.navDeprecated"); deprecatedPhrase = getContent("doclet.Deprecated"); deprecatedForRemovalPhrase = getContent("doclet.DeprecatedForRemoval"); - descfrmClassLabel = getContent("doclet.Description_From_Class"); - descfrmInterfaceLabel = getContent("doclet.Description_From_Interface"); + descriptionFromClassLabel = getContent("doclet.Description_From_Class"); + descriptionFromInterfaceLabel = getContent("doclet.Description_From_Interface"); descriptionLabel = getContent("doclet.Description"); detailLabel = getContent("doclet.Detail"); enclosingClassLabel = getContent("doclet.Enclosing_Class"); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/MethodWriterImpl.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/MethodWriterImpl.java index 247612c57ce..9ba0a2222ea 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/MethodWriterImpl.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/MethodWriterImpl.java @@ -157,13 +157,13 @@ public class MethodWriterImpl extends AbstractExecutableMemberWriter ? utils.getSimpleName(holder) : utils.getFullyQualifiedName(holder)); Content codeLink = HtmlTree.CODE(link); - Content descfrmLabel = HtmlTree.SPAN(HtmlStyle.descfrmTypeLabel, + Content descriptionFromTypeLabel = HtmlTree.SPAN(HtmlStyle.descriptionFromTypeLabel, utils.isClass(holder) - ? contents.descfrmClassLabel - : contents.descfrmInterfaceLabel); - descfrmLabel.add(Entity.NO_BREAK_SPACE); - descfrmLabel.add(codeLink); - methodDocTree.add(HtmlTree.DIV(HtmlStyle.block, descfrmLabel)); + ? contents.descriptionFromClassLabel + : contents.descriptionFromInterfaceLabel); + descriptionFromTypeLabel.add(Entity.NO_BREAK_SPACE); + descriptionFromTypeLabel.add(codeLink); + methodDocTree.add(HtmlTree.DIV(HtmlStyle.block, descriptionFromTypeLabel)); } writer.addInlineComment(method, methodDocTree); } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PropertyWriterImpl.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PropertyWriterImpl.java index b472e4d1949..9ff02bdd8f5 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PropertyWriterImpl.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PropertyWriterImpl.java @@ -118,13 +118,13 @@ public class PropertyWriterImpl extends AbstractMemberWriter utils.isIncluded(holder) ? holder.getSimpleName() : holder.getQualifiedName()); Content codeLink = HtmlTree.CODE(link); - Content descfrmLabel = HtmlTree.SPAN(HtmlStyle.descfrmTypeLabel, + Content descriptionFromLabel = HtmlTree.SPAN(HtmlStyle.descriptionFromTypeLabel, utils.isClass(holder) - ? contents.descfrmClassLabel - : contents.descfrmInterfaceLabel); - descfrmLabel.add(Entity.NO_BREAK_SPACE); - descfrmLabel.add(codeLink); - propertyDocTree.add(HtmlTree.DIV(HtmlStyle.block, descfrmLabel)); + ? contents.descriptionFromClassLabel + : contents.descriptionFromInterfaceLabel); + descriptionFromLabel.add(Entity.NO_BREAK_SPACE); + descriptionFromLabel.add(codeLink); + propertyDocTree.add(HtmlTree.DIV(HtmlStyle.block, descriptionFromLabel)); } writer.addInlineComment(property, propertyDocTree); } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlStyle.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlStyle.java index 2ba0867e90e..5af001978ab 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlStyle.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlStyle.java @@ -385,8 +385,7 @@ public enum HtmlStyle { /** * The class for a label indicating the element from which a description has been copied. */ - // This should be renamed to something less cryptic - descfrmTypeLabel, + descriptionFromTypeLabel, /** * The class for a note providing information about the permitted subtypes of a diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/stylesheet.css b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/stylesheet.css index 23bf07bffb8..a3aaf56fcd0 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/stylesheet.css +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/stylesheet.css @@ -549,7 +549,7 @@ h1.hidden { margin:0 10px 5px 0; color:#474747; } -.deprecated-label, .descfrm-type-label, .implementation-label, .member-name-label, .member-name-link, +.deprecated-label, .description-from-type-label, .implementation-label, .member-name-label, .member-name-link, .module-label-in-package, .module-label-in-type, .override-specify-label, .package-label-in-type, .package-hierarchy-label, .type-name-label, .type-name-link, .search-tag-link, .preview-label { font-weight:bold; diff --git a/test/langtools/jdk/javadoc/doclet/testInterface/TestInterface.java b/test/langtools/jdk/javadoc/doclet/testInterface/TestInterface.java index 1fc0dcfca79..a435b831e7e 100644 --- a/test/langtools/jdk/javadoc/doclet/testInterface/TestInterface.java +++ b/test/langtools/jdk/javadoc/doclet/testInterface/TestInterface.java @@ -150,7 +150,7 @@ public class TestInterface extends JavadocTester {
    public static \ void staticMethod()
    -
    Description copied from inte\ +
    Description copied from inte\ rface: Inter\ faceWithStaticMembers
    A static method
    diff --git a/test/langtools/jdk/javadoc/doclet/testOptions/custom-stylesheet.css b/test/langtools/jdk/javadoc/doclet/testOptions/custom-stylesheet.css index e5db2cb0d3c..a92cf98ada0 100644 --- a/test/langtools/jdk/javadoc/doclet/testOptions/custom-stylesheet.css +++ b/test/langtools/jdk/javadoc/doclet/testOptions/custom-stylesheet.css @@ -609,7 +609,7 @@ h1.hidden { margin:3px 10px 2px 0px; color:#474747; } -.deprecatedLabel, .descfrmTypeLabel, .memberNameLabel, .memberNameLink, +.deprecatedLabel, .descriptionFromTypeLabel, .memberNameLabel, .memberNameLink, .overrideSpecifyLabel, .packageHierarchyLabel, .paramLabel, .returnLabel, .seeLabel, .simpleTagLabel, .throwsLabel, .typeNameLabel, .typeNameLink, .searchTagLink { font-weight:bold; diff --git a/test/langtools/jdk/javadoc/doclet/testOverriddenMethods/TestOverriddenMethodDocCopy.java b/test/langtools/jdk/javadoc/doclet/testOverriddenMethods/TestOverriddenMethodDocCopy.java index 116cbfddfd8..a2b96e19239 100644 --- a/test/langtools/jdk/javadoc/doclet/testOverriddenMethods/TestOverriddenMethodDocCopy.java +++ b/test/langtools/jdk/javadoc/doclet/testOverriddenMethods/TestOverriddenMethodDocCopy.java @@ -54,7 +54,7 @@ public class TestOverriddenMethodDocCopy extends JavadocTester { checkOutput("pkg1/SubClass.html", true, """ - Description copied from class: Description copied from class: BaseClass"""); } } diff --git a/test/langtools/jdk/javadoc/doclet/testOverriddenMethods/TestOverrideMethods.java b/test/langtools/jdk/javadoc/doclet/testOverriddenMethods/TestOverrideMethods.java index aec85bdbc3f..785ddd5072f 100644 --- a/test/langtools/jdk/javadoc/doclet/testOverriddenMethods/TestOverrideMethods.java +++ b/test/langtools/jdk/javadoc/doclet/testOverriddenMethods/TestOverrideMethods.java @@ -412,7 +412,7 @@ public class TestOverrideMethods extends JavadocTester { ="element-name">m1
    (java.lang.Class<? ext\ ends java.lang.CharSequence> p1, int[] p2)
    -
    Description copied from inte\ +
    Description copied from inte\ rface: Ann\ otatedBase
    This is AnnotatedBase::m1.
    @@ -437,7 +437,7 @@ public class TestOverrideMethods extends JavadocTester { ="element-name">m1
    (java.lang.Class<? ext\ ends java.lang.CharSequence> p1, int[] p2)
    -
    Description copied from inte\ +
    Description copied from inte\ rface: Ann\ otatedBase
    This is AnnotatedBase::m1.
    @@ -460,7 +460,7 @@ public class TestOverrideMethods extends JavadocTester { /span> m1(j\ ava.lang.Class<? extends java.lang.CharSequence> p1, int[] p2)
    -
    Description copied from inte\ +
    Description copied from inte\ rface: Ann\ otatedBase
    This is AnnotatedBase::m1.
    @@ -484,7 +484,7 @@ public class TestOverrideMethods extends JavadocTester { @A java.lang.Class<\ ;? extends java.lang.CharSequence> p1, int[] p2)
    -
    Description copied from inte\ +
    Description copied from inte\ rface: Ann\ otatedBase
    This is AnnotatedBase::m1.
    @@ -507,7 +507,7 @@ public class TestOverrideMethods extends JavadocTester { ass="parameters">(java.lang.Class<@A ? extends java.lang.CharSequence> p1, int[] p2)
    -
    Description copied from inte\ +
    Description copied from inte\ rface: Ann\ otatedBase
    This is AnnotatedBase::m1.
    @@ -530,7 +530,7 @@ public class TestOverrideMethods extends JavadocTester { ass="parameters">(java.lang.Class<? extends @A java.lang.CharSequence> p1, int[] p2)
    -
    Description copied from inte\ +
    Description copied from inte\ rface: Ann\ otatedBase
    This is AnnotatedBase::m1.
    @@ -553,7 +553,7 @@ public class TestOverrideMethods extends JavadocTester { ass="parameters">(java.lang.Class<? extends java.lang.CharSequence> p1, int @A [] p2)
    -
    Description copied from inte\ +
    Description copied from inte\ rface: Ann\ otatedBase
    This is AnnotatedBase::m1.
    diff --git a/test/langtools/jdk/javadoc/doclet/testPrivateClasses/TestPrivateClasses.java b/test/langtools/jdk/javadoc/doclet/testPrivateClasses/TestPrivateClasses.java index 135890d22ee..91917705dd5 100644 --- a/test/langtools/jdk/javadoc/doclet/testPrivateClasses/TestPrivateClasses.java +++ b/test/langtools/jdk/javadoc/doclet/testPrivateClasses/TestPrivateClasses.java @@ -224,7 +224,7 @@ public class TestPrivateClasses extends JavadocTester { //Since private flag is used, we can document that private interface method //with generic parameters has been implemented. """ - Description copied from interface: <\ + Description copied from interface: <\ a href="I.html#hello(T)">I""", """
    Specified by:
    diff --git a/test/langtools/jdk/javadoc/doclet/testReturnTag/TestReturnTag.java b/test/langtools/jdk/javadoc/doclet/testReturnTag/TestReturnTag.java index b5d65f79f13..00d5c92c630 100644 --- a/test/langtools/jdk/javadoc/doclet/testReturnTag/TestReturnTag.java +++ b/test/langtools/jdk/javadoc/doclet/testReturnTag/TestReturnTag.java @@ -379,7 +379,7 @@ public class TestReturnTag extends JavadocTester { checkOutput("C.html", true, """ -
    Description copied from class: Super
    +
    Description copied from class: Super
    Returns the result.
    Overrides:
    -- GitLab From 0ca094bc5f568842b1619229206ec4a385e5ebf6 Mon Sep 17 00:00:00 2001 From: Jonathan Gibbons Date: Mon, 4 Oct 2021 16:59:30 +0000 Subject: [PATCH 079/385] 8273244: Improve diagnostic output related to ErroneousTree Reviewed-by: prappo --- .../com/sun/tools/javac/api/JavacTrees.java | 77 +---- .../tools/javac/parser/DocCommentParser.java | 90 ++++-- .../tools/javac/parser/ReferenceParser.java | 184 ++++++++---- .../com/sun/tools/javac/tree/DCTree.java | 275 +++++++++++++++--- .../sun/tools/javac/tree/DocTreeMaker.java | 19 +- .../com/sun/tools/javac/util/AbstractLog.java | 4 +- .../shellsupport/doc/JavadocHelper.java | 2 +- .../jdk/javadoc/internal/doclint/DocLint.java | 3 +- .../jdk/javadoc/internal/tool/JavadocLog.java | 25 +- .../tools/doclint/CrashInAnnotateTest.out | 12 +- .../tools/doclint/EndWithIdentifierTest.out | 4 +- .../tools/doclint/UnfinishedInlineTagTest.out | 6 +- test/langtools/tools/doclint/tidy/README.txt | 10 +- .../doclint/tidy/UnescapedOrUnknownEntity.out | 7 +- .../tools/javac/doctree/AttrTest.java | 4 +- .../tools/javac/doctree/AuthorTest.java | 4 +- .../tools/javac/doctree/BadTest.java | 4 +- .../tools/javac/doctree/CodeTest.java | 4 +- .../tools/javac/doctree/CoverageTest.java | 185 ++++++++++++ .../tools/javac/doctree/DeprecatedTest.java | 4 +- .../tools/javac/doctree/DocCommentTester.java | 203 +++++++++++-- .../tools/javac/doctree/DocRootTest.java | 4 +- .../tools/javac/doctree/ElementTest.java | 4 +- .../tools/javac/doctree/EntityTest.java | 4 +- .../tools/javac/doctree/ExceptionTest.java | 4 +- .../javac/doctree/FirstSentenceTest.java | 8 +- .../tools/javac/doctree/HiddenTest.java | 4 +- .../tools/javac/doctree/InPreTest.java | 4 +- .../tools/javac/doctree/IndexTest.java | 4 +- .../tools/javac/doctree/InheritDocTest.java | 4 +- .../tools/javac/doctree/LinkPlainTest.java | 4 +- .../tools/javac/doctree/LinkTest.java | 4 +- .../tools/javac/doctree/LiteralTest.java | 4 +- .../tools/javac/doctree/ParamTest.java | 4 +- .../tools/javac/doctree/ProvidesTest.java | 4 +- .../tools/javac/doctree/ReturnTest.java | 4 +- .../tools/javac/doctree/SeeTest.java | 4 +- .../tools/javac/doctree/SerialDataTest.java | 4 +- .../tools/javac/doctree/SerialFieldTest.java | 4 +- .../tools/javac/doctree/SerialTest.java | 4 +- .../tools/javac/doctree/SinceTest.java | 4 +- .../tools/javac/doctree/SummaryTest.java | 4 +- .../javac/doctree/SystemPropertyTest.java | 4 +- .../tools/javac/doctree/TagTest.java | 4 +- .../tools/javac/doctree/ThrowableTest.java | 4 +- .../tools/javac/doctree/UsesTest.java | 4 +- .../tools/javac/doctree/ValueTest.java | 4 +- .../tools/javac/doctree/VersionTest.java | 4 +- .../javac/doctree/positions/TestPosition.java | 4 +- .../javac/tree/AbstractTreeScannerTest.java | 23 +- 50 files changed, 907 insertions(+), 358 deletions(-) create mode 100644 test/langtools/tools/javac/doctree/CoverageTest.java diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java index 69c8e9e6215..3b189799368 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java @@ -256,79 +256,16 @@ public class JavacTrees extends DocTrees { @Override @DefinedBy(Api.COMPILER_TREE) public long getStartPosition(CompilationUnitTree file, DocCommentTree comment, DocTree tree) { - return ((DCTree) tree).getSourcePosition((DCDocComment) comment); + DCDocComment dcComment = (DCDocComment) comment; + DCTree dcTree = (DCTree) tree; + return dcComment.getSourcePosition(dcTree.getStartPosition()); } - @Override @DefinedBy(Api.COMPILER_TREE) @SuppressWarnings("fallthrough") + + @Override @DefinedBy(Api.COMPILER_TREE) public long getEndPosition(CompilationUnitTree file, DocCommentTree comment, DocTree tree) { DCDocComment dcComment = (DCDocComment) comment; - if (tree instanceof DCEndPosTree dcEndPosTree) { - int endPos = dcEndPosTree.getEndPos(dcComment); - - if (endPos != Position.NOPOS) { - return endPos; - } - } - int correction = 0; - switch (tree.getKind()) { - case TEXT: - DCText text = (DCText) tree; - - return dcComment.comment.getSourcePos(text.pos + text.text.length()); - case ERRONEOUS: - DCErroneous err = (DCErroneous) tree; - - return dcComment.comment.getSourcePos(err.pos + err.body.length()); - case IDENTIFIER: - DCIdentifier ident = (DCIdentifier) tree; - - return dcComment.comment.getSourcePos(ident.pos + (ident.name != names.error ? ident.name.length() : 0)); - case PARAM: - DCParam param = (DCParam) tree; - - if (param.isTypeParameter && param.getDescription().isEmpty()) { - correction = 1; - } - case AUTHOR: case DEPRECATED: case RETURN: case SEE: - case SERIAL: case SERIAL_DATA: case SERIAL_FIELD: case SINCE: - case THROWS: case UNKNOWN_BLOCK_TAG: case VERSION: { - DocTree last = getLastChild(tree); - - if (last != null) { - return getEndPosition(file, comment, last) + correction; - } - - int pos; - String name; - if (tree.getKind() == DocTree.Kind.RETURN) { - DCTree.DCReturn dcReturn = (DCTree.DCReturn) tree; - pos = dcReturn.pos; - name = dcReturn.getTagName(); - } else { - DCBlockTag block = (DCBlockTag) tree; - pos = block.pos; - name = block.getTagName(); - } - - return dcComment.comment.getSourcePos(pos + name.length() + 1); - } - case ENTITY: { - DCEntity endEl = (DCEntity) tree; - return dcComment.comment.getSourcePos(endEl.pos + (endEl.name != names.error ? endEl.name.length() : 0) + 2); - } - case COMMENT: { - DCComment endEl = (DCComment) tree; - return dcComment.comment.getSourcePos(endEl.pos + endEl.body.length()); - } - default: - DocTree last = getLastChild(tree); - - if (last != null) { - return getEndPosition(file, comment, last); - } - break; - } - - return Position.NOPOS; + DCTree dcTree = (DCTree) tree; + return dcComment.getSourcePosition(dcTree.getEndPosition()); } }; } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/DocCommentParser.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/DocCommentParser.java index ff29793cb11..1c70a913409 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/DocCommentParser.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/DocCommentParser.java @@ -43,6 +43,7 @@ import com.sun.tools.javac.tree.DCTree.DCReference; import com.sun.tools.javac.tree.DCTree.DCText; import com.sun.tools.javac.tree.DocTreeMaker; import com.sun.tools.javac.util.DiagnosticSource; +import com.sun.tools.javac.util.JCDiagnostic; import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.ListBuffer; import com.sun.tools.javac.util.Name; @@ -62,14 +63,21 @@ import static com.sun.tools.javac.util.LayoutCharacters.EOI; public class DocCommentParser { static class ParseException extends Exception { private static final long serialVersionUID = 0; + final int pos; + ParseException(String key) { + this(Position.NOPOS, key); + } + ParseException(int pos, String key) { super(key); + this.pos = pos; } } - private enum Phase {PREAMBLE, BODY, POSTAMBLE} + private enum Phase { PREAMBLE, BODY, POSTAMBLE } private final ParserFactory fac; + private final JCDiagnostic.Factory diags; private final DiagnosticSource diagSource; private final Comment comment; private final DocTreeMaker m; @@ -96,6 +104,7 @@ public class DocCommentParser { public DocCommentParser(ParserFactory fac, DiagnosticSource diagSource, Comment comment, boolean isFileContent) { this.fac = fac; + this.diags = fac.log.diags; this.diagSource = diagSource; this.comment = comment; names = fac.names; @@ -126,18 +135,13 @@ public class DocCommentParser { List tags = blockTags(); List postamble = isFileContent ? blockContent(Phase.POSTAMBLE) : List.nil(); - int pos = Position.NOPOS; - if (!preamble.isEmpty()) - pos = preamble.head.pos; - else if (!body.isEmpty()) - pos = body.head.pos; - else if (!tags.isEmpty()) - pos = tags.head.pos; - else if (!postamble.isEmpty()) - pos = postamble.head.pos; - - DCDocComment dc = m.at(pos).newDocCommentTree(comment, body, tags, preamble, postamble); - return dc; + int pos = !preamble.isEmpty() ? preamble.head.pos + : !body.isEmpty() ? body.head.pos + : !tags.isEmpty() ? tags.head.pos + : !postamble.isEmpty() ? postamble.head.pos + : 0; + + return m.at(pos).newDocCommentTree(comment, body, tags, preamble, postamble); } void nextChar() { @@ -281,7 +285,7 @@ public class DocCommentParser { return erroneous("dc.no.tag.name", p); } catch (ParseException e) { blockContent(); - return erroneous(e.getMessage(), p); + return erroneous(e.getMessage(), p, e.pos); } } @@ -334,7 +338,7 @@ public class DocCommentParser { } } } catch (ParseException e) { - return erroneous(e.getMessage(), p); + return erroneous(e.getMessage(), p, e.pos); } } @@ -471,18 +475,15 @@ public class DocCommentParser { ref.moduleName, ref.qualExpr, ref.member, ref.paramTypes) .setEndPos(bp); - } catch (ReferenceParser.ParseException parseException) { - throw new ParseException(parseException.getMessage()); + } catch (ReferenceParser.ParseException pe) { + throw new ParseException(pos + pe.pos, pe.getMessage()); } } /** - * Read Java identifier - * Matching pairs of { } are skipped; the text is terminated by the first - * unmatched }. It is an error if the beginning of the next tag is detected. + * Reads a Java identifier. */ - @SuppressWarnings("fallthrough") protected DCIdentifier identifier() throws ParseException { skipWhitespace(); int pos = bp; @@ -496,10 +497,9 @@ public class DocCommentParser { } /** - * Read a quoted string. + * Reads a quoted string. * It is an error if the beginning of the next tag is detected. */ - @SuppressWarnings("fallthrough") protected DCText quotedString() { int pos = bp; nextChar(); @@ -530,7 +530,7 @@ public class DocCommentParser { } /** - * Read a term (that is, one word). + * Reads a term (that is, one word). * It is an error if the beginning of the next tag is detected. */ @SuppressWarnings("fallthrough") @@ -567,7 +567,7 @@ public class DocCommentParser { } /** - * Read general text content of an inline tag, including HTML entities and elements. + * Reads general text content of an inline tag, including HTML entities and elements. * Matching pairs of { } are skipped; the text is terminated by the first * unmatched }. It is an error if the beginning of the next tag is detected. */ @@ -656,7 +656,7 @@ public class DocCommentParser { } /** - * Read an HTML entity. + * Reads an HTML entity. * {@literal &identifier; } or {@literal &#digits; } or {@literal &#xhex-digits; } */ protected DCTree entity() { @@ -966,7 +966,33 @@ public class DocCommentParser { } } + /** + * Creates an {@code ErroneousTree} node, for a range of text starting at a given position, + * ending at the last non-whitespace character before the current position, + * and with the preferred position set to the last character within that range. + * + * @param code the resource key for the error message + * @param pos the starting position + * + * @return the {@code ErroneousTree} node + */ protected DCErroneous erroneous(String code, int pos) { + return erroneous(code, pos, Position.NOPOS); + } + + /** + * Creates an {@code ErroneousTree} node, for a range of text starting at a given position, + * ending at the last non-whitespace character before the current position, + * and with a given preferred position. + * + * @param code the resource key for the error message + * @param pos the starting position + * @param pref the preferred position for the node, or {@code NOPOS} to use the default value + * as the last character of the range + * + * @return the {@code ErroneousTree} node + */ + protected DCErroneous erroneous(String code, int pos, int pref) { int i = bp - 1; loop: while (i > pos) { @@ -981,8 +1007,14 @@ public class DocCommentParser { } i--; } + if (pref == Position.NOPOS) { + pref = i; + } + int end = i + 1; textStart = -1; - return m.at(pos).newErroneousTree(newString(pos, i + 1), diagSource, code); + JCDiagnostic.DiagnosticPosition dp = DCTree.createDiagnosticPosition(comment, pos, pref, end); + JCDiagnostic diag = diags.error(null, diagSource, dp, code); + return m.at(pos).newErroneousTree(newString(pos, end), diag).setPrefPos(pref); } protected boolean isIdentifierStart(char ch) { @@ -1169,7 +1201,7 @@ public class DocCommentParser { } inlineText(WhitespaceRetentionPolicy.REMOVE_ALL); // skip unexpected content nextChar(); - throw new ParseException("dc.unexpected.content"); + throw new ParseException(pos, "dc.unexpected.content"); } }, @@ -1226,7 +1258,7 @@ public class DocCommentParser { } inlineText(WhitespaceRetentionPolicy.REMOVE_ALL); // skip unexpected content nextChar(); - throw new ParseException("dc.unexpected.content"); + throw new ParseException(pos, "dc.unexpected.content"); } }, diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/ReferenceParser.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/ReferenceParser.java index c57b3b6eb19..65958282275 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/ReferenceParser.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/ReferenceParser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,11 +30,17 @@ import com.sun.source.tree.Tree; import com.sun.source.util.TreeScanner; import com.sun.tools.javac.parser.Tokens.TokenKind; import com.sun.tools.javac.tree.JCTree; +import com.sun.tools.javac.util.DiagnosticSource; +import com.sun.tools.javac.util.JCDiagnostic; import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.ListBuffer; import com.sun.tools.javac.util.Log; import com.sun.tools.javac.util.Name; +import javax.tools.JavaFileObject; +import java.util.Locale; +import java.util.Queue; + /** * A utility class to parse a string in a doc comment containing a * reference to an API element, such as a type, field or method. @@ -71,8 +77,11 @@ public class ReferenceParser { */ public static class ParseException extends Exception { private static final long serialVersionUID = 0; - ParseException(String message) { + final int pos; + + ParseException(int pos, String message) { super(message); + this.pos = pos; } } @@ -100,106 +109,157 @@ public class ReferenceParser { Name member; List paramTypes; - Log.DeferredDiagnosticHandler deferredDiagnosticHandler - = new Log.DeferredDiagnosticHandler(fac.log); + Log.DeferredDiagnosticHandler dh = new Log.DeferredDiagnosticHandler(fac.log); try { int slash = sig.indexOf("/"); - int hash = sig.indexOf("#", slash + 1); + int afterSlash = slash + 1; + int hash = sig.indexOf("#", afterSlash); + int afterHash = hash + 1; int lparen = sig.indexOf("(", Math.max(slash, hash) + 1); - if (slash > -1) { - moduleName = parseModule(sig.substring(0, slash)); - } else { - moduleName = null; - } - if (slash > 0 && sig.length() == slash + 1) { + int afterLparen = lparen + 1; + + moduleName = switch (slash) { + case -1 -> null; + case 0 -> throw new ParseException(0, "dc.ref.syntax.error"); + default -> parseModule(sig, 0, slash, dh); + }; + + if (slash > 0 && sig.length() == afterSlash) { qualExpr = null; member = null; } else if (hash == -1) { if (lparen == -1) { - qualExpr = parseType(sig.substring(slash + 1)); + qualExpr = parseType(sig, afterSlash, sig.length(), dh); member = null; } else { qualExpr = null; - member = parseMember(sig.substring(slash + 1, lparen)); + member = parseMember(sig, afterSlash, lparen, dh); } } else { - qualExpr = (hash == slash + 1) ? null : parseType(sig.substring(slash + 1, hash)); - if (lparen == -1) - member = parseMember(sig.substring(hash + 1)); - else - member = parseMember(sig.substring(hash + 1, lparen)); + qualExpr = (hash == afterSlash) ? null : parseType(sig, afterSlash, hash, dh); + if (lparen == -1) { + member = parseMember(sig, afterHash, sig.length(), dh); + } else { + member = parseMember(sig, afterHash, lparen, dh); + } } - if (lparen < 0) { + if (lparen == -1) { paramTypes = null; } else { int rparen = sig.indexOf(")", lparen); - if (rparen != sig.length() - 1) - throw new ParseException("dc.ref.bad.parens"); - paramTypes = parseParams(sig.substring(lparen + 1, rparen)); + if (rparen != sig.length() - 1) { + throw new ParseException(rparen, "dc.ref.bad.parens"); + } + paramTypes = parseParams(sig, afterLparen, rparen, dh); } - if (!deferredDiagnosticHandler.getDiagnostics().isEmpty()) - throw new ParseException("dc.ref.syntax.error"); + assert dh.getDiagnostics().isEmpty(); } finally { - fac.log.popDiagnosticHandler(deferredDiagnosticHandler); + fac.log.popDiagnosticHandler(dh); } return new Reference(moduleName, qualExpr, member, paramTypes); } - private JCTree.JCExpression parseModule(String s) throws ParseException { - JavacParser p = fac.newParser(s, false, false, false); - JCTree.JCExpression expr = p.qualident(false); - if (p.token().kind != TokenKind.EOF) - throw new ParseException("dc.ref.unexpected.input"); - return expr; + private JCTree.JCExpression parseModule(String sig, int beginIndex, int endIndex, Log.DeferredDiagnosticHandler dh) throws ParseException { + String s = sig.substring(beginIndex, endIndex); + JavaFileObject prev = fac.log.useSource(null); + try { + JavacParser p = fac.newParser(s, false, false, false); + JCTree.JCExpression expr = p.qualident(false); + if (p.token().kind != TokenKind.EOF) { + throw new ParseException(beginIndex + p.token().pos, "dc.ref.unexpected.input"); + } + checkDiags(dh, beginIndex); + return expr; + } finally { + fac.log.useSource(prev); + } } - private JCTree parseType(String s) throws ParseException { - JavacParser p = fac.newParser(s, false, false, false); - JCTree tree = p.parseType(); - if (p.token().kind != TokenKind.EOF) - throw new ParseException("dc.ref.unexpected.input"); - return tree; + private JCTree parseType(String sig, int beginIndex, int endIndex, Log.DeferredDiagnosticHandler dh) throws ParseException { + String s = sig.substring(beginIndex, endIndex); + JavaFileObject prev = fac.log.useSource(null); + try { + JavacParser p = fac.newParser(s, false, false, false); + JCTree tree = p.parseType(); + if (p.token().kind != TokenKind.EOF) { + throw new ParseException(beginIndex + p.token().pos, "dc.ref.unexpected.input"); + } + checkDiags(dh, beginIndex); + return tree; + } finally { + fac.log.useSource(prev); + } } - private Name parseMember(String s) throws ParseException { - JavacParser p = fac.newParser(s, false, false, false); - Name name = p.ident(); - if (p.token().kind != TokenKind.EOF) - throw new ParseException("dc.ref.unexpected.input"); - return name; + private Name parseMember(String sig, int beginIndex, int endIndex, Log.DeferredDiagnosticHandler dh) throws ParseException { + String s = sig.substring(beginIndex, endIndex); + JavaFileObject prev = fac.log.useSource(null); + try { + JavacParser p = fac.newParser(s, false, false, false); + Name name = p.ident(); + if (p.token().kind != TokenKind.EOF) { + throw new ParseException(beginIndex + p.token().pos, "dc.ref.unexpected.input"); + } + checkDiags(dh, beginIndex); + return name; + } finally { + fac.log.useSource(prev); + } } - private List parseParams(String s) throws ParseException { - if (s.trim().isEmpty()) + private List parseParams(String sig, int beginIndex, int endIndex, Log.DeferredDiagnosticHandler dh) throws ParseException { + String s = sig.substring(beginIndex, endIndex); + if (s.isBlank()) { return List.nil(); + } - JavacParser p = fac.newParser(s.replace("...", "[]"), false, false, false); - ListBuffer paramTypes = new ListBuffer<>(); - paramTypes.add(p.parseType()); - - if (p.token().kind == TokenKind.IDENTIFIER) - p.nextToken(); - - while (p.token().kind == TokenKind.COMMA) { - p.nextToken(); + JavaFileObject prev = fac.log.useSource(null); + try { + JavacParser p = fac.newParser(s.replace("...", "[]"), false, false, false); + ListBuffer paramTypes = new ListBuffer<>(); paramTypes.add(p.parseType()); - if (p.token().kind == TokenKind.IDENTIFIER) + if (p.token().kind == TokenKind.IDENTIFIER) { p.nextToken(); - } + } + + while (p.token().kind == TokenKind.COMMA) { + p.nextToken(); + paramTypes.add(p.parseType()); + + if (p.token().kind == TokenKind.IDENTIFIER) { + p.nextToken(); + } + } + + if (p.token().kind != TokenKind.EOF) { + throw new ParseException(p.token().pos, "dc.ref.unexpected.input"); + } + + Tree typeAnno = new TypeAnnotationFinder().scan(paramTypes, null); + if (typeAnno != null) { + int annoPos = ((JCTree) typeAnno).getStartPosition(); + throw new ParseException(beginIndex + annoPos, "dc.ref.annotations.not.allowed"); + } - if (p.token().kind != TokenKind.EOF) - throw new ParseException("dc.ref.unexpected.input"); + checkDiags(dh, beginIndex); - if (new TypeAnnotationFinder().scan(paramTypes, null) != null) - throw new ParseException("dc.ref.annotations.not.allowed"); + return paramTypes.toList(); + } finally { + fac.log.useSource(prev); + } + } - return paramTypes.toList(); + private void checkDiags(Log.DeferredDiagnosticHandler h, int offset) throws ParseException { + JCDiagnostic d = h.getDiagnostics().peek(); + if (d != null) { + throw new ParseException(offset + ((int) d.getPosition()), "dc.ref.syntax.error"); + } } static class TypeAnnotationFinder extends TreeScanner { @@ -213,4 +273,4 @@ public class ReferenceParser { return t1 != null ? t1 : t2; } } -} \ No newline at end of file +} diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/DCTree.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/DCTree.java index 079fc1577c4..39462b00bc7 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/DCTree.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/DCTree.java @@ -25,26 +25,57 @@ package com.sun.tools.javac.tree; +import java.io.IOException; +import java.io.StringWriter; +import java.util.List; + +import javax.lang.model.element.Name; +import javax.lang.model.util.Elements; import javax.tools.Diagnostic; +import javax.tools.JavaFileObject; import com.sun.source.doctree.*; +import com.sun.source.util.DocTreeScanner; + import com.sun.tools.javac.parser.Tokens.Comment; import com.sun.tools.javac.util.Assert; import com.sun.tools.javac.util.DefinedBy; import com.sun.tools.javac.util.DefinedBy.Api; -import com.sun.tools.javac.util.DiagnosticSource; import com.sun.tools.javac.util.JCDiagnostic; -import com.sun.tools.javac.util.JCDiagnostic.SimpleDiagnosticPosition; import com.sun.tools.javac.util.Position; -import java.io.IOException; -import java.io.StringWriter; -import java.util.List; - -import javax.lang.model.element.Name; -import javax.tools.JavaFileObject; +import static com.sun.tools.javac.util.Position.NOPOS; /** + * + * Root class for abstract syntax documentation tree nodes. It provides definitions + * for specific tree nodes as subclasses nested inside. + * + * Apart from the top-level {@link DCDocComment} node, generally nodes fall into + * three groups: + *
      + *
    • Leaf nodes, such as {@link DCIdentifier}, {@link DCText} + *
    • Inline tag nodes, such as {@link DCLink}, {@link DCLiteral} + *
    • Block tag nodes, such as {@link DCParam}, {@link DCThrows} + *
    + * + * Trees are typically wide and shallow, without a significant amount of nesting. + * + * Nodes have various associated positions: + *
      + *
    • the {@link #pos position} of the first character that is unique to this node, + * and not part of any child node + *
    • the {@link #getStartPosition start} of the range of characters for this node + *
    • the "{@link #getPreferredPosition() preferred}" position in the range of characters + * for this node + *
    • the {@link #getEndPosition() end} of the range of characters for this node + *
    + * + * All values are relative to the beginning of the + * {@link Elements#getDocComment comment text} in which they appear. + * To convert a value to the position in the enclosing source text, + * use {@link DCDocComment#getSourcePosition(int)}. + * *

    This is NOT part of any supported API. * If you write code that depends on this, you do so at your own risk. * This code and its internal interfaces are subject to change or @@ -53,41 +84,150 @@ import javax.tools.JavaFileObject; public abstract class DCTree implements DocTree { /** - * The position in the comment string. - * Use {@link #getSourcePosition getSourcePosition} to convert + * The position of the first character that is unique to this node. + * It is normally set by the methods in {@link DocTreeMaker}. + * + * The value is relative to the beginning of the comment text. + * Use {@link DCDocComment#getSourcePosition(int)} to convert * it to a position in the source file. * - * TODO: why not simply translate all these values into - * source file positions? Is it useful to have string-offset - * positions as well? + * @see #getStartPosition() + * @see #getPreferredPosition() + * @see #getEndPosition() */ public int pos; /** - * {@return the source position for this tree node} + * {@return a {@code DiagnosticPosition} for this node} + * The method may be used when reporting diagnostics for this node. * - * @param dc the enclosing doc comment + * @param dc the enclosing comment, used to convert comment-based positions + * to file-based positions */ - public long getSourcePosition(DCDocComment dc) { - return dc.comment.getSourcePos(pos); + public JCDiagnostic.DiagnosticPosition pos(DCDocComment dc) { + return createDiagnosticPosition(dc.comment, getStartPosition(), getPreferredPosition(), getEndPosition()); } /** - * {@return the source position for position relative to this tree node} - * This is primarily useful for nodes that wrap a single string child. + * {@return the start position of this tree node} + * + * For most nodes, this is the position of the first character that is unique to this node. * - * @param dc the enclosing doc comment - * @param offset the offset + * The value is relative to the beginning of the comment text. + * Use {@link DCDocComment#getSourcePosition(int)} to convert + * it to a position in the source file. */ - public long getSourcePosition(DCDocComment dc, int offset) { - return dc.comment.getSourcePos(pos + offset); + public int getStartPosition() { + return pos; } - public JCDiagnostic.DiagnosticPosition pos(DCDocComment dc) { - return new SimpleDiagnosticPosition(dc.comment.getSourcePos(pos)); + /** + * {@return the "preferred" position of this tree node} + * + * It is typically the position of the first character that is unique to this node. + * It is the position that is used for the caret in "line and caret" diagnostic messages. + * + * The value is relative to the beginning of the comment text. + * Use {@link DCDocComment#getSourcePosition(int)} to convert + * it to a position in the source file. + */ + public int getPreferredPosition() { + return pos; } - /** Convert a tree to a pretty-printed string. */ + /** + * {@return the end position of the tree node} + * + * The value is typically derived in one of three ways: + *

      + *
    • computed from the start and length of "leaf" nodes, such as {@link TextTree}, + *
    • computed recursively from the end of the last child node, such as for most {@link DCBlockTag block tags}, or + *
    • provided explicitly, such as for subtypes of {@link DCEndPosTree} + *
    + * + * The value is relative to the beginning of the comment text. + * Use {@link DCDocComment#getSourcePosition(int)} to convert + * it to a position in the source file. + */ + public int getEndPosition() { + if (this instanceof DCEndPosTree dcEndPosTree) { + int endPos = dcEndPosTree.getEndPos(); + + if (endPos != NOPOS) { + return endPos; + } + } + + switch (getKind()) { + case TEXT -> { + DCText text = (DCText) this; + return text.pos + text.text.length(); + } + + case ERRONEOUS -> { + DCErroneous err = (DCErroneous) this; + return err.pos + err.body.length(); + } + + case IDENTIFIER -> { + DCIdentifier ident = (DCIdentifier) this; + return ident.pos + ident.name.length(); + } + + case AUTHOR, DEPRECATED, HIDDEN, PARAM, PROVIDES, RETURN, SEE, SERIAL, SERIAL_DATA, SERIAL_FIELD, SINCE, + THROWS, UNKNOWN_BLOCK_TAG, USES, VERSION -> { + DCTree last = getLastChild(); + + if (last != null) { + int correction = (this instanceof DCParam p && p.isTypeParameter && p.getDescription().isEmpty()) ? 1 : 0; + return last.getEndPosition() + correction; + } + + String name = ((BlockTagTree) this).getTagName(); + return this.pos + name.length() + 1; + } + + case ENTITY -> { + DCEntity endEl = (DCEntity) this; + return endEl.pos + endEl.name.length() + 2; + } + + case COMMENT -> { + DCComment endEl = (DCComment) this; + return endEl.pos + endEl.body.length(); + } + + case ATTRIBUTE -> { + DCAttribute attr = (DCAttribute) this; + if (attr.vkind == AttributeTree.ValueKind.EMPTY) { + return attr.pos + attr.name.length(); + } + DCTree last = getLastChild(); + if (last != null) { + return last.getEndPosition() + (attr.vkind == AttributeTree.ValueKind.UNQUOTED ? 0 : 1); + } + } + + case DOC_COMMENT -> { + DCDocComment dc = (DCDocComment) this; + DCTree last = getLastChild(); + return last == null ? dc.pos : last.getEndPosition(); + } + + default -> { + DCTree last = getLastChild(); + if (last != null) { + return last.getEndPosition(); + } + } + } + + return NOPOS; + } + + /** + * Convert a tree to a pretty-printed string. + */ @Override public String toString() { StringWriter s = new StringWriter(); @@ -102,12 +242,64 @@ public abstract class DCTree implements DocTree { return s.toString(); } + /** + * {@return the last (right-most) child of this node} + */ + private DCTree getLastChild() { + final DCTree[] last = new DCTree[] {null}; + + accept(new DocTreeScanner() { + @Override @DefinedBy(Api.COMPILER_TREE) + public Void scan(DocTree node, Void p) { + if (node instanceof DCTree dcTree) last[0] = dcTree; + return null; + } + }, null); + + return last[0]; + } + + /** + * {@return a diagnostic position based on the positions in a comment} + * + * The positions are lazily converted to file-based positions, as needed. + * + * @param comment the enclosing comment + * @param start the start position in the comment + * @param pref the preferred position in the comment + * @param end the end position in the comment + */ + public static JCDiagnostic.DiagnosticPosition createDiagnosticPosition(Comment comment, int start, int pref, int end) { + return new JCDiagnostic.DiagnosticPosition() { + + @Override + public JCTree getTree() { + return null; + } + + @Override + public int getStartPosition() { + return comment.getSourcePos(start); + } + + @Override + public int getPreferredPosition() { + return comment.getSourcePos(pref); + } + + @Override + public int getEndPosition(EndPosTable endPosTable) { + return comment.getSourcePos(end); + } + }; + } + public static abstract class DCEndPosTree> extends DCTree { - private int endPos = Position.NOPOS; + private int endPos = NOPOS; - public int getEndPos(DCDocComment dc) { - return dc.comment.getSourcePos(endPos); + public int getEndPos() { + return endPos; } @SuppressWarnings("unchecked") @@ -183,6 +375,10 @@ public abstract class DCTree implements DocTree { public List getPostamble() { return postamble; } + + public int getSourcePosition(int index) { + return comment.getSourcePos(index); + } } public static abstract class DCBlockTag extends DCTree implements BlockTagTree { @@ -388,14 +584,11 @@ public abstract class DCTree implements DocTree { } } - public static class DCErroneous extends DCTree implements ErroneousTree, JCDiagnostic.DiagnosticPosition { + public static class DCErroneous extends DCTree implements ErroneousTree { public final String body; public final JCDiagnostic diag; - DCErroneous(String body, JCDiagnostic.Factory diags, DiagnosticSource diagSource, String code, Object... args) { - this.body = body; - this.diag = diags.error(null, diagSource, this, code, args); - } + private int prefPos = NOPOS; DCErroneous(String body, JCDiagnostic diag) { this.body = body; @@ -422,11 +615,6 @@ public abstract class DCTree implements DocTree { return diag; } - @Override - public JCTree getTree() { - return null; - } - @Override public int getStartPosition() { return pos; @@ -434,14 +622,19 @@ public abstract class DCTree implements DocTree { @Override public int getPreferredPosition() { - return pos + body.length() - 1; + return prefPos == NOPOS ? pos + body.length() - 1 : prefPos; } @Override - public int getEndPosition(EndPosTable endPosTable) { + public int getEndPosition() { return pos + body.length(); } + public DCErroneous setPrefPos(int prefPos) { + this.prefPos = prefPos; + return this; + } + } public static class DCHidden extends DCBlockTag implements HiddenTree { diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/DocTreeMaker.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/DocTreeMaker.java index b885becb7d3..392e1b51563 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/DocTreeMaker.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/DocTreeMaker.java @@ -126,9 +126,6 @@ public class DocTreeMaker implements DocTreeFactory { */ public int pos = Position.NOPOS; - /** Access to diag factory for ErroneousTrees. */ - private final JCDiagnostic.Factory diags; - private final JavacTrees trees; /** Utility class to parse reference signatures. */ @@ -138,7 +135,6 @@ public class DocTreeMaker implements DocTreeFactory { */ protected DocTreeMaker(Context context) { context.put(treeMakerKey, this); - diags = JCDiagnostic.Factory.instance(context); this.pos = Position.NOPOS; trees = JavacTrees.instance(context); referenceParser = new ReferenceParser(ParserFactory.instance(context)); @@ -153,13 +149,6 @@ public class DocTreeMaker implements DocTreeFactory { return this; } - /** Reassign current position. - */ - public DocTreeMaker at(DiagnosticPosition pos) { - this.pos = (pos == null ? Position.NOPOS : pos.getStartPosition()); - return this; - } - @Override @DefinedBy(Api.COMPILER_TREE) public DCAttribute newAttributeTree(Name name, ValueKind vkind, List value) { DCAttribute tree = new DCAttribute(name, vkind, cast(value)); @@ -289,12 +278,6 @@ public class DocTreeMaker implements DocTreeFactory { return tree; } - public DCErroneous newErroneousTree(String text, DiagnosticSource diagSource, String code, Object... args) { - DCErroneous tree = new DCErroneous(text, diags, diagSource, code, args); - tree.pos = pos; - return tree; - } - @Override @DefinedBy(Api.COMPILER_TREE) public DCThrows newExceptionTree(ReferenceTree name, List description) { // TODO: verify the reference is just to a type (not a field or method) @@ -720,7 +703,7 @@ public class DocTreeMaker implements DocTreeFactory { } /* - * Returns the position of the the first non-white space + * Returns the position of the first non-whitespace character. */ private int skipWhiteSpace(String s, int start) { for (int i = start; i < s.length(); i++) { diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/AbstractLog.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/AbstractLog.java index 6bdefeda9ba..d303b5f710f 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/AbstractLog.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/AbstractLog.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,7 +50,7 @@ import com.sun.tools.javac.util.JCDiagnostic.SimpleDiagnosticPosition; public abstract class AbstractLog { /** Factory for diagnostics */ - protected JCDiagnostic.Factory diags; + public final JCDiagnostic.Factory diags; /** The file that's currently being translated. */ diff --git a/src/jdk.compiler/share/classes/jdk/internal/shellsupport/doc/JavadocHelper.java b/src/jdk.compiler/share/classes/jdk/internal/shellsupport/doc/JavadocHelper.java index f23224de5e8..08ee400aebd 100644 --- a/src/jdk.compiler/share/classes/jdk/internal/shellsupport/doc/JavadocHelper.java +++ b/src/jdk.compiler/share/classes/jdk/internal/shellsupport/doc/JavadocHelper.java @@ -495,7 +495,7 @@ public abstract class JavadocHelper implements AutoCloseable { //if there is a newline immediately behind this tree, insert behind //the newline: long endPos = sp.getEndPosition(null, dcTree, tree); - if (endPos >= 0) { + if (endPos >= offset) { if (endPos - offset + 1 < docComment.length() && docComment.charAt((int) (endPos - offset + 1)) == '\n') { endPos++; diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/DocLint.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/DocLint.java index 5ef7c1ada2b..9f1a290ba20 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/DocLint.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/DocLint.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -287,7 +287,6 @@ public class DocLint extends com.sun.tools.doclint.DocLint { void visitDecl(Tree tree, Name name) { TreePath p = getCurrentPath(); DocCommentTree dc = env.trees.getDocCommentTree(p); - checker.scan(dc, p); } }; diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/JavadocLog.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/JavadocLog.java index 92b7115e1fc..8409169968b 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/JavadocLog.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/JavadocLog.java @@ -45,13 +45,15 @@ import javax.tools.FileObject; import javax.tools.ForwardingFileObject; import javax.tools.JavaFileObject; +import jdk.javadoc.doclet.Reporter; + import com.sun.source.doctree.CommentTree; import com.sun.source.doctree.DocTree; import com.sun.source.doctree.DocTypeTree; import com.sun.source.doctree.ReferenceTree; import com.sun.source.doctree.TextTree; +import com.sun.tools.javac.tree.DCTree.DCDocComment; import com.sun.tools.javac.tree.DCTree; -import jdk.javadoc.doclet.Reporter; import com.sun.tools.javac.tree.EndPosTable; import com.sun.tools.javac.util.Context.Factory; @@ -278,12 +280,13 @@ public class JavadocLog extends Log implements Reporter { DiagnosticSource ds = getDiagnosticSource(path); DCTree.DCDocComment docComment = (DCTree.DCDocComment) path.getDocComment(); - DCTree tree = (DCTree) path.getLeaf(); + DCTree docTree = (DCTree) path.getLeaf(); // note: it is important to evaluate the offsets in the context of the position // within the comment text, and not in the context of the overall source text - int sStart = (int) tree.getSourcePosition(docComment, start); - int sPos = (int) tree.getSourcePosition(docComment, pos); - int sEnd = (int) tree.getSourcePosition(docComment, end); + int dtStart = docTree.getStartPosition(); + int sStart = docComment.getSourcePosition(dtStart + start); + int sPos = docComment.getSourcePosition(dtStart + pos); + int sEnd = docComment.getSourcePosition(dtStart + end); DiagnosticPosition dp = createDiagnosticPosition(null, sStart, sPos, sEnd); report(dt, flags, ds, dp, message); @@ -292,7 +295,7 @@ public class JavadocLog extends Log implements Reporter { private int getSourcePos(DocTreePath path, int offset) { DCTree.DCDocComment docComment = (DCTree.DCDocComment) path.getDocComment(); DCTree tree = (DCTree) path.getLeaf(); - return (int) tree.getSourcePosition(docComment, offset); + return docComment.getSourcePosition(tree.getStartPosition() + offset); } @Override // Reporter @@ -566,11 +569,9 @@ public class JavadocLog extends Log implements Reporter { * @return the diagnostic position */ private DiagnosticPosition getDiagnosticPosition(DocTreePath path) { - DocSourcePositions posns = getSourcePositions(); - CompilationUnitTree compUnit = path.getTreePath().getCompilationUnit(); - int start = (int) posns.getStartPosition(compUnit, path.getDocComment(), path.getLeaf()); - int end = (int) posns.getEndPosition(compUnit, path.getDocComment(), path.getLeaf()); - return createDiagnosticPosition(null, start, start, end); + DCDocComment dc = (DCDocComment) path.getDocComment(); + DCTree dcTree = (DCTree) path.getLeaf(); + return dcTree.pos(dc); } /** @@ -657,7 +658,7 @@ public class JavadocLog extends Log implements Reporter { } /** - * Returns the diagnostic source for an documentation tree node. + * Returns the diagnostic source for a documentation tree node. * * @param path the path for the documentation tree node * @return the diagnostic source diff --git a/test/langtools/tools/doclint/CrashInAnnotateTest.out b/test/langtools/tools/doclint/CrashInAnnotateTest.out index 74cffab6173..0275032554e 100644 --- a/test/langtools/tools/doclint/CrashInAnnotateTest.out +++ b/test/langtools/tools/doclint/CrashInAnnotateTest.out @@ -1,7 +1,7 @@ -CrashInAnnotateTest.java:10:5: compiler.err.proc.messager: annotations not allowed -CrashInAnnotateTest.java:11:5: compiler.err.proc.messager: syntax error in reference -CrashInAnnotateTest.java:16:5: compiler.err.proc.messager: annotations not allowed -CrashInAnnotateTest.java:21:5: compiler.err.proc.messager: syntax error in reference -CrashInAnnotateTest.java:24:5: compiler.err.proc.messager: syntax error in reference -CrashInAnnotateTest.java:25:5: compiler.err.proc.messager: syntax error in reference +CrashInAnnotateTest.java:10:20: compiler.err.proc.messager: annotations not allowed +CrashInAnnotateTest.java:11:37: compiler.err.proc.messager: syntax error in reference +CrashInAnnotateTest.java:16:39: compiler.err.proc.messager: annotations not allowed +CrashInAnnotateTest.java:21:23: compiler.err.proc.messager: syntax error in reference +CrashInAnnotateTest.java:24:54: compiler.err.proc.messager: syntax error in reference +CrashInAnnotateTest.java:25:37: compiler.err.proc.messager: syntax error in reference 6 errors \ No newline at end of file diff --git a/test/langtools/tools/doclint/EndWithIdentifierTest.out b/test/langtools/tools/doclint/EndWithIdentifierTest.out index 41f15e40653..48b473414d8 100644 --- a/test/langtools/tools/doclint/EndWithIdentifierTest.out +++ b/test/langtools/tools/doclint/EndWithIdentifierTest.out @@ -1,12 +1,12 @@ EndWithIdentifierTest.java:17: error: syntax error in reference /**{@link*/ - ^ + ^ EndWithIdentifierTest.java:22: error: reference not found * @see List*/ ^ EndWithIdentifierTest.java:25: error: semicolon missing /**&*/ - ^ + ^ EndWithIdentifierTest.java:28: error: malformed HTML /** files = new ArrayList<>(); + try (DirectoryStream ds = Files.newDirectoryStream(src, this::isDocCommentTesterTest)) { + for (Path p : ds) { + files.add(fm.getJavaFileObjects(p).iterator().next()); + } + } + + JavacTask task = (JavacTask) compiler.getTask(null, null, null, null, null, files); + + DocTrees trees = DocTrees.instance(task); + Map counts = new TreeMap<>(); + DocTreeScanner dtScanner = new DocTreeScanner() { + @Override + public Object scan(DocTree node, Object o) { + if (node != null) { + DocTree.Kind k = node.getKind(); + counts.put(k, counts.computeIfAbsent(k, k_ -> 0) + 1); + } + return super.scan(node, o); + } + }; + + TreePathScanner declScanner = new DeclScanner() { + @Override + void visitDecl(Tree tree, Name name) { + TreePath path = getCurrentPath(); + DocCommentTree dc = trees.getDocCommentTree(path); + dtScanner.scan(dc, null); + } + }; + + + task.addTaskListener(new TaskListener() { + @Override + public void finished(TaskEvent e) { + if (e.getKind() == TaskEvent.Kind.PARSE) { + declScanner.scan(e.getCompilationUnit(), null); + } + } + }); + + task.parse(); + + counts.forEach((k, v) -> System.err.printf("%20s: %5d%n", k, v)); + + // Note: DOC_TYPE cannot appear in any doc comment in a *.java file, + // and OTHER is a special value that never appears in any standard DocTree node. + List notFound = Stream.of(DocTree.Kind.values()) + .filter(k -> switch (k) { case DOC_TYPE, OTHER -> false; default -> true; }) + .filter(k -> !counts.containsKey(k)) + .toList(); + + if (!notFound.isEmpty()) { + System.err.println(); + System.err.println("ERROR: The following kinds were not found: " + notFound.stream() + .map(DocTree.Kind::name) + .collect(Collectors.joining(", "))); + System.err.println(); + throw new Exception("Not Found: " + notFound); + } + } + + boolean isDocCommentTesterTest(Path p) throws IOException { + if (!p.getFileName().toString().endsWith(".java")) { + return false; + } + + String marker = " * @run main DocCommentTester " + p.getFileName(); + for (String line : Files.readAllLines(p)) { + if (line.equals(marker)) { + return true; + } else if (line.contains("{")) { + return false; + } + } + return false; + } + + static abstract class DeclScanner extends TreePathScanner { + abstract void visitDecl(Tree tree, Name name); + + @Override + public Void visitClass(ClassTree tree, Void ignore) { + super.visitClass(tree, ignore); + visitDecl(tree, tree.getSimpleName()); + return null; + } + + @Override + public Void visitMethod(MethodTree tree, Void ignore) { + super.visitMethod(tree, ignore); + visitDecl(tree, tree.getName()); + return null; + } + + @Override + public Void visitVariable(VariableTree tree, Void ignore) { + super.visitVariable(tree, ignore); + visitDecl(tree, tree.getName()); + return null; + } + } +} diff --git a/test/langtools/tools/javac/doctree/DeprecatedTest.java b/test/langtools/tools/javac/doctree/DeprecatedTest.java index 8d9a59e565f..ac5923afa19 100644 --- a/test/langtools/tools/javac/doctree/DeprecatedTest.java +++ b/test/langtools/tools/javac/doctree/DeprecatedTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 7021614 + * @bug 7021614 8273244 * @summary extend com.sun.source API to support parsing javadoc comments * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.file diff --git a/test/langtools/tools/javac/doctree/DocCommentTester.java b/test/langtools/tools/javac/doctree/DocCommentTester.java index 6270cec2ddc..4849521b1a5 100644 --- a/test/langtools/tools/javac/doctree/DocCommentTester.java +++ b/test/langtools/tools/javac/doctree/DocCommentTester.java @@ -37,6 +37,7 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; import javax.lang.model.element.Name; +import javax.tools.Diagnostic; import javax.tools.JavaFileObject; import javax.tools.StandardJavaFileManager; @@ -57,14 +58,16 @@ import com.sun.tools.javac.tree.DCTree.DCDocComment; import com.sun.tools.javac.tree.DCTree.DCErroneous; import com.sun.tools.javac.tree.DocPretty; +/** + * A class to test doc comment trees. + * It is normally executed by calling {@code main}, providing a source file to be analyzed. + * The file is scanned for top-level declarations, and the comment for any such declarations + * is analyzed with a series of "checkers". + * + * @see DocCommentTester.ASTChecker#main(String... args) + */ public class DocCommentTester { - public static final String BI_MARKER = "BREAK_ITERATOR"; - public final boolean useBreakIterator; - - public DocCommentTester(boolean useBreakIterator) { - this.useBreakIterator = useBreakIterator; - } public static void main(String... args) throws Exception { ArrayList list = new ArrayList<>(Arrays.asList(args)); if (!list.isEmpty() && "-useBreakIterator".equals(list.get(0))) { @@ -75,6 +78,13 @@ public class DocCommentTester { } } + public static final String BI_MARKER = "BREAK_ITERATOR"; + public final boolean useBreakIterator; + + public DocCommentTester(boolean useBreakIterator) { + this.useBreakIterator = useBreakIterator; + } + public void run(List args) throws Exception { String testSrc = System.getProperty("test.src"); @@ -98,7 +108,9 @@ public class DocCommentTester { final Checker[] checkers = { new ASTChecker(this, trees), new PosChecker(this, trees), - new PrettyChecker(this, trees) + new PrettyChecker(this, trees), + new RangeChecker(this, trees), + new StartEndPosChecker(this, trees) }; DeclScanner d = new DeclScanner() { @@ -194,7 +206,7 @@ public class DocCommentTester { int errors; /** - * Verify the structure of the DocTree AST by comparing it against golden text. + * Verifies the structure of the DocTree AST by comparing it against golden text. */ static class ASTChecker extends Checker { static final String NEWLINE = System.getProperty("line.separator"); @@ -280,7 +292,7 @@ public class DocCommentTester { final DocTrees trees = DocTrees.instance(t); DeclScanner d = new DeclScanner() { - Printer p = new Printer(); + final Printer p = new Printer(); String source; @Override @@ -796,7 +808,7 @@ public class DocCommentTester { } /** - * Verify the reported tree positions by comparing the characters found + * Verifies the reported tree positions by comparing the characters found * at and after the reported position with the beginning of the pretty- * printed text. */ @@ -811,16 +823,16 @@ public class DocCommentTester { final CharSequence cs = fo.getCharContent(true); final DCDocComment dc = (DCDocComment) trees.getDocCommentTree(path); - DCTree t = (DCTree) trees.getDocCommentTree(path); DocTreeScanner scanner = new DocTreeScanner<>() { @Override public Void scan(DocTree node, Void ignore) { if (node != null) { try { + DCTree dcTree = (DCTree) node; String expect = getExpectText(node); - long pos = ((DCTree) node).getSourcePosition(dc); - String found = getFoundText(cs, (int) pos, expect.length()); + long startPos = dc.getSourcePosition(dcTree.getStartPosition()); + String found = getFoundText(cs, (int) startPos, expect.length()); if (!found.equals(expect)) { System.err.println("expect: " + expect); System.err.println("found: " + found); @@ -828,7 +840,7 @@ public class DocCommentTester { } } catch (StringIndexOutOfBoundsException e) { - error(node.getClass() + ": " + e.toString()); + error(node.getClass() + ": " + e); e.printStackTrace(); } } @@ -836,7 +848,7 @@ public class DocCommentTester { } }; - scanner.scan(t, null); + scanner.scan(dc, null); } String getExpectText(DocTree t) { @@ -857,7 +869,7 @@ public class DocCommentTester { } /** - * Verify the pretty printed text against a normalized form of the + * Verifies the pretty printed text against a normalized form of the * original doc comment. */ static class PrettyChecker extends Checker { @@ -905,9 +917,9 @@ public class DocCommentTester { } String normalizeFragment(String s) { - return s.replaceAll("\\{@docRoot\\s+\\}", "{@docRoot}") - .replaceAll("\\{@inheritDoc\\s+\\}", "{@inheritDoc}") - .replaceAll("(\\{@value\\s+[^}]+)\\s+(\\})", "$1$2") + return s.replaceAll("\\{@docRoot\\s+}", "{@docRoot}") + .replaceAll("\\{@inheritDoc\\s+}", "{@inheritDoc}") + .replaceAll("(\\{@value\\s+[^}]+)\\s+(})", "$1$2") .replaceAll("\n[ \t]+@", "\n@"); } @@ -919,21 +931,166 @@ public class DocCommentTester { sb.append(' '); } switch (ch) { - case '{': + case '{' -> depth++; - break; - case '}': + + case '}' -> { depth--; if (depth < 0) { sb.append(ch); return i + 1; } - break; + } } sb.append(ch); } return s.length(); } } + + + /** + * Verifies the general "left to right" constraints for the positions of + * nodes in the DocTree AST. + */ + static class RangeChecker extends Checker { + int cursor = 0; + + RangeChecker(DocCommentTester test, DocTrees docTrees) { + test.super(docTrees); + } + + @Override + void check(TreePath path, Name name) throws Exception { + final DCDocComment dc = (DCDocComment) trees.getDocCommentTree(path); + + DocTreeScanner scanner = new DocTreeScanner<>() { + @Override + public Void scan(DocTree node, Void ignore) { + if (node instanceof DCTree dcTree) { + int start = dcTree.getStartPosition(); + int pref = dcTree.getPreferredPosition(); + int end = dcTree.getEndPosition(); + + // check within the node, start <= pref <= end + check("start:pref", dcTree, start, pref); + check("pref:end", dcTree, pref, end); + + // check cursor <= start + check("cursor:start", dcTree, cursor, start); + cursor = start; + + // recursively scan any children, updating the cursor + super.scan(node, ignore); + + // check cursor <= end + check("cursor:end", dcTree, cursor, end); + cursor = end; + } + return null; + } + }; + + cursor = 0; + scanner.scan(dc, null); + + } + + void check(String name, DCTree tree, int first, int second) { + if (!(first <= second)) { + error(name, tree, first, second); + } + } + + private void error(String name, DCTree tree, int first, int second) { + String t = tree.toString().replaceAll("\\s+", " "); + if (t.length() > 32) { + t = t.substring(0, 15) + "..." + t.substring(t.length() - 15); + } + error("Checking " + name + " for " + tree.getKind() + " `" + t + "`; first:" + first + ", second:" + second); + + } + } + + /** + * Verifies that the start and end positions of all nodes in a DocCommentTree point to the + * expected characters in the source code. + * + * The expected characters are derived from the beginning and end of the DocPretty output + * for each node. Note that while the whitespace within the DocPretty output may not exactly + * match the original source code, the first and last characters should match. + */ + static class StartEndPosChecker extends Checker { + + StartEndPosChecker(DocCommentTester test, DocTrees docTrees) { + test.super(docTrees); + } + + @Override + void check(TreePath path, Name name) throws Exception { + final DCDocComment dc = (DCDocComment) trees.getDocCommentTree(path); + JavaFileObject jfo = path.getCompilationUnit().getSourceFile(); + CharSequence content = jfo.getCharContent(true); + + DocTreeScanner scanner = new DocTreeScanner<>() { + @Override + public Void scan(DocTree node, Void ignore) { + if (node instanceof DCTree dcTree) { + int start = dc.getSourcePosition(dc.getStartPosition()); + int end = dc.getSourcePosition(dcTree.getEndPosition()); + + try { + StringWriter out = new StringWriter(); + DocPretty dp = new DocPretty(out); + dp.print(trees.getDocCommentTree(path)); + String pretty = out.toString(); + + if (pretty.isEmpty()) { + if (start != end) { + error("Error: expected content is empty, but actual content is not: " + + dcTree.getKind() + " [" + start + "," + end + ")" + + ": \"" + content.subSequence(start, end) + "\"" ); + } + } else { + check(dcTree, "start", content, start, pretty, 0); + check(dcTree, "end", content, end - 1, pretty, pretty.length() - 1); + } + + } catch (IOException e) { + error("Error generating DocPretty for tree at position " + start + "; " + e); + } + } + return null; + } + }; + + scanner.scan(dc, null); + } + + void check(DCTree tree, String label, CharSequence content, int contentIndex, String pretty, int prettyIndex) { + if (contentIndex == Diagnostic.NOPOS) { + error("NOPOS for content " + label + ": " + tree.getKind() + " >>" + abbrev(pretty, MAX) + "<<"); + } + + char contentChar = content.charAt(contentIndex); + char prettyChar = pretty.charAt(prettyIndex); + if (contentChar != prettyChar) { + error ("Mismatch for content " + label + ": " + + "expect: '" + prettyChar + "', found: '" + contentChar + "' at position " + contentIndex + ": " + + tree.getKind() + " >>" + abbrev(pretty, MAX) + "<<"); + } + } + + static final int MAX = 64; + + static String abbrev(String s, int max) { + s = s.replaceAll("\\s+", " "); + if (s.length() > max) { + s = s.substring(0, max / 2 - 2) + " ... " + s.substring(max / 2 + 2); + } + return s; + } + + } } diff --git a/test/langtools/tools/javac/doctree/DocRootTest.java b/test/langtools/tools/javac/doctree/DocRootTest.java index c48b4b74789..674e8185182 100644 --- a/test/langtools/tools/javac/doctree/DocRootTest.java +++ b/test/langtools/tools/javac/doctree/DocRootTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 7021614 + * @bug 7021614 8273244 * @summary extend com.sun.source API to support parsing javadoc comments * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.file diff --git a/test/langtools/tools/javac/doctree/ElementTest.java b/test/langtools/tools/javac/doctree/ElementTest.java index c2346b20a7d..911814c5880 100644 --- a/test/langtools/tools/javac/doctree/ElementTest.java +++ b/test/langtools/tools/javac/doctree/ElementTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 7021614 8078320 8247788 + * @bug 7021614 8078320 8247788 8273244 * @summary extend com.sun.source API to support parsing javadoc comments * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.file diff --git a/test/langtools/tools/javac/doctree/EntityTest.java b/test/langtools/tools/javac/doctree/EntityTest.java index 3e7517d2715..4e75a733b30 100644 --- a/test/langtools/tools/javac/doctree/EntityTest.java +++ b/test/langtools/tools/javac/doctree/EntityTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 7021614 + * @bug 7021614 8273244 * @summary extend com.sun.source API to support parsing javadoc comments * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.file diff --git a/test/langtools/tools/javac/doctree/ExceptionTest.java b/test/langtools/tools/javac/doctree/ExceptionTest.java index 98a2ac285f5..600b428b4cf 100644 --- a/test/langtools/tools/javac/doctree/ExceptionTest.java +++ b/test/langtools/tools/javac/doctree/ExceptionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 7021614 + * @bug 7021614 8273244 * @summary extend com.sun.source API to support parsing javadoc comments * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.file diff --git a/test/langtools/tools/javac/doctree/FirstSentenceTest.java b/test/langtools/tools/javac/doctree/FirstSentenceTest.java index a93726a891c..3a973d87bd2 100644 --- a/test/langtools/tools/javac/doctree/FirstSentenceTest.java +++ b/test/langtools/tools/javac/doctree/FirstSentenceTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 7021614 8078320 8132096 + * @bug 7021614 8078320 8132096 8273244 * @summary extend com.sun.source API to support parsing javadoc comments * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.file @@ -38,7 +38,7 @@ class FirstSentenceTest { /** */ void empty() { } /* -DocComment[DOC_COMMENT, pos:-1 +DocComment[DOC_COMMENT, pos:0 firstSentence: empty body: empty block tags: empty @@ -46,7 +46,7 @@ DocComment[DOC_COMMENT, pos:-1 */ /* BREAK_ITERATOR -DocComment[DOC_COMMENT, pos:-1 +DocComment[DOC_COMMENT, pos:0 firstSentence: empty body: empty block tags: empty diff --git a/test/langtools/tools/javac/doctree/HiddenTest.java b/test/langtools/tools/javac/doctree/HiddenTest.java index 9a8c19b27d8..7ed981780e3 100644 --- a/test/langtools/tools/javac/doctree/HiddenTest.java +++ b/test/langtools/tools/javac/doctree/HiddenTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 8073100 + * @bug 8073100 8273244 * @summary extend com.sun.source API to support parsing javadoc comments * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.file diff --git a/test/langtools/tools/javac/doctree/InPreTest.java b/test/langtools/tools/javac/doctree/InPreTest.java index 78730a4d108..1929c221bc7 100644 --- a/test/langtools/tools/javac/doctree/InPreTest.java +++ b/test/langtools/tools/javac/doctree/InPreTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 8078320 + * @bug 8078320 8273244 * @summary extend com.sun.source API to support parsing javadoc comments * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.file diff --git a/test/langtools/tools/javac/doctree/IndexTest.java b/test/langtools/tools/javac/doctree/IndexTest.java index 0cbd079a13c..f41477a72c8 100644 --- a/test/langtools/tools/javac/doctree/IndexTest.java +++ b/test/langtools/tools/javac/doctree/IndexTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 8144287 + * @bug 8144287 8273244 * @summary extend com.sun.source API to support parsing javadoc comments * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.file diff --git a/test/langtools/tools/javac/doctree/InheritDocTest.java b/test/langtools/tools/javac/doctree/InheritDocTest.java index 403441e1d28..3034f784893 100644 --- a/test/langtools/tools/javac/doctree/InheritDocTest.java +++ b/test/langtools/tools/javac/doctree/InheritDocTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 7021614 + * @bug 7021614 8273244 * @summary extend com.sun.source API to support parsing javadoc comments * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.file diff --git a/test/langtools/tools/javac/doctree/LinkPlainTest.java b/test/langtools/tools/javac/doctree/LinkPlainTest.java index 695640684bd..04ac81ffe7c 100644 --- a/test/langtools/tools/javac/doctree/LinkPlainTest.java +++ b/test/langtools/tools/javac/doctree/LinkPlainTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 7021614 + * @bug 7021614 8273244 * @summary extend com.sun.source API to support parsing javadoc comments * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.file diff --git a/test/langtools/tools/javac/doctree/LinkTest.java b/test/langtools/tools/javac/doctree/LinkTest.java index 6d3a8897de8..79e2a9d43d1 100644 --- a/test/langtools/tools/javac/doctree/LinkTest.java +++ b/test/langtools/tools/javac/doctree/LinkTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 7021614 + * @bug 7021614 8273244 * @summary extend com.sun.source API to support parsing javadoc comments * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.file diff --git a/test/langtools/tools/javac/doctree/LiteralTest.java b/test/langtools/tools/javac/doctree/LiteralTest.java index 2b68ed23c94..38592ab9e4f 100644 --- a/test/langtools/tools/javac/doctree/LiteralTest.java +++ b/test/langtools/tools/javac/doctree/LiteralTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 7021614 8241780 + * @bug 7021614 8241780 8273244 * @summary extend com.sun.source API to support parsing javadoc comments * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.file diff --git a/test/langtools/tools/javac/doctree/ParamTest.java b/test/langtools/tools/javac/doctree/ParamTest.java index f8bc76ba491..676f201b4a2 100644 --- a/test/langtools/tools/javac/doctree/ParamTest.java +++ b/test/langtools/tools/javac/doctree/ParamTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 7021614 + * @bug 7021614 8273244 * @summary extend com.sun.source API to support parsing javadoc comments * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.file diff --git a/test/langtools/tools/javac/doctree/ProvidesTest.java b/test/langtools/tools/javac/doctree/ProvidesTest.java index 6c1e6745928..132a29982b1 100644 --- a/test/langtools/tools/javac/doctree/ProvidesTest.java +++ b/test/langtools/tools/javac/doctree/ProvidesTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 8160196 + * @bug 8160196 8273244 * @summary Module summary page should display information based on "api" or "detail" mode. * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.file diff --git a/test/langtools/tools/javac/doctree/ReturnTest.java b/test/langtools/tools/javac/doctree/ReturnTest.java index 5b6dfa3a18b..3db7651dd9a 100644 --- a/test/langtools/tools/javac/doctree/ReturnTest.java +++ b/test/langtools/tools/javac/doctree/ReturnTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 7021614 + * @bug 7021614 8273244 * @summary extend com.sun.source API to support parsing javadoc comments * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.file diff --git a/test/langtools/tools/javac/doctree/SeeTest.java b/test/langtools/tools/javac/doctree/SeeTest.java index 8ded81aab94..24d5f85036e 100644 --- a/test/langtools/tools/javac/doctree/SeeTest.java +++ b/test/langtools/tools/javac/doctree/SeeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 7021614 8031212 + * @bug 7021614 8031212 8273244 * @summary extend com.sun.source API to support parsing javadoc comments * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.file diff --git a/test/langtools/tools/javac/doctree/SerialDataTest.java b/test/langtools/tools/javac/doctree/SerialDataTest.java index b73d011b971..f46af82eec4 100644 --- a/test/langtools/tools/javac/doctree/SerialDataTest.java +++ b/test/langtools/tools/javac/doctree/SerialDataTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 7021614 + * @bug 7021614 8273244 * @summary extend com.sun.source API to support parsing javadoc comments * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.file diff --git a/test/langtools/tools/javac/doctree/SerialFieldTest.java b/test/langtools/tools/javac/doctree/SerialFieldTest.java index ac389af8ec8..c9a36915502 100644 --- a/test/langtools/tools/javac/doctree/SerialFieldTest.java +++ b/test/langtools/tools/javac/doctree/SerialFieldTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 7021614 + * @bug 7021614 8273244 * @summary extend com.sun.source API to support parsing javadoc comments * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.file diff --git a/test/langtools/tools/javac/doctree/SerialTest.java b/test/langtools/tools/javac/doctree/SerialTest.java index 9760a0b7156..d45e7173e4f 100644 --- a/test/langtools/tools/javac/doctree/SerialTest.java +++ b/test/langtools/tools/javac/doctree/SerialTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 7021614 + * @bug 7021614 8273244 * @summary extend com.sun.source API to support parsing javadoc comments * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.file diff --git a/test/langtools/tools/javac/doctree/SinceTest.java b/test/langtools/tools/javac/doctree/SinceTest.java index d89e5597e0a..9325efc4cac 100644 --- a/test/langtools/tools/javac/doctree/SinceTest.java +++ b/test/langtools/tools/javac/doctree/SinceTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 7021614 + * @bug 7021614 8273244 * @summary extend com.sun.source API to support parsing javadoc comments * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.file diff --git a/test/langtools/tools/javac/doctree/SummaryTest.java b/test/langtools/tools/javac/doctree/SummaryTest.java index 11231bae122..d2dfa334b66 100644 --- a/test/langtools/tools/javac/doctree/SummaryTest.java +++ b/test/langtools/tools/javac/doctree/SummaryTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 8173425 + * @bug 8173425 8273244 * @summary extend com.sun.source API to support parsing javadoc comments * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.file diff --git a/test/langtools/tools/javac/doctree/SystemPropertyTest.java b/test/langtools/tools/javac/doctree/SystemPropertyTest.java index a7f56f0c00f..de3c6994d2f 100644 --- a/test/langtools/tools/javac/doctree/SystemPropertyTest.java +++ b/test/langtools/tools/javac/doctree/SystemPropertyTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 5076751 + * @bug 5076751 8273244 * @summary System properties documentation needed in javadocs * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.file diff --git a/test/langtools/tools/javac/doctree/TagTest.java b/test/langtools/tools/javac/doctree/TagTest.java index f23a9d6a07a..298ac8e7f0d 100644 --- a/test/langtools/tools/javac/doctree/TagTest.java +++ b/test/langtools/tools/javac/doctree/TagTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 7021614 8078320 + * @bug 7021614 8078320 8273244 * @summary extend com.sun.source API to support parsing javadoc comments * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.file diff --git a/test/langtools/tools/javac/doctree/ThrowableTest.java b/test/langtools/tools/javac/doctree/ThrowableTest.java index 3f3360afb06..e8a9dec0a77 100644 --- a/test/langtools/tools/javac/doctree/ThrowableTest.java +++ b/test/langtools/tools/javac/doctree/ThrowableTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 7021614 + * @bug 7021614 8273244 * @summary extend com.sun.source API to support parsing javadoc comments * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.file diff --git a/test/langtools/tools/javac/doctree/UsesTest.java b/test/langtools/tools/javac/doctree/UsesTest.java index 3d24ed065d6..bb4b7aecb98 100644 --- a/test/langtools/tools/javac/doctree/UsesTest.java +++ b/test/langtools/tools/javac/doctree/UsesTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 8160196 + * @bug 8160196 8273244 * @summary Module summary page should display information based on "api" or "detail" mode. * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.file diff --git a/test/langtools/tools/javac/doctree/ValueTest.java b/test/langtools/tools/javac/doctree/ValueTest.java index 941b2ae6abc..6c0a634f5c7 100644 --- a/test/langtools/tools/javac/doctree/ValueTest.java +++ b/test/langtools/tools/javac/doctree/ValueTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 7021614 + * @bug 7021614 8273244 * @summary extend com.sun.source API to support parsing javadoc comments * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.file diff --git a/test/langtools/tools/javac/doctree/VersionTest.java b/test/langtools/tools/javac/doctree/VersionTest.java index 9fa6ac7bbc3..ce6fba6ccec 100644 --- a/test/langtools/tools/javac/doctree/VersionTest.java +++ b/test/langtools/tools/javac/doctree/VersionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 7021614 + * @bug 7021614 8273244 * @summary extend com.sun.source API to support parsing javadoc comments * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.file diff --git a/test/langtools/tools/javac/doctree/positions/TestPosition.java b/test/langtools/tools/javac/doctree/positions/TestPosition.java index 9d527ad366e..6d66a84d83b 100644 --- a/test/langtools/tools/javac/doctree/positions/TestPosition.java +++ b/test/langtools/tools/javac/doctree/positions/TestPosition.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -77,7 +77,7 @@ public class TestPosition extends AbstractProcessor { new DocTreeScanner() { @Override public Void scan(DocTree node, Void p) { if (node != null) { - DocSourcePositions sp = (DocSourcePositions) trees.getSourcePositions(); //XXX: the cast??? + DocSourcePositions sp = trees.getSourcePositions(); int start = (int) sp.getStartPosition(testElement.getCompilationUnit(), docCommentTree, node); int end = (int) sp.getEndPosition(testElement.getCompilationUnit(), docCommentTree, node); String snippet = code.substring(start, end).replace(" \n", "!trailing-whitespace!\n"); diff --git a/test/langtools/tools/javac/tree/AbstractTreeScannerTest.java b/test/langtools/tools/javac/tree/AbstractTreeScannerTest.java index 8f7508d7034..ab870a72a4e 100644 --- a/test/langtools/tools/javac/tree/AbstractTreeScannerTest.java +++ b/test/langtools/tools/javac/tree/AbstractTreeScannerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -200,10 +200,11 @@ public abstract class AbstractTreeScannerTest { } /** - * Report an error for a specific tree node. - * @param file the source file for the tree - * @param t the tree node - * @param label an indication of the error + * Report an error for a specific tree node. + * + * @param file the source file for the tree + * @param tree the tree node + * @param msg an indication of the error */ void error(JavaFileObject file, Tree tree, String msg) { JCTree t = (JCTree) tree; @@ -211,15 +212,17 @@ public abstract class AbstractTreeScannerTest { } /** - * Report an error for a specific tree node. - * @param file the source file for the tree - * @param t the tree node - * @param label an indication of the error + * Report an error for a specific tree node. + * + * @param file the source file for the tree + * @param comment the top level doc tree node + * @param tree the tree node + * @param msg an indication of the error */ void error(JavaFileObject file, DocCommentTree comment, DocTree tree, String msg) { DCDocComment dc = (DCDocComment) comment; DCTree t = (DCTree) tree; - error(file.getName() + ":" + getLine(file, t.getSourcePosition(dc)) + ": " + msg + " " + trim(t, 64)); + error(file.getName() + ":" + getLine(file, dc.getSourcePosition(t.pos)) + ": " + msg + " " + trim(t, 64)); } /** -- GitLab From 9914e5c416b518f408837e31ba0a35138bfcadc7 Mon Sep 17 00:00:00 2001 From: Mikhailo Seledtsov Date: Mon, 4 Oct 2021 17:20:05 +0000 Subject: [PATCH 080/385] 8274610: Add linux-aarch64 to bootcycle build profiles Reviewed-by: erikj --- make/conf/jib-profiles.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/make/conf/jib-profiles.js b/make/conf/jib-profiles.js index 34fcf3bf35e..d14bd4814bf 100644 --- a/make/conf/jib-profiles.js +++ b/make/conf/jib-profiles.js @@ -633,7 +633,7 @@ var getJibProfilesProfiles = function (input, common, data) { // Bootcycle profiles runs the build with itself as the boot jdk. This can // be done in two ways. Either using the builtin bootcycle target in the // build system. Or by supplying the main jdk build as bootjdk to configure. - [ "linux-x64", "macosx-x64", "windows-x64" ] + [ "linux-x64", "macosx-x64", "windows-x64", "linux-aarch64" ] .forEach(function (name) { var bootcycleName = name + "-bootcycle"; var bootcyclePrebuiltName = name + "-bootcycle-prebuilt"; -- GitLab From 75d6688df9845ecb8f370b4cd2d5a36f13d3cdc0 Mon Sep 17 00:00:00 2001 From: Jonathan Gibbons Date: Mon, 4 Oct 2021 19:00:21 +0000 Subject: [PATCH 081/385] 8274745: ProblemList TestSnippetTag.java Reviewed-by: prappo --- test/langtools/ProblemList.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/langtools/ProblemList.txt b/test/langtools/ProblemList.txt index d9d8cfeeb9d..a59173917db 100644 --- a/test/langtools/ProblemList.txt +++ b/test/langtools/ProblemList.txt @@ -27,6 +27,8 @@ # # javadoc +jdk/javadoc/doclet/testSnippetTag/TestSnippetTag.java 8274744 generic-all + ########################################################################### # # jshell @@ -71,4 +73,3 @@ tools/sjavac/ClasspathDependencies.java ########################################################################### # # jdeps - -- GitLab From 7e757f6a2cbfd03ba9ac602b800d15ba33f6f5f4 Mon Sep 17 00:00:00 2001 From: Erik Gahlin Date: Mon, 4 Oct 2021 21:19:19 +0000 Subject: [PATCH 082/385] 8274559: JFR: Typo in 'jfr help configure' text Reviewed-by: iris, mikael --- src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Configure.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Configure.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Configure.java index a9a5889caca..037ad6dbf06 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Configure.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Configure.java @@ -86,7 +86,7 @@ final class Configure extends Command { stream.println(" (default.jfc). If 'none' is specified, the new"); stream.println(" configuration starts empty."); stream.println(); - stream.println(" --ouput The filename of the generated output file. If not"); + stream.println(" --output The filename of the generated output file. If not"); stream.println(" specified, the filename custom.jfc will be used."); stream.println(); stream.println(" option=value The option value to modify. For available options,"); -- GitLab From 2e542e33b81a53652956bb5e9636e7f4af5540f7 Mon Sep 17 00:00:00 2001 From: David Holmes Date: Mon, 4 Oct 2021 23:14:12 +0000 Subject: [PATCH 083/385] 8274349: ForkJoinPool.commonPool() does not work with 1 CPU Co-authored-by: Doug Lea Reviewed-by: shade, martin --- .../java/util/concurrent/ForkJoinPool.java | 2 +- .../concurrent/forkjoin/Uniprocessor.java | 46 +++++++++++++++++++ .../util/concurrent/tck/ForkJoinPoolTest.java | 40 ++++++++++++++-- 3 files changed, 84 insertions(+), 4 deletions(-) create mode 100644 test/jdk/java/util/concurrent/forkjoin/Uniprocessor.java diff --git a/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java b/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java index f6b8f10d87f..6ef1b0815e5 100644 --- a/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java +++ b/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java @@ -2561,7 +2561,7 @@ public class ForkJoinPool extends AbstractExecutorService { * overridden by system properties */ private ForkJoinPool(byte forCommonPoolOnly) { - int parallelism = Runtime.getRuntime().availableProcessors() - 1; + int parallelism = Math.max(1, Runtime.getRuntime().availableProcessors() - 1); ForkJoinWorkerThreadFactory fac = null; UncaughtExceptionHandler handler = null; try { // ignore exceptions in accessing/parsing properties diff --git a/test/jdk/java/util/concurrent/forkjoin/Uniprocessor.java b/test/jdk/java/util/concurrent/forkjoin/Uniprocessor.java new file mode 100644 index 00000000000..83171d2f4d3 --- /dev/null +++ b/test/jdk/java/util/concurrent/forkjoin/Uniprocessor.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 8274349 + * @run main/othervm -XX:ActiveProcessorCount=1 Uniprocessor + * @summary Check the default FJ pool has a reasonable default parallelism + * level in a uniprocessor environment. + */ + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ForkJoinPool; + +public class Uniprocessor { + + static volatile boolean done = false; + + public static void main(String[] args) throws InterruptedException { + // If the default parallelism were zero then this task would not + // complete and the test will timeout. + CountDownLatch ran = new CountDownLatch(1); + ForkJoinPool.commonPool().submit(() -> ran.countDown()); + ran.await(); + } +} diff --git a/test/jdk/java/util/concurrent/tck/ForkJoinPoolTest.java b/test/jdk/java/util/concurrent/tck/ForkJoinPoolTest.java index 781b7bffe6d..4703bc51483 100644 --- a/test/jdk/java/util/concurrent/tck/ForkJoinPoolTest.java +++ b/test/jdk/java/util/concurrent/tck/ForkJoinPoolTest.java @@ -51,6 +51,7 @@ import java.util.concurrent.ForkJoinWorkerThread; import java.util.concurrent.Future; import java.util.concurrent.RecursiveTask; import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.ReentrantLock; @@ -223,13 +224,46 @@ public class ForkJoinPoolTest extends JSR166TestCase { /** * getParallelism returns size set in constructor */ - public void testGetParallelism() { - ForkJoinPool p = new ForkJoinPool(1); + public void testGetParallelism_requestedValue() { + int parallelism = ThreadLocalRandom.current().nextInt(1, 4); + ForkJoinPool p = new ForkJoinPool(parallelism); try (PoolCleaner cleaner = cleaner(p)) { - assertEquals(1, p.getParallelism()); + assertEquals(parallelism, p.getParallelism()); } } + private static int availableProcessors() { + return Runtime.getRuntime().availableProcessors(); + } + + /** + * default pool parallelism is availableProcessors() + */ + public void testParallelism_defaultValue() { + ForkJoinPool p = new ForkJoinPool(); + try (PoolCleaner cleaner = cleaner(p)) { + assertEquals(availableProcessors(), p.getParallelism()); + } + } + + /** + * default common pool parallelism is max(1, availableProcessors() - 1) + * But getParallelism() returns 1 when property-requested parallelism is 0. + */ + public void testCommonPoolParallelism_defaultValue() { + if (!testImplementationDetails) return; + + Integer propertyParallelism = + Integer.getInteger( + "java.util.concurrent.ForkJoinPool.common.parallelism"); + + int expectedParallelism = (propertyParallelism == null) + ? Math.max(1, availableProcessors() - 1) + : Math.max(1, propertyParallelism); + assertEquals(expectedParallelism, + ForkJoinPool.commonPool().getParallelism()); + } + /** * getPoolSize returns number of started workers. */ -- GitLab From e43f540cde58ee973b97a943f14d3c60e064b801 Mon Sep 17 00:00:00 2001 From: Andrey Turbanov Date: Tue, 5 Oct 2021 00:53:17 +0000 Subject: [PATCH 084/385] 8274651: Possible race in FontDesignMetrics.KeyReference.dispose Reviewed-by: prr, serb --- .../share/classes/sun/font/FontDesignMetrics.java | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/java.desktop/share/classes/sun/font/FontDesignMetrics.java b/src/java.desktop/share/classes/sun/font/FontDesignMetrics.java index b024514ab47..c5f020991d4 100644 --- a/src/java.desktop/share/classes/sun/font/FontDesignMetrics.java +++ b/src/java.desktop/share/classes/sun/font/FontDesignMetrics.java @@ -188,16 +188,10 @@ public final class FontDesignMetrics extends FontMetrics { /* It is possible that since this reference object has been * enqueued, that a new metrics has been put into the table * for the same key value. So we'll test to see if the table maps - * to THIS reference. If its a new one, we'll leave it alone. - * It is possible that a new entry comes in after our test, but - * it is unlikely and if this were a problem we would need to - * synchronize all 'put' and 'remove' accesses to the cache which - * I would prefer not to do. + * to THIS reference. If it's a new one, we'll leave it alone. */ public void dispose() { - if (metricsCache.get(key) == this) { - metricsCache.remove(key); - } + metricsCache.remove(key, this); } } @@ -595,7 +589,7 @@ public final class FontDesignMetrics extends FontMetrics { // if the calculations in any other methods change this needs // to be changed too. // the 0.95 value used here and in the other methods allows some - // tiny fraction of leeway before rouding up. A higher value (0.99) + // tiny fraction of leeway before rounding up. A higher value (0.99) // caused some excessive rounding up. return (int)(roundingUpValue + descent + leading) - -- GitLab From 53d7e95bc637c8b629efc4587b2ae7961d719b00 Mon Sep 17 00:00:00 2001 From: Andrey Turbanov Date: Tue, 5 Oct 2021 06:39:29 +0000 Subject: [PATCH 085/385] 8274635: Use String.equals instead of String.compareTo in jdk.accessibility Reviewed-by: serb --- .../util/AccessibilityEventMonitor.java | 6 ++---- .../accessibility/internal/AccessBridge.java | 20 +++++++++---------- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/AccessibilityEventMonitor.java b/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/AccessibilityEventMonitor.java index e9a90e9e45c..79e0b4d2b09 100644 --- a/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/AccessibilityEventMonitor.java +++ b/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/AccessibilityEventMonitor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2021, Oracle and/or its affiliates. All rights reserved. * 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,10 +25,8 @@ package com.sun.java.accessibility.util; -import java.util.*; import java.beans.*; import java.awt.*; -import java.awt.event.*; import javax.accessibility.*; /** @@ -317,7 +315,7 @@ public class AccessibilityEventMonitor { // handle childbirth/death String name = e.getPropertyName(); - if (name.compareTo(AccessibleContext.ACCESSIBLE_CHILD_PROPERTY) == 0) { + if (name.equals(AccessibleContext.ACCESSIBLE_CHILD_PROPERTY)) { Object oldValue = e.getOldValue(); Object newValue = e.getNewValue(); diff --git a/src/jdk.accessibility/windows/classes/com/sun/java/accessibility/internal/AccessBridge.java b/src/jdk.accessibility/windows/classes/com/sun/java/accessibility/internal/AccessBridge.java index 072a7ad89af..faf041e269f 100644 --- a/src/jdk.accessibility/windows/classes/com/sun/java/accessibility/internal/AccessBridge.java +++ b/src/jdk.accessibility/windows/classes/com/sun/java/accessibility/internal/AccessBridge.java @@ -5240,7 +5240,7 @@ final public class AccessBridge { accessBridge.debugString("[INFO]: AccessibleContext: " + ac); String propertyName = e.getPropertyName(); - if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_CARET_PROPERTY) == 0) { + if (propertyName.equals(AccessibleContext.ACCESSIBLE_CARET_PROPERTY)) { int oldValue = 0; int newValue = 0; @@ -5253,7 +5253,7 @@ final public class AccessBridge { accessBridge.debugString("[INFO]: - about to call propertyCaretChange() old value: " + oldValue + "new value: " + newValue); accessBridge.propertyCaretChange(e, ac, oldValue, newValue); - } else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_DESCRIPTION_PROPERTY) == 0) { + } else if (propertyName.equals(AccessibleContext.ACCESSIBLE_DESCRIPTION_PROPERTY)) { String oldValue = null; String newValue = null; @@ -5266,7 +5266,7 @@ final public class AccessBridge { accessBridge.debugString("[INFO]: - about to call propertyDescriptionChange() old value: " + oldValue + "new value: " + newValue); accessBridge.propertyDescriptionChange(e, ac, oldValue, newValue); - } else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_NAME_PROPERTY) == 0) { + } else if (propertyName.equals(AccessibleContext.ACCESSIBLE_NAME_PROPERTY)) { String oldValue = null; String newValue = null; @@ -5279,12 +5279,12 @@ final public class AccessBridge { accessBridge.debugString("[INFO]: - about to call propertyNameChange() old value: " + oldValue + " new value: " + newValue); accessBridge.propertyNameChange(e, ac, oldValue, newValue); - } else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_SELECTION_PROPERTY) == 0) { + } else if (propertyName.equals(AccessibleContext.ACCESSIBLE_SELECTION_PROPERTY)) { accessBridge.debugString("[INFO]: - about to call propertySelectionChange() " + ac + " " + Thread.currentThread() + " " + e.getSource()); accessBridge.propertySelectionChange(e, ac); - } else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_STATE_PROPERTY) == 0) { + } else if (propertyName.equals(AccessibleContext.ACCESSIBLE_STATE_PROPERTY)) { String oldValue = null; String newValue = null; @@ -5301,11 +5301,11 @@ final public class AccessBridge { accessBridge.debugString("[INFO]: - about to call propertyStateChange()"); accessBridge.propertyStateChange(e, ac, oldValue, newValue); - } else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_TEXT_PROPERTY) == 0) { + } else if (propertyName.equals(AccessibleContext.ACCESSIBLE_TEXT_PROPERTY)) { accessBridge.debugString("[INFO]: - about to call propertyTextChange()"); accessBridge.propertyTextChange(e, ac); - } else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_VALUE_PROPERTY) == 0) { // strings 'cause of floating point, etc. + } else if (propertyName.equals(AccessibleContext.ACCESSIBLE_VALUE_PROPERTY)) { // strings 'cause of floating point, etc. String oldValue = null; String newValue = null; @@ -5318,10 +5318,10 @@ final public class AccessBridge { accessBridge.debugString("[INFO]: - about to call propertyDescriptionChange()"); accessBridge.propertyValueChange(e, ac, oldValue, newValue); - } else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY) == 0) { + } else if (propertyName.equals(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY)) { accessBridge.propertyVisibleDataChange(e, ac); - } else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_CHILD_PROPERTY) == 0) { + } else if (propertyName.equals(AccessibleContext.ACCESSIBLE_CHILD_PROPERTY)) { AccessibleContext oldAC = null; AccessibleContext newAC = null; Accessible a; @@ -5337,7 +5337,7 @@ final public class AccessBridge { accessBridge.debugString("[INFO]: - about to call propertyChildChange() old AC: " + oldAC + "new AC: " + newAC); accessBridge.propertyChildChange(e, ac, oldAC, newAC); - } else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_ACTIVE_DESCENDANT_PROPERTY) == 0) { + } else if (propertyName.equals(AccessibleContext.ACCESSIBLE_ACTIVE_DESCENDANT_PROPERTY)) { handleActiveDescendentEvent(e, ac); } } -- GitLab From 3953e0774c59c5e936e752aa08b6b6778e232994 Mon Sep 17 00:00:00 2001 From: Christian Hagedorn Date: Tue, 5 Oct 2021 07:02:06 +0000 Subject: [PATCH 086/385] 8271459: C2: Missing NegativeArraySizeException when creating StringBuilder with negative capacity Reviewed-by: roland, thartmann, neliasso --- src/hotspot/share/opto/stringopts.cpp | 53 +++++- .../stringopts/TestNegativeArraySize.java | 180 ++++++++++++++++++ .../compiler/lib/ir_framework/IRNode.java | 8 +- .../ir_framework/tests/TestIRMatching.java | 42 +++- 4 files changed, 276 insertions(+), 7 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/c2/irTests/stringopts/TestNegativeArraySize.java diff --git a/src/hotspot/share/opto/stringopts.cpp b/src/hotspot/share/opto/stringopts.cpp index 16507d97811..8c0a060d862 100644 --- a/src/hotspot/share/opto/stringopts.cpp +++ b/src/hotspot/share/opto/stringopts.cpp @@ -65,7 +65,8 @@ class StringConcat : public ResourceObj { StringMode, IntMode, CharMode, - StringNullCheckMode + StringNullCheckMode, + NegativeIntCheckMode }; StringConcat(PhaseStringOpts* stringopts, CallStaticJavaNode* end): @@ -122,12 +123,19 @@ class StringConcat : public ResourceObj { void push_string(Node* value) { push(value, StringMode); } + void push_string_null_check(Node* value) { push(value, StringNullCheckMode); } + + void push_negative_int_check(Node* value) { + push(value, NegativeIntCheckMode); + } + void push_int(Node* value) { push(value, IntMode); } + void push_char(Node* value) { push(value, CharMode); } @@ -502,13 +510,35 @@ StringConcat* PhaseStringOpts::build_candidate(CallStaticJavaNode* call) { #ifndef PRODUCT if (PrintOptimizeStringConcat) { tty->print("giving up because StringBuilder(null) throws exception"); - alloc->jvms()->dump_spec(tty); tty->cr(); + alloc->jvms()->dump_spec(tty); + tty->cr(); } #endif return NULL; } // StringBuilder(str) argument needs null check. sc->push_string_null_check(use->in(TypeFunc::Parms + 1)); + } else if (sig == ciSymbols::int_void_signature()) { + // StringBuilder(int) case. + Node* parm = use->in(TypeFunc::Parms + 1); + assert(parm != NULL, "must exist"); + const TypeInt* type = _gvn->type(parm)->is_int(); + if (type->_hi < 0) { + // Initial capacity argument is always negative in which case StringBuilder(int) throws + // a NegativeArraySizeException. Bail out from string opts. +#ifndef PRODUCT + if (PrintOptimizeStringConcat) { + tty->print("giving up because a negative argument is passed to StringBuilder(int) which " + "throws a NegativeArraySizeException"); + alloc->jvms()->dump_spec(tty); + tty->cr(); + } +#endif + return NULL; + } else if (type->_lo < 0) { + // Argument could be negative: We need a runtime check to throw NegativeArraySizeException in that case. + sc->push_negative_int_check(parm); + } } // The int variant takes an initial size for the backing // array so just treat it like the void version. @@ -1794,6 +1824,23 @@ void PhaseStringOpts::replace_string_concat(StringConcat* sc) { for (int argi = 0; argi < sc->num_arguments(); argi++) { Node* arg = sc->argument(argi); switch (sc->mode(argi)) { + case StringConcat::NegativeIntCheckMode: { + // Initial capacity argument might be negative in which case StringBuilder(int) throws + // a NegativeArraySizeException. Insert a runtime check with an uncommon trap. + const TypeInt* type = kit.gvn().type(arg)->is_int(); + assert(type->_hi >= 0 && type->_lo < 0, "no runtime int check needed"); + Node* p = __ Bool(__ CmpI(arg, kit.intcon(0)), BoolTest::ge); + IfNode* iff = kit.create_and_map_if(kit.control(), p, PROB_MIN, COUNT_UNKNOWN); + { + // Negative int -> uncommon trap. + PreserveJVMState pjvms(&kit); + kit.set_control(__ IfFalse(iff)); + kit.uncommon_trap(Deoptimization::Reason_intrinsic, + Deoptimization::Action_maybe_recompile); + } + kit.set_control(__ IfTrue(iff)); + break; + } case StringConcat::IntMode: { Node* string_size = int_stringSize(kit, arg); @@ -1963,6 +2010,8 @@ void PhaseStringOpts::replace_string_concat(StringConcat* sc) { for (int argi = 0; argi < sc->num_arguments(); argi++) { Node* arg = sc->argument(argi); switch (sc->mode(argi)) { + case StringConcat::NegativeIntCheckMode: + break; // Nothing to do, was only needed to add a runtime check earlier. case StringConcat::IntMode: { start = int_getChars(kit, arg, dst_array, coder, start, string_sizes->in(argi)); break; diff --git a/test/hotspot/jtreg/compiler/c2/irTests/stringopts/TestNegativeArraySize.java b/test/hotspot/jtreg/compiler/c2/irTests/stringopts/TestNegativeArraySize.java new file mode 100644 index 00000000000..9978d338494 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/irTests/stringopts/TestNegativeArraySize.java @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 8271459 + * @requires vm.compiler2.enabled + * @summary C2 applies string opts to StringBuilder object created with a negative size and misses the NegativeArraySizeException. + * @library /test/lib / + * @run driver compiler.c2.irTests.stringopts.TestNegativeArraySize + */ + +package compiler.c2.irTests.stringopts; + +import compiler.lib.ir_framework.*; +import jdk.test.lib.Asserts; + +public class TestNegativeArraySize { + + static int iFld; + + public static void main(String[] args) { + // Dont inline any StringBuilder methods for this IR test to check if string opts are applied or not. + TestFramework.runWithFlags("-XX:CompileCommand=dontinline,java.lang.StringBuilder::*"); + } + + @Test + @IR(failOn = {IRNode.ALLOC_OF, "StringBuilder", IRNode.CALL_OF_METHOD, "toString", IRNode.INTRINSIC_TRAP}) + static String positiveConst() { + // C2 knows that argument is 5 and applies string opts without runtime check. + StringBuilder sb = new StringBuilder(5); // StringBuilder object optimized away by string opts. + return sb.toString(); // Call optimized away by string opts. + } + + @Test + @IR(counts = {IRNode.ALLOC_OF, "StringBuilder", "1", IRNode.CALL_OF_METHOD, "toString", "1"}) + @IR(failOn = IRNode.INTRINSIC_TRAP) // No runtime check, we bail out of string opts + static String negativeConst() { + StringBuilder sb = new StringBuilder(-5); // C2 knows that we always have a negative int -> bail out of string opts + return sb.toString(); // Call stays due to bailout. + } + + @Run(test = "negativeConst") + static void runNegativeConst() { + try { + negativeConst(); + Asserts.fail("should have thrown exception"); + } catch (NegativeArraySizeException e) { + // Expected; + } + } + + @Test + @IR(failOn = {IRNode.ALLOC_OF, "StringBuilder", IRNode.CALL_OF_METHOD, "toString"}) + @IR(counts = {IRNode.INTRINSIC_TRAP, "1"}) // Uncommon trap of runtime check + static String positiveFld() { + // C2 does not know if iFld is positive or negative. It applies string opts but inserts a runtime check to + // bail out to interpreter. This path, however, is never taken because iFld is always positive. + StringBuilder sb = new StringBuilder(iFld); + return sb.toString(); + } + + @Run(test = "positiveFld") + static void runPositiveFld() { + iFld = 4; + positiveFld(); + } + + @Test + @IR(failOn = {IRNode.ALLOC_OF, "StringBuilder", IRNode.CALL_OF_METHOD, "toString"}) + @IR(counts = {IRNode.INTRINSIC_TRAP, "1"}) // Uncommon trap of runtime check + static String negativeFld() { + // C2 does not know if iFld is positive or negative. It applies string opts but inserts a runtime check to + // bail out to interpreter. This path is always taken because iFld is always negative. + StringBuilder sb = new StringBuilder(iFld); + return sb.toString(); + } + + @Run(test = "negativeFld") + static void runNegativeFld() { + iFld = -4; + try { + negativeFld(); + Asserts.fail("should have thrown exception"); + } catch (NegativeArraySizeException e) { + // Expected; + } + } + + @Test + @IR(failOn = {IRNode.ALLOC_OF, "StringBuilder", IRNode.CALL_OF_METHOD, "toString"}) + @IR(counts = {IRNode.INTRINSIC_TRAP, "1"}) // Uncommon trap of runtime check + static String maybeNegativeConst(boolean flag) { + // C2 knows that cap is between -5 and 5. It applies string opts but inserts a runtime check to + // bail out to interpreter. This path is sometimes taken and sometimes not. + int cap = flag ? 5 : -5; + StringBuilder sb = new StringBuilder(cap); + return sb.toString(); + } + + @Run(test = "maybeNegativeConst") + static void runMaybeNegativeConst() { + boolean flag = TestFramework.toggleBoolean(); + try { + maybeNegativeConst(flag); + Asserts.assertTrue(flag); + } catch (NegativeArraySizeException e) { + Asserts.assertFalse(flag); + } + } + + @Test + @IR(failOn = {IRNode.ALLOC_OF, "StringBuilder", IRNode.CALL_OF_METHOD, "toString", IRNode.INTRINSIC_TRAP}) + static String alwaysPositiveConst(boolean flag) { + // C2 knows that cap is between 1 and 100 and applies string opts without runtime check. + int cap = flag ? 1 : 100; + StringBuilder sb = new StringBuilder(cap); // Object optimized away. + return sb.toString(); // Optimized away. + } + + @Run(test = "alwaysPositiveConst") + static void runAlwaysPositiveConst() { + alwaysPositiveConst(TestFramework.toggleBoolean()); + } + + @Test + @IR(failOn = {IRNode.ALLOC_OF, "StringBuilder", IRNode.CALL_OF_METHOD, "toString"}) + @IR(counts = {IRNode.INTRINSIC_TRAP, "1"}) // Uncommon trap of runtime check + static String negativeArg(int cap) { + // C2 does not know if cap is positive or negative. It applies string opts but inserts a runtime check to + // bail out to interpreter. This path is always taken because cap is always negative. + StringBuilder sb = new StringBuilder(cap); + return sb.toString(); + } + + @Run(test = "negativeArg") + static void runNegativeArg() { + try { + negativeArg(-5); + Asserts.fail("should have thrown exception"); + } catch (NegativeArraySizeException e) { + // Expected + } + } + + @Test + @IR(failOn = {IRNode.ALLOC_OF, "StringBuilder", IRNode.CALL_OF_METHOD, "toString"}) + @IR(counts = {IRNode.INTRINSIC_TRAP, "1"}) // Uncommon trap of runtime check + static String positiveArg(int cap) { + // C2 does not know if cap is positive or negative. It applies string opts but inserts a runtime check to + // bail out to interpreter. This path, however, is never taken because cap is always positive. + StringBuilder sb = new StringBuilder(cap); + return sb.toString(); + } + + @Run(test = "positiveArg") + static void runPositiveArg() { + positiveArg(5); + } +} diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java index 92a6fc10d5e..a995cad3f2d 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java @@ -114,9 +114,10 @@ public class IRNode { public static final String COUNTEDLOOP = START + "CountedLoop\\b" + MID + END; public static final String COUNTEDLOOP_MAIN = START + "CountedLoop\\b" + MID + "main" + END; - public static final String CALL = START + "CallStaticJava" + MID + END; - public static final String DYNAMIC_CALL_OF_METHOD = COMPOSITE_PREFIX + START + "CallDynamicJava" + MID + IS_REPLACED + END; - public static final String STATIC_CALL_OF_METHOD = COMPOSITE_PREFIX + START + "CallStaticJava" + MID + IS_REPLACED + END; + public static final String CALL = START + "Call.*Java" + MID + END; + public static final String CALL_OF_METHOD = COMPOSITE_PREFIX + START + "Call.*Java" + MID + IS_REPLACED + " " + END; + public static final String DYNAMIC_CALL_OF_METHOD = COMPOSITE_PREFIX + START + "CallDynamicJava" + MID + IS_REPLACED + " " + END; + public static final String STATIC_CALL_OF_METHOD = COMPOSITE_PREFIX + START + "CallStaticJava" + MID + IS_REPLACED + " " + END; public static final String TRAP = START + "CallStaticJava" + MID + "uncommon_trap.*reason" + END; public static final String PREDICATE_TRAP = START + "CallStaticJava" + MID + "uncommon_trap.*predicate" + END; public static final String UNSTABLE_IF_TRAP = START + "CallStaticJava" + MID + "uncommon_trap.*unstable_if" + END; @@ -125,6 +126,7 @@ public class IRNode { public static final String NULL_ASSERT_TRAP = START + "CallStaticJava" + MID + "uncommon_trap.*null_assert" + END; public static final String RANGE_CHECK_TRAP = START + "CallStaticJava" + MID + "uncommon_trap.*range_check" + END; public static final String UNHANDLED_TRAP = START + "CallStaticJava" + MID + "uncommon_trap.*unhandled" + END; + public static final String INTRINSIC_TRAP = START + "CallStaticJava" + MID + "uncommon_trap.*intrinsic" + END; // Does not work for VM builds without JVMCI like x86_32 (a rule containing this regex will be skipped without having JVMCI built). public static final String INTRINSIC_OR_TYPE_CHECKED_INLINING_TRAP = START + "CallStaticJava" + MID + "uncommon_trap.*intrinsic_or_type_checked_inlining" + END; diff --git a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestIRMatching.java b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestIRMatching.java index 08fac4c871a..c2335717875 100644 --- a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestIRMatching.java +++ b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestIRMatching.java @@ -100,6 +100,12 @@ public class TestIRMatching { BadCountsConstraint.create(BadCount.class, "bad3()", 2, 1, "Store") ); + runCheck(GoodRuleConstraint.create(Calls.class, "calls()", 1), + BadFailOnConstraint.create(Calls.class, "calls()", 2, 1, "CallStaticJava", "dontInline"), + BadFailOnConstraint.create(Calls.class, "calls()", 2, 2, "CallStaticJava", "dontInline"), + GoodRuleConstraint.create(Calls.class, "calls()", 3) + ); + String[] allocArrayMatches = { "MyClass", "wrapper for: _new_array_Java"}; runCheck(BadFailOnConstraint.create(AllocArray.class, "allocArray()", 1, allocArrayMatches), BadFailOnConstraint.create(AllocArray.class, "allocArray()", 2, allocArrayMatches), @@ -185,8 +191,9 @@ public class TestIRMatching { WhiteBox.getWhiteBox().isJVMCISupportedByGC() ? BadFailOnConstraint.create(Traps.class, "instrinsicOrTypeCheckedInlining()", 2, "CallStaticJava", "uncommon_trap", "intrinsic_or_type_checked_inlining") : GoodRuleConstraint.create(Traps.class, "instrinsicOrTypeCheckedInlining()", 2), - BadFailOnConstraint.create(Traps.class, "instrinsicOrTypeCheckedInlining()", 3, "CallStaticJava", "uncommon_trap", "null_check"), - GoodRuleConstraint.create(Traps.class, "instrinsicOrTypeCheckedInlining()", 4) + BadFailOnConstraint.create(Traps.class, "instrinsicOrTypeCheckedInlining()", 3, "CallStaticJava", "uncommon_trap", "intrinsic"), + BadFailOnConstraint.create(Traps.class, "instrinsicOrTypeCheckedInlining()", 4, "CallStaticJava", "uncommon_trap", "null_check"), + GoodRuleConstraint.create(Traps.class, "instrinsicOrTypeCheckedInlining()", 5) ); @@ -867,6 +874,29 @@ class RunTests { } } +class Calls { + + @Test + @IR(counts = {IRNode.CALL, "1"}) + @IR(failOn = {IRNode.CALL_OF_METHOD, "dontInline", // Fails + IRNode.STATIC_CALL_OF_METHOD, "dontInline"}) // Fails + @IR(failOn = {IRNode.CALL_OF_METHOD, "forceInline", + IRNode.STATIC_CALL_OF_METHOD, "forceInline", + IRNode.CALL_OF_METHOD, "dontInlines", + IRNode.STATIC_CALL_OF_METHOD, "dontInlines", + IRNode.CALL_OF_METHOD, "dont", + IRNode.STATIC_CALL_OF_METHOD, "dont"}) + public void calls() { + dontInline(); + forceInline(); + } + + @DontInline + public void dontInline() {} + + @ForceInline + public void forceInline() {} +} class AllocArray { MyClass[] myClassArray; @@ -994,6 +1024,7 @@ class Traps { IRNode.NULL_ASSERT_TRAP, IRNode.RANGE_CHECK_TRAP, IRNode.CLASS_CHECK_TRAP, + IRNode.INTRINSIC_TRAP, IRNode.INTRINSIC_OR_TYPE_CHECKED_INLINING_TRAP, IRNode.UNHANDLED_TRAP}) public void noTraps() { @@ -1014,6 +1045,7 @@ class Traps { IRNode.NULL_ASSERT_TRAP, IRNode.RANGE_CHECK_TRAP, IRNode.CLASS_CHECK_TRAP, + IRNode.INTRINSIC_TRAP, IRNode.INTRINSIC_OR_TYPE_CHECKED_INLINING_TRAP, IRNode.UNHANDLED_TRAP}) public void predicateTrap() { @@ -1033,6 +1065,7 @@ class Traps { IRNode.NULL_ASSERT_TRAP, IRNode.RANGE_CHECK_TRAP, IRNode.CLASS_CHECK_TRAP, + IRNode.INTRINSIC_TRAP, IRNode.INTRINSIC_OR_TYPE_CHECKED_INLINING_TRAP, IRNode.UNHANDLED_TRAP}) public void nullCheck() { @@ -1049,6 +1082,7 @@ class Traps { IRNode.UNSTABLE_IF_TRAP, IRNode.RANGE_CHECK_TRAP, IRNode.CLASS_CHECK_TRAP, + IRNode.INTRINSIC_TRAP, IRNode.INTRINSIC_OR_TYPE_CHECKED_INLINING_TRAP, IRNode.UNHANDLED_TRAP}) public Object nullAssert() { @@ -1064,6 +1098,7 @@ class Traps { IRNode.NULL_ASSERT_TRAP, IRNode.RANGE_CHECK_TRAP, IRNode.CLASS_CHECK_TRAP, + IRNode.INTRINSIC_TRAP, IRNode.INTRINSIC_OR_TYPE_CHECKED_INLINING_TRAP, IRNode.UNHANDLED_TRAP}) public void unstableIf(boolean flag) { @@ -1082,6 +1117,7 @@ class Traps { IRNode.UNSTABLE_IF_TRAP, IRNode.NULL_ASSERT_TRAP, IRNode.RANGE_CHECK_TRAP, + IRNode.INTRINSIC_TRAP, IRNode.INTRINSIC_OR_TYPE_CHECKED_INLINING_TRAP, IRNode.UNHANDLED_TRAP}) public void classCheck() { @@ -1100,6 +1136,7 @@ class Traps { IRNode.UNSTABLE_IF_TRAP, IRNode.NULL_ASSERT_TRAP, IRNode.CLASS_CHECK_TRAP, + IRNode.INTRINSIC_TRAP, IRNode.INTRINSIC_OR_TYPE_CHECKED_INLINING_TRAP, IRNode.UNHANDLED_TRAP}) public void rangeCheck() { @@ -1110,6 +1147,7 @@ class Traps { @Test @IR(failOn = IRNode.TRAP) // fails @IR(failOn = IRNode.INTRINSIC_OR_TYPE_CHECKED_INLINING_TRAP) // fails + @IR(failOn = IRNode.INTRINSIC_TRAP) // fails @IR(failOn = IRNode.NULL_CHECK_TRAP) // fails @IR(failOn = {IRNode.PREDICATE_TRAP, IRNode.UNSTABLE_IF_TRAP, -- GitLab From 8f7a37c92f5713f7728f54d4a5924484a535e968 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Tue, 5 Oct 2021 07:25:00 +0000 Subject: [PATCH 087/385] 8274434: move os::get_default_process_handle and os::dll_lookup to os_posix for POSIX platforms Reviewed-by: dholmes, lucy --- src/hotspot/os/aix/os_aix.cpp | 9 --------- src/hotspot/os/bsd/os_bsd.cpp | 16 ---------------- src/hotspot/os/linux/os_linux.cpp | 9 --------- src/hotspot/os/posix/os_posix.cpp | 15 +++++++++++++++ 4 files changed, 15 insertions(+), 34 deletions(-) diff --git a/src/hotspot/os/aix/os_aix.cpp b/src/hotspot/os/aix/os_aix.cpp index 508f92f2e5a..df8563067e4 100644 --- a/src/hotspot/os/aix/os_aix.cpp +++ b/src/hotspot/os/aix/os_aix.cpp @@ -1118,15 +1118,6 @@ void *os::dll_load(const char *filename, char *ebuf, int ebuflen) { return NULL; } -void* os::dll_lookup(void* handle, const char* name) { - void* res = dlsym(handle, name); - return res; -} - -void* os::get_default_process_handle() { - return (void*)::dlopen(NULL, RTLD_LAZY); -} - void os::print_dll_info(outputStream *st) { st->print_cr("Dynamic libraries:"); LoadedLibraries::print(st); diff --git a/src/hotspot/os/bsd/os_bsd.cpp b/src/hotspot/os/bsd/os_bsd.cpp index 5a3d0f32dc1..c0cbbe94a57 100644 --- a/src/hotspot/os/bsd/os_bsd.cpp +++ b/src/hotspot/os/bsd/os_bsd.cpp @@ -1163,22 +1163,6 @@ void * os::dll_load(const char *filename, char *ebuf, int ebuflen) { } #endif // !__APPLE__ -void* os::get_default_process_handle() { -#ifdef __APPLE__ - // MacOS X needs to use RTLD_FIRST instead of RTLD_LAZY - // to avoid finding unexpected symbols on second (or later) - // loads of a library. - return (void*)::dlopen(NULL, RTLD_FIRST); -#else - return (void*)::dlopen(NULL, RTLD_LAZY); -#endif -} - -// XXX: Do we need a lock around this as per Linux? -void* os::dll_lookup(void* handle, const char* name) { - return dlsym(handle, name); -} - int _print_dll_info_cb(const char * name, address base_address, address top_address, void * param) { outputStream * out = (outputStream *) param; out->print_cr(INTPTR_FORMAT " \t%s", (intptr_t)base_address, name); diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index 27abc8d9030..e75e2e51b0e 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -1781,15 +1781,6 @@ void * os::Linux::dll_load_in_vmthread(const char *filename, char *ebuf, return result; } -void* os::dll_lookup(void* handle, const char* name) { - void* res = dlsym(handle, name); - return res; -} - -void* os::get_default_process_handle() { - return (void*)::dlopen(NULL, RTLD_LAZY); -} - static bool _print_ascii_file(const char* filename, outputStream* st, const char* hdr = NULL) { int fd = ::open(filename, O_RDONLY); if (fd == -1) { diff --git a/src/hotspot/os/posix/os_posix.cpp b/src/hotspot/os/posix/os_posix.cpp index 24522c2649f..60820b31f92 100644 --- a/src/hotspot/os/posix/os_posix.cpp +++ b/src/hotspot/os/posix/os_posix.cpp @@ -639,6 +639,21 @@ bool os::has_allocatable_memory_limit(size_t* limit) { #endif } +void* os::get_default_process_handle() { +#ifdef __APPLE__ + // MacOS X needs to use RTLD_FIRST instead of RTLD_LAZY + // to avoid finding unexpected symbols on second (or later) + // loads of a library. + return (void*)::dlopen(NULL, RTLD_FIRST); +#else + return (void*)::dlopen(NULL, RTLD_LAZY); +#endif +} + +void* os::dll_lookup(void* handle, const char* name) { + return dlsym(handle, name); +} + void os::dll_unload(void *lib) { ::dlclose(lib); } -- GitLab From a914ee72167f642b76b1c1cdddd7ff0698d061cc Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Tue, 5 Oct 2021 08:07:02 +0000 Subject: [PATCH 088/385] 8274632: Possible pointer overflow in PretouchTask chunk claiming Reviewed-by: tschatzl, ayang --- src/hotspot/share/gc/shared/pretouchTask.cpp | 14 ++++++-------- src/hotspot/share/gc/shared/pretouchTask.hpp | 3 +-- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/src/hotspot/share/gc/shared/pretouchTask.cpp b/src/hotspot/share/gc/shared/pretouchTask.cpp index 4f900439a3f..244c7282cf7 100644 --- a/src/hotspot/share/gc/shared/pretouchTask.cpp +++ b/src/hotspot/share/gc/shared/pretouchTask.cpp @@ -36,7 +36,6 @@ PretouchTask::PretouchTask(const char* task_name, size_t chunk_size) : AbstractGangTask(task_name), _cur_addr(start_address), - _start_addr(start_address), _end_addr(end_address), _page_size(page_size), _chunk_size(chunk_size) { @@ -52,14 +51,13 @@ size_t PretouchTask::chunk_size() { void PretouchTask::work(uint worker_id) { while (true) { - char* touch_addr = Atomic::fetch_and_add(&_cur_addr, _chunk_size); - if (touch_addr < _start_addr || touch_addr >= _end_addr) { + char* cur_start = Atomic::load(&_cur_addr); + char* cur_end = cur_start + MIN2(_chunk_size, pointer_delta(_end_addr, cur_start, 1)); + if (cur_start >= cur_end) { break; - } - - char* end_addr = touch_addr + MIN2(_chunk_size, pointer_delta(_end_addr, touch_addr, sizeof(char))); - - os::pretouch_memory(touch_addr, end_addr, _page_size); + } else if (cur_start == Atomic::cmpxchg(&_cur_addr, cur_start, cur_end)) { + os::pretouch_memory(cur_start, cur_end, _page_size); + } // Else attempt to claim chunk failed, so try again. } } diff --git a/src/hotspot/share/gc/shared/pretouchTask.hpp b/src/hotspot/share/gc/shared/pretouchTask.hpp index 49cd48dc9cf..c6883220372 100644 --- a/src/hotspot/share/gc/shared/pretouchTask.hpp +++ b/src/hotspot/share/gc/shared/pretouchTask.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +29,6 @@ class PretouchTask : public AbstractGangTask { char* volatile _cur_addr; - char* const _start_addr; char* const _end_addr; size_t _page_size; size_t _chunk_size; -- GitLab From a5080effc7ec7e260e84e3169c36c5217f18d231 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Tue, 5 Oct 2021 10:17:24 +0000 Subject: [PATCH 089/385] 8272564: Incorrect attribution of method invocations of Object methods on interfaces Reviewed-by: jlaskey, mcimadamore, vromero --- .../com/sun/tools/javac/comp/Attr.java | 2 +- .../com/sun/tools/javac/comp/Resolve.java | 18 ++++- .../javac/api/TestGetElementReference.java | 2 +- .../api/TestGetElementReferenceData.java | 8 ++ .../tools/javac/api/TestIsAccessible.java | 75 ++++++++++++++++++ .../tools/javac/resolve/NoObjectToString.java | 79 +++++++++++++++++++ 6 files changed, 180 insertions(+), 4 deletions(-) create mode 100644 test/langtools/tools/javac/api/TestIsAccessible.java create mode 100644 test/langtools/tools/javac/resolve/NoObjectToString.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 3bf1f593634..56b678f8472 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 @@ -2590,7 +2590,7 @@ public class Attr extends JCTree.Visitor { //where Type adjustMethodReturnType(Symbol msym, Type qualifierType, Name methodName, List argtypes, Type restype) { if (msym != null && - msym.owner == syms.objectType.tsym && + (msym.owner == syms.objectType.tsym || msym.owner.isInterface()) && methodName == names.getClass && argtypes.isEmpty()) { // as a special case, x.getClass() has type Class 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 c18060a85a6..a9d47bf7ca7 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 @@ -469,7 +469,7 @@ public class Resolve { return true; else { Symbol s2 = ((MethodSymbol)sym).implementation(site.tsym, types, true); - return (s2 == null || s2 == sym || sym.owner == s2.owner || + return (s2 == null || s2 == sym || sym.owner == s2.owner || (sym.owner.isInterface() && s2.owner == syms.objectType.tsym) || !types.isSubSignature(types.memberType(site, s2), types.memberType(site, sym))); } } @@ -1854,7 +1854,8 @@ public class Resolve { List[] itypes = (List[])new List[] { List.nil(), List.nil() }; InterfaceLookupPhase iphase = InterfaceLookupPhase.ABSTRACT_OK; - for (TypeSymbol s : superclasses(intype)) { + boolean isInterface = site.tsym.isInterface(); + for (TypeSymbol s : isInterface ? List.of(intype.tsym) : superclasses(intype)) { bestSoFar = findMethodInScope(env, site, name, argtypes, typeargtypes, s.members(), bestSoFar, allowBoxing, useVarargs, true); if (name == names.init) return bestSoFar; @@ -1892,6 +1893,19 @@ public class Resolve { } } } + if (isInterface && bestSoFar.kind.isResolutionError()) { + bestSoFar = findMethodInScope(env, site, name, argtypes, typeargtypes, + syms.objectType.tsym.members(), bestSoFar, allowBoxing, useVarargs, true); + if (bestSoFar.kind.isValid()) { + Symbol baseSymbol = bestSoFar; + bestSoFar = new MethodSymbol(bestSoFar.flags_field, bestSoFar.name, bestSoFar.type, intype.tsym) { + @Override + public Symbol baseSymbol() { + return baseSymbol; + } + }; + } + } return bestSoFar; } diff --git a/test/langtools/tools/javac/api/TestGetElementReference.java b/test/langtools/tools/javac/api/TestGetElementReference.java index 7eb8cd02381..9de0dc61c18 100644 --- a/test/langtools/tools/javac/api/TestGetElementReference.java +++ b/test/langtools/tools/javac/api/TestGetElementReference.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8012929 8243074 8266281 + * @bug 8012929 8243074 8266281 8272564 * @summary Trees.getElement should work not only for declaration trees, but also for use-trees * @modules jdk.compiler * @build TestGetElementReference diff --git a/test/langtools/tools/javac/api/TestGetElementReferenceData.java b/test/langtools/tools/javac/api/TestGetElementReferenceData.java index b86defa69f6..8e86092a364 100644 --- a/test/langtools/tools/javac/api/TestGetElementReferenceData.java +++ b/test/langtools/tools/javac/api/TestGetElementReferenceData.java @@ -37,6 +37,10 @@ public class TestGetElementReferenceData { target(TestGetElementReferenceData :: test/*getElement:METHOD:test.nested.TestGetElementReferenceData.test()*/); Object/*getElement:CLASS:java.lang.Object*/ o = null; if (o/*getElement:LOCAL_VARIABLE:o*/ instanceof String/*getElement:CLASS:java.lang.String*/ str/*getElement:BINDING_VARIABLE:str*/) ; + I i = null; + i.toString/*getElement:METHOD:test.nested.TestGetElementReferenceData.I.toString()*/(); + J j = null; + j.toString/*getElement:METHOD:test.nested.TestGetElementReferenceData.I.toString()*/(); } private static void target(Runnable r) { r.run(); } public static class Base { @@ -50,4 +54,8 @@ public class TestGetElementReferenceData { @Target(ElementType.TYPE_USE) @interface TypeAnnotation { } + interface I { + public String toString(); + } + interface J extends I {} } diff --git a/test/langtools/tools/javac/api/TestIsAccessible.java b/test/langtools/tools/javac/api/TestIsAccessible.java new file mode 100644 index 00000000000..dd1f509a33a --- /dev/null +++ b/test/langtools/tools/javac/api/TestIsAccessible.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 8272564 + * @summary Verify accessibility of Object-based methods inherited from super interfaces. + * @modules jdk.compiler + */ + +import com.sun.source.tree.CompilationUnitTree; +import com.sun.source.tree.Scope; +import com.sun.source.util.JavacTask; +import com.sun.source.util.TreePath; +import com.sun.source.util.Trees; +import java.net.URI; +import java.util.Arrays; +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.DeclaredType; +import javax.tools.JavaCompiler; +import javax.tools.JavaFileObject; +import javax.tools.SimpleJavaFileObject; +import javax.tools.ToolProvider; + +public class TestIsAccessible { + public static void main(String[] args) throws Exception { + final JavaCompiler tool = ToolProvider.getSystemJavaCompiler(); + assert tool != null; + final JavacTask ct = (JavacTask)tool.getTask(null, null, null, null, null, Arrays.asList(new MyFileObject())); + + CompilationUnitTree cut = ct.parse().iterator().next(); + TreePath tp = new TreePath(new TreePath(cut), cut.getTypeDecls().get(0)); + Scope s = Trees.instance(ct).getScope(tp); + TypeElement name = ct.getElements().getTypeElement("javax.lang.model.element.Name"); + Trees trees = Trees.instance(ct); + + if (trees.isAccessible(s, name)) { + for (Element member : ct.getElements().getAllMembers(name)) { + if (!trees.isAccessible(s, member, (DeclaredType) name.asType())) { + throw new IllegalStateException("Inaccessible Name member: " + member); + } + } + } + } + + static class MyFileObject extends SimpleJavaFileObject { + public MyFileObject() { + super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE); + } + public CharSequence getCharContent(boolean ignoreEncodingErrors) { + return "public class Test { }"; + } + } +} diff --git a/test/langtools/tools/javac/resolve/NoObjectToString.java b/test/langtools/tools/javac/resolve/NoObjectToString.java new file mode 100644 index 00000000000..c7275a8cd5e --- /dev/null +++ b/test/langtools/tools/javac/resolve/NoObjectToString.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 8272564 + * @summary Correct resolution of toString() (and other similar calls) on interfaces + * @modules jdk.jdeps/com.sun.tools.classfile + * @compile NoObjectToString.java + * @run main NoObjectToString + */ + +import java.io.*; +import com.sun.tools.classfile.*; +import com.sun.tools.classfile.ConstantPool.CONSTANT_Methodref_info; + +public class NoObjectToString { + public static void main(String... args) throws Exception { + NoObjectToString c = new NoObjectToString(); + c.run(args); + } + + void run(String... args) throws Exception { + //Verify there are no references to Object.toString() in a Test: + InputStream in = NoObjectToString.class.getResourceAsStream("NoObjectToString$Test.class"); + try { + ClassFile cf = ClassFile.read(in); + for (ConstantPool.CPInfo cpinfo: cf.constant_pool.entries()) { + if (cpinfo.getTag() == ConstantPool.CONSTANT_Methodref) { + CONSTANT_Methodref_info ref = (CONSTANT_Methodref_info) cpinfo; + String methodDesc = ref.getClassInfo().getName() + "." + ref.getNameAndTypeInfo().getName() + ":" + ref.getNameAndTypeInfo().getType(); + + if ("java/lang/Object.toString:()Ljava/lang/String;".equals(methodDesc)) { + throw new AssertionError("Found call to j.l.Object.toString"); + } + } + } + } catch (ConstantPoolException ignore) { + throw new AssertionError(ignore); + } finally { + in.close(); + } + } + + class Test { + void test(I i, J j, K k) { + i.toString(); + j.toString(); + k.toString(); + } + } + + interface I { + public String toString(); + } + interface J extends I {} + interface K {} + +} -- GitLab From 8609ea55acdcc203408f58f7bf96ea9228aef613 Mon Sep 17 00:00:00 2001 From: Harold Seigel Date: Tue, 5 Oct 2021 12:39:56 +0000 Subject: [PATCH 090/385] 8273342: Null pointer dereference in classFileParser.cpp:2817 Reviewed-by: coleenp, dholmes --- src/hotspot/share/runtime/fieldDescriptor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/runtime/fieldDescriptor.cpp b/src/hotspot/share/runtime/fieldDescriptor.cpp index 83f31e05085..4e07a456bb0 100644 --- a/src/hotspot/share/runtime/fieldDescriptor.cpp +++ b/src/hotspot/share/runtime/fieldDescriptor.cpp @@ -55,7 +55,7 @@ Symbol* fieldDescriptor::generic_signature() const { } } assert(false, "should never happen"); - return NULL; + return vmSymbols::void_signature(); // return a default value (for code analyzers) } bool fieldDescriptor::is_trusted_final() const { -- GitLab From 1459180f352a5632c0afca2ed55abf31e4b0bfb0 Mon Sep 17 00:00:00 2001 From: Andrey Turbanov Date: Tue, 5 Oct 2021 13:36:37 +0000 Subject: [PATCH 091/385] 8274079: Cleanup unnecessary calls to Throwable.initCause() in java.base module Reviewed-by: weijun --- .../com/sun/crypto/provider/AESCipher.java | 4 +--- .../sun/crypto/provider/ConstructKeys.java | 20 ++++------------ .../sun/crypto/provider/DESedeWrapCipher.java | 12 +++------- .../com/sun/crypto/provider/DHPrivateKey.java | 6 ++--- .../com/sun/crypto/provider/PBES2Core.java | 10 ++------ .../provider/PBEWithMD5AndDESCipher.java | 8 ++----- .../PBEWithMD5AndTripleDESCipher.java | 8 ++----- .../com/sun/crypto/provider/PBKDF2Core.java | 6 ++--- .../provider/PBKDF2HmacSHA1Factory.java | 6 ++--- .../sun/crypto/provider/PBKDF2KeyImpl.java | 4 +--- .../com/sun/crypto/provider/PBMAC1Core.java | 7 +----- .../com/sun/crypto/provider/RSACipher.java | 10 ++------ .../classes/java/io/ObjectStreamClass.java | 4 +--- .../java/security/cert/TrustAnchor.java | 8 ++----- .../java/security/cert/X509CRLSelector.java | 2 +- .../share/classes/java/time/Duration.java | 6 ++--- .../classes/javax/net/ssl/SSLContext.java | 18 +++++--------- .../security/auth/login/Configuration.java | 10 ++++---- .../security/auth/x500/X500Principal.java | 24 +++++++------------ .../sun/security/provider/DigestBase.java | 5 ++-- .../sun/security/provider/JavaKeyStore.java | 4 ++-- .../sun/security/util/HostnameChecker.java | 5 ++-- 22 files changed, 55 insertions(+), 132 deletions(-) diff --git a/src/java.base/share/classes/com/sun/crypto/provider/AESCipher.java b/src/java.base/share/classes/com/sun/crypto/provider/AESCipher.java index c082dde20b8..4c9ac6768d9 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/AESCipher.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/AESCipher.java @@ -72,9 +72,7 @@ abstract class AESCipher extends CipherSpi { engineSetPadding(padding); } catch (GeneralSecurityException gse) { // internal error; re-throw as provider exception - ProviderException pe =new ProviderException("Internal Error"); - pe.initCause(gse); - throw pe; + throw new ProviderException("Internal Error", gse); } } } diff --git a/src/java.base/share/classes/com/sun/crypto/provider/ConstructKeys.java b/src/java.base/share/classes/com/sun/crypto/provider/ConstructKeys.java index 68c2c830df6..e8375d1eb81 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/ConstructKeys.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/ConstructKeys.java @@ -76,16 +76,10 @@ final class ConstructKeys { encodedKeyAlgorithm + "algorithm"); } catch (InvalidKeySpecException ikse2) { - InvalidKeyException ike = - new InvalidKeyException("Cannot construct public key"); - ike.initCause(ikse2); - throw ike; + throw new InvalidKeyException("Cannot construct public key", ikse2); } } catch (InvalidKeySpecException ikse) { - InvalidKeyException ike = - new InvalidKeyException("Cannot construct public key"); - ike.initCause(ikse); - throw ike; + throw new InvalidKeyException("Cannot construct public key", ikse); } return key; @@ -116,16 +110,10 @@ final class ConstructKeys { encodedKeyAlgorithm + "algorithm"); } catch (InvalidKeySpecException ikse2) { - InvalidKeyException ike = - new InvalidKeyException("Cannot construct private key"); - ike.initCause(ikse2); - throw ike; + throw new InvalidKeyException("Cannot construct private key", ikse2); } } catch (InvalidKeySpecException ikse) { - InvalidKeyException ike = - new InvalidKeyException("Cannot construct private key"); - ike.initCause(ikse); - throw ike; + throw new InvalidKeyException("Cannot construct private key", ikse); } finally { SharedSecrets.getJavaSecuritySpecAccess().clearEncodedKeySpec(keySpec); if (keyBytes != encodedKey) { diff --git a/src/java.base/share/classes/com/sun/crypto/provider/DESedeWrapCipher.java b/src/java.base/share/classes/com/sun/crypto/provider/DESedeWrapCipher.java index 23846d14fd1..8ba473e467e 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/DESedeWrapCipher.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/DESedeWrapCipher.java @@ -181,10 +181,7 @@ public final class DESedeWrapCipher extends CipherSpi { engineInit(opmode, key, (AlgorithmParameterSpec) null, random); } catch (InvalidAlgorithmParameterException iape) { // should never happen - InvalidKeyException ike = - new InvalidKeyException("Parameters required"); - ike.initCause(iape); - throw ike; + throw new InvalidKeyException("Parameters required", iape); } } @@ -285,11 +282,8 @@ public final class DESedeWrapCipher extends CipherSpi { paramsEng.engineInit(params.getEncoded()); ivSpec = paramsEng.engineGetParameterSpec(IvParameterSpec.class); } catch (Exception ex) { - InvalidAlgorithmParameterException iape = - new InvalidAlgorithmParameterException - ("Wrong parameter type: IV expected"); - iape.initCause(ex); - throw iape; + throw new InvalidAlgorithmParameterException + ("Wrong parameter type: IV expected", ex); } } engineInit(opmode, key, ivSpec, random); diff --git a/src/java.base/share/classes/com/sun/crypto/provider/DHPrivateKey.java b/src/java.base/share/classes/com/sun/crypto/provider/DHPrivateKey.java index dcce2c4efa5..7b8ab570a08 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/DHPrivateKey.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/DHPrivateKey.java @@ -291,10 +291,8 @@ final class DHPrivateKey implements PrivateKey, DerInputStream in = new DerInputStream(this.key); this.x = in.getBigInteger(); } catch (IOException e) { - InvalidKeyException ike = new InvalidKeyException( - "Error parsing key encoding: " + e.getMessage()); - ike.initCause(e); - throw ike; + throw new InvalidKeyException( + "Error parsing key encoding: " + e.getMessage(), e); } } diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PBES2Core.java b/src/java.base/share/classes/com/sun/crypto/provider/PBES2Core.java index db56dfcd505..a4d6ac58c25 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/PBES2Core.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/PBES2Core.java @@ -162,10 +162,7 @@ abstract class PBES2Core extends CipherSpi { try { engineInit(opmode, key, (AlgorithmParameterSpec) null, random); } catch (InvalidAlgorithmParameterException ie) { - InvalidKeyException ike = - new InvalidKeyException("requires PBE parameters"); - ike.initCause(ie); - throw ike; + throw new InvalidKeyException("requires PBE parameters", ie); } } @@ -279,10 +276,7 @@ abstract class PBES2Core extends CipherSpi { try { s = (PBKDF2KeyImpl)kdf.engineGenerateSecret(pbeSpec); } catch (InvalidKeySpecException ikse) { - InvalidKeyException ike = - new InvalidKeyException("Cannot construct PBE key"); - ike.initCause(ikse); - throw ike; + throw new InvalidKeyException("Cannot construct PBE key", ikse); } finally { pbeSpec.clearPassword(); } diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PBEWithMD5AndDESCipher.java b/src/java.base/share/classes/com/sun/crypto/provider/PBEWithMD5AndDESCipher.java index 80a27b625dd..5034434024d 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/PBEWithMD5AndDESCipher.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/PBEWithMD5AndDESCipher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,6 @@ package com.sun.crypto.provider; import java.security.*; import java.security.spec.*; import javax.crypto.*; -import javax.crypto.spec.*; /** * This class represents password-based encryption as defined by the PKCS #5 @@ -183,10 +182,7 @@ public final class PBEWithMD5AndDESCipher extends CipherSpi { try { engineInit(opmode, key, (AlgorithmParameterSpec) null, random); } catch (InvalidAlgorithmParameterException ie) { - InvalidKeyException ike = - new InvalidKeyException("requires PBE parameters"); - ike.initCause(ie); - throw ike; + throw new InvalidKeyException("requires PBE parameters", ie); } } diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PBEWithMD5AndTripleDESCipher.java b/src/java.base/share/classes/com/sun/crypto/provider/PBEWithMD5AndTripleDESCipher.java index 18fee3b355f..16784afc897 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/PBEWithMD5AndTripleDESCipher.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/PBEWithMD5AndTripleDESCipher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,6 @@ package com.sun.crypto.provider; import java.security.*; import java.security.spec.*; import javax.crypto.*; -import javax.crypto.spec.*; /** * This class implements a proprietary password-based encryption algorithm. @@ -195,10 +194,7 @@ public final class PBEWithMD5AndTripleDESCipher extends CipherSpi { try { core.init(opmode, key, (AlgorithmParameterSpec) null, random); } catch (InvalidAlgorithmParameterException ie) { - InvalidKeyException ike = - new InvalidKeyException("requires PBE parameters"); - ike.initCause(ie); - throw ike; + throw new InvalidKeyException("requires PBE parameters", ie); } } diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PBKDF2Core.java b/src/java.base/share/classes/com/sun/crypto/provider/PBKDF2Core.java index 78c7b72b081..87207c778ec 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/PBKDF2Core.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/PBKDF2Core.java @@ -151,10 +151,8 @@ abstract class PBKDF2Core extends SecretKeyFactorySpi { try { return new PBKDF2KeyImpl(spec, prfAlgo); } catch (InvalidKeySpecException re) { - InvalidKeyException ike = new InvalidKeyException - ("Invalid key component(s)"); - ike.initCause(re); - throw ike; + throw new InvalidKeyException + ("Invalid key component(s)", re); } finally { if (password != null) { Arrays.fill(password, (char) 0); diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PBKDF2HmacSHA1Factory.java b/src/java.base/share/classes/com/sun/crypto/provider/PBKDF2HmacSHA1Factory.java index 6f260ee7b62..d8070e968b6 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/PBKDF2HmacSHA1Factory.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/PBKDF2HmacSHA1Factory.java @@ -151,10 +151,8 @@ public final class PBKDF2HmacSHA1Factory extends SecretKeyFactorySpi { try { return new PBKDF2KeyImpl(spec, "HmacSHA1"); } catch (InvalidKeySpecException re) { - InvalidKeyException ike = new InvalidKeyException - ("Invalid key component(s)"); - ike.initCause(re); - throw ike; + throw new InvalidKeyException + ("Invalid key component(s)", re); } finally { if (password != null) { Arrays.fill(password, (char) 0); diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PBKDF2KeyImpl.java b/src/java.base/share/classes/com/sun/crypto/provider/PBKDF2KeyImpl.java index 56477a1ac13..b6827e22e2b 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/PBKDF2KeyImpl.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/PBKDF2KeyImpl.java @@ -121,9 +121,7 @@ final class PBKDF2KeyImpl implements javax.crypto.interfaces.PBEKey { this.key = deriveKey(prf, passwdBytes, salt, iterCount, keyLength); } catch (NoSuchAlgorithmException nsae) { // not gonna happen; re-throw just in case - InvalidKeySpecException ike = new InvalidKeySpecException(); - ike.initCause(nsae); - throw ike; + throw new InvalidKeySpecException(nsae); } finally { Arrays.fill(passwdBytes, (byte) 0x00); diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Core.java b/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Core.java index bd16a20a9ee..a3d896aa034 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Core.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/PBMAC1Core.java @@ -26,9 +26,7 @@ package com.sun.crypto.provider; import java.util.Arrays; -import java.nio.ByteBuffer; -import javax.crypto.MacSpi; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; import javax.crypto.spec.PBEKeySpec; @@ -181,10 +179,7 @@ abstract class PBMAC1Core extends HmacCore { s = (PBKDF2KeyImpl)kdf.engineGenerateSecret(pbeSpec); derivedKey = s.getEncoded(); } catch (InvalidKeySpecException ikse) { - InvalidKeyException ike = - new InvalidKeyException("Cannot construct PBE key"); - ike.initCause(ikse); - throw ike; + throw new InvalidKeyException("Cannot construct PBE key", ikse); } finally { pbeSpec.clearPassword(); if (s != null) { diff --git a/src/java.base/share/classes/com/sun/crypto/provider/RSACipher.java b/src/java.base/share/classes/com/sun/crypto/provider/RSACipher.java index 196acef1511..f9c910e2ff1 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/RSACipher.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/RSACipher.java @@ -211,10 +211,7 @@ public final class RSACipher extends CipherSpi { } catch (InvalidAlgorithmParameterException iape) { // never thrown when null parameters are used; // but re-throw it just in case - InvalidKeyException ike = - new InvalidKeyException("Wrong parameters"); - ike.initCause(iape); - throw ike; + throw new InvalidKeyException("Wrong parameters", iape); } } @@ -237,10 +234,7 @@ public final class RSACipher extends CipherSpi { params.getParameterSpec(OAEPParameterSpec.class); init(opmode, key, random, spec); } catch (InvalidParameterSpecException ipse) { - InvalidAlgorithmParameterException iape = - new InvalidAlgorithmParameterException("Wrong parameter"); - iape.initCause(ipse); - throw iape; + throw new InvalidAlgorithmParameterException("Wrong parameter", ipse); } } } diff --git a/src/java.base/share/classes/java/io/ObjectStreamClass.java b/src/java.base/share/classes/java/io/ObjectStreamClass.java index 1eff6c27278..82ba054f61f 100644 --- a/src/java.base/share/classes/java/io/ObjectStreamClass.java +++ b/src/java.base/share/classes/java/io/ObjectStreamClass.java @@ -1712,9 +1712,7 @@ public class ObjectStreamClass implements Serializable { } else if (th instanceof Error) { throw (Error) th; } else { - IOException ex = new IOException("unexpected exception type"); - ex.initCause(th); - throw ex; + throw new IOException("unexpected exception type", th); } } diff --git a/src/java.base/share/classes/java/security/cert/TrustAnchor.java b/src/java.base/share/classes/java/security/cert/TrustAnchor.java index 2fee634ec41..f026bea4179 100644 --- a/src/java.base/share/classes/java/security/cert/TrustAnchor.java +++ b/src/java.base/share/classes/java/security/cert/TrustAnchor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,7 +32,6 @@ import javax.security.auth.x500.X500Principal; import sun.security.util.AnchorCertificates; import sun.security.x509.NameConstraintsExtension; -import sun.security.x509.X500Name; /** * A trust anchor or most-trusted Certification Authority (CA). @@ -286,10 +285,7 @@ public class TrustAnchor { try { nc = new NameConstraintsExtension(Boolean.FALSE, bytes); } catch (IOException ioe) { - IllegalArgumentException iae = - new IllegalArgumentException(ioe.getMessage()); - iae.initCause(ioe); - throw iae; + throw new IllegalArgumentException(ioe.getMessage(), ioe); } } } diff --git a/src/java.base/share/classes/java/security/cert/X509CRLSelector.java b/src/java.base/share/classes/java/security/cert/X509CRLSelector.java index ad2947c5885..444100cbdcc 100644 --- a/src/java.base/share/classes/java/security/cert/X509CRLSelector.java +++ b/src/java.base/share/classes/java/security/cert/X509CRLSelector.java @@ -371,7 +371,7 @@ public class X509CRLSelector implements CRLSelector { try { x500Principals.add(new X500Principal((byte[])nameObject)); } catch (IllegalArgumentException e) { - throw (IOException)new IOException("Invalid name").initCause(e); + throw new IOException("Invalid name", e); } } } diff --git a/src/java.base/share/classes/java/time/Duration.java b/src/java.base/share/classes/java/time/Duration.java index e998d04eecd..6455d34d670 100644 --- a/src/java.base/share/classes/java/time/Duration.java +++ b/src/java.base/share/classes/java/time/Duration.java @@ -411,7 +411,7 @@ public final class Duration try { return create(negate, daysAsSecs, hoursAsSecs, minsAsSecs, seconds, nanos); } catch (ArithmeticException ex) { - throw (DateTimeParseException) new DateTimeParseException("Text cannot be parsed to a Duration: overflow", text, 0).initCause(ex); + throw new DateTimeParseException("Text cannot be parsed to a Duration: overflow", text, 0, ex); } } } @@ -432,7 +432,7 @@ public final class Duration long val = Long.parseLong(text, start, end, 10); return Math.multiplyExact(val, multiplier); } catch (NumberFormatException | ArithmeticException ex) { - throw (DateTimeParseException) new DateTimeParseException("Text cannot be parsed to a Duration: " + errorText, text, 0).initCause(ex); + throw new DateTimeParseException("Text cannot be parsed to a Duration: " + errorText, text, 0, ex); } } @@ -451,7 +451,7 @@ public final class Duration } return fraction * negate; } catch (NumberFormatException | ArithmeticException ex) { - throw (DateTimeParseException) new DateTimeParseException("Text cannot be parsed to a Duration: fraction", text, 0).initCause(ex); + throw new DateTimeParseException("Text cannot be parsed to a Duration: fraction", text, 0, ex); } } diff --git a/src/java.base/share/classes/javax/net/ssl/SSLContext.java b/src/java.base/share/classes/javax/net/ssl/SSLContext.java index c05c92969cb..982a375b331 100644 --- a/src/java.base/share/classes/javax/net/ssl/SSLContext.java +++ b/src/java.base/share/classes/javax/net/ssl/SSLContext.java @@ -372,12 +372,9 @@ public class SSLContext { try { return contextSpi.engineCreateSSLEngine(); } catch (AbstractMethodError e) { - UnsupportedOperationException unsup = - new UnsupportedOperationException( - "Provider: " + getProvider() + - " doesn't support this operation"); - unsup.initCause(e); - throw unsup; + throw new UnsupportedOperationException( + "Provider: " + getProvider() + + " doesn't support this operation", e); } } @@ -412,12 +409,9 @@ public class SSLContext { try { return contextSpi.engineCreateSSLEngine(peerHost, peerPort); } catch (AbstractMethodError e) { - UnsupportedOperationException unsup = - new UnsupportedOperationException( - "Provider: " + getProvider() + - " does not support this operation"); - unsup.initCause(e); - throw unsup; + throw new UnsupportedOperationException( + "Provider: " + getProvider() + + " does not support this operation", e); } } diff --git a/src/java.base/share/classes/javax/security/auth/login/Configuration.java b/src/java.base/share/classes/javax/security/auth/login/Configuration.java index b4c9bc66918..e6a0bd3166f 100644 --- a/src/java.base/share/classes/javax/security/auth/login/Configuration.java +++ b/src/java.base/share/classes/javax/security/auth/login/Configuration.java @@ -270,17 +270,15 @@ public abstract class Configuration { } catch (PrivilegedActionException e) { Exception ee = e.getException(); if (ee instanceof InstantiationException) { - throw (SecurityException) new - SecurityException + throw new SecurityException ("Configuration error:" + ee.getCause().getMessage() + - "\n").initCause(ee.getCause()); + "\n", ee.getCause()); } else { - throw (SecurityException) new - SecurityException + throw new SecurityException ("Configuration error: " + ee.toString() + - "\n").initCause(ee); + "\n", ee); } } } diff --git a/src/java.base/share/classes/javax/security/auth/x500/X500Principal.java b/src/java.base/share/classes/javax/security/auth/x500/X500Principal.java index 72666414a2d..f0bf5e0ae2e 100644 --- a/src/java.base/share/classes/javax/security/auth/x500/X500Principal.java +++ b/src/java.base/share/classes/javax/security/auth/x500/X500Principal.java @@ -181,10 +181,8 @@ public final class X500Principal implements Principal, java.io.Serializable { try { thisX500Name = new X500Name(name, keywordMap); } catch (Exception e) { - IllegalArgumentException iae = new IllegalArgumentException - ("improperly specified input name: " + name); - iae.initCause(e); - throw iae; + throw new IllegalArgumentException + ("improperly specified input name: " + name, e); } } @@ -226,10 +224,8 @@ public final class X500Principal implements Principal, java.io.Serializable { try { thisX500Name = new X500Name(name); } catch (Exception e) { - IllegalArgumentException iae = new IllegalArgumentException - ("improperly specified input name"); - iae.initCause(e); - throw iae; + throw new IllegalArgumentException + ("improperly specified input name", e); } } @@ -266,17 +262,13 @@ public final class X500Principal implements Principal, java.io.Serializable { try { is.reset(); } catch (IOException ioe) { - IllegalArgumentException iae = new IllegalArgumentException + throw new IllegalArgumentException ("improperly specified input stream " + - ("and unable to reset input stream")); - iae.initCause(e); - throw iae; + ("and unable to reset input stream"), e); } } - IllegalArgumentException iae = new IllegalArgumentException - ("improperly specified input stream"); - iae.initCause(e); - throw iae; + throw new IllegalArgumentException + ("improperly specified input stream", e); } } diff --git a/src/java.base/share/classes/sun/security/provider/DigestBase.java b/src/java.base/share/classes/sun/security/provider/DigestBase.java index 2d5f485c06e..dbe59396ac0 100644 --- a/src/java.base/share/classes/sun/security/provider/DigestBase.java +++ b/src/java.base/share/classes/sun/security/provider/DigestBase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -184,8 +184,7 @@ abstract class DigestBase extends MessageDigestSpi implements Cloneable { try { engineDigest(b, 0, b.length); } catch (DigestException e) { - throw (ProviderException) - new ProviderException("Internal error").initCause(e); + throw new ProviderException("Internal error", e); } return b; } diff --git a/src/java.base/share/classes/sun/security/provider/JavaKeyStore.java b/src/java.base/share/classes/sun/security/provider/JavaKeyStore.java index ffa547c32e2..9f00c950433 100644 --- a/src/java.base/share/classes/sun/security/provider/JavaKeyStore.java +++ b/src/java.base/share/classes/sun/security/provider/JavaKeyStore.java @@ -810,9 +810,9 @@ public abstract class JavaKeyStore extends KeyStoreSpi { if (!MessageDigest.isEqual(computed, actual)) { Throwable t = new UnrecoverableKeyException ("Password verification failed"); - throw (IOException) new IOException + throw new IOException ("Keystore was tampered with, or " - + "password was incorrect").initCause(t); + + "password was incorrect", t); } } } diff --git a/src/java.base/share/classes/sun/security/util/HostnameChecker.java b/src/java.base/share/classes/sun/security/util/HostnameChecker.java index 0183e3f4f4a..aacd94837c9 100644 --- a/src/java.base/share/classes/sun/security/util/HostnameChecker.java +++ b/src/java.base/share/classes/sun/security/util/HostnameChecker.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -254,8 +254,7 @@ public class HostnameChecker { return new X500Name(subjectX500.getEncoded()); } } catch (IOException e) { - throw(CertificateParsingException) - new CertificateParsingException().initCause(e); + throw new CertificateParsingException(e); } } -- GitLab From 7ad74d82d7117113dd73966a0dd96168adfd6463 Mon Sep 17 00:00:00 2001 From: Peter Levart Date: Tue, 5 Oct 2021 14:16:20 +0000 Subject: [PATCH 092/385] 8274299: Make Method/Constructor/Field accessors @Stable Reviewed-by: redestad, mchung --- .../java/lang/reflect/Constructor.java | 13 +- .../classes/java/lang/reflect/Field.java | 146 ++++-- .../classes/java/lang/reflect/Method.java | 8 +- .../DelegatingConstructorAccessorImpl.java | 22 +- .../reflect/DelegatingMethodAccessorImpl.java | 21 +- .../internal/reflect/FieldAccessorImpl.java | 11 + .../NativeConstructorAccessorImpl.java | 9 +- .../reflect/NativeMethodAccessorImpl.java | 9 +- .../internal/reflect/ReflectionFactory.java | 17 +- .../reflect/UnsafeFieldAccessorImpl.java | 5 +- .../UnsafeStaticFieldAccessorImpl.java | 2 + .../reflect/ReflectionColdstartBenchmark.java | 129 +++++ .../reflect/ReflectionSpeedBenchmark.java | 439 ++++++++++++++++++ 13 files changed, 747 insertions(+), 84 deletions(-) create mode 100644 test/micro/org/openjdk/bench/java/lang/reflect/ReflectionColdstartBenchmark.java create mode 100644 test/micro/org/openjdk/bench/java/lang/reflect/ReflectionSpeedBenchmark.java diff --git a/src/java.base/share/classes/java/lang/reflect/Constructor.java b/src/java.base/share/classes/java/lang/reflect/Constructor.java index eec4512b632..400a8990f8d 100644 --- a/src/java.base/share/classes/java/lang/reflect/Constructor.java +++ b/src/java.base/share/classes/java/lang/reflect/Constructor.java @@ -30,6 +30,7 @@ import jdk.internal.reflect.CallerSensitive; import jdk.internal.reflect.ConstructorAccessor; import jdk.internal.reflect.Reflection; import jdk.internal.vm.annotation.ForceInline; +import jdk.internal.vm.annotation.Stable; import sun.reflect.annotation.TypeAnnotation; import sun.reflect.annotation.TypeAnnotationParser; import sun.reflect.generics.repository.ConstructorRepository; @@ -62,10 +63,12 @@ import java.util.StringJoiner; * @since 1.1 */ public final class Constructor extends Executable { + @Stable private Class clazz; private int slot; private Class[] parameterTypes; private Class[] exceptionTypes; + @Stable private int modifiers; // Generics and annotations support private transient String signature; @@ -94,7 +97,8 @@ public final class Constructor extends Executable { return genericInfo; //return cached repository } - private volatile ConstructorAccessor constructorAccessor; + @Stable + private ConstructorAccessor constructorAccessor; // For sharing of ConstructorAccessors. This branching structure // is currently only two levels deep (i.e., one root Constructor // and potentially many Constructor objects pointing to it.) @@ -491,7 +495,7 @@ public final class Constructor extends Executable { if ((clazz.getModifiers() & Modifier.ENUM) != 0) throw new IllegalArgumentException("Cannot reflectively create enum objects"); - ConstructorAccessor ca = constructorAccessor; // read volatile + ConstructorAccessor ca = constructorAccessor; // read @Stable if (ca == null) { ca = acquireConstructorAccessor(); } @@ -532,8 +536,8 @@ public final class Constructor extends Executable { private ConstructorAccessor acquireConstructorAccessor() { // First check to see if one has been created yet, and take it // if so. - ConstructorAccessor tmp = null; - if (root != null) tmp = root.getConstructorAccessor(); + Constructor root = this.root; + ConstructorAccessor tmp = root == null ? null : root.getConstructorAccessor(); if (tmp != null) { constructorAccessor = tmp; } else { @@ -556,6 +560,7 @@ public final class Constructor extends Executable { void setConstructorAccessor(ConstructorAccessor accessor) { constructorAccessor = accessor; // Propagate up + Constructor root = this.root; if (root != null) { root.setConstructorAccessor(accessor); } diff --git a/src/java.base/share/classes/java/lang/reflect/Field.java b/src/java.base/share/classes/java/lang/reflect/Field.java index 9cbca96942f..e8d0e68671b 100644 --- a/src/java.base/share/classes/java/lang/reflect/Field.java +++ b/src/java.base/share/classes/java/lang/reflect/Field.java @@ -30,6 +30,7 @@ import jdk.internal.reflect.CallerSensitive; import jdk.internal.reflect.FieldAccessor; import jdk.internal.reflect.Reflection; import jdk.internal.vm.annotation.ForceInline; +import jdk.internal.vm.annotation.Stable; import sun.reflect.generics.repository.FieldRepository; import sun.reflect.generics.factory.CoreReflectionFactory; import sun.reflect.generics.factory.GenericsFactory; @@ -65,12 +66,15 @@ import sun.reflect.annotation.TypeAnnotationParser; public final class Field extends AccessibleObject implements Member { + @Stable private Class clazz; private int slot; // This is guaranteed to be interned by the VM in the 1.4 // reflection implementation private String name; + @Stable private Class type; + @Stable private int modifiers; private boolean trustedFinal; // Generics and annotations support @@ -79,8 +83,10 @@ class Field extends AccessibleObject implements Member { private transient FieldRepository genericInfo; private byte[] annotations; // Cached field accessor created without override + @Stable private FieldAccessor fieldAccessor; // Cached field accessor created with override + @Stable private FieldAccessor overrideFieldAccessor; // For sharing of FieldAccessors. This branching structure is // currently only two levels deep (i.e., one root Field and @@ -421,8 +427,10 @@ class Field extends AccessibleObject implements Member { if (!override) { Class caller = Reflection.getCallerClass(); checkAccess(caller, obj); + return getFieldAccessor().get(obj); + } else { + return getOverrideFieldAccessor().get(obj); } - return getFieldAccessor(obj).get(obj); } /** @@ -455,8 +463,10 @@ class Field extends AccessibleObject implements Member { if (!override) { Class caller = Reflection.getCallerClass(); checkAccess(caller, obj); + return getFieldAccessor().getBoolean(obj); + } else { + return getOverrideFieldAccessor().getBoolean(obj); } - return getFieldAccessor(obj).getBoolean(obj); } /** @@ -489,8 +499,10 @@ class Field extends AccessibleObject implements Member { if (!override) { Class caller = Reflection.getCallerClass(); checkAccess(caller, obj); + return getFieldAccessor().getByte(obj); + } else { + return getOverrideFieldAccessor().getByte(obj); } - return getFieldAccessor(obj).getByte(obj); } /** @@ -525,8 +537,10 @@ class Field extends AccessibleObject implements Member { if (!override) { Class caller = Reflection.getCallerClass(); checkAccess(caller, obj); + return getFieldAccessor().getChar(obj); + } else { + return getOverrideFieldAccessor().getChar(obj); } - return getFieldAccessor(obj).getChar(obj); } /** @@ -561,8 +575,10 @@ class Field extends AccessibleObject implements Member { if (!override) { Class caller = Reflection.getCallerClass(); checkAccess(caller, obj); + return getFieldAccessor().getShort(obj); + } else { + return getOverrideFieldAccessor().getShort(obj); } - return getFieldAccessor(obj).getShort(obj); } /** @@ -597,8 +613,10 @@ class Field extends AccessibleObject implements Member { if (!override) { Class caller = Reflection.getCallerClass(); checkAccess(caller, obj); + return getFieldAccessor().getInt(obj); + } else { + return getOverrideFieldAccessor().getInt(obj); } - return getFieldAccessor(obj).getInt(obj); } /** @@ -633,8 +651,10 @@ class Field extends AccessibleObject implements Member { if (!override) { Class caller = Reflection.getCallerClass(); checkAccess(caller, obj); + return getFieldAccessor().getLong(obj); + } else { + return getOverrideFieldAccessor().getLong(obj); } - return getFieldAccessor(obj).getLong(obj); } /** @@ -669,8 +689,10 @@ class Field extends AccessibleObject implements Member { if (!override) { Class caller = Reflection.getCallerClass(); checkAccess(caller, obj); + return getFieldAccessor().getFloat(obj); + } else { + return getOverrideFieldAccessor().getFloat(obj); } - return getFieldAccessor(obj).getFloat(obj); } /** @@ -705,8 +727,10 @@ class Field extends AccessibleObject implements Member { if (!override) { Class caller = Reflection.getCallerClass(); checkAccess(caller, obj); + return getFieldAccessor().getDouble(obj); + } else { + return getOverrideFieldAccessor().getDouble(obj); } - return getFieldAccessor(obj).getDouble(obj); } /** @@ -795,8 +819,10 @@ class Field extends AccessibleObject implements Member { if (!override) { Class caller = Reflection.getCallerClass(); checkAccess(caller, obj); + getFieldAccessor().set(obj, value); + } else { + getOverrideFieldAccessor().set(obj, value); } - getFieldAccessor(obj).set(obj, value); } /** @@ -832,8 +858,10 @@ class Field extends AccessibleObject implements Member { if (!override) { Class caller = Reflection.getCallerClass(); checkAccess(caller, obj); + getFieldAccessor().setBoolean(obj, z); + } else { + getOverrideFieldAccessor().setBoolean(obj, z); } - getFieldAccessor(obj).setBoolean(obj, z); } /** @@ -869,8 +897,10 @@ class Field extends AccessibleObject implements Member { if (!override) { Class caller = Reflection.getCallerClass(); checkAccess(caller, obj); + getFieldAccessor().setByte(obj, b); + } else { + getOverrideFieldAccessor().setByte(obj, b); } - getFieldAccessor(obj).setByte(obj, b); } /** @@ -906,8 +936,10 @@ class Field extends AccessibleObject implements Member { if (!override) { Class caller = Reflection.getCallerClass(); checkAccess(caller, obj); + getFieldAccessor().setChar(obj, c); + } else { + getOverrideFieldAccessor().setChar(obj, c); } - getFieldAccessor(obj).setChar(obj, c); } /** @@ -943,8 +975,10 @@ class Field extends AccessibleObject implements Member { if (!override) { Class caller = Reflection.getCallerClass(); checkAccess(caller, obj); + getFieldAccessor().setShort(obj, s); + } else { + getOverrideFieldAccessor().setShort(obj, s); } - getFieldAccessor(obj).setShort(obj, s); } /** @@ -980,8 +1014,10 @@ class Field extends AccessibleObject implements Member { if (!override) { Class caller = Reflection.getCallerClass(); checkAccess(caller, obj); + getFieldAccessor().setInt(obj, i); + } else { + getOverrideFieldAccessor().setInt(obj, i); } - getFieldAccessor(obj).setInt(obj, i); } /** @@ -1017,8 +1053,10 @@ class Field extends AccessibleObject implements Member { if (!override) { Class caller = Reflection.getCallerClass(); checkAccess(caller, obj); + getFieldAccessor().setLong(obj, l); + } else { + getOverrideFieldAccessor().setLong(obj, l); } - getFieldAccessor(obj).setLong(obj, l); } /** @@ -1054,8 +1092,10 @@ class Field extends AccessibleObject implements Member { if (!override) { Class caller = Reflection.getCallerClass(); checkAccess(caller, obj); + getFieldAccessor().setFloat(obj, f); + } else { + getOverrideFieldAccessor().setFloat(obj, f); } - getFieldAccessor(obj).setFloat(obj, f); } /** @@ -1091,8 +1131,10 @@ class Field extends AccessibleObject implements Member { if (!override) { Class caller = Reflection.getCallerClass(); checkAccess(caller, obj); + getFieldAccessor().setDouble(obj, d); + } else { + getOverrideFieldAccessor().setDouble(obj, d); } - getFieldAccessor(obj).setDouble(obj, d); } // check access to field @@ -1105,53 +1147,69 @@ class Field extends AccessibleObject implements Member { } // security check is done before calling this method - private FieldAccessor getFieldAccessor(Object obj) - throws IllegalAccessException - { - boolean ov = override; - FieldAccessor a = (ov) ? overrideFieldAccessor : fieldAccessor; - return (a != null) ? a : acquireFieldAccessor(ov); + private FieldAccessor getFieldAccessor() { + FieldAccessor a = fieldAccessor; + return (a != null) ? a : acquireFieldAccessor(); + } + + private FieldAccessor getOverrideFieldAccessor() { + FieldAccessor a = overrideFieldAccessor; + return (a != null) ? a : acquireOverrideFieldAccessor(); } // NOTE that there is no synchronization used here. It is correct // (though not efficient) to generate more than one FieldAccessor // for a given Field. However, avoiding synchronization will // probably make the implementation more scalable. - private FieldAccessor acquireFieldAccessor(boolean overrideFinalCheck) { + private FieldAccessor acquireFieldAccessor() { // First check to see if one has been created yet, and take it // if so - FieldAccessor tmp = null; - if (root != null) tmp = root.getFieldAccessor(overrideFinalCheck); + Field root = this.root; + FieldAccessor tmp = root == null ? null : root.fieldAccessor; if (tmp != null) { - if (overrideFinalCheck) - overrideFieldAccessor = tmp; - else - fieldAccessor = tmp; + fieldAccessor = tmp; } else { // Otherwise fabricate one and propagate it up to the root - tmp = reflectionFactory.newFieldAccessor(this, overrideFinalCheck); - setFieldAccessor(tmp, overrideFinalCheck); + tmp = reflectionFactory.newFieldAccessor(this, false); + setFieldAccessor(tmp); } + return tmp; + } + private FieldAccessor acquireOverrideFieldAccessor() { + // First check to see if one has been created yet, and take it + // if so + Field root = this.root; + FieldAccessor tmp = root == null ? null : root.overrideFieldAccessor; + if (tmp != null) { + overrideFieldAccessor = tmp; + } else { + // Otherwise fabricate one and propagate it up to the root + tmp = reflectionFactory.newFieldAccessor(this, true); + setOverrideFieldAccessor(tmp); + } return tmp; } - // Returns FieldAccessor for this Field object, not looking up - // the chain to the root - private FieldAccessor getFieldAccessor(boolean overrideFinalCheck) { - return (overrideFinalCheck)? overrideFieldAccessor : fieldAccessor; + // Sets the fieldAccessor for this Field object and + // (recursively) its root + private void setFieldAccessor(FieldAccessor accessor) { + fieldAccessor = accessor; + // Propagate up + Field root = this.root; + if (root != null) { + root.setFieldAccessor(accessor); + } } - // Sets the FieldAccessor for this Field object and + // Sets the overrideFieldAccessor for this Field object and // (recursively) its root - private void setFieldAccessor(FieldAccessor accessor, boolean overrideFinalCheck) { - if (overrideFinalCheck) - overrideFieldAccessor = accessor; - else - fieldAccessor = accessor; + private void setOverrideFieldAccessor(FieldAccessor accessor) { + overrideFieldAccessor = accessor; // Propagate up + Field root = this.root; if (root != null) { - root.setFieldAccessor(accessor, overrideFinalCheck); + root.setOverrideFieldAccessor(accessor); } } diff --git a/src/java.base/share/classes/java/lang/reflect/Method.java b/src/java.base/share/classes/java/lang/reflect/Method.java index dedf2d5dd91..037c4c7008a 100644 --- a/src/java.base/share/classes/java/lang/reflect/Method.java +++ b/src/java.base/share/classes/java/lang/reflect/Method.java @@ -85,7 +85,8 @@ public final class Method extends Executable { private byte[] annotations; private byte[] parameterAnnotations; private byte[] annotationDefault; - private volatile MethodAccessor methodAccessor; + @Stable + private MethodAccessor methodAccessor; // For sharing of MethodAccessors. This branching structure is // currently only two levels deep (i.e., one root Method and // potentially many Method objects pointing to it.) @@ -665,8 +666,8 @@ public final class Method extends Executable { private MethodAccessor acquireMethodAccessor() { // First check to see if one has been created yet, and take it // if so - MethodAccessor tmp = null; - if (root != null) tmp = root.getMethodAccessor(); + Method root = this.root; + MethodAccessor tmp = root == null ? null : root.getMethodAccessor(); if (tmp != null) { methodAccessor = tmp; } else { @@ -689,6 +690,7 @@ public final class Method extends Executable { void setMethodAccessor(MethodAccessor accessor) { methodAccessor = accessor; // Propagate up + Method root = this.root; if (root != null) { root.setMethodAccessor(accessor); } diff --git a/src/java.base/share/classes/jdk/internal/reflect/DelegatingConstructorAccessorImpl.java b/src/java.base/share/classes/jdk/internal/reflect/DelegatingConstructorAccessorImpl.java index 6b0f7f51b13..eaa9a786392 100644 --- a/src/java.base/share/classes/jdk/internal/reflect/DelegatingConstructorAccessorImpl.java +++ b/src/java.base/share/classes/jdk/internal/reflect/DelegatingConstructorAccessorImpl.java @@ -25,16 +25,25 @@ package jdk.internal.reflect; +import jdk.internal.vm.annotation.Stable; + import java.lang.reflect.InvocationTargetException; +import java.util.Objects; /** Delegates its invocation to another ConstructorAccessorImpl and can change its delegate at run time. */ class DelegatingConstructorAccessorImpl extends ConstructorAccessorImpl { - private ConstructorAccessorImpl delegate; + // initial non-null delegate + @Stable + private final ConstructorAccessorImpl initialDelegate; + // alternative delegate: starts as null; + // only single change from null -> non-null is guaranteed + @Stable + private ConstructorAccessorImpl altDelegate; DelegatingConstructorAccessorImpl(ConstructorAccessorImpl delegate) { - setDelegate(delegate); + initialDelegate = Objects.requireNonNull(delegate); } public Object newInstance(Object[] args) @@ -42,10 +51,15 @@ class DelegatingConstructorAccessorImpl extends ConstructorAccessorImpl { IllegalArgumentException, InvocationTargetException { - return delegate.newInstance(args); + return delegate().newInstance(args); + } + + private ConstructorAccessorImpl delegate() { + var d = altDelegate; + return d != null ? d : initialDelegate; } void setDelegate(ConstructorAccessorImpl delegate) { - this.delegate = delegate; + altDelegate = Objects.requireNonNull(delegate); } } diff --git a/src/java.base/share/classes/jdk/internal/reflect/DelegatingMethodAccessorImpl.java b/src/java.base/share/classes/jdk/internal/reflect/DelegatingMethodAccessorImpl.java index 1acab93eb42..09cb4159174 100644 --- a/src/java.base/share/classes/jdk/internal/reflect/DelegatingMethodAccessorImpl.java +++ b/src/java.base/share/classes/jdk/internal/reflect/DelegatingMethodAccessorImpl.java @@ -25,25 +25,38 @@ package jdk.internal.reflect; +import jdk.internal.vm.annotation.Stable; + import java.lang.reflect.InvocationTargetException; +import java.util.Objects; /** Delegates its invocation to another MethodAccessorImpl and can change its delegate at run time. */ class DelegatingMethodAccessorImpl extends MethodAccessorImpl { - private MethodAccessorImpl delegate; + // initial non-null delegate + @Stable private final MethodAccessorImpl initialDelegate; + // alternative delegate: starts as null; + // only single change from null -> non-null is guaranteed + @Stable private MethodAccessorImpl altDelegate; DelegatingMethodAccessorImpl(MethodAccessorImpl delegate) { - setDelegate(delegate); + initialDelegate = Objects.requireNonNull(delegate); } + @Override public Object invoke(Object obj, Object[] args) throws IllegalArgumentException, InvocationTargetException { - return delegate.invoke(obj, args); + return delegate().invoke(obj, args); + } + + private MethodAccessorImpl delegate() { + var d = altDelegate; + return d != null ? d : initialDelegate; } void setDelegate(MethodAccessorImpl delegate) { - this.delegate = delegate; + altDelegate = Objects.requireNonNull(delegate); } } diff --git a/src/java.base/share/classes/jdk/internal/reflect/FieldAccessorImpl.java b/src/java.base/share/classes/jdk/internal/reflect/FieldAccessorImpl.java index b5121c860dc..b703d082534 100644 --- a/src/java.base/share/classes/jdk/internal/reflect/FieldAccessorImpl.java +++ b/src/java.base/share/classes/jdk/internal/reflect/FieldAccessorImpl.java @@ -25,12 +25,23 @@ package jdk.internal.reflect; +import jdk.internal.vm.annotation.Stable; + +import java.lang.reflect.Field; + /** Package-private implementation of the FieldAccessor interface which has access to all classes and all fields, regardless of language restrictions. See MagicAccessorImpl. */ abstract class FieldAccessorImpl extends MagicAccessorImpl implements FieldAccessor { + @Stable + protected final Field field; + + FieldAccessorImpl(Field field) { + this.field = field; + } + /** Matches specification in {@link java.lang.reflect.Field} */ public abstract Object get(Object obj) throws IllegalArgumentException; diff --git a/src/java.base/share/classes/jdk/internal/reflect/NativeConstructorAccessorImpl.java b/src/java.base/share/classes/jdk/internal/reflect/NativeConstructorAccessorImpl.java index 06eb4f7748f..6cd7d7d0f01 100644 --- a/src/java.base/share/classes/jdk/internal/reflect/NativeConstructorAccessorImpl.java +++ b/src/java.base/share/classes/jdk/internal/reflect/NativeConstructorAccessorImpl.java @@ -25,8 +25,6 @@ package jdk.internal.reflect; -import sun.reflect.misc.ReflectUtil; - import java.lang.reflect.*; import jdk.internal.misc.Unsafe; @@ -39,12 +37,13 @@ class NativeConstructorAccessorImpl extends ConstructorAccessorImpl { = U.objectFieldOffset(NativeConstructorAccessorImpl.class, "generated"); private final Constructor c; - private DelegatingConstructorAccessorImpl parent; + private final DelegatingConstructorAccessorImpl parent; private int numInvocations; private volatile int generated; NativeConstructorAccessorImpl(Constructor c) { this.c = c; + this.parent = new DelegatingConstructorAccessorImpl(this); } public Object newInstance(Object[] args) @@ -77,8 +76,8 @@ class NativeConstructorAccessorImpl extends ConstructorAccessorImpl { return newInstance0(c, args); } - void setParent(DelegatingConstructorAccessorImpl parent) { - this.parent = parent; + DelegatingConstructorAccessorImpl getParent() { + return parent; } private static native Object newInstance0(Constructor c, Object[] args) diff --git a/src/java.base/share/classes/jdk/internal/reflect/NativeMethodAccessorImpl.java b/src/java.base/share/classes/jdk/internal/reflect/NativeMethodAccessorImpl.java index 1198b56d746..7f57035a0dd 100644 --- a/src/java.base/share/classes/jdk/internal/reflect/NativeMethodAccessorImpl.java +++ b/src/java.base/share/classes/jdk/internal/reflect/NativeMethodAccessorImpl.java @@ -25,8 +25,6 @@ package jdk.internal.reflect; -import sun.reflect.misc.ReflectUtil; - import java.lang.reflect.*; import jdk.internal.misc.Unsafe; @@ -39,12 +37,13 @@ class NativeMethodAccessorImpl extends MethodAccessorImpl { = U.objectFieldOffset(NativeMethodAccessorImpl.class, "generated"); private final Method method; - private DelegatingMethodAccessorImpl parent; + private final DelegatingMethodAccessorImpl parent; private int numInvocations; private volatile int generated; NativeMethodAccessorImpl(Method method) { this.method = method; + this.parent = new DelegatingMethodAccessorImpl(this); } public Object invoke(Object obj, Object[] args) @@ -77,8 +76,8 @@ class NativeMethodAccessorImpl extends MethodAccessorImpl { return invoke0(method, obj, args); } - void setParent(DelegatingMethodAccessorImpl parent) { - this.parent = parent; + DelegatingMethodAccessorImpl getParent() { + return parent; } private static native Object invoke0(Method m, Object obj, Object[] args); diff --git a/src/java.base/share/classes/jdk/internal/reflect/ReflectionFactory.java b/src/java.base/share/classes/jdk/internal/reflect/ReflectionFactory.java index a6b896df7fe..17f0c7d95f2 100644 --- a/src/java.base/share/classes/jdk/internal/reflect/ReflectionFactory.java +++ b/src/java.base/share/classes/jdk/internal/reflect/ReflectionFactory.java @@ -44,7 +44,6 @@ import java.util.Properties; import jdk.internal.access.JavaLangReflectAccess; import jdk.internal.access.SharedSecrets; import jdk.internal.misc.VM; -import sun.reflect.misc.ReflectUtil; import sun.security.action.GetPropertyAction; import sun.security.util.SecurityConstants; @@ -210,12 +209,8 @@ public class ReflectionFactory { method.getExceptionTypes(), method.getModifiers()); } else { - NativeMethodAccessorImpl acc = - new NativeMethodAccessorImpl(method); - DelegatingMethodAccessorImpl res = - new DelegatingMethodAccessorImpl(acc); - acc.setParent(res); - return res; + NativeMethodAccessorImpl acc = new NativeMethodAccessorImpl(method); + return acc.getParent(); } } @@ -252,12 +247,8 @@ public class ReflectionFactory { c.getExceptionTypes(), c.getModifiers()); } else { - NativeConstructorAccessorImpl acc = - new NativeConstructorAccessorImpl(c); - DelegatingConstructorAccessorImpl res = - new DelegatingConstructorAccessorImpl(acc); - acc.setParent(res); - return res; + NativeConstructorAccessorImpl acc = new NativeConstructorAccessorImpl(c); + return acc.getParent(); } } diff --git a/src/java.base/share/classes/jdk/internal/reflect/UnsafeFieldAccessorImpl.java b/src/java.base/share/classes/jdk/internal/reflect/UnsafeFieldAccessorImpl.java index 1c6fd0046a5..9f43263bf3e 100644 --- a/src/java.base/share/classes/jdk/internal/reflect/UnsafeFieldAccessorImpl.java +++ b/src/java.base/share/classes/jdk/internal/reflect/UnsafeFieldAccessorImpl.java @@ -28,6 +28,7 @@ package jdk.internal.reflect; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import jdk.internal.misc.Unsafe; +import jdk.internal.vm.annotation.Stable; /** Base class for jdk.internal.misc.Unsafe-based FieldAccessors. The observation is that there are only nine types of fields from the @@ -39,12 +40,12 @@ import jdk.internal.misc.Unsafe; abstract class UnsafeFieldAccessorImpl extends FieldAccessorImpl { static final Unsafe unsafe = Unsafe.getUnsafe(); - protected final Field field; + @Stable protected final long fieldOffset; protected final boolean isFinal; UnsafeFieldAccessorImpl(Field field) { - this.field = field; + super(field); if (Modifier.isStatic(field.getModifiers())) fieldOffset = unsafe.staticFieldOffset(field); else diff --git a/src/java.base/share/classes/jdk/internal/reflect/UnsafeStaticFieldAccessorImpl.java b/src/java.base/share/classes/jdk/internal/reflect/UnsafeStaticFieldAccessorImpl.java index eab39628e88..e75fffb1328 100644 --- a/src/java.base/share/classes/jdk/internal/reflect/UnsafeStaticFieldAccessorImpl.java +++ b/src/java.base/share/classes/jdk/internal/reflect/UnsafeStaticFieldAccessorImpl.java @@ -31,6 +31,7 @@ import java.security.AccessController; import java.util.Set; import jdk.internal.misc.Unsafe; +import jdk.internal.vm.annotation.Stable; /** Base class for jdk.internal.misc.Unsafe-based FieldAccessors for static fields. The observation is that there are only nine types of @@ -45,6 +46,7 @@ abstract class UnsafeStaticFieldAccessorImpl extends UnsafeFieldAccessorImpl { Set.of("base")); } + @Stable protected final Object base; // base UnsafeStaticFieldAccessorImpl(Field field) { diff --git a/test/micro/org/openjdk/bench/java/lang/reflect/ReflectionColdstartBenchmark.java b/test/micro/org/openjdk/bench/java/lang/reflect/ReflectionColdstartBenchmark.java new file mode 100644 index 00000000000..743e8842dbb --- /dev/null +++ b/test/micro/org/openjdk/bench/java/lang/reflect/ReflectionColdstartBenchmark.java @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.bench.java.lang.reflect; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.infra.Blackhole; + +import java.lang.reflect.Method; +import java.util.concurrent.TimeUnit; + +/** + * Benchmark measuring cold-start of reflective method invocation. + */ +@BenchmarkMode(Mode.SingleShotTime) +@OutputTimeUnit(TimeUnit.MICROSECONDS) +@State(Scope.Benchmark) +@Fork(value = 30, warmups = 10) +public class ReflectionColdstartBenchmark { + + static class Nested { + static Object m00(Object p) {return p;} + + static Object m01(Object p) {return p;} + + static Object m02(Object p) {return p;} + + static Object m03(Object p) {return p;} + + static Object m04(Object p) {return p;} + + static Object m05(Object p) {return p;} + + static Object m06(Object p) {return p;} + + static Object m07(Object p) {return p;} + + static Object m08(Object p) {return p;} + + static Object m09(Object p) {return p;} + + static Object m0A(Object p) {return p;} + + static Object m0B(Object p) {return p;} + + static Object m0C(Object p) {return p;} + + static Object m0D(Object p) {return p;} + + static Object m0E(Object p) {return p;} + + static Object m0F(Object p) {return p;} + + static Object m10(Object p) {return p;} + + static Object m11(Object p) {return p;} + + static Object m12(Object p) {return p;} + + static Object m13(Object p) {return p;} + + static Object m14(Object p) {return p;} + + static Object m15(Object p) {return p;} + + static Object m16(Object p) {return p;} + + static Object m17(Object p) {return p;} + + static Object m18(Object p) {return p;} + + static Object m19(Object p) {return p;} + + static Object m1A(Object p) {return p;} + + static Object m1B(Object p) {return p;} + + static Object m1C(Object p) {return p;} + + static Object m1D(Object p) {return p;} + + static Object m1E(Object p) {return p;} + + static Object m1F(Object p) {return p;} + } + + private Method[] methods; + private Object arg; + + @Setup(Level.Trial) + public void setup() { + methods = Nested.class.getDeclaredMethods(); + arg = new Object(); + } + + @Benchmark + public void invokeMethods(Blackhole bh) throws ReflectiveOperationException { + for (Method m : methods) { + bh.consume(m.invoke(null, arg)); + } + } +} diff --git a/test/micro/org/openjdk/bench/java/lang/reflect/ReflectionSpeedBenchmark.java b/test/micro/org/openjdk/bench/java/lang/reflect/ReflectionSpeedBenchmark.java new file mode 100644 index 00000000000..c2cdbb4cc21 --- /dev/null +++ b/test/micro/org/openjdk/bench/java/lang/reflect/ReflectionSpeedBenchmark.java @@ -0,0 +1,439 @@ +/* + * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.bench.java.lang.reflect; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.concurrent.TimeUnit; + +/** + * Benchmark measuring field access and method invocation using different conditions: + *
      + *
    • Const - Method/Field is constant-foldable
    • + *
    • Var - Method/Field is single-instance but not constant-foldable
    • + *
    • Poly - multiple Method/Field instances used at single call-site
    • + *
    + */ +@BenchmarkMode(Mode.AverageTime) +@Warmup(iterations = 10, time = 1, batchSize = 10) +@Measurement(iterations = 10, time = 1, batchSize = 10) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Thread) +@Fork(value = 1, warmups = 0) +public class ReflectionSpeedBenchmark { + + static final Method staticMethodConst; + static final Method instanceMethodConst; + static final Field staticFieldConst; + static final Field instanceFieldConst; + static final Constructor constructorConst; + static final Object[] constructorArgs; + + static Method staticMethodVar; + static Method instanceMethodVar; + static Field staticFieldVar; + static Field instanceFieldVar; + static Constructor constructorVar; + + static Method[] staticMethodsPoly; + static Method[] instanceMethodsPoly; + static Field[] staticFieldsPoly; + static Field[] instanceFieldsPoly; + static Constructor[] constructorsPoly; + static Object[][] constructorsArgsPoly; + + static { + try { + staticMethodConst = staticMethodVar = ReflectionSpeedBenchmark.class.getDeclaredMethod("sumStatic", int.class, int.class); + instanceMethodConst = instanceMethodVar = ReflectionSpeedBenchmark.class.getDeclaredMethod("sumInstance", int.class, int.class); + + staticFieldConst = staticFieldVar = ReflectionSpeedBenchmark.class.getDeclaredField("staticField"); + instanceFieldConst = instanceFieldVar = ReflectionSpeedBenchmark.class.getDeclaredField("instanceField"); + + constructorConst = constructorVar = NestedConstruction.class.getDeclaredConstructor(); + constructorArgs = new Object[0]; + + staticMethodsPoly = NestedStatic.class.getDeclaredMethods(); + staticFieldsPoly = NestedStatic.class.getDeclaredFields(); + instanceMethodsPoly = NestedInstance.class.getDeclaredMethods(); + instanceFieldsPoly = NestedInstance.class.getDeclaredFields(); + + constructorsPoly = NestedConstruction.class.getDeclaredConstructors(); + constructorsArgsPoly = new Object[constructorsPoly.length][]; + for (int i = 0; i < constructorsPoly.length; i++) { + constructorsArgsPoly[i] = new Object[constructorsPoly[i].getParameterCount()]; + } + } catch (NoSuchMethodException e) { + throw new NoSuchMethodError(e.getMessage()); + } catch (NoSuchFieldException e) { + throw new NoSuchFieldError(e.getMessage()); + } + } + + public static class NestedStatic { + // # of fields must be 2^N + public static Object + f00, f01, f02, f03, f04, f05, f06, f07, f08, f09, f0A, f0B, f0C, f0D, f0E, f0F, + f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f1A, f1B, f1C, f1D, f1E, f1F; + + // # of methods must be 2^N + public static Object m00(Object p) {return p;} + + public static Object m01(Object p) {return p;} + + public static Object m02(Object p) {return p;} + + public static Object m03(Object p) {return p;} + + public static Object m04(Object p) {return p;} + + public static Object m05(Object p) {return p;} + + public static Object m06(Object p) {return p;} + + public static Object m07(Object p) {return p;} + + public static Object m08(Object p) {return p;} + + public static Object m09(Object p) {return p;} + + public static Object m0A(Object p) {return p;} + + public static Object m0B(Object p) {return p;} + + public static Object m0C(Object p) {return p;} + + public static Object m0D(Object p) {return p;} + + public static Object m0E(Object p) {return p;} + + public static Object m0F(Object p) {return p;} + + public static Object m10(Object p) {return p;} + + public static Object m11(Object p) {return p;} + + public static Object m12(Object p) {return p;} + + public static Object m13(Object p) {return p;} + + public static Object m14(Object p) {return p;} + + public static Object m15(Object p) {return p;} + + public static Object m16(Object p) {return p;} + + public static Object m17(Object p) {return p;} + + public static Object m18(Object p) {return p;} + + public static Object m19(Object p) {return p;} + + public static Object m1A(Object p) {return p;} + + public static Object m1B(Object p) {return p;} + + public static Object m1C(Object p) {return p;} + + public static Object m1D(Object p) {return p;} + + public static Object m1E(Object p) {return p;} + + public static Object m1F(Object p) {return p;} + } + + public static class NestedInstance { + // # of fields must be 2^N + public Object + f00, f01, f02, f03, f04, f05, f06, f07, f08, f09, f0A, f0B, f0C, f0D, f0E, f0F, + f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f1A, f1B, f1C, f1D, f1E, f1F; + + // # of methods must be 2^N + public Object m00(Object p) {return p;} + + public Object m01(Object p) {return p;} + + public Object m02(Object p) {return p;} + + public Object m03(Object p) {return p;} + + public Object m04(Object p) {return p;} + + public Object m05(Object p) {return p;} + + public Object m06(Object p) {return p;} + + public Object m07(Object p) {return p;} + + public Object m08(Object p) {return p;} + + public Object m09(Object p) {return p;} + + public Object m0A(Object p) {return p;} + + public Object m0B(Object p) {return p;} + + public Object m0C(Object p) {return p;} + + public Object m0D(Object p) {return p;} + + public Object m0E(Object p) {return p;} + + public Object m0F(Object p) {return p;} + + public Object m10(Object p) {return p;} + + public Object m11(Object p) {return p;} + + public Object m12(Object p) {return p;} + + public Object m13(Object p) {return p;} + + public Object m14(Object p) {return p;} + + public Object m15(Object p) {return p;} + + public Object m16(Object p) {return p;} + + public Object m17(Object p) {return p;} + + public Object m18(Object p) {return p;} + + public Object m19(Object p) {return p;} + + public Object m1A(Object p) {return p;} + + public Object m1B(Object p) {return p;} + + public Object m1C(Object p) {return p;} + + public Object m1D(Object p) {return p;} + + public Object m1E(Object p) {return p;} + + public Object m1F(Object p) {return p;} + } + + public static class NestedConstruction { + // # of constructors must be 2^N + public NestedConstruction() {} + + public NestedConstruction(Void p1) {} + + public NestedConstruction(Void p1, Void p2) {} + + public NestedConstruction(Void p1, Void p2, Void p3) {} + + public NestedConstruction(Void p1, Void p2, Void p3, Void p4) {} + + public NestedConstruction(Void p1, Void p2, Void p3, Void p4, Void p5) {} + + public NestedConstruction(Void p1, Void p2, Void p3, Void p4, Void p5, Void p6) {} + + public NestedConstruction(Void p1, Void p2, Void p3, Void p4, Void p5, Void p6, Void p7) {} + } + + private int rnd = 0; + private int a, b; + private Object o; + private NestedInstance instance; + + private int nextRnd() { + return rnd += 7; + } + + @Setup(Level.Iteration) + public void setup() { + a = nextRnd(); + b = nextRnd(); + o = new Object(); + instance = new NestedInstance(); + } + + public static int sumStatic(int a, int b) { + return a + b; + } + + public int sumInstance(int a, int b) { + return a + b; + } + + public static int staticField; + public int instanceField; + + // methods + + @Benchmark + public int staticMethodConst() { + try { + return (Integer) staticMethodConst.invoke(null, a, b); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new AssertionError(e); + } + } + + @Benchmark + public int instanceMethodConst() { + try { + return (Integer) instanceMethodConst.invoke(this, a, b); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new AssertionError(e); + } + } + + @Benchmark + public int staticMethodVar() { + try { + return (Integer) staticMethodVar.invoke(null, a, b); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new AssertionError(e); + } + } + + @Benchmark + public int instanceMethodVar() { + try { + return (Integer) instanceMethodVar.invoke(this, a, b); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new AssertionError(e); + } + } + + @Benchmark + public Object staticMethodPoly() { + try { + return staticMethodsPoly[nextRnd() & (staticMethodsPoly.length - 1)].invoke(null, o); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new AssertionError(e); + } + } + + @Benchmark + public Object instanceMethodPoly() { + try { + return instanceMethodsPoly[nextRnd() & (instanceMethodsPoly.length - 1)].invoke(instance, o); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new AssertionError(e); + } + } + + // fields + + @Benchmark + public int staticFieldConst() { + try { + return staticFieldConst.getInt(null); + } catch (IllegalAccessException e) { + throw new AssertionError(e); + } + } + + @Benchmark + public int instanceFieldConst() { + try { + return instanceFieldConst.getInt(this); + } catch (IllegalAccessException e) { + throw new AssertionError(e); + } + } + + @Benchmark + public int staticFieldVar() { + try { + return staticFieldVar.getInt(null); + } catch (IllegalAccessException e) { + throw new AssertionError(e); + } + } + + @Benchmark + public int instanceFieldVar() { + try { + return instanceFieldVar.getInt(this); + } catch (IllegalAccessException e) { + throw new AssertionError(e); + } + } + + @Benchmark + public Object staticFieldPoly() { + try { + return staticFieldsPoly[nextRnd() & (staticFieldsPoly.length - 1)].get(null); + } catch (IllegalAccessException e) { + throw new AssertionError(e); + } + } + + @Benchmark + public Object instanceFieldPoly() { + try { + return instanceFieldsPoly[nextRnd() & (instanceFieldsPoly.length - 1)].get(instance); + } catch (IllegalAccessException e) { + throw new AssertionError(e); + } + } + + // constructors + + @Benchmark + public Object constructorConst() { + try { + return constructorConst.newInstance(constructorArgs); + } catch (ReflectiveOperationException e) { + throw new AssertionError(e); + } + } + + @Benchmark + public Object constructorVar() { + try { + return constructorVar.newInstance(constructorArgs); + } catch (ReflectiveOperationException e) { + throw new AssertionError(e); + } + } + + @Benchmark + public Object constructorPoly() { + try { + int i = nextRnd() & (constructorsPoly.length - 1); + return constructorsPoly[i].newInstance(constructorsArgsPoly[i]); + } catch (ReflectiveOperationException e) { + throw new AssertionError(e); + } + } +} \ No newline at end of file -- GitLab From bb0bab57a1ff447bfb41cfe10c91838a6812b93d Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Tue, 5 Oct 2021 14:31:17 +0000 Subject: [PATCH 093/385] 8274286: Skip null for make_referent_alive in referenceProcessor Reviewed-by: kbarrett, tschatzl --- .../share/gc/shared/referenceProcessor.cpp | 37 ++++++++++++------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/src/hotspot/share/gc/shared/referenceProcessor.cpp b/src/hotspot/share/gc/shared/referenceProcessor.cpp index e3886e8de14..c67447e0fe7 100644 --- a/src/hotspot/share/gc/shared/referenceProcessor.cpp +++ b/src/hotspot/share/gc/shared/referenceProcessor.cpp @@ -290,6 +290,15 @@ void DiscoveredListIterator::complete_enqueue() { } } +inline void log_preclean_ref(const DiscoveredListIterator& iter, const char* reason) { + if (log_develop_is_enabled(Trace, gc, ref)) { + ResourceMark rm; + log_develop_trace(gc, ref)("Precleaning %s reference " PTR_FORMAT ": %s", + reason, p2i(iter.obj()), + iter.obj()->klass()->internal_name()); + } +} + inline void log_dropped_ref(const DiscoveredListIterator& iter, const char* reason) { if (log_develop_is_enabled(Trace, gc, ref)) { ResourceMark rm; @@ -1125,14 +1134,15 @@ void ReferenceProcessor::preclean_discovered_references(BoolObjectClosure* is_al } } -// Walk the given discovered ref list, and remove all reference objects -// whose referents are still alive, whose referents are NULL or which -// are not active (have a non-NULL next field). NOTE: When we are -// thus precleaning the ref lists (which happens single-threaded today), -// we do not disable refs discovery to honor the correct semantics of -// java.lang.Reference. As a result, we need to be careful below -// that ref removal steps interleave safely with ref discovery steps -// (in this thread). +// Walk the given discovered ref list, and remove all reference objects whose +// referents are still alive or NULL. NOTE: When we are precleaning the +// ref lists, we do not disable refs discovery to honor the correct semantics of +// java.lang.Reference. Therefore, as we iterate over the discovered list (DL) +// and drop elements from it, newly discovered refs can be discovered and added +// to the DL. Because precleaning is implemented single-threaded today, for +// each per-thread DL, the insertion of refs (calling `complete_gc`) happens +// after the iteration. The clear separation means no special synchronization +// is needed. bool ReferenceProcessor::preclean_discovered_reflist(DiscoveredList& refs_list, BoolObjectClosure* is_alive, OopClosure* keep_alive, @@ -1145,11 +1155,12 @@ bool ReferenceProcessor::preclean_discovered_reflist(DiscoveredList& refs_lis return true; } iter.load_ptrs(DEBUG_ONLY(true /* allow_null_referent */)); - if (iter.referent() == NULL || iter.is_referent_alive()) { - // The referent has been cleared, or is alive; we need to trace - // and mark its cohort. - log_develop_trace(gc, ref)("Precleaning Reference (" INTPTR_FORMAT ": %s)", - p2i(iter.obj()), iter.obj()->klass()->internal_name()); + if (iter.referent() == nullptr) { + log_preclean_ref(iter, "cleared"); + iter.remove(); + iter.move_to_next(); + } else if (iter.is_referent_alive()) { + log_preclean_ref(iter, "reachable"); // Remove Reference object from list iter.remove(); // Keep alive its cohort. -- GitLab From 90a5ae802e6ef0a6d0a5096a595b0680069960c3 Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Tue, 5 Oct 2021 15:13:54 +0000 Subject: [PATCH 094/385] 8274282: Clarify special wait assert Reviewed-by: dholmes, pchilanomate --- src/hotspot/share/runtime/mutex.cpp | 13 +++++++--- test/hotspot/gtest/runtime/test_mutex.cpp | 31 ++++++++++++++--------- 2 files changed, 29 insertions(+), 15 deletions(-) diff --git a/src/hotspot/share/runtime/mutex.cpp b/src/hotspot/share/runtime/mutex.cpp index 98f56a3c18b..08af284127f 100644 --- a/src/hotspot/share/runtime/mutex.cpp +++ b/src/hotspot/share/runtime/mutex.cpp @@ -384,14 +384,21 @@ void Mutex::check_rank(Thread* thread) { if (owned_by_self()) { // wait() case Mutex* least = get_least_ranked_lock_besides_this(locks_owned); - // We enforce not holding locks of rank nosafepoint or lower while waiting. + // For JavaThreads, we enforce not holding locks of rank nosafepoint or lower while waiting + // because the held lock has a NoSafepointVerifier so waiting on a lower ranked lock will not be + // able to check for safepoints first with a TBIVM. + // For all threads, we enforce not holding the tty lock or below, since this could block progress also. // Also "this" should be the monitor with lowest rank owned by this thread. - if (least != NULL && (least->rank() <= nosafepoint || least->rank() <= this->rank())) { + if (least != NULL && ((least->rank() <= Mutex::nosafepoint && thread->is_Java_thread()) || + least->rank() <= Mutex::tty || + least->rank() <= this->rank())) { assert(false, "Attempting to wait on monitor %s/%d while holding lock %s/%d -- " "possible deadlock. %s", name(), rank(), least->name(), least->rank(), least->rank() <= this->rank() ? "Should wait on the least ranked monitor from all owned locks." : - "Should not block(wait) while holding a lock of rank nosafepoint or below."); + thread->is_Java_thread() ? + "Should not block(wait) while holding a lock of rank nosafepoint or below." : + "Should not block(wait) while holding a lock of rank tty or below."); } } else { // lock()/lock_without_safepoint_check()/try_lock() case diff --git a/test/hotspot/gtest/runtime/test_mutex.cpp b/test/hotspot/gtest/runtime/test_mutex.cpp index 2115ae2dfb9..47df5f1dcad 100644 --- a/test/hotspot/gtest/runtime/test_mutex.cpp +++ b/test/hotspot/gtest/runtime/test_mutex.cpp @@ -220,20 +220,27 @@ TEST_VM_ASSERT_MSG(MutexRank, monitor_wait_rank_nosafepoint, monitor_rank_nosafepoint->unlock(); } +// NonJavaThreads can't wait while holding tty lock or below. +class VM_MutexWaitTTY : public VM_GTestExecuteAtSafepoint { + public: + void doit() { + Monitor* monitor_rank_tty = new Monitor(Mutex::tty, "monitor_rank_tty", Mutex::_safepoint_check_never); + Monitor* monitor_rank_event = new Monitor(Mutex::event, "monitor_rank_event", Mutex::_safepoint_check_never); + + monitor_rank_tty->lock_without_safepoint_check(); + monitor_rank_event->lock_without_safepoint_check(); + monitor_rank_event->wait_without_safepoint_check(1); + monitor_rank_event->unlock(); + monitor_rank_tty->unlock(); + } +}; + TEST_VM_ASSERT_MSG(MutexRank, monitor_wait_event_tty, ".* Attempting to wait on monitor monitor_rank_event/0 while holding lock monitor_rank_tty/.*" - "-- possible deadlock. Should not block\\(wait\\) while holding a lock of rank nosafepoint or below.") { - JavaThread* THREAD = JavaThread::current(); - ThreadInVMfromNative invm(THREAD); - - Monitor* monitor_rank_tty = new Monitor(Mutex::tty, "monitor_rank_tty", Mutex::_safepoint_check_never); - Monitor* monitor_rank_event = new Monitor(Mutex::event, "monitor_rank_event", Mutex::_safepoint_check_never); - - monitor_rank_tty->lock_without_safepoint_check(); - monitor_rank_event->lock_without_safepoint_check(); - monitor_rank_event->wait_without_safepoint_check(1); - monitor_rank_event->unlock(); - monitor_rank_tty->unlock(); + "-- possible deadlock. Should not block\\(wait\\) while holding a lock of rank tty or below.") { + VM_MutexWaitTTY op; + ThreadInVMfromNative invm(JavaThread::current()); + VMThread::execute(&op); } TEST_VM_ASSERT_MSG(MutexRank, monitor_wait_tty_nosafepoint, -- GitLab From 92b64a2053e3f3e0314ed489b92afd37c285ac5f Mon Sep 17 00:00:00 2001 From: Jonathan Gibbons Date: Tue, 5 Oct 2021 15:21:44 +0000 Subject: [PATCH 095/385] 8273745: VerifyLocale.java occasionally times out Reviewed-by: prappo --- .../jdk/javadoc/tool/VerifyLocale.java | 37 +++++++++++++++---- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/test/langtools/jdk/javadoc/tool/VerifyLocale.java b/test/langtools/jdk/javadoc/tool/VerifyLocale.java index 9e72d78f062..1ee7c4926df 100644 --- a/test/langtools/jdk/javadoc/tool/VerifyLocale.java +++ b/test/langtools/jdk/javadoc/tool/VerifyLocale.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 8035473 8149565 + * @bug 8035473 8149565 8273745 * @summary Verify that init method works correctly. * @modules jdk.javadoc/jdk.javadoc.internal.tool */ @@ -31,6 +31,7 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.Collections; +import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Set; @@ -47,6 +48,8 @@ import jdk.javadoc.doclet.Reporter; import jdk.javadoc.doclet.DocletEnvironment; public class VerifyLocale implements Doclet { + // These static values are shared between the main method and the + // Doclet instance indirectly created from the main method. static String language; static String country; static String variant; @@ -64,29 +67,47 @@ public class VerifyLocale implements Doclet { int skipCount = 0; int testCount = 0; - for (Locale loc : Locale.getAvailableLocales()) { + var languages = new HashSet<>(); + var countries = new HashSet<>(); + var variants = new HashSet<>(); + for (Locale loc : Locale.getAvailableLocales()) { language = loc.getLanguage(); country = loc.getCountry(); variant = loc.getVariant(); - System.err.printf("test locale: %s [%s,%s,%s] %s%n", - loc, language, country, variant, loc.toLanguageTag()); - // skip locales for which the round-trip fails + // skip locales for which the round-trip fails (e.g. no_NO_NY : nn_NO) if (!loc.equals(Locale.forLanguageTag(loc.toLanguageTag()))) { - System.err.println("skipped " + loc + "!"); + System.err.println("skipped " + loc + + " (language tag round trip: " + + loc.toLanguageTag() + + ": " + Locale.forLanguageTag(loc.toLanguageTag()) + ")"); + System.err.println(); + skipCount++; + continue; + } + + // to reduce the potentially large number of locales to be tested, skip + // those for which we have already seen any of the language, country or variant. + if (!languages.add(language) + & !countries.add(country) + & !variants.add(variant)) { + System.err.println("skipped " + loc + " (duplicate part)"); System.err.println(); skipCount++; continue; } + System.err.printf("test locale: %s [%s,%s,%s] %s%n", + loc, language, country, variant, loc.toLanguageTag()); + if (!language.equals("")) { List options = List.of("-locale", loc.toLanguageTag()); System.err.println("test options: " + options); DocumentationTask t = tool.getTask(null, null, null, VerifyLocale.class, options, List.of(fo)); if (!t.call()) - throw new Error("Javadoc encountered warnings or errors."); + throw new Error("javadoc encountered warnings or errors."); testCount++; } System.err.println(); -- GitLab From 4e3948f18b9b8dab96239ad24473134b712ada1a Mon Sep 17 00:00:00 2001 From: Jonathan Gibbons Date: Tue, 5 Oct 2021 15:27:02 +0000 Subject: [PATCH 096/385] 8274744: TestSnippetTag test fails after recent integration Reviewed-by: prappo --- test/langtools/ProblemList.txt | 2 - .../doclet/testSnippetTag/TestSnippetTag.java | 66 +++++++++---------- 2 files changed, 33 insertions(+), 35 deletions(-) diff --git a/test/langtools/ProblemList.txt b/test/langtools/ProblemList.txt index a59173917db..60cc7e33b4a 100644 --- a/test/langtools/ProblemList.txt +++ b/test/langtools/ProblemList.txt @@ -27,8 +27,6 @@ # # javadoc -jdk/javadoc/doclet/testSnippetTag/TestSnippetTag.java 8274744 generic-all - ########################################################################### # # jshell diff --git a/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestSnippetTag.java b/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestSnippetTag.java index 1f26855678c..20a9e81e9ab 100644 --- a/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestSnippetTag.java +++ b/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestSnippetTag.java @@ -288,7 +288,7 @@ public class TestSnippetTag extends JavadocTester { """ error: unexpected content {@snippet :} - ^ + ^ """), new Capture.TestCase( """ @@ -297,7 +297,7 @@ public class TestSnippetTag extends JavadocTester { """ error: unexpected content {@snippet : } - ^ + ^ """), new Capture.TestCase( """ @@ -306,7 +306,7 @@ public class TestSnippetTag extends JavadocTester { """ error: unexpected content {@snippet :a} - ^ + ^ """), new Capture.TestCase( """ @@ -315,7 +315,7 @@ public class TestSnippetTag extends JavadocTester { """, """ error: unexpected content - {@snippet + :} ^ """), new Capture.TestCase( @@ -325,7 +325,7 @@ public class TestSnippetTag extends JavadocTester { """, """ error: unexpected content - {@snippet + : } ^ """), new Capture.TestCase( @@ -335,7 +335,7 @@ public class TestSnippetTag extends JavadocTester { """, """ error: unexpected content - {@snippet + :a} ^ """), new Capture.TestCase( @@ -345,8 +345,8 @@ public class TestSnippetTag extends JavadocTester { """, """ error: unexpected content - {@snippet - ^ + :} + ^ """), new Capture.TestCase( """ @@ -355,8 +355,8 @@ public class TestSnippetTag extends JavadocTester { """, """ error: unexpected content - {@snippet - ^ + : } + ^ """), new Capture.TestCase( """ @@ -365,8 +365,8 @@ public class TestSnippetTag extends JavadocTester { """, """ error: unexpected content - {@snippet - ^ + :a} + ^ """), // // @@ -381,7 +381,7 @@ public class TestSnippetTag extends JavadocTester { """ error: no content {@snippet file="} - ^ + ^ """), new Capture.TestCase( """ @@ -390,7 +390,7 @@ public class TestSnippetTag extends JavadocTester { """, """ error: no content - {@snippet file=" + } ^ """), new Capture.TestCase( @@ -400,7 +400,7 @@ public class TestSnippetTag extends JavadocTester { """ error: no content {@snippet file='} - ^ + ^ """), new Capture.TestCase( """ @@ -409,7 +409,7 @@ public class TestSnippetTag extends JavadocTester { """, """ error: no content - {@snippet file=' + } ^ """), new Capture.TestCase( @@ -419,8 +419,8 @@ public class TestSnippetTag extends JavadocTester { """, """ error: no content - {@snippet file=' - ^ + } + ^ """), new Capture.TestCase( """ @@ -430,8 +430,8 @@ public class TestSnippetTag extends JavadocTester { """, """ error: no content - {@snippet - ^ + } + ^ """), new Capture.TestCase( """ @@ -440,8 +440,8 @@ public class TestSnippetTag extends JavadocTester { """, """ error: no content - {@snippet - ^ + file='} + ^ """), // // @@ -484,7 +484,7 @@ public class TestSnippetTag extends JavadocTester { """ error: unexpected content {@snippet file=:} - ^ + ^ """), new Capture.TestCase( """ @@ -493,7 +493,7 @@ public class TestSnippetTag extends JavadocTester { """ error: no content {@snippet - ^ + ^ """), new Capture.TestCase( """ @@ -502,7 +502,7 @@ public class TestSnippetTag extends JavadocTester { """ error: no content {@snippet file - ^ + ^ """), new Capture.TestCase( """ @@ -511,7 +511,7 @@ public class TestSnippetTag extends JavadocTester { """ error: no content {@snippet file= - ^ + ^ """), new Capture.TestCase( """ @@ -520,7 +520,7 @@ public class TestSnippetTag extends JavadocTester { """ error: no content {@snippet file=" - ^ + ^ """), new Capture.TestCase( """ @@ -529,7 +529,7 @@ public class TestSnippetTag extends JavadocTester { """ error: no content {@snippet file=' - ^ + ^ """), new Capture.TestCase( """ @@ -537,7 +537,7 @@ public class TestSnippetTag extends JavadocTester { """ error: no content {@snippet :*/ - ^ + ^ """), new Capture.TestCase( """ @@ -545,8 +545,8 @@ public class TestSnippetTag extends JavadocTester { Hello, World!""", """ error: unterminated inline tag - {@snippet : - ^ + Hello, World!*/ + ^ """), new Capture.TestCase( """ @@ -555,7 +555,7 @@ public class TestSnippetTag extends JavadocTester { """ error: no content {@snippet file="gibberish" :*/ - ^ + ^ """), new Capture.TestCase( """ @@ -564,7 +564,7 @@ public class TestSnippetTag extends JavadocTester { """ error: unterminated inline tag {@snippet file="gibberish" : - ^ + ^ """) // )); -- GitLab From e1f0df0de3b205cecdb1aa1d74562536c06097dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Walln=C3=B6fer?= Date: Tue, 5 Oct 2021 16:57:12 +0000 Subject: [PATCH 097/385] 8267853: Remove unused styles from stylesheet Reviewed-by: prappo --- .../doclets/toolkit/resources/stylesheet.css | 35 +++---------------- .../CheckStylesheetClasses.java | 13 ++----- .../doclet/testStylesheet/TestStylesheet.java | 5 +-- 3 files changed, 7 insertions(+), 46 deletions(-) diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/stylesheet.css b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/stylesheet.css index a3aaf56fcd0..85058fc5457 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/stylesheet.css +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/stylesheet.css @@ -102,11 +102,6 @@ button { /* * Styles for document title and copyright. */ -.clear { - clear:both; - height:0; - overflow:hidden; -} .about-language { float:right; padding:0 21px 8px 8px; @@ -117,13 +112,6 @@ button { .legal-copy { margin-left:.5em; } -.tab { - background-color:#0066FF; - color:#ffffff; - padding:8px; - width:5em; - font-weight:bold; -} /* * Styles for navigation bar. */ @@ -233,7 +221,7 @@ ul.sub-nav-list li { } } /* - * Styles for page header and footer. + * Styles for page header. */ .title { color:#2c4557; @@ -246,7 +234,7 @@ ul.sub-nav-list li { margin:0 0 15px 0; padding:0; } -.header ul li, .footer ul li { +.header ul li { list-style:none; font-size:13px; } @@ -476,15 +464,9 @@ div.table-tabs > button.table-tab { .col-first a:link, .col-first a:visited, .col-second a:link, .col-second a:visited, .col-constructor-name a:link, .col-constructor-name a:visited, -.col-summary-item-name a:link, .col-summary-item-name a:visited, -.constant-values-container a:link, .constant-values-container a:visited, -.all-classes-container a:link, .all-classes-container a:visited, -.all-packages-container a:link, .all-packages-container a:visited { +.col-summary-item-name a:link, .col-summary-item-name a:visited { font-weight:bold; } -.table-sub-heading-color { - background-color:#EEEEFF; -} .even-row-color, .even-row-color .table-header { background-color:#FFFFFF; } @@ -494,10 +476,6 @@ div.table-tabs > button.table-tab { /* * Styles for contents. */ -.deprecated-content { - margin:0; - padding:10px 0; -} div.block { font-size:14px; font-family:'DejaVu Serif', Georgia, "Times New Roman", Times, serif; @@ -539,18 +517,13 @@ div.block { color:green; padding:0 30px 0 0; } -h1.hidden { - visibility:hidden; - overflow:hidden; - font-size:10px; -} .block { display:block; margin:0 10px 5px 0; color:#474747; } .deprecated-label, .description-from-type-label, .implementation-label, .member-name-label, .member-name-link, -.module-label-in-package, .module-label-in-type, .override-specify-label, .package-label-in-type, +.module-label-in-package, .module-label-in-type, .package-label-in-type, .package-hierarchy-label, .type-name-label, .type-name-link, .search-tag-link, .preview-label { font-weight:bold; } diff --git a/test/langtools/jdk/javadoc/doclet/checkStylesheetClasses/CheckStylesheetClasses.java b/test/langtools/jdk/javadoc/doclet/checkStylesheetClasses/CheckStylesheetClasses.java index 1c458e54c83..53f65392ab5 100644 --- a/test/langtools/jdk/javadoc/doclet/checkStylesheetClasses/CheckStylesheetClasses.java +++ b/test/langtools/jdk/javadoc/doclet/checkStylesheetClasses/CheckStylesheetClasses.java @@ -112,7 +112,7 @@ public class CheckStylesheetClasses { // summary and details tables; styles for these may be present in the stylesheet // using constructs like these: // .summary section[class$="-summary"], .details section[class$="-details"], - htmlStyleNames.removeIf(s -> s.endsWith("-details")); + htmlStyleNames.removeIf(s -> s.endsWith("-details") && !styleSheetNames.contains(s)); htmlStyleNames.removeIf(s -> s.endsWith("-summary") && !styleSheetNames.contains(s)); // signature classes @@ -138,7 +138,7 @@ public class CheckStylesheetClasses { removeAll(styleSheetNames, "result-highlight", "result-item", "search-tag-desc-result", "search-tag-holder-result", "ui-autocomplete", "ui-autocomplete-category", - "watermark"); + "watermark", "expanded"); // snippet-related removeAll(styleSheetNames, "bold", "highlighted", "italic"); @@ -146,15 +146,6 @@ public class CheckStylesheetClasses { // very JDK specific styleSheetNames.remove("module-graph"); - // apparently unused - // "tab" is commented implying it is in the header/footer, but - // (a) it is a poorly chosen name - // (b) it does not seem to be used in make/Docs.gmk or anywhere else - removeAll(styleSheetNames, "all-classes-container", "all-packages-container", - "clear", "constant-values-container", "deprecated-content", "expanded", - "footer", "hidden", "override-specify-label", "serialized-class-details", - "tab", "table-sub-heading-color"); - boolean ok = check(htmlStyleNames, "HtmlStyle", styleSheetNames, "stylesheet") & check(styleSheetNames, "stylesheet", htmlStyleNames, "HtmlStyle"); diff --git a/test/langtools/jdk/javadoc/doclet/testStylesheet/TestStylesheet.java b/test/langtools/jdk/javadoc/doclet/testStylesheet/TestStylesheet.java index 95d5fd0267c..2af09148f0b 100644 --- a/test/langtools/jdk/javadoc/doclet/testStylesheet/TestStylesheet.java +++ b/test/langtools/jdk/javadoc/doclet/testStylesheet/TestStylesheet.java @@ -160,10 +160,7 @@ public class TestStylesheet extends JavadocTester { .col-first a:link, .col-first a:visited, .col-second a:link, .col-second a:visited, .col-constructor-name a:link, .col-constructor-name a:visited, - .col-summary-item-name a:link, .col-summary-item-name a:visited, - .constant-values-container a:link, .constant-values-container a:visited, - .all-classes-container a:link, .all-classes-container a:visited, - .all-packages-container a:link, .all-packages-container a:visited { + .col-summary-item-name a:link, .col-summary-item-name a:visited { font-weight:bold; }""", """ -- GitLab From 37890650a7c97d484b6b520d909f677dac4e46e1 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Tue, 5 Oct 2021 17:30:31 +0000 Subject: [PATCH 098/385] 8274397: [macOS] Stop setting env. var JAVA_MAIN_CLASS_ in launcher code Reviewed-by: rriggs, serb --- .../macosx/native/libjli/java_md_macosx.m | 88 +++++++++++++------ .../native/libosxapp/NSApplicationAWT.m | 17 +--- .../launcher/MacOSAppNamePropertyTest.java | 70 +++++++++++++++ .../tools/launcher/SystemPropertyTest.java | 44 ++++++++++ test/jdk/tools/launcher/TestSpecialArgs.java | 6 +- 5 files changed, 179 insertions(+), 46 deletions(-) create mode 100644 test/jdk/tools/launcher/MacOSAppNamePropertyTest.java create mode 100644 test/jdk/tools/launcher/SystemPropertyTest.java diff --git a/src/java.base/macosx/native/libjli/java_md_macosx.m b/src/java.base/macosx/native/libjli/java_md_macosx.m index b83ebf91f13..9e00c0f07c0 100644 --- a/src/java.base/macosx/native/libjli/java_md_macosx.m +++ b/src/java.base/macosx/native/libjli/java_md_macosx.m @@ -793,7 +793,7 @@ SetXDockArgForAWT(const char *arg) * change drastically between update release, and it may even be * removed or replaced with another mechanism. * - * NOTE: It is used by SWT, and JavaFX. + * NOTE: It is used by SWT */ snprintf(envVar, sizeof(envVar), "APP_NAME_%d", getpid()); setenv(envVar, (arg + 12), 1); @@ -828,40 +828,78 @@ SetMainClassForAWT(JNIEnv *env, jclass mainClass) { jmethodID getCanonicalNameMID = NULL; NULL_CHECK(getCanonicalNameMID = (*env)->GetMethodID(env, classClass, "getCanonicalName", "()Ljava/lang/String;")); + jclass strClass = NULL; + NULL_CHECK(strClass = (*env)->FindClass(env, "java/lang/String")); + + jmethodID lastIndexMID = NULL; + NULL_CHECK(lastIndexMID = (*env)->GetMethodID(env, strClass, "lastIndexOf", "(I)I")); + + jmethodID subStringMID = NULL; + NULL_CHECK(subStringMID = (*env)->GetMethodID(env, strClass, "substring", "(I)Ljava/lang/String;")); + jstring mainClassString = (*env)->CallObjectMethod(env, mainClass, getCanonicalNameMID); if ((*env)->ExceptionCheck(env) || NULL == mainClassString) { - /* - * Clears all errors caused by getCanonicalName() on the mainclass and - * leaves the JAVA_MAIN_CLASS__ empty. - */ (*env)->ExceptionClear(env); return; } - const char *mainClassName = NULL; - NULL_CHECK(mainClassName = (*env)->GetStringUTFChars(env, mainClassString, NULL)); + jint lastPeriod = (*env)->CallIntMethod(env, mainClassString, lastIndexMID, (jint)'.'); + if ((*env)->ExceptionCheck(env)) { + (*env)->ExceptionClear(env); + return; + } - char envVar[80]; - /* - * The JAVA_MAIN_CLASS_ environment variable is used to pass - * the name of a Java class whose main() method is invoked by - * the Java launcher code to start the application, to the AWT code - * in order to assign the name to the Apple menu bar when the app - * is active on the Mac. - * The _ part is added to avoid collisions with child processes. - * - * WARNING: This environment variable is an implementation detail and - * isn't meant for use outside of the core platform. The mechanism for - * passing this information from Java launcher to other modules may - * change drastically between update release, and it may even be - * removed or replaced with another mechanism. + if (lastPeriod != -1) { + mainClassString = (*env)->CallObjectMethod(env, mainClassString, subStringMID, lastPeriod+1); + if ((*env)->ExceptionCheck(env)) { + (*env)->ExceptionClear(env); + return; + } + } + + /* There are multiple apple.awt.*" system properties that AWT(the desktop module) + * references that are inherited from Apple JDK. + * This inherited AWT code looks for this property and uses it for the name + * of the app as it appears in the system menu bar. * - * NOTE: It is used by SWT, and JavaFX. + * No idea if how much external code ever sets it, but use it if set, else + * if not set (the high probability event) set it to the application class name. */ - snprintf(envVar, sizeof(envVar), "JAVA_MAIN_CLASS_%d", getpid()); - setenv(envVar, mainClassName, 1); + const char* propName = "apple.awt.application.name"; + jstring jKey = NULL; + NULL_CHECK(jKey = (*env)->NewStringUTF(env, propName)); + + jclass sysClass = NULL; + NULL_CHECK(sysClass = (*env)->FindClass(env, "java/lang/System")); + + jmethodID getPropertyMID = NULL; + NULL_CHECK(getPropertyMID = (*env)->GetStaticMethodID(env, sysClass, + "getProperty", "(Ljava/lang/String;)Ljava/lang/String;")); + + jmethodID setPropertyMID = NULL; + NULL_CHECK(setPropertyMID = (*env)->GetStaticMethodID(env, sysClass, + "setProperty", + "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;")); + + jstring jValue = (*env)->CallStaticObjectMethod(env, sysClass, getPropertyMID, jKey); + if ((*env)->ExceptionCheck(env)) { + (*env)->ExceptionClear(env); + (*env)->DeleteLocalRef(env, jKey); + return; + } + if (jValue == NULL) { + (*env)->CallStaticObjectMethod(env, sysClass, setPropertyMID, + jKey, mainClassString); + if ((*env)->ExceptionCheck(env)) { + (*env)->ExceptionClear(env); + (*env)->DeleteLocalRef(env, jKey); + return; + } + } else { + (*env)->DeleteLocalRef(env, jValue); + } - (*env)->ReleaseStringUTFChars(env, mainClassString, mainClassName); + (*env)->DeleteLocalRef(env, jKey); } void diff --git a/src/java.desktop/macosx/native/libosxapp/NSApplicationAWT.m b/src/java.desktop/macosx/native/libosxapp/NSApplicationAWT.m index 700f435d482..f7a65db5a69 100644 --- a/src/java.desktop/macosx/native/libosxapp/NSApplicationAWT.m +++ b/src/java.desktop/macosx/native/libosxapp/NSApplicationAWT.m @@ -180,26 +180,11 @@ AWT_ASSERT_APPKIT_THREAD; } // If it wasn't specified as an argument, see if it was specified as a system property. + // The launcher code sets this if it is not already set on the command line. if (fApplicationName == nil) { fApplicationName = [PropertiesUtilities javaSystemPropertyForKey:@"apple.awt.application.name" withEnv:env]; } - // If we STILL don't have it, the app name is retrieved from an environment variable (set in java.c) It should be UTF8. - if (fApplicationName == nil) { - char mainClassEnvVar[80]; - snprintf(mainClassEnvVar, sizeof(mainClassEnvVar), "JAVA_MAIN_CLASS_%d", getpid()); - char *mainClass = getenv(mainClassEnvVar); - if (mainClass != NULL) { - fApplicationName = [NSString stringWithUTF8String:mainClass]; - unsetenv(mainClassEnvVar); - - NSRange lastPeriod = [fApplicationName rangeOfString:@"." options:NSBackwardsSearch]; - if (lastPeriod.location != NSNotFound) { - fApplicationName = [fApplicationName substringFromIndex:lastPeriod.location + 1]; - } - } - } - // The dock name is nil for double-clickable Java apps (bundled and Web Start apps) // When that happens get the display name, and if that's not available fall back to // CFBundleName. diff --git a/test/jdk/tools/launcher/MacOSAppNamePropertyTest.java b/test/jdk/tools/launcher/MacOSAppNamePropertyTest.java new file mode 100644 index 00000000000..1f12544f242 --- /dev/null +++ b/test/jdk/tools/launcher/MacOSAppNamePropertyTest.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 8274397 + * @summary Ensure the app name system property is set on macOS + * @requires os.family == "mac" + * @compile MacOSAppNamePropertyTest.java SystemPropertyTest.java + * @run main MacOSAppNamePropertyTest + */ + +import java.util.ArrayList; +import java.util.List; +/* + * If the system property apple.awt.application.name is unset, it should default + * to the name of this test class. + * If it is set, then it should be used instead of the class. + * The arg. to the test indicates the *expected* name. + * The test will fail if the property is not set or does not match + */ +public class MacOSAppNamePropertyTest extends TestHelper { + + static final String APPNAME = "SystemPropertyTest"; + + public static void main(String[]args) { + if (!isMacOSX) { + return; + } + execTest(null, APPNAME); + execTest("-Dapple.awt.application.name=Foo", "Foo"); + } + + static void execTest(String propSetting, String expect) { + List cmdList = new ArrayList<>(); + cmdList.add(javaCmd); + cmdList.add("-cp"); + cmdList.add(TEST_CLASSES_DIR.getAbsolutePath()); + if (propSetting != null) { + cmdList.add(propSetting); + } + cmdList.add(APPNAME); + cmdList.add(expect); + TestResult tr = doExec(cmdList.toArray(new String[cmdList.size()])); + if (!tr.isOK()) { + System.err.println(tr.toString()); + throw new RuntimeException("Test Fails"); + } + } +} diff --git a/test/jdk/tools/launcher/SystemPropertyTest.java b/test/jdk/tools/launcher/SystemPropertyTest.java new file mode 100644 index 00000000000..9ec89efb0a2 --- /dev/null +++ b/test/jdk/tools/launcher/SystemPropertyTest.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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. + */ + + +/* + * Child launched by MacOSAppNamePropertyTest.java + * If the system property apple.awt.application.name is unset, it should default + * to the name of this main program class, less any package name. + * If it is set, then it should be used instead of the class name. + * The arg. to the test indicates the *expected* name. + * The test will fail if the property is not set or does not match + */ +public class SystemPropertyTest { + + public static void main(String[]args) { + String prop = System.getProperty("apple.awt.application.name"); + if (prop == null) { + throw new RuntimeException("Property not set"); + } + if (!prop.equals(args[0])) { + throw new RuntimeException("Got " + prop + " expected " + args[0]); + } + } +} diff --git a/test/jdk/tools/launcher/TestSpecialArgs.java b/test/jdk/tools/launcher/TestSpecialArgs.java index c58fd6dcaf8..922a52edf73 100644 --- a/test/jdk/tools/launcher/TestSpecialArgs.java +++ b/test/jdk/tools/launcher/TestSpecialArgs.java @@ -83,15 +83,11 @@ public class TestSpecialArgs extends TestHelper { Set envToRemove = new HashSet<>(); Map map = System.getenv(); for (String s : map.keySet()) { - if (s.startsWith("JAVA_MAIN_CLASS_") - || s.startsWith("APP_NAME_") + if (s.startsWith("APP_NAME_") || s.startsWith("APP_ICON_")) { envToRemove.add(s); } } - runTest(envToRemove, javaCmd, "-cp", TEST_CLASSES_DIR.getAbsolutePath(), - "EnvironmentVariables", "JAVA_MAIN_CLASS_*", - "EnvironmentVariables"); runTest(envToRemove, javaCmd, "-cp", TEST_CLASSES_DIR.getAbsolutePath(), "-Xdock:name=TestAppName", "EnvironmentVariables", -- GitLab From c391e59ea6fe6759553425e342b2d97824dd9323 Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Tue, 5 Oct 2021 17:31:57 +0000 Subject: [PATCH 099/385] 8274244: ReportOnImportedModuleAnnotation.java fails on rerun Reviewed-by: jjg --- .../ReportOnImportedModuleAnnotation.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/test/langtools/tools/javac/processing/ReportOnImportedModuleAnnotation/ReportOnImportedModuleAnnotation.java b/test/langtools/tools/javac/processing/ReportOnImportedModuleAnnotation/ReportOnImportedModuleAnnotation.java index 777a14cd219..cfaca246a87 100644 --- a/test/langtools/tools/javac/processing/ReportOnImportedModuleAnnotation/ReportOnImportedModuleAnnotation.java +++ b/test/langtools/tools/javac/processing/ReportOnImportedModuleAnnotation/ReportOnImportedModuleAnnotation.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,7 +27,10 @@ * 8235458 * @summary javac shouldn't fail when an annotation processor report a message about an annotation on a module * javac should process annotated module when imports statement are present + * @library /tools/lib * @modules jdk.compiler + * @build toolbox.ToolBox + * @run main ReportOnImportedModuleAnnotation */ import java.io.PrintWriter; @@ -41,6 +44,8 @@ import javax.tools.StandardJavaFileManager; import javax.tools.StandardLocation; import javax.tools.ToolProvider; +import toolbox.ToolBox; + public class ReportOnImportedModuleAnnotation { public static void main(String[] args) throws Exception { @@ -49,6 +54,9 @@ public class ReportOnImportedModuleAnnotation { final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); + // Clean any existing files in output directory + (new ToolBox()).cleanDirectory(testOutputPath); + // Compile annotation and processor modules StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null); fileManager.setLocationFromPaths(StandardLocation.MODULE_SOURCE_PATH, List.of(testBasePath.resolve("mods-src1/"))); -- GitLab From 03d3c0338437bf10b631881c8910ca85985742f6 Mon Sep 17 00:00:00 2001 From: Weijun Wang Date: Tue, 5 Oct 2021 18:18:51 +0000 Subject: [PATCH 100/385] 8273670: Remove weak etypes from default krb5 etype list Reviewed-by: valeriep, mullan --- .../security/krb5/internal/crypto/EType.java | 86 +++++++-------- .../jdk/sun/security/krb5/auto/DupEtypes.java | 5 +- test/jdk/sun/security/krb5/auto/OneKDC.java | 9 +- test/jdk/sun/security/krb5/auto/W83.java | 3 +- test/jdk/sun/security/krb5/config/YesNo.java | 6 +- test/jdk/sun/security/krb5/config/yesno.conf | 1 + .../sun/security/krb5/etype/WeakCrypto.java | 102 +++++++++++------- 7 files changed, 112 insertions(+), 100 deletions(-) diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/EType.java b/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/EType.java index 148a4a5edd5..1f8b6d993e8 100644 --- a/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/EType.java +++ b/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/EType.java @@ -48,17 +48,39 @@ import java.util.ArrayList; public abstract class EType { private static final boolean DEBUG = Krb5.DEBUG; - private static boolean allowWeakCrypto; + + // etypes supported by JDK, including weak ones + private static int[] supportedETypes; + // common default etypes if not defined in krb5.conf + private static int[] defaultETypes; static { initStatic(); } public static void initStatic() { - boolean allowed = false; + + int maxKeyLength = 0; + try { + maxKeyLength = Cipher.getMaxAllowedKeyLength("AES"); + } catch (Exception e) { + // should not happen + } + + defaultETypes = maxKeyLength >= 256 + ? new int[] { + EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96, + EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96, + EncryptedData.ETYPE_AES256_CTS_HMAC_SHA384_192, + EncryptedData.ETYPE_AES128_CTS_HMAC_SHA256_128, } + : new int[] { + EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96, + EncryptedData.ETYPE_AES128_CTS_HMAC_SHA256_128, }; + + boolean allowWeakCrypto = false; try { Config cfg = Config.getInstance(); - allowed = cfg.getBooleanObject("libdefaults", "allow_weak_crypto") + allowWeakCrypto = cfg.getBooleanObject("libdefaults", "allow_weak_crypto") == Boolean.TRUE; } catch (Exception exc) { if (DEBUG) { @@ -67,7 +89,17 @@ public abstract class EType { exc.getMessage()); } } - allowWeakCrypto = allowed; + + if (allowWeakCrypto) { + int[] result = Arrays.copyOf(defaultETypes, defaultETypes.length + 4); + result[defaultETypes.length] = EncryptedData.ETYPE_DES3_CBC_HMAC_SHA1_KD; + result[defaultETypes.length + 1] = EncryptedData.ETYPE_ARCFOUR_HMAC; + result[defaultETypes.length + 2] = EncryptedData.ETYPE_DES_CBC_CRC; + result[defaultETypes.length + 3] = EncryptedData.ETYPE_DES_CBC_MD5; + supportedETypes = result; + } else { + supportedETypes = defaultETypes; + } } public static EType getInstance (int eTypeConst) @@ -196,50 +228,9 @@ public abstract class EType { return result; } - // Note: the first 2 entries of BUILTIN_ETYPES and BUILTIN_ETYPES_NOAES256 - // should be kept DES-related. They will be removed when allow_weak_crypto - // is set to false. - - private static final int[] BUILTIN_ETYPES = new int[] { - EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96, - EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96, - EncryptedData.ETYPE_AES256_CTS_HMAC_SHA384_192, - EncryptedData.ETYPE_AES128_CTS_HMAC_SHA256_128, - EncryptedData.ETYPE_DES3_CBC_HMAC_SHA1_KD, - EncryptedData.ETYPE_ARCFOUR_HMAC, - EncryptedData.ETYPE_DES_CBC_CRC, - EncryptedData.ETYPE_DES_CBC_MD5, - }; - - private static final int[] BUILTIN_ETYPES_NOAES256 = new int[] { - EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96, - EncryptedData.ETYPE_AES128_CTS_HMAC_SHA256_128, - EncryptedData.ETYPE_DES3_CBC_HMAC_SHA1_KD, - EncryptedData.ETYPE_ARCFOUR_HMAC, - EncryptedData.ETYPE_DES_CBC_CRC, - EncryptedData.ETYPE_DES_CBC_MD5, - }; - - // used in Config public static int[] getBuiltInDefaults() { - int allowed = 0; - try { - allowed = Cipher.getMaxAllowedKeyLength("AES"); - } catch (Exception e) { - // should not happen - } - int[] result; - if (allowed < 256) { - result = BUILTIN_ETYPES_NOAES256; - } else { - result = BUILTIN_ETYPES; - } - if (!allowWeakCrypto) { - // The last 4 etypes are now weak ones - return Arrays.copyOfRange(result, 0, result.length - 4); - } - return result; + return defaultETypes.clone(); } /** @@ -312,8 +303,7 @@ public abstract class EType { } public static boolean isSupported(int eTypeConst) { - int[] enabledETypes = getBuiltInDefaults(); - return isSupported(eTypeConst, enabledETypes); + return isSupported(eTypeConst, supportedETypes); } /** diff --git a/test/jdk/sun/security/krb5/auto/DupEtypes.java b/test/jdk/sun/security/krb5/auto/DupEtypes.java index 0974e1374f1..81801dbe2a6 100644 --- a/test/jdk/sun/security/krb5/auto/DupEtypes.java +++ b/test/jdk/sun/security/krb5/auto/DupEtypes.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,7 +47,8 @@ public class DupEtypes { KDC.saveConfig(OneKDC.KRB5_CONF, kdc, "default_keytab_name = " + OneKDC.KTAB, - "allow_weak_crypto = true"); + "allow_weak_crypto = true", + "permitted_enctypes = aes256-cts arcfour-hmac des-cbc-crc des-cbc-md5"); Config.refresh(); // Rewrite to include DES keys diff --git a/test/jdk/sun/security/krb5/auto/OneKDC.java b/test/jdk/sun/security/krb5/auto/OneKDC.java index 6d7362ff4c5..d73d323af91 100644 --- a/test/jdk/sun/security/krb5/auto/OneKDC.java +++ b/test/jdk/sun/security/krb5/auto/OneKDC.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2021, Oracle and/or its affiliates. All rights reserved. * 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,11 +72,8 @@ public class OneKDC extends KDC { String extraConfig = ""; if (etype != null) { - extraConfig += "default_tkt_enctypes=" + etype - + "\ndefault_tgs_enctypes=" + etype; - if (etype.startsWith("des")) { - extraConfig += "\nallow_weak_crypto = true"; - } + extraConfig += "permitted_enctypes=" + etype + + "\nallow_weak_crypto = true"; } KDC.saveConfig(KRB5_CONF, this, "forwardable = true", diff --git a/test/jdk/sun/security/krb5/auto/W83.java b/test/jdk/sun/security/krb5/auto/W83.java index 0f534fc8810..9093f5b7ce9 100644 --- a/test/jdk/sun/security/krb5/auto/W83.java +++ b/test/jdk/sun/security/krb5/auto/W83.java @@ -50,7 +50,8 @@ public class W83 { kdc.addPrincipal(OneKDC.USER, OneKDC.PASS); kdc.addPrincipalRandKey("krbtgt/" + OneKDC.REALM); KDC.saveConfig(OneKDC.KRB5_CONF, kdc, - "allow_weak_crypto = true"); + "allow_weak_crypto = true", + "permitted_enctypes = aes256-cts arcfour-hmac"); System.setProperty("java.security.krb5.conf", OneKDC.KRB5_CONF); Config.refresh(); diff --git a/test/jdk/sun/security/krb5/config/YesNo.java b/test/jdk/sun/security/krb5/config/YesNo.java index 22e5144d7c9..b11090855f1 100644 --- a/test/jdk/sun/security/krb5/config/YesNo.java +++ b/test/jdk/sun/security/krb5/config/YesNo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,8 +48,8 @@ public class YesNo { check("e", null); check("f", null); - if (!Arrays.stream(EType.getBuiltInDefaults()) - .anyMatch(n -> n < 4)) { + if (!Arrays.stream(EType.getDefaults("default_tkt_enctypes")) + .anyMatch(n -> n == 23)) { throw new Exception(); } } diff --git a/test/jdk/sun/security/krb5/config/yesno.conf b/test/jdk/sun/security/krb5/config/yesno.conf index 681c19daf51..441f13beae3 100644 --- a/test/jdk/sun/security/krb5/config/yesno.conf +++ b/test/jdk/sun/security/krb5/config/yesno.conf @@ -4,4 +4,5 @@ b = FALSE c = YES d = no e = nothing +default_tkt_enctypes = rc4-hmac allow_weak_crypto = yes diff --git a/test/jdk/sun/security/krb5/etype/WeakCrypto.java b/test/jdk/sun/security/krb5/etype/WeakCrypto.java index 8d43174b475..669d2e7ea87 100644 --- a/test/jdk/sun/security/krb5/etype/WeakCrypto.java +++ b/test/jdk/sun/security/krb5/etype/WeakCrypto.java @@ -22,61 +22,83 @@ */ /* * @test - * @bug 6844909 8012679 8139348 + * @bug 6844909 8012679 8139348 8273670 * @modules java.security.jgss/sun.security.krb5 * java.security.jgss/sun.security.krb5.internal.crypto + * @library /test/lib * @run main/othervm WeakCrypto - * @run main/othervm WeakCrypto true - * @run main/othervm WeakCrypto false - * @summary support allow_weak_crypto in krb5.conf */ -import java.lang.Exception; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.Arrays; -import java.util.List; - +import jdk.test.lib.Asserts; +import sun.security.krb5.Config; import sun.security.krb5.EncryptionKey; import sun.security.krb5.internal.crypto.EType; -import sun.security.krb5.EncryptedData; + +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; public class WeakCrypto { + public static void main(String[] args) throws Exception { - static List weakOnes = List.of( - EncryptedData.ETYPE_DES_CBC_CRC, - EncryptedData.ETYPE_DES_CBC_MD5, - EncryptedData.ETYPE_DES3_CBC_HMAC_SHA1_KD, - EncryptedData.ETYPE_ARCFOUR_HMAC - ); + System.setProperty("java.security.krb5.conf", "tmp.conf"); - public static void main(String[] args) throws Exception { + test(null, null, + 18, 17, 20, 19); // the defaults + test(false, null, + 18, 17, 20, 19); // the defaults + test(true, null, + 18, 17, 20, 19); // the defaults - String conf = "[libdefaults]\n" + - (args.length > 0 ? ("allow_weak_crypto = " + args[0]) : ""); - Files.write(Paths.get("krb5.conf"), conf.getBytes()); - System.setProperty("java.security.krb5.conf", "krb5.conf"); + String strongAndWeak = "aes256-cts aes128-cts aes256-sha2 aes128-sha2" + + " des3-hmac-sha1 arcfour-hmac des-cbc-crc des-cbc-md5"; + test(null, strongAndWeak, 18, 17, 20, 19); + test(false, strongAndWeak, 18, 17, 20, 19); + test(true, strongAndWeak, 18, 17, 20, 19, 16, 23, 1, 3); - // expected number of supported weak etypes - int expected = 0; - if (args.length != 0 && args[0].equals("true")) { - expected = weakOnes.size(); - } + String anotherOrder = "aes256-cts aes256-sha2 aes128-cts aes128-sha2" + + " des3-hmac-sha1 arcfour-hmac des-cbc-crc des-cbc-md5"; + test(null, anotherOrder, 18, 20, 17, 19); + test(false, anotherOrder, 18, 20, 17, 19); + test(true, anotherOrder, 18, 20, 17, 19, 16, 23, 1, 3); - // Ensure EType.getBuiltInDefaults() has the correct etypes - if (Arrays.stream(EType.getBuiltInDefaults()) - .filter(weakOnes::contains) - .count() != expected) { - throw new Exception("getBuiltInDefaults fails"); - } + String two = "aes256-cts arcfour-hmac"; + test(null, two, 18); + test(false, two, 18); + test(true, two, 18, 23); + } + + /** + * Writes a krb5.conf and makes sure it's correctly parsed. + * + * @param allowWeak if "allow_weak_crypto = true" should be written + * @param etypes redefined "default_tkt_enctypes" + * @param expected expected etypes + */ + static void test(Boolean allowWeak, String etypes, int... expected) throws Exception { - // Ensure keys generated have the correct etypes - if (Arrays.stream(EncryptionKey.acquireSecretKeys( - "password".toCharArray(), "salt")) - .map(EncryptionKey::getEType) - .filter(weakOnes::contains) - .count() != expected) { - throw new Exception("acquireSecretKeys fails"); + String s = "[libdefaults]\n"; + if (allowWeak != null) { + s += "allow_weak_crypto = " + allowWeak + "\n"; } + if (etypes != null) { + s += "default_tkt_enctypes = " + etypes; + } + Files.write(Path.of("tmp.conf"), s.getBytes(StandardCharsets.UTF_8)); + Config.refresh(); + + // Check internal config read + int[] config = EType.getDefaults("default_tkt_enctypes"); + Asserts.assertTrue(Arrays.equals(config, expected), + "config: " + Arrays.toString(config)); + + // Check actual etypes used + int[] generated = Arrays.stream(EncryptionKey.acquireSecretKeys( + "password".toCharArray(), "salt")) + .mapToInt(EncryptionKey::getEType) + .toArray(); + Asserts.assertTrue(Arrays.equals(generated, expected), + "generated: " + Arrays.toString(generated)); } } -- GitLab From 1e75203356666a3213deddd775ad1e883ea6d78d Mon Sep 17 00:00:00 2001 From: Weijun Wang Date: Tue, 5 Oct 2021 18:19:45 +0000 Subject: [PATCH 101/385] 8274656: Remove default_checksum and safe_checksum_type from krb5.conf Reviewed-by: valeriep --- .../classes/sun/security/krb5/Checksum.java | 66 +------ .../classes/sun/security/krb5/Config.java | 1 - .../sun/security/krb5/EncryptedData.java | 4 +- .../sun/security/krb5/KrbAppMessage.java | 115 ----------- .../classes/sun/security/krb5/KrbPriv.java | 178 ----------------- .../classes/sun/security/krb5/KrbSafe.java | 183 ------------------ .../classes/sun/security/krb5/KrbTgsReq.java | 6 +- .../security/krb5/internal/AuthContext.java | 52 ----- .../krb5/internal/EncKrbPrivPart.java | 173 ----------------- .../sun/security/krb5/internal/KRBPriv.java | 143 -------------- .../sun/security/krb5/internal/KRBSafe.java | 146 -------------- .../security/krb5/internal/KRBSafeBody.java | 177 ----------------- .../security/krb5/internal/MethodData.java | 111 ----------- 13 files changed, 5 insertions(+), 1350 deletions(-) delete mode 100644 src/java.security.jgss/share/classes/sun/security/krb5/KrbAppMessage.java delete mode 100644 src/java.security.jgss/share/classes/sun/security/krb5/KrbPriv.java delete mode 100644 src/java.security.jgss/share/classes/sun/security/krb5/KrbSafe.java delete mode 100644 src/java.security.jgss/share/classes/sun/security/krb5/internal/AuthContext.java delete mode 100644 src/java.security.jgss/share/classes/sun/security/krb5/internal/EncKrbPrivPart.java delete mode 100644 src/java.security.jgss/share/classes/sun/security/krb5/internal/KRBPriv.java delete mode 100644 src/java.security.jgss/share/classes/sun/security/krb5/internal/KRBSafe.java delete mode 100644 src/java.security.jgss/share/classes/sun/security/krb5/internal/KRBSafeBody.java delete mode 100644 src/java.security.jgss/share/classes/sun/security/krb5/internal/MethodData.java diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/Checksum.java b/src/java.security.jgss/share/classes/sun/security/krb5/Checksum.java index 5535d0524a2..a186eba494e 100644 --- a/src/java.security.jgss/share/classes/sun/security/krb5/Checksum.java +++ b/src/java.security.jgss/share/classes/sun/security/krb5/Checksum.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. * 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,56 +73,7 @@ public class Checksum { // draft-brezak-win2k-krb-rc4-hmac-04.txt public static final int CKSUMTYPE_HMAC_MD5_ARCFOUR = -138; - // default checksum type, -1 if not set - static int CKSUMTYPE_DEFAULT; - static int SAFECKSUMTYPE_DEFAULT; - private static boolean DEBUG = Krb5.DEBUG; - static { - initStatic(); - } - - public static void initStatic() { - String temp = null; - Config cfg = null; - try { - cfg = Config.getInstance(); - temp = cfg.get("libdefaults", "default_checksum"); - if (temp != null) { - CKSUMTYPE_DEFAULT = Config.getType(temp); - } else { - CKSUMTYPE_DEFAULT = -1; - } - } catch (Exception exc) { - if (DEBUG) { - System.out.println("Exception in getting default checksum "+ - "value from the configuration. " + - "No default checksum set."); - exc.printStackTrace(); - } - CKSUMTYPE_DEFAULT = -1; - } - - - try { - temp = cfg.get("libdefaults", "safe_checksum_type"); - if (temp != null) - { - SAFECKSUMTYPE_DEFAULT = Config.getType(temp); - } else { - SAFECKSUMTYPE_DEFAULT = -1; - } - } catch (Exception exc) { - if (DEBUG) { - System.out.println("Exception in getting safe default " + - "checksum value " + - "from the configuration. " + - "No safe default checksum set."); - exc.printStackTrace(); - } - SAFECKSUMTYPE_DEFAULT = -1; - } - } /** * Constructs a new Checksum using the raw data and type. @@ -169,21 +120,6 @@ public class Checksum { data, data.length, key.getBytes(), usage); } - /** - * Verifies the keyed checksum over the data passed in. - */ - public boolean verifyKeyedChecksum(byte[] data, EncryptionKey key, int usage) - throws KdcErrException, KrbApErrException, KrbCryptoException { - CksumType cksumEngine = CksumType.getInstance(cksumType); - if (!cksumEngine.isKeyed()) { - throw new KrbApErrException(Krb5.KRB_AP_ERR_INAPP_CKSUM); - } else { - return cksumEngine.verifyChecksum( - data, data.length, key.getBytes(), checksum, usage); - } - } - - /** * Verifies the checksum over the data passed in. The checksum might * be a keyed or not. diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/Config.java b/src/java.security.jgss/share/classes/sun/security/krb5/Config.java index fadb115245f..9dc2c700ae7 100644 --- a/src/java.security.jgss/share/classes/sun/security/krb5/Config.java +++ b/src/java.security.jgss/share/classes/sun/security/krb5/Config.java @@ -153,7 +153,6 @@ public class Config { } KdcComm.initStatic(); EType.initStatic(); - Checksum.initStatic(); KrbAsReqBuilder.ReferralsState.initStatic(); } diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/EncryptedData.java b/src/java.security.jgss/share/classes/sun/security/krb5/EncryptedData.java index 81b000229e8..c3b6c157a05 100644 --- a/src/java.security.jgss/share/classes/sun/security/krb5/EncryptedData.java +++ b/src/java.security.jgss/share/classes/sun/security/krb5/EncryptedData.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -126,7 +126,7 @@ public class EncryptedData implements Cloneable { } */ - // used in KrbApRep, KrbApReq, KrbAsReq, KrbCred, KrbPriv + // used in KrbApRep, KrbApReq, KrbAsReq public EncryptedData( EncryptionKey key, byte[] plaintext, diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/KrbAppMessage.java b/src/java.security.jgss/share/classes/sun/security/krb5/KrbAppMessage.java deleted file mode 100644 index 47aa1681a1a..00000000000 --- a/src/java.security.jgss/share/classes/sun/security/krb5/KrbAppMessage.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * 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. - */ - -/* - * - * (C) Copyright IBM Corp. 1999 All Rights Reserved. - * Copyright 1997 The Open Group Research Institute. All rights reserved. - */ - -package sun.security.krb5; - -import sun.security.krb5.internal.*; - -abstract class KrbAppMessage { - - private static boolean DEBUG = Krb5.DEBUG; - /** - * Common checks for KRB-PRIV and KRB-SAFE - */ - void check(KerberosTime packetTimestamp, - Integer packetUsec, - Integer packetSeqNumber, - HostAddress packetSAddress, - HostAddress packetRAddress, - SeqNumber seqNumber, - HostAddress sAddress, - HostAddress rAddress, - boolean timestampRequired, - boolean seqNumberRequired, - PrincipalName packetPrincipal) - throws KrbApErrException { - - if (!Krb5.AP_EMPTY_ADDRESSES_ALLOWED || sAddress != null) { - if (packetSAddress == null || sAddress == null || - !packetSAddress.equals(sAddress)) { - if (DEBUG && packetSAddress == null) { - System.out.println("packetSAddress is null"); - } - if (DEBUG && sAddress == null) { - System.out.println("sAddress is null"); - } - throw new KrbApErrException(Krb5.KRB_AP_ERR_BADADDR); - } - } - - if (!Krb5.AP_EMPTY_ADDRESSES_ALLOWED || rAddress != null) { - if (packetRAddress == null || rAddress == null || - !packetRAddress.equals(rAddress)) - throw new KrbApErrException(Krb5.KRB_AP_ERR_BADADDR); - } - - if (packetTimestamp != null) { - if (packetUsec != null) { - packetTimestamp = - packetTimestamp.withMicroSeconds(packetUsec.intValue()); - } - if (!packetTimestamp.inClockSkew()) { - throw new KrbApErrException(Krb5.KRB_AP_ERR_SKEW); - } - } else { - if (timestampRequired) { - throw new KrbApErrException(Krb5.KRB_AP_ERR_SKEW); - } - } - - // XXX check replay cache - // if (rcache.repeated(packetTimestamp, packetUsec, packetSAddress)) - // throw new KrbApErrException(Krb5.KRB_AP_ERR_REPEAT); - - // XXX consider moving up to api level - if (seqNumber == null && seqNumberRequired == true) - throw new KrbApErrException(Krb5.API_INVALID_ARG); - - if (packetSeqNumber != null && seqNumber != null) { - if (packetSeqNumber.intValue() != seqNumber.current()) - throw new KrbApErrException(Krb5.KRB_AP_ERR_BADORDER); - // should be done only when no more exceptions are possible - seqNumber.step(); - } else { - if (seqNumberRequired) { - throw new KrbApErrException(Krb5.KRB_AP_ERR_BADORDER); - } - } - - // Must not be relaxed, per RFC 4120 - if (packetTimestamp == null && packetSeqNumber == null) - throw new KrbApErrException(Krb5.KRB_AP_ERR_MODIFIED); - - // XXX check replay cache - // rcache.save_identifier(packetTimestamp, packetUsec, packetSAddress, - // packetPrincipal, pcaketRealm); - } - -} diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/KrbPriv.java b/src/java.security.jgss/share/classes/sun/security/krb5/KrbPriv.java deleted file mode 100644 index e1984290564..00000000000 --- a/src/java.security.jgss/share/classes/sun/security/krb5/KrbPriv.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * 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. - */ - -/* - * - * (C) Copyright IBM Corp. 1999 All Rights Reserved. - * Copyright 1997 The Open Group Research Institute. All rights reserved. - */ - -package sun.security.krb5; - -import sun.security.krb5.internal.*; -import sun.security.krb5.internal.crypto.*; -import sun.security.util.*; -import java.io.IOException; - -/** XXX This class does not appear to be used. **/ - -class KrbPriv extends KrbAppMessage { - private byte[] obuf; - private byte[] userData; - - private KrbPriv(byte[] userData, - Credentials creds, - EncryptionKey subKey, - KerberosTime timestamp, - SeqNumber seqNumber, - HostAddress saddr, - HostAddress raddr - ) throws KrbException, IOException { - EncryptionKey reqKey = null; - if (subKey != null) - reqKey = subKey; - else - reqKey = creds.key; - - obuf = mk_priv( - userData, - reqKey, - timestamp, - seqNumber, - saddr, - raddr - ); - } - - private KrbPriv(byte[] msg, - Credentials creds, - EncryptionKey subKey, - SeqNumber seqNumber, - HostAddress saddr, - HostAddress raddr, - boolean timestampRequired, - boolean seqNumberRequired - ) throws KrbException, IOException { - - KRBPriv krb_priv = new KRBPriv(msg); - EncryptionKey reqKey = null; - if (subKey != null) - reqKey = subKey; - else - reqKey = creds.key; - userData = rd_priv(krb_priv, - reqKey, - seqNumber, - saddr, - raddr, - timestampRequired, - seqNumberRequired, - creds.client - ); - } - - public byte[] getMessage() throws KrbException { - return obuf; - } - - public byte[] getData() { - return userData; - } - - private byte[] mk_priv(byte[] userData, - EncryptionKey key, - KerberosTime timestamp, - SeqNumber seqNumber, - HostAddress sAddress, - HostAddress rAddress - ) throws Asn1Exception, IOException, - KdcErrException, KrbCryptoException { - - Integer usec = null; - Integer seqno = null; - - if (timestamp != null) - usec = timestamp.getMicroSeconds(); - - if (seqNumber != null) { - seqno = seqNumber.current(); - seqNumber.step(); - } - - EncKrbPrivPart unenc_encKrbPrivPart = - new EncKrbPrivPart(userData, - timestamp, - usec, - seqno, - sAddress, - rAddress - ); - - byte[] temp = unenc_encKrbPrivPart.asn1Encode(); - - EncryptedData encKrbPrivPart = - new EncryptedData(key, temp, - KeyUsage.KU_ENC_KRB_PRIV_PART); - - KRBPriv krb_priv = new KRBPriv(encKrbPrivPart); - - temp = krb_priv.asn1Encode(); - - return krb_priv.asn1Encode(); - } - - private byte[] rd_priv(KRBPriv krb_priv, - EncryptionKey key, - SeqNumber seqNumber, - HostAddress sAddress, - HostAddress rAddress, - boolean timestampRequired, - boolean seqNumberRequired, - PrincipalName cname - ) throws Asn1Exception, KdcErrException, - KrbApErrException, IOException, KrbCryptoException { - - byte[] bytes = krb_priv.encPart.decrypt(key, - KeyUsage.KU_ENC_KRB_PRIV_PART); - byte[] temp = krb_priv.encPart.reset(bytes); - DerValue ref = new DerValue(temp); - EncKrbPrivPart enc_part = new EncKrbPrivPart(ref); - - check(enc_part.timestamp, - enc_part.usec, - enc_part.seqNumber, - enc_part.sAddress, - enc_part.rAddress, - seqNumber, - sAddress, - rAddress, - timestampRequired, - seqNumberRequired, - cname - ); - - return enc_part.userData; - } -} diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/KrbSafe.java b/src/java.security.jgss/share/classes/sun/security/krb5/KrbSafe.java deleted file mode 100644 index 7b7949156e8..00000000000 --- a/src/java.security.jgss/share/classes/sun/security/krb5/KrbSafe.java +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * 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. - */ - -/* - * - * (C) Copyright IBM Corp. 1999 All Rights Reserved. - * Copyright 1997 The Open Group Research Institute. All rights reserved. - */ - -package sun.security.krb5; - -import sun.security.krb5.EncryptionKey; -import sun.security.krb5.internal.*; -import sun.security.krb5.internal.crypto.*; -import java.io.IOException; - -class KrbSafe extends KrbAppMessage { - - private byte[] obuf; - private byte[] userData; - - public KrbSafe(byte[] userData, - Credentials creds, - EncryptionKey subKey, - KerberosTime timestamp, - SeqNumber seqNumber, - HostAddress saddr, - HostAddress raddr - ) throws KrbException, IOException { - EncryptionKey reqKey = null; - if (subKey != null) - reqKey = subKey; - else - reqKey = creds.key; - - obuf = mk_safe(userData, - reqKey, - timestamp, - seqNumber, - saddr, - raddr - ); - } - - public KrbSafe(byte[] msg, - Credentials creds, - EncryptionKey subKey, - SeqNumber seqNumber, - HostAddress saddr, - HostAddress raddr, - boolean timestampRequired, - boolean seqNumberRequired - ) throws KrbException, IOException { - - KRBSafe krb_safe = new KRBSafe(msg); - - EncryptionKey reqKey = null; - if (subKey != null) - reqKey = subKey; - else - reqKey = creds.key; - - userData = rd_safe( - krb_safe, - reqKey, - seqNumber, - saddr, - raddr, - timestampRequired, - seqNumberRequired, - creds.client - ); - } - - public byte[] getMessage() { - return obuf; - } - - public byte[] getData() { - return userData; - } - - private byte[] mk_safe(byte[] userData, - EncryptionKey key, - KerberosTime timestamp, - SeqNumber seqNumber, - HostAddress sAddress, - HostAddress rAddress - ) throws Asn1Exception, IOException, KdcErrException, - KrbApErrException, KrbCryptoException { - - Integer usec = null; - Integer seqno = null; - - if (timestamp != null) - usec = timestamp.getMicroSeconds(); - - if (seqNumber != null) { - seqno = seqNumber.current(); - seqNumber.step(); - } - - KRBSafeBody krb_safeBody = - new KRBSafeBody(userData, - timestamp, - usec, - seqno, - sAddress, - rAddress - ); - - byte[] temp = krb_safeBody.asn1Encode(); - Checksum cksum = new Checksum( - Checksum.SAFECKSUMTYPE_DEFAULT, - temp, - key, - KeyUsage.KU_KRB_SAFE_CKSUM - ); - - KRBSafe krb_safe = new KRBSafe(krb_safeBody, cksum); - - temp = krb_safe.asn1Encode(); - - return krb_safe.asn1Encode(); - } - - private byte[] rd_safe(KRBSafe krb_safe, - EncryptionKey key, - SeqNumber seqNumber, - HostAddress sAddress, - HostAddress rAddress, - boolean timestampRequired, - boolean seqNumberRequired, - PrincipalName cname - ) throws Asn1Exception, KdcErrException, - KrbApErrException, IOException, KrbCryptoException { - - byte[] temp = krb_safe.safeBody.asn1Encode(); - - if (!krb_safe.cksum.verifyKeyedChecksum(temp, key, - KeyUsage.KU_KRB_SAFE_CKSUM)) { - throw new KrbApErrException( - Krb5.KRB_AP_ERR_MODIFIED); - } - - check(krb_safe.safeBody.timestamp, - krb_safe.safeBody.usec, - krb_safe.safeBody.seqNumber, - krb_safe.safeBody.sAddress, - krb_safe.safeBody.rAddress, - seqNumber, - sAddress, - rAddress, - timestampRequired, - seqNumberRequired, - cname - ); - - return krb_safe.safeBody.userData; - } -} diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/KrbTgsReq.java b/src/java.security.jgss/share/classes/sun/security/krb5/KrbTgsReq.java index 259b7b494ce..cedd612d2c9 100644 --- a/src/java.security.jgss/share/classes/sun/security/krb5/KrbTgsReq.java +++ b/src/java.security.jgss/share/classes/sun/security/krb5/KrbTgsReq.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -316,9 +316,7 @@ public class KrbTgsReq { additionalTickets); byte[] temp = reqBody.asn1Encode(Krb5.KRB_TGS_REQ); - // if the checksum type is one of the keyed checksum types, - // use session key. - Checksum cksum = new Checksum(Checksum.CKSUMTYPE_DEFAULT, temp, key, + Checksum cksum = new Checksum(-1, temp, key, KeyUsage.KU_PA_TGS_REQ_CKSUM); // Usage will be KeyUsage.KU_PA_TGS_REQ_AUTHENTICATOR diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/internal/AuthContext.java b/src/java.security.jgss/share/classes/sun/security/krb5/internal/AuthContext.java deleted file mode 100644 index 05ed71b3229..00000000000 --- a/src/java.security.jgss/share/classes/sun/security/krb5/internal/AuthContext.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * 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. - */ - -/* - * - * (C) Copyright IBM Corp. 1999 All Rights Reserved. - * Copyright 1997 The Open Group Research Institute. All rights reserved. - */ - -package sun.security.krb5.internal; - -import sun.security.krb5.EncryptionKey; -import java.util.BitSet; - -public class AuthContext { - public HostAddress remoteAddress; - public int remotePort; - public HostAddress localAddress; - public int localPort; - public EncryptionKey keyBlock; - public EncryptionKey localSubkey; - public EncryptionKey remoteSubkey; - public BitSet authContextFlags; - public int remoteSeqNumber; - public int localSeqNumber; - public Authenticator authenticator; - public int reqCksumType; - public int safeCksumType; - public byte[] initializationVector; - //public ReplayCache replayCache; -}; diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/internal/EncKrbPrivPart.java b/src/java.security.jgss/share/classes/sun/security/krb5/internal/EncKrbPrivPart.java deleted file mode 100644 index f6bf61dd1a6..00000000000 --- a/src/java.security.jgss/share/classes/sun/security/krb5/internal/EncKrbPrivPart.java +++ /dev/null @@ -1,173 +0,0 @@ -/* - * 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. - */ - -/* - * (C) Copyright IBM Corp. 1999 All Rights Reserved. - * Copyright 1997 The Open Group Research Institute. All rights reserved. - */ - -package sun.security.krb5.internal; - -import sun.security.util.*; -import sun.security.krb5.Asn1Exception; -import java.util.Vector; -import java.io.IOException; -import java.math.BigInteger; - -/** - * Implements the ASN.1 EncKrbPrivPart type. - * - *
    {@code
    - * EncKrbPrivPart  ::= [APPLICATION 28] SEQUENCE {
    - *         user-data       [0] OCTET STRING,
    - *         timestamp       [1] KerberosTime OPTIONAL,
    - *         usec            [2] Microseconds OPTIONAL,
    - *         seq-number      [3] UInt32 OPTIONAL,
    - *         s-address       [4] HostAddress -- sender's addr --,
    - *         r-address       [5] HostAddress OPTIONAL -- recip's addr
    - * }
    - * }
    - * - *

    - * This definition reflects the Network Working Group RFC 4120 - * specification available at - * - * http://www.ietf.org/rfc/rfc4120.txt. - */ -public class EncKrbPrivPart { - - public byte[] userData = null; - public KerberosTime timestamp; //optional - public Integer usec; //optional - public Integer seqNumber; //optional - public HostAddress sAddress; //optional - public HostAddress rAddress; //optional - - public EncKrbPrivPart( - byte[] new_userData, - KerberosTime new_timestamp, - Integer new_usec, - Integer new_seqNumber, - HostAddress new_sAddress, - HostAddress new_rAddress) { - if (new_userData != null) { - userData = new_userData.clone(); - } - timestamp = new_timestamp; - usec = new_usec; - seqNumber = new_seqNumber; - sAddress = new_sAddress; - rAddress = new_rAddress; - } - - public EncKrbPrivPart(byte[] data) throws Asn1Exception, IOException { - init(new DerValue(data)); - } - - public EncKrbPrivPart(DerValue encoding) throws Asn1Exception, IOException { - init(encoding); - } - - /** - * Initializes an EncKrbPrivPart object. - * @param encoding a single DER-encoded value. - * @exception Asn1Exception if an error occurs while decoding an ASN1 encoded data. - * @exception IOException if an I/O error occurs while reading encoded data. - */ - private void init(DerValue encoding) throws Asn1Exception, IOException { - DerValue der, subDer; - if (((encoding.getTag() & (byte) 0x1F) != (byte) 0x1C) - || (encoding.isApplication() != true) - || (encoding.isConstructed() != true)) { - throw new Asn1Exception(Krb5.ASN1_BAD_ID); - } - der = encoding.getData().getDerValue(); - if (der.getTag() != DerValue.tag_Sequence) { - throw new Asn1Exception(Krb5.ASN1_BAD_ID); - } - subDer = der.getData().getDerValue(); - if ((subDer.getTag() & (byte) 0x1F) == (byte) 0x00) { - userData = subDer.getData().getOctetString(); - } else { - throw new Asn1Exception(Krb5.ASN1_BAD_ID); - } - timestamp = KerberosTime.parse(der.getData(), (byte) 0x01, true); - if ((der.getData().peekByte() & 0x1F) == 0x02) { - subDer = der.getData().getDerValue(); - usec = subDer.getData().getBigInteger().intValue(); - } else { - usec = null; - } - if ((der.getData().peekByte() & 0x1F) == 0x03) { - subDer = der.getData().getDerValue(); - seqNumber = subDer.getData().getBigInteger().intValue(); - } else { - seqNumber = null; - } - sAddress = HostAddress.parse(der.getData(), (byte) 0x04, false); - if (der.getData().available() > 0) { - rAddress = HostAddress.parse(der.getData(), (byte) 0x05, true); - } - if (der.getData().available() > 0) { - throw new Asn1Exception(Krb5.ASN1_BAD_ID); - } - } - - /** - * Encodes an EncKrbPrivPart object. - * @return byte array of encoded EncKrbPrivPart object. - * @exception Asn1Exception if an error occurs while decoding an ASN1 encoded data. - * @exception IOException if an I/O error occurs while reading encoded data. - */ - public byte[] asn1Encode() throws Asn1Exception, IOException { - DerOutputStream temp = new DerOutputStream(); - DerOutputStream bytes = new DerOutputStream(); - - temp.putOctetString(userData); - bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 0x00), temp); - if (timestamp != null) { - bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 0x01), timestamp.asn1Encode()); - } - if (usec != null) { - temp = new DerOutputStream(); - temp.putInteger(BigInteger.valueOf(usec.intValue())); - bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 0x02), temp); - } - if (seqNumber != null) { - temp = new DerOutputStream(); - // encode as an unsigned integer (UInt32) - temp.putInteger(BigInteger.valueOf(seqNumber.longValue())); - bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 0x03), temp); - } - bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 0x04), sAddress.asn1Encode()); - if (rAddress != null) { - bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 0x05), rAddress.asn1Encode()); - } - temp = new DerOutputStream(); - temp.write(DerValue.tag_Sequence, bytes); - bytes = new DerOutputStream(); - bytes.write(DerValue.createTag(DerValue.TAG_APPLICATION, true, (byte) 0x1C), temp); - return bytes.toByteArray(); - } -} diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/internal/KRBPriv.java b/src/java.security.jgss/share/classes/sun/security/krb5/internal/KRBPriv.java deleted file mode 100644 index 09adfe3aa0f..00000000000 --- a/src/java.security.jgss/share/classes/sun/security/krb5/internal/KRBPriv.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * 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. - */ - -/* - * - * (C) Copyright IBM Corp. 1999 All Rights Reserved. - * Copyright 1997 The Open Group Research Institute. All rights reserved. - */ - -package sun.security.krb5.internal; - -import sun.security.krb5.EncryptedData; -import sun.security.krb5.Asn1Exception; -import sun.security.util.*; -import java.io.IOException; -import java.math.BigInteger; - -/** - * Implements the ASN.1 KRB-PRIV type. - * - *

    {@code
    - * KRB-PRIV        ::= [APPLICATION 21] SEQUENCE {
    - *         pvno            [0] INTEGER (5),
    - *         msg-type        [1] INTEGER (21),
    - *                           -- NOTE: there is no [2] tag
    - *         enc-part        [3] EncryptedData -- EncKrbPrivPart
    - * }
    - * }
    - * - *

    - * This definition reflects the Network Working Group RFC 4120 - * specification available at - * - * http://www.ietf.org/rfc/rfc4120.txt. - */ - -public class KRBPriv { - public int pvno; - public int msgType; - public EncryptedData encPart; - - public KRBPriv(EncryptedData new_encPart) { - pvno = Krb5.PVNO; - msgType = Krb5.KRB_PRIV; - encPart = new_encPart; - } - - public KRBPriv(byte[] data) throws Asn1Exception, - KrbApErrException, IOException { - init(new DerValue(data)); - } - - public KRBPriv(DerValue encoding) throws Asn1Exception, - KrbApErrException, IOException { - init(encoding); - } - - - /** - * Initializes an KRBPriv object. - * @param encoding a single DER-encoded value. - * @exception Asn1Exception if an error occurs while decoding an ASN1 encoded data. - * @exception IOException if an I/O error occurs while reading encoded data. - * @exception KrbApErrException if the value read from the DER-encoded data - * stream does not match the pre-defined value. - */ - private void init(DerValue encoding) throws Asn1Exception, - KrbApErrException, IOException { - DerValue der, subDer; - if (((encoding.getTag() & (byte)0x1F) != (byte)0x15) - || (encoding.isApplication() != true) - || (encoding.isConstructed() != true)) - throw new Asn1Exception(Krb5.ASN1_BAD_ID); - der = encoding.getData().getDerValue(); - if (der.getTag() != DerValue.tag_Sequence) - throw new Asn1Exception(Krb5.ASN1_BAD_ID); - subDer = der.getData().getDerValue(); - if ((subDer.getTag() & 0x1F) == 0x00) { - pvno = subDer.getData().getBigInteger().intValue(); - if (pvno != Krb5.PVNO) { - throw new KrbApErrException(Krb5.KRB_AP_ERR_BADVERSION); - } - } - else - throw new Asn1Exception(Krb5.ASN1_BAD_ID); - subDer = der.getData().getDerValue(); - if ((subDer.getTag() & 0x1F) == 0x01) { - msgType = subDer.getData().getBigInteger().intValue(); - if (msgType != Krb5.KRB_PRIV) - throw new KrbApErrException(Krb5.KRB_AP_ERR_MSG_TYPE); - } - else - throw new Asn1Exception(Krb5.ASN1_BAD_ID); - encPart = EncryptedData.parse(der.getData(), (byte)0x03, false); - if (der.getData().available() >0) - throw new Asn1Exception(Krb5.ASN1_BAD_ID); - } - - /** - * Encodes an KRBPriv object. - * @return byte array of encoded EncAPRepPart object. - * @exception Asn1Exception if an error occurs while decoding an ASN1 encoded data. - * @exception IOException if an I/O error occurs while reading encoded data. - */ - public byte[] asn1Encode() throws Asn1Exception, IOException { - DerOutputStream temp, bytes; - temp = new DerOutputStream(); - temp.putInteger(BigInteger.valueOf(pvno)); - bytes = new DerOutputStream(); - bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x00), temp); - temp = new DerOutputStream(); - temp.putInteger(BigInteger.valueOf(msgType)); - bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x01), temp); - bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x03), encPart.asn1Encode()); - temp = new DerOutputStream(); - temp.write(DerValue.tag_Sequence, bytes); - bytes = new DerOutputStream(); - bytes.write(DerValue.createTag(DerValue.TAG_APPLICATION, true, (byte)0x15), temp); - return bytes.toByteArray(); - } - -} diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/internal/KRBSafe.java b/src/java.security.jgss/share/classes/sun/security/krb5/internal/KRBSafe.java deleted file mode 100644 index c9e85534ff0..00000000000 --- a/src/java.security.jgss/share/classes/sun/security/krb5/internal/KRBSafe.java +++ /dev/null @@ -1,146 +0,0 @@ -/* - * 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. - */ - -/* - * - * (C) Copyright IBM Corp. 1999 All Rights Reserved. - * Copyright 1997 The Open Group Research Institute. All rights reserved. - */ - -package sun.security.krb5.internal; - -import sun.security.krb5.Checksum; -import sun.security.krb5.Asn1Exception; -import sun.security.krb5.RealmException; -import sun.security.util.*; -import java.io.IOException; -import java.math.BigInteger; - -/** - * Implements the ASN.1 KRBSafe type. - * - *

    {@code
    - * KRB-SAFE        ::= [APPLICATION 20] SEQUENCE {
    - *         pvno            [0] INTEGER (5),
    - *         msg-type        [1] INTEGER (20),
    - *         safe-body       [2] KRB-SAFE-BODY,
    - *         cksum           [3] Checksum
    - * }
    - * }
    - * - *

    - * This definition reflects the Network Working Group RFC 4120 - * specifications available at - * - * http://www.ietf.org/rfc/rfc4120.txt. - */ - -public class KRBSafe { - public int pvno; - public int msgType; - public KRBSafeBody safeBody; - public Checksum cksum; - - public KRBSafe(KRBSafeBody new_safeBody, Checksum new_cksum) { - pvno = Krb5.PVNO; - msgType = Krb5.KRB_SAFE; - safeBody = new_safeBody; - cksum = new_cksum; - } - - public KRBSafe(byte[] data) throws Asn1Exception, - RealmException, KrbApErrException, IOException { - init(new DerValue(data)); - } - - public KRBSafe(DerValue encoding) throws Asn1Exception, - RealmException, KrbApErrException, IOException { - init(encoding); - } - - /** - * Initializes an KRBSafe object. - * @param encoding a single DER-encoded value. - * @exception Asn1Exception if an error occurs while decoding an ASN1 encoded data. - * @exception IOException if an I/O error occurs while reading encoded data. - * @exception RealmException if an error occurs while parsing a Realm object. - * @exception KrbApErrException if the value read from the DER-encoded data - * stream does not match the pre-defined value. - */ - private void init(DerValue encoding) throws Asn1Exception, - RealmException, KrbApErrException, IOException { - DerValue der, subDer; - if (((encoding.getTag() & (byte)0x1F) != (byte)0x14) - || (encoding.isApplication() != true) - || (encoding.isConstructed() != true)) - throw new Asn1Exception(Krb5.ASN1_BAD_ID); - der = encoding.getData().getDerValue(); - if (der.getTag() != DerValue.tag_Sequence) - throw new Asn1Exception(Krb5.ASN1_BAD_ID); - subDer = der.getData().getDerValue(); - if ((subDer.getTag() & 0x1F) == 0x00) { - pvno = subDer.getData().getBigInteger().intValue(); - if (pvno != Krb5.PVNO) - throw new KrbApErrException(Krb5.KRB_AP_ERR_BADVERSION); - } - else - throw new Asn1Exception(Krb5.ASN1_BAD_ID); - subDer = der.getData().getDerValue(); - if ((subDer.getTag() & 0x1F) == 0x01) { - msgType = subDer.getData().getBigInteger().intValue(); - if (msgType != Krb5.KRB_SAFE) - throw new KrbApErrException(Krb5.KRB_AP_ERR_MSG_TYPE); - } - - else - throw new Asn1Exception(Krb5.ASN1_BAD_ID); - safeBody = KRBSafeBody.parse(der.getData(), (byte)0x02, false); - cksum = Checksum.parse(der.getData(), (byte)0x03, false); - if (der.getData().available() > 0) - throw new Asn1Exception(Krb5.ASN1_BAD_ID); - } - - /** - * Encodes an KRBSafe object. - * @return byte array of encoded KRBSafe object. - * @exception Asn1Exception if an error occurs while decoding an ASN1 encoded data. - * @exception IOException if an I/O error occurs while reading encoded data. - */ - public byte[] asn1Encode() throws Asn1Exception, IOException { - DerOutputStream temp = new DerOutputStream(); - DerOutputStream bytes = new DerOutputStream(); - temp.putInteger(BigInteger.valueOf(pvno)); - bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x00), temp); - temp = new DerOutputStream(); - temp.putInteger(BigInteger.valueOf(msgType)); - bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x01), temp); - bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x02), safeBody.asn1Encode()); - bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x03), cksum.asn1Encode()); - temp = new DerOutputStream(); - temp.write(DerValue.tag_Sequence, bytes); - bytes = new DerOutputStream(); - bytes.write(DerValue.createTag(DerValue.TAG_APPLICATION, true, (byte)0x14), temp); - return bytes.toByteArray(); - } -} diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/internal/KRBSafeBody.java b/src/java.security.jgss/share/classes/sun/security/krb5/internal/KRBSafeBody.java deleted file mode 100644 index d138d6968b9..00000000000 --- a/src/java.security.jgss/share/classes/sun/security/krb5/internal/KRBSafeBody.java +++ /dev/null @@ -1,177 +0,0 @@ -/* - * 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. - */ - -/* - * - * (C) Copyright IBM Corp. 1999 All Rights Reserved. - * Copyright 1997 The Open Group Research Institute. All rights reserved. - */ - -package sun.security.krb5.internal; - -import sun.security.util.*; -import sun.security.krb5.Asn1Exception; -import java.util.Vector; -import java.io.IOException; -import java.math.BigInteger; - -/** - * Implements the ASN.1 KRBSafeBody type. - * - *

    {@code
    - * KRB-SAFE-BODY   ::= SEQUENCE {
    - *         user-data       [0] OCTET STRING,
    - *         timestamp       [1] KerberosTime OPTIONAL,
    - *         usec            [2] Microseconds OPTIONAL,
    - *         seq-number      [3] UInt32 OPTIONAL,
    - *         s-address       [4] HostAddress,
    - *         r-address       [5] HostAddress OPTIONAL
    - * }
    - * }
    - * - *

    - * This definition reflects the Network Working Group RFC 4120 - * specification available at - * - * http://www.ietf.org/rfc/rfc4120.txt. - */ - -public class KRBSafeBody { - public byte[] userData = null; - public KerberosTime timestamp; //optional - public Integer usec; //optional - public Integer seqNumber; //optional - public HostAddress sAddress; - public HostAddress rAddress; //optional - - public KRBSafeBody( - byte[] new_userData, - KerberosTime new_timestamp, - Integer new_usec, - Integer new_seqNumber, - HostAddress new_sAddress, - HostAddress new_rAddress - ) { - if (new_userData != null) { - userData = new_userData.clone(); - } - timestamp = new_timestamp; - usec = new_usec; - seqNumber = new_seqNumber; - sAddress = new_sAddress; - rAddress = new_rAddress; - } - - - /** - * Constructs a KRBSafeBody object. - * @param encoding a Der-encoded data. - * @exception Asn1Exception if an error occurs while decoding an ASN1 encoded data. - * @exception IOException if an I/O error occurs while reading encoded data. - */ - public KRBSafeBody(DerValue encoding) throws Asn1Exception, IOException { - DerValue der; - if (encoding.getTag() != DerValue.tag_Sequence) { - throw new Asn1Exception(Krb5.ASN1_BAD_ID); - } - der = encoding.getData().getDerValue(); - if ((der.getTag() & 0x1F) == 0x00) { - userData = der.getData().getOctetString(); - } - else - throw new Asn1Exception(Krb5.ASN1_BAD_ID); - timestamp = KerberosTime.parse(encoding.getData(), (byte)0x01, true); - if ((encoding.getData().peekByte() & 0x1F) == 0x02) { - der = encoding.getData().getDerValue(); - usec = der.getData().getBigInteger().intValue(); - } - if ((encoding.getData().peekByte() & 0x1F) == 0x03) { - der = encoding.getData().getDerValue(); - seqNumber = der.getData().getBigInteger().intValue(); - } - sAddress = HostAddress.parse(encoding.getData(), (byte)0x04, false); - if (encoding.getData().available() > 0) - rAddress = HostAddress.parse(encoding.getData(), (byte)0x05, true); - if (encoding.getData().available() > 0) - throw new Asn1Exception(Krb5.ASN1_BAD_ID); - } - - /** - * Encodes an KRBSafeBody object. - * @return the byte array of encoded KRBSafeBody object. - * @exception Asn1Exception if an error occurs while decoding an ASN1 encoded data. - * @exception IOException if an I/O error occurs while reading encoded data. - */ - public byte[] asn1Encode() throws Asn1Exception, IOException { - DerOutputStream bytes = new DerOutputStream(); - DerOutputStream temp = new DerOutputStream(); - temp.putOctetString(userData); - bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x00), temp); - if (timestamp != null) - bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x01), timestamp.asn1Encode()); - if (usec != null) { - temp = new DerOutputStream(); - temp.putInteger(BigInteger.valueOf(usec.intValue())); - bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x02), temp); - } - if (seqNumber != null) { - temp = new DerOutputStream(); - // encode as an unsigned integer (UInt32) - temp.putInteger(BigInteger.valueOf(seqNumber.longValue())); - bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x03), temp); - } - bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x04), sAddress.asn1Encode()); - if (rAddress != null) - temp = new DerOutputStream(); - temp.write(DerValue.tag_Sequence, bytes); - return temp.toByteArray(); - } - - /** - * Parse (unmarshal) a KRBSafeBody from a DER input stream. This form - * parsing might be used when expanding a value which is part of - * a constructed sequence and uses explicitly tagged type. - * - * @exception Asn1Exception on error. - * @param data the Der input stream value, which contains one or more marshaled value. - * @param explicitTag tag number. - * @param optional indicates if this data field is optional - * @return an instance of KRBSafeBody. - * - */ - public static KRBSafeBody parse(DerInputStream data, byte explicitTag, boolean optional) throws Asn1Exception, IOException { - if ((optional) && (((byte)data.peekByte() & (byte)0x1F) != explicitTag)) - return null; - DerValue der = data.getDerValue(); - if (explicitTag != (der.getTag() & (byte)0x1F)) - throw new Asn1Exception(Krb5.ASN1_BAD_ID); - else { - DerValue subDer = der.getData().getDerValue(); - return new KRBSafeBody(subDer); - } - } - - - -} diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/internal/MethodData.java b/src/java.security.jgss/share/classes/sun/security/krb5/internal/MethodData.java deleted file mode 100644 index d700410ca00..00000000000 --- a/src/java.security.jgss/share/classes/sun/security/krb5/internal/MethodData.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * 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. - */ - -/* - * - * (C) Copyright IBM Corp. 1999 All Rights Reserved. - * Copyright 1997 The Open Group Research Institute. All rights reserved. - */ - -package sun.security.krb5.internal; - -import sun.security.util.*; -import sun.security.krb5.Asn1Exception; -import java.io.IOException; -import java.math.BigInteger; - -/** - * Implements the ASN.1 EncKrbPrivPart type. - * - *

    {@code
    - *     METHOD-DATA ::=    SEQUENCE {
    - *                        method-type[0]   INTEGER,
    - *                        method-data[1]   OCTET STRING OPTIONAL
    - *  }
    - * }
    - */ -public class MethodData { - private int methodType; - private byte[] methodData = null; //optional - - public MethodData(int type, byte[] data) { - methodType = type; - if (data != null) { - methodData = data.clone(); - } - } - - /** - * Constructs a MethodData object. - * @param encoding a Der-encoded data. - * @exception Asn1Exception if an error occurs while decoding an ASN1 encoded data. - * @exception IOException if an I/O error occurs while reading encoded data. - */ - public MethodData(DerValue encoding) throws Asn1Exception, IOException { - DerValue der; - if (encoding.getTag() != DerValue.tag_Sequence) { - throw new Asn1Exception(Krb5.ASN1_BAD_ID); - } - der = encoding.getData().getDerValue(); - if ((der.getTag() & 0x1F) == 0x00) { - BigInteger bint = der.getData().getBigInteger(); - methodType = bint.intValue(); - } - else - throw new Asn1Exception(Krb5.ASN1_BAD_ID); - if (encoding.getData().available() > 0) { - der = encoding.getData().getDerValue(); - if ((der.getTag() & 0x1F) == 0x01) { - methodData = der.getData().getOctetString(); - } - else throw new Asn1Exception(Krb5.ASN1_BAD_ID); - } - if (encoding.getData().available() > 0) - throw new Asn1Exception(Krb5.ASN1_BAD_ID); - } - - /** - * Encodes an MethodData object. - * @return the byte array of encoded MethodData object. - * @exception Asn1Exception if an error occurs while decoding an ASN1 encoded data. - * @exception IOException if an I/O error occurs while reading encoded data. - */ - - public byte[] asn1Encode() throws Asn1Exception, IOException { - DerOutputStream bytes = new DerOutputStream(); - DerOutputStream temp = new DerOutputStream(); - temp.putInteger(BigInteger.valueOf(methodType)); - bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x00), temp); - if (methodData != null) { - temp = new DerOutputStream(); - temp.putOctetString(methodData); - bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x01), temp); - } - - temp = new DerOutputStream(); - temp.write(DerValue.tag_Sequence, bytes); - return temp.toByteArray(); - } - -} -- GitLab From 332f0673880d547a5f09cb4efd3b952868a84b91 Mon Sep 17 00:00:00 2001 From: Jonathan Gibbons Date: Tue, 5 Oct 2021 18:54:19 +0000 Subject: [PATCH 102/385] 8274729: Define Position.NOPOS == Diagnostic.NOPOS Reviewed-by: jlahoda --- .../share/classes/com/sun/tools/javac/util/Position.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Position.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Position.java index 0217f14a11b..b11686bd091 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Position.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Position.java @@ -29,6 +29,8 @@ import java.util.BitSet; import com.sun.tools.javac.util.DefinedBy.Api; +import javax.tools.Diagnostic; + import static com.sun.tools.javac.util.LayoutCharacters.*; /** A class that defines source code positions as simple character @@ -45,7 +47,7 @@ import static com.sun.tools.javac.util.LayoutCharacters.*; * deletion without notice.
    */ public class Position { - public static final int NOPOS = -1; + public static final int NOPOS = (int) Diagnostic.NOPOS; public static final int FIRSTPOS = 0; public static final int FIRSTLINE = 1; -- GitLab From d34ec6ccfc27d9401acce0e03595b910764fbfaf Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Tue, 5 Oct 2021 19:10:29 +0000 Subject: [PATCH 103/385] 8274793: Suppress warnings on non-serializable non-transient instance fields in sun.net Reviewed-by: alanb --- .../share/classes/sun/net/www/http/KeepAliveCache.java | 1 + .../sun/net/www/protocol/http/ntlm/NTLMAuthentication.java | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/java.base/share/classes/sun/net/www/http/KeepAliveCache.java b/src/java.base/share/classes/sun/net/www/http/KeepAliveCache.java index 4c21276a582..45dfdad08e0 100644 --- a/src/java.base/share/classes/sun/net/www/http/KeepAliveCache.java +++ b/src/java.base/share/classes/sun/net/www/http/KeepAliveCache.java @@ -79,6 +79,7 @@ public class KeepAliveCache // This class is never serialized (see writeObject/readObject). private final ReentrantLock cacheLock = new ReentrantLock(); + @SuppressWarnings("serial") // Type of field is not Serializable private Thread keepAliveTimer = null; /** diff --git a/src/java.base/unix/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java b/src/java.base/unix/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java index 8de55c57c26..90b1fdc1d28 100644 --- a/src/java.base/unix/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java +++ b/src/java.base/unix/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java @@ -119,8 +119,10 @@ public class NTLMAuthentication extends AuthenticationInfo { }); }; + @SuppressWarnings("serial") // Type of field is not Serializable PasswordAuthentication pw; + @SuppressWarnings("serial") // Type of field is not Serializable Client client; /** * Create a NTLMAuthentication: -- GitLab From 83b2219220266c1365466970d08606fef766c4fa Mon Sep 17 00:00:00 2001 From: Igor Veresov Date: Tue, 5 Oct 2021 19:44:17 +0000 Subject: [PATCH 104/385] 8273612: Fix for JDK-8272873 causes timeout in running some tests with -Xcomp Reviewed-by: kvn, neliasso --- src/hotspot/share/compiler/compilationPolicy.cpp | 4 ++++ .../jtreg/compiler/jvmci/compilerToVM/IsMatureTest.java | 4 +--- .../compiler/jvmci/compilerToVM/IsMatureVsReprofileTest.java | 4 ++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/hotspot/share/compiler/compilationPolicy.cpp b/src/hotspot/share/compiler/compilationPolicy.cpp index 1f9902895f1..592cb5d65f2 100644 --- a/src/hotspot/share/compiler/compilationPolicy.cpp +++ b/src/hotspot/share/compiler/compilationPolicy.cpp @@ -887,6 +887,10 @@ bool CompilationPolicy::is_method_profiled(const methodHandle& method) { // Determine is a method is mature. bool CompilationPolicy::is_mature(Method* method) { + if (Arguments::is_compiler_only()) { + // Always report profiles as immature with -Xcomp + return false; + } methodHandle mh(Thread::current(), method); MethodData* mdo = method->method_data(); if (mdo != NULL) { diff --git a/test/hotspot/jtreg/compiler/jvmci/compilerToVM/IsMatureTest.java b/test/hotspot/jtreg/compiler/jvmci/compilerToVM/IsMatureTest.java index 87f4d3df6cc..82838d67d26 100644 --- a/test/hotspot/jtreg/compiler/jvmci/compilerToVM/IsMatureTest.java +++ b/test/hotspot/jtreg/compiler/jvmci/compilerToVM/IsMatureTest.java @@ -80,9 +80,7 @@ public class IsMatureTest { "Multiple times invoked method should have method data"); // The method may or may not be mature if it's compiled with limited profile. if (compLevel != CompilerWhiteBoxTest.COMP_LEVEL_LIMITED_PROFILE) { - /* a method is not mature in Xcomp mode with tiered compilation disabled, - see NonTieredCompPolicy::is_mature */ - Asserts.assertEQ(isMature, !(Platform.isComp() && !TIERED), + Asserts.assertEQ(isMature, !Platform.isComp(), "Unexpected isMature state for multiple times invoked method"); } } diff --git a/test/hotspot/jtreg/compiler/jvmci/compilerToVM/IsMatureVsReprofileTest.java b/test/hotspot/jtreg/compiler/jvmci/compilerToVM/IsMatureVsReprofileTest.java index 6a289723a65..2a12549b25b 100644 --- a/test/hotspot/jtreg/compiler/jvmci/compilerToVM/IsMatureVsReprofileTest.java +++ b/test/hotspot/jtreg/compiler/jvmci/compilerToVM/IsMatureVsReprofileTest.java @@ -83,7 +83,7 @@ public class IsMatureVsReprofileTest { isMature = CompilerToVMHelper.isMature(metaspaceMethodData); /* a method is not mature for -Xcomp and -Tiered, see NonTieredCompPolicy::is_mature */ - Asserts.assertEQ(!IS_XCOMP || TIERED, isMature, + Asserts.assertEQ(!IS_XCOMP, isMature, "Unexpected isMature state for compiled method"); HotSpotResolvedJavaMethod resolvedMethod = CTVMUtilities.getResolvedMethod(method); @@ -94,7 +94,7 @@ public class IsMatureVsReprofileTest { isMature = CompilerToVMHelper.isMature(metaspaceMethodData); Asserts.assertNE(metaspaceMethodData, 0L, "Got null MDO after reprofile"); - Asserts.assertEQ(TIERED && IS_XCOMP, isMature, + Asserts.assertFalse(isMature, "Got unexpected isMature state after reprofiling"); } } -- GitLab From 47262670f371923a704ec521da40010c2a46be5a Mon Sep 17 00:00:00 2001 From: Christoph Langer Date: Tue, 5 Oct 2021 21:06:52 +0000 Subject: [PATCH 105/385] 8274642: jdk/jshell/CommandCompletionTest.java fails with NoSuchElementException after JDK-8271287 Reviewed-by: jlahoda --- test/langtools/jdk/jshell/CommandCompletionTest.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/test/langtools/jdk/jshell/CommandCompletionTest.java b/test/langtools/jdk/jshell/CommandCompletionTest.java index 9f2bbdb0beb..27746a748b9 100644 --- a/test/langtools/jdk/jshell/CommandCompletionTest.java +++ b/test/langtools/jdk/jshell/CommandCompletionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -49,10 +49,13 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import java.util.stream.StreamSupport; +import org.testng.SkipException; import org.testng.annotations.Test; + import jdk.internal.jshell.tool.JShellTool; import jdk.internal.jshell.tool.JShellToolBuilder; import jdk.jshell.SourceCodeAnalysis.Suggestion; + import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; import static org.testng.Assert.fail; @@ -337,7 +340,10 @@ public class CommandCompletionTest extends ReplToolTesting { selectedFile = content.filter(CLASSPATH_FILTER) .findAny() .map(file -> file.getFileName().toString()) - .get(); + .orElse(null); + } + if (selectedFile == null) { + throw new SkipException("No suitable file(s) found for this test in " + home); } try (Stream content = Files.list(home)) { completions = content.filter(CLASSPATH_FILTER) -- GitLab From d4e8712c0acc786e64f81ad29e54e6e50134f0e0 Mon Sep 17 00:00:00 2001 From: "Daniel D. Daugherty" Date: Tue, 5 Oct 2021 21:47:18 +0000 Subject: [PATCH 106/385] 8274797: ProblemList resourcehogs/serviceability/sa/TestHeapDumpForLargeArray.java on macosx-x64 Reviewed-by: darcy --- 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 988426e23ec..3bf51607a35 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -120,6 +120,8 @@ serviceability/sa/ClhsdbFindPC.java#xcomp-core 8269982 macosx-aarch64 serviceability/sa/ClhsdbFindPC.java#no-xcomp-core 8269982 macosx-aarch64 serviceability/sa/ClhsdbPstack.java#core 8269982 macosx-aarch64 +resourcehogs/serviceability/sa/TestHeapDumpForLargeArray.java 8274620 macosx-x64 + ############################################################################# # :hotspot_misc -- GitLab From df7b0c707713195c93ff4e745c89155ee8e4c571 Mon Sep 17 00:00:00 2001 From: Sergey Tsypanov Date: Tue, 5 Oct 2021 22:19:35 +0000 Subject: [PATCH 107/385] 8274715: Implement forEach in Collections.CopiesList Reviewed-by: martin --- .../share/classes/java/util/Collections.java | 10 ++++++ .../bench/java/util/NCopiesBenchmarks.java | 34 +++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 test/micro/org/openjdk/bench/java/util/NCopiesBenchmarks.java diff --git a/src/java.base/share/classes/java/util/Collections.java b/src/java.base/share/classes/java/util/Collections.java index 5eec62ddd75..b68de65f15f 100644 --- a/src/java.base/share/classes/java/util/Collections.java +++ b/src/java.base/share/classes/java/util/Collections.java @@ -5182,6 +5182,16 @@ public class Collections { return element; } + @Override + public void forEach(Consumer action) { + Objects.requireNonNull(action); + int n = this.n; + E element = this.element; + for (int i = 0; i < n; i++) { + action.accept(element); + } + } + public Object[] toArray() { final Object[] a = new Object[n]; if (element != null) diff --git a/test/micro/org/openjdk/bench/java/util/NCopiesBenchmarks.java b/test/micro/org/openjdk/bench/java/util/NCopiesBenchmarks.java new file mode 100644 index 00000000000..0fb845059ed --- /dev/null +++ b/test/micro/org/openjdk/bench/java/util/NCopiesBenchmarks.java @@ -0,0 +1,34 @@ +package micro.org.openjdk.bench.java.util; + +import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.infra.Blackhole; + +import java.util.*; +import java.util.concurrent.TimeUnit; + +/** + * @see JDK-8274715 + */ +@Fork(value = 3) +@State(Scope.Thread) +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS) +@Measurement(iterations = 5, time = 2, timeUnit = TimeUnit.SECONDS) +public class NCopiesBenchmarks { + @Param({"10", "50", "100"}) + int size; + + private List list; + + @Setup + public void prepare() { + list = Collections.nCopies(size, new Object()); + } + + @Benchmark + public void forEach(Blackhole bh) { + list.forEach(bh::consume); + } + +} -- GitLab From 986ee5d0bfd407dc1b7ce75c7c94b6585bfb497d Mon Sep 17 00:00:00 2001 From: Yasumasa Suenaga Date: Wed, 6 Oct 2021 00:36:50 +0000 Subject: [PATCH 108/385] 8274670: Improve version string handling in SA Reviewed-by: cjplummer, sspitsyn --- .../classes/sun/jvm/hotspot/runtime/VM.java | 18 +++++++++--------- .../runtime/VMVersionMismatchException.java | 10 +++++----- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VM.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VM.java index 02c82bf4a62..9f7024f1526 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VM.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VM.java @@ -359,26 +359,26 @@ public class VM { if (System.getProperty("sun.jvm.hotspot.runtime.VM.disableVersionCheck") == null) { // read sa build version. String versionProp = "sun.jvm.hotspot.runtime.VM.saBuildVersion"; - String saVersion = saProps.getProperty(versionProp); - if (saVersion == null) + String versionPropVal = saProps.getProperty(versionProp); + if (versionPropVal == null) { throw new RuntimeException("Missing property " + versionProp); + } - // Strip nonproduct VM version substring (note: saVersion doesn't have it). - String vmVersion = vmRelease.replaceAll("(-fastdebug)|(-debug)|(-jvmg)|(-optimized)|(-profiled)",""); + var saVersion = Runtime.Version.parse(versionPropVal); + var vmVersion = Runtime.Version.parse(vmRelease); if (saVersion.equals(vmVersion)) { // Exact match return; } - if (saVersion.indexOf('-') == saVersion.lastIndexOf('-') && - vmVersion.indexOf('-') == vmVersion.lastIndexOf('-')) { + if (!saVersion.equalsIgnoreOptional(vmVersion)) { // Throw exception if different release versions: - // .-b - throw new VMVersionMismatchException(saVersion, vmRelease); + // + + throw new VMVersionMismatchException(saVersion, vmVersion); } else { // Otherwise print warning to allow mismatch not release versions // during development. - System.err.println("WARNING: Hotspot VM version " + vmRelease + + System.err.println("WARNING: Hotspot VM version " + vmVersion + " does not match with SA version " + saVersion + "." + " You may see unexpected results. "); } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VMVersionMismatchException.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VMVersionMismatchException.java index aff07b32501..687706d72c0 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VMVersionMismatchException.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VMVersionMismatchException.java @@ -27,7 +27,7 @@ package sun.jvm.hotspot.runtime; /** An instance of this exception is thrown when debuggee VM version is not supported current version of SA. */ public class VMVersionMismatchException extends RuntimeException { - public VMVersionMismatchException(String supported, String target) { + public VMVersionMismatchException(Runtime.Version supported, Runtime.Version target) { super(); supportedVersions = supported; targetVersion = target; @@ -38,14 +38,14 @@ public class VMVersionMismatchException extends RuntimeException { ". Target VM is " + targetVersion; } - public String getSupportedVersions() { + public Runtime.Version getSupportedVersions() { return supportedVersions; } - public String getTargetVersion() { + public Runtime.Version getTargetVersion() { return targetVersion; } - private String supportedVersions; - private String targetVersion; + private final Runtime.Version supportedVersions; + private final Runtime.Version targetVersion; } -- GitLab From 8a4d2b4aa76e6aae1cb27f476c6cc71dcd9779f0 Mon Sep 17 00:00:00 2001 From: Andrey Turbanov Date: Wed, 6 Oct 2021 02:53:09 +0000 Subject: [PATCH 109/385] 8274680: Remove unnecessary conversion to String in java.desktop Reviewed-by: pbansal, jdv, serb, kizune --- .../plugins/jpeg/DHTMarkerSegment.java | 8 +++----- .../plugins/jpeg/DQTMarkerSegment.java | 11 ++++------- .../plugins/jpeg/DRIMarkerSegment.java | 5 ++--- .../plugins/jpeg/JFIFMarkerSegment.java | 3 +-- .../sun/imageio/plugins/png/PNGMetadata.java | 14 +++++++------- .../javax/imageio/plugins/tiff/TIFFField.java | 19 +++++-------------- .../swing/DefaultListSelectionModel.java | 8 ++++---- .../classes/javax/swing/GroupLayout.java | 12 ++++++------ .../javax/swing/event/TreeModelEvent.java | 7 +++---- .../classes/javax/swing/text/TabStop.java | 4 ++-- .../swing/text/html/OptionListModel.java | 6 +++--- .../swing/tree/DefaultTreeSelectionModel.java | 5 ++--- .../sun/java2d/marlin/RendererContext.java | 5 ++--- .../share/classes/sun/print/PSPrinterJob.java | 2 +- .../swing/plaf/synth/DefaultSynthStyle.java | 6 +++--- .../sun/awt/windows/WDesktopProperties.java | 4 ++-- 16 files changed, 50 insertions(+), 69 deletions(-) diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/DHTMarkerSegment.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/DHTMarkerSegment.java index 80405bac20c..34eca627d97 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/DHTMarkerSegment.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/DHTMarkerSegment.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,7 +33,6 @@ import javax.imageio.plugins.jpeg.JPEGHuffmanTable; import java.io.IOException; import java.util.List; import java.util.ArrayList; -import java.util.Iterator; import org.w3c.dom.Node; import org.w3c.dom.NodeList; @@ -119,8 +118,7 @@ class DHTMarkerSegment extends MarkerSegment { void print() { printTag("DHT"); - System.out.println("Num tables: " - + Integer.toString(tables.size())); + System.out.println("Num tables: " + tables.size()); for (int i= 0; i * If the value at the anchor index is not selected, do the same thing in diff --git a/src/java.desktop/share/classes/javax/swing/GroupLayout.java b/src/java.desktop/share/classes/javax/swing/GroupLayout.java index ebcf2f1b5f2..61ed76bd536 100644 --- a/src/java.desktop/share/classes/javax/swing/GroupLayout.java +++ b/src/java.desktop/share/classes/javax/swing/GroupLayout.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1230,7 +1230,7 @@ public class GroupLayout implements LayoutManager2 { String padding = ""; if (spring instanceof ComponentSpring) { ComponentSpring cSpring = (ComponentSpring)spring; - origin = Integer.toString(cSpring.getOrigin()) + " "; + origin = cSpring.getOrigin() + " "; String name = cSpring.getComponent().getName(); if (name != null) { origin = "name=" + name + ", "; @@ -1885,7 +1885,7 @@ public class GroupLayout implements LayoutManager2 { * @param comp1 the first component * @param comp2 the second component * @param type the type of gap - * @param pref the preferred size of the grap; one of + * @param pref the preferred size of the gap; one of * {@code DEFAULT_SIZE} or a value >= 0 * @param max the maximum size of the gap; one of * {@code DEFAULT_SIZE}, {@code PREFERRED_SIZE} @@ -1944,7 +1944,7 @@ public class GroupLayout implements LayoutManager2 { * @param type the type of gap; one of * {@code LayoutStyle.ComponentPlacement.RELATED} or * {@code LayoutStyle.ComponentPlacement.UNRELATED} - * @param pref the preferred size of the grap; one of + * @param pref the preferred size of the gap; one of * {@code DEFAULT_SIZE} or a value >= 0 * @param max the maximum size of the gap; one of * {@code DEFAULT_SIZE}, {@code PREFERRED_SIZE} @@ -3506,10 +3506,10 @@ public class GroupLayout implements LayoutManager2 { String getMatchDescription() { if (targets != null) { - return "leading: " + targets.toString(); + return "leading: " + targets; } if (sources != null) { - return "trailing: " + sources.toString(); + return "trailing: " + sources; } return "--"; } diff --git a/src/java.desktop/share/classes/javax/swing/event/TreeModelEvent.java b/src/java.desktop/share/classes/javax/swing/event/TreeModelEvent.java index 1d377bf2a65..6661cb3775e 100644 --- a/src/java.desktop/share/classes/javax/swing/event/TreeModelEvent.java +++ b/src/java.desktop/share/classes/javax/swing/event/TreeModelEvent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -294,14 +294,13 @@ public class TreeModelEvent extends EventObject { public String toString() { StringBuilder sb = new StringBuilder(); - sb.append(getClass().getName() + " " + - Integer.toString(hashCode())); + sb.append(getClass().getName() + " " + hashCode()); if(path != null) sb.append(" path " + path); if(childIndices != null) { sb.append(" indices [ "); for(int counter = 0; counter < childIndices.length; counter++) - sb.append(Integer.toString(childIndices[counter])+ " "); + sb.append(childIndices[counter] + " "); sb.append("]"); } if(children != null) { diff --git a/src/java.desktop/share/classes/javax/swing/text/TabStop.java b/src/java.desktop/share/classes/javax/swing/text/TabStop.java index 4d2d60d448b..12b0ea45913 100644 --- a/src/java.desktop/share/classes/javax/swing/text/TabStop.java +++ b/src/java.desktop/share/classes/javax/swing/text/TabStop.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -181,7 +181,7 @@ public class TabStop implements Serializable { buf = "bar "; break; } - buf = buf + "tab @" + String.valueOf(position); + buf = buf + "tab @" + position; if (leader != LEAD_NONE) buf = buf + " (w/leaders)"; return buf; diff --git a/src/java.desktop/share/classes/javax/swing/text/html/OptionListModel.java b/src/java.desktop/share/classes/javax/swing/text/html/OptionListModel.java index 70603d0cc63..2b84b54b3e1 100644 --- a/src/java.desktop/share/classes/javax/swing/text/html/OptionListModel.java +++ b/src/java.desktop/share/classes/javax/swing/text/html/OptionListModel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -456,7 +456,7 @@ class OptionListModel extends DefaultListModel implements ListSelectionMod public String toString() { String s = ((getValueIsAdjusting()) ? "~" : "=") + value.toString(); - return getClass().getName() + " " + Integer.toString(hashCode()) + " " + s; + return getClass().getName() + " " + hashCode() + " " + s; } /** @@ -499,7 +499,7 @@ class OptionListModel extends DefaultListModel implements ListSelectionMod * anchor and the new lead are either all selected or all deselected. * If the value at the anchor index is selected, first clear all the * values in the range [anchor, oldLeadIndex], then select all the values - * values in the range [anchor, newLeadIndex], where oldLeadIndex is the old + * in the range [anchor, newLeadIndex], where oldLeadIndex is the old * leadIndex and newLeadIndex is the new one. *

    * If the value at the anchor index is not selected, do the same thing in reverse, diff --git a/src/java.desktop/share/classes/javax/swing/tree/DefaultTreeSelectionModel.java b/src/java.desktop/share/classes/javax/swing/tree/DefaultTreeSelectionModel.java index 5ac8129d53e..2c592f24d2b 100644 --- a/src/java.desktop/share/classes/javax/swing/tree/DefaultTreeSelectionModel.java +++ b/src/java.desktop/share/classes/javax/swing/tree/DefaultTreeSelectionModel.java @@ -1174,10 +1174,9 @@ public class DefaultTreeSelectionModel implements Cloneable, Serializable, TreeS sb.append(getClass().getName() + " " + hashCode() + " [ "); for(int counter = 0; counter < selCount; counter++) { if(rows != null) - sb.append(selection[counter].toString() + "@" + - Integer.toString(rows[counter])+ " "); + sb.append(selection[counter] + "@" + rows[counter] + " "); else - sb.append(selection[counter].toString() + " "); + sb.append(selection[counter] + " "); } sb.append("]"); return sb.toString(); 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 830d0a6d07d..ed3735ee09c 100644 --- a/src/java.desktop/share/classes/sun/java2d/marlin/RendererContext.java +++ b/src/java.desktop/share/classes/sun/java2d/marlin/RendererContext.java @@ -48,13 +48,12 @@ final class RendererContext extends ReentrantContext implements MarlinConst { * @return new RendererContext instance */ static RendererContext createContext() { - return new RendererContext("ctx" - + Integer.toString(CTX_COUNT.getAndIncrement())); + return new RendererContext("ctx" + CTX_COUNT.getAndIncrement()); } // Smallest object used as Cleaner's parent reference private final Object cleanerObj; - // dirty flag indicating an exception occured during pipeline in pathTo() + // dirty flag indicating an exception occurred during pipeline in pathTo() boolean dirty = false; // shared data final double[] double6 = new double[6]; diff --git a/src/java.desktop/share/classes/sun/print/PSPrinterJob.java b/src/java.desktop/share/classes/sun/print/PSPrinterJob.java index 4645aabd861..e90b0b586c8 100644 --- a/src/java.desktop/share/classes/sun/print/PSPrinterJob.java +++ b/src/java.desktop/share/classes/sun/print/PSPrinterJob.java @@ -613,7 +613,7 @@ public class PSPrinterJob extends RasterPrinterJob { int cnt = Integer.parseInt(mFontProps.getProperty("font.num", "9")); for (int i = 0; i < cnt; i++){ mPSStream.println(" /" + mFontProps.getProperty - ("font." + String.valueOf(i), "Courier ISOF")); + ("font." + i, "Courier ISOF")); } } mPSStream.println("] D"); diff --git a/src/java.desktop/share/classes/sun/swing/plaf/synth/DefaultSynthStyle.java b/src/java.desktop/share/classes/sun/swing/plaf/synth/DefaultSynthStyle.java index 587aceb454f..55cf2bfdebc 100644 --- a/src/java.desktop/share/classes/sun/swing/plaf/synth/DefaultSynthStyle.java +++ b/src/java.desktop/share/classes/sun/swing/plaf/synth/DefaultSynthStyle.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -470,7 +470,7 @@ public class DefaultSynthStyle extends SynthStyle implements Cloneable { /** * Merges the contents of this Style with that of the passed in Style, - * returning the resulting merged syle. Properties of this + * returning the resulting merged style. Properties of this * DefaultSynthStyle will take precedence over those of the * passed in DefaultSynthStyle. For example, if this * style specifics a non-null font, the returned style will have its @@ -887,7 +887,7 @@ public class DefaultSynthStyle extends SynthStyle implements Cloneable { sb.append(super.toString()).append(','); - sb.append("state=").append(Integer.toString(state)).append(','); + sb.append("state=").append(state).append(','); sb.append("font=").append(font).append(','); diff --git a/src/java.desktop/windows/classes/sun/awt/windows/WDesktopProperties.java b/src/java.desktop/windows/classes/sun/awt/windows/WDesktopProperties.java index 8126c31b95c..131a1c701e1 100644 --- a/src/java.desktop/windows/classes/sun/awt/windows/WDesktopProperties.java +++ b/src/java.desktop/windows/classes/sun/awt/windows/WDesktopProperties.java @@ -106,7 +106,7 @@ final class WDesktopProperties { private synchronized void setBooleanProperty(String key, boolean value) { assert( key != null ); if (log.isLoggable(PlatformLogger.Level.FINE)) { - log.fine(key + "=" + String.valueOf(value)); + log.fine(key + "=" + value); } map.put(key, Boolean.valueOf(value)); } @@ -117,7 +117,7 @@ final class WDesktopProperties { private synchronized void setIntegerProperty(String key, int value) { assert( key != null ); if (log.isLoggable(PlatformLogger.Level.FINE)) { - log.fine(key + "=" + String.valueOf(value)); + log.fine(key + "=" + value); } map.put(key, Integer.valueOf(value)); } -- GitLab From 2faced09ce0f6901dcdc969e6c85f2a5b55778f1 Mon Sep 17 00:00:00 2001 From: Per Liden Date: Wed, 6 Oct 2021 07:44:47 +0000 Subject: [PATCH 110/385] 8274738: ZGC: Use relaxed atomic load when reading bits in the live map Reviewed-by: stefank, eosterlund --- src/hotspot/share/gc/z/zLiveMap.inline.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/gc/z/zLiveMap.inline.hpp b/src/hotspot/share/gc/z/zLiveMap.inline.hpp index bf0fd808a8b..1d3052473c6 100644 --- a/src/hotspot/share/gc/z/zLiveMap.inline.hpp +++ b/src/hotspot/share/gc/z/zLiveMap.inline.hpp @@ -98,9 +98,9 @@ inline BitMap::idx_t ZLiveMap::index_to_segment(BitMap::idx_t index) const { inline bool ZLiveMap::get(size_t index) const { BitMap::idx_t segment = index_to_segment(index); - return is_marked() && // Page is marked - is_segment_live(segment) && // Segment is marked - _bitmap.at(index); // Object is marked + return is_marked() && // Page is marked + is_segment_live(segment) && // Segment is marked + _bitmap.par_at(index, memory_order_relaxed); // Object is marked } inline bool ZLiveMap::set(size_t index, bool finalizable, bool& inc_live) { -- GitLab From c74726dbd0767d02abf9535361a86ffb69b646d9 Mon Sep 17 00:00:00 2001 From: Andrew Haley Date: Wed, 6 Oct 2021 08:18:10 +0000 Subject: [PATCH 111/385] 8274730: AArch64: AES/GCM acceleration is broken by the fix for JDK-8273297 Reviewed-by: adinn, roland, kvn --- src/hotspot/cpu/aarch64/matcher_aarch64.hpp | 2 +- .../cpu/aarch64/stubGenerator_aarch64.cpp | 9 +++++++-- src/hotspot/share/opto/library_call.cpp | 17 +++++++++++------ 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/hotspot/cpu/aarch64/matcher_aarch64.hpp b/src/hotspot/cpu/aarch64/matcher_aarch64.hpp index 9252ff12725..e0bb39f9e5f 100644 --- a/src/hotspot/cpu/aarch64/matcher_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/matcher_aarch64.hpp @@ -56,7 +56,7 @@ static const bool supports_generic_vector_operands = false; // No support for 48 extra htbl entries in aes-gcm intrinsic - static const int htbl_entries = -1; + static const int htbl_entries = 0; static constexpr bool isSimpleConstant64(jlong value) { // Will one (StoreL ConL) be cheaper than two (StoreI ConI)?. diff --git a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp index 8c7ae234d04..72e24e4fe61 100644 --- a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp @@ -3094,7 +3094,8 @@ class StubGenerator: public StubCodeGenerator { // key = c_rarg4 // state = c_rarg5 - GHASH.state // subkeyHtbl = c_rarg6 - powers of H - // counter = c_rarg7 - pointer to 16 bytes of CTR + // subkeyHtbl_48_entries = c_rarg7 (not used) + // counter = [sp, #0] pointer to 16 bytes of CTR // return - number of processed bytes address generate_galoisCounterMode_AESCrypt() { address ghash_polynomial = __ pc(); @@ -3107,6 +3108,8 @@ class StubGenerator: public StubCodeGenerator { __ align(CodeEntryAlignment); StubCodeMark mark(this, "StubRoutines", "galoisCounterMode_AESCrypt"); address start = __ pc(); + __ enter(); + const Register in = c_rarg0; const Register len = c_rarg1; const Register ct = c_rarg2; @@ -3118,10 +3121,12 @@ class StubGenerator: public StubCodeGenerator { const Register subkeyHtbl = c_rarg6; + // Pointer to CTR is passed on the stack before the (fp, lr) pair. + const Address counter_mem(sp, 2 * wordSize); const Register counter = c_rarg7; + __ ldr(counter, counter_mem); const Register keylen = r10; - __ enter(); // Save state before entering routine __ sub(sp, sp, 4 * 16); __ st1(v12, v13, v14, v15, __ T16B, Address(sp)); diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index 7c8b8bae6aa..c22ae2e91df 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -6794,14 +6794,19 @@ bool LibraryCallKit::inline_galoisCounterMode_AESCrypt() { ciKlass* klass = ciTypeArrayKlass::make(T_LONG); Node* klass_node = makecon(TypeKlassPtr::make(klass)); - // htbl entries is set to 96 only fox x86-64 + // Does this target support this intrinsic? if (Matcher::htbl_entries == -1) return false; - // new array to hold 48 computed htbl entries - Node* subkeyHtbl_48_entries = new_array(klass_node, intcon(Matcher::htbl_entries), 0); - if (subkeyHtbl_48_entries == NULL) return false; - - Node* subkeyHtbl_48_entries_start = array_element_address(subkeyHtbl_48_entries, intcon(0), T_LONG); + Node* subkeyHtbl_48_entries_start; + if (Matcher::htbl_entries != 0) { + // new array to hold 48 computed htbl entries + Node* subkeyHtbl_48_entries = new_array(klass_node, intcon(Matcher::htbl_entries), 0); + if (subkeyHtbl_48_entries == NULL) return false; + subkeyHtbl_48_entries_start = array_element_address(subkeyHtbl_48_entries, intcon(0), T_LONG); + } else { + // This target doesn't need the extra-large Htbl. + subkeyHtbl_48_entries_start = ConvL2X(intcon(0)); + } // Call the stub, passing params Node* gcmCrypt = make_runtime_call(RC_LEAF|RC_NO_FP, -- GitLab From df125f680b6a4517109be80512a113064ca6281d Mon Sep 17 00:00:00 2001 From: Christian Hagedorn Date: Wed, 6 Oct 2021 08:21:18 +0000 Subject: [PATCH 112/385] 8273410: IR verification framework fails with "Should find method name in validIrRulesMap" Reviewed-by: thartmann, neliasso --- .../lib/ir_framework/test/TestVM.java | 5 +- .../ir_framework/tests/TestBadFormat.java | 7 + .../ir_framework/tests/TestCheckedTests.java | 222 ++++++++++++++++++ 3 files changed, 233 insertions(+), 1 deletion(-) create mode 100644 test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestCheckedTests.java diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/test/TestVM.java b/test/hotspot/jtreg/compiler/lib/ir_framework/test/TestVM.java index 87d392dcec5..51d6c7add41 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/test/TestVM.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/test/TestVM.java @@ -619,13 +619,16 @@ public class TestVM { DeclaredTest test = declaredTests.get(testMethod); checkCheckedTest(m, checkAnno, runAnno, testMethod, test); test.setAttachedMethod(m); + TestFormat.check(getAnnotation(testMethod, Arguments.class) != null || testMethod.getParameterCount() == 0, + "Missing @Arguments annotation to define arguments of " + testMethod + " required by " + + "checked test " + m); CheckedTest.Parameter parameter = getCheckedTestParameter(m, testMethod); dontCompileAndDontInlineMethod(m); CheckedTest checkedTest = new CheckedTest(test, m, checkAnno, parameter, shouldExcludeTest(testMethod.getName())); allTests.add(checkedTest); if (PRINT_VALID_IR_RULES) { // Only need to emit IR verification information if IR verification is actually performed. - irMatchRulePrinter.emitRuleEncoding(m, checkedTest.isSkipped()); + irMatchRulePrinter.emitRuleEncoding(testMethod, checkedTest.isSkipped()); } } diff --git a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestBadFormat.java b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestBadFormat.java index 4eb0cba6f14..247872a74b3 100644 --- a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestBadFormat.java +++ b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestBadFormat.java @@ -139,6 +139,13 @@ class BadArgumentsAnnotation { @Test public void noArgAnnotation(int a) {} + @FailCount(0) // Combined with both checkNoArgAnnotation2() below + @Test + public void noArgAnnotation2(int a) {} + + @Check(test = "noArgAnnotation2") + public void checkNoArgAnnotation2() {} + @Test @Arguments(Argument.DEFAULT) public void argNumberMismatch(int a, int b) {} diff --git a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestCheckedTests.java b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestCheckedTests.java new file mode 100644 index 00000000000..b6e28cb3bea --- /dev/null +++ b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestCheckedTests.java @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 ir_framework.tests; + +import compiler.lib.ir_framework.*; +import compiler.lib.ir_framework.driver.IRViolationException; +import compiler.lib.ir_framework.driver.TestVMException; +import jdk.test.lib.Asserts; + +/* + * @test + * @bug 8273410 + * @requires vm.debug == true & vm.compMode != "Xint" & vm.compiler2.enabled & vm.flagless + * @summary Test different custom run tests. + * @library /test/lib /testlibrary_tests / + * @run driver ir_framework.tests.TestCheckedTests + */ + +public class TestCheckedTests { + public int iFld; + + public static void main(String[] args) { + TestFramework.run(); + try { + TestFramework.run(BadIRAndRuntimeCheckedTests.class); + Utils.shouldHaveThrownException(); + } catch (TestVMException e) { + Asserts.assertTrue(e.getExceptionInfo().contains("Test Failures (2)")); + Asserts.assertTrue(e.getExceptionInfo().contains("checkTestBad3")); + Asserts.assertTrue(e.getExceptionInfo().contains("checkTestBad5")); + Asserts.assertTrue(e.getExceptionInfo().split("BadCheckedTestException").length == 3); + Asserts.assertFalse(e.getExceptionInfo().contains("Failed IR Rules")); + } + + try { + TestFramework.run(BadIRCheckedTests.class); + Utils.shouldHaveThrownException(); + } catch (IRViolationException e) { + Asserts.assertTrue(e.getExceptionInfo().contains("Failed IR Rules (3)")); + } + } + + @Test + @IR(counts = {IRNode.STORE_I, "1"}) + public void testGood1() { + iFld = 3; + } + + @Check(test = "testGood1") + public void checkTestGood1(TestInfo info) { + } + + @Test + @IR(failOn = IRNode.LOAD) + public int testGood2() { + iFld = 3; + return 3; + } + + @Check(test = "testGood2") + public void sameName(int retValue) { + if (retValue != 3) { + throw new RuntimeException("must be 3 but was " + retValue); + } + } + + @Test + @Arguments(Argument.NUMBER_42) + @IR(failOn = IRNode.LOAD) + @IR(counts = {IRNode.STORE_I, "0"}) + public int testGood3(int x) { + return x; + } + + @Check(test = "testGood3") + public void sameName(int retValue, TestInfo info) { + if (retValue != 42) { + throw new RuntimeException("must be 42"); + } + } +} + +class BadIRAndRuntimeCheckedTests { + public int iFld; + + @Test + @IR(counts = {IRNode.STORE_I, "2"}) + public void testBad1() { + iFld = 3; + } + + @Check(test = "testBad1") + public void checkTestBad1(TestInfo info) { + } + + @Test + @IR(failOn = IRNode.STORE_I) + public int testBad2() { + iFld = 3; + return 3; + } + + @Check(test = "testBad2") + public void sameName(int retValue) { + if (retValue != 3) { + throw new RuntimeException("must be 3"); + } + } + + @Test + @Arguments(Argument.NUMBER_42) + public int testBad3(int x) { + return x; + } + + @Check(test = "testBad3") + public void checkTestBad3(int retValue) { + if (retValue == 42) { + // Always + throw new BadCheckedTestException("expected"); + } + } + + @Test + @Arguments(Argument.NUMBER_42) + @IR(failOn = IRNode.LOAD) + @IR(counts = {IRNode.STORE_I, "1"}) + public int testBad4(int x) { + return x; + } + + @Check(test = "testBad4") + public void sameName(int retValue, TestInfo info) { + if (retValue != 42) { + throw new RuntimeException("must be 42"); + } + } + + @Test + @Arguments(Argument.NUMBER_42) + public int testBad5(int x) { + return x; + } + + @Check(test = "testBad5") + public void checkTestBad5(int retValue) { + if (retValue == 42) { + // Always + throw new BadCheckedTestException("expected"); + } + } +} + +class BadIRCheckedTests { + public int iFld; + + @Test + @IR(counts = {IRNode.STORE_I, "2"}) + public void testBad1() { + iFld = 3; + } + + @Check(test = "testBad1") + public void checkTestBad1(TestInfo info) { + } + + @Test + @IR(failOn = IRNode.STORE_I) + public int testBad2() { + iFld = 3; + return 3; + } + + @Check(test = "testBad2") + public void sameName(int retValue) { + if (retValue != 3) { + throw new RuntimeException("must be 3"); + } + } + + @Test + @Arguments(Argument.NUMBER_42) + @IR(failOn = IRNode.LOAD) + @IR(counts = {IRNode.STORE_I, "1"}) + public int testBad4(int x) { + return x; + } + + @Check(test = "testBad4") + public void sameName(int retValue, TestInfo info) { + if (retValue != 42) { + throw new RuntimeException("must be 42"); + } + } +} + +class BadCheckedTestException extends RuntimeException { + BadCheckedTestException(String s) { + super(s); + } +} -- GitLab From cdf89304eafce58e66127d4e277f5fcaf07c9954 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Walln=C3=B6fer?= Date: Wed, 6 Oct 2021 09:28:37 +0000 Subject: [PATCH 113/385] 8274625: Search field placeholder behavior Reviewed-by: prappo --- .../doclets/formats/html/Navigation.java | 9 ++++++--- .../doclets/formats/html/markup/HtmlAttr.java | 3 ++- .../doclets/formats/html/markup/HtmlTree.java | 8 +++----- .../formats/html/resources/search.js.template | 16 ++-------------- .../doclets/toolkit/resources/doclets.properties | 1 + .../doclets/toolkit/resources/stylesheet.css | 5 +++-- .../CheckStylesheetClasses.java | 3 +-- .../javadoc/doclet/testSearch/TestSearch.java | 10 ++-------- .../doclet/testStylesheet/TestStylesheet.java | 5 +++-- 9 files changed, 23 insertions(+), 37 deletions(-) diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Navigation.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Navigation.java index 80227d3a4ff..7ecbad9d6fd 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Navigation.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Navigation.java @@ -76,6 +76,7 @@ public class Navigation { private Content userHeader; private final String rowListTitle; private final Content searchLabel; + private final String searchPlaceholder; private SubNavLinks subNavLinks; public enum PageMode { @@ -131,6 +132,7 @@ public class Navigation { this.links = new Links(path); this.rowListTitle = configuration.getDocResources().getText("doclet.Navigation"); this.searchLabel = contents.getContent("doclet.search"); + this.searchPlaceholder = configuration.getDocResources().getText("doclet.search_placeholder"); } public Navigation setNavLinkModule(Content navLinkModule) { @@ -595,10 +597,11 @@ public class Navigation { } private void addSearch(Content tree) { - String search = "search"; String reset = "reset"; - HtmlTree inputText = HtmlTree.INPUT("text", HtmlIds.SEARCH_INPUT, search); - HtmlTree inputReset = HtmlTree.INPUT(reset, HtmlIds.RESET_BUTTON, reset); + HtmlTree inputText = HtmlTree.INPUT("text", HtmlIds.SEARCH_INPUT) + .put(HtmlAttr.PLACEHOLDER, searchPlaceholder); + HtmlTree inputReset = HtmlTree.INPUT(reset, HtmlIds.RESET_BUTTON) + .put(HtmlAttr.VALUE, reset); HtmlTree searchDiv = HtmlTree.DIV(HtmlStyle.navListSearch, HtmlTree.LABEL(HtmlIds.SEARCH_INPUT.name(), searchLabel)); searchDiv.add(inputText); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlAttr.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlAttr.java index 614482c68c2..ba95ddc1af5 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlAttr.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlAttr.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -57,6 +57,7 @@ public enum HtmlAttr { ONCLICK, ONKEYDOWN, ONLOAD, + PLACEHOLDER, REL, ROLE, ROWS, diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlTree.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlTree.java index 41561dd6a74..1d05cd8c4d4 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlTree.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlTree.java @@ -520,20 +520,18 @@ public class HtmlTree extends Content { } /** - * Creates an HTML {@code INPUT} element with the given id and initial value. + * Creates an HTML {@code INPUT} element with the given id. * The element as marked as initially disabled. * * @param type the type of input * @param id the id - * @param value the initial value * @return the element */ - public static HtmlTree INPUT(String type, HtmlId id, String value) { + public static HtmlTree INPUT(String type, HtmlId id) { return new HtmlTree(TagName.INPUT) .put(HtmlAttr.TYPE, type) .setId(id) - .put(HtmlAttr.VALUE, value) - .put(HtmlAttr.DISABLED, "disabled"); + .put(HtmlAttr.DISABLED, ""); } /** diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/search.js.template b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/search.js.template index be45302b7e1..b5c92aefeb3 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/search.js.template +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/search.js.template @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -96,28 +96,16 @@ function createMatcher(pattern, flags) { var isCamelCase = /[A-Z]/.test(pattern); return new RegExp(pattern, flags + (isCamelCase ? "" : "i")); } -var watermark = 'Search'; $(function() { var search = $("#search-input"); var reset = $("#reset-button"); search.val(''); search.prop("disabled", false); reset.prop("disabled", false); - search.val(watermark).addClass('watermark'); - search.blur(function() { - if ($(this).val().length === 0) { - $(this).val(watermark).addClass('watermark'); - } - }); - search.on('click keydown paste', function() { - if ($(this).val() === watermark) { - $(this).val('').removeClass('watermark'); - } - }); reset.click(function() { search.val('').focus(); }); - search.focus()[0].setSelectionRange(0, 0); + search.focus(); }); $.widget("custom.catcomplete", $.ui.autocomplete, { _create: function() { diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets.properties b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets.properties index 579091028f8..3dc2ca72861 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets.properties +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets.properties @@ -223,6 +223,7 @@ doclet.Type=Type doclet.Modifier_and_Type=Modifier and Type doclet.Implementation=Implementation(s): doclet.search=SEARCH: +doclet.search_placeholder=Search doclet.Field=Field doclet.Property=Property doclet.Constructor=Constructor diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/stylesheet.css b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/stylesheet.css index 85058fc5457..3a986db7e68 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/stylesheet.css +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/stylesheet.css @@ -617,8 +617,9 @@ ul.ui-autocomplete li { top:10px; font-size:0; } -.watermark { - color:#545454; +::placeholder { + color:#909090; + opacity: 1; } .search-tag-desc-result { font-style:italic; diff --git a/test/langtools/jdk/javadoc/doclet/checkStylesheetClasses/CheckStylesheetClasses.java b/test/langtools/jdk/javadoc/doclet/checkStylesheetClasses/CheckStylesheetClasses.java index 53f65392ab5..1cc649b2c27 100644 --- a/test/langtools/jdk/javadoc/doclet/checkStylesheetClasses/CheckStylesheetClasses.java +++ b/test/langtools/jdk/javadoc/doclet/checkStylesheetClasses/CheckStylesheetClasses.java @@ -137,8 +137,7 @@ public class CheckStylesheetClasses { // used in search.js; may be worth documenting in HtmlStyle removeAll(styleSheetNames, "result-highlight", "result-item", "search-tag-desc-result", "search-tag-holder-result", - "ui-autocomplete", "ui-autocomplete-category", - "watermark", "expanded"); + "ui-autocomplete", "ui-autocomplete-category", "expanded"); // snippet-related removeAll(styleSheetNames, "bold", "highlighted", "italic"); diff --git a/test/langtools/jdk/javadoc/doclet/testSearch/TestSearch.java b/test/langtools/jdk/javadoc/doclet/testSearch/TestSearch.java index cdf575482c9..4b613263d21 100644 --- a/test/langtools/jdk/javadoc/doclet/testSearch/TestSearch.java +++ b/test/langtools/jdk/javadoc/doclet/testSearch/TestSearch.java @@ -421,8 +421,8 @@ public class TestSearch extends JavadocTester { "

    ", """ - - + + """); checkOutput(fileName, true, "
    "); @@ -710,12 +710,6 @@ public class TestSearch extends JavadocTester { checkOutput("search.js", true, "function searchIndexWithMatcher(indexArray, matcher, category, nameFunc) {", - """ - search.on('click keydown paste', function() { - if ($(this).val() === watermark) { - $(this).val('').removeClass('watermark'); - } - });""", """ function getURLPrefix(ui) { var urlPrefix=""; diff --git a/test/langtools/jdk/javadoc/doclet/testStylesheet/TestStylesheet.java b/test/langtools/jdk/javadoc/doclet/testStylesheet/TestStylesheet.java index 2af09148f0b..b8e10e32d8c 100644 --- a/test/langtools/jdk/javadoc/doclet/testStylesheet/TestStylesheet.java +++ b/test/langtools/jdk/javadoc/doclet/testStylesheet/TestStylesheet.java @@ -191,8 +191,9 @@ public class TestStylesheet extends JavadocTester { font-size:0; }""", """ - .watermark { - color:#545454; + ::placeholder { + color:#909090; + opacity: 1; }"""); checkOutput("pkg/A.html", true, -- GitLab From 9759fcb17b62d76d75b893481bbd4ef45e7ad366 Mon Sep 17 00:00:00 2001 From: Andrey Turbanov Date: Wed, 6 Oct 2021 10:50:38 +0000 Subject: [PATCH 114/385] 8274496: Use String.contains() instead of String.indexOf() in java.desktop Reviewed-by: pbansal, serb --- .../classes/javax/swing/text/html/CSS.java | 27 +++++++++---------- .../javax/swing/text/html/HTMLDocument.java | 4 +-- .../javax/swing/text/html/HTMLWriter.java | 12 ++++----- .../javax/swing/text/html/InlineView.java | 10 +++---- .../share/classes/sun/font/Font2D.java | 8 +++--- .../unix/classes/sun/awt/X11/XWM.java | 4 +-- .../unix/classes/sun/font/NativeFont.java | 14 +++++----- .../unix/classes/sun/font/XMap.java | 23 +++++++--------- .../classes/sun/print/IPPPrintService.java | 4 +-- .../sun/awt/windows/WDataTransferer.java | 4 +-- 10 files changed, 52 insertions(+), 58 deletions(-) diff --git a/src/java.desktop/share/classes/javax/swing/text/html/CSS.java b/src/java.desktop/share/classes/javax/swing/text/html/CSS.java index 150e24ca263..76ce4ac815f 100644 --- a/src/java.desktop/share/classes/javax/swing/text/html/CSS.java +++ b/src/java.desktop/share/classes/javax/swing/text/html/CSS.java @@ -38,7 +38,6 @@ import java.net.URL; import java.util.ArrayList; import java.util.Enumeration; import java.util.Hashtable; -import java.util.Vector; import javax.swing.ImageIcon; import javax.swing.SizeRequirements; @@ -891,8 +890,8 @@ public class CSS implements Serializable { (CSS.Attribute.VERTICAL_ALIGN); if ((vAlignV != null)) { String vAlign = vAlignV.toString(); - if ((vAlign.indexOf("sup") >= 0) || - (vAlign.indexOf("sub") >= 0)) { + if ((vAlign.contains("sup")) || + (vAlign.contains("sub"))) { size -= 2; } } @@ -908,7 +907,7 @@ public class CSS implements Serializable { style |= Font.BOLD; } Object fs = a.getAttribute(CSS.Attribute.FONT_STYLE); - if ((fs != null) && (fs.toString().indexOf("italic") >= 0)) { + if ((fs != null) && (fs.toString().contains("italic"))) { style |= Font.ITALIC; } if (family.equalsIgnoreCase("monospace")) { @@ -1965,12 +1964,12 @@ public class CSS implements Serializable { */ Object toStyleConstants(StyleConstants key, View v) { if (key == StyleConstants.Italic) { - if (svalue.indexOf("italic") >= 0) { + if (svalue.contains("italic")) { return Boolean.TRUE; } return Boolean.FALSE; } else if (key == StyleConstants.Underline) { - if (svalue.indexOf("underline") >= 0) { + if (svalue.contains("underline")) { return Boolean.TRUE; } return Boolean.FALSE; @@ -1984,17 +1983,17 @@ public class CSS implements Serializable { } return StyleConstants.ALIGN_LEFT; } else if (key == StyleConstants.StrikeThrough) { - if (svalue.indexOf("line-through") >= 0) { + if (svalue.contains("line-through")) { return Boolean.TRUE; } return Boolean.FALSE; } else if (key == StyleConstants.Superscript) { - if (svalue.indexOf("super") >= 0) { + if (svalue.contains("super")) { return Boolean.TRUE; } return Boolean.FALSE; } else if (key == StyleConstants.Subscript) { - if (svalue.indexOf("sub") >= 0) { + if (svalue.contains("sub")) { return Boolean.TRUE; } return Boolean.FALSE; @@ -2004,23 +2003,23 @@ public class CSS implements Serializable { // Used by ViewAttributeSet boolean isItalic() { - return (svalue.indexOf("italic") != -1); + return (svalue.contains("italic")); } boolean isStrike() { - return (svalue.indexOf("line-through") != -1); + return (svalue.contains("line-through")); } boolean isUnderline() { - return (svalue.indexOf("underline") != -1); + return (svalue.contains("underline")); } boolean isSub() { - return (svalue.indexOf("sub") != -1); + return (svalue.contains("sub")); } boolean isSup() { - return (svalue.indexOf("sup") != -1); + return (svalue.contains("sup")); } } diff --git a/src/java.desktop/share/classes/javax/swing/text/html/HTMLDocument.java b/src/java.desktop/share/classes/javax/swing/text/html/HTMLDocument.java index bf9ebcfe651..00272bc1eaa 100644 --- a/src/java.desktop/share/classes/javax/swing/text/html/HTMLDocument.java +++ b/src/java.desktop/share/classes/javax/swing/text/html/HTMLDocument.java @@ -3252,8 +3252,8 @@ public class HTMLDocument extends DefaultStyledDocument { } if (rel != null) { rel = rel.toLowerCase(); - if ((media.indexOf("all") != -1 || - media.indexOf("screen") != -1) && + if ((media.contains("all") || + media.contains("screen")) && (rel.equals("stylesheet") || (rel.equals("alternate stylesheet") && title.equals(defaultStyle)))) { diff --git a/src/java.desktop/share/classes/javax/swing/text/html/HTMLWriter.java b/src/java.desktop/share/classes/javax/swing/text/html/HTMLWriter.java index f8a9558505c..a166235d4c2 100644 --- a/src/java.desktop/share/classes/javax/swing/text/html/HTMLWriter.java +++ b/src/java.desktop/share/classes/javax/swing/text/html/HTMLWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1074,23 +1074,23 @@ public class HTMLWriter extends AbstractWriter { } } else if (key == CSS.Attribute.FONT_STYLE) { String s = from.getAttribute(key).toString(); - if (s.indexOf("italic") >= 0) { + if (s.contains("italic")) { addAttribute(to, HTML.Tag.I, SimpleAttributeSet.EMPTY); } } else if (key == CSS.Attribute.TEXT_DECORATION) { String decor = from.getAttribute(key).toString(); - if (decor.indexOf("underline") >= 0) { + if (decor.contains("underline")) { addAttribute(to, HTML.Tag.U, SimpleAttributeSet.EMPTY); } - if (decor.indexOf("line-through") >= 0) { + if (decor.contains("line-through")) { addAttribute(to, HTML.Tag.STRIKE, SimpleAttributeSet.EMPTY); } } else if (key == CSS.Attribute.VERTICAL_ALIGN) { String vAlign = from.getAttribute(key).toString(); - if (vAlign.indexOf("sup") >= 0) { + if (vAlign.contains("sup")) { addAttribute(to, HTML.Tag.SUP, SimpleAttributeSet.EMPTY); } - if (vAlign.indexOf("sub") >= 0) { + if (vAlign.contains("sub")) { addAttribute(to, HTML.Tag.SUB, SimpleAttributeSet.EMPTY); } } else if (key == CSS.Attribute.TEXT_ALIGN) { diff --git a/src/java.desktop/share/classes/javax/swing/text/html/InlineView.java b/src/java.desktop/share/classes/javax/swing/text/html/InlineView.java index c6fe5fe01fc..38975b3c686 100644 --- a/src/java.desktop/share/classes/javax/swing/text/html/InlineView.java +++ b/src/java.desktop/share/classes/javax/swing/text/html/InlineView.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -188,15 +188,15 @@ public class InlineView extends LabelView { AttributeSet a = getAttributes(); Object decor = a.getAttribute(CSS.Attribute.TEXT_DECORATION); boolean u = (decor != null) ? - (decor.toString().indexOf("underline") >= 0) : false; + (decor.toString().contains("underline")) : false; setUnderline(u); boolean s = (decor != null) ? - (decor.toString().indexOf("line-through") >= 0) : false; + (decor.toString().contains("line-through")) : false; setStrikeThrough(s); Object vAlign = a.getAttribute(CSS.Attribute.VERTICAL_ALIGN); - s = (vAlign != null) ? (vAlign.toString().indexOf("sup") >= 0) : false; + s = (vAlign != null) ? (vAlign.toString().contains("sup")) : false; setSuperscript(s); - s = (vAlign != null) ? (vAlign.toString().indexOf("sub") >= 0) : false; + s = (vAlign != null) ? (vAlign.toString().contains("sub")) : false; setSubscript(s); Object whitespace = a.getAttribute(CSS.Attribute.WHITE_SPACE); diff --git a/src/java.desktop/share/classes/sun/font/Font2D.java b/src/java.desktop/share/classes/sun/font/Font2D.java index 076455d7719..481416b5922 100644 --- a/src/java.desktop/share/classes/sun/font/Font2D.java +++ b/src/java.desktop/share/classes/sun/font/Font2D.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -153,21 +153,21 @@ public abstract class Font2D { String fName = fullName.toLowerCase(); for (int i=0; i < boldItalicNames.length; i++) { - if (fName.indexOf(boldItalicNames[i]) != -1) { + if (fName.contains(boldItalicNames[i])) { style = Font.BOLD|Font.ITALIC; return; } } for (int i=0; i < italicNames.length; i++) { - if (fName.indexOf(italicNames[i]) != -1) { + if (fName.contains(italicNames[i])) { style = Font.ITALIC; return; } } for (int i=0; i < boldNames.length; i++) { - if (fName.indexOf(boldNames[i]) != -1 ) { + if (fName.contains(boldNames[i])) { style = Font.BOLD; return; } diff --git a/src/java.desktop/unix/classes/sun/awt/X11/XWM.java b/src/java.desktop/unix/classes/sun/awt/X11/XWM.java index 409b12b1425..5bcb85eb5e3 100644 --- a/src/java.desktop/unix/classes/sun/awt/X11/XWM.java +++ b/src/java.desktop/unix/classes/sun/awt/X11/XWM.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -252,7 +252,7 @@ final class XWM * Quick checks for specific servers. */ String vendor_string = XlibWrapper.ServerVendor(XToolkit.getDisplay()); - if (vendor_string.indexOf("eXcursion") != -1) { + if (vendor_string.contains("eXcursion")) { /* * Use NO_WM since in all other aspects eXcursion is like not * having a window manager running. I.e. it does not reparent diff --git a/src/java.desktop/unix/classes/sun/font/NativeFont.java b/src/java.desktop/unix/classes/sun/font/NativeFont.java index 3bd212b2525..23bd76d0d48 100644 --- a/src/java.desktop/unix/classes/sun/font/NativeFont.java +++ b/src/java.desktop/unix/classes/sun/font/NativeFont.java @@ -133,14 +133,14 @@ public class NativeFont extends PhysicalFont { String styleStr = null; - if (tmpWeight.indexOf("bold") >= 0 || - tmpWeight.indexOf("demi") >= 0) { + if (tmpWeight.contains("bold") || + tmpWeight.contains("demi")) { style |= Font.BOLD; styleStr = "Bold"; } if (tmpSlant.equals("i") || - tmpSlant.indexOf("italic") >= 0) { + tmpSlant.contains("italic")) { style |= Font.ITALIC; if (styleStr == null) { @@ -150,7 +150,7 @@ public class NativeFont extends PhysicalFont { } } else if (tmpSlant.equals("o") || - tmpSlant.indexOf("oblique") >= 0) { + tmpSlant.contains("oblique")) { style |= Font.ITALIC; if (styleStr == null) { styleStr = "Oblique"; @@ -169,10 +169,10 @@ public class NativeFont extends PhysicalFont { if (encoding.startsWith("-")) { encoding = xlfd.substring(hPos[13]+1); } - if (encoding.indexOf("fontspecific") >= 0) { - if (tmpFamily.indexOf("dingbats") >= 0) { + if (encoding.contains("fontspecific")) { + if (tmpFamily.contains("dingbats")) { encoding = "dingbats"; - } else if (tmpFamily.indexOf("symbol") >= 0) { + } else if (tmpFamily.contains("symbol")) { encoding = "symbol"; } else { encoding = "iso8859-1"; diff --git a/src/java.desktop/unix/classes/sun/font/XMap.java b/src/java.desktop/unix/classes/sun/font/XMap.java index b2ace270b68..48bb6a40403 100644 --- a/src/java.desktop/unix/classes/sun/font/XMap.java +++ b/src/java.desktop/unix/classes/sun/font/XMap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,12 +25,7 @@ package sun.font; -import java.awt.FontFormatException; -import java.awt.font.FontRenderContext; -import java.awt.geom.GeneralPath; -import java.awt.geom.Rectangle2D; import java.util.HashMap; -import java.util.Locale; import java.nio.charset.*; import java.nio.CharBuffer; import java.nio.ByteBuffer; @@ -119,13 +114,13 @@ class XMap { } else if (encoding.equals("ksc5601.1987-0")) { jclass ="sun.font.X11KSC5601"; nBytes = DOUBLE_BYTE; - } else if (encoding.equals( "ksc5601.1992-3")) { + } else if (encoding.equals("ksc5601.1992-3")) { jclass ="sun.font.X11Johab"; nBytes = DOUBLE_BYTE; - } else if (encoding.equals( "ksc5601.1987-1")) { + } else if (encoding.equals("ksc5601.1987-1")) { jclass ="EUC_KR"; nBytes = DOUBLE_BYTE; - } else if (encoding.equals( "cns11643-1")) { + } else if (encoding.equals("cns11643-1")) { jclass = "sun.font.X11CNS11643P1"; nBytes = DOUBLE_BYTE; } else if (encoding.equals("cns11643-2")) { @@ -137,7 +132,7 @@ class XMap { } else if (encoding.equals("gb2312.1980-0")) { jclass = "sun.font.X11GB2312"; nBytes = DOUBLE_BYTE; - } else if (encoding.indexOf("big5") >= 0) { + } else if (encoding.contains("big5")) { jclass = "Big5"; nBytes = DOUBLE_BYTE; addAscii = true; @@ -146,16 +141,16 @@ class XMap { } else if (encoding.equals("gbk-0")) { jclass = "sun.font.X11GBK"; nBytes = DOUBLE_BYTE; - } else if (encoding.indexOf("sun.unicode-0") >= 0) { + } else if (encoding.contains("sun.unicode-0")) { jclass = "sun.font.X11SunUnicode_0"; nBytes = DOUBLE_BYTE; - } else if (encoding.indexOf("gb18030.2000-1") >= 0) { + } else if (encoding.contains("gb18030.2000-1")) { jclass = "sun.font.X11GB18030_1"; nBytes = DOUBLE_BYTE; - } else if (encoding.indexOf( "gb18030.2000-0") >= 0) { + } else if (encoding.contains("gb18030.2000-0")) { jclass = "sun.font.X11GB18030_0"; nBytes = DOUBLE_BYTE; - } else if (encoding.indexOf("hkscs") >= 0) { + } else if (encoding.contains("hkscs")) { jclass = "MS950_HKSCS_XP"; nBytes = DOUBLE_BYTE; } diff --git a/src/java.desktop/unix/classes/sun/print/IPPPrintService.java b/src/java.desktop/unix/classes/sun/print/IPPPrintService.java index 7ef37b116ab..2bb401698da 100644 --- a/src/java.desktop/unix/classes/sun/print/IPPPrintService.java +++ b/src/java.desktop/unix/classes/sun/print/IPPPrintService.java @@ -927,7 +927,7 @@ public class IPPPrintService implements PrintService, SunPrinterJobService { gifImagesAdded = true; } else if (mimeType.equals("image/jpeg")) { jpgImagesAdded = true; - } else if (mimeType.indexOf("postscript") != -1) { + } else if (mimeType.contains("postscript")) { psSupported = true; } break; @@ -1555,7 +1555,7 @@ public class IPPPrintService implements PrintService, SunPrinterJobService { return mediaSizeNames[defaultMediaIndex]; } else { for (int i=0; i< mediaSizeNames.length; i++) { - if (mediaSizeNames[i].toString().indexOf(name) != -1) { + if (mediaSizeNames[i].toString().contains(name)) { defaultMediaIndex = i; return mediaSizeNames[defaultMediaIndex]; } diff --git a/src/java.desktop/windows/classes/sun/awt/windows/WDataTransferer.java b/src/java.desktop/windows/classes/sun/awt/windows/WDataTransferer.java index c82fc91a4e1..6273cb2c22d 100644 --- a/src/java.desktop/windows/classes/sun/awt/windows/WDataTransferer.java +++ b/src/java.desktop/windows/classes/sun/awt/windows/WDataTransferer.java @@ -606,10 +606,10 @@ class HTMLCodec extends InputStream { //to avoid HTML and BODY tags doubling String stContext = new String(bytes); String stUpContext = stContext.toUpperCase(); - if( -1 == stUpContext.indexOf(""; htmlSuffix = "" + htmlSuffix; }; -- GitLab From c80a612709f1e483575e2843c1f0ea84e1b9a257 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Wed, 6 Oct 2021 11:14:26 +0000 Subject: [PATCH 115/385] 8273381: Assert in PtrQueueBufferAllocatorTest.stress_free_list_allocator_vm Reviewed-by: sjohanss, tschatzl --- .../gtest/gc/shared/test_ptrQueueBufferAllocator.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/test/hotspot/gtest/gc/shared/test_ptrQueueBufferAllocator.cpp b/test/hotspot/gtest/gc/shared/test_ptrQueueBufferAllocator.cpp index 1335954de2a..978dd1e6f8c 100644 --- a/test/hotspot/gtest/gc/shared/test_ptrQueueBufferAllocator.cpp +++ b/test/hotspot/gtest/gc/shared/test_ptrQueueBufferAllocator.cpp @@ -180,12 +180,18 @@ public: {} virtual void main_run() { + bool shutdown_requested = false; while (true) { BufferNode* node = _cbl->pop(); if (node != NULL) { _allocator->release(node); - } else if (!Atomic::load_acquire(_continue_running)) { + } else if (shutdown_requested) { return; + } else if (!Atomic::load_acquire(_continue_running)) { + // To avoid a race that could leave buffers in the list after this + // thread has shut down, continue processing until the list is empty + // *after* the shut down request has been received. + shutdown_requested = true; } ThreadBlockInVM tbiv(this); // Safepoint check. } -- GitLab From b8af6a9bfb28aaf0fea0cfdaba13236dc8cbaa3a Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Wed, 6 Oct 2021 12:14:33 +0000 Subject: [PATCH 116/385] 8273917: Remove 'leaf' ranking for Mutex Reviewed-by: eosterlund, dholmes --- src/hotspot/share/compiler/compileTask.hpp | 2 +- src/hotspot/share/gc/shared/space.cpp | 2 +- .../gc/shenandoah/shenandoahControlThread.cpp | 4 +- .../share/gc/shenandoah/shenandoahPacer.hpp | 2 +- src/hotspot/share/oops/methodData.cpp | 3 +- src/hotspot/share/runtime/mutex.cpp | 4 +- src/hotspot/share/runtime/mutex.hpp | 6 +- src/hotspot/share/runtime/mutexLocker.cpp | 137 +++++++++++------- src/hotspot/share/services/heapDumper.cpp | 4 +- test/hotspot/gtest/runtime/test_mutex.cpp | 38 ++--- .../gtest/runtime/test_safepoint_locks.cpp | 2 +- 11 files changed, 117 insertions(+), 87 deletions(-) diff --git a/src/hotspot/share/compiler/compileTask.hpp b/src/hotspot/share/compiler/compileTask.hpp index 812c3ae9fb0..3a48aed5b1d 100644 --- a/src/hotspot/share/compiler/compileTask.hpp +++ b/src/hotspot/share/compiler/compileTask.hpp @@ -104,7 +104,7 @@ class CompileTask : public CHeapObj { public: CompileTask() : _failure_reason(NULL), _failure_reason_on_C_heap(false) { - _lock = new Monitor(Mutex::nonleaf+2, "CompileTaskLock", Mutex::_safepoint_check_always); + _lock = new Monitor(Mutex::nonleaf, "CompileTask_lock", Mutex::_safepoint_check_always); } void initialize(int compile_id, const methodHandle& method, int osr_bci, int comp_level, diff --git a/src/hotspot/share/gc/shared/space.cpp b/src/hotspot/share/gc/shared/space.cpp index 29ee0bc0b48..3c5d17cabc3 100644 --- a/src/hotspot/share/gc/shared/space.cpp +++ b/src/hotspot/share/gc/shared/space.cpp @@ -773,7 +773,7 @@ void OffsetTableContigSpace::alloc_block(HeapWord* start, HeapWord* end) { OffsetTableContigSpace::OffsetTableContigSpace(BlockOffsetSharedArray* sharedOffsetArray, MemRegion mr) : _offsets(sharedOffsetArray, mr), - _par_alloc_lock(Mutex::leaf, "OffsetTableContigSpace par alloc lock", + _par_alloc_lock(Mutex::nonleaf, "OffsetTableContigSpaceParAlloc_lock", Mutex::_safepoint_check_always, true) { _offsets.set_contig_space(this); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp index 97f1bfde249..e32ca50a21e 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp @@ -47,8 +47,8 @@ ShenandoahControlThread::ShenandoahControlThread() : ConcurrentGCThread(), - _alloc_failure_waiters_lock(Mutex::leaf, "ShenandoahAllocFailureGC_lock", Monitor::_safepoint_check_always, true), - _gc_waiters_lock(Mutex::leaf, "ShenandoahRequestedGC_lock", Monitor::_safepoint_check_always, true), + _alloc_failure_waiters_lock(Mutex::nonleaf, "ShenandoahAllocFailureGC_lock", Monitor::_safepoint_check_always, true), + _gc_waiters_lock(Mutex::nonleaf, "ShenandoahRequestedGC_lock", Monitor::_safepoint_check_always, true), _periodic_task(this), _requested_gc_cause(GCCause::_no_cause_specified), _degen_point(ShenandoahGC::_degenerated_outside_cycle), diff --git a/src/hotspot/share/gc/shenandoah/shenandoahPacer.hpp b/src/hotspot/share/gc/shenandoah/shenandoahPacer.hpp index a42c8d0bbcd..f716bafddbf 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahPacer.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahPacer.hpp @@ -67,7 +67,7 @@ public: _heap(heap), _last_time(os::elapsedTime()), _progress_history(new TruncatedSeq(5)), - _wait_monitor(new Monitor(Mutex::leaf, "_wait_monitor", Monitor::_safepoint_check_always, true)), + _wait_monitor(new Monitor(Mutex::nonleaf-1, "ShenandoahWaitMonitor_lock", Monitor::_safepoint_check_always, true)), _epoch(0), _tax_rate(1), _budget(0), diff --git a/src/hotspot/share/oops/methodData.cpp b/src/hotspot/share/oops/methodData.cpp index 69f7ae1b85d..3f8dd5cd243 100644 --- a/src/hotspot/share/oops/methodData.cpp +++ b/src/hotspot/share/oops/methodData.cpp @@ -1206,7 +1206,8 @@ void MethodData::post_initialize(BytecodeStream* stream) { // Initialize the MethodData* corresponding to a given method. MethodData::MethodData(const methodHandle& method) : _method(method()), - _extra_data_lock(Mutex::leaf, "MDO extra data lock", Mutex::_safepoint_check_always), + // Holds Compile_lock + _extra_data_lock(Mutex::nonleaf-2, "MDOExtraData_lock", Mutex::_safepoint_check_always), _compiler_counters(), _parameters_type_data_di(parameters_uninitialized) { initialize(); diff --git a/src/hotspot/share/runtime/mutex.cpp b/src/hotspot/share/runtime/mutex.cpp index 08af284127f..2ef595a83c6 100644 --- a/src/hotspot/share/runtime/mutex.cpp +++ b/src/hotspot/share/runtime/mutex.cpp @@ -285,6 +285,8 @@ Mutex::Mutex(int Rank, const char * name, SafepointCheckRequired safepoint_check _safepoint_check_required = safepoint_check_required; _skip_rank_check = false; + assert(_rank >= 0 && _rank <= nonleaf, "Bad lock rank %d: %s", _rank, name); + assert(_rank > nosafepoint || _safepoint_check_required == _safepoint_check_never, "Locks below nosafepoint rank should never safepoint: %s", name); @@ -295,8 +297,6 @@ Mutex::Mutex(int Rank, const char * name, SafepointCheckRequired safepoint_check // allowing Java threads to block in native. assert(_safepoint_check_required == _safepoint_check_always || _allow_vm_block, "Safepoint check never locks should always allow the vm to block: %s", name); - - assert(_rank >= 0, "Bad lock rank: %s", name); #endif } diff --git a/src/hotspot/share/runtime/mutex.hpp b/src/hotspot/share/runtime/mutex.hpp index cb98d42655c..b045a02392b 100644 --- a/src/hotspot/share/runtime/mutex.hpp +++ b/src/hotspot/share/runtime/mutex.hpp @@ -53,10 +53,8 @@ class Mutex : public CHeapObj { tty = stackwatermark + 3, oopstorage = tty + 3, nosafepoint = oopstorage + 6, - leaf = nosafepoint + 6, - barrier = leaf + 10, - nonleaf = barrier + 1, - max_nonleaf = nonleaf + 900 + nonleaf = nosafepoint + 20, + max_nonleaf = nonleaf }; private: diff --git a/src/hotspot/share/runtime/mutexLocker.cpp b/src/hotspot/share/runtime/mutexLocker.cpp index f93a7ecbce1..d84de912b7a 100644 --- a/src/hotspot/share/runtime/mutexLocker.cpp +++ b/src/hotspot/share/runtime/mutexLocker.cpp @@ -194,11 +194,28 @@ void assert_locked_or_safepoint_or_handshake(const Mutex* lock, const JavaThread } #endif +static void add_mutex(Mutex* var) { + assert(_num_mutex < MAX_NUM_MUTEX, "increase MAX_NUM_MUTEX"); + _mutex_array[_num_mutex++] = var; +} + #define def(var, type, pri, vm_block, safepoint_check_allowed ) { \ var = new type(Mutex::pri, #var, Mutex::safepoint_check_allowed, vm_block); \ - assert(_num_mutex < MAX_NUM_MUTEX, "increase MAX_NUM_MUTEX"); \ - _mutex_array[_num_mutex++] = var; \ + add_mutex(var); \ +} + +// Specify relative ranked lock +#ifdef ASSERT +#define defl(var, type, held_lock, vm_block, safepoint_check_allowed) { \ + var = new type(held_lock->rank()-1, #var, Mutex::safepoint_check_allowed, vm_block); \ + add_mutex(var); \ +} +#else +#define defl(var, type, held_lock, vm_block, safepoint_check_allowed) { \ + var = new type(Mutex::nonleaf, #var, Mutex::safepoint_check_allowed, vm_block); \ + add_mutex(var); \ } +#endif // Using Padded subclasses to prevent false sharing of these global monitors and mutexes. void mutex_init() { @@ -208,7 +225,6 @@ void mutex_init() { if (UseG1GC) { def(CGC_lock , PaddedMonitor, nosafepoint, true, _safepoint_check_never); - def(G1OldGCCount_lock , PaddedMonitor, leaf, true, _safepoint_check_always); def(G1DetachedRefinementStats_lock, PaddedMutex, nosafepoint-2, true, _safepoint_check_never); @@ -224,17 +240,12 @@ void mutex_init() { } def(StringDedup_lock , PaddedMonitor, nosafepoint, true, _safepoint_check_never); def(StringDedupIntern_lock , PaddedMutex , nosafepoint, true, _safepoint_check_never); - def(ParGCRareEvent_lock , PaddedMutex , leaf, true, _safepoint_check_always); - def(CodeCache_lock , PaddedMonitor, nosafepoint-3, true, _safepoint_check_never); - def(CodeSweeper_lock , PaddedMonitor, nosafepoint-5, true, _safepoint_check_never); + def(ParGCRareEvent_lock , PaddedMutex , nonleaf, true, _safepoint_check_always); def(RawMonitor_lock , PaddedMutex , nosafepoint-1, true, _safepoint_check_never); - def(OopMapCacheAlloc_lock , PaddedMutex , leaf, true, _safepoint_check_always); // used for oop_map_cache allocation. def(Metaspace_lock , PaddedMutex , nosafepoint-3, true, _safepoint_check_never); - def(ClassLoaderDataGraph_lock , PaddedMutex , nonleaf, false, _safepoint_check_always); def(Patching_lock , PaddedMutex , nosafepoint, true, _safepoint_check_never); // used for safepointing and code patching. - def(CompiledMethod_lock , PaddedMutex , nosafepoint-4, true, _safepoint_check_never); def(MonitorDeflation_lock , PaddedMonitor, nosafepoint, true, _safepoint_check_never); // used for monitor deflation thread operations def(Service_lock , PaddedMonitor, service, true, _safepoint_check_never); // used for service thread operations @@ -246,68 +257,54 @@ void mutex_init() { def(JmethodIdCreation_lock , PaddedMutex , nosafepoint-2, true, _safepoint_check_never); // used for creating jmethodIDs. - def(SystemDictionary_lock , PaddedMonitor, leaf, true, _safepoint_check_always); - def(SharedDictionary_lock , PaddedMutex , leaf, true, _safepoint_check_always); - def(ClassInitError_lock , PaddedMonitor, leaf+1, true, _safepoint_check_always); - def(Module_lock , PaddedMutex , leaf+2, false, _safepoint_check_always); - def(InlineCacheBuffer_lock , PaddedMutex , nosafepoint-1, true, _safepoint_check_never); - def(VMStatistic_lock , PaddedMutex , leaf, false, _safepoint_check_always); - def(ExpandHeap_lock , PaddedMutex , leaf, true, _safepoint_check_always); // Used during compilation by VM thread - def(JNIHandleBlockFreeList_lock , PaddedMutex , nosafepoint-1, true, _safepoint_check_never); // handles are used by VM thread - def(SignatureHandlerLibrary_lock , PaddedMutex , leaf, false, _safepoint_check_always); - def(SymbolArena_lock , PaddedMutex , nosafepoint, true, _safepoint_check_never); - def(ExceptionCache_lock , PaddedMutex , leaf, false, _safepoint_check_always); + def(SharedDictionary_lock , PaddedMutex , nonleaf, true, _safepoint_check_always); + def(VMStatistic_lock , PaddedMutex , nonleaf, false, _safepoint_check_always); + def(JNIHandleBlockFreeList_lock , PaddedMutex , nosafepoint-1, true, _safepoint_check_never); // handles are used by VM thread + def(SignatureHandlerLibrary_lock , PaddedMutex , nonleaf, false, _safepoint_check_always); + def(SymbolArena_lock , PaddedMutex , nosafepoint, true, _safepoint_check_never); + def(ExceptionCache_lock , PaddedMutex , nonleaf, false, _safepoint_check_always); #ifndef PRODUCT - def(FullGCALot_lock , PaddedMutex , leaf, false, _safepoint_check_always); // a lock to make FullGCALot MT safe + def(FullGCALot_lock , PaddedMutex , nonleaf, false, _safepoint_check_always); // a lock to make FullGCALot MT safe #endif - def(BeforeExit_lock , PaddedMonitor, leaf, true, _safepoint_check_always); - def(PerfDataMemAlloc_lock , PaddedMutex , leaf, true, _safepoint_check_always); // used for allocating PerfData memory for performance data - def(PerfDataManager_lock , PaddedMutex , leaf, true, _safepoint_check_always); // used for synchronized access to PerfDataManager resources + def(BeforeExit_lock , PaddedMonitor, nonleaf, true, _safepoint_check_always); - def(Threads_lock , PaddedMonitor, barrier, true, _safepoint_check_always); // Used for safepoint protocol. def(NonJavaThreadsList_lock , PaddedMutex, nosafepoint-1, true, _safepoint_check_never); def(NonJavaThreadsListSync_lock , PaddedMutex, nosafepoint, true, _safepoint_check_never); - def(VMOperation_lock , PaddedMonitor, nonleaf, true, _safepoint_check_always); // VM_thread allowed to block on these def(RetData_lock , PaddedMutex , nonleaf, false, _safepoint_check_always); def(Terminator_lock , PaddedMonitor, nonleaf, true, _safepoint_check_always); def(InitCompleted_lock , PaddedMonitor, nosafepoint, true, _safepoint_check_never); - def(VtableStubs_lock , PaddedMutex , nosafepoint-2, true, _safepoint_check_never); def(Notify_lock , PaddedMonitor, nonleaf, true, _safepoint_check_always); def(JNICritical_lock , PaddedMonitor, nonleaf, true, _safepoint_check_always); // used for JNI critical regions def(AdapterHandlerLibrary_lock , PaddedMutex , nonleaf, true, _safepoint_check_always); - def(Heap_lock , PaddedMonitor, nonleaf+1, false, _safepoint_check_always); // Doesn't safepoint check during termination. - def(JfieldIdCreation_lock , PaddedMutex , nonleaf+1, true, _safepoint_check_always); // jfieldID, Used in VM_Operation + def(Heap_lock , PaddedMonitor, nonleaf, false, _safepoint_check_always); // Doesn't safepoint check during termination. + def(JfieldIdCreation_lock , PaddedMutex , nonleaf, true, _safepoint_check_always); // jfieldID, Used in VM_Operation def(CompiledIC_lock , PaddedMutex , nosafepoint, true, _safepoint_check_never); // locks VtableStubs_lock, InlineCacheBuffer_lock - def(CompileTaskAlloc_lock , PaddedMutex , nonleaf+2, true, _safepoint_check_always); - def(CompileStatistics_lock , PaddedMutex , nonleaf+2, false, _safepoint_check_always); - def(DirectivesStack_lock , PaddedMutex , nosafepoint, true, _safepoint_check_never); - def(MultiArray_lock , PaddedMutex , nonleaf+2, false, _safepoint_check_always); + def(MethodCompileQueue_lock , PaddedMonitor, nonleaf, false, _safepoint_check_always); + def(CompileStatistics_lock , PaddedMutex , nonleaf, false, _safepoint_check_always); + def(DirectivesStack_lock , PaddedMutex , nosafepoint, true, _safepoint_check_never); + def(MultiArray_lock , PaddedMutex , nonleaf, false, _safepoint_check_always); - def(JvmtiThreadState_lock , PaddedMutex , nonleaf+2, false, _safepoint_check_always); // Used by JvmtiThreadState/JvmtiEventController + def(JvmtiThreadState_lock , PaddedMutex , nonleaf, false, _safepoint_check_always); // Used by JvmtiThreadState/JvmtiEventController def(EscapeBarrier_lock , PaddedMonitor, nosafepoint, true, _safepoint_check_never); // Used to synchronize object reallocation/relocking triggered by JVMTI - def(Management_lock , PaddedMutex , nonleaf+2, false, _safepoint_check_always); // used for JVM management + def(Management_lock , PaddedMutex , nonleaf, false, _safepoint_check_always); // used for JVM management def(ConcurrentGCBreakpoints_lock , PaddedMonitor, nonleaf, true, _safepoint_check_always); - def(Compile_lock , PaddedMutex , nonleaf+3, false, _safepoint_check_always); - def(MethodData_lock , PaddedMutex , nonleaf+3, false, _safepoint_check_always); - def(TouchedMethodLog_lock , PaddedMutex , nonleaf+3, false, _safepoint_check_always); + def(MethodData_lock , PaddedMutex , nonleaf, false, _safepoint_check_always); + def(TouchedMethodLog_lock , PaddedMutex , nonleaf, false, _safepoint_check_always); - def(MethodCompileQueue_lock , PaddedMonitor, nonleaf+4, false, _safepoint_check_always); - def(CompileThread_lock , PaddedMonitor, nonleaf+5, false, _safepoint_check_always); - def(PeriodicTask_lock , PaddedMonitor, nonleaf+5, true, _safepoint_check_always); - def(RedefineClasses_lock , PaddedMonitor, nonleaf+5, true, _safepoint_check_always); - def(Verify_lock , PaddedMutex, nonleaf+5, true, _safepoint_check_always); - def(Zip_lock , PaddedMonitor, nosafepoint-2, true, _safepoint_check_never); + def(CompileThread_lock , PaddedMonitor, nonleaf, false, _safepoint_check_always); + def(PeriodicTask_lock , PaddedMonitor, nonleaf, true, _safepoint_check_always); + def(RedefineClasses_lock , PaddedMonitor, nonleaf, true, _safepoint_check_always); + def(Verify_lock , PaddedMutex, nonleaf, true, _safepoint_check_always); if (WhiteBoxAPI) { def(Compilation_lock , PaddedMonitor, nosafepoint, true, _safepoint_check_never); } #if INCLUDE_JFR - def(JfrMsg_lock , PaddedMonitor, leaf, true, _safepoint_check_always); def(JfrBuffer_lock , PaddedMutex , nosafepoint, true, _safepoint_check_never); def(JfrStacktrace_lock , PaddedMutex , stackwatermark-1, true, _safepoint_check_never); def(JfrThreadSampler_lock , PaddedMonitor, nosafepoint, true, _safepoint_check_never); @@ -317,29 +314,61 @@ void mutex_init() { def(UnsafeJlong_lock , PaddedMutex , nosafepoint, true, _safepoint_check_never); #endif - def(CodeHeapStateAnalytics_lock , PaddedMutex , nonleaf+6, false, _safepoint_check_always); + def(CodeHeapStateAnalytics_lock , PaddedMutex , nonleaf, false, _safepoint_check_always); def(NMethodSweeperStats_lock , PaddedMutex , nosafepoint, true, _safepoint_check_never); def(ThreadsSMRDelete_lock , PaddedMonitor, nosafepoint-3, true, _safepoint_check_never); // Holds ConcurrentHashTableResize_lock - def(ThreadIdTableCreate_lock , PaddedMutex , leaf, false, _safepoint_check_always); - def(SharedDecoder_lock , PaddedMutex , tty-1, true, _safepoint_check_never); - def(DCmdFactory_lock , PaddedMutex , nosafepoint, true, _safepoint_check_never); + def(ThreadIdTableCreate_lock , PaddedMutex , nonleaf, false, _safepoint_check_always); + def(SharedDecoder_lock , PaddedMutex , tty-1, true, _safepoint_check_never); + def(DCmdFactory_lock , PaddedMutex , nosafepoint, true, _safepoint_check_never); #if INCLUDE_NMT - def(NMTQuery_lock , PaddedMutex , max_nonleaf, false, _safepoint_check_always); + def(NMTQuery_lock , PaddedMutex , nonleaf, false, _safepoint_check_always); #endif #if INCLUDE_CDS #if INCLUDE_JVMTI - def(CDSClassFileStream_lock , PaddedMutex , max_nonleaf, false, _safepoint_check_always); + def(CDSClassFileStream_lock , PaddedMutex , nonleaf, false, _safepoint_check_always); #endif - def(DumpTimeTable_lock , PaddedMutex , nosafepoint-1, true, _safepoint_check_never); + def(DumpTimeTable_lock , PaddedMutex , nosafepoint, true, _safepoint_check_never); def(CDSLambda_lock , PaddedMutex , nosafepoint, true, _safepoint_check_never); def(DumpRegion_lock , PaddedMutex , nosafepoint, true, _safepoint_check_never); def(ClassListFile_lock , PaddedMutex , nosafepoint, true, _safepoint_check_never); - def(LambdaFormInvokers_lock , PaddedMutex , nonleaf+2, false, _safepoint_check_always); + def(LambdaFormInvokers_lock , PaddedMutex , nonleaf, false, _safepoint_check_always); #endif // INCLUDE_CDS def(Bootclasspath_lock , PaddedMutex , nosafepoint, true, _safepoint_check_never); + def(Zip_lock , PaddedMonitor, nosafepoint-1, true, _safepoint_check_never); // Holds DumpTimeTable_lock #if INCLUDE_JVMCI - def(JVMCI_lock , PaddedMonitor, nonleaf+2, true, _safepoint_check_always); + def(JVMCI_lock , PaddedMonitor, nonleaf, true, _safepoint_check_always); +#endif + + // These locks have safepoint_check_never and relative rankings. + defl(InlineCacheBuffer_lock , PaddedMutex , CompiledIC_lock, true, _safepoint_check_never); + defl(VtableStubs_lock , PaddedMutex , CompiledIC_lock, true, _safepoint_check_never); // Also holds DumpTimeTable_lock + defl(CodeCache_lock , PaddedMonitor, VtableStubs_lock, true, _safepoint_check_never); + defl(CompiledMethod_lock , PaddedMutex , CodeCache_lock, true, _safepoint_check_never); + defl(CodeSweeper_lock , PaddedMonitor, CompiledMethod_lock, true, _safepoint_check_never); + + // These locks have safepoint_check_always and relative rankings. + defl(Threads_lock , PaddedMonitor, CompileThread_lock, true, _safepoint_check_always); + defl(Heap_lock , PaddedMonitor, MultiArray_lock, false, _safepoint_check_always); + defl(Compile_lock , PaddedMutex , MethodCompileQueue_lock, false, _safepoint_check_always); + + defl(PerfDataMemAlloc_lock , PaddedMutex , Heap_lock, true, _safepoint_check_always); + defl(PerfDataManager_lock , PaddedMutex , Heap_lock, true, _safepoint_check_always); + defl(ClassLoaderDataGraph_lock , PaddedMutex , MultiArray_lock, false, _safepoint_check_always); + defl(VMOperation_lock , PaddedMonitor, Compile_lock, true, _safepoint_check_always); + defl(ClassInitError_lock , PaddedMonitor, Threads_lock, true, _safepoint_check_always); + + if (UseG1GC) { + defl(G1OldGCCount_lock , PaddedMonitor, Threads_lock, true, _safepoint_check_always); + } + defl(CompileTaskAlloc_lock , PaddedMutex , MethodCompileQueue_lock, true, _safepoint_check_always); + defl(ExpandHeap_lock , PaddedMutex , Heap_lock, true, _safepoint_check_always); + defl(OopMapCacheAlloc_lock , PaddedMutex , Threads_lock, true, _safepoint_check_always); + defl(Module_lock , PaddedMutex , ClassLoaderDataGraph_lock, false, _safepoint_check_always); + defl(SystemDictionary_lock , PaddedMonitor, Module_lock, true, _safepoint_check_always); + +#if INCLUDE_JFR + defl(JfrMsg_lock , PaddedMonitor, Module_lock, true, _safepoint_check_always); #endif } diff --git a/src/hotspot/share/services/heapDumper.cpp b/src/hotspot/share/services/heapDumper.cpp index 14fe68acd8a..b46a27b1673 100644 --- a/src/hotspot/share/services/heapDumper.cpp +++ b/src/hotspot/share/services/heapDumper.cpp @@ -748,7 +748,7 @@ class ParDumpWriter : public AbstractDumpWriter { static void before_work() { assert(_lock == NULL, "ParDumpWriter lock must be initialized only once"); - _lock = new (std::nothrow) PaddedMonitor(Mutex::leaf, "ParallelHProfWriter_lock", Mutex::_safepoint_check_always); + _lock = new (std::nothrow) PaddedMonitor(Mutex::nonleaf, "ParallelHProfWriter_lock", Mutex::_safepoint_check_always); } static void after_work() { @@ -1814,7 +1814,7 @@ class DumperController : public CHeapObj { public: DumperController(uint number) : _started(false), - _lock(new (std::nothrow) PaddedMonitor(Mutex::leaf, "DumperController_lock", + _lock(new (std::nothrow) PaddedMonitor(Mutex::nonleaf, "DumperController_lock", Mutex::_safepoint_check_always)), _dumper_number(number), _complete_number(0) { } diff --git a/test/hotspot/gtest/runtime/test_mutex.cpp b/test/hotspot/gtest/runtime/test_mutex.cpp index 47df5f1dcad..ee7bc392123 100644 --- a/test/hotspot/gtest/runtime/test_mutex.cpp +++ b/test/hotspot/gtest/runtime/test_mutex.cpp @@ -53,14 +53,16 @@ TEST_VM(MutexName, mutex_name) { #ifdef ASSERT -const int rankA = 50; +const int rankA = Mutex::nonleaf-5; +const int rankAplusOne = Mutex::nonleaf-4; +const int rankAplusTwo = Mutex::nonleaf-3; TEST_OTHER_VM(MutexRank, mutex_lock_rank_in_order) { JavaThread* THREAD = JavaThread::current(); ThreadInVMfromNative invm(THREAD); Mutex* mutex_rankA = new Mutex(rankA, "mutex_rankA", Mutex::_safepoint_check_always); - Mutex* mutex_rankA_plus_one = new Mutex(rankA + 1, "mutex_rankA_plus_one", Mutex::_safepoint_check_always); + Mutex* mutex_rankA_plus_one = new Mutex(rankAplusOne, "mutex_rankA_plus_one", Mutex::_safepoint_check_always); mutex_rankA_plus_one->lock(); mutex_rankA->lock(); @@ -69,12 +71,12 @@ TEST_OTHER_VM(MutexRank, mutex_lock_rank_in_order) { } TEST_VM_ASSERT_MSG(MutexRank, mutex_lock_rank_out_of_orderA, - ".* Attempting to acquire lock mutex_rankA_plus_one/51 out of order with lock mutex_rankA/50 -- possible deadlock") { + ".* Attempting to acquire lock mutex_rankA_plus_one/.* out of order with lock mutex_rankA/.* -- possible deadlock") { JavaThread* THREAD = JavaThread::current(); ThreadInVMfromNative invm(THREAD); Mutex* mutex_rankA = new Mutex(rankA, "mutex_rankA", Mutex::_safepoint_check_always); - Mutex* mutex_rankA_plus_one = new Mutex(rankA + 1, "mutex_rankA_plus_one", Mutex::_safepoint_check_always); + Mutex* mutex_rankA_plus_one = new Mutex(rankAplusOne, "mutex_rankA_plus_one", Mutex::_safepoint_check_always); mutex_rankA->lock(); mutex_rankA_plus_one->lock(); @@ -83,7 +85,7 @@ TEST_VM_ASSERT_MSG(MutexRank, mutex_lock_rank_out_of_orderA, } TEST_VM_ASSERT_MSG(MutexRank, mutex_lock_rank_out_of_orderB, - ".* Attempting to acquire lock mutex_rankB/50 out of order with lock mutex_rankA/50 -- possible deadlock") { + ".* Attempting to acquire lock mutex_rankB/.* out of order with lock mutex_rankA/.* -- possible deadlock") { JavaThread* THREAD = JavaThread::current(); ThreadInVMfromNative invm(THREAD); @@ -101,8 +103,8 @@ TEST_OTHER_VM(MutexRank, mutex_trylock_rank_out_of_orderA) { ThreadInVMfromNative invm(THREAD); Mutex* mutex_rankA = new Mutex(rankA, "mutex_rankA", Mutex::_safepoint_check_always); - Mutex* mutex_rankA_plus_one = new Mutex(rankA + 1, "mutex_rankA_plus_one", Mutex::_safepoint_check_always); - Mutex* mutex_rankA_plus_two = new Mutex(rankA + 2, "mutex_rankA_plus_two", Mutex::_safepoint_check_always); + Mutex* mutex_rankA_plus_one = new Mutex(rankAplusOne, "mutex_rankA_plus_one", Mutex::_safepoint_check_always); + Mutex* mutex_rankA_plus_two = new Mutex(rankAplusTwo, "mutex_rankA_plus_two", Mutex::_safepoint_check_always); mutex_rankA_plus_one->lock(); mutex_rankA_plus_two->try_lock_without_rank_check(); @@ -113,12 +115,12 @@ TEST_OTHER_VM(MutexRank, mutex_trylock_rank_out_of_orderA) { } TEST_VM_ASSERT_MSG(MutexRank, mutex_trylock_rank_out_of_orderB, - ".* Attempting to acquire lock mutex_rankA_plus_one/51 out of order with lock mutex_rankA/50 -- possible deadlock") { + ".* Attempting to acquire lock mutex_rankA_plus_one/.* out of order with lock mutex_rankA/.* -- possible deadlock") { JavaThread* THREAD = JavaThread::current(); ThreadInVMfromNative invm(THREAD); Mutex* mutex_rankA = new Mutex(rankA, "mutex_rankA", Mutex::_safepoint_check_always); - Mutex* mutex_rankA_plus_one = new Mutex(rankA + 1, "mutex_rankA_plus_one", Mutex::_safepoint_check_always); + Mutex* mutex_rankA_plus_one = new Mutex(rankAplusOne, "mutex_rankA_plus_one", Mutex::_safepoint_check_always); mutex_rankA->lock(); mutex_rankA_plus_one->try_lock_without_rank_check(); @@ -163,7 +165,7 @@ TEST_OTHER_VM(MutexRank, monitor_wait_rank_in_order) { ThreadInVMfromNative invm(THREAD); Monitor* monitor_rankA = new Monitor(rankA, "monitor_rankA", Mutex::_safepoint_check_always); - Monitor* monitor_rankA_plus_one = new Monitor(rankA + 1, "monitor_rankA_plus_one", Mutex::_safepoint_check_always); + Monitor* monitor_rankA_plus_one = new Monitor(rankAplusOne, "monitor_rankA_plus_one", Mutex::_safepoint_check_always); monitor_rankA_plus_one->lock(); monitor_rankA->lock(); @@ -173,13 +175,13 @@ TEST_OTHER_VM(MutexRank, monitor_wait_rank_in_order) { } TEST_VM_ASSERT_MSG(MutexRank, monitor_wait_rank_out_of_order, - ".* Attempting to wait on monitor monitor_rankA_plus_one/51 while holding lock monitor_rankA/50 " + ".* Attempting to wait on monitor monitor_rankA_plus_one/.* while holding lock monitor_rankA/.* " "-- possible deadlock. Should wait on the least ranked monitor from all owned locks.") { JavaThread* THREAD = JavaThread::current(); ThreadInVMfromNative invm(THREAD); Monitor* monitor_rankA = new Monitor(rankA, "monitor_rankA", Mutex::_safepoint_check_always); - Monitor* monitor_rankA_plus_one = new Monitor(rankA + 1, "monitor_rankA_plus_one", Mutex::_safepoint_check_always); + Monitor* monitor_rankA_plus_one = new Monitor(rankAplusOne, "monitor_rankA_plus_one", Mutex::_safepoint_check_always); monitor_rankA_plus_one->lock(); monitor_rankA->lock(); @@ -189,13 +191,13 @@ TEST_VM_ASSERT_MSG(MutexRank, monitor_wait_rank_out_of_order, } TEST_VM_ASSERT_MSG(MutexRank, monitor_wait_rank_out_of_order_trylock, - ".* Attempting to wait on monitor monitor_rankA_plus_one/51 while holding lock monitor_rankA/50 " + ".* Attempting to wait on monitor monitor_rankA_plus_one/.* while holding lock monitor_rankA/.* " "-- possible deadlock. Should wait on the least ranked monitor from all owned locks.") { JavaThread* THREAD = JavaThread::current(); ThreadInVMfromNative invm(THREAD); Monitor* monitor_rankA = new Monitor(rankA, "monitor_rankA", Mutex::_safepoint_check_always); - Monitor* monitor_rankA_plus_one = new Monitor(rankA + 1, "monitor_rankA_plus_one", Mutex::_safepoint_check_always); + Monitor* monitor_rankA_plus_one = new Monitor(rankAplusOne, "monitor_rankA_plus_one", Mutex::_safepoint_check_always); monitor_rankA->lock(); monitor_rankA_plus_one->try_lock_without_rank_check(); @@ -280,12 +282,12 @@ TEST_VM_ASSERT_MSG(MutexRank, monitor_negative_rank, } TEST_VM_ASSERT_MSG(MutexRank, monitor_nosafepoint_rank, - ".*failed: Locks above nosafepoint rank should safepoint: monitor_rank_leaf") { + ".*failed: Locks above nosafepoint rank should safepoint: monitor_rank_nonleaf") { JavaThread* THREAD = JavaThread::current(); ThreadInVMfromNative invm(THREAD); - Monitor* monitor_rank_leaf = new Monitor(Mutex::leaf, "monitor_rank_leaf", Mutex::_safepoint_check_never); - monitor_rank_leaf->lock_without_safepoint_check(); - monitor_rank_leaf->unlock(); + Monitor* monitor_rank_nonleaf = new Monitor(Mutex::nonleaf, "monitor_rank_nonleaf", Mutex::_safepoint_check_never); + monitor_rank_nonleaf->lock_without_safepoint_check(); + monitor_rank_nonleaf->unlock(); } #endif // ASSERT diff --git a/test/hotspot/gtest/runtime/test_safepoint_locks.cpp b/test/hotspot/gtest/runtime/test_safepoint_locks.cpp index 6b6d68ccb55..a89785fe046 100644 --- a/test/hotspot/gtest/runtime/test_safepoint_locks.cpp +++ b/test/hotspot/gtest/runtime/test_safepoint_locks.cpp @@ -32,7 +32,7 @@ // Test mismatched safepoint check flag on lock declaration vs. lock acquisition. TEST_VM_ASSERT_MSG(SafepointLockAssertTest, always_check, ".*This lock should always have a safepoint check for Java threads: SFPT_Test_lock") { - MutexLocker ml(new Mutex(Mutex::leaf, "SFPT_Test_lock", Mutex::_safepoint_check_always), + MutexLocker ml(new Mutex(Mutex::nonleaf, "SFPT_Test_lock", Mutex::_safepoint_check_always), Mutex::_no_safepoint_check_flag); } -- GitLab From c10de3538b47c182d7bfeb02f348fac9b2ad0641 Mon Sep 17 00:00:00 2001 From: Christian Stein Date: Wed, 6 Oct 2021 15:11:28 +0000 Subject: [PATCH 117/385] 8262944: Improve exception message when automatic module lists provider class not in JAR file Reviewed-by: dfuchs, jvernee, alanb, lancea, mchung --- .../jdk/internal/module/ModulePath.java | 2 +- .../lang/module/AutomaticModulesTest.java | 31 +++++++++++++++---- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/src/java.base/share/classes/jdk/internal/module/ModulePath.java b/src/java.base/share/classes/jdk/internal/module/ModulePath.java index 99713872588..47c21ed3b3d 100644 --- a/src/java.base/share/classes/jdk/internal/module/ModulePath.java +++ b/src/java.base/share/classes/jdk/internal/module/ModulePath.java @@ -551,7 +551,7 @@ public class ModulePath implements ModuleFinder { if (!cn.isEmpty()) { String pn = packageName(cn); if (!packages.contains(pn)) { - String msg = "Provider class " + cn + " not in module"; + String msg = "Provider class " + cn + " not in JAR file " + fn; throw new InvalidModuleDescriptorException(msg); } providerClasses.add(cn); diff --git a/test/jdk/java/lang/module/AutomaticModulesTest.java b/test/jdk/java/lang/module/AutomaticModulesTest.java index fc6dd78ea83..a1977ae8774 100644 --- a/test/jdk/java/lang/module/AutomaticModulesTest.java +++ b/test/jdk/java/lang/module/AutomaticModulesTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /** * @test - * @bug 8142968 8253751 + * @bug 8142968 8253751 8262944 * @library /test/lib * @build AutomaticModulesTest * jdk.test.lib.util.JarUtils @@ -35,6 +35,7 @@ import java.io.IOException; import java.lang.module.Configuration; import java.lang.module.FindException; +import java.lang.module.InvalidModuleDescriptorException; import java.lang.module.ModuleDescriptor; import java.lang.module.ModuleDescriptor.Requires.Modifier; import java.lang.module.ModuleFinder; @@ -434,10 +435,28 @@ public class AutomaticModulesTest { Files.write(services.resolve("p.S"), Set.of("q.P")); Path dir = Files.createTempDirectory(USER_DIR, "mods"); - JarUtils.createJarFile(dir.resolve("m.jar"), tmpdir); - - // should throw FindException - ModuleFinder.of(dir).findAll(); + Path jarfile = dir.resolve("m.jar"); + JarUtils.createJarFile(jarfile, tmpdir); + + // catch FindException, inspect its cause's type and details, and rethrow + var expectedMessage = "Provider class q.P not in JAR file " + jarfile.getFileName(); + try { + ModuleFinder.of(dir).findAll(); + } catch (FindException exception) { + if (exception.getCause() instanceof InvalidModuleDescriptorException imde) { + var actualMessage = imde.getMessage(); + if (actualMessage.equals(expectedMessage)) { + throw exception; // rethrow as expected + } + throw new AssertionError( + """ + Unexpected detail message in InvalidModuleDescriptorException: + Expected message -> '%s' + Actual message -> '%s' + """.formatted(expectedMessage, actualMessage)); + } + throw new AssertionError("Unexpected exception cause: " + exception.getCause()); + } } /** -- GitLab From f3cedbe9288e7aea8d5603a2dc9bdc2661c391a6 Mon Sep 17 00:00:00 2001 From: Andrey Turbanov Date: Wed, 6 Oct 2021 18:11:07 +0000 Subject: [PATCH 118/385] 8274464: Remove redundant stream() call before forEach in java.* modules Reviewed-by: dfuchs, amenkov, vtewari --- .../javax/management/remote/rmi/RMIJRMPServerImpl.java | 2 +- .../java/lang/management/DefaultPlatformMBeanProvider.java | 3 +-- .../share/classes/javax/xml/catalog/CatalogFeatures.java | 4 +--- src/java.xml/share/classes/javax/xml/catalog/CatalogImpl.java | 4 ++-- 4 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIJRMPServerImpl.java b/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIJRMPServerImpl.java index e6787692ee7..c3ab4c1eee6 100644 --- a/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIJRMPServerImpl.java +++ b/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIJRMPServerImpl.java @@ -119,7 +119,7 @@ public class RMIJRMPServerImpl extends RMIServerImpl { else if (credentialsTypes != null) { allowedTypes = Arrays.stream(credentialsTypes).filter( s -> s!= null).collect(Collectors.toSet()); - allowedTypes.stream().forEach(ReflectUtil::checkPackageAccess); + allowedTypes.forEach(ReflectUtil::checkPackageAccess); cFilter = this::newClientCheckInput; } else { allowedTypes = null; diff --git a/src/java.management/share/classes/java/lang/management/DefaultPlatformMBeanProvider.java b/src/java.management/share/classes/java/lang/management/DefaultPlatformMBeanProvider.java index 7e928227e57..9d9c524b533 100644 --- a/src/java.management/share/classes/java/lang/management/DefaultPlatformMBeanProvider.java +++ b/src/java.management/share/classes/java/lang/management/DefaultPlatformMBeanProvider.java @@ -416,8 +416,7 @@ class DefaultPlatformMBeanProvider extends PlatformMBeanProvider { map = Collections.emptyMap(); } else { map = new HashMap<>(list.size()); - list.stream() - .forEach(mbean -> map.put(mbean.getObjectName().getCanonicalName(),mbean)); + list.forEach(mbean -> map.put(mbean.getObjectName().getCanonicalName(),mbean)); } return map; } diff --git a/src/java.xml/share/classes/javax/xml/catalog/CatalogFeatures.java b/src/java.xml/share/classes/javax/xml/catalog/CatalogFeatures.java index 811985877b7..78480a820d7 100644 --- a/src/java.xml/share/classes/javax/xml/catalog/CatalogFeatures.java +++ b/src/java.xml/share/classes/javax/xml/catalog/CatalogFeatures.java @@ -576,9 +576,7 @@ public class CatalogFeatures { * @param builder the CatalogFeatures builder */ private void setProperties(Builder builder) { - builder.values.entrySet().stream().forEach((entry) -> { - setProperty(entry.getKey(), State.APIPROPERTY, entry.getValue()); - }); + builder.values.forEach((feature, value) -> setProperty(feature, State.APIPROPERTY, value)); } /** * Sets the value of a property, updates only if it shall override. diff --git a/src/java.xml/share/classes/javax/xml/catalog/CatalogImpl.java b/src/java.xml/share/classes/javax/xml/catalog/CatalogImpl.java index db0f2b7f1f8..92c407e103f 100644 --- a/src/java.xml/share/classes/javax/xml/catalog/CatalogImpl.java +++ b/src/java.xml/share/classes/javax/xml/catalog/CatalogImpl.java @@ -413,14 +413,14 @@ class CatalogImpl extends GroupEntry implements Catalog { void loadNextCatalogs() { //loads catalogs specified in nextCatalogs if (nextCatalogs != null) { - nextCatalogs.stream().forEach((next) -> { + nextCatalogs.forEach((next) -> { getCatalog(this, next.getCatalogURI()); }); } //loads catalogs from the input list if (inputFiles != null) { - inputFiles.stream().forEach((uri) -> { + inputFiles.forEach((uri) -> { getCatalog(null, URI.create(uri)); }); } -- GitLab From 4e7d7caa0ce1a3c9fc45ca6a85b1a7ec209775b2 Mon Sep 17 00:00:00 2001 From: Andrey Turbanov Date: Wed, 6 Oct 2021 18:17:58 +0000 Subject: [PATCH 119/385] 8273711: Remove redundant stream() call before forEach in jdk.jlink Reviewed-by: alanb, psandoz, dfuchs --- .../jdk/tools/jlink/internal/ImageFileCreator.java | 4 ++-- .../tools/jlink/internal/ImagePluginConfiguration.java | 2 +- .../jdk/tools/jlink/internal/ImagePluginStack.java | 6 +++--- .../jdk/tools/jlink/internal/PerfectHashBuilder.java | 4 ++-- .../jdk/tools/jlink/internal/PluginRepository.java | 2 +- .../jlink/internal/ResourcePoolConfiguration.java | 10 +++++----- .../jlink/internal/plugins/ReleaseInfoPlugin.java | 5 ++--- .../tools/jlink/internal/plugins/ResourceFilter.java | 2 +- .../jlink/internal/plugins/StringSharingPlugin.java | 4 +--- 9 files changed, 18 insertions(+), 21 deletions(-) diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImageFileCreator.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImageFileCreator.java index 8beddc5a037..5664c195003 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImageFileCreator.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImageFileCreator.java @@ -109,7 +109,7 @@ public final class ImageFileCreator { } private void readAllEntries(Set archives) { - archives.stream().forEach((archive) -> { + archives.forEach((archive) -> { Map> es; try (Stream entries = archive.entries()) { es = entries.collect(Collectors.partitioningBy(n -> n.type() @@ -237,7 +237,7 @@ public final class ImageFileCreator { out.write(bytes, 0, bytes.length); // write module content - content.stream().forEach((res) -> { + content.forEach((res) -> { res.write(out); }); diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImagePluginConfiguration.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImagePluginConfiguration.java index aa26f3dc5e4..74af459fb13 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImagePluginConfiguration.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImagePluginConfiguration.java @@ -94,7 +94,7 @@ public final class ImagePluginConfiguration { } List orderedPlugins = new ArrayList<>(); - plugins.entrySet().stream().forEach((entry) -> { + plugins.entrySet().forEach((entry) -> { orderedPlugins.addAll(entry.getValue()); }); Plugin lastSorter = null; diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImagePluginStack.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImagePluginStack.java index ce93b4a06fe..ad4188b4395 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImagePluginStack.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImagePluginStack.java @@ -181,7 +181,7 @@ public final class ImagePluginStack { this.imageBuilder = Objects.requireNonNull(imageBuilder); this.lastSorter = lastSorter; this.plugins.addAll(Objects.requireNonNull(plugins)); - plugins.stream().forEach((p) -> { + plugins.forEach((p) -> { Objects.requireNonNull(p); if (p instanceof ResourcePrevisitor) { resourcePrevisitors.add((ResourcePrevisitor) p); @@ -227,13 +227,13 @@ public final class ImagePluginStack { resources.getStringTable()).resourcePool(); } PreVisitStrings previsit = new PreVisitStrings(); - resourcePrevisitors.stream().forEach((p) -> { + resourcePrevisitors.forEach((p) -> { p.previsit(resources.resourcePool(), previsit); }); // Store the strings resulting from the previsit. List sorted = previsit.getSortedStrings(); - sorted.stream().forEach((s) -> { + sorted.forEach((s) -> { resources.getStringTable().addString(s); }); diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/PerfectHashBuilder.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/PerfectHashBuilder.java index 8c593a37038..55c745552f6 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/PerfectHashBuilder.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/PerfectHashBuilder.java @@ -283,7 +283,7 @@ public class PerfectHashBuilder { // Build bucket chains based on key hash. Collisions end up in same chain. Bucket[] buckets = (Bucket[])Array.newInstance(bucketComponent, count); - map.values().stream().forEach((entry) -> { + map.values().forEach((entry) -> { int index = (entry.hashCode() & 0x7FFFFFFF) % count; Bucket bucket = buckets[index]; @@ -327,7 +327,7 @@ public class PerfectHashBuilder { } // Undo the attempted packing. - undo.stream().forEach((i) -> { + undo.forEach((i) -> { order[i] = null; }); diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/PluginRepository.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/PluginRepository.java index 568bde86a22..c2decd3c064 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/PluginRepository.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/PluginRepository.java @@ -143,7 +143,7 @@ public final class PluginRepository { while (providers.hasNext()) { factories.add(providers.next()); } - registeredPlugins.values().stream().forEach((fact) -> { + registeredPlugins.values().forEach((fact) -> { if (clazz.isInstance(fact)) { @SuppressWarnings("unchecked") T trans = (T) fact; diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolConfiguration.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolConfiguration.java index e3f54788370..91e81aad481 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolConfiguration.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolConfiguration.java @@ -47,15 +47,15 @@ final class ResourcePoolConfiguration { // drop hashes ModuleDescriptor.Builder builder = ModuleDescriptor.newModule(md.name()); - md.requires().stream() + md.requires() .forEach(builder::requires); - md.exports().stream() + md.exports() .forEach(builder::exports); - md.opens().stream() + md.opens() .forEach(builder::opens); - md.uses().stream() + md.uses() .forEach(builder::uses); - md.provides().stream() + md.provides() .forEach(builder::provides); builder.packages(md.packages()); diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ReleaseInfoPlugin.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ReleaseInfoPlugin.java index 30edf916a2c..b4301ea8e45 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ReleaseInfoPlugin.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ReleaseInfoPlugin.java @@ -99,9 +99,8 @@ public final class ReleaseInfoPlugin extends AbstractPlugin { if (keys == null || keys.isEmpty()) { throw new IllegalArgumentException("No key specified for delete"); } - Utils.parseList(keys).stream().forEach((k) -> { - release.remove(k); - }); + Utils.parseList(keys) + .forEach(release::remove); } break; diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ResourceFilter.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ResourceFilter.java index c72df27b7eb..4a5c3b52572 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ResourceFilter.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ResourceFilter.java @@ -65,7 +65,7 @@ public class ResourceFilter implements Predicate { throw new UncheckedIOException(ex); } - lines.stream().forEach((line) -> { + lines.forEach((line) -> { matchers.add(Utils.getJRTFSPathMatcher(line.trim())); }); } else { diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/StringSharingPlugin.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/StringSharingPlugin.java index 88f5a0eb7ce..e4c49c2c18c 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/StringSharingPlugin.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/StringSharingPlugin.java @@ -311,9 +311,7 @@ public class StringSharingPlugin extends AbstractPlugin implements ResourcePrevi buffers.add(buffer); } ByteBuffer bb = ByteBuffer.allocate(l); - buffers.stream().forEach((buf) -> { - bb.put(buf); - }); + buffers.forEach(bb::put); byte[] compressed_indices = bb.array(); byte[] compressed_size = CompressIndexes. compress(compressed_indices.length); -- GitLab From 754bc82c4c03e1bedb4b36b5c52873b0a78a6ceb Mon Sep 17 00:00:00 2001 From: Andrey Turbanov Date: Wed, 6 Oct 2021 18:20:18 +0000 Subject: [PATCH 120/385] 8274525: Replace uses of StringBuffer with StringBuilder in java.xml Reviewed-by: joehw, iris, naoto, dfuchs --- .../com/sun/xml/internal/stream/Entity.java | 13 +++++-------- .../internal/stream/StaxErrorReporter.java | 4 ++-- .../internal/stream/XMLEventReaderImpl.java | 6 +++--- .../internal/stream/events/LocationImpl.java | 19 ++++++------------- .../classes/javax/xml/datatype/Duration.java | 11 +++++------ 5 files changed, 21 insertions(+), 32 deletions(-) diff --git a/src/java.xml/share/classes/com/sun/xml/internal/stream/Entity.java b/src/java.xml/share/classes/com/sun/xml/internal/stream/Entity.java index 69508b50384..9d67a90a419 100644 --- a/src/java.xml/share/classes/com/sun/xml/internal/stream/Entity.java +++ b/src/java.xml/share/classes/com/sun/xml/internal/stream/Entity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -461,13 +461,10 @@ public abstract class Entity { /** Returns a string representation of this object. */ public String toString() { - - StringBuffer str = new StringBuffer(); - str.append("name=\""+name+'"'); - str.append(",ch="+ new String(ch)); - str.append(",position="+position); - str.append(",count="+count); - return str.toString(); + return "name=\"" + name + '"' + + ",ch=" + new String(ch) + + ",position=" + position + + ",count=" + count; } // toString():String diff --git a/src/java.xml/share/classes/com/sun/xml/internal/stream/StaxErrorReporter.java b/src/java.xml/share/classes/com/sun/xml/internal/stream/StaxErrorReporter.java index e48ae7ba0af..86535efc6bf 100644 --- a/src/java.xml/share/classes/com/sun/xml/internal/stream/StaxErrorReporter.java +++ b/src/java.xml/share/classes/com/sun/xml/internal/stream/StaxErrorReporter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -93,7 +93,7 @@ public class StaxErrorReporter extends XMLErrorReporter { message = messageFormatter.formatMessage(fLocale, key, arguments); } else { - StringBuffer str = new StringBuffer(); + StringBuilder str = new StringBuilder(); str.append(domain); str.append('#'); str.append(key); diff --git a/src/java.xml/share/classes/com/sun/xml/internal/stream/XMLEventReaderImpl.java b/src/java.xml/share/classes/com/sun/xml/internal/stream/XMLEventReaderImpl.java index 04181ba4b51..1eea8dd782d 100644 --- a/src/java.xml/share/classes/com/sun/xml/internal/stream/XMLEventReaderImpl.java +++ b/src/java.xml/share/classes/com/sun/xml/internal/stream/XMLEventReaderImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -142,8 +142,8 @@ public class XMLEventReaderImpl implements javax.xml.stream.XMLEventReader{ return ""; } - //create the string buffer and add initial data - StringBuffer buffer = new StringBuffer(); + //create the string builder and add initial data + StringBuilder buffer = new StringBuilder(); if(data != null && data.length() > 0 ) { buffer.append(data); } diff --git a/src/java.xml/share/classes/com/sun/xml/internal/stream/events/LocationImpl.java b/src/java.xml/share/classes/com/sun/xml/internal/stream/events/LocationImpl.java index e52a7f69c24..66e0d699e79 100644 --- a/src/java.xml/share/classes/com/sun/xml/internal/stream/events/LocationImpl.java +++ b/src/java.xml/share/classes/com/sun/xml/internal/stream/events/LocationImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. * 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,18 +67,11 @@ public class LocationImpl implements Location{ } public String toString(){ - StringBuffer sbuffer = new StringBuffer() ; - sbuffer.append("Line number = " + getLineNumber()); - sbuffer.append("\n") ; - sbuffer.append("Column number = " + getColumnNumber()); - sbuffer.append("\n") ; - sbuffer.append("System Id = " + getSystemId()); - sbuffer.append("\n") ; - sbuffer.append("Public Id = " + getPublicId()); - sbuffer.append("\n") ; - sbuffer.append("CharacterOffset = " + getCharacterOffset()); - sbuffer.append("\n") ; - return sbuffer.toString(); + return "Line number = " + getLineNumber() + "\n" + + "Column number = " + getColumnNumber() + "\n" + + "System Id = " + getSystemId() + "\n" + + "Public Id = " + getPublicId() + "\n" + + "CharacterOffset = " + getCharacterOffset() + "\n"; } } diff --git a/src/java.xml/share/classes/javax/xml/datatype/Duration.java b/src/java.xml/share/classes/javax/xml/datatype/Duration.java index a5c786fb18d..cad8a56c58b 100644 --- a/src/java.xml/share/classes/javax/xml/datatype/Duration.java +++ b/src/java.xml/share/classes/javax/xml/datatype/Duration.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -885,8 +885,7 @@ public abstract class Duration { * @return A non-{@code null} valid {@code String} representation of this {@code Duration}. */ public String toString() { - - StringBuffer buf = new StringBuffer(); + StringBuilder buf = new StringBuilder(); if (getSign() < 0) { buf.append('-'); @@ -946,15 +945,15 @@ public abstract class Duration { } /* Insert decimal point */ - StringBuffer buf; + StringBuilder buf; int insertionPoint = intString.length() - scale; if (insertionPoint == 0) { /* Point goes right before intVal */ return "0." + intString; } else if (insertionPoint > 0) { /* Point goes inside intVal */ - buf = new StringBuffer(intString); + buf = new StringBuilder(intString); buf.insert(insertionPoint, '.'); } else { /* We must insert zeros between point and intVal */ - buf = new StringBuffer(3 - insertionPoint + intString.length()); + buf = new StringBuilder(3 - insertionPoint + intString.length()); buf.append("0."); for (int i = 0; i < -insertionPoint; i++) { buf.append('0'); -- GitLab From 9945f7a0744db2470bcfa856e8f831b6a6eb2de8 Mon Sep 17 00:00:00 2001 From: Andrey Turbanov Date: Wed, 6 Oct 2021 18:23:46 +0000 Subject: [PATCH 121/385] 8274318: Replace 'for' cycles with iterator with enhanced-for in java.management Reviewed-by: cjplummer, sspitsyn, dfuchs --- .../management/remote/rmi/RMIServerImpl.java | 5 ++--- .../MBeanServerFileAccessController.java | 4 +--- .../javax/management/relation/RoleResult.java | 19 ++++++------------- 3 files changed, 9 insertions(+), 19 deletions(-) diff --git a/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIServerImpl.java b/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIServerImpl.java index 957a08e2535..a1d336c8cd8 100644 --- a/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIServerImpl.java +++ b/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIServerImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -494,8 +494,7 @@ public abstract class RMIServerImpl implements Closeable, RMIServer { if (subject != null) { Set principals = subject.getPrincipals(); String sep = ""; - for (Iterator it = principals.iterator(); it.hasNext(); ) { - Principal p = it.next(); + for (Principal p : principals) { String name = p.getName().replace(' ', '_').replace(';', ':'); buf.append(sep).append(name); sep = ";"; diff --git a/src/java.management/share/classes/com/sun/jmx/remote/security/MBeanServerFileAccessController.java b/src/java.management/share/classes/com/sun/jmx/remote/security/MBeanServerFileAccessController.java index 449fd042246..da130f22aa3 100644 --- a/src/java.management/share/classes/com/sun/jmx/remote/security/MBeanServerFileAccessController.java +++ b/src/java.management/share/classes/com/sun/jmx/remote/security/MBeanServerFileAccessController.java @@ -33,7 +33,6 @@ import java.security.Principal; import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.HashMap; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Properties; @@ -314,8 +313,7 @@ public class MBeanServerFileAccessController if (s == null) return; /* security has not been enabled */ final Set principals = s.getPrincipals(); String newPropertyValue = null; - for (Iterator i = principals.iterator(); i.hasNext(); ) { - final Principal p = i.next(); + for (Principal p : principals) { Access access = accessMap.get(p.getName()); if (access != null) { boolean ok; diff --git a/src/java.management/share/classes/javax/management/relation/RoleResult.java b/src/java.management/share/classes/javax/management/relation/RoleResult.java index d14dbb7d356..60836c897e5 100644 --- a/src/java.management/share/classes/javax/management/relation/RoleResult.java +++ b/src/java.management/share/classes/javax/management/relation/RoleResult.java @@ -35,7 +35,6 @@ import java.io.ObjectStreamField; import java.io.Serializable; import java.security.AccessController; -import java.util.Iterator; /** * Represents the result of a multiple access to several roles of a relation @@ -132,7 +131,6 @@ public class RoleResult implements Serializable { setRoles(list); setRolesUnresolved(unresolvedList); - return; } // @@ -173,15 +171,13 @@ public class RoleResult implements Serializable { roleList = new RoleList(); - for (Iterator roleIter = list.iterator(); - roleIter.hasNext();) { - Role currRole = (Role)(roleIter.next()); - roleList.add((Role)(currRole.clone())); + for (Object o : list) { + Role currRole = (Role)o; + roleList.add((Role)currRole.clone()); } } else { roleList = null; } - return; } /** @@ -196,16 +192,13 @@ public class RoleResult implements Serializable { unresolvedRoleList = new RoleUnresolvedList(); - for (Iterator roleUnresIter = unresolvedList.iterator(); - roleUnresIter.hasNext();) { - RoleUnresolved currRoleUnres = - (RoleUnresolved)(roleUnresIter.next()); - unresolvedRoleList.add((RoleUnresolved)(currRoleUnres.clone())); + for (Object o : unresolvedList) { + RoleUnresolved currRoleUnres = (RoleUnresolved)o; + unresolvedRoleList.add((RoleUnresolved)currRoleUnres.clone()); } } else { unresolvedRoleList = null; } - return; } /** -- GitLab From 9561fea79035f23ca3a6619c9e150433cdf4a232 Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Wed, 6 Oct 2021 22:31:23 +0000 Subject: [PATCH 122/385] 8273102: Delete deprecated for removal the empty finalize() in java.desktop module Reviewed-by: pbansal, aivanov, iris, prr --- .../classes/java/awt/color/ICC_Profile.java | 18 ----------------- .../classes/java/awt/image/ColorModel.java | 20 ------------------- .../java/awt/image/IndexColorModel.java | 19 ------------------ 3 files changed, 57 deletions(-) diff --git a/src/java.desktop/share/classes/java/awt/color/ICC_Profile.java b/src/java.desktop/share/classes/java/awt/color/ICC_Profile.java index da14d248926..ff8e0745e19 100644 --- a/src/java.desktop/share/classes/java/awt/color/ICC_Profile.java +++ b/src/java.desktop/share/classes/java/awt/color/ICC_Profile.java @@ -767,24 +767,6 @@ public class ICC_Profile implements Serializable { deferralInfo = pdi; } - /** - * Frees the resources associated with an {@code ICC_Profile} object. - * - * @deprecated The {@code finalize} method has been deprecated. Subclasses - * that override {@code finalize} in order to perform cleanup should - * be modified to use alternative cleanup mechanisms and to remove - * the overriding {@code finalize} method. When overriding the - * {@code finalize} method, its implementation must explicitly - * ensure that {@code super.finalize()} is invoked as described in - * {@link Object#finalize}. See the specification for {@link - * Object#finalize()} for further information about migration - * options. - */ - @Deprecated(since = "9", forRemoval = true) - @SuppressWarnings("removal") - protected void finalize() { - } - /** * Constructs an {@code ICC_Profile} object corresponding to the data in a * byte array. diff --git a/src/java.desktop/share/classes/java/awt/image/ColorModel.java b/src/java.desktop/share/classes/java/awt/image/ColorModel.java index 37c6a5d66d7..98d870c5abf 100644 --- a/src/java.desktop/share/classes/java/awt/image/ColorModel.java +++ b/src/java.desktop/share/classes/java/awt/image/ColorModel.java @@ -1617,26 +1617,6 @@ public abstract class ColorModel implements Transparency{ ("This method is not supported by this color model"); } - /** - * Disposes of system resources associated with this - * {@code ColorModel} once this {@code ColorModel} is no - * longer referenced. - * - * @deprecated The {@code finalize} method has been deprecated. - * Subclasses that override {@code finalize} in order to perform cleanup - * should be modified to use alternative cleanup mechanisms and - * to remove the overriding {@code finalize} method. - * When overriding the {@code finalize} method, its implementation must explicitly - * ensure that {@code super.finalize()} is invoked as described in {@link Object#finalize}. - * See the specification for {@link Object#finalize()} for further - * information about migration options. - */ - @Deprecated(since = "9", forRemoval = true) - @SuppressWarnings("removal") - public void finalize() { - } - - /** * Returns a {@code Raster} representing the alpha channel of an * image, extracted from the input {@code Raster}, provided that diff --git a/src/java.desktop/share/classes/java/awt/image/IndexColorModel.java b/src/java.desktop/share/classes/java/awt/image/IndexColorModel.java index 1d9e6e59b75..49ab60bce89 100644 --- a/src/java.desktop/share/classes/java/awt/image/IndexColorModel.java +++ b/src/java.desktop/share/classes/java/awt/image/IndexColorModel.java @@ -1510,25 +1510,6 @@ public class IndexColorModel extends ColorModel { } } - /** - * Disposes of system resources associated with this - * {@code ColorModel} once this {@code ColorModel} is no - * longer referenced. - * - * @deprecated The {@code finalize} method has been deprecated. - * Subclasses that override {@code finalize} in order to perform cleanup - * should be modified to use alternative cleanup mechanisms and - * to remove the overriding {@code finalize} method. - * When overriding the {@code finalize} method, its implementation must explicitly - * ensure that {@code super.finalize()} is invoked as described in {@link Object#finalize}. - * See the specification for {@link Object#finalize()} for further - * information about migration options. - */ - @Deprecated(since = "9", forRemoval = true) - @SuppressWarnings("removal") - public void finalize() { - } - /** * Returns the {@code String} representation of the contents of * this {@code ColorModel} object. -- GitLab From 734d1fbd33be0aa20b26e6e8c776709f478069de Mon Sep 17 00:00:00 2001 From: Jonathan Gibbons Date: Wed, 6 Oct 2021 22:40:44 +0000 Subject: [PATCH 123/385] 8274211: Test man page that options are documented Reviewed-by: prappo --- .../jdk/javadoc/tool/CheckManPageOptions.java | 287 ++++++++++++++++++ 1 file changed, 287 insertions(+) create mode 100644 test/langtools/jdk/javadoc/tool/CheckManPageOptions.java diff --git a/test/langtools/jdk/javadoc/tool/CheckManPageOptions.java b/test/langtools/jdk/javadoc/tool/CheckManPageOptions.java new file mode 100644 index 00000000000..f876d92b7dd --- /dev/null +++ b/test/langtools/jdk/javadoc/tool/CheckManPageOptions.java @@ -0,0 +1,287 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 8274211 + * @summary Test man page that options are documented + * @modules jdk.javadoc/jdk.javadoc.internal.tool:+open + * @run main CheckManPageOptions + */ + +import jdk.javadoc.doclet.Doclet; +import jdk.javadoc.doclet.StandardDoclet; +import jdk.javadoc.internal.tool.ToolOptions; + +import java.io.IOException; +import java.io.PrintStream; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Locale; +import java.util.TreeSet; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +/** + * Checks the set of options found by fuzzy-parsing the troff or Markdown versions + * of the javadoc man page against the set of options declared in the source code. + */ +public class CheckManPageOptions { + public static void main(String... args) throws Exception { + new CheckManPageOptions().run(args); + } + + static final PrintStream out = System.err; + + // FIXME: JDK-8274295, JDK-8266666 + List MISSING_IN_MAN_PAGE = List.of( + "--legal-notices", + "--link-platform-properties", + "--no-platform-links", + "--since", + "--since-label", + "--snippet-path"); + + void run(String... args) throws Exception { + var file = args.length == 0 ? findDefaultFile() : Path.of(args[0]); + out.println("File: " + file); + out.println(); + + var manPageOptions = getManPageOptions(file); + out.println("Man page options: " + manPageOptions); + out.println(); + + var toolOptions = getToolOptions(); + out.println("ToolOptions: " + toolOptions); + out.println(); + + var docletOptions = getDocletOptions(); + out.println("DocletOptions: " + docletOptions); + out.println(); + + var toolDocletOnly = new TreeSet(); + toolDocletOnly.addAll(toolOptions); + toolDocletOnly.addAll(docletOptions); + toolDocletOnly.removeAll(manPageOptions); + toolDocletOnly.removeAll(MISSING_IN_MAN_PAGE); + if (!toolDocletOnly.isEmpty()) { + error("The following options are defined by the tool or doclet, but not defined in the man page:\n" + + toSimpleList(toolDocletOnly)); + } + + var manPageOnly = new TreeSet(); + manPageOnly.addAll(manPageOptions); + manPageOnly.removeAll(toolOptions); + manPageOnly.removeAll(docletOptions); + if (!manPageOnly.isEmpty()) { + error("The following options are defined in the man page, but not defined by the tool or doclet:\n" + + toSimpleList(manPageOnly)); + } + + if (!MISSING_IN_MAN_PAGE.isEmpty()) { + var notMissing = new TreeSet<>(MISSING_IN_MAN_PAGE); + notMissing.retainAll(manPageOptions); + if (!notMissing.isEmpty()) { + error("The following options were declared as missing, but were found on the man page:\n" + + toSimpleList(notMissing)); + } + + out.println("NOTE: the following options are currently excluded and need to be documented in the man page:"); + out.println(toSimpleList(MISSING_IN_MAN_PAGE)); + } + + if (errors > 0) { + out.println(errors + " errors found"); + throw new Exception(errors + " errors found"); + } + } + + int errors = 0; + void error(String message) { + ("Error: " + message).lines().forEach(out::println); + errors++; + } + + String toSimpleList(Collection items) { + return items.stream().collect(Collectors.joining(", ", " ", "")); + } + + Path findDefaultFile() { + return findRootDir().resolve("src/jdk.javadoc/share/man/javadoc.1"); + } + + Path findRootDir() { + Path dir = Path.of(System.getProperty("test.src", ".")).toAbsolutePath(); + while (dir != null) { + if (Files.exists(dir.resolve("src"))) { + return dir; + } else { + Path openDir = dir.resolve("open"); + if (Files.exists(openDir.resolve("src"))) { + return openDir; + } + } + dir = dir.getParent(); + } + throw new IllegalStateException("cannot find root dir"); + } + + List getToolOptions() throws Error { + try { + Class toolOptionsClass = ToolOptions.class; + + Constructor constr = toolOptionsClass.getDeclaredConstructor(); + constr.setAccessible(true); + + Method getSupportedOptions = toolOptionsClass.getMethod("getSupportedOptions"); + Class toolOptionClass = List.of(toolOptionsClass.getDeclaredClasses()).stream() + .filter(c -> c.getSimpleName().equals("ToolOption")) + .findFirst() + .orElseThrow(); + + Field kindField = toolOptionClass.getDeclaredField("kind"); + kindField.setAccessible(true); + Method getNames = toolOptionClass.getDeclaredMethod("getNames"); + getNames.setAccessible(true); + + ToolOptions t = constr.newInstance(); + var list = new ArrayList(); + var options = (List) getSupportedOptions.invoke(t); + for (var option : options) { + Object kind = kindField.get(option); + if (kind.toString().equals("HIDDEN")) { + continue; + } + + @SuppressWarnings("unchecked") + var oNames = (List) getNames.invoke(option); + oNames.stream() + .filter(o -> !o.equals("@")) + .forEach(list::add); + } + return list; + } catch (ReflectiveOperationException e) { + throw new Error(e); + } + } + + List getDocletOptions() { + StandardDoclet d = new StandardDoclet(); + d.init(Locale.getDefault(), null); + return getDocletOptions(d); + } + + List getDocletOptions(Doclet d) { + return d.getSupportedOptions().stream() + .filter(o -> o.getKind() != Doclet.Option.Kind.OTHER) + .flatMap(o -> o.getNames().stream()) + .map(n -> n.replaceAll(":$", "")) + .toList(); + } + + List getManPageOptions(Path file) throws IOException { + String page = Files.readString(file); + String name = file.getFileName().toString(); + String extn = name.substring(name.lastIndexOf('.')); + return switch (extn) { + case ".1" -> parseNRoff(page); + case ".md" -> parseMarkdown(page); + default -> throw new IllegalArgumentException(file.toString()); + }; + } + + List parseNRoff(String page) { + var list = new ArrayList(); + + // In the troff man page, options are defined in one of two forms: + // 1. options delegated to javac appear in pairs of lines of the form + // .IP \[bu] 2 + // \f[CB]\-.... + // 2. options implemented by the tool or doclet appear in lines of the form + // .B \f[CB]\-... + + Pattern p1 = Pattern.compile("\\R" + Pattern.quote(".IP \\[bu] 2") + "\\R" + Pattern.quote("\\f[CB]\\-") + ".*"); + Pattern p2 = Pattern.compile("\\R" + Pattern.quote(".B \\f[CB]\\-") + ".*"); + Pattern outer = Pattern.compile("(" + p1.pattern() + "|" + p2.pattern() + ")"); + Matcher outerMatcher = outer.matcher(page); + + // In the defining areas, option names are represented as follows: + // \f[CB]OPTION\f[R] or \f[CB]OPTION: + // where OPTION is the shortest string not containing whitespace or colon, + // and in which all '-' characters are escaped with a single backslash. + + Pattern inner = Pattern.compile("\\s\\\\f\\[CB](\\\\-[^ :]+?)(:|\\\\f\\[R])"); + + while (outerMatcher.find()) { + String lines = outerMatcher.group(); + out.println("found:" + lines + "\n"); + + Matcher innerMatcher = inner.matcher(lines); + while (innerMatcher.find()) { + String option = innerMatcher.group(1).replace("\\-", "-"); + list.add(option); + } + } + + return list; + } + + List parseMarkdown(String page) { + var list = new ArrayList(); + // In the Markdown man page, options are defined in one of two forms: + // 1. options delegated to javac appear in lines of the form + // - `-... + // 2. options implemented by the tool or doclet appear in lines of the form + // `-...` + + Pattern p1 = Pattern.compile("\\R- `-.*"); + Pattern p2 = Pattern.compile("\\R`-.*"); + Pattern outer = Pattern.compile("(" + p1.pattern() + "|" + p2.pattern() + ")"); + Matcher outerMatcher = outer.matcher(page); + + // In the defining areas, option names are represented as follows: + // `OPTION` + // where OPTION is the shortest string not containing whitespace or colon + Pattern inner = Pattern.compile("\\s`([^:`]+)"); + + while (outerMatcher.find()) { + String lines = outerMatcher.group(); + out.println("found:" + lines + "\n"); + + Matcher innerMatcher = inner.matcher(lines); + while (innerMatcher.find()) { + String option = innerMatcher.group(1); + list.add(option); + } + } + + return list; + } + } -- GitLab From d57fb6f684eac5a7e68842dcf3284309e3867521 Mon Sep 17 00:00:00 2001 From: "lawrence.andrews" Date: Wed, 6 Oct 2021 23:12:56 +0000 Subject: [PATCH 124/385] 8274456: Remove jtreg tag manual=yesno java/awt/print/PrinterJob/PageDialogTest.java Reviewed-by: serb --- .../awt/print/PrinterJob/PageDialogTest.java | 228 +++++++----------- 1 file changed, 91 insertions(+), 137 deletions(-) diff --git a/test/jdk/java/awt/print/PrinterJob/PageDialogTest.java b/test/jdk/java/awt/print/PrinterJob/PageDialogTest.java index dd359c1e17a..8a8f9839ddf 100644 --- a/test/jdk/java/awt/print/PrinterJob/PageDialogTest.java +++ b/test/jdk/java/awt/print/PrinterJob/PageDialogTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2021, Oracle and/or its affiliates. All rights reserved. * 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,157 +21,111 @@ * questions. */ -/* @test +/* + @test @bug 6302514 - @run main/manual=yesno PageDialogTest + @run main/manual PageDialogTest @summary A toolkit modal dialog should not be blocked by Page/Print dialog. */ -import java.awt.*; -import java.awt.event.*; -import java.awt.print.*; -import javax.swing.*; +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.Dialog; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Panel; +import java.awt.TextArea; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.awt.print.PageFormat; +import java.awt.print.PrinterJob; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; public class PageDialogTest { - public static void main(String[] args) { - String[] instructions = - { - "The test shows a Toolkit modal dialog. ", - "Click the 'Open' button. It opens a page dialog.", - "The test fails if the page dialog blocks the toolkit", - "modal dialog, otherwise it passes." - }; - - Sysout.createDialog( ); - Sysout.printInstructions( instructions ); - - Dialog td = new Dialog((Frame) null, "Toolkit modal dialog", - Dialog.ModalityType.TOOLKIT_MODAL); - td.setLayout(new FlowLayout()); - td.add(new Button("Dummy")); - Button tdb = new Button("Open"); - tdb.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent event) { - PrinterJob.getPrinterJob().pageDialog(new PageFormat()); - } + public static Frame frame; + public static Dialog dialog; + public static volatile boolean testResult; + public static final CountDownLatch countDownLatch = new CountDownLatch(1); + + public static void createUI() { + frame = new Frame("Test 6302514"); + String instructions = + "1. Click on the 'Show Dialog' button to show a 'Toolkit Modal Dialog' \n" + + "2. Click on the 'Open PageDialog' button to show 'Page Dialog'.\n" + + "3. The test fails if the page dialog blocks the toolkit\n"+ + " else test pass.\n" + + "4. Close Page dialog and 'Toolkit modal dialog'\n" + + "5. Click appropriate button to mark the test case pass or fail.\n" ; + + TextArea instructionsTextArea = new TextArea( instructions, 8, + 50, TextArea.SCROLLBARS_NONE ); + instructionsTextArea.setEditable(false); + frame.add(BorderLayout.NORTH, instructionsTextArea); + + Panel buttonPanel = new Panel(new FlowLayout()); + Button passButton = new Button("pass"); + passButton.setActionCommand("pass"); + passButton.addActionListener(e -> { + testResult = true; + countDownLatch.countDown(); + dialog.dispose(); + frame.dispose(); }); - td.add(tdb); - td.setSize(250, 150); - td.setVisible(true); - } -} - -class Sysout { - private static TestDialog dialog; - - public static void createDialogWithInstructions( String[] instructions ) - { - dialog = new TestDialog( new Frame(), "Instructions" ); - dialog.printInstructions( instructions ); - dialog.show(); - println( "Any messages for the tester will display here." ); - } - public static void createDialog( ) - { - dialog = new TestDialog( new Frame(), "Instructions" ); - String[] defInstr = { "Instructions will appear here. ", "" } ; - dialog.printInstructions( defInstr ); - dialog.show(); - println( "Any messages for the tester will display here." ); - } + Button failButton = new Button("fail"); + failButton.addActionListener(e->{ + testResult = false; + countDownLatch.countDown(); + dialog.dispose(); + frame.dispose(); + }); + Button showDialog = new Button("Show Dialog"); + showDialog.addActionListener(e->{ + createToolkitModalDialog(); + }); - public static void printInstructions( String[] instructions ) - { - dialog.printInstructions( instructions ); + buttonPanel.add(showDialog); + buttonPanel.add(passButton); + buttonPanel.add(failButton); + frame.add(BorderLayout.SOUTH, buttonPanel); + frame.pack(); + frame.setVisible(true); } + public static void createToolkitModalDialog() { + dialog = new Dialog((Frame) null, "Toolkit modal dialog", + Dialog.ModalityType.TOOLKIT_MODAL); + dialog.setLayout(new FlowLayout()); + dialog.addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + super.windowClosing(e); + dialog.dispose(); + } + }); - public static void println( String messageIn ) - { - dialog.displayMessage( messageIn ); + Button openPageDialogButton = new Button("Open PageDialog"); + openPageDialogButton.addActionListener(e->{ + PrinterJob.getPrinterJob().pageDialog(new PageFormat()); + }); + dialog.add(openPageDialogButton); + dialog.setSize(250, 150); + dialog.setLocationRelativeTo(null); + dialog.setVisible(true); } -}// Sysout class - -/** - This is part of the standard test machinery. It provides a place for the - test instructions to be displayed, and a place for interactive messages - to the user to be displayed. - To have the test instructions displayed, see Sysout. - To have a message to the user be displayed, see Sysout. - Do not call anything in this dialog directly. - */ -class TestDialog extends Dialog { - - TextArea instructionsText; - TextArea messageText; - int maxStringLength = 80; - - //DO NOT call this directly, go through Sysout - public TestDialog( Frame frame, String name ) - { - super( frame, name ); - int scrollBoth = TextArea.SCROLLBARS_BOTH; - instructionsText = new TextArea( "", 15, maxStringLength, scrollBoth ); - add( "North", instructionsText ); - - messageText = new TextArea( "", 5, maxStringLength, scrollBoth ); - add("Center", messageText); - - pack(); - - show(); - }// TestDialog() - - //DO NOT call this directly, go through Sysout - public void printInstructions( String[] instructions ) - { - //Clear out any current instructions - instructionsText.setText( "" ); - - //Go down array of instruction strings - - String printStr, remainingStr; - for( int i=0; i < instructions.length; i++ ) - { - //chop up each into pieces maxSringLength long - remainingStr = instructions[ i ]; - while( remainingStr.length() > 0 ) - { - //if longer than max then chop off first max chars to print - if( remainingStr.length() >= maxStringLength ) - { - //Try to chop on a word boundary - int posOfSpace = remainingStr. - lastIndexOf( ' ', maxStringLength - 1 ); - - if( posOfSpace <= 0 ) posOfSpace = maxStringLength - 1; - - printStr = remainingStr.substring( 0, posOfSpace + 1 ); - remainingStr = remainingStr.substring( posOfSpace + 1 ); - } - //else just print - else - { - printStr = remainingStr; - remainingStr = ""; - } - - instructionsText.append( printStr + "\n" ); - - }// while - - }// for - - }//printInstructions() - - //DO NOT call this directly, go through Sysout - public void displayMessage( String messageIn ) - { - messageText.append( messageIn + "\n" ); + public static void main(String []args) throws InterruptedException { + createUI(); + if ( !countDownLatch.await(5, TimeUnit.MINUTES)) { + throw new RuntimeException("Timeout : user did not perform any " + + "action on the UI."); + } + if ( !testResult) { + throw new RuntimeException("Test failed"); + } } +} - }// TestDialog class -- GitLab From c833b4d130fabfa6a6f3a38313f76eb7e392c6a5 Mon Sep 17 00:00:00 2001 From: Jie Fu Date: Wed, 6 Oct 2021 23:22:04 +0000 Subject: [PATCH 125/385] 8274329: Fix non-portable HotSpot code in MethodMatcher::parse_method_pattern Reviewed-by: iklam, ihse, kvn --- src/hotspot/share/compiler/methodMatcher.cpp | 26 ++++++++++++++------ 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/src/hotspot/share/compiler/methodMatcher.cpp b/src/hotspot/share/compiler/methodMatcher.cpp index 50cae0430d7..045e1365d34 100644 --- a/src/hotspot/share/compiler/methodMatcher.cpp +++ b/src/hotspot/share/compiler/methodMatcher.cpp @@ -45,16 +45,20 @@ // 0x28 '(' and 0x29 ')' are used for the signature // 0x2e '.' is always replaced before the matching // 0x2f '/' is only used in the class name as package separator +// +// It seems hard to get Non-ASCII characters to work in all circumstances due +// to limitations in Windows. So only ASCII characters are supported on Windows. -#define RANGEBASE "\x1\x2\x3\x4\x5\x6\x7\x8\xa\xb\xc\xd\xe\xf" \ +#define RANGEBASE_ASCII "\x1\x2\x3\x4\x5\x6\x7\x8\xa\xb\xc\xd\xe\xf" \ "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" \ "\x21\x22\x23\x24\x25\x26\x27\x2a\x2b\x2c\x2d" \ "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" \ "\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" \ "\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5c\x5e\x5f" \ "\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" \ - "\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" \ - "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" \ + "\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" + +#define RANGEBASE_NON_ASCII "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" \ "\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" \ "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf" \ "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" \ @@ -62,6 +66,8 @@ "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" \ "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef" +#define RANGEBASE RANGEBASE_ASCII NOT_WINDOWS(RANGEBASE_NON_ASCII) + #define RANGE0 "[*" RANGEBASE "]" #define RANGESLASH "[*" RANGEBASE "/]" @@ -167,6 +173,15 @@ bool MethodMatcher::canonicalize(char * line, const char *& error_msg) { if (*lp == ':') *lp = ' '; } if (*lp == ',' || *lp == '.') *lp = ' '; + +#ifdef _WINDOWS + // It seems hard to get Non-ASCII characters to work in all circumstances due + // to limitations in Windows. So only ASCII characters are supported on Windows. + if (!isascii(*lp)) { + error_msg = "Non-ASCII characters are not supported on Windows."; + return false; + } +#endif } return true; } @@ -240,10 +255,6 @@ void skip_leading_spaces(char*& line, int* total_bytes_read ) { } } -PRAGMA_DIAG_PUSH -// warning C4189: The file contains a character that cannot be represented -// in the current code page -PRAGMA_DISABLE_MSVC_WARNING(4819) void MethodMatcher::parse_method_pattern(char*& line, const char*& error_msg, MethodMatcher* matcher) { MethodMatcher::Mode c_match; MethodMatcher::Mode m_match; @@ -334,7 +345,6 @@ void MethodMatcher::parse_method_pattern(char*& line, const char*& error_msg, Me error_msg = "Could not parse method pattern"; } } -PRAGMA_DIAG_POP bool MethodMatcher::matches(const methodHandle& method) const { Symbol* class_name = method->method_holder()->name(); -- GitLab From 4e960fe53f0948c0b0decfeb13f6dd8f74bf3d6f Mon Sep 17 00:00:00 2001 From: Andrey Turbanov Date: Thu, 7 Oct 2021 03:42:50 +0000 Subject: [PATCH 126/385] 8274497: Unnecessary Vector usage in AquaFileSystemModel Reviewed-by: serb, pbansal --- .../com/apple/laf/AquaFileSystemModel.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/java.desktop/macosx/classes/com/apple/laf/AquaFileSystemModel.java b/src/java.desktop/macosx/classes/com/apple/laf/AquaFileSystemModel.java index 29e947629e3..14aa78ec849 100644 --- a/src/java.desktop/macosx/classes/com/apple/laf/AquaFileSystemModel.java +++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaFileSystemModel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,8 +47,8 @@ class AquaFileSystemModel extends AbstractTableModel implements PropertyChangeLi private Vector files = null; JFileChooser filechooser = null; - Vector fileCache = null; - Object fileCacheLock; + ArrayList fileCache = null; + final Object fileCacheLock; Vector directories = null; int fetchID = 0; @@ -136,7 +136,7 @@ class AquaFileSystemModel extends AbstractTableModel implements PropertyChangeLi synchronized(fileCacheLock) { for (int i = 0; i < fileCache.size(); i++) { - final SortableFile sf = fileCache.elementAt(i); + final SortableFile sf = fileCache.get(i); final File f = sf.fFile; if (filechooser.isTraversable(f)) { directories.addElement(f); @@ -180,7 +180,7 @@ class AquaFileSystemModel extends AbstractTableModel implements PropertyChangeLi // PENDING(jeff) pick the size more sensibly invalidateFileCache(); synchronized(fileCacheLock) { - fileCache = new Vector(50); + fileCache = new ArrayList<>(50); } filesLoader = new FilesLoader(currentDirectory, fetchID); @@ -244,7 +244,7 @@ class AquaFileSystemModel extends AbstractTableModel implements PropertyChangeLi synchronized(fileCacheLock) { if (fileCache != null) { if (!isAscending) row = fileCache.size() - row - 1; - return fileCache.elementAt(row).getValueAt(col); + return fileCache.get(row).getValueAt(col); } return null; } @@ -383,7 +383,7 @@ class AquaFileSystemModel extends AbstractTableModel implements PropertyChangeLi } class FilesLoader implements Runnable { - Vector queuedTasks = new Vector<>(); + ArrayList queuedTasks = new ArrayList<>(); File currentDirectory = null; int fid; Thread loadThread; @@ -473,7 +473,7 @@ class AquaFileSystemModel extends AbstractTableModel implements PropertyChangeLi synchronized(fileCacheLock) { if (fileCache != null) { for (int i = 0; i < contentFiles.size(); i++) { - fileCache.addElement(contentFiles.elementAt(i)); + fileCache.add(contentFiles.elementAt(i)); fireTableRowsInserted(i, i); } } -- GitLab From 5762ec25877ab9207a2fb05888f952690737e318 Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Thu, 7 Oct 2021 07:02:01 +0000 Subject: [PATCH 127/385] 8274780: ChannelInputStream.readNBytes(int) incorrectly calls readAllBytes() Reviewed-by: alanb, bpb --- .../sun/nio/ch/ChannelInputStream.java | 2 +- .../nio/channels/Channels/ReadXBytes.java | 30 +++++++++++++++---- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/src/java.base/share/classes/sun/nio/ch/ChannelInputStream.java b/src/java.base/share/classes/sun/nio/ch/ChannelInputStream.java index b11a4e00ea8..6f312cb9ed2 100644 --- a/src/java.base/share/classes/sun/nio/ch/ChannelInputStream.java +++ b/src/java.base/share/classes/sun/nio/ch/ChannelInputStream.java @@ -168,7 +168,7 @@ public class ChannelInputStream return new byte[0]; if (!(ch instanceof SeekableByteChannel sbc)) - return super.readAllBytes(); + return super.readNBytes(len); long length = sbc.size(); long position = sbc.position(); diff --git a/test/jdk/java/nio/channels/Channels/ReadXBytes.java b/test/jdk/java/nio/channels/Channels/ReadXBytes.java index 8dd303acd5b..19214b9d4fc 100644 --- a/test/jdk/java/nio/channels/Channels/ReadXBytes.java +++ b/test/jdk/java/nio/channels/Channels/ReadXBytes.java @@ -23,25 +23,30 @@ /* * @test - * @bug 8268435 + * @bug 8268435 8274780 * @summary Verify ChannelInputStream methods readAllBytes and readNBytes * @library .. * @library /test/lib * @build jdk.test.lib.RandomFactory * @modules java.base/jdk.internal.util - * @run testng/othervm -Xmx8G ReadXBytes + * @run testng/othervm/timeout=900 -Xmx8G ReadXBytes * @key randomness */ import java.io.File; import java.io.FileInputStream; +import java.io.FilterInputStream; import java.io.InputStream; import java.io.IOException; import java.io.RandomAccessFile; +import java.nio.channels.Channel; import java.nio.channels.Channels; import java.nio.channels.FileChannel; +import java.nio.channels.ReadableByteChannel; +import java.nio.channels.SeekableByteChannel; import java.nio.file.Files; import java.nio.file.Path; import static java.nio.file.StandardOpenOption.READ; +import java.util.List; import java.util.Random; import jdk.internal.util.ArraysSupport; @@ -51,6 +56,7 @@ import org.testng.Assert; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertThrows; +import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertTrue; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; @@ -129,10 +135,22 @@ public class ReadXBytes { public void dataTest(long length, FileCreator c, DataTest f) throws IOException { Path file = c.create(length); - try (FileInputStream fis = new FileInputStream(file.toFile()); - FileChannel fc = FileChannel.open(file, READ); - InputStream cis = Channels.newInputStream(fc)) { - f.test(length, cis, fis); + try { + for (boolean seekable : List.of(false, true)) { + try (FileInputStream fis = new FileInputStream(file.toFile())) { + ReadableByteChannel ch; + if (seekable) { + ch = FileChannel.open(file, READ); + } else { + InputStream fis2 = new FileInputStream(file.toFile()); + ch = Channels.newChannel(new FilterInputStream(fis2) {}); + assertFalse(ch instanceof SeekableByteChannel); + } + try (InputStream cis = Channels.newInputStream(ch)) { + f.test(length, cis, fis); + } + } + } } finally { Files.delete(file); } -- GitLab From 29dcbb72a2d9b224203d92ad3224cf149a7d08de Mon Sep 17 00:00:00 2001 From: Richard Reingruber Date: Thu, 7 Oct 2021 08:20:20 +0000 Subject: [PATCH 128/385] 8274716: JDWP Spec: the description for the Dispose command confuses suspend with resume. Reviewed-by: alanb, cjplummer, sspitsyn --- make/data/jdwp/jdwp.spec | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/make/data/jdwp/jdwp.spec b/make/data/jdwp/jdwp.spec index b55a286aaa1..51fe13cd9ef 100644 --- a/make/data/jdwp/jdwp.spec +++ b/make/data/jdwp/jdwp.spec @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -134,9 +134,9 @@ JDWP "Java(tm) Debug Wire Protocol" "
      " "
    • All event requests are cancelled. " "
    • All threads suspended by the thread-level " - "resume command " + "suspend command " "or the VM-level " - "resume command " + "suspend command " "are resumed as many times as necessary for them to run. " "
    • Garbage collection is re-enabled in all cases where it was " "disabled " -- GitLab From d5ccfa2ae965a9ae0f3597b0b90d702a3e0ea558 Mon Sep 17 00:00:00 2001 From: Andrey Turbanov Date: Thu, 7 Oct 2021 09:38:42 +0000 Subject: [PATCH 129/385] 8274755: Replace 'while' cycles with iterator with enhanced-for in jdk.jdi Reviewed-by: alanb, amenkov, sspitsyn, cjplummer --- .../com/sun/tools/jdi/ConcreteMethodImpl.java | 17 ++++-------- .../com/sun/tools/jdi/ConnectorImpl.java | 5 ++-- .../tools/jdi/EventRequestManagerImpl.java | 17 +++++------- .../com/sun/tools/jdi/InvokableTypeImpl.java | 18 +++++-------- .../com/sun/tools/jdi/ReferenceTypeImpl.java | 27 ++++++++----------- .../classes/com/sun/tools/jdi/TargetVM.java | 24 +++++++---------- .../sun/tools/jdi/ThreadReferenceImpl.java | 6 ++--- .../classes/com/sun/tools/jdi/VMState.java | 6 ++--- .../com/sun/tools/jdi/VirtualMachineImpl.java | 7 ++--- 9 files changed, 46 insertions(+), 81 deletions(-) diff --git a/src/jdk.jdi/share/classes/com/sun/tools/jdi/ConcreteMethodImpl.java b/src/jdk.jdi/share/classes/com/sun/tools/jdi/ConcreteMethodImpl.java index 4ce0f2cae51..9266674ce2a 100644 --- a/src/jdk.jdi/share/classes/com/sun/tools/jdi/ConcreteMethodImpl.java +++ b/src/jdk.jdi/share/classes/com/sun/tools/jdi/ConcreteMethodImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. * 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,8 +37,6 @@ import com.sun.jdi.AbsentInformationException; import com.sun.jdi.LocalVariable; import com.sun.jdi.Location; import com.sun.jdi.VirtualMachine; -import com.sun.tools.jdi.JDWP.Method.VariableTable; -import com.sun.tools.jdi.JDWP.Method.VariableTableWithGeneric; /** * Represents methods with method bodies. @@ -220,9 +218,7 @@ public class ConcreteMethodImpl extends MethodImpl { List variables = getVariables(); List retList = new ArrayList<>(2); - Iterator iter = variables.iterator(); - while(iter.hasNext()) { - LocalVariable variable = iter.next(); + for (LocalVariable variable : variables) { if (variable.name().equals(name)) { retList.add(variable); } @@ -234,9 +230,7 @@ public class ConcreteMethodImpl extends MethodImpl { List variables = getVariables(); List retList = new ArrayList<>(variables.size()); - Iterator iter = variables.iterator(); - while(iter.hasNext()) { - LocalVariable variable = iter.next(); + for (LocalVariable variable : variables) { if (variable.isArgument()) { retList.add(variable); } @@ -289,9 +283,8 @@ public class ConcreteMethodImpl extends MethodImpl { int highestLine = -1; SDE.LineStratum lastLineStratum = null; SDE.Stratum baseStratum = declaringType.stratum(SDE.BASE_STRATUM_NAME); - Iterator it = getBaseLocations().lineLocations.iterator(); - while(it.hasNext()) { - LocationImpl loc = (LocationImpl)it.next(); + for (Location lineLocation : getBaseLocations().lineLocations) { + LocationImpl loc = (LocationImpl)lineLocation; int baseLineNumber = loc.lineNumber(baseStratum); SDE.LineStratum lineStratum = stratum.lineStratum(declaringType, baseLineNumber); diff --git a/src/jdk.jdi/share/classes/com/sun/tools/jdi/ConnectorImpl.java b/src/jdk.jdi/share/classes/com/sun/tools/jdi/ConnectorImpl.java index cadec74b2a0..38d01c6aba8 100644 --- a/src/jdk.jdi/share/classes/com/sun/tools/jdi/ConnectorImpl.java +++ b/src/jdk.jdi/share/classes/com/sun/tools/jdi/ConnectorImpl.java @@ -51,9 +51,8 @@ abstract class ConnectorImpl implements Connector { Map defaults = new LinkedHashMap<>(); Collection values = defaultArguments.values(); - Iterator iter = values.iterator(); - while (iter.hasNext()) { - ArgumentImpl argument = (ArgumentImpl)iter.next(); + for (Argument a : values) { + ArgumentImpl argument = (ArgumentImpl)a; defaults.put(argument.name(), (Argument)argument.clone()); } return defaults; diff --git a/src/jdk.jdi/share/classes/com/sun/tools/jdi/EventRequestManagerImpl.java b/src/jdk.jdi/share/classes/com/sun/tools/jdi/EventRequestManagerImpl.java index ae1acb447c5..e30fb3d3d6f 100644 --- a/src/jdk.jdi/share/classes/com/sun/tools/jdi/EventRequestManagerImpl.java +++ b/src/jdk.jdi/share/classes/com/sun/tools/jdi/EventRequestManagerImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,6 @@ package com.sun.tools.jdi; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; -import java.util.Iterator; import java.util.List; import java.util.Map; @@ -611,9 +610,7 @@ class EventRequestManagerImpl extends MirrorImpl * Make sure this isn't a duplicate */ List requests = stepRequests(); - Iterator iter = requests.iterator(); - while (iter.hasNext()) { - StepRequest request = iter.next(); + for (StepRequest request : requests) { if ((request != this) && request.isEnabled() && request.thread().equals(thread)) { @@ -880,9 +877,8 @@ class EventRequestManagerImpl extends MirrorImpl public void deleteEventRequests(List eventRequests) { validateMirrors(eventRequests); // copy the eventRequests to avoid ConcurrentModificationException - Iterator iter = (new ArrayList<>(eventRequests)).iterator(); - while (iter.hasNext()) { - ((EventRequestImpl)iter.next()).delete(); + for (EventRequest eventRequest : new ArrayList<>(eventRequests)) { + ((EventRequestImpl)eventRequest).delete(); } } @@ -969,9 +965,8 @@ class EventRequestManagerImpl extends MirrorImpl EventRequest request(int eventCmd, int requestId) { List rl = requestList(eventCmd); synchronized(rl) { // Refer Collections.synchronizedList javadoc. - Iterator itr = rl.iterator(); - while (itr.hasNext()){ - EventRequestImpl er = (EventRequestImpl)itr.next(); + for (EventRequest eventRequest : rl) { + EventRequestImpl er = (EventRequestImpl)eventRequest; if (er.id == requestId) return er; } diff --git a/src/jdk.jdi/share/classes/com/sun/tools/jdi/InvokableTypeImpl.java b/src/jdk.jdi/share/classes/com/sun/tools/jdi/InvokableTypeImpl.java index 5d6393d489d..4af22da6f8b 100644 --- a/src/jdk.jdi/share/classes/com/sun/tools/jdi/InvokableTypeImpl.java +++ b/src/jdk.jdi/share/classes/com/sun/tools/jdi/InvokableTypeImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,6 @@ package com.sun.tools.jdi; import java.util.ArrayList; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; @@ -141,9 +140,8 @@ abstract class InvokableTypeImpl extends ReferenceTypeImpl { return true; } else { List interfaces = interfaces(); - Iterator iter = interfaces.iterator(); - while (iter.hasNext()) { - InterfaceTypeImpl interfaze = (InterfaceTypeImpl) iter.next(); + for (InterfaceType interfaceType : interfaces) { + InterfaceTypeImpl interfaze = (InterfaceTypeImpl)interfaceType; if (interfaze.isAssignableTo(type)) { return true; } @@ -159,9 +157,8 @@ abstract class InvokableTypeImpl extends ReferenceTypeImpl { * parent types first, so that the methods in this class will * overwrite them in the hash table */ - Iterator iter = interfaces().iterator(); - while (iter.hasNext()) { - InterfaceTypeImpl interfaze = (InterfaceTypeImpl) iter.next(); + for (InterfaceType interfaceType : interfaces()) { + InterfaceTypeImpl interfaze = (InterfaceTypeImpl)interfaceType; if (!seenInterfaces.contains(interfaze)) { interfaze.addVisibleMethods(methodMap, seenInterfaces); seenInterfaces.add(interfaze); @@ -177,9 +174,8 @@ abstract class InvokableTypeImpl extends ReferenceTypeImpl { final void addInterfaces(List list) { List immediate = interfaces(); list.addAll(interfaces()); - Iterator iter = immediate.iterator(); - while (iter.hasNext()) { - InterfaceTypeImpl interfaze = (InterfaceTypeImpl) iter.next(); + for (InterfaceType interfaceType : immediate) { + InterfaceTypeImpl interfaze = (InterfaceTypeImpl)interfaceType; interfaze.addInterfaces(list); } ClassTypeImpl superclass = (ClassTypeImpl) superclass(); diff --git a/src/jdk.jdi/share/classes/com/sun/tools/jdi/ReferenceTypeImpl.java b/src/jdk.jdi/share/classes/com/sun/tools/jdi/ReferenceTypeImpl.java index 3c3be9adbe6..96aba339f4b 100644 --- a/src/jdk.jdi/share/classes/com/sun/tools/jdi/ReferenceTypeImpl.java +++ b/src/jdk.jdi/share/classes/com/sun/tools/jdi/ReferenceTypeImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. * 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,9 +118,8 @@ public abstract class ReferenceTypeImpl extends TypeImpl implements ReferenceTyp // Fetch all methods for the class, check performance impact // Needs no synchronization now, since methods() returns // unmodifiable local data - Iterator it = methods().iterator(); - while (it.hasNext()) { - MethodImpl method = (MethodImpl)it.next(); + for (Method m : methods()) { + MethodImpl method = (MethodImpl)m; if (method.ref() == ref) { return method; } @@ -132,9 +131,8 @@ public abstract class ReferenceTypeImpl extends TypeImpl implements ReferenceTyp // Fetch all fields for the class, check performance impact // Needs no synchronization now, since fields() returns // unmodifiable local data - Iteratorit = fields().iterator(); - while (it.hasNext()) { - FieldImpl field = (FieldImpl)it.next(); + for (Field f : fields()) { + FieldImpl field = (FieldImpl)f; if (field.ref() == ref) { return field; } @@ -420,12 +418,11 @@ public abstract class ReferenceTypeImpl extends TypeImpl implements ReferenceTyp /* Add inherited, visible fields */ List types = inheritedTypes(); - Iterator iter = types.iterator(); - while (iter.hasNext()) { + for (ReferenceType referenceType : types) { /* * TO DO: Be defensive and check for cyclic interface inheritance */ - ReferenceTypeImpl type = (ReferenceTypeImpl)iter.next(); + ReferenceTypeImpl type = (ReferenceTypeImpl)referenceType; type.addVisibleFields(visibleList, visibleTable, ambiguousNames); } @@ -454,9 +451,8 @@ public abstract class ReferenceTypeImpl extends TypeImpl implements ReferenceTyp /* Add inherited fields */ List types = inheritedTypes(); - Iterator iter = types.iterator(); - while (iter.hasNext()) { - ReferenceTypeImpl type = (ReferenceTypeImpl)iter.next(); + for (ReferenceType referenceType : types) { + ReferenceTypeImpl type = (ReferenceTypeImpl)referenceType; type.addAllFields(fieldList, typeSet); } } @@ -916,9 +912,8 @@ public abstract class ReferenceTypeImpl extends TypeImpl implements ReferenceTyp List list = new ArrayList(); - Iterator iter = methods.iterator(); - while(iter.hasNext()) { - MethodImpl method = (MethodImpl)iter.next(); + for (Method m : methods) { + MethodImpl method = (MethodImpl)m; // eliminate native and abstract to eliminate // false positives if (!method.isAbstract() && diff --git a/src/jdk.jdi/share/classes/com/sun/tools/jdi/TargetVM.java b/src/jdk.jdi/share/classes/com/sun/tools/jdi/TargetVM.java index 8a33c23a70c..29287f0ae4a 100644 --- a/src/jdk.jdi/share/classes/com/sun/tools/jdi/TargetVM.java +++ b/src/jdk.jdi/share/classes/com/sun/tools/jdi/TargetVM.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +29,6 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; -import java.util.Iterator; import java.util.List; import java.util.Map; @@ -187,19 +186,16 @@ public class TargetVM implements Runnable { // Closing a queue causes a VMDisconnectEvent to // be put onto the queue. synchronized(eventQueues) { - Iterator iter = eventQueues.iterator(); - while (iter.hasNext()) { - ((EventQueueImpl)iter.next()).close(); + for (EventQueue eventQueue : eventQueues) { + ((EventQueueImpl)eventQueue).close(); } } // indirectly throw VMDisconnectedException to // command requesters. synchronized(waitingQueue) { - Iterator iter = waitingQueue.values().iterator(); - while (iter.hasNext()) { - Packet packet = iter.next(); - synchronized(packet) { + for (Packet packet : waitingQueue.values()) { + synchronized (packet) { packet.notify(); } } @@ -258,9 +254,8 @@ public class TargetVM implements Runnable { void notifyDequeueEventSet() { int maxQueueSize = 0; synchronized(eventQueues) { - Iterator iter = eventQueues.iterator(); - while (iter.hasNext()) { - EventQueueImpl queue = (EventQueueImpl)iter.next(); + for (EventQueue eventQueue : eventQueues) { + EventQueueImpl queue = (EventQueueImpl)eventQueue; maxQueueSize = Math.max(maxQueueSize, queue.size()); } } @@ -271,9 +266,8 @@ public class TargetVM implements Runnable { int maxQueueSize = 0; synchronized(eventQueues) { - Iterator iter = eventQueues.iterator(); - while (iter.hasNext()) { - EventQueueImpl queue = (EventQueueImpl)iter.next(); + for (EventQueue eventQueue : eventQueues) { + EventQueueImpl queue = (EventQueueImpl)eventQueue; queue.enqueue(eventSet); maxQueueSize = Math.max(maxQueueSize, queue.size()); } diff --git a/src/jdk.jdi/share/classes/com/sun/tools/jdi/ThreadReferenceImpl.java b/src/jdk.jdi/share/classes/com/sun/tools/jdi/ThreadReferenceImpl.java index 6938fad85b1..7540da2e15a 100644 --- a/src/jdk.jdi/share/classes/com/sun/tools/jdi/ThreadReferenceImpl.java +++ b/src/jdk.jdi/share/classes/com/sun/tools/jdi/ThreadReferenceImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -314,9 +314,7 @@ public class ThreadReferenceImpl extends ObjectReferenceImpl StackFrame frame = frame(0); Location location = frame.location(); List requests = vm.eventRequestManager().breakpointRequests(); - Iterator iter = requests.iterator(); - while (iter.hasNext()) { - BreakpointRequest request = iter.next(); + for (BreakpointRequest request : requests) { if (location.equals(request.location())) { return true; } diff --git a/src/jdk.jdi/share/classes/com/sun/tools/jdi/VMState.java b/src/jdk.jdi/share/classes/com/sun/tools/jdi/VMState.java index 8f764c1524e..593c3083b92 100644 --- a/src/jdk.jdi/share/classes/com/sun/tools/jdi/VMState.java +++ b/src/jdk.jdi/share/classes/com/sun/tools/jdi/VMState.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -174,9 +174,7 @@ class VMState { } synchronized boolean hasListener(VMListener listener) { - Iterator> iter = listeners.iterator(); - while (iter.hasNext()) { - WeakReference ref = iter.next(); + for (WeakReference ref : listeners) { if (listener.equals(ref.get())) { return true; } diff --git a/src/jdk.jdi/share/classes/com/sun/tools/jdi/VirtualMachineImpl.java b/src/jdk.jdi/share/classes/com/sun/tools/jdi/VirtualMachineImpl.java index e517dd88d29..e03aca9dbf5 100644 --- a/src/jdk.jdi/share/classes/com/sun/tools/jdi/VirtualMachineImpl.java +++ b/src/jdk.jdi/share/classes/com/sun/tools/jdi/VirtualMachineImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. * 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,6 @@ import com.sun.jdi.ByteType; import com.sun.jdi.ByteValue; import com.sun.jdi.CharType; import com.sun.jdi.CharValue; -import com.sun.jdi.ClassLoaderReference; import com.sun.jdi.ClassNotLoadedException; import com.sun.jdi.DoubleType; import com.sun.jdi.DoubleValue; @@ -1179,9 +1178,7 @@ class VirtualMachineImpl extends MirrorImpl Type findBootType(String signature) throws ClassNotLoadedException { List types = retrieveClassesBySignature(signature); - Iterator iter = types.iterator(); - while (iter.hasNext()) { - ReferenceType type = iter.next(); + for (ReferenceType type : types) { if (type.classLoader() == null) { return type; } -- GitLab From 8319836152cbd0aa5bf6c93d3ba04733cacf83b4 Mon Sep 17 00:00:00 2001 From: Yude Lin Date: Thu, 7 Oct 2021 11:28:49 +0000 Subject: [PATCH 130/385] 8274546: Shenandoah: Remove unused ShenandoahUpdateRootsTask copy Reviewed-by: zgu, tschatzl --- .../shenandoah/shenandoahConcurrentMark.cpp | 27 ------------------- 1 file changed, 27 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp index 214ab73a2a2..ed1ff8c26c7 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp @@ -42,33 +42,6 @@ #include "memory/iterator.inline.hpp" #include "memory/resourceArea.hpp" -class ShenandoahUpdateRootsTask : public AbstractGangTask { -private: - ShenandoahRootUpdater* _root_updater; - bool _check_alive; -public: - ShenandoahUpdateRootsTask(ShenandoahRootUpdater* root_updater, bool check_alive) : - AbstractGangTask("Shenandoah Update Roots"), - _root_updater(root_updater), - _check_alive(check_alive){ - } - - void work(uint worker_id) { - assert(ShenandoahSafepoint::is_at_shenandoah_safepoint(), "Must be at a safepoint"); - ShenandoahParallelWorkerSession worker_session(worker_id); - - ShenandoahHeap* heap = ShenandoahHeap::heap(); - ShenandoahUpdateRefsClosure cl; - if (_check_alive) { - ShenandoahForwardedIsAliveClosure is_alive; - _root_updater->roots_do(worker_id, &is_alive, &cl); - } else { - AlwaysTrueClosure always_true;; - _root_updater->roots_do(worker_id, &always_true, &cl); - } - } -}; - class ShenandoahConcurrentMarkingTask : public AbstractGangTask { private: ShenandoahConcurrentMark* const _cm; -- GitLab From 340c715c3b0f5ad5204f9dddb17a787b07426543 Mon Sep 17 00:00:00 2001 From: Lin Zang Date: Thu, 7 Oct 2021 11:57:18 +0000 Subject: [PATCH 131/385] 8273929: Remove GzipRandomAccess in heap dump test Reviewed-by: cjplummer, sspitsyn --- .../lib/hprof/parser/GzipRandomAccess.java | 577 ------------------ .../lib/jdk/test/lib/hprof/parser/Reader.java | 1 - 2 files changed, 578 deletions(-) delete mode 100644 test/lib/jdk/test/lib/hprof/parser/GzipRandomAccess.java diff --git a/test/lib/jdk/test/lib/hprof/parser/GzipRandomAccess.java b/test/lib/jdk/test/lib/hprof/parser/GzipRandomAccess.java deleted file mode 100644 index 9b86e3451f8..00000000000 --- a/test/lib/jdk/test/lib/hprof/parser/GzipRandomAccess.java +++ /dev/null @@ -1,577 +0,0 @@ -/* - * Copyright (c) 2020 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. - */ -package jdk.test.lib.hprof.parser; - -import java.io.ByteArrayOutputStream; -import java.io.Closeable; -import java.io.EOFException; -import java.io.IOException; -import java.io.InputStream; -import java.io.RandomAccessFile; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.zip.DataFormatException; -import java.util.zip.Inflater; - -public class GzipRandomAccess implements AutoCloseable, Closeable { - // A comparator which compares chunks by their file offset. - private static FileOffsetComparator fileOffsetComp = new FileOffsetComparator(); - - // A comparator which compares chunks by their offset. - private static OffsetComparator offsetComp = new OffsetComparator(); - - // The size to use when reading from the random access file. - private static final int READ_SIZE = 65536; - - // The last used buffer. - private Buffer last; - - // The underlying random access file to use. - private final RandomAccessFile raf; - - // The length of the random access file. - private final long fileSize; - - // The maximum size of a buffer cache. - private final int cacheSize; - - // The maximum numbers of buffers to cache. - private final int maxCachedBuffers; - - // A buffer used to read from the file. - private final byte[] in; - - // A sorted list of the buffers we know so far. - private final ArrayList buffers; - - // The inflater to use. - private final Inflater inf; - - // The head of the list which contains the buffers with cached data. - private final Buffer cacheHead; - - // The number of cached buffers in the list. - private int cachedBuffers; - - // This is private to ensure we only handle the specific hprof gzip files - // written by the VM. - private GzipRandomAccess(String file, int bufferSize, int maxCachedBuffers) - throws IOException { - last = null; - raf = new RandomAccessFile(file, "r"); - fileSize = raf.length(); - this.cacheSize = bufferSize; - this.maxCachedBuffers = maxCachedBuffers; - cachedBuffers = 0; - in = new byte[READ_SIZE]; - buffers = new ArrayList<>(); - inf = new Inflater(true); - cacheHead = new Buffer(-1, -1); - cacheHead.next = cacheHead; - cacheHead.prev = cacheHead; - buffers.add(new Buffer(0, 0)); - } - - /** - * Clears the cache. - */ - public synchronized void clearCache() { - while (cacheHead.next != cacheHead) { - assert cacheHead.next.cache != null; - Buffer buf = cacheHead.next; - remove(buf); - buf.cache = null; - } - - last = null; - cachedBuffers = 0; - } - - /** - * Returns an approximate file offset for the given offset. The return value should - * only be used for progress indication and the like. Note that you should only query - * offsets you've already read. - * - * @param offset The offset. - * @return The approximate file offset. - */ - public synchronized long getFileOffset(long offset) { - int pos = Collections.binarySearch(buffers, new Buffer(0, offset), offsetComp); - int realPos = pos >= 0 ? pos : -pos - 2; - - if (realPos >= buffers.size() - 1) { - return buffers.get(buffers.size() - 1).fileOffset; - } - - // Assume uniform compression. - Buffer buf = buffers.get(realPos); - long diff = offset - buf.offset; - long bufFileEnd = buffers.get(realPos + 1).fileOffset; - long fileDiff = bufFileEnd - buf.fileOffset; - double filePerDiff = (double) Math.max(1, fileDiff) / Math.max(1, buf.cacheLen); - - return buf.fileOffset + (long) (filePerDiff * diff); - } - - /** - * @return Returns the size of the underlying file. - */ - public long getFileSize() { - return fileSize; - } - - /** - * Returns an @link {@link InputStream} to read from the given offset. Note - * that closing the input stream does not close the underlying @link - * {@link GzipRandomAccess} object. - * - * @param offset The offset. - * @return The input stream. - */ - public InputStream asStream(long offset) { - return new InputStreamImpl(offset, this); - } - - /** - * Returns a @link ReadBuffer which uses this object to do the actual - * operation. Note that closing the returned object closes the - * underlying @link {@link GzipRandomAccess} object. - * - * @return The @link ReadBuffer. - */ - public ReadBuffer asFileBuffer() { - return new ReadBufferImpl(this); - } - - /** - * Closes the object and clears the cache. The object is unusable after this - * call. - */ - @Override - public synchronized void close() throws IOException { - clearCache(); - buffers.clear(); - raf.close(); - inf.end(); - } - - /** - * Reads bytes from the gzip file. - * - * @param offset The offset from which to start the read. - * @param b The buffer to read into. - * @param off The offset in the buffer to use. - * @param len The number of bytes to read at most. - * @return The number of bytes read or -1 if we are at the end of the file. - * @throws IOException On error. - */ - public synchronized int read(long offset, byte[] b, int off, int len) throws IOException { - Buffer buf = last; - - while (buf == null || (buf.offset > offset) || (buf.offset + buf.cacheLen <= offset)) { - int pos = Collections.binarySearch(buffers, new Buffer(0, offset), offsetComp); - buf = buffers.get(pos >= 0 ? pos : -pos - 2); - - if (buf.fileOffset >= fileSize) { - return -1; - } - - if (buf.cache != null) { - // If already loaded, move to front of the cache list. - last = buf; - - if (cacheHead.next != buf) { - remove(buf); - addFirst(buf); - } - } else { - try { - // Note that the load will also add the following buffer to the list, - // so the while loop will eventually terminate. - loadBuffer(buf); - } catch (DataFormatException e) { - throw new IOException(e); - } - } - } - - int copyOffset = (int) (offset - buf.offset); - int toCopyMax = buf.cacheLen - copyOffset; - int toCopy = Math.min(toCopyMax, len); - - if (toCopy <= 0) { - return -1; - } - - System.arraycopy(buf.cache, copyOffset, b, off, toCopy); - - return toCopy; - } - - /** - * Returns the access object for the given file or null if not - * supported for the file. - * - * @param file The file name. - * @param cacheSizeInMB The size of the cache to use in megabytes. - * @return The access object or null. - */ - public static GzipRandomAccess getAccess(String file, int cacheSizeInMB) - throws IOException { - try (RandomAccessFile raf = new RandomAccessFile(file, "r")) { - int header = raf.readInt(); - - if ((header >>> 8) != 0x1f8b08) { - // No gzip with deflate. - return null; - } - - if ((header & 16) == 0) { - // No comment - return null; - } - - raf.readInt(); // timestamp - raf.readChar(); // Extra flags and os. - - if ((header & 4) != 0) { - // Skip extra flags. - raf.skipBytes(raf.read() + (raf.read() << 256)); - } - - // Skip name - if ((header & 8) != 0) { - while (raf.read() != 0) { - // Wait for the last 0. - } - } - - // Read the comment. - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - int b; - - while ((b = raf.read()) > 0) { - bos.write(b); - } - - // Check if the block size is included in the comment. - String comment = bos.toString("UTF-8"); - String expectedPrefix = "HPROF BLOCKSIZE="; - - if (comment.startsWith(expectedPrefix)) { - String chunkSizeStr = comment.substring(expectedPrefix.length()).split(" ")[0]; - - try { - int chunkSize = Integer.parseInt(chunkSizeStr); - - if (chunkSize > 0) { - long nrOfChunks = Math.max(1000, cacheSizeInMB * 1024L * 1024L / - chunkSize); - - return new GzipRandomAccess(file, chunkSize, (int) nrOfChunks); - } - } catch (NumberFormatException e) { - // Could not parse. - } - } - } - - return null; - } - - // Loads the content of a buffer. If this is the first time the buffer is - // loaded, the next buffer is added too (but not loaded). - private void loadBuffer(Buffer buf) throws IOException, DataFormatException { - // If we have used all caches, take a cache from the least recently used cached buffer. - if (cachedBuffers >= maxCachedBuffers) { - Buffer toRemove = cacheHead.prev; - remove(toRemove); - buf.cache = toRemove.cache; - toRemove.cache = null; - } else { - // Otherwise allocate a new cache. - buf.cache = new byte[cacheSize]; - cachedBuffers += 1; - } - - // Move to front of LRU list. - last = buf; - addFirst(buf); - - // Fill in the cache - inf.reset(); - raf.seek(buf.fileOffset); - - int read = raf.read(in, 0, READ_SIZE); - int inCount = read; - int outCount = 0; - - // Skip header, but check at least a little - if (read < 4) { - throw new IOException("Missing data"); - } - - if ((in[0] != 0x1f) || ((in[1] & 0xff) != 0x8b)) { - throw new IOException("Missing gzip id"); - } - - if (in[2] != 8) { - throw new IOException("Only supports deflate"); - } - - int off = 10; - - // Extras - if ((in[3] & 4) != 0) { - int len = (in[off + 1] & 0xff) * 256 + (in[off] & 0xff); - off += 2 + len; - } - - // Name - if ((in[3] & 8) != 0) { - int len = 0; - - while (in[off + len] != 0) { - ++len; - } - - off += len + 1; - } - - // Comment - if ((in[3] & 16) != 0) { - int len = 0; - - while (in[off + len] != 0) { - ++len; - } - - off += len + 1; - } - - // Header CRC - if ((in[3] & 2) != 0) { - off += 2; - } - - inf.setInput(in, off, read - off); - outCount = inf.inflate(buf.cache, 0, buf.cache.length); - - while (!inf.finished()) { - if (inf.needsInput()) { - read = raf.read(in, 0, READ_SIZE); - inf.setInput(in, 0, read); - inCount += read; - } - - outCount += inf.inflate(buf.cache, outCount, buf.cache.length - outCount); - } - - // Add the following buffer too if needed. - if ((inf.getRemaining() != 0) || (inCount + buf.fileOffset + 8 != fileSize)) { - long nextFileOffset = inCount - inf.getRemaining() + buf.fileOffset + 8 /* CRC */; - long nextOffset = outCount + buf.offset; - - Buffer nextChunk = new Buffer(nextFileOffset, nextOffset); - int pos = Collections.binarySearch(buffers, nextChunk, fileOffsetComp); - - if (pos < 0) { - buffers.add(-pos - 1, nextChunk); - } - } - - buf.cacheLen = outCount; - } - - // Adds the buffer to the front of the LRU list. - private void addFirst(Buffer buf) { - assert buf.next == null; - assert buf.prev == null; - assert buf.cache != null; - - if (cacheHead.prev == cacheHead) { - cacheHead.prev = buf; - } - - cacheHead.next.prev = buf; - buf.next = cacheHead.next; - buf.prev = cacheHead; - cacheHead.next = buf; - } - - // Removes the buffer from the LRU list. - private void remove(Buffer buf) { - assert buf.prev != null; - assert buf.next != null; - assert buf.cache != null; - assert cacheHead.prev != cacheHead; - - buf.prev.next = buf.next; - buf.next.prev = buf.prev; - buf.next = null; - buf.prev = null; - } - - // Represents a gzipped buffer. The gzipped hprof file consists of a list of these buffers. - private static class Buffer { - public byte[] cache; - public int cacheLen; - public final long fileOffset; - public final long offset; - public Buffer next; - public Buffer prev; - - public Buffer(long fileOffset, long offset) { - this.cache = null; - this.cacheLen = 0; - this.fileOffset = fileOffset; - this.offset = offset; - this.next = null; - this.prev = null; - } - } - - // Compares chunks by file offset. - private static class FileOffsetComparator implements Comparator { - - @Override - public int compare(Buffer x, Buffer y) { - return Long.compare(x.fileOffset, y.fileOffset); - } - } - - // Compares chunks by offset. - private static class OffsetComparator implements Comparator { - - @Override - public int compare(Buffer x, Buffer y) { - return Long.compare(x.offset, y.offset); - } - } - - // Implements an InputStream for this object. - private static class InputStreamImpl extends InputStream { - - private long offset; - private final GzipRandomAccess access; - - public InputStreamImpl(long offset, GzipRandomAccess access) { - this.offset = offset; - this.access = access; - } - - @Override - public synchronized int read(byte[] b, int off, int len) throws IOException { - int read = access.read(offset, b, off, len); - - if (read > 0) { - this.offset += read; - } - - return read; - } - - @Override - public int read() throws IOException { - byte[] b = new byte[1]; - int read = read(b, 0, 1); - - if (read != 1) { - return -1; - } - - return b[0] & 0xff; - } - } - - // Implements a ReadBuffer for this object. - public static class ReadBufferImpl implements ReadBuffer { - - private final GzipRandomAccess access; - private final byte[] tmp = new byte[8]; - - public ReadBufferImpl(GzipRandomAccess access) { - this.access = access; - } - - private void readFully(long pos, int len) throws IOException { - int left = len; - int off = 0; - - while (left > 0) { - int read = access.read(pos, tmp, off, left); - - if (read <= 0) { - throw new EOFException("Could not read at " + pos); - } - - left -= read; - off += read; - pos += read; - } - } - - private int readInt(int offset) { - return (((tmp[offset + 0] & 0xff) << 24) | ((tmp[offset + 1] & 0xff) << 16) | - ((tmp[offset + 2] & 0xff) << 8) | (tmp[offset + 3] & 0xff)); - } - - @Override - public void close() throws Exception { - access.close(); - } - - @Override - public char getChar(long pos) throws IOException { - readFully(pos, 2); - return (char) (((tmp[0] & 0xff) << 8) | (tmp[1] & 0xff)); - } - - @Override - public byte getByte(long pos) throws IOException { - readFully(pos, 1); - return tmp[0]; - } - - @Override - public short getShort(long pos) throws IOException { - return (short) getChar(pos); - } - - @Override - public int getInt(long pos) throws IOException { - readFully(pos, 4); - return readInt(0); - } - - @Override - public long getLong(long pos) throws IOException { - readFully(pos, 8); - long i1 = readInt(0); - int i2 = readInt(4); - - return (i1 << 32) | (i2 & 0xffffffffl); - } - } -} diff --git a/test/lib/jdk/test/lib/hprof/parser/Reader.java b/test/lib/jdk/test/lib/hprof/parser/Reader.java index 726fe05d5ff..bfca980a4e1 100644 --- a/test/lib/jdk/test/lib/hprof/parser/Reader.java +++ b/test/lib/jdk/test/lib/hprof/parser/Reader.java @@ -84,7 +84,6 @@ public abstract class Reader { } heapFile = heapFile.substring(0, pos); } - GzipRandomAccess access = null; try (FileInputStream fis = new FileInputStream(heapFile); BufferedInputStream bis = new BufferedInputStream(fis); PositionDataInputStream in = new PositionDataInputStream(bis)) { -- GitLab From 722d639fad2e4fc6eb2aabd427e2719501899cfe Mon Sep 17 00:00:00 2001 From: Jie Fu Date: Thu, 7 Oct 2021 12:42:16 +0000 Subject: [PATCH 132/385] 8274838: runtime/cds/appcds/TestSerialGCWithCDS.java fails on Windows Reviewed-by: iklam, hseigel --- .../jtreg/runtime/cds/appcds/TestSerialGCWithCDS.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/test/hotspot/jtreg/runtime/cds/appcds/TestSerialGCWithCDS.java b/test/hotspot/jtreg/runtime/cds/appcds/TestSerialGCWithCDS.java index a7c8a87961c..aa44720901e 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/TestSerialGCWithCDS.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/TestSerialGCWithCDS.java @@ -97,7 +97,8 @@ public class TestSerialGCWithCDS { // a small SerialGC heap that may be too small. String[] sizes = { "4m", // usually this will success load the archived heap - "2m", // usually this will fail to loade th archived heap, but app can launch + "2m", // usually this will fail to load the archived heap, but app can launch + // or fail with "GC triggered before VM initialization completed" "1m" // usually this will cause VM launch to fail with "Too small maximum heap" }; for (String sz : sizes) { @@ -113,7 +114,12 @@ public class TestSerialGCWithCDS { if (out.getExitValue() == 0) { out.shouldContain(HELLO); } else { - out.shouldContain("Too small maximum heap"); + String output = out.getStdout() + out.getStderr(); + String exp1 = "Too small maximum heap"; + String exp2 = "GC triggered before VM initialization completed"; + if (!output.contains(exp1) && !output.contains(exp2)) { + throw new RuntimeException("Either '" + exp1 + "' or '" + exp2 + "' must be in stdout/stderr \n"); + } } n++; } -- GitLab From 03a8d342b86e720d3cba08d540182b4ab161fba3 Mon Sep 17 00:00:00 2001 From: Sean Coffey Date: Thu, 7 Oct 2021 15:12:13 +0000 Subject: [PATCH 133/385] 8273826: Correct Manifest file name and NPE checks Reviewed-by: weijun, hchao, mullan --- .../share/classes/java/util/jar/JarFile.java | 2 +- .../classes/java/util/jar/JarInputStream.java | 2 +- .../classes/java/util/jar/JarVerifier.java | 2 +- .../security/util/ManifestEntryVerifier.java | 21 +-- .../jarsigner/warnings/LowerCaseManifest.java | 121 ++++++++++++++++++ 5 files changed, 137 insertions(+), 11 deletions(-) create mode 100644 test/jdk/sun/security/tools/jarsigner/warnings/LowerCaseManifest.java diff --git a/src/java.base/share/classes/java/util/jar/JarFile.java b/src/java.base/share/classes/java/util/jar/JarFile.java index 703171a631f..b5336c61cb8 100644 --- a/src/java.base/share/classes/java/util/jar/JarFile.java +++ b/src/java.base/share/classes/java/util/jar/JarFile.java @@ -749,7 +749,7 @@ public class JarFile extends ZipFile { } if (mev == null) { mev = new ManifestEntryVerifier - (getManifestFromReference()); + (getManifestFromReference(), jv.manifestName); } if (name.equalsIgnoreCase(MANIFEST_NAME)) { b = jv.manifestRawBytes; diff --git a/src/java.base/share/classes/java/util/jar/JarInputStream.java b/src/java.base/share/classes/java/util/jar/JarInputStream.java index 3d8c74df683..eb519421732 100644 --- a/src/java.base/share/classes/java/util/jar/JarInputStream.java +++ b/src/java.base/share/classes/java/util/jar/JarInputStream.java @@ -95,7 +95,7 @@ public class JarInputStream extends ZipInputStream { closeEntry(); if (doVerify) { jv = new JarVerifier(e.getName(), bytes); - mev = new ManifestEntryVerifier(man); + mev = new ManifestEntryVerifier(man, jv.manifestName); } return (JarEntry)super.getNextEntry(); } diff --git a/src/java.base/share/classes/java/util/jar/JarVerifier.java b/src/java.base/share/classes/java/util/jar/JarVerifier.java index 5cd640b5e3f..280d64e9d37 100644 --- a/src/java.base/share/classes/java/util/jar/JarVerifier.java +++ b/src/java.base/share/classes/java/util/jar/JarVerifier.java @@ -444,7 +444,7 @@ class JarVerifier { { this.is = Objects.requireNonNull(is); this.jv = jv; - this.mev = new ManifestEntryVerifier(man); + this.mev = new ManifestEntryVerifier(man, jv.manifestName); this.jv.beginEntry(je, mev); this.numLeft = je.getSize(); if (this.numLeft == 0) diff --git a/src/java.base/share/classes/sun/security/util/ManifestEntryVerifier.java b/src/java.base/share/classes/sun/security/util/ManifestEntryVerifier.java index 062190aeddf..43d0e751dee 100644 --- a/src/java.base/share/classes/sun/security/util/ManifestEntryVerifier.java +++ b/src/java.base/share/classes/sun/security/util/ManifestEntryVerifier.java @@ -63,7 +63,9 @@ public class ManifestEntryVerifier { ArrayList manifestHashes; private String name = null; - private Manifest man; + + private final String manifestFileName; // never null + private final Manifest man; private boolean skip = true; @@ -74,11 +76,12 @@ public class ManifestEntryVerifier { /** * Create a new ManifestEntryVerifier object. */ - public ManifestEntryVerifier(Manifest man) + public ManifestEntryVerifier(Manifest man, String manifestFileName) { createdDigests = new HashMap<>(11); digests = new ArrayList<>(); manifestHashes = new ArrayList<>(); + this.manifestFileName = manifestFileName; this.man = man; } @@ -187,7 +190,6 @@ public class ManifestEntryVerifier { * the first time we have verified this object, remove its * code signers from sigFileSigners and place in verifiedSigners. * - * */ public CodeSigner[] verify(Hashtable verifiedSigners, Hashtable sigFileSigners) @@ -209,7 +211,6 @@ public class ManifestEntryVerifier { getParams(verifiedSigners, sigFileSigners); for (int i=0; i < digests.size(); i++) { - MessageDigest digest = digests.get(i); if (params != null) { try { @@ -251,7 +252,8 @@ public class ManifestEntryVerifier { /** * Get constraints parameters for JAR. The constraints should be * checked against all code signers. Returns the parameters, - * or null if the signers for this entry have already been checked. + * or null if the signers for this entry have already been checked + * or there are no signers for this entry. */ private JarConstraintsParameters getParams( Map verifiedSigners, @@ -262,17 +264,20 @@ public class ManifestEntryVerifier { // the signers of the JAR. But if it doesn't then we need to fallback // and check verifiedSigners to see if the signers of this entry have // been checked already. - if (verifiedSigners.containsKey(JarFile.MANIFEST_NAME)) { + if (verifiedSigners.containsKey(manifestFileName)) { if (verifiedSigners.size() > 1) { // this means we already checked it previously return null; } else { return new JarConstraintsParameters( - verifiedSigners.get(JarFile.MANIFEST_NAME)); + verifiedSigners.get(manifestFileName)); } } else { + if (debug != null) { + debug.println(manifestFileName + " not present in verifiedSigners"); + } CodeSigner[] signers = sigFileSigners.get(name); - if (verifiedSigners.containsValue(signers)) { + if (signers == null || verifiedSigners.containsValue(signers)) { return null; } else { return new JarConstraintsParameters(signers); diff --git a/test/jdk/sun/security/tools/jarsigner/warnings/LowerCaseManifest.java b/test/jdk/sun/security/tools/jarsigner/warnings/LowerCaseManifest.java new file mode 100644 index 00000000000..e942462486c --- /dev/null +++ b/test/jdk/sun/security/tools/jarsigner/warnings/LowerCaseManifest.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.util.JarUtils; + +import java.nio.file.*; +import java.security.Security; +import java.util.Collections; + + +/** + * @test + * @bug 8273826 + * @summary Test for signed jar file with lowercase META-INF files + * @library /test/lib ../ + * @build jdk.test.lib.util.JarUtils + * @run main LowerCaseManifest + */ +public class LowerCaseManifest extends Test { + + public static void main(String[] args) throws Throwable { + new LowerCaseManifest().start(); + } + + private void start() throws Throwable { + // create a jar file that contains one class file + Utils.createFiles(FIRST_FILE); + JarUtils.createJar(UNSIGNED_JARFILE, FIRST_FILE); + + // create key pair for jar signing + createAlias(CA_KEY_ALIAS, "-ext", "bc:c"); + createAlias(KEY_ALIAS); + + issueCert(KEY_ALIAS); + + // sign jar + OutputAnalyzer analyzer = jarsigner( + "-keystore", KEYSTORE, + "-verbose", + "-storepass", PASSWORD, + "-keypass", PASSWORD, + "-signedjar", SIGNED_JARFILE, + UNSIGNED_JARFILE, + KEY_ALIAS); + + checkSigning(analyzer); + + // verify signed jar + analyzer = jarsigner( + "-verify", + "-verbose", + "-keystore", KEYSTORE, + "-storepass", PASSWORD, + "-keypass", PASSWORD, + SIGNED_JARFILE, + KEY_ALIAS); + + checkVerifying(analyzer, 0, JAR_VERIFIED); + + // verify signed jar in strict mode + analyzer = jarsigner( + "-verify", + "-verbose", + "-strict", + "-keystore", KEYSTORE, + "-storepass", PASSWORD, + "-keypass", PASSWORD, + SIGNED_JARFILE, + KEY_ALIAS); + + checkVerifying(analyzer, 0, JAR_VERIFIED); + + // convert the META-INF/ files to lower case + FileSystem fs = FileSystems.newFileSystem(Path.of(SIGNED_JARFILE), Collections.emptyMap()); + for (String s : new String[]{"ALIAS.SF", "ALIAS.RSA", "MANIFEST.MF"}) { + Path origPath = fs.getPath("META-INF/" + s); + Path lowerCase = fs.getPath("META-INF/" + s.toLowerCase()); + Files.write(lowerCase, Files.readAllBytes(origPath)); + Files.delete(origPath); + } + fs.close(); + + // verify signed jar in strict mode (with lower case META-INF names in place) + analyzer = jarsigner( + "-verify", + "-verbose", + "-strict", + "-J-Djava.security.debug=jar", + "-keystore", KEYSTORE, + "-storepass", PASSWORD, + "-keypass", PASSWORD, + SIGNED_JARFILE, + KEY_ALIAS); + + checkVerifying(analyzer, 0, + JAR_VERIFIED, "!not present in verifiedSigners"); + System.out.println("Test passed"); + } + +} -- GitLab From 4ab274ac1a241b2d63f46084ec23aa7cff4bc28e Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Thu, 7 Oct 2021 15:24:00 +0000 Subject: [PATCH 134/385] 8274858: Remove unused dictionary_classes_do functions Reviewed-by: dholmes, hseigel --- .../share/classfile/classLoaderDataGraph.cpp | 17 +---------------- .../share/classfile/classLoaderDataGraph.hpp | 7 ------- src/hotspot/share/memory/universe.cpp | 17 +++++++++++------ 3 files changed, 12 insertions(+), 29 deletions(-) diff --git a/src/hotspot/share/classfile/classLoaderDataGraph.cpp b/src/hotspot/share/classfile/classLoaderDataGraph.cpp index 72a1e78838f..c1e672a0c43 100644 --- a/src/hotspot/share/classfile/classLoaderDataGraph.cpp +++ b/src/hotspot/share/classfile/classLoaderDataGraph.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -426,21 +426,6 @@ void ClassLoaderDataGraph::classes_unloading_do(void f(Klass* const)) { while (ClassLoaderData* X = iter.get_next()) \ if (X->dictionary() != NULL) -// Walk classes in the loaded class dictionaries in various forms. -// Only walks the classes defined in this class loader. -void ClassLoaderDataGraph::dictionary_classes_do(void f(InstanceKlass*)) { - FOR_ALL_DICTIONARY(cld) { - cld->dictionary()->classes_do(f); - } -} - -// Only walks the classes defined in this class loader. -void ClassLoaderDataGraph::dictionary_classes_do(void f(InstanceKlass*, TRAPS), TRAPS) { - FOR_ALL_DICTIONARY(cld) { - cld->dictionary()->classes_do(f, CHECK); - } -} - void ClassLoaderDataGraph::verify_dictionary() { FOR_ALL_DICTIONARY(cld) { cld->dictionary()->verify(); diff --git a/src/hotspot/share/classfile/classLoaderDataGraph.hpp b/src/hotspot/share/classfile/classLoaderDataGraph.hpp index ea6bf0129f8..fd5fdca633e 100644 --- a/src/hotspot/share/classfile/classLoaderDataGraph.hpp +++ b/src/hotspot/share/classfile/classLoaderDataGraph.hpp @@ -96,13 +96,6 @@ class ClassLoaderDataGraph : public AllStatic { // Called from VMOperation static void walk_metadata_and_clean_metaspaces(); - // dictionary do - // Iterate over all klasses in dictionary, but - // just the classes from defining class loaders. - static void dictionary_classes_do(void f(InstanceKlass*)); - // Added for initialize_itable_for_klass to handle exceptions. - static void dictionary_classes_do(void f(InstanceKlass*, TRAPS), TRAPS); - // VM_CounterDecay iteration support static InstanceKlass* try_get_next_class(); static void adjust_saved_class(ClassLoaderData* cld); diff --git a/src/hotspot/share/memory/universe.cpp b/src/hotspot/share/memory/universe.cpp index fcc22bdb86f..6c7f5a2fab6 100644 --- a/src/hotspot/share/memory/universe.cpp +++ b/src/hotspot/share/memory/universe.cpp @@ -523,15 +523,20 @@ static void reinitialize_vtables() { } } +static void reinitialize_itables() { -static void initialize_itable_for_klass(InstanceKlass* k) { - k->itable().initialize_itable(); -} - + class ReinitTableClosure : public KlassClosure { + public: + void do_klass(Klass* k) { + if (k->is_instance_klass()) { + InstanceKlass::cast(k)->itable().initialize_itable(); + } + } + }; -static void reinitialize_itables() { MutexLocker mcld(ClassLoaderDataGraph_lock); - ClassLoaderDataGraph::dictionary_classes_do(initialize_itable_for_klass); + ReinitTableClosure cl; + ClassLoaderDataGraph::classes_do(&cl); } -- GitLab From 8ca084617f331b6af934179f3f776c8158da5bba Mon Sep 17 00:00:00 2001 From: Naoto Sato Date: Thu, 7 Oct 2021 15:32:11 +0000 Subject: [PATCH 135/385] 8274407: (tz) Update Timezone Data to 2021c 8274467: TestZoneInfo310.java fails with tzdata2021b 8274468: TimeZoneTest.java fails with tzdata2021b Reviewed-by: rriggs, iris, coffeys --- make/data/tzdata/VERSION | 2 +- make/data/tzdata/africa | 124 ++------ make/data/tzdata/antarctica | 29 +- make/data/tzdata/asia | 26 +- make/data/tzdata/australasia | 117 +++++++- make/data/tzdata/backward | 11 +- make/data/tzdata/europe | 20 +- make/data/tzdata/leapseconds | 8 +- make/data/tzdata/northamerica | 266 ++++++------------ make/data/tzdata/southamerica | 87 +++--- make/data/tzdata/zone.tab | 9 +- .../sun/util/calendar/ZoneInfoFile.java | 8 +- test/jdk/java/util/TimeZone/TimeZoneTest.java | 6 +- 13 files changed, 306 insertions(+), 407 deletions(-) diff --git a/make/data/tzdata/VERSION b/make/data/tzdata/VERSION index 71632a7bb61..b5c971d8979 100644 --- a/make/data/tzdata/VERSION +++ b/make/data/tzdata/VERSION @@ -21,4 +21,4 @@ # or visit www.oracle.com if you need additional information or have any # questions. # -tzdata2021a +tzdata2021c diff --git a/make/data/tzdata/africa b/make/data/tzdata/africa index 5de2e5f4ab1..0f367713ea9 100644 --- a/make/data/tzdata/africa +++ b/make/data/tzdata/africa @@ -53,9 +53,6 @@ # Milne J. Civil time. Geogr J. 1899 Feb;13(2):173-94. # https://www.jstor.org/stable/1774359 # -# A reliable and entertaining source about time zones is -# Derek Howse, Greenwich time and longitude, Philip Wilson Publishers (1997). -# # European-style abbreviations are commonly used along the Mediterranean. # For sub-Saharan Africa abbreviations were less standardized. # Previous editions of this database used WAT, CAT, SAT, and EAT @@ -176,8 +173,9 @@ Zone Africa/Ndjamena 1:00:12 - LMT 1912 # N'Djamena # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Africa/Abidjan -0:16:08 - LMT 1912 0:00 - GMT +Link Africa/Abidjan Africa/Accra # Ghana Link Africa/Abidjan Africa/Bamako # Mali -Link Africa/Abidjan Africa/Banjul # Gambia +Link Africa/Abidjan Africa/Banjul # The Gambia Link Africa/Abidjan Africa/Conakry # Guinea Link Africa/Abidjan Africa/Dakar # Senegal Link Africa/Abidjan Africa/Freetown # Sierra Leone @@ -404,93 +402,8 @@ Zone Africa/Cairo 2:05:09 - LMT 1900 Oct # Gabon # See Africa/Lagos. -# Gambia -# See Africa/Abidjan. - +# The Gambia # Ghana - -# From P Chan (2020-11-20): -# Interpretation Amendment Ordinance, 1915 (No.24 of 1915) [1915-11-02] -# Ordinances of the Gold Coast, Ashanti, Northern Territories 1915, p 69-71 -# https://books.google.com/books?id=ErA-AQAAIAAJ&pg=PA70 -# This Ordinance added "'Time' shall mean Greenwich Mean Time" to the -# Interpretation Ordinance, 1876. -# -# Determination of the Time Ordinance, 1919 (No. 18 of 1919) [1919-11-24] -# Ordinances of the Gold Coast, Ashanti, Northern Territories 1919, p 75-76 -# https://books.google.com/books?id=MbA-AQAAIAAJ&pg=PA75 -# This Ordinance removed the previous definition of time and introduced DST. -# -# Time Determination Ordinance (Cap. 214) -# The Laws of the Gold Coast (including Togoland Under British Mandate) -# Vol. II (1937), p 2328 -# https://books.google.com/books?id=Z7M-AQAAIAAJ&pg=PA2328 -# Revised edition of the 1919 Ordinance. -# -# Time Determination (Amendment) Ordinance, 1940 (No. 9 of 1940) [1940-04-06] -# Annual Volume of the Laws of the Gold Coast: -# Containing All Legislation Enacted During Year 1940, p 22 -# https://books.google.com/books?id=1ao-AQAAIAAJ&pg=PA22 -# This Ordinance changed the forward transition from September to May. -# -# Defence (Time Determination Ordinance Amendment) Regulations, 1942 -# (Regulations No. 6 of 1942) [1942-01-31, commenced on 1942-02-08] -# Annual Volume of the Laws of the Gold Coast: -# Containing All Legislation Enacted During Year 1942, p 48 -# https://books.google.com/books?id=Das-AQAAIAAJ&pg=PA48 -# These regulations advanced the [standard] time by thirty minutes. -# -# Defence (Time Determination Ordinance Amendment (No.2)) Regulations, -# 1942 (Regulations No. 28 of 1942) [1942-04-25] -# Annual Volume of the Laws of the Gold Coast: -# Containing All Legislation Enacted During Year 1942, p 87 -# https://books.google.com/books?id=Das-AQAAIAAJ&pg=PA87 -# These regulations abolished DST and changed the time to GMT+0:30. -# -# Defence (Revocation) (No.4) Regulations, 1945 (Regulations No. 45 of -# 1945) [1945-10-24, commenced on 1946-01-06] -# Annual Volume of the Laws of the Gold Coast: -# Containing All Legislation Enacted During Year 1945, p 256 -# https://books.google.com/books?id=9as-AQAAIAAJ&pg=PA256 -# These regulations revoked the previous two sets of Regulations. -# -# Time Determination (Amendment) Ordinance, 1945 (No. 18 of 1945) [1946-01-06] -# Annual Volume of the Laws of the Gold Coast: -# Containing All Legislation Enacted During Year 1945, p 69 -# https://books.google.com/books?id=9as-AQAAIAAJ&pg=PA69 -# This Ordinance abolished DST. -# -# Time Determination (Amendment) Ordinance, 1950 (No. 26 of 1950) [1950-07-22] -# Annual Volume of the Laws of the Gold Coast: -# Containing All Legislation Enacted During Year 1950, p 35 -# https://books.google.com/books?id=e60-AQAAIAAJ&pg=PA35 -# This Ordinance restored DST but with thirty minutes offset. -# -# Time Determination Ordinance (Cap. 264) -# The Laws of the Gold Coast, Vol. V (1954), p 380 -# https://books.google.com/books?id=Mqc-AQAAIAAJ&pg=PA380 -# Revised edition of the Time Determination Ordinance. -# -# Time Determination (Amendment) Ordinance, 1956 (No. 21 of 1956) [1956-08-29] -# Annual Volume of the Ordinances of the Gold Coast Enacted During the -# Year 1956, p 83 -# https://books.google.com/books?id=VLE-AQAAIAAJ&pg=PA83 -# This Ordinance abolished DST. - -# Rule NAME FROM TO - IN ON AT SAVE LETTER/S -Rule Ghana 1919 only - Nov 24 0:00 0:20 +0020 -Rule Ghana 1920 1942 - Jan 1 2:00 0 GMT -Rule Ghana 1920 1939 - Sep 1 2:00 0:20 +0020 -Rule Ghana 1940 1941 - May 1 2:00 0:20 +0020 -Rule Ghana 1950 1955 - Sep 1 2:00 0:30 +0030 -Rule Ghana 1951 1956 - Jan 1 2:00 0 GMT - -# Zone NAME STDOFF RULES FORMAT [UNTIL] -Zone Africa/Accra -0:00:52 - LMT 1915 Nov 2 - 0:00 Ghana %s 1942 Feb 8 - 0:30 - +0030 1946 Jan 6 - 0:00 Ghana %s - # Guinea # See Africa/Abidjan. @@ -755,7 +668,7 @@ Zone Indian/Mauritius 3:50:00 - LMT 1907 # Port Louis # See Africa/Nairobi. # Morocco -# See the 'europe' file for Spanish Morocco (Africa/Ceuta). +# See Africa/Ceuta for Spanish Morocco. # From Alex Krivenyshev (2008-05-09): # Here is an article that Morocco plan to introduce Daylight Saving Time between @@ -1405,23 +1318,21 @@ Zone Africa/Lagos 0:13:35 - LMT 1905 Jul 1 0:13:35 - LMT 1914 Jan 1 0:30 - +0030 1919 Sep 1 1:00 - WAT -Link Africa/Lagos Africa/Bangui # Central African Republic -Link Africa/Lagos Africa/Brazzaville # Rep. of the Congo -Link Africa/Lagos Africa/Douala # Cameroon -Link Africa/Lagos Africa/Kinshasa # Dem. Rep. of the Congo (west) -Link Africa/Lagos Africa/Libreville # Gabon -Link Africa/Lagos Africa/Luanda # Angola -Link Africa/Lagos Africa/Malabo # Equatorial Guinea -Link Africa/Lagos Africa/Niamey # Niger -Link Africa/Lagos Africa/Porto-Novo # Benin +Link Africa/Lagos Africa/Bangui # Central African Republic +Link Africa/Lagos Africa/Brazzaville # Rep. of the Congo +Link Africa/Lagos Africa/Douala # Cameroon +Link Africa/Lagos Africa/Kinshasa # Dem. Rep. of the Congo (west) +Link Africa/Lagos Africa/Libreville # Gabon +Link Africa/Lagos Africa/Luanda # Angola +Link Africa/Lagos Africa/Malabo # Equatorial Guinea +Link Africa/Lagos Africa/Niamey # Niger +Link Africa/Lagos Africa/Porto-Novo # Benin # Réunion # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Indian/Reunion 3:41:52 - LMT 1911 Jun # Saint-Denis 4:00 - +04 # -# Crozet Islands also observes Réunion time; see the 'antarctica' file. -# # Scattered Islands (Îles Éparses) administered from Réunion are as follows. # The following information about them is taken from # Îles Éparses (, 1997-07-22, @@ -1513,8 +1424,8 @@ Rule SA 1943 1944 - Mar Sun>=15 2:00 0 - Zone Africa/Johannesburg 1:52:00 - LMT 1892 Feb 8 1:30 - SAST 1903 Mar 2:00 SA SAST -Link Africa/Johannesburg Africa/Maseru # Lesotho -Link Africa/Johannesburg Africa/Mbabane # Eswatini +Link Africa/Johannesburg Africa/Maseru # Lesotho +Link Africa/Johannesburg Africa/Mbabane # Eswatini # # Marion and Prince Edward Is # scientific station since 1947 @@ -1550,12 +1461,13 @@ Zone Africa/Khartoum 2:10:08 - LMT 1931 3:00 - EAT 2017 Nov 1 2:00 - CAT +# South Sudan + # From Steffen Thorsen (2021-01-18): # "South Sudan will change its time zone by setting the clock back 1 # hour on February 1, 2021...." # from https://eyeradio.org/south-sudan-adopts-new-time-zone-makuei/ -# South Sudan # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Africa/Juba 2:06:28 - LMT 1931 2:00 Sudan CA%sT 2000 Jan 15 12:00 @@ -1660,7 +1572,7 @@ Rule Tunisia 2005 only - Sep 30 1:00s 0 - Rule Tunisia 2006 2008 - Mar lastSun 2:00s 1:00 S Rule Tunisia 2006 2008 - Oct lastSun 2:00s 0 - -# See Europe/Paris for PMT-related transitions. +# See Europe/Paris commentary for PMT-related transitions. # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Africa/Tunis 0:40:44 - LMT 1881 May 12 0:09:21 - PMT 1911 Mar 11 # Paris Mean Time diff --git a/make/data/tzdata/antarctica b/make/data/tzdata/antarctica index 509fadc29a9..13f024ef9bc 100644 --- a/make/data/tzdata/antarctica +++ b/make/data/tzdata/antarctica @@ -171,7 +171,7 @@ Zone Antarctica/Mawson 0 - -00 1954 Feb 13 # # Alfred Faure, Possession Island, Crozet Islands, -462551+0515152, since 1964; # sealing & whaling stations operated variously 1802/1911+; -# see Indian/Reunion. +# see Asia/Dubai. # # Martin-de-Viviès, Amsterdam Island, -374105+0773155, since 1950 # Port-aux-Français, Kerguelen Islands, -492110+0701303, since 1951; @@ -185,17 +185,7 @@ Zone Indian/Kerguelen 0 - -00 1950 # Port-aux-Français 5:00 - +05 # # year-round base in the main continent -# Dumont d'Urville, Île des Pétrels, -6640+14001, since 1956-11 -# (2005-12-05) -# -# Another base at Port-Martin, 50km east, began operation in 1947. -# It was destroyed by fire on 1952-01-14. -# -# Zone NAME STDOFF RULES FORMAT [UNTIL] -Zone Antarctica/DumontDUrville 0 - -00 1947 - 10:00 - +10 1952 Jan 14 - 0 - -00 1956 Nov - 10:00 - +10 +# Dumont d'Urville - see Pacific/Port_Moresby. # France & Italy - year-round base # Concordia, -750600+1232000, since 2005 @@ -211,20 +201,7 @@ Zone Antarctica/DumontDUrville 0 - -00 1947 # Zuchelli, Terra Nova Bay, -744140+1640647, since 1986 # Japan - year-round bases -# Syowa (also known as Showa), -690022+0393524, since 1957 -# -# From Hideyuki Suzuki (1999-02-06): -# In all Japanese stations, +0300 is used as the standard time. -# -# Syowa station, which is the first antarctic station of Japan, -# was established on 1957-01-29. Since Syowa station is still the main -# station of Japan, it's appropriate for the principal location. -# Zone NAME STDOFF RULES FORMAT [UNTIL] -Zone Antarctica/Syowa 0 - -00 1957 Jan 29 - 3:00 - +03 -# See: -# NIPR Antarctic Research Activities (1999-08-17) -# http://www.nipr.ac.jp/english/ara01.html +# See Asia/Riyadh. # S Korea - year-round base # Jang Bogo, Terra Nova Bay, -743700+1641205 since 2014 diff --git a/make/data/tzdata/asia b/make/data/tzdata/asia index 143d8e8fdc3..a5cee81a42e 100644 --- a/make/data/tzdata/asia +++ b/make/data/tzdata/asia @@ -57,9 +57,6 @@ # Byalokoz EL. New Counting of Time in Russia since July 1, 1919. # (See the 'europe' file for a fuller citation.) # -# A reliable and entertaining source about time zones is -# Derek Howse, Greenwich time and longitude, Philip Wilson Publishers (1997). -# # The following alphabetic abbreviations appear in these tables # (corrections are welcome): # std dst @@ -2257,6 +2254,14 @@ Zone Asia/Tokyo 9:18:59 - LMT 1887 Dec 31 15:00u # From Paul Eggert (2013-12-11): # As Steffen suggested, consider the past 21-month experiment to be DST. +# From Steffen Thorsen (2021-09-24): +# The Jordanian Government announced yesterday that they will start DST +# in February instead of March: +# https://petra.gov.jo/Include/InnerPage.jsp?ID=37683&lang=en&name=en_news (English) +# https://petra.gov.jo/Include/InnerPage.jsp?ID=189969&lang=ar&name=news (Arabic) +# From the Arabic version, it seems to say it would be at midnight +# (assume 24:00) on the last Thursday in February, starting from 2022. + # Rule NAME FROM TO - IN ON AT SAVE LETTER/S Rule Jordan 1973 only - Jun 6 0:00 1:00 S Rule Jordan 1973 1975 - Oct 1 0:00 0 - @@ -2287,8 +2292,9 @@ Rule Jordan 2004 only - Oct 15 0:00s 0 - Rule Jordan 2005 only - Sep lastFri 0:00s 0 - Rule Jordan 2006 2011 - Oct lastFri 0:00s 0 - Rule Jordan 2013 only - Dec 20 0:00 0 - -Rule Jordan 2014 max - Mar lastThu 24:00 1:00 S +Rule Jordan 2014 2021 - Mar lastThu 24:00 1:00 S Rule Jordan 2014 max - Oct lastFri 0:00s 0 - +Rule Jordan 2022 max - Feb lastThu 24:00 1:00 S # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Asia/Amman 2:23:44 - LMT 1931 2:00 Jordan EE%sT @@ -2763,7 +2769,8 @@ Rule NBorneo 1935 1941 - Dec 14 0:00 0 - # # peninsular Malaysia # taken from Mok Ly Yng (2003-10-30) -# http://www.math.nus.edu.sg/aslaksen/teaching/timezone.html +# https://web.archive.org/web/20190822231045/http://www.math.nus.edu.sg/~mathelmr/teaching/timezone.html +# This agrees with Singapore since 1905-06-01. # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Asia/Kuala_Lumpur 6:46:46 - LMT 1901 Jan 1 6:55:25 - SMT 1905 Jun 1 # Singapore M.T. @@ -3523,6 +3530,12 @@ Zone Asia/Hebron 2:20:23 - LMT 1900 Oct # influence of the sources. There is no current abbreviation for DST, # so use "PDT", the usual American style. +# From P Chan (2021-05-10): +# Here's a fairly comprehensive article in Japanese: +# https://wiki.suikawiki.org/n/Philippine%20Time +# From Paul Eggert (2021-05-10): +# The info in the Japanese table has not been absorbed (yet) below. + # Rule NAME FROM TO - IN ON AT SAVE LETTER/S Rule Phil 1936 only - Nov 1 0:00 1:00 D Rule Phil 1937 only - Feb 1 0:00 0 S @@ -3589,12 +3602,13 @@ Link Asia/Qatar Asia/Bahrain # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Asia/Riyadh 3:06:52 - LMT 1947 Mar 14 3:00 - +03 +Link Asia/Riyadh Antarctica/Syowa Link Asia/Riyadh Asia/Aden # Yemen Link Asia/Riyadh Asia/Kuwait # Singapore # taken from Mok Ly Yng (2003-10-30) -# http://www.math.nus.edu.sg/aslaksen/teaching/timezone.html +# https://web.archive.org/web/20190822231045/http://www.math.nus.edu.sg/~mathelmr/teaching/timezone.html # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Asia/Singapore 6:55:25 - LMT 1901 Jan 1 6:55:25 - SMT 1905 Jun 1 # Singapore M.T. diff --git a/make/data/tzdata/australasia b/make/data/tzdata/australasia index e28538e0c84..af72f11e5ae 100644 --- a/make/data/tzdata/australasia +++ b/make/data/tzdata/australasia @@ -487,7 +487,7 @@ Link Pacific/Guam Pacific/Saipan # N Mariana Is # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Pacific/Tarawa 11:32:04 - LMT 1901 # Bairiki 12:00 - +12 -Zone Pacific/Enderbury -11:24:20 - LMT 1901 +Zone Pacific/Kanton 0 - -00 1937 Aug 31 -12:00 - -12 1979 Oct -11:00 - -11 1994 Dec 31 13:00 - +13 @@ -620,13 +620,46 @@ Link Pacific/Auckland Antarctica/McMurdo # was probably like Pacific/Auckland # Cook Is -# From Shanks & Pottenger: +# +# From Alexander Krivenyshev (2021-03-24): +# In 1899 the Cook Islands celebrated Christmas twice to correct the calendar. +# According to the old books, missionaries were unaware of +# the International Date line, when they came from Sydney. +# Thus the Cook Islands were one day ahead.... +# http://nzetc.victoria.ac.nz/tm/scholarly/tei-KloDisc-t1-body-d18.html +# ... Appendix to the Journals of the House of Representatives, 1900 +# https://atojs.natlib.govt.nz/cgi-bin/atojs?a=d&d=AJHR1900-I.2.1.2.3 +# (page 20) +# +# From Michael Deckers (2021-03-24): +# ... in the Cook Island Act of 1915-10-11, online at +# http://www.paclii.org/ck/legis/ck-nz_act/cia1915132/ +# "651. The hour of the day shall in each of the islands included in the +# Cook Islands be determined in accordance with the meridian of that island." +# so that local (mean?) time was still used in Rarotonga (and Niue) in 1915. +# This was changed in the Cook Island Amendment Act of 1952-10-16 ... +# http://www.paclii.org/ck/legis/ck-nz_act/ciaa1952212/ +# "651 (1) The hour of the day in each of the islands included in the Cook +# Islands, other than Niue, shall be determined as if each island were +# situated on the meridian one hundred and fifty-seven degrees thirty minutes +# West of Greenwich. (2) The hour of the day in the Island of Niue shall be +# determined as if that island were situated on the meridian one hundred and +# seventy degrees West of Greenwich." +# This act does not state when it takes effect, so one has to assume it +# applies since 1952-10-16. But there is the possibility that the act just +# legalized prior existing practice, as we had seen with the Guernsey law of +# 1913-06-18 for the switch in 1909-04-19. +# +# From Paul Eggert (2021-03-24): +# Transitions after 1952 are from Shanks & Pottenger. +# # Rule NAME FROM TO - IN ON AT SAVE LETTER/S Rule Cook 1978 only - Nov 12 0:00 0:30 - Rule Cook 1979 1991 - Mar Sun>=1 0:00 0 - Rule Cook 1979 1990 - Oct lastSun 0:00 0:30 - # Zone NAME STDOFF RULES FORMAT [UNTIL] -Zone Pacific/Rarotonga -10:39:04 - LMT 1901 # Avarua +Zone Pacific/Rarotonga 13:20:56 - LMT 1899 Dec 26 # Avarua + -10:39:04 - LMT 1952 Oct 16 -10:30 - -1030 1978 Nov 12 -10:00 Cook -10/-0930 @@ -634,10 +667,18 @@ Zone Pacific/Rarotonga -10:39:04 - LMT 1901 # Avarua # Niue +# See Pacific/Raratonga comments for 1952 transition. +# +# From Tim Parenti (2021-09-13): +# Consecutive contemporaneous editions of The Air Almanac listed -11:20 for +# Niue as of Apr 1964 but -11 as of Aug 1964: +# Apr 1964: https://books.google.com/books?id=_1So677Y5vUC&pg=SL1-PA23 +# Aug 1964: https://books.google.com/books?id=MbJloqd-zyUC&pg=SL1-PA23 +# Without greater specificity, guess 1964-07-01 for this transition. + # Zone NAME STDOFF RULES FORMAT [UNTIL] -Zone Pacific/Niue -11:19:40 - LMT 1901 # Alofi - -11:20 - -1120 1951 - -11:30 - -1130 1978 Oct 1 +Zone Pacific/Niue -11:19:40 - LMT 1952 Oct 16 # Alofi + -11:20 - -1120 1964 Jul -11:00 - -11 # Norfolk @@ -661,6 +702,7 @@ Zone Pacific/Palau -15:02:04 - LMT 1844 Dec 31 # Koror Zone Pacific/Port_Moresby 9:48:40 - LMT 1880 9:48:32 - PMMT 1895 # Port Moresby Mean Time 10:00 - +10 +Link Pacific/Port_Moresby Antarctica/DumontDUrville # # From Paul Eggert (2014-10-13): # Base the Bougainville entry on the Arawa-Kieta region, which appears to have @@ -765,13 +807,17 @@ Link Pacific/Pago_Pago Pacific/Midway # in US minor outlying islands # From Paul Eggert (2014-07-08): # That web page currently lists transitions for 2012/3 and 2013/4. # Assume the pattern instituted in 2012 will continue indefinitely. +# +# From Geoffrey D. Bennett (2021-09-20): +# https://www.mcil.gov.ws/storage/2021/09/MCIL-Scan_20210920_120553.pdf +# DST has been cancelled for this year. # Rule NAME FROM TO - IN ON AT SAVE LETTER/S Rule WS 2010 only - Sep lastSun 0:00 1 - Rule WS 2011 only - Apr Sat>=1 4:00 0 - Rule WS 2011 only - Sep lastSat 3:00 1 - -Rule WS 2012 max - Apr Sun>=1 4:00 0 - -Rule WS 2012 max - Sep lastSun 3:00 1 - +Rule WS 2012 2021 - Apr Sun>=1 4:00 0 - +Rule WS 2012 2020 - Sep lastSun 3:00 1 - # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Pacific/Apia 12:33:04 - LMT 1892 Jul 5 -11:26:56 - LMT 1911 @@ -818,8 +864,8 @@ Rule Tonga 2001 2002 - Jan lastSun 2:00 0 - Rule Tonga 2016 only - Nov Sun>=1 2:00 1:00 - Rule Tonga 2017 only - Jan Sun>=15 3:00 0 - # Zone NAME STDOFF RULES FORMAT [UNTIL] -Zone Pacific/Tongatapu 12:19:20 - LMT 1901 - 12:20 - +1220 1941 +Zone Pacific/Tongatapu 12:19:12 - LMT 1945 Sep 10 + 12:20 - +1220 1961 13:00 - +13 1999 13:00 Tonga +13/+14 @@ -1761,6 +1807,23 @@ Zone Pacific/Wallis 12:15:20 - LMT 1901 # One source for this is page 202 of: Bartky IR. One Time Fits All: # The Campaigns for Global Uniformity (2007). +# Kanton + +# From Paul Eggert (2021-05-27): +# Kiribati's +13 timezone is represented by Kanton, its only populated +# island. (It was formerly spelled "Canton", but Gilbertese lacks "C".) +# Kanton was settled on 1937-08-31 by two British radio operators +# ; +# Americans came the next year and built an airfield, partly to +# establish airline service and perhaps partly anticipating the +# next war. Aside from the war, the airfield was used by commercial +# airlines until long-range jets became standard; although currently +# for emergency use only, China says it is considering rebuilding the +# airfield for high-end niche tourism. Kanton has about two dozen +# people, caretakers who rotate in from the rest of Kiribati in 2-5 +# year shifts, and who use some of the leftover structures +# . + # Kwajalein # From an AP article (1993-08-22): @@ -2044,6 +2107,17 @@ Zone Pacific/Wallis 12:15:20 - LMT 1901 # Tonga +# From Paul Eggert (2021-03-04): +# In 1943 "The standard time kept is 12 hrs. 19 min. 12 sec. fast +# on Greenwich mean time." according to the Admiralty's Hydrographic +# Dept., Pacific Islands Pilot, Vol. II, 7th ed., 1943, p 360. + +# From Michael Deckers (2021-03-03): +# [Ian R Bartky: "One Time Fits All: The Campaigns for Global Uniformity". +# Stanford University Press. 2007. p. 255]: +# On 10 September 1945 Tonga adopted a standard time 12 hours, +# 20 minutes in advance of Greenwich. + # From Paul Eggert (1996-01-22): # Today's _Wall Street Journal_ (p 1) reports that "Tonga has been plotting # to sneak ahead of [New Zealanders] by introducing daylight-saving time." @@ -2072,9 +2146,26 @@ Zone Pacific/Wallis 12:15:20 - LMT 1901 # The Crown Prince, presented an unanswerable argument: "Remember that # on the World Day of Prayer, you would be the first people on Earth # to say your prayers in the morning." - -# From Paul Eggert (2006-03-22): -# Shanks & Pottenger say the transition was on 1968-10-01; go with Mundell. +# +# From Tim Parenti (2021-09-13), per Paul Eggert (2006-03-22) and Michael +# Deckers (2021-03-03): +# Mundell places the transition from +12:20 to +13 in 1941, while Shanks & +# Pottenger say the transition was on 1968-10-01. +# +# The Air Almanac published contemporaneous tables of standard times, +# which listed +12:20 as of Nov 1960 and +13 as of Mar 1961: +# Nov 1960: https://books.google.com/books?id=bVgtWM6kPZUC&pg=SL1-PA19 +# Mar 1961: https://books.google.com/books?id=W2nItAul4g0C&pg=SL1-PA19 +# (Thanks to P Chan for pointing us toward these sources.) +# This agrees with Bartky, who writes that "since 1961 [Tonga's] official time +# has been thirteen hours in advance of Greenwich time" (p. 202) and further +# writes in an endnote that this was because "the legislation was amended" on +# 1960-10-19. (p. 255) +# +# Without greater specificity, presume that Bartky and the Air Almanac point to +# a 1961-01-01 transition, as Tāufaʻāhau Tupou IV was still Crown Prince in +# 1961 and this still jives with the gist of Mundell's telling, and go with +# this over Shanks & Pottenger. # From Eric Ulevik (1999-05-03): # Tonga's director of tourism, who is also secretary of the National Millennium diff --git a/make/data/tzdata/backward b/make/data/tzdata/backward index 48482b74d30..59c125623e2 100644 --- a/make/data/tzdata/backward +++ b/make/data/tzdata/backward @@ -26,8 +26,10 @@ # This file is in the public domain, so clarified as of # 2009-05-17 by Arthur David Olson. -# This file provides links between current names for timezones -# and their old names. Many names changed in late 1993. +# This file provides links from old or merged timezone names to current ones. +# Many names changed in late 1993. Several of these names are +# also present in the file 'backzone', which has data important only +# for pre-1970 timestamps and so is out of scope for tzdb proper. # Link TARGET LINK-NAME Link Africa/Nairobi Africa/Asmera @@ -36,7 +38,7 @@ Link America/Argentina/Catamarca America/Argentina/ComodRivadavia Link America/Adak America/Atka Link America/Argentina/Buenos_Aires America/Buenos_Aires Link America/Argentina/Catamarca America/Catamarca -Link America/Atikokan America/Coral_Harbour +Link America/Panama America/Coral_Harbour Link America/Argentina/Cordoba America/Cordoba Link America/Tijuana America/Ensenada Link America/Indiana/Indianapolis America/Fort_Wayne @@ -51,7 +53,7 @@ Link America/Rio_Branco America/Porto_Acre Link America/Argentina/Cordoba America/Rosario Link America/Tijuana America/Santa_Isabel Link America/Denver America/Shiprock -Link America/Port_of_Spain America/Virgin +Link America/Puerto_Rico America/Virgin Link Pacific/Auckland Antarctica/South_Pole Link Asia/Ashgabat Asia/Ashkhabad Link Asia/Kolkata Asia/Calcutta @@ -126,6 +128,7 @@ Link Pacific/Auckland NZ Link Pacific/Chatham NZ-CHAT Link America/Denver Navajo Link Asia/Shanghai PRC +Link Pacific/Kanton Pacific/Enderbury Link Pacific/Honolulu Pacific/Johnston Link Pacific/Pohnpei Pacific/Ponape Link Pacific/Pago_Pago Pacific/Samoa diff --git a/make/data/tzdata/europe b/make/data/tzdata/europe index eb9056e92d5..87f9a19f7ac 100644 --- a/make/data/tzdata/europe +++ b/make/data/tzdata/europe @@ -91,7 +91,6 @@ # 0:00 GMT BST BDST Greenwich, British Summer # 0:00 GMT IST Greenwich, Irish Summer # 0:00 WET WEST WEMT Western Europe -# 0:19:32.13 AMT* NST* Amsterdam, Netherlands Summer (1835-1937) # 1:00 BST British Standard (1968-1971) # 1:00 IST GMT Irish Standard (1968-) with winter DST # 1:00 CET CEST CEMT Central Europe @@ -1823,6 +1822,10 @@ Zone Europe/Rome 0:49:56 - LMT 1866 Dec 12 1:00 Italy CE%sT 1980 1:00 EU CE%sT +# Kosovo +# See Europe/Belgrade. + + Link Europe/Rome Europe/Vatican Link Europe/Rome Europe/San_Marino @@ -2173,6 +2176,10 @@ Zone Europe/Monaco 0:29:32 - LMT 1892 Jun 1 # The data entries before 1945 are taken from # https://www.staff.science.uu.nl/~gent0113/wettijd/wettijd.htm +# From Paul Eggert (2021-05-09): +# I invented the abbreviations AMT for Amsterdam Mean Time and NST for +# Netherlands Summer Time, used in the Netherlands from 1835 to 1937. + # Rule NAME FROM TO - IN ON AT SAVE LETTER/S Rule Neth 1916 only - May 1 0:00 1:00 NST # Netherlands Summer Time Rule Neth 1916 only - Oct 1 0:00 0 AMT # Amsterdam Mean Time @@ -2399,12 +2406,10 @@ Rule Port 1943 1945 - Aug Sat>=25 22:00s 1:00 S Rule Port 1944 1945 - Apr Sat>=21 22:00s 2:00 M Rule Port 1946 only - Apr Sat>=1 23:00s 1:00 S Rule Port 1946 only - Oct Sat>=1 23:00s 0 - -Rule Port 1947 1949 - Apr Sun>=1 2:00s 1:00 S -Rule Port 1947 1949 - Oct Sun>=1 2:00s 0 - -# Shanks & Pottenger say DST was observed in 1950; go with Whitman. +# Whitman says DST was not observed in 1950; go with Shanks & Pottenger. # Whitman gives Oct lastSun for 1952 on; go with Shanks & Pottenger. -Rule Port 1951 1965 - Apr Sun>=1 2:00s 1:00 S -Rule Port 1951 1965 - Oct Sun>=1 2:00s 0 - +Rule Port 1947 1965 - Apr Sun>=1 2:00s 1:00 S +Rule Port 1947 1965 - Oct Sun>=1 2:00s 0 - Rule Port 1977 only - Mar 27 0:00s 1:00 S Rule Port 1977 only - Sep 25 0:00s 0 - Rule Port 1978 1979 - Apr Sun>=1 0:00s 1:00 S @@ -3706,6 +3711,9 @@ Zone Atlantic/Canary -1:01:36 - LMT 1922 Mar # Las Palmas de Gran C. # # Source: The newspaper "Dagens Nyheter", 1916-10-01, page 7 upper left. +# An extra-special abbreviation style is SET for Swedish Time (svensk +# normaltid) 1879-1899, 3° west of the Stockholm Observatory. + # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Europe/Stockholm 1:12:12 - LMT 1879 Jan 1 1:00:14 - SET 1900 Jan 1 # Swedish Time diff --git a/make/data/tzdata/leapseconds b/make/data/tzdata/leapseconds index 6f1941601d3..cc514561ff1 100644 --- a/make/data/tzdata/leapseconds +++ b/make/data/tzdata/leapseconds @@ -95,11 +95,11 @@ Leap 2016 Dec 31 23:59:60 + S # Any additional leap seconds will come after this. # This Expires line is commented out for now, # so that pre-2020a zic implementations do not reject this file. -#Expires 2021 Dec 28 00:00:00 +#Expires 2022 Jun 28 00:00:00 # POSIX timestamps for the data in this file: #updated 1467936000 (2016-07-08 00:00:00 UTC) -#expires 1640649600 (2021-12-28 00:00:00 UTC) +#expires 1656374400 (2022-06-28 00:00:00 UTC) -# Updated through IERS Bulletin C61 -# File expires on: 28 December 2021 +# Updated through IERS Bulletin C62 +# File expires on: 28 June 2022 diff --git a/make/data/tzdata/northamerica b/make/data/tzdata/northamerica index 610c606c01a..ddd4929b1d4 100644 --- a/make/data/tzdata/northamerica +++ b/make/data/tzdata/northamerica @@ -752,7 +752,11 @@ Zone America/Adak 12:13:22 - LMT 1867 Oct 19 12:44:35 -11:00 US B%sT 1983 Oct 30 2:00 -10:00 US AH%sT 1983 Nov 30 -10:00 US H%sT -# The following switches don't quite make our 1970 cutoff. +# The following switches don't make our 1970 cutoff. +# +# Kiska observed Tokyo date and time during Japanese occupation from +# 1942-06-06 to 1943-07-29, and similarly for Attu from 1942-06-07 to +# 1943-05-29 (all dates American). Both islands are now uninhabited. # # Shanks writes that part of southwest Alaska (e.g. Aniak) # switched from -11:00 to -10:00 on 1968-09-22 at 02:00, @@ -848,6 +852,8 @@ Zone America/Phoenix -7:28:18 - LMT 1883 Nov 18 11:31:42 -7:00 - MST 1967 -7:00 US M%sT 1968 Mar 21 -7:00 - MST +Link America/Phoenix America/Creston + # From Arthur David Olson (1988-02-13): # A writer from the Inter Tribal Council of Arizona, Inc., # notes in private correspondence dated 1987-12-28 that "Presently, only the @@ -1616,24 +1622,7 @@ Zone America/Moncton -4:19:08 - LMT 1883 Dec 9 # From Paul Eggert (2020-01-10): # See America/Toronto for most of Quebec, including Montreal. # See America/Halifax for the Îles de la Madeleine and the Listuguj reserve. -# -# Matthews and Vincent (1998) also write that Quebec east of the -63 -# meridian is supposed to observe AST, but residents as far east as -# Natashquan use EST/EDT, and residents east of Natashquan use AST. -# The Quebec department of justice writes in -# "The situation in Minganie and Basse-Côte-Nord" -# https://www.justice.gouv.qc.ca/en/department/ministre/functions-and-responsabilities/legal-time-in-quebec/the-situation-in-minganie-and-basse-cote-nord/ -# that the coastal strip from just east of Natashquan to Blanc-Sablon -# observes Atlantic standard time all year round. -# This common practice was codified into law as of 2007; see Legal Time Act, -# CQLR c T-5.1 . -# For lack of better info, guess this practice began around 1970, contra to -# Shanks & Pottenger who have this region observing AST/ADT. - -# Zone NAME STDOFF RULES FORMAT [UNTIL] -Zone America/Blanc-Sablon -3:48:28 - LMT 1884 - -4:00 Canada A%sT 1970 - -4:00 - AST +# See America/Puerto_Rico for east of Natashquan. # Ontario @@ -1672,54 +1661,6 @@ Zone America/Blanc-Sablon -3:48:28 - LMT 1884 # time became a comic failure in Orillia. Toronto Star 2017-07-08. # https://www.thestar.com/news/insight/2017/07/08/bold-attempt-at-daylight-saving-time-became-a-comic-failure-in-orillia.html -# From Paul Eggert (1997-10-17): -# Mark Brader writes that an article in the 1997-10-14 Toronto Star -# says that Atikokan, Ontario currently does not observe DST, -# but will vote on 11-10 whether to use EST/EDT. -# He also writes that the Ontario Time Act (1990, Chapter T.9) -# http://www.gov.on.ca/MBS/english/publications/statregs/conttext.html -# says that Ontario east of 90W uses EST/EDT, and west of 90W uses CST/CDT. -# Officially Atikokan is therefore on CST/CDT, and most likely this report -# concerns a non-official time observed as a matter of local practice. -# -# From Paul Eggert (2000-10-02): -# Matthews and Vincent (1998) write that Atikokan, Pickle Lake, and -# New Osnaburgh observe CST all year, that Big Trout Lake observes -# CST/CDT, and that Upsala and Shebandowan observe EST/EDT, all in -# violation of the official Ontario rules. -# -# From Paul Eggert (2006-07-09): -# Chris Walton (2006-07-06) mentioned an article by Stephanie MacLellan in the -# 2005-07-21 Chronicle-Journal, which said: -# -# The clocks in Atikokan stay set on standard time year-round. -# This means they spend about half the time on central time and -# the other half on eastern time. -# -# For the most part, the system works, Mayor Dennis Brown said. -# -# "The majority of businesses in Atikokan deal more with Eastern -# Canada, but there are some that deal with Western Canada," he -# said. "I don't see any changes happening here." -# -# Walton also writes "Supposedly Pickle Lake and Mishkeegogamang -# [New Osnaburgh] follow the same practice." - -# From Garry McKinnon (2006-07-14) via Chris Walton: -# I chatted with a member of my board who has an outstanding memory -# and a long history in Atikokan (and in the telecom industry) and he -# can say for certain that Atikokan has been practicing the current -# time keeping since 1952, at least. - -# From Paul Eggert (2006-07-17): -# Shanks & Pottenger say that Atikokan has agreed with Rainy River -# ever since standard time was introduced, but the information from -# McKinnon sounds more authoritative. For now, assume that Atikokan -# switched to EST immediately after WWII era daylight saving time -# ended. This matches the old (less-populous) America/Coral_Harbour -# entry since our cutoff date of 1970, so we can move -# America/Coral_Harbour to the 'backward' file. - # From Mark Brader (2010-03-06): # # Currently the database has: @@ -1850,6 +1791,7 @@ Zone America/Toronto -5:17:32 - LMT 1895 -5:00 Canada E%sT 1946 -5:00 Toronto E%sT 1974 -5:00 Canada E%sT +Link America/Toronto America/Nassau Zone America/Thunder_Bay -5:57:00 - LMT 1895 -6:00 - CST 1910 -5:00 - EST 1942 @@ -1865,11 +1807,7 @@ Zone America/Rainy_River -6:18:16 - LMT 1895 -6:00 Canada C%sT 1940 Sep 29 -6:00 1:00 CDT 1942 Feb 9 2:00s -6:00 Canada C%sT -Zone America/Atikokan -6:06:28 - LMT 1895 - -6:00 Canada C%sT 1940 Sep 29 - -6:00 1:00 CDT 1942 Feb 9 2:00s - -6:00 Canada C%sT 1945 Sep 30 2:00 - -5:00 - EST +# For Atikokan see America/Panama. # Manitoba @@ -2060,60 +1998,6 @@ Zone America/Edmonton -7:33:52 - LMT 1906 Sep # Shanks & Pottenger write that since 1970 most of this region has # been like Vancouver. # Dawson Creek uses MST. Much of east BC is like Edmonton. -# Matthews and Vincent (1998) write that Creston is like Dawson Creek. - -# It seems though that (re: Creston) is not entirely correct: - -# From Chris Walton (2011-12-01): -# There are two areas within the Canadian province of British Columbia -# that do not currently observe daylight saving: -# a) The Creston Valley (includes the town of Creston and surrounding area) -# b) The eastern half of the Peace River Regional District -# (includes the cities of Dawson Creek and Fort St. John) - -# Earlier this year I stumbled across a detailed article about the time -# keeping history of Creston; it was written by Tammy Hardwick who is the -# manager of the Creston & District Museum. The article was written in May 2009. -# http://www.ilovecreston.com/?p=articles&t=spec&ar=260 -# According to the article, Creston has not changed its clocks since June 1918. -# i.e. Creston has been stuck on UT-7 for 93 years. -# Dawson Creek, on the other hand, changed its clocks as recently as April 1972. - -# Unfortunately the exact date for the time change in June 1918 remains -# unknown and will be difficult to ascertain. I e-mailed Tammy a few months -# ago to ask if Sunday June 2 was a reasonable guess. She said it was just -# as plausible as any other date (in June). She also said that after writing -# the article she had discovered another time change in 1916; this is the -# subject of another article which she wrote in October 2010. -# http://www.creston.museum.bc.ca/index.php?module=comments&uop=view_comment&cm+id=56 - -# Here is a summary of the three clock change events in Creston's history: -# 1. 1884 or 1885: adoption of Mountain Standard Time (GMT-7) -# Exact date unknown -# 2. Oct 1916: switch to Pacific Standard Time (GMT-8) -# Exact date in October unknown; Sunday October 1 is a reasonable guess. -# 3. June 1918: switch to Pacific Daylight Time (GMT-7) -# Exact date in June unknown; Sunday June 2 is a reasonable guess. -# note 1: -# On Oct 27/1918 when daylight saving ended in the rest of Canada, -# Creston did not change its clocks. -# note 2: -# During WWII when the Federal Government legislated a mandatory clock change, -# Creston did not oblige. -# note 3: -# There is no guarantee that Creston will remain on Mountain Standard Time -# (UTC-7) forever. -# The subject was debated at least once this year by the town Council. -# http://www.bclocalnews.com/kootenay_rockies/crestonvalleyadvance/news/116760809.html - -# During a period WWII, summer time (Daylight saying) was mandatory in Canada. -# In Creston, that was handled by shifting the area to PST (-8:00) then applying -# summer time to cause the offset to be -7:00, the same as it had been before -# the change. It can be argued that the timezone abbreviation during this -# period should be PDT rather than MST, but that doesn't seem important enough -# (to anyone) to further complicate the rules. - -# The transition dates (and times) are guesses. # From Matt Johnson (2015-09-21): # Fort Nelson, BC, Canada will cancel DST this year. So while previously they @@ -2167,10 +2051,7 @@ Zone America/Fort_Nelson -8:10:47 - LMT 1884 -8:00 Vanc P%sT 1987 -8:00 Canada P%sT 2015 Mar 8 2:00 -7:00 - MST -Zone America/Creston -7:46:04 - LMT 1884 - -7:00 - MST 1916 Oct 1 - -8:00 - PST 1918 Jun 2 - -7:00 - MST +# For Creston see America/Phoenix. # Northwest Territories, Nunavut, Yukon @@ -2952,64 +2833,61 @@ Zone America/Tijuana -7:48:04 - LMT 1922 Jan 1 0:11:56 # Anguilla # Antigua and Barbuda -# See America/Port_of_Spain. +# See America/Puerto_Rico. -# Bahamas -# -# For 1899 Milne gives -5:09:29.5; round that. -# -# From P Chan (2020-11-27, corrected on 2020-12-02): -# There were two periods of DST observed in 1942-1945: 1942-05-01 -# midnight to 1944-12-31 midnight and 1945-02-01 to 1945-10-17 midnight. -# "midnight" should mean 24:00 from the context. -# -# War Time Order 1942 [1942-05-01] and War Time (No. 2) Order 1942 [1942-09-29] -# Appendix to the Statutes of 7 George VI. and the Year 1942. p 34, 43 -# https://books.google.com/books?id=5rlNAQAAIAAJ&pg=RA3-PA34 -# https://books.google.com/books?id=5rlNAQAAIAAJ&pg=RA3-PA43 -# -# War Time Order 1943 [1943-03-31] and War Time Order 1944 [1943-12-29] -# Appendix to the Statutes of 8 George VI. and the Year 1943. p 9-10, 28-29 -# https://books.google.com/books?id=5rlNAQAAIAAJ&pg=RA4-PA9 -# https://books.google.com/books?id=5rlNAQAAIAAJ&pg=RA4-PA28 -# -# War Time Order 1945 [1945-01-31] and the Order which revoke War Time Order -# 1945 [1945-10-16] Appendix to the Statutes of 9 George VI. and the Year -# 1945. p 160, 247-248 -# https://books.google.com/books?id=5rlNAQAAIAAJ&pg=RA6-PA160 -# https://books.google.com/books?id=5rlNAQAAIAAJ&pg=RA6-PA247 -# -# From Sue Williams (2006-12-07): -# The Bahamas announced about a month ago that they plan to change their DST -# rules to sync with the U.S. starting in 2007.... -# http://www.jonesbahamas.com/?c=45&a=10412 +# The Bahamas +# See America/Toronto. -# Rule NAME FROM TO - IN ON AT SAVE LETTER/S -Rule Bahamas 1942 only - May 1 24:00 1:00 W -Rule Bahamas 1944 only - Dec 31 24:00 0 S -Rule Bahamas 1945 only - Feb 1 0:00 1:00 W -Rule Bahamas 1945 only - Aug 14 23:00u 1:00 P # Peace -Rule Bahamas 1945 only - Oct 17 24:00 0 S -Rule Bahamas 1964 1975 - Oct lastSun 2:00 0 S -Rule Bahamas 1964 1975 - Apr lastSun 2:00 1:00 D -# Zone NAME STDOFF RULES FORMAT [UNTIL] -Zone America/Nassau -5:09:30 - LMT 1912 Mar 2 - -5:00 Bahamas E%sT 1976 - -5:00 US E%sT # Barbados # For 1899 Milne gives -3:58:29.2; round that. +# From P Chan (2020-12-09 and 2020-12-11): +# Standard time of GMT-4 was adopted in 1911. +# Definition of Time Act, 1911 (1911-7) [1911-08-28] +# 1912, Laws of Barbados (5 v.), OCLC Number: 919801291, Vol. 4, Image No. 522 +# 1944, Laws of Barbados (5 v.), OCLC Number: 84548697, Vol. 4, Image No. 122 +# http://llmc.com/browse.aspx?type=2&coll=85&div=297 +# +# DST was observed in 1942-44. +# Defence (Daylight Saving) Regulations, 1942, 1942-04-13 +# Defence (Daylight Saving) (Repeal) Regulations, 1942, 1942-08-22 +# Defence (Daylight Saving) Regulations, 1943, 1943-04-16 +# Defence (Daylight Saving) (Repeal) Regulations, 1943, 1943-09-01 +# Defence (Daylight Saving) Regulations, 1944, 1944-03-21 +# [Defence (Daylight Saving) (Amendment) Regulations 1944, 1944-03-28] +# Defence (Daylight Saving) (Repeal) Regulations, 1944, 1944-08-30 +# +# 1914-, Subsidiary Legis., Annual Vols. OCLC Number: 226290591 +# 1942: Image Nos. 527-528, 555-556 +# 1943: Image Nos. 178-179, 198 +# 1944: Image Nos. 113-115, 129 +# http://llmc.com/titledescfull.aspx?type=2&coll=85&div=297&set=98437 +# +# From Tim Parenti (2021-02-20): +# The transitions below are derived from P Chan's sources, except that the 1977 +# through 1980 transitions are from Shanks & Pottenger since we have no better +# data there. Of particular note, the 1944 DST regulation only advanced the +# time to "exactly three and a half hours later than Greenwich mean time", as +# opposed to "three hours" in the 1942 and 1943 regulations. + # Rule NAME FROM TO - IN ON AT SAVE LETTER/S +Rule Barb 1942 only - Apr 19 5:00u 1:00 D +Rule Barb 1942 only - Aug 31 6:00u 0 S +Rule Barb 1943 only - May 2 5:00u 1:00 D +Rule Barb 1943 only - Sep 5 6:00u 0 S +Rule Barb 1944 only - Apr 10 5:00u 0:30 - +Rule Barb 1944 only - Sep 10 6:00u 0 S Rule Barb 1977 only - Jun 12 2:00 1:00 D Rule Barb 1977 1978 - Oct Sun>=1 2:00 0 S Rule Barb 1978 1980 - Apr Sun>=15 2:00 1:00 D Rule Barb 1979 only - Sep 30 2:00 0 S Rule Barb 1980 only - Sep 25 2:00 0 S # Zone NAME STDOFF RULES FORMAT [UNTIL] -Zone America/Barbados -3:58:29 - LMT 1924 # Bridgetown - -3:58:29 - BMT 1932 # Bridgetown Mean Time +Zone America/Barbados -3:58:29 - LMT 1911 Aug 28 # Bridgetown + -4:00 Barb A%sT 1944 + -4:00 Barb AST/-0330 1945 -4:00 Barb A%sT # Belize @@ -3171,6 +3049,9 @@ Zone Atlantic/Bermuda -4:19:18 - LMT 1890 # Hamilton -4:00 Canada A%sT 1976 -4:00 US A%sT +# Caribbean Netherlands +# See America/Puerto_Rico. + # Cayman Is # See America/Panama. @@ -3399,7 +3280,7 @@ Zone America/Havana -5:29:28 - LMT 1890 -5:00 Cuba C%sT # Dominica -# See America/Port_of_Spain. +# See America/Puerto_Rico. # Dominican Republic @@ -3451,7 +3332,7 @@ Zone America/El_Salvador -5:56:48 - LMT 1921 # San Salvador # Guadeloupe # St Barthélemy # St Martin (French part) -# See America/Port_of_Spain. +# See America/Puerto_Rico. # Guatemala # @@ -3638,7 +3519,7 @@ Zone America/Martinique -4:04:20 - LMT 1890 # Fort-de-France -4:00 - AST # Montserrat -# See America/Port_of_Spain. +# See America/Puerto_Rico. # Nicaragua # @@ -3710,6 +3591,7 @@ Zone America/Managua -5:45:08 - LMT 1890 Zone America/Panama -5:18:08 - LMT 1890 -5:19:36 - CMT 1908 Apr 22 # Colón Mean Time -5:00 - EST +Link America/Panama America/Atikokan Link America/Panama America/Cayman # Puerto Rico @@ -3719,10 +3601,29 @@ Zone America/Puerto_Rico -4:24:25 - LMT 1899 Mar 28 12:00 # San Juan -4:00 - AST 1942 May 3 -4:00 US A%sT 1946 -4:00 - AST +Link America/Puerto_Rico America/Anguilla +Link America/Puerto_Rico America/Antigua +Link America/Puerto_Rico America/Aruba +Link America/Puerto_Rico America/Curacao +Link America/Puerto_Rico America/Blanc-Sablon # Quebec (Lower North Shore) +Link America/Puerto_Rico America/Dominica +Link America/Puerto_Rico America/Grenada +Link America/Puerto_Rico America/Guadeloupe +Link America/Puerto_Rico America/Kralendijk # Caribbean Netherlands +Link America/Puerto_Rico America/Lower_Princes # Sint Maarten +Link America/Puerto_Rico America/Marigot # St Martin (French part) +Link America/Puerto_Rico America/Montserrat +Link America/Puerto_Rico America/Port_of_Spain # Trinidad & Tobago +Link America/Puerto_Rico America/St_Barthelemy # St Barthélemy +Link America/Puerto_Rico America/St_Kitts # St Kitts & Nevis +Link America/Puerto_Rico America/St_Lucia +Link America/Puerto_Rico America/St_Thomas # Virgin Islands (US) +Link America/Puerto_Rico America/St_Vincent +Link America/Puerto_Rico America/Tortola # Virgin Islands (UK) # St Kitts-Nevis # St Lucia -# See America/Port_of_Spain. +# See America/Puerto_Rico. # St Pierre and Miquelon # There are too many St Pierres elsewhere, so we'll use 'Miquelon'. @@ -3733,7 +3634,10 @@ Zone America/Miquelon -3:44:40 - LMT 1911 May 15 # St Pierre -3:00 Canada -03/-02 # St Vincent and the Grenadines -# See America/Port_of_Spain. +# See America/Puerto_Rico. + +# Sint Maarten +# See America/Puerto_Rico. # Turks and Caicos # @@ -3804,8 +3708,8 @@ Zone America/Grand_Turk -4:44:32 - LMT 1890 -5:00 US E%sT # British Virgin Is -# Virgin Is -# See America/Port_of_Spain. +# US Virgin Is +# See America/Puerto_Rico. # Local Variables: diff --git a/make/data/tzdata/southamerica b/make/data/tzdata/southamerica index 566dabfadb4..503ed65f580 100644 --- a/make/data/tzdata/southamerica +++ b/make/data/tzdata/southamerica @@ -597,7 +597,7 @@ Zone America/Argentina/Ushuaia -4:33:12 - LMT 1894 Oct 31 -3:00 - -03 # Aruba -Link America/Curacao America/Aruba +# See America/Puerto_Rico. # Bolivia # Zone NAME STDOFF RULES FORMAT [UNTIL] @@ -1392,35 +1392,14 @@ Zone America/Bogota -4:56:16 - LMT 1884 Mar 13 # no information; probably like America/Bogota # Curaçao - -# Milne gives 4:35:46.9 for Curaçao mean time; round to nearest. -# -# From Paul Eggert (2006-03-22): -# Shanks & Pottenger say that The Bottom and Philipsburg have been at -# -4:00 since standard time was introduced on 1912-03-02; and that -# Kralendijk and Rincon used Kralendijk Mean Time (-4:33:08) from -# 1912-02-02 to 1965-01-01. The former is dubious, since S&P also say -# Saba Island has been like Curaçao. -# This all predates our 1970 cutoff, though. -# -# By July 2007 Curaçao and St Maarten are planned to become -# associated states within the Netherlands, much like Aruba; -# Bonaire, Saba and St Eustatius would become directly part of the -# Netherlands as Kingdom Islands. This won't affect their time zones -# though, as far as we know. +# See America/Puerto_Rico. # -# Zone NAME STDOFF RULES FORMAT [UNTIL] -Zone America/Curacao -4:35:47 - LMT 1912 Feb 12 # Willemstad - -4:30 - -0430 1965 - -4:00 - AST - # From Arthur David Olson (2011-06-15): # use links for places with new iso3166 codes. # The name "Lower Prince's Quarter" is both longer than fourteen characters -# and contains an apostrophe; use "Lower_Princes" below. - -Link America/Curacao America/Lower_Princes # Sint Maarten -Link America/Curacao America/Kralendijk # Caribbean Netherlands +# and contains an apostrophe; use "Lower_Princes".... +# From Paul Eggert (2021-09-29): +# These backward-compatibility links now are in the 'northamerica' file. # Ecuador # @@ -1563,11 +1542,40 @@ Zone America/Cayenne -3:29:20 - LMT 1911 Jul -3:00 - -03 # Guyana + +# From P Chan (2020-11-27): +# https://books.google.com/books?id=5-5CAQAAMAAJ&pg=SA1-PA547 +# The Official Gazette of British Guiana. (New Series.) Vol. XL. July to +# December, 1915, p 1547, lists as several notes: +# "Local Mean Time 3 hours 52 mins. 39 secs. slow of Greenwich Mean Time +# (Georgetown.) From 1st August, 1911, British Guiana Standard Mean Time 4 +# hours slow of Greenwich Mean Time, by notice in Official Gazette on 1st July, +# 1911. From 1st March, 1915, British Guiana Standard Mean Time 3 hours 45 +# mins. 0 secs. slow of Greenwich Mean Time, by notice in Official Gazette on +# 23rd January, 1915." +# +# https://parliament.gov.gy/documents/acts/10923-act_no._27_of_1975_-_interpretation_and_general_clauses_(amendment)_act_1975.pdf +# Interpretation and general clauses (Amendment) Act 1975 (Act No. 27 of 1975) +# [dated 1975-07-31] +# "This Act...shall come into operation on 1st August, 1975." +# "...where any expression of time occurs...the time referred to shall signify +# the standard time of Guyana which shall be three hours behind Greenwich Mean +# Time." +# +# Circular No. 10/1992 dated 1992-03-20 +# https://dps.gov.gy/wp-content/uploads/2018/12/1992-03-20-Circular-010.pdf +# "...cabinet has decided that with effect from Sunday 29th March, 1992, Guyana +# Standard Time would be re-established at 01:00 hours by adjusting the hands +# of the clock back to 24:00 hours." +# Legislated in the Interpretation and general clauses (Amendment) Act 1992 +# (Act No. 6 of 1992) [passed 1992-03-27, published 1992-04-18] +# https://parliament.gov.gy/documents/acts/5885-6_of_1992_interpretation_and_general_clauses_(amendment)_act_1992.pdf + # Zone NAME STDOFF RULES FORMAT [UNTIL] -Zone America/Guyana -3:52:40 - LMT 1915 Mar # Georgetown - -3:45 - -0345 1975 Jul 31 - -3:00 - -03 1991 -# IATA SSIM (1996-06) says -4:00. Assume a 1991 switch. +Zone America/Guyana -3:52:39 - LMT 1911 Aug 1 # Georgetown + -4:00 - -04 1915 Mar 1 + -3:45 - -0345 1975 Aug 1 + -3:00 - -03 1992 Mar 29 1:00 -4:00 - -04 # Paraguay @@ -1708,24 +1716,7 @@ Zone America/Paramaribo -3:40:40 - LMT 1911 -3:00 - -03 # Trinidad and Tobago -# Zone NAME STDOFF RULES FORMAT [UNTIL] -Zone America/Port_of_Spain -4:06:04 - LMT 1912 Mar 2 - -4:00 - AST - -# These all agree with Trinidad and Tobago since 1970. -Link America/Port_of_Spain America/Anguilla -Link America/Port_of_Spain America/Antigua -Link America/Port_of_Spain America/Dominica -Link America/Port_of_Spain America/Grenada -Link America/Port_of_Spain America/Guadeloupe -Link America/Port_of_Spain America/Marigot # St Martin (French part) -Link America/Port_of_Spain America/Montserrat -Link America/Port_of_Spain America/St_Barthelemy # St Barthélemy -Link America/Port_of_Spain America/St_Kitts # St Kitts & Nevis -Link America/Port_of_Spain America/St_Lucia -Link America/Port_of_Spain America/St_Thomas # Virgin Islands (US) -Link America/Port_of_Spain America/St_Vincent -Link America/Port_of_Spain America/Tortola # Virgin Islands (UK) +# See America/Puerto_Rico. # Uruguay # From Paul Eggert (1993-11-18): diff --git a/make/data/tzdata/zone.tab b/make/data/tzdata/zone.tab index 28db0745e08..0420a6934c9 100644 --- a/make/data/tzdata/zone.tab +++ b/make/data/tzdata/zone.tab @@ -26,7 +26,7 @@ # This file is in the public domain, so clarified as of # 2009-05-17 by Arthur David Olson. # -# From Paul Eggert (2018-06-27): +# From Paul Eggert (2021-09-20): # This file is intended as a backward-compatibility aid for older programs. # New programs should use zone1970.tab. This file is like zone1970.tab (see # zone1970.tab's comments), but with the following additional restrictions: @@ -39,6 +39,9 @@ # clocks have agreed since 1970; this is a narrower definition than # that of zone1970.tab. # +# Unlike zone1970.tab, a row's third column can be a Link from +# 'backward' instead of a Zone. +# # This table is intended as an aid for users, to help them select timezones # appropriate for their practical needs. It is not intended to take or # endorse any position on legal or territorial claims. @@ -251,7 +254,7 @@ KE -0117+03649 Africa/Nairobi KG +4254+07436 Asia/Bishkek KH +1133+10455 Asia/Phnom_Penh KI +0125+17300 Pacific/Tarawa Gilbert Islands -KI -0308-17105 Pacific/Enderbury Phoenix Islands +KI -0247-17143 Pacific/Kanton Phoenix Islands KI +0152-15720 Pacific/Kiritimati Line Islands KM -1141+04316 Indian/Comoro KN +1718-06243 America/St_Kitts @@ -414,7 +417,7 @@ TK -0922-17114 Pacific/Fakaofo TL -0833+12535 Asia/Dili TM +3757+05823 Asia/Ashgabat TN +3648+01011 Africa/Tunis -TO -2110-17510 Pacific/Tongatapu +TO -210800-1751200 Pacific/Tongatapu TR +4101+02858 Europe/Istanbul TT +1039-06131 America/Port_of_Spain TV -0831+17913 Pacific/Funafuti diff --git a/src/java.base/share/classes/sun/util/calendar/ZoneInfoFile.java b/src/java.base/share/classes/sun/util/calendar/ZoneInfoFile.java index 721b0ca91de..a25335e7d5e 100644 --- a/src/java.base/share/classes/sun/util/calendar/ZoneInfoFile.java +++ b/src/java.base/share/classes/sun/util/calendar/ZoneInfoFile.java @@ -574,7 +574,7 @@ public final class ZoneInfoFile { // ZoneRulesBuilder adjusts < 0 case (-1, for last, don't have // "<=" case yet) to positive value if not February (it appears // we don't have February cutoff in tzdata table yet) - // Ideally, if JSR310 can just pass in the nagative and + // Ideally, if JSR310 can just pass in the negative and // we can then pass in the dom = -1, dow > 0 into ZoneInfo // // hacking, assume the >=24 is the result of ZRB optimization for @@ -894,12 +894,12 @@ public final class ZoneInfoFile { } // A simple/raw version of j.t.ZoneOffsetTransitionRule + // timeEndOfDay is included in secondOfDay as "86,400" secs. private static class ZoneOffsetTransitionRule { private final int month; private final byte dom; private final int dow; private final int secondOfDay; - private final boolean timeEndOfDay; private final int timeDefinition; private final int standardOffset; private final int offsetBefore; @@ -917,7 +917,6 @@ public final class ZoneInfoFile { this.dom = (byte)(((data & (63 << 22)) >>> 22) - 32); this.dow = dowByte == 0 ? -1 : dowByte; this.secondOfDay = timeByte == 31 ? in.readInt() : timeByte * 3600; - this.timeEndOfDay = timeByte == 24; this.timeDefinition = (data & (3 << 12)) >>> 12; this.standardOffset = stdByte == 255 ? in.readInt() : (stdByte - 128) * 900; @@ -938,9 +937,6 @@ public final class ZoneInfoFile { epochDay = nextOrSame(epochDay, dow); } } - if (timeEndOfDay) { - epochDay += 1; - } int difference = 0; switch (timeDefinition) { case 0: // UTC diff --git a/test/jdk/java/util/TimeZone/TimeZoneTest.java b/test/jdk/java/util/TimeZone/TimeZoneTest.java index 146dbbfd12c..d31d1722b7b 100644 --- a/test/jdk/java/util/TimeZone/TimeZoneTest.java +++ b/test/jdk/java/util/TimeZone/TimeZoneTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,7 @@ * @test * @bug 4028006 4044013 4096694 4107276 4107570 4112869 4130885 7039469 7126465 7158483 * 8008577 8077685 8098547 8133321 8138716 8148446 8151876 8159684 8166875 8181157 - * 8228469 + * 8228469 8274407 * @modules java.base/sun.util.resources * @library /java/text/testlib * @summary test TimeZone @@ -102,7 +102,7 @@ public class TimeZoneTest extends IntlTest public void TestShortZoneIDs() throws Exception { ZoneDescriptor[] JDK_116_REFERENCE_LIST = { - new ZoneDescriptor("MIT", 780, true), + new ZoneDescriptor("MIT", 780, false), // Samoa no longer observes DST starting 2021b new ZoneDescriptor("HST", -600, false), new ZoneDescriptor("AST", -540, true), new ZoneDescriptor("PST", -480, true), -- GitLab From 7de2cf852d75ea6eb039e69067d4e32421283de5 Mon Sep 17 00:00:00 2001 From: Andrey Turbanov Date: Thu, 7 Oct 2021 16:55:45 +0000 Subject: [PATCH 136/385] 8273910: Redundant condition and assignment in java.net.URI Reviewed-by: dfuchs --- src/java.base/share/classes/java/net/URI.java | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/java.base/share/classes/java/net/URI.java b/src/java.base/share/classes/java/net/URI.java index 5df726966db..0485e97e4f7 100644 --- a/src/java.base/share/classes/java/net/URI.java +++ b/src/java.base/share/classes/java/net/URI.java @@ -2207,7 +2207,6 @@ public final class URI ru.authority = child.authority; ru.host = child.host; ru.userInfo = child.userInfo; - ru.host = child.host; ru.port = child.port; ru.path = child.path; } @@ -3490,14 +3489,12 @@ public final class URI if (q <= p) break; l = p; + p = q; + q = scan(p, n, L_ALPHANUM | L_DASH, H_ALPHANUM | H_DASH); if (q > p) { + if (input.charAt(q - 1) == '-') + fail("Illegal character in hostname", q - 1); p = q; - q = scan(p, n, L_ALPHANUM | L_DASH, H_ALPHANUM | H_DASH); - if (q > p) { - if (input.charAt(q - 1) == '-') - fail("Illegal character in hostname", q - 1); - p = q; - } } q = scan(p, n, '.'); if (q <= p) -- GitLab From 920e70701da9699765c993e11feba3cc0fd0362c Mon Sep 17 00:00:00 2001 From: "Daniel D. Daugherty" Date: Thu, 7 Oct 2021 17:14:26 +0000 Subject: [PATCH 137/385] 8274920: ProblemList 2 VectorAPI tests failing due to "assert(!vbox->is_Phi()) failed" Reviewed-by: kvn --- test/hotspot/jtreg/ProblemList-Xcomp.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/hotspot/jtreg/ProblemList-Xcomp.txt b/test/hotspot/jtreg/ProblemList-Xcomp.txt index 0de6561be71..e2fa6527be8 100644 --- a/test/hotspot/jtreg/ProblemList-Xcomp.txt +++ b/test/hotspot/jtreg/ProblemList-Xcomp.txt @@ -38,3 +38,6 @@ vmTestbase/nsk/jvmti/scenarios/sampling/SP07/sp07t002/TestDescription.java 82456 vmTestbase/vm/mlvm/hiddenloader/stress/oome/heap/Test.java 8273095 generic-all serviceability/sa/TestJhsdbJstackMixed.java 8248675 linux-aarch64 + +compiler/vectorapi/VectorCastShape64Test.java 8274855 generic-x64 +compiler/vectorapi/VectorCastShape128Test.java 8274855 generic-x64 -- GitLab From 8de77634c414cc348a6eb7b28fd6339befdb12d7 Mon Sep 17 00:00:00 2001 From: Yumin Qi Date: Thu, 7 Oct 2021 21:33:32 +0000 Subject: [PATCH 138/385] 8273152: Refactor CDS FileMapHeader loading code Reviewed-by: ccheung, iklam --- src/hotspot/share/cds/archiveBuilder.cpp | 4 - src/hotspot/share/cds/cdsConstants.cpp | 20 +- src/hotspot/share/cds/dynamicArchive.cpp | 7 +- src/hotspot/share/cds/filemap.cpp | 305 +++++++++++------- src/hotspot/share/cds/filemap.hpp | 44 ++- src/hotspot/share/include/cds.h | 43 ++- src/hotspot/share/runtime/arguments.cpp | 3 +- .../share/native/libsaproc/ps_core_common.c | 15 +- .../cds/appcds/SharedArchiveConsistency.java | 18 +- .../dynamicArchive/ArchiveConsistency.java | 94 +++++- .../lib/jdk/test/lib/cds/CDSArchiveUtils.java | 146 ++++++--- 11 files changed, 466 insertions(+), 233 deletions(-) diff --git a/src/hotspot/share/cds/archiveBuilder.cpp b/src/hotspot/share/cds/archiveBuilder.cpp index 45b2db20146..cb5c0aeb8c7 100644 --- a/src/hotspot/share/cds/archiveBuilder.cpp +++ b/src/hotspot/share/cds/archiveBuilder.cpp @@ -1128,10 +1128,6 @@ void ArchiveBuilder::write_archive(FileMapInfo* mapinfo, print_region_stats(mapinfo, closed_heap_regions, open_heap_regions); mapinfo->set_requested_base((char*)MetaspaceShared::requested_base_address()); - if (mapinfo->header()->magic() == CDS_DYNAMIC_ARCHIVE_MAGIC) { - mapinfo->set_header_base_archive_name_size(strlen(Arguments::GetSharedArchivePath()) + 1); - mapinfo->set_header_base_archive_is_default(FLAG_IS_DEFAULT(SharedArchiveFile)); - } mapinfo->set_header_crc(mapinfo->compute_header_crc()); // After this point, we should not write any data into mapinfo->header() since this // would corrupt its checksum we have calculated before. diff --git a/src/hotspot/share/cds/cdsConstants.cpp b/src/hotspot/share/cds/cdsConstants.cpp index bb62306b5bd..5d8948b0ee0 100644 --- a/src/hotspot/share/cds/cdsConstants.cpp +++ b/src/hotspot/share/cds/cdsConstants.cpp @@ -31,15 +31,17 @@ #include "utilities/globalDefinitions.hpp" CDSConst CDSConstants::offsets[] = { - { "CDSFileMapHeaderBase::_magic", offset_of(CDSFileMapHeaderBase, _magic) }, - { "CDSFileMapHeaderBase::_crc", offset_of(CDSFileMapHeaderBase, _crc) }, - { "CDSFileMapHeaderBase::_version", offset_of(CDSFileMapHeaderBase, _version) }, - { "CDSFileMapHeaderBase::_space[0]", offset_of(CDSFileMapHeaderBase, _space) }, - { "FileMapHeader::_jvm_ident", offset_of(FileMapHeader, _jvm_ident) }, - { "FileMapHeader::_base_archive_name_size", offset_of(FileMapHeader, _base_archive_name_size) }, - { "CDSFileMapRegion::_crc", offset_of(CDSFileMapRegion, _crc) }, - { "CDSFileMapRegion::_used", offset_of(CDSFileMapRegion, _used) }, - { "DynamicArchiveHeader::_base_region_crc", offset_of(DynamicArchiveHeader, _base_region_crc) } + { "GenericCDSFileMapHeader::_magic", offset_of(GenericCDSFileMapHeader, _magic) }, + { "GenericCDSFileMapHeader::_crc", offset_of(GenericCDSFileMapHeader, _crc) }, + { "GenericCDSFileMapHeader::_version", offset_of(GenericCDSFileMapHeader, _version) }, + { "GenericCDSFileMapHeader::_header_size", offset_of(GenericCDSFileMapHeader, _header_size) }, + { "GenericCDSFileMapHeader::_base_archive_path_offset", offset_of(GenericCDSFileMapHeader, _base_archive_path_offset) }, + { "GenericCDSFileMapHeader::_base_archive_name_size", offset_of(GenericCDSFileMapHeader, _base_archive_name_size) }, + { "CDSFileMapHeaderBase::_space[0]", offset_of(CDSFileMapHeaderBase, _space) }, + { "FileMapHeader::_jvm_ident", offset_of(FileMapHeader, _jvm_ident) }, + { "CDSFileMapRegion::_crc", offset_of(CDSFileMapRegion, _crc) }, + { "CDSFileMapRegion::_used", offset_of(CDSFileMapRegion, _used) }, + { "DynamicArchiveHeader::_base_region_crc", offset_of(DynamicArchiveHeader, _base_region_crc) } }; CDSConst CDSConstants::constants[] = { diff --git a/src/hotspot/share/cds/dynamicArchive.cpp b/src/hotspot/share/cds/dynamicArchive.cpp index d868eb535b8..b3c18e318a8 100644 --- a/src/hotspot/share/cds/dynamicArchive.cpp +++ b/src/hotspot/share/cds/dynamicArchive.cpp @@ -180,14 +180,15 @@ public: void DynamicArchiveBuilder::init_header() { FileMapInfo* mapinfo = new FileMapInfo(false); assert(FileMapInfo::dynamic_info() == mapinfo, "must be"); + FileMapInfo* base_info = FileMapInfo::current_info(); + // header only be available after populate_header + mapinfo->populate_header(base_info->core_region_alignment()); _header = mapinfo->dynamic_header(); - FileMapInfo* base_info = FileMapInfo::current_info(); _header->set_base_header_crc(base_info->crc()); for (int i = 0; i < MetaspaceShared::n_regions; i++) { _header->set_base_region_crc(i, base_info->space_crc(i)); } - _header->populate(base_info, base_info->core_region_alignment()); } void DynamicArchiveBuilder::release_header() { @@ -325,7 +326,7 @@ void DynamicArchiveBuilder::write_archive(char* serialized_data) { size_t file_size = pointer_delta(top, base, sizeof(char)); log_info(cds, dynamic)("Written dynamic archive " PTR_FORMAT " - " PTR_FORMAT - " [" SIZE_FORMAT " bytes header, " SIZE_FORMAT " bytes total]", + " [" UINT32_FORMAT " bytes header, " SIZE_FORMAT " bytes total]", p2i(base), p2i(top), _header->header_size(), file_size); log_info(cds, dynamic)("%d klasses; %d symbols", klasses()->length(), symbols()->length()); diff --git a/src/hotspot/share/cds/filemap.cpp b/src/hotspot/share/cds/filemap.cpp index 9ba4e6ef2bb..1651aef99b0 100644 --- a/src/hotspot/share/cds/filemap.cpp +++ b/src/hotspot/share/cds/filemap.cpp @@ -54,6 +54,7 @@ #include "oops/oop.inline.hpp" #include "prims/jvmtiExport.hpp" #include "runtime/arguments.hpp" +#include "runtime/globals_extension.hpp" #include "runtime/java.hpp" #include "runtime/mutexLocker.hpp" #include "runtime/os.hpp" @@ -169,21 +170,13 @@ template static void get_header_version(char (&header_version) [N]) { FileMapInfo::FileMapInfo(bool is_static) { memset((void*)this, 0, sizeof(FileMapInfo)); _is_static = is_static; - size_t header_size; - if (is_static) { + if (_is_static) { assert(_current_info == NULL, "must be singleton"); // not thread safe _current_info = this; - header_size = sizeof(FileMapHeader); } else { assert(_dynamic_archive_info == NULL, "must be singleton"); // not thread safe _dynamic_archive_info = this; - header_size = sizeof(DynamicArchiveHeader); } - _header = (FileMapHeader*)os::malloc(header_size, mtInternal); - memset((void*)_header, 0, header_size); - _header->set_header_size(header_size); - _header->set_version(INVALID_CDS_ARCHIVE_VERSION); - _header->set_has_platform_or_app_classes(true); _file_offset = 0; _file_open = false; } @@ -199,16 +192,49 @@ FileMapInfo::~FileMapInfo() { } void FileMapInfo::populate_header(size_t core_region_alignment) { - header()->populate(this, core_region_alignment); -} - -void FileMapHeader::populate(FileMapInfo* mapinfo, size_t core_region_alignment) { - if (DynamicDumpSharedSpaces) { - _magic = CDS_DYNAMIC_ARCHIVE_MAGIC; + assert(_header == NULL, "Sanity check"); + size_t c_header_size; + size_t header_size; + size_t base_archive_name_size = 0; + size_t base_archive_path_offset = 0; + if (is_static()) { + c_header_size = sizeof(FileMapHeader); + header_size = c_header_size; } else { - _magic = CDS_ARCHIVE_MAGIC; + // dynamic header including base archive name for non-default base archive + c_header_size = sizeof(DynamicArchiveHeader); + header_size = c_header_size; + if (!FLAG_IS_DEFAULT(SharedArchiveFile)) { + base_archive_name_size = strlen(Arguments::GetSharedArchivePath()) + 1; + header_size += base_archive_name_size; + base_archive_path_offset = c_header_size; + } + } + _header = (FileMapHeader*)os::malloc(header_size, mtInternal); + memset((void*)_header, 0, header_size); + _header->populate(this, + core_region_alignment, + header_size, + base_archive_name_size, + base_archive_path_offset); +} + +void FileMapHeader::populate(FileMapInfo *info, size_t core_region_alignment, + size_t header_size, size_t base_archive_name_size, + size_t base_archive_path_offset) { + // 1. We require _generic_header._magic to be at the beginning of the file + // 2. FileMapHeader also assumes that _generic_header is at the beginning of the file + assert(offset_of(FileMapHeader, _generic_header) == 0, "must be"); + set_header_size((unsigned int)header_size); + set_base_archive_path_offset((unsigned int)base_archive_path_offset); + set_base_archive_name_size((unsigned int)base_archive_name_size); + set_magic(DynamicDumpSharedSpaces ? CDS_DYNAMIC_ARCHIVE_MAGIC : CDS_ARCHIVE_MAGIC); + set_version(CURRENT_CDS_ARCHIVE_VERSION); + + if (!info->is_static() && base_archive_name_size != 0) { + // copy base archive name + copy_base_archive_name(Arguments::GetSharedArchivePath()); } - _version = CURRENT_CDS_ARCHIVE_VERSION; _core_region_alignment = core_region_alignment; _obj_alignment = ObjectAlignmentInBytes; _compact_strings = CompactStrings; @@ -245,22 +271,29 @@ void FileMapHeader::populate(FileMapInfo* mapinfo, size_t core_region_alignment) _requested_base_address = (char*)SharedBaseAddress; _mapped_base_address = (char*)SharedBaseAddress; _allow_archiving_with_java_agent = AllowArchivingWithJavaAgent; - // the following 2 fields will be set in write_header for dynamic archive header - _base_archive_name_size = 0; - _base_archive_is_default = false; if (!DynamicDumpSharedSpaces) { - set_shared_path_table(mapinfo->_shared_path_table); + set_shared_path_table(info->_shared_path_table); CDS_JAVA_HEAP_ONLY(_heap_obj_roots = CompressedOops::encode(HeapShared::roots());) } } +void FileMapHeader::copy_base_archive_name(const char* archive) { + assert(base_archive_name_size() != 0, "_base_archive_name_size not set"); + assert(base_archive_path_offset() != 0, "_base_archive_path_offset not set"); + assert(header_size() > sizeof(*this), "_base_archive_name_size not included in header size?"); + memcpy((char*)this + base_archive_path_offset(), archive, base_archive_name_size()); +} + void FileMapHeader::print(outputStream* st) { ResourceMark rm; - st->print_cr("- magic: 0x%08x", _magic); - st->print_cr("- crc: 0x%08x", _crc); - st->print_cr("- version: %d", _version); + st->print_cr("- magic: 0x%08x", magic()); + st->print_cr("- crc: 0x%08x", crc()); + st->print_cr("- version: %d", version()); + st->print_cr("- header_size: " UINT32_FORMAT, header_size()); + st->print_cr("- base_archive_path_offset: " UINT32_FORMAT, base_archive_path_offset()); + st->print_cr("- base_archive_name_size: " UINT32_FORMAT, base_archive_name_size()); for (int i = 0; i < NUM_CDS_REGIONS; i++) { FileMapRegion* si = space_at(i); @@ -268,7 +301,6 @@ void FileMapHeader::print(outputStream* st) { } st->print_cr("============ end regions ======== "); - st->print_cr("- header_size: " SIZE_FORMAT, _header_size); st->print_cr("- core_region_alignment: " SIZE_FORMAT, _core_region_alignment); st->print_cr("- obj_alignment: %d", _obj_alignment); st->print_cr("- narrow_oop_base: " INTPTR_FORMAT, p2i(_narrow_oop_base)); @@ -283,9 +315,7 @@ void FileMapHeader::print(outputStream* st) { st->print_cr("- cloned_vtables_offset: " SIZE_FORMAT_HEX, _cloned_vtables_offset); st->print_cr("- serialized_data_offset: " SIZE_FORMAT_HEX, _serialized_data_offset); st->print_cr("- heap_end: " INTPTR_FORMAT, p2i(_heap_end)); - st->print_cr("- base_archive_is_default: %d", _base_archive_is_default); st->print_cr("- jvm_ident: %s", _jvm_ident); - st->print_cr("- base_archive_name_size: " SIZE_FORMAT, _base_archive_name_size); st->print_cr("- shared_path_table_offset: " SIZE_FORMAT_HEX, _shared_path_table_offset); st->print_cr("- shared_path_table_size: %d", _shared_path_table_size); st->print_cr("- app_class_paths_start_index: %d", _app_class_paths_start_index); @@ -1012,122 +1042,169 @@ void FileMapInfo::validate_non_existent_class_paths() { } } +// a utility class for checking file header +class FileHeaderHelper { + int _fd; + GenericCDSFileMapHeader _header; + +public: + FileHeaderHelper() { + _fd = -1; + } + + ~FileHeaderHelper() { + if (_fd != -1) { + os::close(_fd); + } + } + + bool initialize(const char* archive_name) { + _fd = os::open(archive_name, O_RDONLY | O_BINARY, 0); + if (_fd < 0) { + return false; + } + return initialize(_fd); + } + + // for an already opened file, do not set _fd + bool initialize(int fd) { + assert(fd != -1, "Archive should be opened"); + size_t size = sizeof(GenericCDSFileMapHeader); + lseek(fd, 0, SEEK_SET); + size_t n = os::read(fd, (void*)&_header, (unsigned int)size); + if (n != size) { + vm_exit_during_initialization("Unable to read generic CDS file map header from shared archive"); + return false; + } + return true; + } + + GenericCDSFileMapHeader* get_generic_file_header() { + return &_header; + } + + bool read_base_archive_name(char** target) { + assert(_fd != -1, "Archive should be open"); + size_t name_size = (size_t)_header._base_archive_name_size; + assert(name_size != 0, "For non-default base archive, name size should be non-zero!"); + *target = NEW_C_HEAP_ARRAY(char, name_size, mtInternal); + lseek(_fd, _header._base_archive_path_offset, SEEK_SET); // position to correct offset. + size_t n = os::read(_fd, *target, (unsigned int)name_size); + if (n != name_size) { + log_info(cds)("Unable to read base archive name from archive"); + FREE_C_HEAP_ARRAY(char, *target); + return false; + } + if (!os::file_exists(*target)) { + log_info(cds)("Base archive %s does not exist", *target); + FREE_C_HEAP_ARRAY(char, *target); + return false; + } + return true; + } +}; + bool FileMapInfo::check_archive(const char* archive_name, bool is_static) { - int fd = os::open(archive_name, O_RDONLY | O_BINARY, 0); - if (fd < 0) { + FileHeaderHelper file_helper; + if (!file_helper.initialize(archive_name)) { // do not vm_exit_during_initialization here because Arguments::init_shared_archive_paths() // requires a shared archive name. The open_for_read() function will log a message regarding // failure in opening a shared archive. return false; } - size_t sz = is_static ? sizeof(FileMapHeader) : sizeof(DynamicArchiveHeader); - void* header = os::malloc(sz, mtInternal); - memset(header, 0, sz); - size_t n = os::read(fd, header, (unsigned int)sz); - if (n != sz) { - os::free(header); - os::close(fd); - vm_exit_during_initialization("Unable to read header from shared archive", archive_name); - return false; - } + GenericCDSFileMapHeader* header = file_helper.get_generic_file_header(); if (is_static) { - FileMapHeader* static_header = (FileMapHeader*)header; - if (static_header->magic() != CDS_ARCHIVE_MAGIC) { - os::free(header); - os::close(fd); + if (header->_magic != CDS_ARCHIVE_MAGIC) { vm_exit_during_initialization("Not a base shared archive", archive_name); return false; } + if (header->_base_archive_path_offset != 0) { + log_info(cds)("_base_archive_path_offset should be 0"); + log_info(cds)("_base_archive_path_offset = " UINT32_FORMAT, header->_base_archive_path_offset); + return false; + } } else { - DynamicArchiveHeader* dynamic_header = (DynamicArchiveHeader*)header; - if (dynamic_header->magic() != CDS_DYNAMIC_ARCHIVE_MAGIC) { - os::free(header); - os::close(fd); + if (header->_magic != CDS_DYNAMIC_ARCHIVE_MAGIC) { vm_exit_during_initialization("Not a top shared archive", archive_name); return false; } + unsigned int name_size = header->_base_archive_name_size; + unsigned int path_offset = header->_base_archive_path_offset; + unsigned int header_size = header->_header_size; + if (path_offset + name_size != header_size) { + log_info(cds)("_header_size should be equal to _base_archive_path_offset plus _base_archive_name_size"); + log_info(cds)(" _base_archive_name_size = " UINT32_FORMAT, name_size); + log_info(cds)(" _base_archive_path_offset = " UINT32_FORMAT, path_offset); + log_info(cds)(" _header_size = " UINT32_FORMAT, header_size); + return false; + } + char* base_name = NULL; + if (!file_helper.read_base_archive_name(&base_name)) { + return false; + } + FREE_C_HEAP_ARRAY(char, base_name); } - os::free(header); - os::close(fd); return true; } bool FileMapInfo::get_base_archive_name_from_header(const char* archive_name, - int* size, char** base_archive_name) { - int fd = os::open(archive_name, O_RDONLY | O_BINARY, 0); - if (fd < 0) { - *size = 0; + char** base_archive_name) { + FileHeaderHelper file_helper; + if (!file_helper.initialize(archive_name)) { return false; } - - // read the header as a dynamic archive header - size_t sz = sizeof(DynamicArchiveHeader); - DynamicArchiveHeader* dynamic_header = (DynamicArchiveHeader*)os::malloc(sz, mtInternal); - size_t n = os::read(fd, dynamic_header, (unsigned int)sz); - if (n != sz) { - fail_continue("Unable to read the file header."); - os::free(dynamic_header); - os::close(fd); + GenericCDSFileMapHeader* header = file_helper.get_generic_file_header(); + if (header->_magic != CDS_DYNAMIC_ARCHIVE_MAGIC) { + // Not a dynamic header, no need to proceed further. return false; } - if (dynamic_header->magic() != CDS_DYNAMIC_ARCHIVE_MAGIC) { - // Not a dynamic header, no need to proceed further. - *size = 0; - os::free(dynamic_header); - os::close(fd); + + if ((header->_base_archive_name_size == 0 && header->_base_archive_path_offset != 0) || + (header->_base_archive_name_size != 0 && header->_base_archive_path_offset == 0)) { + fail_continue("Default base archive not set correct"); return false; } - if (dynamic_header->base_archive_is_default()) { + if (header->_base_archive_name_size == 0 && + header->_base_archive_path_offset == 0) { *base_archive_name = Arguments::get_default_shared_archive_path(); } else { // read the base archive name - size_t name_size = dynamic_header->base_archive_name_size(); - if (name_size == 0) { - os::free(dynamic_header); - os::close(fd); - return false; - } - *base_archive_name = NEW_C_HEAP_ARRAY(char, name_size, mtInternal); - n = os::read(fd, *base_archive_name, (unsigned int)name_size); - if (n != name_size) { - fail_continue("Unable to read the base archive name from the header."); - FREE_C_HEAP_ARRAY(char, *base_archive_name); + if (!file_helper.read_base_archive_name(base_archive_name)) { *base_archive_name = NULL; - os::free(dynamic_header); - os::close(fd); return false; } } - - os::free(dynamic_header); - os::close(fd); return true; } // Read the FileMapInfo information from the file. bool FileMapInfo::init_from_file(int fd) { - size_t sz = is_static() ? sizeof(FileMapHeader) : sizeof(DynamicArchiveHeader); - size_t n = os::read(fd, header(), (unsigned int)sz); - if (n != sz) { + FileHeaderHelper file_helper; + if (!file_helper.initialize(fd)) { fail_continue("Unable to read the file header."); return false; } - - if (!Arguments::has_jimage()) { - FileMapInfo::fail_continue("The shared archive file cannot be used with an exploded module build."); - return false; - } + GenericCDSFileMapHeader* gen_header = file_helper.get_generic_file_header(); unsigned int expected_magic = is_static() ? CDS_ARCHIVE_MAGIC : CDS_DYNAMIC_ARCHIVE_MAGIC; - if (header()->magic() != expected_magic) { + if (gen_header->_magic != expected_magic) { log_info(cds)("_magic expected: 0x%08x", expected_magic); - log_info(cds)(" actual: 0x%08x", header()->magic()); + log_info(cds)(" actual: 0x%08x", gen_header->_magic); FileMapInfo::fail_continue("The shared archive file has a bad magic number."); return false; } + _header = (FileMapHeader*)os::malloc(gen_header->_header_size, mtInternal); + lseek(fd, 0, SEEK_SET); // reset to begin of the archive + size_t size = gen_header->_header_size; + size_t n = os::read(fd, (void*)_header, (unsigned int)size); + if (n != size) { + fail_continue("Failed to read file header from the top archive file\n"); + return false; + } + if (header()->version() != CURRENT_CDS_ARCHIVE_VERSION) { log_info(cds)("_version expected: %d", CURRENT_CDS_ARCHIVE_VERSION); log_info(cds)(" actual: %d", header()->version()); @@ -1135,11 +1212,17 @@ bool FileMapInfo::init_from_file(int fd) { return false; } - if (header()->header_size() != sz) { - log_info(cds)("_header_size expected: " SIZE_FORMAT, sz); - log_info(cds)(" actual: " SIZE_FORMAT, header()->header_size()); - FileMapInfo::fail_continue("The shared archive file has an incorrect header size."); - return false; + unsigned int base_offset = header()->base_archive_path_offset(); + unsigned int name_size = header()->base_archive_name_size(); + unsigned int header_size = header()->header_size(); + if (base_offset != 0 && name_size != 0) { + if (header_size != base_offset + name_size) { + log_info(cds)("_header_size: " UINT32_FORMAT, header_size); + log_info(cds)("base_archive_name_size: " UINT32_FORMAT, name_size); + log_info(cds)("base_archive_path_offset: " UINT32_FORMAT, base_offset); + FileMapInfo::fail_continue("The shared archive file has an incorrect header size."); + return false; + } } const char* actual_ident = header()->jvm_ident(); @@ -1169,7 +1252,7 @@ bool FileMapInfo::init_from_file(int fd) { } } - _file_offset = n + header()->base_archive_name_size(); // accounts for the size of _base_archive_name + _file_offset = header()->header_size(); // accounts for the size of _base_archive_name if (is_static()) { // just checking the last region is sufficient since the archive is written @@ -1253,16 +1336,12 @@ void FileMapInfo::open_for_write(const char* path) { // Seek past the header. We will write the header after all regions are written // and their CRCs computed. size_t header_bytes = header()->header_size(); - if (header()->magic() == CDS_DYNAMIC_ARCHIVE_MAGIC) { - header_bytes += strlen(Arguments::GetSharedArchivePath()) + 1; - } header_bytes = align_up(header_bytes, MetaspaceShared::core_region_alignment()); _file_offset = header_bytes; seek_to_position(_file_offset); } - // Write the header to the file, seek to the next allocation boundary. void FileMapInfo::write_header() { @@ -1270,13 +1349,6 @@ void FileMapInfo::write_header() { seek_to_position(_file_offset); assert(is_file_position_aligned(), "must be"); write_bytes(header(), header()->header_size()); - - if (header()->magic() == CDS_DYNAMIC_ARCHIVE_MAGIC) { - char* base_archive_name = (char*)Arguments::GetSharedArchivePath(); - if (base_archive_name != NULL) { - write_bytes(base_archive_name, header()->base_archive_name_size()); - } - } } size_t FileMapRegion::used_aligned() const { @@ -2220,6 +2292,11 @@ bool FileMapInfo::initialize() { return false; } + if (!Arguments::has_jimage()) { + FileMapInfo::fail_continue("The shared archive file cannot be used with an exploded module build."); + return false; + } + if (!open_for_read()) { return false; } @@ -2258,9 +2335,9 @@ void FileMapHeader::set_as_offset(char* p, size_t *offset) { int FileMapHeader::compute_crc() { char* start = (char*)this; - // start computing from the field after _crc - char* buf = (char*)&_crc + sizeof(_crc); - size_t sz = _header_size - (buf - start); + // start computing from the field after _crc to end of base archive name. + char* buf = (char*)&(_generic_header._crc) + sizeof(_generic_header._crc); + size_t sz = header_size() - (buf - start); int crc = ClassLoader::crc32(0, buf, (jint)sz); return crc; } diff --git a/src/hotspot/share/cds/filemap.hpp b/src/hotspot/share/cds/filemap.hpp index 2fa528e6927..7708bbe7fa5 100644 --- a/src/hotspot/share/cds/filemap.hpp +++ b/src/hotspot/share/cds/filemap.hpp @@ -184,8 +184,6 @@ class FileMapHeader: private CDSFileMapHeaderBase { friend class VMStructs; private: - size_t _header_size; - // The following fields record the states of the VM during dump time. // They are compared with the runtime states to see if the archive // can be used. @@ -203,15 +201,12 @@ private: size_t _serialized_data_offset; // Data accessed using {ReadClosure,WriteClosure}::serialize() address _heap_begin; // heap begin at dump time. address _heap_end; // heap end at dump time. - bool _base_archive_is_default; // indicates if the base archive is the system default one bool _has_non_jar_in_classpath; // non-jar file entry exists in classpath // The following fields are all sanity checks for whether this archive // will function correctly with this JVM and the bootclasspath it's // invoked with. char _jvm_ident[JVM_IDENT_MAX]; // identifier string of the jvm that created this dump - // size of the base archive name including NULL terminator - size_t _base_archive_name_size; // The following is a table of all the boot/app/module path entries that were used // during dumping. At run time, we validate these entries according to their @@ -243,17 +238,21 @@ private: } void set_as_offset(char* p, size_t *offset); public: - // Accessors -- fields declared in CDSFileMapHeaderBase - unsigned int magic() const { return _magic; } - int crc() const { return _crc; } - int version() const { return _version; } - - void set_crc(int crc_value) { _crc = crc_value; } - void set_version(int v) { _version = v; } - - // Accessors -- fields declared in FileMapHeader + // Accessors -- fields declared in GenericCDSFileMapHeader + unsigned int magic() const { return _generic_header._magic; } + int crc() const { return _generic_header._crc; } + int version() const { return _generic_header._version; } + unsigned int header_size() const { return _generic_header._header_size; } + unsigned int base_archive_path_offset() const { return _generic_header._base_archive_path_offset; } + unsigned int base_archive_name_size() const { return _generic_header._base_archive_name_size; } + + void set_magic(unsigned int m) { _generic_header._magic = m; } + void set_crc(int crc_value) { _generic_header._crc = crc_value; } + void set_version(int v) { _generic_header._version = v; } + void set_header_size(unsigned int s) { _generic_header._header_size = s; } + void set_base_archive_path_offset(unsigned int s) { _generic_header._base_archive_path_offset = s; } + void set_base_archive_name_size(unsigned int s) { _generic_header._base_archive_name_size = s; } - size_t header_size() const { return _header_size; } size_t core_region_alignment() const { return _core_region_alignment; } int obj_alignment() const { return _obj_alignment; } address narrow_oop_base() const { return _narrow_oop_base; } @@ -267,9 +266,7 @@ public: char* serialized_data() const { return from_mapped_offset(_serialized_data_offset); } address heap_begin() const { return _heap_begin; } address heap_end() const { return _heap_end; } - bool base_archive_is_default() const { return _base_archive_is_default; } const char* jvm_ident() const { return _jvm_ident; } - size_t base_archive_name_size() const { return _base_archive_name_size; } char* requested_base_address() const { return _requested_base_address; } char* mapped_base_address() const { return _mapped_base_address; } bool has_platform_or_app_classes() const { return _has_platform_or_app_classes; } @@ -287,12 +284,10 @@ public: void set_has_platform_or_app_classes(bool v) { _has_platform_or_app_classes = v; } void set_cloned_vtables(char* p) { set_as_offset(p, &_cloned_vtables_offset); } void set_serialized_data(char* p) { set_as_offset(p, &_serialized_data_offset); } - void set_base_archive_name_size(size_t s) { _base_archive_name_size = s; } - void set_base_archive_is_default(bool b) { _base_archive_is_default = b; } - void set_header_size(size_t s) { _header_size = s; } void set_ptrmap_size_in_bits(size_t s) { _ptrmap_size_in_bits = s; } void set_mapped_base_address(char* p) { _mapped_base_address = p; } void set_heap_obj_roots(narrowOop r) { _heap_obj_roots = r; } + void copy_base_archive_name(const char* name); void set_shared_path_table(SharedPathTable table) { set_as_offset((char*)table.table(), &_shared_path_table_offset); @@ -317,8 +312,8 @@ public: return FileMapRegion::cast(&_space[i]); } - void populate(FileMapInfo* info, size_t core_region_alignment); - + void populate(FileMapInfo *info, size_t core_region_alignment, size_t header_size, + size_t base_archive_name_size, size_t base_archive_path_offset); static bool is_valid_region(int region) { return (0 <= region && region < NUM_CDS_REGIONS); } @@ -363,7 +358,7 @@ private: public: static bool get_base_archive_name_from_header(const char* archive_name, - int* size, char** base_archive_name); + char** base_archive_name); static bool check_archive(const char* archive_name, bool is_static); static SharedPathTable shared_path_table() { return _shared_path_table; @@ -398,9 +393,6 @@ public: int narrow_klass_shift() const { return header()->narrow_klass_shift(); } size_t core_region_alignment() const { return header()->core_region_alignment(); } - void set_header_base_archive_name_size(size_t size) { header()->set_base_archive_name_size(size); } - void set_header_base_archive_is_default(bool is_default) { header()->set_base_archive_is_default(is_default); } - CompressedOops::Mode narrow_oop_mode() const { return header()->narrow_oop_mode(); } jshort app_module_paths_start_index() const { return header()->app_module_paths_start_index(); } jshort app_class_paths_start_index() const { return header()->app_class_paths_start_index(); } diff --git a/src/hotspot/share/include/cds.h b/src/hotspot/share/include/cds.h index b12e25dad72..69f9758ea28 100644 --- a/src/hotspot/share/include/cds.h +++ b/src/hotspot/share/include/cds.h @@ -38,10 +38,9 @@ #define NUM_CDS_REGIONS 7 // this must be the same as MetaspaceShared::n_regions #define CDS_ARCHIVE_MAGIC 0xf00baba2 #define CDS_DYNAMIC_ARCHIVE_MAGIC 0xf00baba8 -#define CURRENT_CDS_ARCHIVE_VERSION 11 -#define INVALID_CDS_ARCHIVE_VERSION -1 +#define CURRENT_CDS_ARCHIVE_VERSION 12 -struct CDSFileMapRegion { +typedef struct CDSFileMapRegion { int _crc; // CRC checksum of this region. int _read_only; // read only region? int _allow_exec; // executable code in this region? @@ -58,15 +57,37 @@ struct CDSFileMapRegion { size_t _oopmap_offset; // Bitmap for relocating embedded oops (offset from SharedBaseAddress). size_t _oopmap_size_in_bits; char* _mapped_base; // Actually mapped address (NULL if this region is not mapped). -}; +} CDSFileMapRegion; -struct CDSFileMapHeaderBase { - unsigned int _magic; // identify file type - int _crc; // header crc checksum - int _version; // must be CURRENT_CDS_ARCHIVE_VERSION - struct CDSFileMapRegion _space[NUM_CDS_REGIONS]; -}; +// This portion of the archive file header must remain unchanged for _version >= 12. +// This makes it possible to read important information from a CDS archive created by +// a different version of HotSpot, so that we can automatically regenerate the archive as necessary. +typedef struct GenericCDSFileMapHeader { + unsigned int _magic; // identification of file type + int _crc; // header crc checksum + int _version; // CURRENT_CDS_ARCHIVE_VERSION of the jdk that dumped the this archive + unsigned int _header_size; // total size of the header, in bytes + unsigned int _base_archive_path_offset; // offset where the base archive name is stored + // static archive: 0 + // dynamic archive: + // 0 for default base archive + // non-zero for non-default base archive + // (char*)this + _base_archive_path_offset + // points to a 0-terminated string for the base archive name + unsigned int _base_archive_name_size; // size of base archive name including ending '\0' + // static: 0 + // dynamic: + // 0 for default base archive + // non-zero for non-default base archive +} GenericCDSFileMapHeader; -typedef struct CDSFileMapHeaderBase CDSFileMapHeaderBase; +// This type is used by the Serviceability Agent to access the contents of +// a memory-mapped CDS archive. +typedef struct CDSFileMapHeaderBase { + // We cannot inherit from GenericCDSFileMapHeader as this type may be used + // by both C and C++ code. + GenericCDSFileMapHeader _generic_header; + CDSFileMapRegion _space[NUM_CDS_REGIONS]; +} CDSFileMapHeaderBase; #endif // SHARE_INCLUDE_CDS_H diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index 31003615001..4996f545775 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -3531,9 +3531,8 @@ bool Arguments::init_shared_archive_paths() { } if (archives == 1) { char* temp_archive_path = os::strdup_check_oom(SharedArchiveFile, mtArguments); - int name_size; bool success = - FileMapInfo::get_base_archive_name_from_header(temp_archive_path, &name_size, &SharedArchivePath); + FileMapInfo::get_base_archive_name_from_header(temp_archive_path, &SharedArchivePath); if (!success) { SharedArchivePath = temp_archive_path; } else { diff --git a/src/jdk.hotspot.agent/share/native/libsaproc/ps_core_common.c b/src/jdk.hotspot.agent/share/native/libsaproc/ps_core_common.c index 09526beedc2..e821ec2f493 100644 --- a/src/jdk.hotspot.agent/share/native/libsaproc/ps_core_common.c +++ b/src/jdk.hotspot.agent/share/native/libsaproc/ps_core_common.c @@ -356,26 +356,27 @@ bool init_classsharing_workaround(struct ps_prochandle* ph) { } // read CDSFileMapHeaderBase from the file - memset(&header, 0, sizeof(CDSFileMapHeaderBase)); - if ((n = read(fd, &header, sizeof(CDSFileMapHeaderBase))) - != sizeof(CDSFileMapHeaderBase)) { + size_t header_size = sizeof(CDSFileMapHeaderBase); + memset(&header, 0, header_size); + if ((n = read(fd, &header, header_size)) + != header_size) { print_debug("can't read shared archive file map header from %s\n", classes_jsa); close(fd); return false; } // check file magic - if (header._magic != CDS_ARCHIVE_MAGIC) { + if (header._generic_header._magic != CDS_ARCHIVE_MAGIC) { print_debug("%s has bad shared archive file magic number 0x%x, expecting 0x%x\n", - classes_jsa, header._magic, CDS_ARCHIVE_MAGIC); + classes_jsa, header._generic_header._magic, CDS_ARCHIVE_MAGIC); close(fd); return false; } // check version - if (header._version != CURRENT_CDS_ARCHIVE_VERSION) { + if (header._generic_header._version != CURRENT_CDS_ARCHIVE_VERSION) { print_debug("%s has wrong shared archive file version %d, expecting %d\n", - classes_jsa, header._version, CURRENT_CDS_ARCHIVE_VERSION); + classes_jsa, header._generic_header._version, CURRENT_CDS_ARCHIVE_VERSION); close(fd); return false; } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/SharedArchiveConsistency.java b/test/hotspot/jtreg/runtime/cds/appcds/SharedArchiveConsistency.java index 233511f704d..d77ede12a12 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/SharedArchiveConsistency.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/SharedArchiveConsistency.java @@ -58,6 +58,8 @@ public class SharedArchiveConsistency { public static int num_regions = shared_region_name.length; public static String[] matchMessages = { + "UseSharedSpaces: Header checksum verification failed.", + "The shared archive file has an incorrect header size.", "Unable to use shared archive", "An error has occurred while processing the shared archive file.", "Checksum verification failed.", @@ -158,7 +160,7 @@ public class SharedArchiveConsistency { System.out.println("\n2c. Corrupt _magic, should fail\n"); String modMagic = startNewArchive("modify-magic"); copiedJsa = CDSArchiveUtils.copyArchiveFile(orgJsaFile, modMagic); - CDSArchiveUtils.modifyHeaderIntField(copiedJsa, CDSArchiveUtils.offsetMagic, -1); + CDSArchiveUtils.modifyHeaderIntField(copiedJsa, CDSArchiveUtils.offsetMagic(), -1); output = shareAuto ? TestCommon.execAuto(execArgs) : TestCommon.execCommon(execArgs); output.shouldContain("The shared archive file has a bad magic number"); output.shouldNotContain("Checksum verification failed"); @@ -170,7 +172,7 @@ public class SharedArchiveConsistency { System.out.println("\n2d. Corrupt _version, should fail\n"); String modVersion = startNewArchive("modify-version"); copiedJsa = CDSArchiveUtils.copyArchiveFile(orgJsaFile, modVersion); - CDSArchiveUtils.modifyHeaderIntField(copiedJsa, CDSArchiveUtils.offsetVersion, 0x00000000); + CDSArchiveUtils.modifyHeaderIntField(copiedJsa, CDSArchiveUtils.offsetVersion(), 0x00000000); output = shareAuto ? TestCommon.execAuto(execArgs) : TestCommon.execCommon(execArgs); output.shouldContain("The shared archive file has the wrong version"); output.shouldNotContain("Checksum verification failed"); @@ -213,10 +215,22 @@ public class SharedArchiveConsistency { CDSArchiveUtils.deleteBytesAtRandomPositionAfterHeader(orgJsaFile, deleteBytes, 4096 /*bytes*/); testAndCheck(verifyExecArgs); + // modify contents in random area System.out.println("\n7. modify Content in random areas, should fail\n"); String randomAreas = startNewArchive("random-areas"); copiedJsa = CDSArchiveUtils.copyArchiveFile(orgJsaFile, randomAreas); CDSArchiveUtils.modifyRegionContentRandomly(copiedJsa); testAndCheck(verifyExecArgs); + + // modify _base_archive_path_offet to non-zero + System.out.println("\n8. modify _base_archive_path_offset to non-zero\n"); + String baseArchivePathOffsetName = startNewArchive("base-arhive-path-offset"); + copiedJsa = CDSArchiveUtils.copyArchiveFile(orgJsaFile, baseArchivePathOffsetName); + int baseArchivePathOffset = CDSArchiveUtils.baseArchivePathOffset(copiedJsa); + System.out.println(" baseArchivePathOffset = " + baseArchivePathOffset); + CDSArchiveUtils.writeData(copiedJsa, CDSArchiveUtils.offsetBaseArchivePathOffset(), 1024); + baseArchivePathOffset = CDSArchiveUtils.baseArchivePathOffset(copiedJsa); + System.out.println("new baseArchivePathOffset = " + baseArchivePathOffset); + testAndCheck(verifyExecArgs); } } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/ArchiveConsistency.java b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/ArchiveConsistency.java index 4bc5157f28c..fbecc57d604 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/ArchiveConsistency.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/ArchiveConsistency.java @@ -36,6 +36,7 @@ import java.io.File; import java.io.IOException; import jdk.test.lib.cds.CDSArchiveUtils; +import jdk.test.lib.cds.CDSTestUtils; import jdk.test.lib.helpers.ClassFileInstaller; public class ArchiveConsistency extends DynamicArchiveTestBase { @@ -52,6 +53,31 @@ public class ArchiveConsistency extends DynamicArchiveTestBase { doTest(baseArchiveName, topArchiveName); } + static void runTwo(String base, String top, + String jarName, String mainClassName, int exitValue, + String ... checkMessages) throws Exception { + CDSTestUtils.Result result = run2(base, top, + "-Xlog:cds", + "-Xlog:cds+dynamic=debug", + "-XX:+VerifySharedSpaces", + "-cp", + jarName, + mainClassName); + if (exitValue == 0) { + result.assertNormalExit( output -> { + for (String s : checkMessages) { + output.shouldContain(s); + } + }); + } else { + result.assertAbnormalExit( output -> { + for (String s : checkMessages) { + output.shouldContain(s); + } + }); + } + } + private static void doTest(String baseArchiveName, String topArchiveName) throws Exception { String appJar = ClassFileInstaller.getJarPath("hello.jar"); String mainClass = "Hello"; @@ -68,20 +94,66 @@ public class ArchiveConsistency extends DynamicArchiveTestBase { throw new IOException(jsa + " does not exist!"); } - // Modify the CRC values in the header of the top archive. + // 1. Modify the CRC values in the header of the top archive. + System.out.println("\n1. Modify the CRC values in the header of the top archive"); String modTop = getNewArchiveName("modTopRegionsCrc"); File copiedJsa = CDSArchiveUtils.copyArchiveFile(jsa, modTop); CDSArchiveUtils.modifyAllRegionsCrc(copiedJsa); - run2(baseArchiveName, modTop, - "-Xlog:class+load", - "-Xlog:cds+dynamic=debug,cds=debug", - "-XX:+VerifySharedSpaces", - "-cp", appJar, mainClass) - .assertAbnormalExit(output -> { - output.shouldContain("Header checksum verification failed") - .shouldContain("Unable to use shared archive") - .shouldHaveExitValue(1); - }); + runTwo(baseArchiveName, modTop, + appJar, mainClass, 1, + new String[] {"Header checksum verification failed", + "Unable to use shared archive"}); + + // 2. Make header size larger than the archive size + System.out.println("\n2. Make header size larger than the archive size"); + String largerHeaderSize = getNewArchiveName("largerHeaderSize"); + copiedJsa = CDSArchiveUtils.copyArchiveFile(jsa, largerHeaderSize); + CDSArchiveUtils.modifyHeaderIntField(copiedJsa, CDSArchiveUtils.offsetHeaderSize(), (int)copiedJsa.length() + 1024); + runTwo(baseArchiveName, largerHeaderSize, + appJar, mainClass, 1, + new String[] {"_header_size should be equal to _base_archive_path_offset plus _base_archive_name_size", + "Unable to use shared archive"}); + + // 3. Make base archive path offset beyond of header size + System.out.println("\n3. Make base archive path offset beyond of header size."); + String wrongBaseArchivePathOffset = getNewArchiveName("wrongBaseArchivePathOffset"); + copiedJsa = CDSArchiveUtils.copyArchiveFile(jsa, wrongBaseArchivePathOffset); + int fileHeaderSize = (int)CDSArchiveUtils.fileHeaderSize(copiedJsa); + int baseArchivePathOffset = CDSArchiveUtils.baseArchivePathOffset(copiedJsa); + CDSArchiveUtils.modifyHeaderIntField(copiedJsa, CDSArchiveUtils.offsetBaseArchivePathOffset(), baseArchivePathOffset + 1024); + runTwo(baseArchiveName, wrongBaseArchivePathOffset, + appJar, mainClass, 1, + new String[] {"_header_size should be equal to _base_archive_path_offset plus _base_archive_name_size", + "The shared archive file has an incorrect header size", + "Unable to use shared archive"}); + + // 4. Make base archive path offset points to middle of name size + System.out.println("\n4. Make base archive path offset points to middle of name size"); + String wrongBasePathOffset = getNewArchiveName("wrongBasePathOffset"); + copiedJsa = CDSArchiveUtils.copyArchiveFile(jsa, wrongBasePathOffset); + int baseArchiveNameSize = CDSArchiveUtils.baseArchiveNameSize(copiedJsa); + baseArchivePathOffset = CDSArchiveUtils.baseArchivePathOffset(copiedJsa); + CDSArchiveUtils.modifyHeaderIntField(copiedJsa, baseArchivePathOffset, + baseArchivePathOffset + baseArchiveNameSize/2); + runTwo(baseArchiveName, wrongBasePathOffset, + appJar, mainClass, 1, + new String[] {"An error has occurred while processing the shared archive file.", + "Header checksum verification failed", + "Unable to use shared archive"}); + // 5. Make base archive name not terminated with '\0' + System.out.println("\n5. Make base archive name not terminated with '\0'"); + String wrongBaseName = getNewArchiveName("wrongBaseName"); + copiedJsa = CDSArchiveUtils.copyArchiveFile(jsa, wrongBaseName); + baseArchivePathOffset = CDSArchiveUtils.baseArchivePathOffset(copiedJsa); + baseArchiveNameSize = CDSArchiveUtils.baseArchiveNameSize(copiedJsa); + long offset = baseArchivePathOffset + baseArchiveNameSize - 1; // end of line + CDSArchiveUtils.writeData(copiedJsa, offset, new byte[] {(byte)'X'}); + + runTwo(baseArchiveName, wrongBaseName, + appJar, mainClass, 1, + new String[] {"Base archive " + baseArchiveName, + " does not exist", + "Header checksum verification failed"}); } } diff --git a/test/lib/jdk/test/lib/cds/CDSArchiveUtils.java b/test/lib/jdk/test/lib/cds/CDSArchiveUtils.java index a20668831b6..21f374a1c46 100644 --- a/test/lib/jdk/test/lib/cds/CDSArchiveUtils.java +++ b/test/lib/jdk/test/lib/cds/CDSArchiveUtils.java @@ -46,25 +46,28 @@ import sun.hotspot.WhiteBox; // This class performs operations on shared archive file public class CDSArchiveUtils { // offsets - public static int offsetMagic; // CDSFileMapHeaderBase::_magic - public static int offsetVersion; // CDSFileMapHeaderBase::_version - public static int offsetJvmIdent; // FileMapHeader::_jvm_ident - public static int offsetBaseArchiveNameSize; // FileMapHeader::_base_archive_name_size - public static int spOffsetCrc; // CDSFileMapRegion::_crc - public static int spOffset; // offset of CDSFileMapRegion - public static int spUsedOffset; // offset of CDSFileMapRegion::_used + private static int offsetMagic; // offset of GenericCDSFileMapHeader::_magic + private static int offsetCrc; // offset of GenericCDSFileMapHeader::_crc + private static int offsetVersion; // offset of GenericCDSFileMapHeader::_version + private static int offsetHeaderSize; // offset of GenericCDSFileMapHeader::_header_size + private static int offsetBaseArchivePathOffset;// offset of GenericCDSFileMapHeader::_base_archive_path_offset + private static int offsetBaseArchiveNameSize; // offset of GenericCDSFileMapHeader::_base_archive_name_size + private static int offsetJvmIdent; // offset of FileMapHeader::_jvm_ident + private static int spOffsetCrc; // offset of CDSFileMapRegion::_crc + private static int spOffset; // offset of CDSFileMapRegion + private static int spUsedOffset; // offset of CDSFileMapRegion::_used // constants - public static int staticMagic; // static magic value defined in hotspot - public static int dynamicMagic; // dyamic magic value defined in hotspot - public static int sizetSize; // size of size_t - public static int intSize; // size of int - public static int staticArchiveHeaderSize; // static archive file header size - public static int dynamicArchiveHeaderSize; // dynamic archive file header size - public static int cdsFileMapRegionSize; // size of CDSFileMapRegion - public static long alignment; // MetaspaceShared::core_region_alignment + private static int staticMagic; // static magic value defined in hotspot + private static int dynamicMagic; // dyamic magic value defined in hotspot + private static int sizetSize; // size of size_t + private static int intSize; // size of int + private static int staticArchiveHeaderSize; // static archive file header size + private static int dynamicArchiveHeaderSize; // dynamic archive file header size + private static int cdsFileMapRegionSize; // size of CDSFileMapRegion + private static long alignment; // MetaspaceShared::core_region_alignment // The following should be consistent with the enum in the C++ MetaspaceShared class - public static String[] shared_region_name = { + private static String[] shared_region_name = { "rw", // ReadWrite "ro", // ReadOnly "bm", // relocation bitmaps @@ -73,31 +76,33 @@ public class CDSArchiveUtils { "first_open_archive", "last_open_archive" }; - public static int num_regions = shared_region_name.length; + private static int num_regions = shared_region_name.length; static { WhiteBox wb; try { wb = WhiteBox.getWhiteBox(); // offsets - offsetMagic = wb.getCDSOffsetForName("CDSFileMapHeaderBase::_magic"); - offsetVersion = wb.getCDSOffsetForName("CDSFileMapHeaderBase::_version"); + offsetMagic = wb.getCDSOffsetForName("GenericCDSFileMapHeader::_magic"); + offsetCrc = wb.getCDSOffsetForName("GenericCDSFileMapHeader::_crc"); + offsetVersion = wb.getCDSOffsetForName("GenericCDSFileMapHeader::_version"); + offsetHeaderSize = wb.getCDSOffsetForName("GenericCDSFileMapHeader::_header_size"); + offsetBaseArchivePathOffset = wb.getCDSOffsetForName("GenericCDSFileMapHeader::_base_archive_path_offset"); + offsetBaseArchiveNameSize = wb.getCDSOffsetForName("GenericCDSFileMapHeader::_base_archive_name_size"); offsetJvmIdent = wb.getCDSOffsetForName("FileMapHeader::_jvm_ident"); - offsetBaseArchiveNameSize = wb.getCDSOffsetForName("FileMapHeader::_base_archive_name_size"); spOffsetCrc = wb.getCDSOffsetForName("CDSFileMapRegion::_crc"); spUsedOffset = wb.getCDSOffsetForName("CDSFileMapRegion::_used") - spOffsetCrc; spOffset = wb.getCDSOffsetForName("CDSFileMapHeaderBase::_space[0]") - offsetMagic; // constants staticMagic = wb.getCDSConstantForName("static_magic"); dynamicMagic = wb.getCDSConstantForName("dynamic_magic"); + // following two sizes are runtime values staticArchiveHeaderSize = wb.getCDSConstantForName("static_file_header_size"); dynamicArchiveHeaderSize = wb.getCDSConstantForName("dynamic_archive_header_size"); sizetSize = wb.getCDSConstantForName("size_t_size"); intSize = wb.getCDSConstantForName("int_size"); cdsFileMapRegionSize = wb.getCDSConstantForName("CDSFileMapRegion_size"); alignment = wb.metaspaceSharedRegionAlignment(); - // file_header_size is structure size, real size aligned with alignment - // so must be calculated after alignment is available } catch (Exception e) { throw new RuntimeException(e.getMessage()); } @@ -110,17 +115,51 @@ public class CDSArchiveUtils { } } + // accessors + // offsets + public static int offsetMagic() { return offsetMagic; } + public static int offsetCrc() { return offsetCrc; } + public static int offsetVersion() { return offsetVersion; } + public static int offsetHeaderSize() { return offsetHeaderSize; } + public static int offsetBaseArchivePathOffset() { return offsetBaseArchivePathOffset; } + public static int offsetBaseArchiveNameSize() { return offsetBaseArchiveNameSize; } + public static int offsetJvmIdent() { return offsetJvmIdent; } + public static int spOffsetCrc() { return spOffsetCrc; } + public static int spOffset() { return spOffset; } + public static int spUsedOffset() { return spUsedOffset; } + // constants + public static int staticMagic() { return staticMagic; } + public static int dynamicMagic() { return dynamicMagic; } + public static int sizetSize() { return sizetSize; } + public static int staticArchiveHeaderSize() { return staticArchiveHeaderSize; } + public static int dynamicArchiveHeaderSize() { return dynamicArchiveHeaderSize; } + public static int cdsFileMapRegionSize() { return cdsFileMapRegionSize; } + public static long alignment() { return alignment; } + + + public static long fileHeaderSize(File jsaFile) throws Exception { - long magicValue = readInt(jsaFile, offsetMagic, 4); - if (magicValue == staticMagic) { - return alignUpWithAlignment((long)staticArchiveHeaderSize); - } else if (magicValue == dynamicMagic) { - // dynamic archive store base archive name after header, so we count it in header size. - int baseArchiveNameSize = (int)readInt(jsaFile, (long)offsetBaseArchiveNameSize, 4); - return alignUpWithAlignment((long)dynamicArchiveHeaderSize + baseArchiveNameSize); - } else { - throw new RuntimeException("Wrong magic value from archive file: " + magicValue); - } + long headerSize = readInt(jsaFile, offsetHeaderSize, 4); + return headerSize; + } + + public static long fileHeaderSizeAligned(File jsaFile) throws Exception { + long size = fileHeaderSize(jsaFile); + return alignUpWithAlignment(size); + } + + public static int baseArchivePathOffset(File jsaFile) throws Exception { + return (int)readInt(jsaFile, offsetBaseArchivePathOffset, 4); + } + + public static int baseArchiveNameSize(File jsaFile) throws Exception { + return (int)readInt(jsaFile, offsetBaseArchiveNameSize, 4); + } + + public static String baseArchiveName(File jsaFile) throws Exception { + int size = baseArchiveNameSize(jsaFile); + int baseArchivePathOffset = (int)readInt(jsaFile, offsetBaseArchivePathOffset, 4); + return readString(jsaFile, baseArchivePathOffset, size - 1); // exclude terminating '\0' } private static long alignUpWithAlignment(long l) { @@ -159,7 +198,7 @@ public class CDSArchiveUtils { int bufSize; System.out.printf("%-24s%12s%12s%16s\n", "Space Name", "Used bytes", "Reg Start", "Random Offset"); - start0 = fileHeaderSize(jsaFile); + start0 = fileHeaderSizeAligned(jsaFile); for (int i = 0; i < num_regions; i++) { used[i] = usedRegionSizeAligned(jsaFile, i); start = start0; @@ -188,7 +227,7 @@ public class CDSArchiveUtils { int bufSize; System.out.printf("%-24s%12s%12s%16s\n", "Space Name", "Used bytes", "Reg Start", "Random Offset"); - start0 = fileHeaderSize(jsaFile); + start0 = fileHeaderSizeAligned(jsaFile); for (int i = 0; i < num_regions; i++) { used[i] = usedRegionSizeAligned(jsaFile, i); start = start0; @@ -225,12 +264,12 @@ public class CDSArchiveUtils { } byte[] buf = new byte[4096]; System.out.printf("%-24s%12d\n", "Total: ", total); - long regionStartOffset = fileHeaderSize(jsaFile); + long regionStartOffset = fileHeaderSizeAligned(jsaFile); for (int i = 0; i < region; i++) { regionStartOffset += used[i]; } System.out.println("Corrupt " + shared_region_name[region] + " section, start = " + regionStartOffset - + " (header_size + 0x" + Long.toHexString(regionStartOffset - fileHeaderSize(jsaFile)) + ")"); + + " (header_size + 0x" + Long.toHexString(regionStartOffset - fileHeaderSizeAligned(jsaFile)) + ")"); long bytesWritten = 0L; while (bytesWritten < used[region]) { bytesWritten += writeData(jsaFile, regionStartOffset + bytesWritten, buf); @@ -262,16 +301,17 @@ public class CDSArchiveUtils { writeData(jsaFile, 0, buf); } + public static void modifyFileHeaderSize(File jsaFile, int newHeaderSize) throws Exception { + modifyHeaderIntField(jsaFile, offsetHeaderSize, newHeaderSize); + } + public static void modifyJvmIdent(File jsaFile, String newJvmIdent) throws Exception { byte[] buf = newJvmIdent.getBytes(); writeData(jsaFile, (long)offsetJvmIdent, buf); } public static void modifyHeaderIntField(File jsaFile, long offset, int value) throws Exception { - System.out.println(" offset " + offset); - - byte[] bytes = ByteBuffer.allocate(4).putInt(value).array(); - writeData(jsaFile, offset, bytes); + writeData(jsaFile, offset, value); } // copy archive and set copied read/write permit @@ -300,16 +340,30 @@ public class CDSArchiveUtils { return FileChannel.open(file.toPath(), new HashSet(arry)); } - public static long readInt(File file, long offset, int nBytes) throws Exception { + private static long readInt(File file, long offset, int nBytes) throws Exception { try (FileChannel fc = getFileChannel(file, false /*read only*/)) { - ByteBuffer bb = ByteBuffer.allocate(nBytes); - bb.order(ByteOrder.nativeOrder()); + ByteBuffer bb = ByteBuffer.allocate(nBytes).order(ByteOrder.nativeOrder()); fc.position(offset); fc.read(bb); + bb.rewind(); return (nBytes > 4 ? bb.getLong(0) : bb.getInt(0)); } } + private static String readString(File file, long offset, int nBytes) throws Exception { + try (FileChannel fc = getFileChannel(file, false /*read only*/)) { + ByteBuffer bb = ByteBuffer.allocate(nBytes).order(ByteOrder.nativeOrder()); + fc.position(offset); + fc.read(bb); + byte[] arr = bb.flip().array(); + for (byte i : arr) { + System.out.print((char)i); + } + System.out.println(""); + return new String(arr); + } + } + private static long writeData(FileChannel fc, long offset, ByteBuffer bb) throws Exception { fc.position(offset); return fc.write(bb); @@ -318,13 +372,17 @@ public class CDSArchiveUtils { public static long writeData(File file, long offset, byte[] array) throws Exception { try (FileChannel fc = getFileChannel(file, true /*write*/)) { ByteBuffer bbuf = ByteBuffer.wrap(array); + bbuf.order(ByteOrder.nativeOrder()); return writeData(fc, offset, bbuf); } } public static long writeData(File file, long offset, int value) throws Exception { try (FileChannel fc = getFileChannel(file, true /*write*/)) { - ByteBuffer bbuf = ByteBuffer.allocate(4).putInt(value).position(0); + ByteBuffer bbuf = ByteBuffer.allocate(4) + .order(ByteOrder.nativeOrder()) + .putInt(value) + .rewind(); return writeData(fc, offset, bbuf); } } -- GitLab From 97ea9dd2f24f9f1fb9b9345a4202a825ee28e014 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Fri, 8 Oct 2021 06:40:18 +0000 Subject: [PATCH 139/385] 8274840: Update OS detection code to recognize Windows 11 Co-authored-by: Arno Zeller Reviewed-by: clanger, dholmes --- src/hotspot/os/windows/os_windows.cpp | 6 +++++- src/java.base/windows/native/libjava/java_props_md.c | 11 ++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp index 01158d84cb1..6d0610ccd75 100644 --- a/src/hotspot/os/windows/os_windows.cpp +++ b/src/hotspot/os/windows/os_windows.cpp @@ -1858,7 +1858,11 @@ void os::win32::print_windows_version(outputStream* st) { case 10000: if (is_workstation) { - st->print("10"); + if (build_number >= 22000) { + st->print("11"); + } else { + st->print("10"); + } } else { // distinguish Windows Server by build number // - 2016 GA 10/2016 build: 14393 diff --git a/src/java.base/windows/native/libjava/java_props_md.c b/src/java.base/windows/native/libjava/java_props_md.c index 69f068e5ebc..21532c37b25 100644 --- a/src/java.base/windows/native/libjava/java_props_md.c +++ b/src/java.base/windows/native/libjava/java_props_md.c @@ -471,6 +471,8 @@ GetJavaProperties(JNIEnv* env) * Windows Server 2012 6 2 (!VER_NT_WORKSTATION) * Windows Server 2012 R2 6 3 (!VER_NT_WORKSTATION) * Windows 10 10 0 (VER_NT_WORKSTATION) + * Windows 11 10 0 (VER_NT_WORKSTATION) + * where (buildNumber >= 22000) * Windows Server 2016 10 0 (!VER_NT_WORKSTATION) * Windows Server 2019 10 0 (!VER_NT_WORKSTATION) * where (buildNumber > 17762) @@ -544,7 +546,14 @@ GetJavaProperties(JNIEnv* env) } else if (majorVersion == 10) { if (is_workstation) { switch (minorVersion) { - case 0: sprops.os_name = "Windows 10"; break; + case 0: + /* Windows 11 21H2 (original release) build number is 22000 */ + if (buildNumber >= 22000) { + sprops.os_name = "Windows 11"; + } else { + sprops.os_name = "Windows 10"; + } + break; default: sprops.os_name = "Windows NT (unknown)"; } } else { -- GitLab From b60837a7d5d6f920d2fb968369564df155dc1018 Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Fri, 8 Oct 2021 08:06:53 +0000 Subject: [PATCH 140/385] 8272586: emit abstract machine code in hs-err logs Reviewed-by: kvn, dholmes --- src/hotspot/share/code/nmethod.cpp | 8 +- src/hotspot/share/compiler/compileTask.cpp | 8 +- src/hotspot/share/compiler/compileTask.hpp | 6 +- src/hotspot/share/compiler/disassembler.cpp | 2 +- src/hotspot/share/utilities/vmError.cpp | 166 ++++++++++++----- src/hotspot/share/utilities/vmError.hpp | 4 + .../MachCodeFramesInErrorFile.java | 174 ++++++++++++++++++ 7 files changed, 318 insertions(+), 50 deletions(-) create mode 100644 test/hotspot/jtreg/runtime/ErrorHandling/MachCodeFramesInErrorFile.java diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 68776290ad5..239b0d611e2 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -67,6 +67,7 @@ #include "runtime/sharedRuntime.hpp" #include "runtime/signature.hpp" #include "runtime/sweeper.hpp" +#include "runtime/threadWXSetters.inline.hpp" #include "runtime/vmThread.hpp" #include "utilities/align.hpp" #include "utilities/copy.hpp" @@ -923,7 +924,7 @@ void nmethod::print_on(outputStream* st, const char* msg) const { CompileTask::print(st, this, msg, /*short_form:*/ true); st->print_cr(" (" INTPTR_FORMAT ")", p2i(this)); } else { - CompileTask::print(st, this, msg, /*short_form:*/ false); + CompileTask::print(st, this, msg, /*short_form:*/ false, /* cr */ true, /* timestamp */ false); } } } @@ -2528,7 +2529,7 @@ void nmethod::print(outputStream* st) const { st->print("(n/a) "); } - print_on(tty, NULL); + print_on(st, NULL); if (WizardMode) { st->print("((nmethod*) " INTPTR_FORMAT ") ", p2i(this)); @@ -2879,6 +2880,9 @@ void nmethod::decode2(outputStream* ost) const { AbstractDisassembler::show_block_comment()); #endif + // Decoding an nmethod can write to a PcDescCache (see PcDescCache::add_pc_desc) + MACOS_AARCH64_ONLY(ThreadWXEnable wx(WXWrite, Thread::current());) + st->cr(); this->print(st); st->cr(); diff --git a/src/hotspot/share/compiler/compileTask.cpp b/src/hotspot/share/compiler/compileTask.cpp index d610d8bdcf8..b78806346c5 100644 --- a/src/hotspot/share/compiler/compileTask.cpp +++ b/src/hotspot/share/compiler/compileTask.cpp @@ -236,11 +236,13 @@ void CompileTask::print_tty() { // CompileTask::print_impl void CompileTask::print_impl(outputStream* st, Method* method, int compile_id, int comp_level, bool is_osr_method, int osr_bci, bool is_blocking, - const char* msg, bool short_form, bool cr, + const char* msg, bool short_form, bool cr, bool timestamp, jlong time_queued, jlong time_started) { if (!short_form) { - // Print current time - st->print("%7d ", (int)tty->time_stamp().milliseconds()); + if (timestamp) { + // Print current time + st->print("%7d ", (int)tty->time_stamp().milliseconds()); + } if (Verbose && time_queued != 0) { // Print time in queue and time being processed by compiler thread jlong now = os::elapsed_counter(); diff --git a/src/hotspot/share/compiler/compileTask.hpp b/src/hotspot/share/compiler/compileTask.hpp index 3a48aed5b1d..9d70597fceb 100644 --- a/src/hotspot/share/compiler/compileTask.hpp +++ b/src/hotspot/share/compiler/compileTask.hpp @@ -187,16 +187,16 @@ class CompileTask : public CHeapObj { private: static void print_impl(outputStream* st, Method* method, int compile_id, int comp_level, bool is_osr_method = false, int osr_bci = -1, bool is_blocking = false, - const char* msg = NULL, bool short_form = false, bool cr = true, + const char* msg = NULL, bool short_form = false, bool cr = true, bool timestamp = true, jlong time_queued = 0, jlong time_started = 0); public: void print(outputStream* st = tty, const char* msg = NULL, bool short_form = false, bool cr = true); void print_ul(const char* msg = NULL); - static void print(outputStream* st, const nmethod* nm, const char* msg = NULL, bool short_form = false, bool cr = true) { + static void print(outputStream* st, const nmethod* nm, const char* msg = NULL, bool short_form = false, bool cr = true, bool timestamp = true) { print_impl(st, nm->method(), nm->compile_id(), nm->comp_level(), nm->is_osr_method(), nm->is_osr_method() ? nm->osr_entry_bci() : -1, /*is_blocking*/ false, - msg, short_form, cr); + msg, short_form, cr, timestamp); } static void print_ul(const nmethod* nm, const char* msg = NULL); diff --git a/src/hotspot/share/compiler/disassembler.cpp b/src/hotspot/share/compiler/disassembler.cpp index da11221a7ad..54cea9cc281 100644 --- a/src/hotspot/share/compiler/disassembler.cpp +++ b/src/hotspot/share/compiler/disassembler.cpp @@ -872,7 +872,7 @@ void Disassembler::decode(CodeBlob* cb, outputStream* st) { if (cb->is_nmethod()) { // If we have an nmethod at hand, // call the specialized decoder directly. - decode((nmethod*)cb, st); + ((nmethod*)cb)->decode2(st); return; } diff --git a/src/hotspot/share/utilities/vmError.cpp b/src/hotspot/share/utilities/vmError.cpp index ec14e2095ca..29755fec2da 100644 --- a/src/hotspot/share/utilities/vmError.cpp +++ b/src/hotspot/share/utilities/vmError.cpp @@ -87,6 +87,7 @@ Thread* VMError::_thread; address VMError::_pc; void* VMError::_siginfo; void* VMError::_context; +bool VMError::_print_native_stack_used = false; const char* VMError::_filename; int VMError::_lineno; size_t VMError::_size; @@ -241,6 +242,107 @@ void VMError::print_stack_trace(outputStream* st, JavaThread* jt, #endif // ZERO } +/** + * Adds `value` to `list` iff it's not already present and there is sufficient + * capacity (i.e. length(list) < `list_capacity`). The length of the list + * is the index of the first nullptr entry. + * + * @ return true if the value was added, false otherwise + */ +static bool add_if_absent(address value, address* list, int list_capacity) { + for (int i = 0; i < list_capacity; i++) { + if (list[i] == value) { + return false; + } + if (list[i] == nullptr) { + list[i] = value; + if (i + 1 < list_capacity) { + list[i + 1] = nullptr; + } + return true; + } + } + return false; +} + +/** + * Prints the VM generated code unit, if any, containing `pc` if it has not already + * been printed. If the code unit is an InterpreterCodelet or StubCodeDesc, it is + * only printed if `is_crash_pc` is true. + * + * @param printed array of code units that have already been printed (delimited by NULL entry) + * @param printed_capacity the capacity of `printed` + * @return true if the code unit was printed, false otherwise + */ +static bool print_code(outputStream* st, Thread* thread, address pc, bool is_crash_pc, + address* printed, int printed_capacity) { + if (Interpreter::contains(pc)) { + if (is_crash_pc) { + // The interpreter CodeBlob is very large so try to print the codelet instead. + InterpreterCodelet* codelet = Interpreter::codelet_containing(pc); + if (codelet != nullptr) { + if (add_if_absent((address) codelet, printed, printed_capacity)) { + codelet->print_on(st); + Disassembler::decode(codelet->code_begin(), codelet->code_end(), st); + return true; + } + } + } + } else { + StubCodeDesc* desc = StubCodeDesc::desc_for(pc); + if (desc != nullptr) { + if (is_crash_pc) { + if (add_if_absent((address) desc, printed, printed_capacity)) { + desc->print_on(st); + Disassembler::decode(desc->begin(), desc->end(), st); + return true; + } + } + } else if (thread != nullptr) { + CodeBlob* cb = CodeCache::find_blob(pc); + if (cb != nullptr && add_if_absent((address) cb, printed, printed_capacity)) { + // Disassembling nmethod will incur resource memory allocation, + // only do so when thread is valid. + ResourceMark rm(thread); + Disassembler::decode(cb, st); + st->cr(); + return true; + } + } + } + return false; +} + +/** + * Gets the caller frame of `fr`. + * + * @returns an invalid frame (i.e. fr.pc() === 0) if the caller cannot be obtained + */ +static frame next_frame(frame fr, Thread* t) { + // Compiled code may use EBP register on x86 so it looks like + // non-walkable C frame. Use frame.sender() for java frames. + frame invalid; + if (t != nullptr && t->is_Java_thread()) { + // Catch very first native frame by using stack address. + // For JavaThread stack_base and stack_size should be set. + if (!t->is_in_full_stack((address)(fr.real_fp() + 1))) { + return invalid; + } + if (fr.is_java_frame() || fr.is_native_frame() || fr.is_runtime_frame()) { + RegisterMap map(JavaThread::cast(t), false); // No update + return fr.sender(&map); + } else { + // is_first_C_frame() does only simple checks for frame pointer, + // it will pass if java compiled code has a pointer in EBP. + if (os::is_first_C_frame(&fr)) return invalid; + return os::get_sender_for_C_frame(&fr); + } + } else { + if (os::is_first_C_frame(&fr)) return invalid; + return os::get_sender_for_C_frame(&fr); + } +} + void VMError::print_native_stack(outputStream* st, frame fr, Thread* t, char* buf, int buf_size) { // see if it's a valid frame @@ -258,26 +360,9 @@ void VMError::print_native_stack(outputStream* st, frame fr, Thread* t, char* bu } } st->cr(); - // Compiled code may use EBP register on x86 so it looks like - // non-walkable C frame. Use frame.sender() for java frames. - if (t && t->is_Java_thread()) { - // Catch very first native frame by using stack address. - // For JavaThread stack_base and stack_size should be set. - if (!t->is_in_full_stack((address)(fr.real_fp() + 1))) { - break; - } - if (fr.is_java_frame() || fr.is_native_frame() || fr.is_runtime_frame()) { - RegisterMap map(JavaThread::cast(t), false); // No update - fr = fr.sender(&map); - } else { - // is_first_C_frame() does only simple checks for frame pointer, - // it will pass if java compiled code has a pointer in EBP. - if (os::is_first_C_frame(&fr)) break; - fr = os::get_sender_for_C_frame(&fr); - } - } else { - if (os::is_first_C_frame(&fr)) break; - fr = os::get_sender_for_C_frame(&fr); + fr = next_frame(fr, t); + if (fr.pc() == nullptr) { + break; } } @@ -747,6 +832,7 @@ void VMError::report(outputStream* st, bool _verbose) { : os::current_frame(); print_native_stack(st, fr, _thread, buf, sizeof(buf)); + _print_native_stack_used = true; } } @@ -821,30 +907,28 @@ void VMError::report(outputStream* st, bool _verbose) { st->cr(); } - STEP("printing code blob if possible") + STEP("printing code blobs if possible") if (_verbose && _context) { - CodeBlob* cb = CodeCache::find_blob(_pc); - if (cb != NULL) { - if (Interpreter::contains(_pc)) { - // The interpreter CodeBlob is very large so try to print the codelet instead. - InterpreterCodelet* codelet = Interpreter::codelet_containing(_pc); - if (codelet != NULL) { - codelet->print_on(st); - Disassembler::decode(codelet->code_begin(), codelet->code_end(), st); - } - } else { - StubCodeDesc* desc = StubCodeDesc::desc_for(_pc); - if (desc != NULL) { - desc->print_on(st); - Disassembler::decode(desc->begin(), desc->end(), st); - } else if (_thread != NULL) { - // Disassembling nmethod will incur resource memory allocation, - // only do so when thread is valid. - ResourceMark rm(_thread); - Disassembler::decode(cb, st); - st->cr(); + if (!_print_native_stack_used) { + // Only try print code of the crashing frame since + // we cannot walk the native stack using next_frame. + const int printed_capacity = 1; + address printed_singleton = nullptr; + address* printed = &printed_singleton; + print_code(st, _thread, _pc, true, printed, 1); + } else { + // Print up to the first 5 unique code units on the stack + const int printed_capacity = 5; + address printed[printed_capacity]; + printed[0] = nullptr; // length(list) == index of first nullptr + + frame fr = os::fetch_frame_from_context(_context); + for (int count = 0; count < printed_capacity && fr.pc() != nullptr; ) { + if (print_code(st, _thread, fr.pc(), fr.pc() == _pc, printed, printed_capacity)) { + count++; } + fr = next_frame(fr, _thread); } } } diff --git a/src/hotspot/share/utilities/vmError.hpp b/src/hotspot/share/utilities/vmError.hpp index 4311830d552..6a18ff9375d 100644 --- a/src/hotspot/share/utilities/vmError.hpp +++ b/src/hotspot/share/utilities/vmError.hpp @@ -51,6 +51,10 @@ class VMError : public AllStatic { static void* _context; // ContextRecord on Windows, // ucontext_t on Solaris/Linux + // records if VMError::print_native_stack was used to + // print the native stack instead of os::platform_print_native_stack + static bool _print_native_stack_used; + // additional info for VM internal errors static const char* _filename; static int _lineno; diff --git a/test/hotspot/jtreg/runtime/ErrorHandling/MachCodeFramesInErrorFile.java b/test/hotspot/jtreg/runtime/ErrorHandling/MachCodeFramesInErrorFile.java new file mode 100644 index 00000000000..201cc177f54 --- /dev/null +++ b/test/hotspot/jtreg/runtime/ErrorHandling/MachCodeFramesInErrorFile.java @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 8272586 + * @requires vm.compiler2.enabled + * @summary Test that abstract machine code is dumped for the top frames in a hs-err log + * @library /test/lib + * @modules java.base/jdk.internal.misc + * java.compiler + * java.management + * jdk.internal.jvmstat/sun.jvmstat.monitor + * @run driver MachCodeFramesInErrorFile + */ + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import java.util.ArrayList; +import java.util.stream.Stream; +import java.util.stream.Collectors; +import java.util.regex.Pattern; +import java.util.regex.Matcher; + +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.Asserts; + +import jdk.internal.misc.Unsafe; + +public class MachCodeFramesInErrorFile { + private static class Crasher { + // Need to make unsafe a compile-time constant so that + // C2 intrinsifies the call to Unsafe.getLong in method3. + private static final Unsafe unsafe = Unsafe.getUnsafe(); + public static void main(String[] args) { + method1(10); + } + + static void method1(long address) { + System.out.println("in method1"); + method2(address); + } + static void method2(long address) { + System.out.println("in method2"); + method3(address); + } + static void method3(long address) { + System.out.println("in method3"); + // Keep chasing pointers until we crash + while (true) { + address = unsafe.getLong(address); + } + } + } + + /** + * Runs Crasher and tries to force compile the methods in Crasher. The inner + * most method crashes the VM with Unsafe. The resulting hs-err log is + * expected to have a min number of MachCode sections. + */ + public static void main(String[] args) throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-Xmx64m", "--add-exports=java.base/jdk.internal.misc=ALL-UNNAMED", + "-XX:-CreateCoredumpOnCrash", + "-Xcomp", + "-XX:-TieredCompilation", // ensure C2 compiles Crasher.method3 + "-XX:CompileCommand=compileonly,MachCodeFramesInErrorFile$Crasher.m*", + "-XX:CompileCommand=dontinline,MachCodeFramesInErrorFile$Crasher.m*", + Crasher.class.getName()); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + + // Extract hs_err_pid file. + String hs_err_file = output.firstMatch("# *(\\S*hs_err_pid\\d+\\.log)", 1); + if (hs_err_file == null) { + throw new RuntimeException("Did not find hs_err_pid file in output.\n" + + "stderr:\n" + output.getStderr() + "\n" + + "stdout:\n" + output.getStdout()); + } + Path hsErrPath = Paths.get(hs_err_file); + if (!Files.exists(hsErrPath)) { + throw new RuntimeException("hs_err_pid file missing at " + hsErrPath + ".\n"); + } + String hsErr = Files.readString(hsErrPath); + if (!crashedInCrasherMethod(hsErr)) { + return; + } + List nativeFrames = extractNativeFrames(hsErr); + int compiledJavaFrames = (int) nativeFrames.stream().filter(f -> f.startsWith("J ")).count(); + + Matcher matcher = Pattern.compile("\\[MachCode\\]\\s*\\[Verified Entry Point\\]\\s* # \\{method\\} \\{[^}]*\\} '([^']+)' '([^']+)' in '([^']+)'", Pattern.DOTALL).matcher(hsErr); + List machCodeHeaders = matcher.results().map(mr -> String.format("'%s' '%s' in '%s'", mr.group(1), mr.group(2), mr.group(3))).collect(Collectors.toList()); + String message = "Mach code headers: " + machCodeHeaders + + "\n\nExtracted MachCode:\n" + extractMachCode(hsErr) + + "\n\nExtracted native frames:\n" + String.join("\n", nativeFrames); + int minExpectedMachCodeSections = Math.max(1, compiledJavaFrames); + Asserts.assertTrue(machCodeHeaders.size() >= minExpectedMachCodeSections, message); + } + + /** + * Checks whether the crashing frame is in {@code Crasher.method3}. + */ + private static boolean crashedInCrasherMethod(String hsErr) { + boolean checkProblematicFrame = false; + for (String line : hsErr.split(System.lineSeparator())) { + if (line.startsWith("# Problematic frame:")) { + checkProblematicFrame = true; + } else if (checkProblematicFrame) { + String crasherMethod = Crasher.class.getSimpleName() + ".method3"; + if (!line.contains(crasherMethod)) { + // There's any number of things that can subvert the attempt + // to crash in the expected method. + System.out.println("Crashed in method other than " + crasherMethod + "\n\n" + line + "\n\nSkipping rest of test."); + return false; + } + return true; + } + } + throw new RuntimeException("\"# Problematic frame:\" line missing in hs_err_pid file:\n" + hsErr); + } + + /** + * Gets the lines in {@code hsErr} below the line starting with "Native frames:" up to the next blank line. + */ + private static List extractNativeFrames(String hsErr) { + List res = new ArrayList<>(); + boolean inNativeFrames = false; + for (String line : hsErr.split(System.lineSeparator())) { + if (line.startsWith("Native frames: ")) { + inNativeFrames = true; + } else if (inNativeFrames) { + if (line.trim().isEmpty()) { + return res; + } + res.add(line); + } + } + throw new RuntimeException("\"Native frames:\" line missing in hs_err_pid file:\n" + hsErr); + } + + private static String extractMachCode(String hsErr) { + int start = hsErr.indexOf("[MachCode]"); + if (start != -1) { + int end = hsErr.lastIndexOf("[/MachCode]"); + if (end != -1) { + return hsErr.substring(start, end + "[/MachCode]".length()); + } + return hsErr.substring(start); + } + return null; + } +} -- GitLab From 6364719cd1c57220769ea580d958da8dc2fdf7f9 Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Fri, 8 Oct 2021 12:23:19 +0000 Subject: [PATCH 141/385] 8274004: Change 'nonleaf' rank name 8273956: Add checking for rank values Reviewed-by: dholmes, pchilanomate --- src/hotspot/os/aix/osThread_aix.cpp | 3 +- src/hotspot/os/bsd/osThread_bsd.cpp | 3 +- src/hotspot/os/linux/osThread_linux.cpp | 3 +- .../share/classfile/classLoaderData.cpp | 3 +- src/hotspot/share/compiler/compileTask.hpp | 2 +- .../share/gc/g1/g1RegionToSpaceMapper.cpp | 2 +- src/hotspot/share/gc/g1/g1ServiceThread.cpp | 4 +- src/hotspot/share/gc/g1/heapRegion.cpp | 2 +- src/hotspot/share/gc/g1/heapRegionRemSet.cpp | 2 +- .../share/gc/parallel/psCompactionManager.cpp | 3 +- src/hotspot/share/gc/shared/gcLogPrecious.cpp | 3 +- src/hotspot/share/gc/shared/oopStorage.cpp | 8 +- src/hotspot/share/gc/shared/space.cpp | 3 +- .../share/gc/shared/taskTerminator.cpp | 2 +- src/hotspot/share/gc/shared/workgroup.cpp | 3 +- .../gc/shenandoah/shenandoahControlThread.cpp | 4 +- .../share/gc/shenandoah/shenandoahPacer.hpp | 2 +- .../share/gc/z/zMessagePort.inline.hpp | 4 +- src/hotspot/share/gc/z/zMetronome.cpp | 2 +- src/hotspot/share/memory/heapInspection.hpp | 2 +- .../share/memory/metaspace/testHelpers.cpp | 2 +- src/hotspot/share/oops/methodData.cpp | 2 +- src/hotspot/share/prims/jvmtiTagMap.cpp | 2 +- src/hotspot/share/runtime/handshake.cpp | 2 +- src/hotspot/share/runtime/mutex.cpp | 96 +++++--- src/hotspot/share/runtime/mutex.hpp | 80 ++++--- src/hotspot/share/runtime/mutexLocker.cpp | 211 +++++++++--------- src/hotspot/share/runtime/stackWatermark.cpp | 2 +- src/hotspot/share/runtime/vmOperations.cpp | 2 +- src/hotspot/share/runtime/vmThread.cpp | 3 +- src/hotspot/share/services/heapDumper.cpp | 5 +- .../share/services/heapDumperCompression.cpp | 3 +- src/hotspot/share/services/memoryManager.cpp | 3 +- .../utilities/concurrentHashTable.inline.hpp | 3 +- src/hotspot/share/utilities/events.hpp | 2 +- .../gtest/metaspace/test_is_metaspace_obj.cpp | 2 +- .../gtest/metaspace/test_metaspacearena.cpp | 2 +- .../metaspace/test_metaspacearena_stress.cpp | 2 +- test/hotspot/gtest/runtime/test_mutex.cpp | 133 +++++++---- .../gtest/runtime/test_safepoint_locks.cpp | 63 ------ .../gtest/utilities/test_filterQueue.cpp | 2 +- 41 files changed, 335 insertions(+), 347 deletions(-) delete mode 100644 test/hotspot/gtest/runtime/test_safepoint_locks.cpp diff --git a/src/hotspot/os/aix/osThread_aix.cpp b/src/hotspot/os/aix/osThread_aix.cpp index bf0d53e2b49..b6aa44de0ae 100644 --- a/src/hotspot/os/aix/osThread_aix.cpp +++ b/src/hotspot/os/aix/osThread_aix.cpp @@ -46,8 +46,7 @@ void OSThread::pd_initialize() { sigemptyset(&_caller_sigmask); - _startThread_lock = new Monitor(Mutex::event, "startThread_lock", - Monitor::_safepoint_check_never); + _startThread_lock = new Monitor(Mutex::event, "startThread_lock"); assert(_startThread_lock != NULL, "check"); } diff --git a/src/hotspot/os/bsd/osThread_bsd.cpp b/src/hotspot/os/bsd/osThread_bsd.cpp index d41c9a992a8..100a5ce5447 100644 --- a/src/hotspot/os/bsd/osThread_bsd.cpp +++ b/src/hotspot/os/bsd/osThread_bsd.cpp @@ -45,8 +45,7 @@ void OSThread::pd_initialize() { sigemptyset(&_caller_sigmask); - _startThread_lock = new Monitor(Mutex::event, "startThread_lock", - Monitor::_safepoint_check_never); + _startThread_lock = new Monitor(Mutex::event, "startThread_lock"); assert(_startThread_lock !=NULL, "check"); } diff --git a/src/hotspot/os/linux/osThread_linux.cpp b/src/hotspot/os/linux/osThread_linux.cpp index 3846c571454..b6365558da1 100644 --- a/src/hotspot/os/linux/osThread_linux.cpp +++ b/src/hotspot/os/linux/osThread_linux.cpp @@ -40,8 +40,7 @@ void OSThread::pd_initialize() { sigemptyset(&_caller_sigmask); - _startThread_lock = new Monitor(Mutex::event, "startThread_lock", - Monitor::_safepoint_check_never); + _startThread_lock = new Monitor(Mutex::event, "startThread_lock"); assert(_startThread_lock !=NULL, "check"); } diff --git a/src/hotspot/share/classfile/classLoaderData.cpp b/src/hotspot/share/classfile/classLoaderData.cpp index 67fa8602df0..3f20c385bfb 100644 --- a/src/hotspot/share/classfile/classLoaderData.cpp +++ b/src/hotspot/share/classfile/classLoaderData.cpp @@ -133,8 +133,7 @@ void ClassLoaderData::initialize_name(Handle class_loader) { ClassLoaderData::ClassLoaderData(Handle h_class_loader, bool has_class_mirror_holder) : _metaspace(NULL), - _metaspace_lock(new Mutex(Mutex::nosafepoint-2, "MetaspaceAllocation_lock", - Mutex::_safepoint_check_never)), + _metaspace_lock(new Mutex(Mutex::nosafepoint-2, "MetaspaceAllocation_lock")), _unloading(false), _has_class_mirror_holder(has_class_mirror_holder), _modified_oops(true), // A non-strong hidden class loader data doesn't have anything to keep diff --git a/src/hotspot/share/compiler/compileTask.hpp b/src/hotspot/share/compiler/compileTask.hpp index 9d70597fceb..a900bfd4f44 100644 --- a/src/hotspot/share/compiler/compileTask.hpp +++ b/src/hotspot/share/compiler/compileTask.hpp @@ -104,7 +104,7 @@ class CompileTask : public CHeapObj { public: CompileTask() : _failure_reason(NULL), _failure_reason_on_C_heap(false) { - _lock = new Monitor(Mutex::nonleaf, "CompileTask_lock", Mutex::_safepoint_check_always); + _lock = new Monitor(Mutex::safepoint, "CompileTask_lock"); } void initialize(int compile_id, const methodHandle& method, int osr_bci, int comp_level, diff --git a/src/hotspot/share/gc/g1/g1RegionToSpaceMapper.cpp b/src/hotspot/share/gc/g1/g1RegionToSpaceMapper.cpp index b74b36e937c..2a78f259335 100644 --- a/src/hotspot/share/gc/g1/g1RegionToSpaceMapper.cpp +++ b/src/hotspot/share/gc/g1/g1RegionToSpaceMapper.cpp @@ -167,7 +167,7 @@ class G1RegionsSmallerThanCommitSizeMapper : public G1RegionToSpaceMapper { MEMFLAGS type) : G1RegionToSpaceMapper(rs, actual_size, page_size, alloc_granularity, commit_factor, type), _regions_per_page((page_size * commit_factor) / alloc_granularity), - _lock(Mutex::service-3, "G1Mapper_lock", Mutex::_safepoint_check_never) { + _lock(Mutex::service-3, "G1Mapper_lock") { guarantee((page_size * commit_factor) >= alloc_granularity, "allocation granularity smaller than commit granularity"); } diff --git a/src/hotspot/share/gc/g1/g1ServiceThread.cpp b/src/hotspot/share/gc/g1/g1ServiceThread.cpp index 9945c17513c..7ae7f10bf58 100644 --- a/src/hotspot/share/gc/g1/g1ServiceThread.cpp +++ b/src/hotspot/share/gc/g1/g1ServiceThread.cpp @@ -40,9 +40,7 @@ void G1SentinelTask::execute() { G1ServiceThread::G1ServiceThread() : ConcurrentGCThread(), - _monitor(Mutex::nosafepoint, - "G1ServiceThread_lock", - Monitor::_safepoint_check_never), + _monitor(Mutex::nosafepoint, "G1ServiceThread_lock"), _task_queue() { set_name("G1 Service"); create_and_start(); diff --git a/src/hotspot/share/gc/g1/heapRegion.cpp b/src/hotspot/share/gc/g1/heapRegion.cpp index 1b4adfd4bc2..dbf3f42d4a4 100644 --- a/src/hotspot/share/gc/g1/heapRegion.cpp +++ b/src/hotspot/share/gc/g1/heapRegion.cpp @@ -233,7 +233,7 @@ HeapRegion::HeapRegion(uint hrm_index, _top(NULL), _compaction_top(NULL), _bot_part(bot, this), - _par_alloc_lock(Mutex::service-2, "HeapRegionParAlloc_lock", Mutex::_safepoint_check_never), + _par_alloc_lock(Mutex::service-2, "HeapRegionParAlloc_lock"), _pre_dummy_top(NULL), _rem_set(NULL), _hrm_index(hrm_index), diff --git a/src/hotspot/share/gc/g1/heapRegionRemSet.cpp b/src/hotspot/share/gc/g1/heapRegionRemSet.cpp index 7182fae2930..b0ccf00f1db 100644 --- a/src/hotspot/share/gc/g1/heapRegionRemSet.cpp +++ b/src/hotspot/share/gc/g1/heapRegionRemSet.cpp @@ -47,7 +47,7 @@ const char* HeapRegionRemSet::_short_state_strings[] = {"UNTRA", "UPDAT", "CMPL HeapRegionRemSet::HeapRegionRemSet(HeapRegion* hr, G1CardSetConfiguration* config) : - _m(Mutex::service - 1, FormatBuffer<128>("HeapRegionRemSet#%u_lock", hr->hrm_index()), Monitor::_safepoint_check_never), + _m(Mutex::service - 1, FormatBuffer<128>("HeapRegionRemSet#%u_lock", hr->hrm_index())), _code_roots(), _card_set_mm(config, G1CardSetFreePool::free_list_pool()), _card_set(config, &_card_set_mm), diff --git a/src/hotspot/share/gc/parallel/psCompactionManager.cpp b/src/hotspot/share/gc/parallel/psCompactionManager.cpp index 883a0053610..4025a5a4b18 100644 --- a/src/hotspot/share/gc/parallel/psCompactionManager.cpp +++ b/src/hotspot/share/gc/parallel/psCompactionManager.cpp @@ -92,8 +92,7 @@ void ParCompactionManager::initialize(ParMarkBitMap* mbm) { _shadow_region_array = new (ResourceObj::C_HEAP, mtGC) GrowableArray(10, mtGC); - _shadow_region_monitor = new Monitor(Mutex::nosafepoint, "CompactionManager_lock", - Monitor::_safepoint_check_never); + _shadow_region_monitor = new Monitor(Mutex::nosafepoint, "CompactionManager_lock"); } void ParCompactionManager::reset_all_bitmap_query_caches() { diff --git a/src/hotspot/share/gc/shared/gcLogPrecious.cpp b/src/hotspot/share/gc/shared/gcLogPrecious.cpp index b1a730829e6..5070c38ce11 100644 --- a/src/hotspot/share/gc/shared/gcLogPrecious.cpp +++ b/src/hotspot/share/gc/shared/gcLogPrecious.cpp @@ -34,8 +34,7 @@ void GCLogPrecious::initialize() { _lines = new (ResourceObj::C_HEAP, mtGC) stringStream(); _temp = new (ResourceObj::C_HEAP, mtGC) stringStream(); _lock = new Mutex(Mutex::event, /* The lowest lock rank I could find */ - "GCLogPrecious Lock", - Mutex::_safepoint_check_never); + "GCLogPrecious Lock"); } void GCLogPrecious::vwrite_inner(LogTargetHandle log, const char* format, va_list args) { diff --git a/src/hotspot/share/gc/shared/oopStorage.cpp b/src/hotspot/share/gc/shared/oopStorage.cpp index b9ece642f91..cbc07e5153c 100644 --- a/src/hotspot/share/gc/shared/oopStorage.cpp +++ b/src/hotspot/share/gc/shared/oopStorage.cpp @@ -811,10 +811,10 @@ const size_t initial_active_array_size = 8; static Mutex* make_oopstorage_mutex(const char* storage_name, const char* kind, - int rank) { + Mutex::Rank rank) { char name[256]; os::snprintf(name, sizeof(name), "%s %s lock", storage_name, kind); - return new PaddedMutex(rank, name, Mutex::_safepoint_check_never); + return new PaddedMutex(rank, name); } void* OopStorage::operator new(size_t size, MEMFLAGS memflags) { @@ -844,10 +844,6 @@ OopStorage::OopStorage(const char* name, MEMFLAGS memflags) : "%s: active_mutex must have lower rank than allocation_mutex", _name); assert(Service_lock->rank() < _active_mutex->rank(), "%s: active_mutex must have higher rank than Service_lock", _name); - assert(_active_mutex->_safepoint_check_required == Mutex::_safepoint_check_never, - "%s: active mutex requires never safepoint check", _name); - assert(_allocation_mutex->_safepoint_check_required == Mutex::_safepoint_check_never, - "%s: allocation mutex requires never safepoint check", _name); } void OopStorage::delete_empty_block(const Block& block) { diff --git a/src/hotspot/share/gc/shared/space.cpp b/src/hotspot/share/gc/shared/space.cpp index 3c5d17cabc3..a9435ab9163 100644 --- a/src/hotspot/share/gc/shared/space.cpp +++ b/src/hotspot/share/gc/shared/space.cpp @@ -773,8 +773,7 @@ void OffsetTableContigSpace::alloc_block(HeapWord* start, HeapWord* end) { OffsetTableContigSpace::OffsetTableContigSpace(BlockOffsetSharedArray* sharedOffsetArray, MemRegion mr) : _offsets(sharedOffsetArray, mr), - _par_alloc_lock(Mutex::nonleaf, "OffsetTableContigSpaceParAlloc_lock", - Mutex::_safepoint_check_always, true) + _par_alloc_lock(Mutex::safepoint, "OffsetTableContigSpaceParAlloc_lock", true) { _offsets.set_contig_space(this); initialize(mr, SpaceDecorator::Clear, SpaceDecorator::Mangle); diff --git a/src/hotspot/share/gc/shared/taskTerminator.cpp b/src/hotspot/share/gc/shared/taskTerminator.cpp index a3f9c8f8f80..74d66b74e12 100644 --- a/src/hotspot/share/gc/shared/taskTerminator.cpp +++ b/src/hotspot/share/gc/shared/taskTerminator.cpp @@ -72,7 +72,7 @@ TaskTerminator::TaskTerminator(uint n_threads, TaskQueueSetSuper* queue_set) : _n_threads(n_threads), _queue_set(queue_set), _offered_termination(0), - _blocker(Mutex::nosafepoint, "TaskTerminator_lock", Monitor::_safepoint_check_never), + _blocker(Mutex::nosafepoint, "TaskTerminator_lock"), _spin_master(NULL) { } TaskTerminator::~TaskTerminator() { diff --git a/src/hotspot/share/gc/shared/workgroup.cpp b/src/hotspot/share/gc/shared/workgroup.cpp index c09108c719d..54f592234c8 100644 --- a/src/hotspot/share/gc/shared/workgroup.cpp +++ b/src/hotspot/share/gc/shared/workgroup.cpp @@ -245,8 +245,7 @@ void GangWorker::loop() { // *** WorkGangBarrierSync WorkGangBarrierSync::WorkGangBarrierSync() - : _monitor(Mutex::nosafepoint, "WorkGangBarrierSync_lock", - Monitor::_safepoint_check_never), + : _monitor(Mutex::nosafepoint, "WorkGangBarrierSync_lock"), _n_workers(0), _n_completed(0), _should_reset(false), _aborted(false) { } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp index e32ca50a21e..7054c673fb8 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp @@ -47,8 +47,8 @@ ShenandoahControlThread::ShenandoahControlThread() : ConcurrentGCThread(), - _alloc_failure_waiters_lock(Mutex::nonleaf, "ShenandoahAllocFailureGC_lock", Monitor::_safepoint_check_always, true), - _gc_waiters_lock(Mutex::nonleaf, "ShenandoahRequestedGC_lock", Monitor::_safepoint_check_always, true), + _alloc_failure_waiters_lock(Mutex::safepoint, "ShenandoahAllocFailureGC_lock", true), + _gc_waiters_lock(Mutex::safepoint, "ShenandoahRequestedGC_lock", true), _periodic_task(this), _requested_gc_cause(GCCause::_no_cause_specified), _degen_point(ShenandoahGC::_degenerated_outside_cycle), diff --git a/src/hotspot/share/gc/shenandoah/shenandoahPacer.hpp b/src/hotspot/share/gc/shenandoah/shenandoahPacer.hpp index f716bafddbf..faf5172bec0 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahPacer.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahPacer.hpp @@ -67,7 +67,7 @@ public: _heap(heap), _last_time(os::elapsedTime()), _progress_history(new TruncatedSeq(5)), - _wait_monitor(new Monitor(Mutex::nonleaf-1, "ShenandoahWaitMonitor_lock", Monitor::_safepoint_check_always, true)), + _wait_monitor(new Monitor(Mutex::safepoint-1, "ShenandoahWaitMonitor_lock", true)), _epoch(0), _tax_rate(1), _budget(0), diff --git a/src/hotspot/share/gc/z/zMessagePort.inline.hpp b/src/hotspot/share/gc/z/zMessagePort.inline.hpp index fd036ebc983..e9e9ba539a2 100644 --- a/src/hotspot/share/gc/z/zMessagePort.inline.hpp +++ b/src/hotspot/share/gc/z/zMessagePort.inline.hpp @@ -66,9 +66,7 @@ public: template inline ZMessagePort::ZMessagePort() : - _monitor(Monitor::nosafepoint, - "ZMessagePort_lock", - Monitor::_safepoint_check_never), + _monitor(Monitor::nosafepoint, "ZMessagePort_lock"), _has_message(false), _seqnum(0), _queue() {} diff --git a/src/hotspot/share/gc/z/zMetronome.cpp b/src/hotspot/share/gc/z/zMetronome.cpp index 93753377065..b8e1b69a5ab 100644 --- a/src/hotspot/share/gc/z/zMetronome.cpp +++ b/src/hotspot/share/gc/z/zMetronome.cpp @@ -28,7 +28,7 @@ #include "utilities/ticks.hpp" ZMetronome::ZMetronome(uint64_t hz) : - _monitor(Monitor::nosafepoint, "ZMetronome_lock", Monitor::_safepoint_check_never), + _monitor(Monitor::nosafepoint, "ZMetronome_lock"), _interval_ms(MILLIUNITS / hz), _start_ms(0), _nticks(0), diff --git a/src/hotspot/share/memory/heapInspection.hpp b/src/hotspot/share/memory/heapInspection.hpp index b7017f2c4ae..d05af988803 100644 --- a/src/hotspot/share/memory/heapInspection.hpp +++ b/src/hotspot/share/memory/heapInspection.hpp @@ -245,7 +245,7 @@ class ParHeapInspectTask : public AbstractGangTask { _filter(filter), _missed_count(0), _success(true), - _mutex(Mutex::nosafepoint, "ParHeapInspectTask_lock", Mutex::_safepoint_check_never) {} + _mutex(Mutex::nosafepoint, "ParHeapInspectTask_lock") {} uintx missed_count() const { return _missed_count; diff --git a/src/hotspot/share/memory/metaspace/testHelpers.cpp b/src/hotspot/share/memory/metaspace/testHelpers.cpp index c1527c18192..ef75b144643 100644 --- a/src/hotspot/share/memory/metaspace/testHelpers.cpp +++ b/src/hotspot/share/memory/metaspace/testHelpers.cpp @@ -92,7 +92,7 @@ MetaspaceTestContext::~MetaspaceTestContext() { // Create an arena, feeding off this area. MetaspaceTestArena* MetaspaceTestContext::create_arena(Metaspace::MetaspaceType type) { const ArenaGrowthPolicy* growth_policy = ArenaGrowthPolicy::policy_for_space_type(type, false); - Mutex* lock = new Mutex(Monitor::nosafepoint, "MetaspaceTestArea_lock", Monitor::_safepoint_check_never); + Mutex* lock = new Mutex(Monitor::nosafepoint, "MetaspaceTestArea_lock"); MetaspaceArena* arena = NULL; { MutexLocker ml(lock, Mutex::_no_safepoint_check_flag); diff --git a/src/hotspot/share/oops/methodData.cpp b/src/hotspot/share/oops/methodData.cpp index 3f8dd5cd243..89d232ca094 100644 --- a/src/hotspot/share/oops/methodData.cpp +++ b/src/hotspot/share/oops/methodData.cpp @@ -1207,7 +1207,7 @@ void MethodData::post_initialize(BytecodeStream* stream) { MethodData::MethodData(const methodHandle& method) : _method(method()), // Holds Compile_lock - _extra_data_lock(Mutex::nonleaf-2, "MDOExtraData_lock", Mutex::_safepoint_check_always), + _extra_data_lock(Mutex::safepoint-2, "MDOExtraData_lock"), _compiler_counters(), _parameters_type_data_di(parameters_uninitialized) { initialize(); diff --git a/src/hotspot/share/prims/jvmtiTagMap.cpp b/src/hotspot/share/prims/jvmtiTagMap.cpp index 5ffefc0d36e..a19ea2559c7 100644 --- a/src/hotspot/share/prims/jvmtiTagMap.cpp +++ b/src/hotspot/share/prims/jvmtiTagMap.cpp @@ -72,7 +72,7 @@ bool JvmtiTagMap::_has_object_free_events = false; // create a JvmtiTagMap JvmtiTagMap::JvmtiTagMap(JvmtiEnv* env) : _env(env), - _lock(Mutex::nosafepoint, "JvmtiTagMap_lock", Mutex::_safepoint_check_never), + _lock(Mutex::nosafepoint, "JvmtiTagMap_lock"), _needs_rehashing(false), _needs_cleaning(false) { diff --git a/src/hotspot/share/runtime/handshake.cpp b/src/hotspot/share/runtime/handshake.cpp index 044ba38ae94..f4c9c775b02 100644 --- a/src/hotspot/share/runtime/handshake.cpp +++ b/src/hotspot/share/runtime/handshake.cpp @@ -408,7 +408,7 @@ void Handshake::execute(AsyncHandshakeClosure* hs_cl, JavaThread* target) { HandshakeState::HandshakeState(JavaThread* target) : _handshakee(target), _queue(), - _lock(Monitor::nosafepoint, "HandshakeState_lock", Monitor::_safepoint_check_never), + _lock(Monitor::nosafepoint, "HandshakeState_lock"), _active_handshaker(), _suspended(false), _async_suspend_handshake(false) diff --git a/src/hotspot/share/runtime/mutex.cpp b/src/hotspot/share/runtime/mutex.cpp index 2ef595a83c6..caf14ce1164 100644 --- a/src/hotspot/share/runtime/mutex.cpp +++ b/src/hotspot/share/runtime/mutex.cpp @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "logging/log.hpp" +#include "memory/resourceArea.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/mutex.hpp" #include "runtime/os.inline.hpp" @@ -62,24 +63,21 @@ void Mutex::check_block_state(Thread* thread) { void Mutex::check_safepoint_state(Thread* thread) { check_block_state(thread); - // If the JavaThread checks for safepoint, verify that the lock wasn't created with safepoint_check_never. - if (thread->is_active_Java_thread()) { - assert(_safepoint_check_required != _safepoint_check_never, - "This lock should never have a safepoint check for Java threads: %s", - name()); + // If the lock acquisition checks for safepoint, verify that the lock was created with rank that + // has safepoint checks. Technically this doesn't affect NonJavaThreads since they won't actually + // check for safepoint, but let's make the rule unconditional unless there's a good reason not to. + assert(_rank > nosafepoint, + "This lock should not be taken with a safepoint check: %s", name()); + if (thread->is_active_Java_thread()) { // Also check NoSafepointVerifier, and thread state is _thread_in_vm JavaThread::cast(thread)->check_for_valid_safepoint_state(); - } else { - // If initialized with safepoint_check_never, a NonJavaThread should never ask to safepoint check either. - assert(_safepoint_check_required != _safepoint_check_never, - "NonJavaThread should not check for safepoint"); } } void Mutex::check_no_safepoint_state(Thread* thread) { check_block_state(thread); - assert(!thread->is_active_Java_thread() || _safepoint_check_required != _safepoint_check_always, + assert(!thread->is_active_Java_thread() || _rank <= nosafepoint, "This lock should always have a safepoint check for Java threads: %s", name()); } @@ -167,7 +165,7 @@ bool Mutex::try_lock_inner(bool do_rank_checks) { if (do_rank_checks) { check_rank(self); } - // Some safepoint_check_always locks use try_lock, so cannot check + // Some safepoint checking locks use try_lock, so cannot check // safepoint state, but can check blocking state. check_block_state(self); @@ -274,29 +272,21 @@ Mutex::~Mutex() { os::free(const_cast(_name)); } -Mutex::Mutex(int Rank, const char * name, SafepointCheckRequired safepoint_check_required, - bool allow_vm_block) : _owner(NULL) { +Mutex::Mutex(Rank rank, const char * name, bool allow_vm_block) : _owner(NULL) { assert(os::mutex_init_done(), "Too early!"); assert(name != NULL, "Mutex requires a name"); _name = os::strdup(name, mtInternal); #ifdef ASSERT _allow_vm_block = allow_vm_block; - _rank = Rank; - _safepoint_check_required = safepoint_check_required; + _rank = rank; _skip_rank_check = false; - assert(_rank >= 0 && _rank <= nonleaf, "Bad lock rank %d: %s", _rank, name); - - assert(_rank > nosafepoint || _safepoint_check_required == _safepoint_check_never, - "Locks below nosafepoint rank should never safepoint: %s", name); - - assert(_rank <= nosafepoint || _safepoint_check_required == _safepoint_check_always, - "Locks above nosafepoint rank should safepoint: %s", name); + assert(_rank >= static_cast(0) && _rank <= safepoint, "Bad lock rank %s: %s", rank_name(), name); // The allow_vm_block also includes allowing other non-Java threads to block or // allowing Java threads to block in native. - assert(_safepoint_check_required == _safepoint_check_always || _allow_vm_block, - "Safepoint check never locks should always allow the vm to block: %s", name); + assert(_rank > nosafepoint || _allow_vm_block, + "Locks that don't check for safepoint should always allow the vm to block: %s", name); #endif } @@ -312,23 +302,57 @@ void Mutex::print_on_error(outputStream* st) const { // ---------------------------------------------------------------------------------- // Non-product code +// +#ifdef ASSERT +static Mutex::Rank _ranks[] = { Mutex::event, Mutex::service, Mutex::stackwatermark, Mutex::tty, Mutex::oopstorage, + Mutex::nosafepoint, Mutex::safepoint }; + +static const char* _rank_names[] = { "event", "service", "stackwatermark", "tty", "oopstorage", + "nosafepoint", "safepoint" }; + +static const int _num_ranks = 7; + +static const char* rank_name_internal(Mutex::Rank r) { + // Find closest rank and print out the name + stringStream st; + for (int i = 0; i < _num_ranks; i++) { + if (r == _ranks[i]) { + return _rank_names[i]; + } else if (r > _ranks[i] && (i < _num_ranks-1 && r < _ranks[i+1])) { + int delta = static_cast(_ranks[i+1]) - static_cast(r); + st.print("%s-%d", _rank_names[i+1], delta); + return st.as_string(); + } + } + return "fail"; +} -#ifndef PRODUCT -const char* print_safepoint_check(Mutex::SafepointCheckRequired safepoint_check) { - switch (safepoint_check) { - case Mutex::_safepoint_check_never: return "safepoint_check_never"; - case Mutex::_safepoint_check_always: return "safepoint_check_always"; - default: return ""; +const char* Mutex::rank_name() const { + return rank_name_internal(_rank); +} + + +void Mutex::assert_no_overlap(Rank orig, Rank adjusted, int adjust) { + int i = 0; + while (_ranks[i] < orig) i++; + // underflow is caught in constructor + if (i != 0 && adjusted > event && adjusted <= _ranks[i-1]) { + ResourceMark rm; + assert(adjusted > _ranks[i-1], + "Rank %s-%d overlaps with %s", + rank_name_internal(orig), adjust, rank_name_internal(adjusted)); } } +#endif // ASSERT +#ifndef PRODUCT void Mutex::print_on(outputStream* st) const { st->print("Mutex: [" PTR_FORMAT "] %s - owner: " PTR_FORMAT, p2i(this), _name, p2i(owner())); if (_allow_vm_block) { st->print("%s", " allow_vm_block"); } - st->print(" %s", print_safepoint_check(_safepoint_check_required)); + DEBUG_ONLY(st->print(" %s", rank_name())); st->cr(); } #endif // PRODUCT @@ -392,8 +416,9 @@ void Mutex::check_rank(Thread* thread) { if (least != NULL && ((least->rank() <= Mutex::nosafepoint && thread->is_Java_thread()) || least->rank() <= Mutex::tty || least->rank() <= this->rank())) { - assert(false, "Attempting to wait on monitor %s/%d while holding lock %s/%d -- " - "possible deadlock. %s", name(), rank(), least->name(), least->rank(), + ResourceMark rm(thread); + assert(false, "Attempting to wait on monitor %s/%s while holding lock %s/%s -- " + "possible deadlock. %s", name(), rank_name(), least->name(), least->rank_name(), least->rank() <= this->rank() ? "Should wait on the least ranked monitor from all owned locks." : thread->is_Java_thread() ? @@ -409,14 +434,15 @@ void Mutex::check_rank(Thread* thread) { // to acquire, then deadlock prevention rules require that the rank // of m2 be less than the rank of m1. This prevents circular waits. if (least != NULL && least->rank() <= this->rank()) { + ResourceMark rm(thread); if (least->rank() > Mutex::tty) { // Printing owned locks acquires tty lock. If the least rank was below or equal // tty, then deadlock detection code would circle back here, until we run // out of stack and crash hard. Print locks only when it is safe. thread->print_owned_locks(); } - assert(false, "Attempting to acquire lock %s/%d out of order with lock %s/%d -- " - "possible deadlock", this->name(), this->rank(), least->name(), least->rank()); + assert(false, "Attempting to acquire lock %s/%s out of order with lock %s/%s -- " + "possible deadlock", this->name(), this->rank_name(), least->name(), least->rank_name()); } } } diff --git a/src/hotspot/share/runtime/mutex.hpp b/src/hotspot/share/runtime/mutex.hpp index b045a02392b..586b69f1082 100644 --- a/src/hotspot/share/runtime/mutex.hpp +++ b/src/hotspot/share/runtime/mutex.hpp @@ -46,17 +46,41 @@ class Mutex : public CHeapObj { public: // Special low level locks are given names and ranges avoid overlap. - enum Rank { + enum class Rank { event, service = event + 6, stackwatermark = service + 3, tty = stackwatermark + 3, oopstorage = tty + 3, nosafepoint = oopstorage + 6, - nonleaf = nosafepoint + 20, - max_nonleaf = nonleaf + safepoint = nosafepoint + 20 }; + // want C++later "using enum" directives. + static const Rank event = Rank::event; + static const Rank service = Rank::service; + static const Rank stackwatermark = Rank::stackwatermark; + static const Rank tty = Rank::tty; + static const Rank oopstorage = Rank::oopstorage; + static const Rank nosafepoint = Rank::nosafepoint; + static const Rank safepoint = Rank::safepoint; + + static void assert_no_overlap(Rank orig, Rank adjusted, int adjust); + + friend Rank operator-(Rank base, int adjust) { + Rank result = static_cast(static_cast(base) - adjust); + DEBUG_ONLY(assert_no_overlap(base, result, adjust)); + return result; + } + + friend constexpr bool operator<(Rank lhs, Rank rhs) { + return static_cast(lhs) < static_cast(rhs); + } + + friend constexpr bool operator>(Rank lhs, Rank rhs) { return rhs < lhs; } + friend constexpr bool operator<=(Rank lhs, Rank rhs) { return !(lhs > rhs); } + friend constexpr bool operator>=(Rank lhs, Rank rhs) { return !(lhs < rhs); } + private: // The _owner field is only set by the current thread, either to itself after it has acquired // the low-level _lock, or to NULL before it has released the _lock. Accesses by any thread other @@ -73,7 +97,7 @@ class Mutex : public CHeapObj { bool _allow_vm_block; #endif #ifdef ASSERT - int _rank; // rank (to avoid/detect potential deadlocks) + Rank _rank; // rank (to avoid/detect potential deadlocks) Mutex* _next; // Used by a Thread to link up owned locks Thread* _last_owner; // the last thread to own the lock bool _skip_rank_check; // read only by owner when doing rank checks @@ -87,7 +111,8 @@ class Mutex : public CHeapObj { } public: - int rank() const { return _rank; } + Rank rank() const { return _rank; } + const char* rank_name() const; Mutex* next() const { return _next; } void set_next(Mutex *next) { _next = next; } #endif // ASSERT @@ -107,10 +132,10 @@ class Mutex : public CHeapObj { // the safepoint protocol when acquiring locks. // Each lock can be acquired by only JavaThreads, only NonJavaThreads, or shared between - // Java and NonJavaThreads. When the lock is initialized with _safepoint_check_always, + // Java and NonJavaThreads. When the lock is initialized with rank > nosafepoint, // that means that whenever the lock is acquired by a JavaThread, it will verify that // it is done with a safepoint check. In corollary, when the lock is initialized with - // _safepoint_check_never, that means that whenever the lock is acquired by a JavaThread + // rank <= nosafepoint, that means that whenever the lock is acquired by a JavaThread // it will verify that it is done without a safepoint check. // TODO: Locks that are shared between JavaThreads and NonJavaThreads @@ -128,26 +153,11 @@ class Mutex : public CHeapObj { static const SafepointCheckFlag _no_safepoint_check_flag = SafepointCheckFlag::_no_safepoint_check_flag; - enum class SafepointCheckRequired { - _safepoint_check_never, // Mutexes with this value will cause errors - // when acquired by a JavaThread with a safepoint check. - _safepoint_check_always // Mutexes with this value will cause errors - // when acquired by a JavaThread without a safepoint check. - }; - // Bring the enumerator names into class scope. - static const SafepointCheckRequired _safepoint_check_never = - SafepointCheckRequired::_safepoint_check_never; - static const SafepointCheckRequired _safepoint_check_always = - SafepointCheckRequired::_safepoint_check_always; - - NOT_PRODUCT(SafepointCheckRequired _safepoint_check_required;) - public: - Mutex(int rank, const char *name, SafepointCheckRequired safepoint_check_required, bool allow_vm_block); + Mutex(Rank rank, const char *name, bool allow_vm_block); - Mutex(int rank, const char *name, SafepointCheckRequired safepoint_check_required) : - Mutex(rank, name, safepoint_check_required, - safepoint_check_required == _safepoint_check_never ? true : false) {} + Mutex(Rank rank, const char *name) : + Mutex(rank, name, rank > nosafepoint ? false : true) {} ~Mutex(); @@ -188,11 +198,11 @@ class Mutex : public CHeapObj { class Monitor : public Mutex { public: - Monitor(int rank, const char *name, SafepointCheckRequired safepoint_check_required, bool allow_vm_block) : - Mutex(rank, name, safepoint_check_required, allow_vm_block) {} + Monitor(Rank rank, const char *name, bool allow_vm_block) : + Mutex(rank, name, allow_vm_block) {} - Monitor(int rank, const char *name, SafepointCheckRequired safepoint_check_required) : - Mutex(rank, name, safepoint_check_required) {} + Monitor(Rank rank, const char *name) : + Mutex(rank, name) {} // default destructor // Wait until monitor is notified (or times out). @@ -212,10 +222,8 @@ class PaddedMutex : public Mutex { }; char _padding[PADDING_LEN]; public: - PaddedMutex(int rank, const char *name, SafepointCheckRequired safepoint_check_required, bool allow_vm_block) : - Mutex(rank, name, safepoint_check_required, allow_vm_block) {}; - PaddedMutex(int rank, const char *name, SafepointCheckRequired safepoint_check_required) : - Mutex(rank, name, safepoint_check_required) {}; + PaddedMutex(Rank rank, const char *name, bool allow_vm_block) : Mutex(rank, name, allow_vm_block) {}; + PaddedMutex(Rank rank, const char *name) : Mutex(rank, name) {}; }; class PaddedMonitor : public Monitor { @@ -225,10 +233,8 @@ class PaddedMonitor : public Monitor { }; char _padding[PADDING_LEN]; public: - PaddedMonitor(int rank, const char *name, SafepointCheckRequired safepoint_check_required, bool allow_vm_block) : - Monitor(rank, name, safepoint_check_required, allow_vm_block) {}; - PaddedMonitor(int rank, const char *name, SafepointCheckRequired safepoint_check_required) : - Monitor(rank, name, safepoint_check_required) {}; + PaddedMonitor(Rank rank, const char *name, bool allow_vm_block) : Monitor(rank, name, allow_vm_block) {}; + PaddedMonitor(Rank rank, const char *name) : Monitor(rank, name) {}; }; #endif // SHARE_RUNTIME_MUTEX_HPP diff --git a/src/hotspot/share/runtime/mutexLocker.cpp b/src/hotspot/share/runtime/mutexLocker.cpp index d84de912b7a..abea2761572 100644 --- a/src/hotspot/share/runtime/mutexLocker.cpp +++ b/src/hotspot/share/runtime/mutexLocker.cpp @@ -199,176 +199,175 @@ static void add_mutex(Mutex* var) { _mutex_array[_num_mutex++] = var; } -#define def(var, type, pri, vm_block, safepoint_check_allowed ) { \ - var = new type(Mutex::pri, #var, Mutex::safepoint_check_allowed, vm_block); \ - add_mutex(var); \ +#define def(var, type, pri, vm_block) { \ + var = new type(Mutex::pri, #var, vm_block); \ + add_mutex(var); \ } // Specify relative ranked lock #ifdef ASSERT -#define defl(var, type, held_lock, vm_block, safepoint_check_allowed) { \ - var = new type(held_lock->rank()-1, #var, Mutex::safepoint_check_allowed, vm_block); \ - add_mutex(var); \ +#define defl(var, type, held_lock, vm_block) { \ + var = new type(held_lock->rank()-1, #var, vm_block); \ + add_mutex(var); \ } #else -#define defl(var, type, held_lock, vm_block, safepoint_check_allowed) { \ - var = new type(Mutex::nonleaf, #var, Mutex::safepoint_check_allowed, vm_block); \ - add_mutex(var); \ +#define defl(var, type, held_lock, vm_block) { \ + var = new type(Mutex::safepoint, #var, vm_block); \ + add_mutex(var); \ } #endif // Using Padded subclasses to prevent false sharing of these global monitors and mutexes. void mutex_init() { - def(tty_lock , PaddedMutex , tty, true, _safepoint_check_never); // allow to lock in VM + def(tty_lock , PaddedMutex , tty, true); // allow to lock in VM - def(STS_lock , PaddedMonitor, nosafepoint, true, _safepoint_check_never); + def(STS_lock , PaddedMonitor, nosafepoint, true); if (UseG1GC) { - def(CGC_lock , PaddedMonitor, nosafepoint, true, _safepoint_check_never); + def(CGC_lock , PaddedMonitor, nosafepoint, true); - def(G1DetachedRefinementStats_lock, PaddedMutex, nosafepoint-2, true, _safepoint_check_never); + def(G1DetachedRefinementStats_lock, PaddedMutex, nosafepoint-2, true); - def(FreeList_lock , PaddedMutex , service-1, true, _safepoint_check_never); - def(OldSets_lock , PaddedMutex , nosafepoint, true, _safepoint_check_never); - def(Uncommit_lock , PaddedMutex , service-2, true, _safepoint_check_never); - def(RootRegionScan_lock , PaddedMonitor, nosafepoint-1, true, _safepoint_check_never); + def(FreeList_lock , PaddedMutex , service-1, true); + def(OldSets_lock , PaddedMutex , nosafepoint, true); + def(Uncommit_lock , PaddedMutex , service-2, true); + def(RootRegionScan_lock , PaddedMonitor, nosafepoint-1, true); - def(MarkStackFreeList_lock , PaddedMutex , nosafepoint, true, _safepoint_check_never); - def(MarkStackChunkList_lock , PaddedMutex , nosafepoint, true, _safepoint_check_never); + def(MarkStackFreeList_lock , PaddedMutex , nosafepoint, true); + def(MarkStackChunkList_lock , PaddedMutex , nosafepoint, true); - def(MonitoringSupport_lock , PaddedMutex , service-1, true, _safepoint_check_never); // used for serviceability monitoring support + def(MonitoringSupport_lock , PaddedMutex , service-1, true); // used for serviceability monitoring support } - def(StringDedup_lock , PaddedMonitor, nosafepoint, true, _safepoint_check_never); - def(StringDedupIntern_lock , PaddedMutex , nosafepoint, true, _safepoint_check_never); - def(ParGCRareEvent_lock , PaddedMutex , nonleaf, true, _safepoint_check_always); - def(RawMonitor_lock , PaddedMutex , nosafepoint-1, true, _safepoint_check_never); + def(StringDedup_lock , PaddedMonitor, nosafepoint, true); + def(StringDedupIntern_lock , PaddedMutex , nosafepoint, true); + def(ParGCRareEvent_lock , PaddedMutex , safepoint, true); + def(RawMonitor_lock , PaddedMutex , nosafepoint-1, true); - def(Metaspace_lock , PaddedMutex , nosafepoint-3, true, _safepoint_check_never); + def(Metaspace_lock , PaddedMutex , nosafepoint-3, true); - def(Patching_lock , PaddedMutex , nosafepoint, true, _safepoint_check_never); // used for safepointing and code patching. - def(MonitorDeflation_lock , PaddedMonitor, nosafepoint, true, _safepoint_check_never); // used for monitor deflation thread operations - def(Service_lock , PaddedMonitor, service, true, _safepoint_check_never); // used for service thread operations + def(Patching_lock , PaddedMutex , nosafepoint, true); // used for safepointing and code patching. + def(MonitorDeflation_lock , PaddedMonitor, nosafepoint, true); // used for monitor deflation thread operations + def(Service_lock , PaddedMonitor, service, true); // used for service thread operations if (UseNotificationThread) { - def(Notification_lock , PaddedMonitor, service, true, _safepoint_check_never); // used for notification thread operations + def(Notification_lock , PaddedMonitor, service, true); // used for notification thread operations } else { Notification_lock = Service_lock; } - def(JmethodIdCreation_lock , PaddedMutex , nosafepoint-2, true, _safepoint_check_never); // used for creating jmethodIDs. + def(JmethodIdCreation_lock , PaddedMutex , nosafepoint-2, true); // used for creating jmethodIDs. - def(SharedDictionary_lock , PaddedMutex , nonleaf, true, _safepoint_check_always); - def(VMStatistic_lock , PaddedMutex , nonleaf, false, _safepoint_check_always); - def(JNIHandleBlockFreeList_lock , PaddedMutex , nosafepoint-1, true, _safepoint_check_never); // handles are used by VM thread - def(SignatureHandlerLibrary_lock , PaddedMutex , nonleaf, false, _safepoint_check_always); - def(SymbolArena_lock , PaddedMutex , nosafepoint, true, _safepoint_check_never); - def(ExceptionCache_lock , PaddedMutex , nonleaf, false, _safepoint_check_always); + def(SharedDictionary_lock , PaddedMutex , safepoint, true); + def(VMStatistic_lock , PaddedMutex , safepoint, false); + def(JNIHandleBlockFreeList_lock , PaddedMutex , nosafepoint-1, true); // handles are used by VM thread + def(SignatureHandlerLibrary_lock , PaddedMutex , safepoint, false); + def(SymbolArena_lock , PaddedMutex , nosafepoint, true); + def(ExceptionCache_lock , PaddedMutex , safepoint, false); #ifndef PRODUCT - def(FullGCALot_lock , PaddedMutex , nonleaf, false, _safepoint_check_always); // a lock to make FullGCALot MT safe + def(FullGCALot_lock , PaddedMutex , safepoint, false); // a lock to make FullGCALot MT safe #endif - def(BeforeExit_lock , PaddedMonitor, nonleaf, true, _safepoint_check_always); + def(BeforeExit_lock , PaddedMonitor, safepoint, true); - def(NonJavaThreadsList_lock , PaddedMutex, nosafepoint-1, true, _safepoint_check_never); - def(NonJavaThreadsListSync_lock , PaddedMutex, nosafepoint, true, _safepoint_check_never); + def(NonJavaThreadsList_lock , PaddedMutex, nosafepoint-1, true); + def(NonJavaThreadsListSync_lock , PaddedMutex, nosafepoint, true); - def(RetData_lock , PaddedMutex , nonleaf, false, _safepoint_check_always); - def(Terminator_lock , PaddedMonitor, nonleaf, true, _safepoint_check_always); - def(InitCompleted_lock , PaddedMonitor, nosafepoint, true, _safepoint_check_never); - def(Notify_lock , PaddedMonitor, nonleaf, true, _safepoint_check_always); - def(JNICritical_lock , PaddedMonitor, nonleaf, true, _safepoint_check_always); // used for JNI critical regions - def(AdapterHandlerLibrary_lock , PaddedMutex , nonleaf, true, _safepoint_check_always); + def(RetData_lock , PaddedMutex , safepoint, false); + def(Terminator_lock , PaddedMonitor, safepoint, true); + def(InitCompleted_lock , PaddedMonitor, nosafepoint, true); + def(Notify_lock , PaddedMonitor, safepoint, true); + def(JNICritical_lock , PaddedMonitor, safepoint, true); // used for JNI critical regions + def(AdapterHandlerLibrary_lock , PaddedMutex , safepoint, true); - def(Heap_lock , PaddedMonitor, nonleaf, false, _safepoint_check_always); // Doesn't safepoint check during termination. - def(JfieldIdCreation_lock , PaddedMutex , nonleaf, true, _safepoint_check_always); // jfieldID, Used in VM_Operation + def(Heap_lock , PaddedMonitor, safepoint, false); // Doesn't safepoint check during termination. + def(JfieldIdCreation_lock , PaddedMutex , safepoint, true); // jfieldID, Used in VM_Operation - def(CompiledIC_lock , PaddedMutex , nosafepoint, true, _safepoint_check_never); // locks VtableStubs_lock, InlineCacheBuffer_lock - def(MethodCompileQueue_lock , PaddedMonitor, nonleaf, false, _safepoint_check_always); - def(CompileStatistics_lock , PaddedMutex , nonleaf, false, _safepoint_check_always); - def(DirectivesStack_lock , PaddedMutex , nosafepoint, true, _safepoint_check_never); - def(MultiArray_lock , PaddedMutex , nonleaf, false, _safepoint_check_always); + def(CompiledIC_lock , PaddedMutex , nosafepoint, true); // locks VtableStubs_lock, InlineCacheBuffer_lock + def(MethodCompileQueue_lock , PaddedMonitor, safepoint, false); + def(CompileStatistics_lock , PaddedMutex , safepoint, false); + def(DirectivesStack_lock , PaddedMutex , nosafepoint, true); + def(MultiArray_lock , PaddedMutex , safepoint, false); - def(JvmtiThreadState_lock , PaddedMutex , nonleaf, false, _safepoint_check_always); // Used by JvmtiThreadState/JvmtiEventController - def(EscapeBarrier_lock , PaddedMonitor, nosafepoint, true, _safepoint_check_never); // Used to synchronize object reallocation/relocking triggered by JVMTI - def(Management_lock , PaddedMutex , nonleaf, false, _safepoint_check_always); // used for JVM management + def(JvmtiThreadState_lock , PaddedMutex , safepoint, false); // Used by JvmtiThreadState/JvmtiEventController + def(EscapeBarrier_lock , PaddedMonitor, nosafepoint, true); // Used to synchronize object reallocation/relocking triggered by JVMTI + def(Management_lock , PaddedMutex , safepoint, false); // used for JVM management - def(ConcurrentGCBreakpoints_lock , PaddedMonitor, nonleaf, true, _safepoint_check_always); - def(MethodData_lock , PaddedMutex , nonleaf, false, _safepoint_check_always); - def(TouchedMethodLog_lock , PaddedMutex , nonleaf, false, _safepoint_check_always); + def(ConcurrentGCBreakpoints_lock , PaddedMonitor, safepoint, true); + def(MethodData_lock , PaddedMutex , safepoint, false); + def(TouchedMethodLog_lock , PaddedMutex , safepoint, false); - def(CompileThread_lock , PaddedMonitor, nonleaf, false, _safepoint_check_always); - def(PeriodicTask_lock , PaddedMonitor, nonleaf, true, _safepoint_check_always); - def(RedefineClasses_lock , PaddedMonitor, nonleaf, true, _safepoint_check_always); - def(Verify_lock , PaddedMutex, nonleaf, true, _safepoint_check_always); + def(CompileThread_lock , PaddedMonitor, safepoint, false); + def(PeriodicTask_lock , PaddedMonitor, safepoint, true); + def(RedefineClasses_lock , PaddedMonitor, safepoint, true); + def(Verify_lock , PaddedMutex, safepoint, true); if (WhiteBoxAPI) { - def(Compilation_lock , PaddedMonitor, nosafepoint, true, _safepoint_check_never); + def(Compilation_lock , PaddedMonitor, nosafepoint, true); } #if INCLUDE_JFR - def(JfrBuffer_lock , PaddedMutex , nosafepoint, true, _safepoint_check_never); - def(JfrStacktrace_lock , PaddedMutex , stackwatermark-1, true, _safepoint_check_never); - def(JfrThreadSampler_lock , PaddedMonitor, nosafepoint, true, _safepoint_check_never); + def(JfrBuffer_lock , PaddedMutex , nosafepoint, true); + def(JfrStacktrace_lock , PaddedMutex , stackwatermark-1, true); + def(JfrThreadSampler_lock , PaddedMonitor, nosafepoint, true); #endif #ifndef SUPPORTS_NATIVE_CX8 - def(UnsafeJlong_lock , PaddedMutex , nosafepoint, true, _safepoint_check_never); + def(UnsafeJlong_lock , PaddedMutex , nosafepoint, true); #endif - def(CodeHeapStateAnalytics_lock , PaddedMutex , nonleaf, false, _safepoint_check_always); - def(NMethodSweeperStats_lock , PaddedMutex , nosafepoint, true, _safepoint_check_never); - def(ThreadsSMRDelete_lock , PaddedMonitor, nosafepoint-3, true, _safepoint_check_never); // Holds ConcurrentHashTableResize_lock - def(ThreadIdTableCreate_lock , PaddedMutex , nonleaf, false, _safepoint_check_always); - def(SharedDecoder_lock , PaddedMutex , tty-1, true, _safepoint_check_never); - def(DCmdFactory_lock , PaddedMutex , nosafepoint, true, _safepoint_check_never); + def(CodeHeapStateAnalytics_lock , PaddedMutex , safepoint, false); + def(NMethodSweeperStats_lock , PaddedMutex , nosafepoint, true); + def(ThreadsSMRDelete_lock , PaddedMonitor, nosafepoint-3, true); // Holds ConcurrentHashTableResize_lock + def(ThreadIdTableCreate_lock , PaddedMutex , safepoint, false); + def(SharedDecoder_lock , PaddedMutex , tty-1, true); + def(DCmdFactory_lock , PaddedMutex , nosafepoint, true); #if INCLUDE_NMT - def(NMTQuery_lock , PaddedMutex , nonleaf, false, _safepoint_check_always); + def(NMTQuery_lock , PaddedMutex , safepoint, false); #endif #if INCLUDE_CDS #if INCLUDE_JVMTI - def(CDSClassFileStream_lock , PaddedMutex , nonleaf, false, _safepoint_check_always); + def(CDSClassFileStream_lock , PaddedMutex , safepoint, false); #endif - def(DumpTimeTable_lock , PaddedMutex , nosafepoint, true, _safepoint_check_never); - def(CDSLambda_lock , PaddedMutex , nosafepoint, true, _safepoint_check_never); - def(DumpRegion_lock , PaddedMutex , nosafepoint, true, _safepoint_check_never); - def(ClassListFile_lock , PaddedMutex , nosafepoint, true, _safepoint_check_never); - def(LambdaFormInvokers_lock , PaddedMutex , nonleaf, false, _safepoint_check_always); + def(DumpTimeTable_lock , PaddedMutex , nosafepoint, true); + def(CDSLambda_lock , PaddedMutex , nosafepoint, true); + def(DumpRegion_lock , PaddedMutex , nosafepoint, true); + def(ClassListFile_lock , PaddedMutex , nosafepoint, true); + def(LambdaFormInvokers_lock , PaddedMutex , safepoint, false); #endif // INCLUDE_CDS - def(Bootclasspath_lock , PaddedMutex , nosafepoint, true, _safepoint_check_never); - def(Zip_lock , PaddedMonitor, nosafepoint-1, true, _safepoint_check_never); // Holds DumpTimeTable_lock + def(Bootclasspath_lock , PaddedMutex , nosafepoint, true); + def(Zip_lock , PaddedMonitor, nosafepoint-1, true); // Holds DumpTimeTable_lock #if INCLUDE_JVMCI - def(JVMCI_lock , PaddedMonitor, nonleaf, true, _safepoint_check_always); + def(JVMCI_lock , PaddedMonitor, safepoint, true); #endif - // These locks have safepoint_check_never and relative rankings. - defl(InlineCacheBuffer_lock , PaddedMutex , CompiledIC_lock, true, _safepoint_check_never); - defl(VtableStubs_lock , PaddedMutex , CompiledIC_lock, true, _safepoint_check_never); // Also holds DumpTimeTable_lock - defl(CodeCache_lock , PaddedMonitor, VtableStubs_lock, true, _safepoint_check_never); - defl(CompiledMethod_lock , PaddedMutex , CodeCache_lock, true, _safepoint_check_never); - defl(CodeSweeper_lock , PaddedMonitor, CompiledMethod_lock, true, _safepoint_check_never); + // These locks have relative rankings, and inherit safepoint checking attributes from that rank. + defl(InlineCacheBuffer_lock , PaddedMutex , CompiledIC_lock, true); + defl(VtableStubs_lock , PaddedMutex , CompiledIC_lock, true); // Also holds DumpTimeTable_lock + defl(CodeCache_lock , PaddedMonitor, VtableStubs_lock, true); + defl(CompiledMethod_lock , PaddedMutex , CodeCache_lock, true); + defl(CodeSweeper_lock , PaddedMonitor, CompiledMethod_lock, true); - // These locks have safepoint_check_always and relative rankings. - defl(Threads_lock , PaddedMonitor, CompileThread_lock, true, _safepoint_check_always); - defl(Heap_lock , PaddedMonitor, MultiArray_lock, false, _safepoint_check_always); - defl(Compile_lock , PaddedMutex , MethodCompileQueue_lock, false, _safepoint_check_always); + defl(Threads_lock , PaddedMonitor, CompileThread_lock, true); + defl(Heap_lock , PaddedMonitor, MultiArray_lock, false); + defl(Compile_lock , PaddedMutex , MethodCompileQueue_lock, false); - defl(PerfDataMemAlloc_lock , PaddedMutex , Heap_lock, true, _safepoint_check_always); - defl(PerfDataManager_lock , PaddedMutex , Heap_lock, true, _safepoint_check_always); - defl(ClassLoaderDataGraph_lock , PaddedMutex , MultiArray_lock, false, _safepoint_check_always); - defl(VMOperation_lock , PaddedMonitor, Compile_lock, true, _safepoint_check_always); - defl(ClassInitError_lock , PaddedMonitor, Threads_lock, true, _safepoint_check_always); + defl(PerfDataMemAlloc_lock , PaddedMutex , Heap_lock, true); + defl(PerfDataManager_lock , PaddedMutex , Heap_lock, true); + defl(ClassLoaderDataGraph_lock , PaddedMutex , MultiArray_lock, false); + defl(VMOperation_lock , PaddedMonitor, Compile_lock, true); + defl(ClassInitError_lock , PaddedMonitor, Threads_lock, true); if (UseG1GC) { - defl(G1OldGCCount_lock , PaddedMonitor, Threads_lock, true, _safepoint_check_always); + defl(G1OldGCCount_lock , PaddedMonitor, Threads_lock, true); } - defl(CompileTaskAlloc_lock , PaddedMutex , MethodCompileQueue_lock, true, _safepoint_check_always); - defl(ExpandHeap_lock , PaddedMutex , Heap_lock, true, _safepoint_check_always); - defl(OopMapCacheAlloc_lock , PaddedMutex , Threads_lock, true, _safepoint_check_always); - defl(Module_lock , PaddedMutex , ClassLoaderDataGraph_lock, false, _safepoint_check_always); - defl(SystemDictionary_lock , PaddedMonitor, Module_lock, true, _safepoint_check_always); + defl(CompileTaskAlloc_lock , PaddedMutex , MethodCompileQueue_lock, true); + defl(ExpandHeap_lock , PaddedMutex , Heap_lock, true); + defl(OopMapCacheAlloc_lock , PaddedMutex , Threads_lock, true); + defl(Module_lock , PaddedMutex , ClassLoaderDataGraph_lock, false); + defl(SystemDictionary_lock , PaddedMonitor, Module_lock, true); #if INCLUDE_JFR - defl(JfrMsg_lock , PaddedMonitor, Module_lock, true, _safepoint_check_always); + defl(JfrMsg_lock , PaddedMonitor, Module_lock, true); #endif } diff --git a/src/hotspot/share/runtime/stackWatermark.cpp b/src/hotspot/share/runtime/stackWatermark.cpp index 921210c2dc3..397f9332dff 100644 --- a/src/hotspot/share/runtime/stackWatermark.cpp +++ b/src/hotspot/share/runtime/stackWatermark.cpp @@ -164,7 +164,7 @@ StackWatermark::StackWatermark(JavaThread* jt, StackWatermarkKind kind, uint32_t _next(NULL), _jt(jt), _iterator(NULL), - _lock(Mutex::stackwatermark, "StackWatermark_lock", Mutex::_safepoint_check_never), + _lock(Mutex::stackwatermark, "StackWatermark_lock"), _kind(kind), _linked_watermark(NULL) { } diff --git a/src/hotspot/share/runtime/vmOperations.cpp b/src/hotspot/share/runtime/vmOperations.cpp index ed728f1a1da..a84ff5f0bb1 100644 --- a/src/hotspot/share/runtime/vmOperations.cpp +++ b/src/hotspot/share/runtime/vmOperations.cpp @@ -368,7 +368,7 @@ int VM_Exit::wait_for_threads_in_native_to_block() { assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint already"); Thread * thr_cur = Thread::current(); - Monitor timer(Mutex::nosafepoint, "VM_ExitTimer_lock", Monitor::_safepoint_check_never); + Monitor timer(Mutex::nosafepoint, "VM_ExitTimer_lock"); // Compiler threads need longer wait because they can access VM data directly // while in native. If they are active and some structures being used are diff --git a/src/hotspot/share/runtime/vmThread.cpp b/src/hotspot/share/runtime/vmThread.cpp index 63341d8a8ab..08d58de97fd 100644 --- a/src/hotspot/share/runtime/vmThread.cpp +++ b/src/hotspot/share/runtime/vmThread.cpp @@ -128,8 +128,7 @@ void VMThread::create() { assert(_timeout_task == NULL, "sanity"); } - _terminate_lock = new Monitor(Mutex::nosafepoint, "VMThreadTerminate_lock", - Monitor::_safepoint_check_never); + _terminate_lock = new Monitor(Mutex::nosafepoint, "VMThreadTerminate_lock"); if (UsePerfData) { // jvmstat performance counters diff --git a/src/hotspot/share/services/heapDumper.cpp b/src/hotspot/share/services/heapDumper.cpp index b46a27b1673..8c21c80f772 100644 --- a/src/hotspot/share/services/heapDumper.cpp +++ b/src/hotspot/share/services/heapDumper.cpp @@ -748,7 +748,7 @@ class ParDumpWriter : public AbstractDumpWriter { static void before_work() { assert(_lock == NULL, "ParDumpWriter lock must be initialized only once"); - _lock = new (std::nothrow) PaddedMonitor(Mutex::nonleaf, "ParallelHProfWriter_lock", Mutex::_safepoint_check_always); + _lock = new (std::nothrow) PaddedMonitor(Mutex::safepoint, "ParallelHProfWriter_lock"); } static void after_work() { @@ -1814,8 +1814,7 @@ class DumperController : public CHeapObj { public: DumperController(uint number) : _started(false), - _lock(new (std::nothrow) PaddedMonitor(Mutex::nonleaf, "DumperController_lock", - Mutex::_safepoint_check_always)), + _lock(new (std::nothrow) PaddedMonitor(Mutex::safepoint, "DumperController_lock")), _dumper_number(number), _complete_number(0) { } diff --git a/src/hotspot/share/services/heapDumperCompression.cpp b/src/hotspot/share/services/heapDumperCompression.cpp index 8063528b6f8..0d642601797 100644 --- a/src/hotspot/share/services/heapDumperCompression.cpp +++ b/src/hotspot/share/services/heapDumperCompression.cpp @@ -200,8 +200,7 @@ CompressionBackend::CompressionBackend(AbstractWriter* writer, _written(0), _writer(writer), _compressor(compressor), - _lock(new (std::nothrow) PaddedMonitor(Mutex::nosafepoint, "HProfCompressionBackend_lock", - Mutex::_safepoint_check_never)) { + _lock(new (std::nothrow) PaddedMonitor(Mutex::nosafepoint, "HProfCompressionBackend_lock")) { if (_writer == NULL) { set_error("Could not allocate writer"); } else if (_lock == NULL) { diff --git a/src/hotspot/share/services/memoryManager.cpp b/src/hotspot/share/services/memoryManager.cpp index 30a14f77745..11abafa94fe 100644 --- a/src/hotspot/share/services/memoryManager.cpp +++ b/src/hotspot/share/services/memoryManager.cpp @@ -174,8 +174,7 @@ GCMemoryManager::GCMemoryManager(const char* name, const char* gc_end_message) : MemoryManager(name), _gc_end_message(gc_end_message) { _num_collections = 0; _last_gc_stat = NULL; - _last_gc_lock = new Mutex(Mutex::nosafepoint, "GCMemoryManager_lock", - Mutex::_safepoint_check_never); + _last_gc_lock = new Mutex(Mutex::nosafepoint, "GCMemoryManager_lock"); _current_gc_stat = NULL; _num_gc_threads = 1; _notification_enabled = false; diff --git a/src/hotspot/share/utilities/concurrentHashTable.inline.hpp b/src/hotspot/share/utilities/concurrentHashTable.inline.hpp index fcfb350dfe2..85a899c57b6 100644 --- a/src/hotspot/share/utilities/concurrentHashTable.inline.hpp +++ b/src/hotspot/share/utilities/concurrentHashTable.inline.hpp @@ -1014,8 +1014,7 @@ inline ConcurrentHashTable:: { _stats_rate = TableRateStatistics(); _resize_lock = - new Mutex(Mutex::nosafepoint-2, "ConcurrentHashTableResize_lock", - Mutex::_safepoint_check_never); + new Mutex(Mutex::nosafepoint-2, "ConcurrentHashTableResize_lock"); _table = new InternalTable(log2size); assert(log2size_limit >= log2size, "bad ergo"); _size_limit_reached = _table->_log2_size == _log2_size_limit; diff --git a/src/hotspot/share/utilities/events.hpp b/src/hotspot/share/utilities/events.hpp index 7f9ae6909f7..851526ae568 100644 --- a/src/hotspot/share/utilities/events.hpp +++ b/src/hotspot/share/utilities/events.hpp @@ -100,7 +100,7 @@ template class EventLogBase : public EventLog { public: EventLogBase(const char* name, const char* handle, int length = LogEventsBufferEntries): - _mutex(Mutex::event, name, Mutex::_safepoint_check_never), + _mutex(Mutex::event, name), _name(name), _handle(handle), _length(length), diff --git a/test/hotspot/gtest/metaspace/test_is_metaspace_obj.cpp b/test/hotspot/gtest/metaspace/test_is_metaspace_obj.cpp index 9ddc7665c9a..820ad1fd3d1 100644 --- a/test/hotspot/gtest/metaspace/test_is_metaspace_obj.cpp +++ b/test/hotspot/gtest/metaspace/test_is_metaspace_obj.cpp @@ -49,7 +49,7 @@ public: } void do_test(Metaspace::MetadataType mdType) { - _lock = new Mutex(Monitor::nosafepoint, "gtest-IsMetaspaceObjTest_lock", Monitor::_safepoint_check_never); + _lock = new Mutex(Monitor::nosafepoint, "gtest-IsMetaspaceObjTest_lock"); { MutexLocker ml(_lock, Mutex::_no_safepoint_check_flag); _ms = new ClassLoaderMetaspace(_lock, Metaspace::StandardMetaspaceType); diff --git a/test/hotspot/gtest/metaspace/test_metaspacearena.cpp b/test/hotspot/gtest/metaspace/test_metaspacearena.cpp index bc43e21d480..68d9800829a 100644 --- a/test/hotspot/gtest/metaspace/test_metaspacearena.cpp +++ b/test/hotspot/gtest/metaspace/test_metaspacearena.cpp @@ -66,7 +66,7 @@ class MetaspaceArenaTestHelper { void initialize(const ArenaGrowthPolicy* growth_policy, const char* name = "gtest-MetaspaceArena") { _growth_policy = growth_policy; - _lock = new Mutex(Monitor::nosafepoint, "gtest-MetaspaceArenaTest_lock", Monitor::_safepoint_check_never); + _lock = new Mutex(Monitor::nosafepoint, "gtest-MetaspaceArenaTest_lock"); // Lock during space creation, since this is what happens in the VM too // (see ClassLoaderData::metaspace_non_null(), which we mimick here). { diff --git a/test/hotspot/gtest/metaspace/test_metaspacearena_stress.cpp b/test/hotspot/gtest/metaspace/test_metaspacearena_stress.cpp index 9a45107f50a..50c5d0bc0e1 100644 --- a/test/hotspot/gtest/metaspace/test_metaspacearena_stress.cpp +++ b/test/hotspot/gtest/metaspace/test_metaspacearena_stress.cpp @@ -142,7 +142,7 @@ public: _alloc_count(), _dealloc_count() { - _lock = new Mutex(Monitor::nosafepoint, "gtest-MetaspaceArenaTestBed_lock", Monitor::_safepoint_check_never); + _lock = new Mutex(Monitor::nosafepoint, "gtest-MetaspaceArenaTestBed_lock"); // Lock during space creation, since this is what happens in the VM too // (see ClassLoaderData::metaspace_non_null(), which we mimick here). MutexLocker ml(_lock, Mutex::_no_safepoint_check_flag); diff --git a/test/hotspot/gtest/runtime/test_mutex.cpp b/test/hotspot/gtest/runtime/test_mutex.cpp index ee7bc392123..e620a1663ab 100644 --- a/test/hotspot/gtest/runtime/test_mutex.cpp +++ b/test/hotspot/gtest/runtime/test_mutex.cpp @@ -35,7 +35,7 @@ static Mutex* m[iterations]; static int i = 0; static void create_mutex(Thread* thr) { - m[i] = new Mutex(Mutex::nosafepoint, FormatBuffer<128>("MyLock#%u_lock", i), Mutex::_safepoint_check_never); + m[i] = new Mutex(Mutex::nosafepoint, FormatBuffer<128>("MyLock#%u_lock", i)); i++; } @@ -53,16 +53,16 @@ TEST_VM(MutexName, mutex_name) { #ifdef ASSERT -const int rankA = Mutex::nonleaf-5; -const int rankAplusOne = Mutex::nonleaf-4; -const int rankAplusTwo = Mutex::nonleaf-3; +const Mutex::Rank rankA = Mutex::safepoint-5; +const Mutex::Rank rankAplusOne = Mutex::safepoint-4; +const Mutex::Rank rankAplusTwo = Mutex::safepoint-3; TEST_OTHER_VM(MutexRank, mutex_lock_rank_in_order) { JavaThread* THREAD = JavaThread::current(); ThreadInVMfromNative invm(THREAD); - Mutex* mutex_rankA = new Mutex(rankA, "mutex_rankA", Mutex::_safepoint_check_always); - Mutex* mutex_rankA_plus_one = new Mutex(rankAplusOne, "mutex_rankA_plus_one", Mutex::_safepoint_check_always); + Mutex* mutex_rankA = new Mutex(rankA, "mutex_rankA"); + Mutex* mutex_rankA_plus_one = new Mutex(rankAplusOne, "mutex_rankA_plus_one"); mutex_rankA_plus_one->lock(); mutex_rankA->lock(); @@ -71,12 +71,12 @@ TEST_OTHER_VM(MutexRank, mutex_lock_rank_in_order) { } TEST_VM_ASSERT_MSG(MutexRank, mutex_lock_rank_out_of_orderA, - ".* Attempting to acquire lock mutex_rankA_plus_one/.* out of order with lock mutex_rankA/.* -- possible deadlock") { + ".* Attempting to acquire lock mutex_rankA_plus_one/safepoint-4 out of order with lock mutex_rankA/safepoint-5 -- possible deadlock") { JavaThread* THREAD = JavaThread::current(); ThreadInVMfromNative invm(THREAD); - Mutex* mutex_rankA = new Mutex(rankA, "mutex_rankA", Mutex::_safepoint_check_always); - Mutex* mutex_rankA_plus_one = new Mutex(rankAplusOne, "mutex_rankA_plus_one", Mutex::_safepoint_check_always); + Mutex* mutex_rankA = new Mutex(rankA, "mutex_rankA"); + Mutex* mutex_rankA_plus_one = new Mutex(rankAplusOne, "mutex_rankA_plus_one"); mutex_rankA->lock(); mutex_rankA_plus_one->lock(); @@ -89,8 +89,8 @@ TEST_VM_ASSERT_MSG(MutexRank, mutex_lock_rank_out_of_orderB, JavaThread* THREAD = JavaThread::current(); ThreadInVMfromNative invm(THREAD); - Mutex* mutex_rankA = new Mutex(rankA, "mutex_rankA", Mutex::_safepoint_check_always); - Mutex* mutex_rankB = new Mutex(rankA, "mutex_rankB", Mutex::_safepoint_check_always); + Mutex* mutex_rankA = new Mutex(rankA, "mutex_rankA"); + Mutex* mutex_rankB = new Mutex(rankA, "mutex_rankB"); mutex_rankA->lock(); mutex_rankB->lock(); @@ -102,9 +102,9 @@ TEST_OTHER_VM(MutexRank, mutex_trylock_rank_out_of_orderA) { JavaThread* THREAD = JavaThread::current(); ThreadInVMfromNative invm(THREAD); - Mutex* mutex_rankA = new Mutex(rankA, "mutex_rankA", Mutex::_safepoint_check_always); - Mutex* mutex_rankA_plus_one = new Mutex(rankAplusOne, "mutex_rankA_plus_one", Mutex::_safepoint_check_always); - Mutex* mutex_rankA_plus_two = new Mutex(rankAplusTwo, "mutex_rankA_plus_two", Mutex::_safepoint_check_always); + Mutex* mutex_rankA = new Mutex(rankA, "mutex_rankA"); + Mutex* mutex_rankA_plus_one = new Mutex(rankAplusOne, "mutex_rankA_plus_one"); + Mutex* mutex_rankA_plus_two = new Mutex(rankAplusTwo, "mutex_rankA_plus_two"); mutex_rankA_plus_one->lock(); mutex_rankA_plus_two->try_lock_without_rank_check(); @@ -119,8 +119,8 @@ TEST_VM_ASSERT_MSG(MutexRank, mutex_trylock_rank_out_of_orderB, JavaThread* THREAD = JavaThread::current(); ThreadInVMfromNative invm(THREAD); - Mutex* mutex_rankA = new Mutex(rankA, "mutex_rankA", Mutex::_safepoint_check_always); - Mutex* mutex_rankA_plus_one = new Mutex(rankAplusOne, "mutex_rankA_plus_one", Mutex::_safepoint_check_always); + Mutex* mutex_rankA = new Mutex(rankA, "mutex_rankA"); + Mutex* mutex_rankA_plus_one = new Mutex(rankAplusOne, "mutex_rankA_plus_one"); mutex_rankA->lock(); mutex_rankA_plus_one->try_lock_without_rank_check(); @@ -131,28 +131,28 @@ TEST_VM_ASSERT_MSG(MutexRank, mutex_trylock_rank_out_of_orderB, } TEST_VM_ASSERT_MSG(MutexRank, mutex_lock_event_nosafepoint, - ".* Attempting to acquire lock mutex_rank_nosafepoint/.* out of order with lock mutex_rank_event/0 " + ".* Attempting to acquire lock mutex_rank_nosafepoint/nosafepoint out of order with lock mutex_rank_event/event " "-- possible deadlock") { JavaThread* THREAD = JavaThread::current(); ThreadInVMfromNative invm(THREAD); - Mutex* mutex_rank_event = new Mutex(Mutex::event, "mutex_rank_event", Mutex::_safepoint_check_never); - Mutex* mutex_rank_nonleaf = new Mutex(Mutex::nosafepoint, "mutex_rank_nosafepoint", Mutex::_safepoint_check_never); + Mutex* mutex_rank_event = new Mutex(Mutex::event, "mutex_rank_event"); + Mutex* mutex_rank_safepoint = new Mutex(Mutex::nosafepoint, "mutex_rank_nosafepoint"); mutex_rank_event->lock_without_safepoint_check(); - mutex_rank_nonleaf->lock_without_safepoint_check(); - mutex_rank_nonleaf->unlock(); + mutex_rank_safepoint->lock_without_safepoint_check(); + mutex_rank_safepoint->unlock(); mutex_rank_event->unlock(); } TEST_VM_ASSERT_MSG(MutexRank, mutex_lock_tty_nosafepoint, - ".* Attempting to acquire lock mutex_rank_nosafepoint/.* out of order with lock mutex_rank_tty/.*" + ".* Attempting to acquire lock mutex_rank_nosafepoint/nosafepoint out of order with lock mutex_rank_tty/tty " "-- possible deadlock") { JavaThread* THREAD = JavaThread::current(); ThreadInVMfromNative invm(THREAD); - Mutex* mutex_rank_tty = new Mutex(Mutex::tty, "mutex_rank_tty", Mutex::_safepoint_check_never); - Mutex* mutex_rank_nosafepoint = new Mutex(Mutex::nosafepoint, "mutex_rank_nosafepoint", Mutex::_safepoint_check_never); + Mutex* mutex_rank_tty = new Mutex(Mutex::tty, "mutex_rank_tty"); + Mutex* mutex_rank_nosafepoint = new Mutex(Mutex::nosafepoint, "mutex_rank_nosafepoint"); mutex_rank_tty->lock_without_safepoint_check(); mutex_rank_nosafepoint->lock_without_safepoint_check(); @@ -164,8 +164,8 @@ TEST_OTHER_VM(MutexRank, monitor_wait_rank_in_order) { JavaThread* THREAD = JavaThread::current(); ThreadInVMfromNative invm(THREAD); - Monitor* monitor_rankA = new Monitor(rankA, "monitor_rankA", Mutex::_safepoint_check_always); - Monitor* monitor_rankA_plus_one = new Monitor(rankAplusOne, "monitor_rankA_plus_one", Mutex::_safepoint_check_always); + Monitor* monitor_rankA = new Monitor(rankA, "monitor_rankA"); + Monitor* monitor_rankA_plus_one = new Monitor(rankAplusOne, "monitor_rankA_plus_one"); monitor_rankA_plus_one->lock(); monitor_rankA->lock(); @@ -180,8 +180,8 @@ TEST_VM_ASSERT_MSG(MutexRank, monitor_wait_rank_out_of_order, JavaThread* THREAD = JavaThread::current(); ThreadInVMfromNative invm(THREAD); - Monitor* monitor_rankA = new Monitor(rankA, "monitor_rankA", Mutex::_safepoint_check_always); - Monitor* monitor_rankA_plus_one = new Monitor(rankAplusOne, "monitor_rankA_plus_one", Mutex::_safepoint_check_always); + Monitor* monitor_rankA = new Monitor(rankA, "monitor_rankA"); + Monitor* monitor_rankA_plus_one = new Monitor(rankAplusOne, "monitor_rankA_plus_one"); monitor_rankA_plus_one->lock(); monitor_rankA->lock(); @@ -196,8 +196,8 @@ TEST_VM_ASSERT_MSG(MutexRank, monitor_wait_rank_out_of_order_trylock, JavaThread* THREAD = JavaThread::current(); ThreadInVMfromNative invm(THREAD); - Monitor* monitor_rankA = new Monitor(rankA, "monitor_rankA", Mutex::_safepoint_check_always); - Monitor* monitor_rankA_plus_one = new Monitor(rankAplusOne, "monitor_rankA_plus_one", Mutex::_safepoint_check_always); + Monitor* monitor_rankA = new Monitor(rankA, "monitor_rankA"); + Monitor* monitor_rankA_plus_one = new Monitor(rankAplusOne, "monitor_rankA_plus_one"); monitor_rankA->lock(); monitor_rankA_plus_one->try_lock_without_rank_check(); @@ -212,8 +212,9 @@ TEST_VM_ASSERT_MSG(MutexRank, monitor_wait_rank_nosafepoint, JavaThread* THREAD = JavaThread::current(); ThreadInVMfromNative invm(THREAD); - Monitor* monitor_rank_nosafepoint = new Monitor(Mutex::nosafepoint, "monitor_rank_nosafepoint", Mutex::_safepoint_check_never); - Monitor* monitor_rank_nosafepoint_minus_one = new Monitor(Mutex::nosafepoint - 1, "monitor_rank_nosafepoint_minus_one", Mutex::_safepoint_check_never); + Monitor* monitor_rank_nosafepoint = new Monitor(Mutex::nosafepoint, "monitor_rank_nosafepoint"); + Monitor* monitor_rank_nosafepoint_minus_one = new Monitor(Mutex::nosafepoint - 1, + "monitor_rank_nosafepoint_minus_one"); monitor_rank_nosafepoint->lock_without_safepoint_check(); monitor_rank_nosafepoint_minus_one->lock_without_safepoint_check(); @@ -226,8 +227,8 @@ TEST_VM_ASSERT_MSG(MutexRank, monitor_wait_rank_nosafepoint, class VM_MutexWaitTTY : public VM_GTestExecuteAtSafepoint { public: void doit() { - Monitor* monitor_rank_tty = new Monitor(Mutex::tty, "monitor_rank_tty", Mutex::_safepoint_check_never); - Monitor* monitor_rank_event = new Monitor(Mutex::event, "monitor_rank_event", Mutex::_safepoint_check_never); + Monitor* monitor_rank_tty = new Monitor(Mutex::tty, "monitor_rank_tty"); + Monitor* monitor_rank_event = new Monitor(Mutex::event, "monitor_rank_event"); monitor_rank_tty->lock_without_safepoint_check(); monitor_rank_event->lock_without_safepoint_check(); @@ -238,7 +239,7 @@ class VM_MutexWaitTTY : public VM_GTestExecuteAtSafepoint { }; TEST_VM_ASSERT_MSG(MutexRank, monitor_wait_event_tty, - ".* Attempting to wait on monitor monitor_rank_event/0 while holding lock monitor_rank_tty/.*" + ".* Attempting to wait on monitor monitor_rank_event/event while holding lock monitor_rank_tty/tty " "-- possible deadlock. Should not block\\(wait\\) while holding a lock of rank tty or below.") { VM_MutexWaitTTY op; ThreadInVMfromNative invm(JavaThread::current()); @@ -246,13 +247,13 @@ TEST_VM_ASSERT_MSG(MutexRank, monitor_wait_event_tty, } TEST_VM_ASSERT_MSG(MutexRank, monitor_wait_tty_nosafepoint, - ".* Attempting to wait on monitor monitor_rank_tty/.* while holding lock monitor_rank_nosafepoint/.*" + ".* Attempting to wait on monitor monitor_rank_tty/.* while holding lock monitor_rank_nosafepoint/.* " "-- possible deadlock. Should not block\\(wait\\) while holding a lock of rank nosafepoint or below.") { JavaThread* THREAD = JavaThread::current(); ThreadInVMfromNative invm(THREAD); - Monitor* monitor_rank_nosafepoint = new Monitor(Mutex::nosafepoint, "monitor_rank_nosafepoint", Mutex::_safepoint_check_never); - Monitor* monitor_rank_tty = new Monitor(Mutex::tty, "monitor_rank_tty", Mutex::_safepoint_check_never); + Monitor* monitor_rank_nosafepoint = new Monitor(Mutex::nosafepoint, "monitor_rank_nosafepoint"); + Monitor* monitor_rank_tty = new Monitor(Mutex::tty, "monitor_rank_tty"); monitor_rank_nosafepoint->lock_without_safepoint_check(); monitor_rank_tty->lock_without_safepoint_check(); @@ -262,11 +263,11 @@ TEST_VM_ASSERT_MSG(MutexRank, monitor_wait_tty_nosafepoint, } TEST_VM_ASSERT_MSG(MutexRank, monitor_nosafepoint_vm_block, - ".*Safepoint check never locks should always allow the vm to block") { + ".*Locks that don't check for safepoint should always allow the vm to block: monitor_rank_nosafepoint") { JavaThread* THREAD = JavaThread::current(); ThreadInVMfromNative invm(THREAD); - Monitor* monitor_rank_nosafepoint = new Monitor(Mutex::nosafepoint, "monitor_rank_nosafepoint", Mutex::_safepoint_check_never, false); + Monitor* monitor_rank_nosafepoint = new Monitor(Mutex::nosafepoint, "monitor_rank_nosafepoint", false); monitor_rank_nosafepoint->lock_without_safepoint_check(); monitor_rank_nosafepoint->unlock(); } @@ -276,18 +277,58 @@ TEST_VM_ASSERT_MSG(MutexRank, monitor_negative_rank, JavaThread* THREAD = JavaThread::current(); ThreadInVMfromNative invm(THREAD); - Monitor* monitor_rank_broken = new Monitor(Mutex::event-1, "monitor_rank_broken", Mutex::_safepoint_check_never); + Monitor* monitor_rank_broken = new Monitor(Mutex::safepoint-100, "monitor_rank_broken"); monitor_rank_broken->lock_without_safepoint_check(); monitor_rank_broken->unlock(); } -TEST_VM_ASSERT_MSG(MutexRank, monitor_nosafepoint_rank, - ".*failed: Locks above nosafepoint rank should safepoint: monitor_rank_nonleaf") { +TEST_VM_ASSERT_MSG(MutexRank, monitor_overlapping_oopstorage_rank, + ".*Rank oopstorage-4 overlaps with tty-1") { JavaThread* THREAD = JavaThread::current(); ThreadInVMfromNative invm(THREAD); - Monitor* monitor_rank_nonleaf = new Monitor(Mutex::nonleaf, "monitor_rank_nonleaf", Mutex::_safepoint_check_never); - monitor_rank_nonleaf->lock_without_safepoint_check(); - monitor_rank_nonleaf->unlock(); + Monitor* monitor_rank_broken = new Monitor(Mutex::oopstorage-4, "monitor_rank_broken"); +} + +TEST_VM_ASSERT_MSG(MutexRank, monitor_overlapping_safepoint_rank, + ".*Rank safepoint-40 overlaps with service-5") { + JavaThread* THREAD = JavaThread::current(); + ThreadInVMfromNative invm(THREAD); + + Monitor* monitor_rank_broken = new Monitor(Mutex::safepoint-40, "monitor_rank_broken"); +} + +TEST_VM_ASSERT_MSG(MutexRank, monitor_overlapping_safepoint_rank2, + ".*Rank safepoint-1-39 overlaps with service-5") { + JavaThread* THREAD = JavaThread::current(); + ThreadInVMfromNative invm(THREAD); + + Monitor* monitor_rank_ok = new Monitor(Mutex::safepoint-1, "monitor_rank_ok"); + Monitor* monitor_rank_broken = new Monitor(monitor_rank_ok->rank()-39, "monitor_rank_broken"); +} + +// Test mismatched safepoint check flag on lock declaration vs. lock acquisition. +TEST_VM_ASSERT_MSG(MutexSafepoint, always_check, + ".*This lock should always have a safepoint check for Java threads: SFPT_Test_lock") { + MutexLocker ml(new Mutex(Mutex::safepoint, "SFPT_Test_lock"), + Mutex::_no_safepoint_check_flag); +} + +TEST_VM_ASSERT_MSG(MutexSafepoint, never_check, + ".*This lock should not be taken with a safepoint check: SFPT_Test_lock") { + MutexLocker ml(new Mutex(Mutex::nosafepoint, "SFPT_Test_lock"), + Mutex::_safepoint_check_flag); +} + +TEST_VM_ASSERT_MSG(MutexSafepoint, possible_safepoint_lock, + ".* Possible safepoint reached by thread that does not allow it") { + JavaThread* thread = JavaThread::current(); + ThreadInVMfromNative in_native(thread); + MutexLocker ml(new Mutex(Mutex::nosafepoint, "SpecialTest_lock"), + Mutex::_no_safepoint_check_flag); + thread->print_thread_state_on(tty); + // If the lock above succeeds, try to safepoint to test the NSV implied with this nosafepoint lock. + ThreadBlockInVM tbivm(thread); + thread->print_thread_state_on(tty); } #endif // ASSERT diff --git a/test/hotspot/gtest/runtime/test_safepoint_locks.cpp b/test/hotspot/gtest/runtime/test_safepoint_locks.cpp deleted file mode 100644 index a89785fe046..00000000000 --- a/test/hotspot/gtest/runtime/test_safepoint_locks.cpp +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "runtime/interfaceSupport.inline.hpp" -#include "runtime/mutex.hpp" -#include "runtime/mutexLocker.hpp" -#include "unittest.hpp" - -#ifdef ASSERT - -// Test mismatched safepoint check flag on lock declaration vs. lock acquisition. -TEST_VM_ASSERT_MSG(SafepointLockAssertTest, always_check, - ".*This lock should always have a safepoint check for Java threads: SFPT_Test_lock") { - MutexLocker ml(new Mutex(Mutex::nonleaf, "SFPT_Test_lock", Mutex::_safepoint_check_always), - Mutex::_no_safepoint_check_flag); -} - -TEST_VM_ASSERT_MSG(SafepointLockAssertTest, never_check, - ".*This lock should never have a safepoint check for Java threads: SFPT_Test_lock") { - MutexLocker ml(new Mutex(Mutex::nosafepoint, "SFPT_Test_lock", Mutex::_safepoint_check_never), - Mutex::_safepoint_check_flag); -} - -TEST_VM_ASSERT_MSG(SafepointLockAssertTest, nosafepoint_locks, - ".*Locks below nosafepoint rank should never safepoint: SpecialTest_lock") { - MutexLocker ml(new Mutex(Mutex::nosafepoint, "SpecialTest_lock", Mutex::_safepoint_check_always), - Mutex::_safepoint_check_flag); -} - -TEST_VM_ASSERT_MSG(SafepointLockAssertTest, possible_safepoint_lock, - ".* Possible safepoint reached by thread that does not allow it") { - JavaThread* thread = JavaThread::current(); - ThreadInVMfromNative in_native(thread); - MutexLocker ml(new Mutex(Mutex::nosafepoint, "SpecialTest_lock", Mutex::_safepoint_check_never), - Mutex::_no_safepoint_check_flag); - thread->print_thread_state_on(tty); - // If the lock above succeeds, try to safepoint to test the NSV implied with this nosafepoint lock. - ThreadBlockInVM tbivm(thread); - thread->print_thread_state_on(tty); -} - -#endif // ASSERT diff --git a/test/hotspot/gtest/utilities/test_filterQueue.cpp b/test/hotspot/gtest/utilities/test_filterQueue.cpp index a7dc39ef20d..60b1e2d8b8b 100644 --- a/test/hotspot/gtest/utilities/test_filterQueue.cpp +++ b/test/hotspot/gtest/utilities/test_filterQueue.cpp @@ -196,7 +196,7 @@ public: TEST_VM(FilterQueue, stress) { FilterQueue queue; - Mutex lock(Mutex::nosafepoint, "Test_lock", Mutex::_safepoint_check_never); + Mutex lock(Mutex::nosafepoint, "Test_lock"); static const int nthreads = 4; Semaphore post; FilterQueueTestThread* threads[nthreads] = {}; -- GitLab From 2aacd4220a01b467de671212c7a74e6c81a2ad3c Mon Sep 17 00:00:00 2001 From: Roland Westrelin Date: Fri, 8 Oct 2021 14:48:35 +0000 Subject: [PATCH 142/385] 8274145: C2: condition incorrectly made redundant with dominating main loop exit condition Reviewed-by: kvn, neliasso --- src/hotspot/share/opto/loopnode.hpp | 2 + src/hotspot/share/opto/loopopts.cpp | 22 ++- .../TestIfReplacedByMainLoopExit.java | 126 ++++++++++++++++++ 3 files changed, 149 insertions(+), 1 deletion(-) create mode 100644 test/hotspot/jtreg/compiler/loopopts/TestIfReplacedByMainLoopExit.java diff --git a/src/hotspot/share/opto/loopnode.hpp b/src/hotspot/share/opto/loopnode.hpp index 47fa319466a..15a55408314 100644 --- a/src/hotspot/share/opto/loopnode.hpp +++ b/src/hotspot/share/opto/loopnode.hpp @@ -1632,6 +1632,8 @@ public: Node* compute_early_ctrl(Node* n, Node* n_ctrl); void try_sink_out_of_loop(Node* n); + + bool safe_for_if_replacement(const Node* dom) const; }; diff --git a/src/hotspot/share/opto/loopopts.cpp b/src/hotspot/share/opto/loopopts.cpp index fe117797e3f..2e8c7c20ef4 100644 --- a/src/hotspot/share/opto/loopopts.cpp +++ b/src/hotspot/share/opto/loopopts.cpp @@ -1392,7 +1392,8 @@ void PhaseIdealLoop::split_if_with_blocks_post(Node *n) { Node *prevdom = n; Node *dom = idom(prevdom); while (dom != cutoff) { - if (dom->req() > 1 && dom->in(1) == bol && prevdom->in(0) == dom) { + if (dom->req() > 1 && dom->in(1) == bol && prevdom->in(0) == dom && + safe_for_if_replacement(dom)) { // It's invalid to move control dependent data nodes in the inner // strip-mined loop, because: // 1) break validation of LoopNode::verify_strip_mined() @@ -1430,6 +1431,25 @@ void PhaseIdealLoop::split_if_with_blocks_post(Node *n) { } } +bool PhaseIdealLoop::safe_for_if_replacement(const Node* dom) const { + if (!dom->is_CountedLoopEnd()) { + return true; + } + CountedLoopEndNode* le = dom->as_CountedLoopEnd(); + CountedLoopNode* cl = le->loopnode(); + if (cl == NULL) { + return true; + } + if (!cl->is_main_loop()) { + return true; + } + if (cl->is_canonical_loop_entry() == NULL) { + return true; + } + // Further unrolling is possible so loop exit condition might change + return false; +} + // See if a shared loop-varying computation has no loop-varying uses. // Happens if something is only used for JVM state in uncommon trap exits, // like various versions of induction variable+offset. Clone the diff --git a/test/hotspot/jtreg/compiler/loopopts/TestIfReplacedByMainLoopExit.java b/test/hotspot/jtreg/compiler/loopopts/TestIfReplacedByMainLoopExit.java new file mode 100644 index 00000000000..a6ac62a2dd6 --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/TestIfReplacedByMainLoopExit.java @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2021, 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 8274145 + * @summary C2: Incorrect computation after JDK-8269752 + * + * @run main/othervm -Xcomp -XX:CompileOnly=TestIfReplacedByMainLoopExit::iMeth -XX:CompileOnly=TestIfReplacedByMainLoopExit::mainTest -XX:-TieredCompilation TestIfReplacedByMainLoopExit + * + */ + +public class TestIfReplacedByMainLoopExit { + + public static final int N = 400; + + public static long instanceCount=3024694135L; + public static boolean bFld=true; + public int iFld=-11; + + public static long iMeth_check_sum = 0; + + public static void vMeth(int i3, int i4, int i5) { + + int i6=-71, i7=88, i8=217, i9=14, i10=9677, i18=-244, i19=107, iArr[]=new int[N]; + } + + public static void init(int[] a, int seed) { + for (int j = 0; j < a.length; j++) { + a[j] = (j % 2 == 0) ? seed + j : seed - j; + } + } + + public static long checkSum(int[] a) { + long sum = 0; + for (int j = 0; j < a.length; j++) { + sum += (a[j] / (j + 1) + a[j] % (j + 1)); + } + return sum; + } + + public static int iMeth(boolean b, int i2) { + + byte by=81; + int i21=-24074, i22=7, i23=-7, i24=-70, iArr2[]=new int[N]; + boolean b2=false; + init(iArr2, -27); + + vMeth(189, i2, i2); + for (int i20 : iArr2) { + by *= (byte) TestIfReplacedByMainLoopExit.instanceCount; + for (i23 = 1; i23 < 4; ++i23) { + i24 -= i23; + TestIfReplacedByMainLoopExit.bFld = b2; + } + } + long meth_res = (b ? 1 : 0) + i2 + by + i21 + i22 + i23 + i24 + (b2 ? 1 : 0) + checkSum(iArr2); + iMeth_check_sum += meth_res; + return (int)meth_res; + } + + public void mainTest(String[] strArr1) { + int i, i1, i25, i26=9, i27, i28; + byte by1=35; + float f2; + + for (i = 17; 310 > i; ++i) { + i1 = ((iMeth(TestIfReplacedByMainLoopExit.bFld, iFld) - iFld) + by1); + } + i1 = 231; + iFld += -13496; + for (i25 = 2; i25 < 271; i25++) { + i26 -= i; + if (TestIfReplacedByMainLoopExit.bFld) break; + } + i26 = i; + iFld += (int)1.338F; + iFld += 30984; + i27 = 1; + do { + iFld *= i25; + for (i28 = 4; i28 < 75; ++i28) { + i1 += i25; + } + } while (++i27 < 335); + f2 = 210; + do { + iFld -= i25; + } while (--f2 > 0); + + System.out.println("iFld = " + iFld); + } + + public static void main(String[] strArr) { + TestIfReplacedByMainLoopExit _instance = new TestIfReplacedByMainLoopExit(); + _instance.mainTest(strArr); + int iFld_sav = _instance.iFld; + for (int i = 0; i < 10; i++ ) { + _instance.iFld=-11; + _instance.mainTest(strArr); + if (_instance.iFld != iFld_sav) { + throw new RuntimeException("incorrect execution " + _instance.iFld + " != " + iFld_sav); + } + } + } +} -- GitLab From 36b89a18931d42b8002a843ec8218b5c1ba54374 Mon Sep 17 00:00:00 2001 From: Christian Hagedorn Date: Fri, 8 Oct 2021 14:51:18 +0000 Subject: [PATCH 143/385] 8274785: ciReplay: Potential crash due to uninitialized Compile::_ilt variable Reviewed-by: neliasso, kvn --- src/hotspot/share/opto/compile.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index 801a28448d1..031f318f27e 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -549,6 +549,7 @@ Compile::Compile( ciEnv* ci_env, ciMethod* target, int osr_bci, _do_locks_coarsening(do_locks_coarsening), _method(target), _entry_bci(osr_bci), + _ilt(NULL), _stub_function(NULL), _stub_name(NULL), _stub_entry_point(NULL), -- GitLab From ccbce107f299c3b1c444e819c1fda7ae3c4866b5 Mon Sep 17 00:00:00 2001 From: Sergey Tsypanov Date: Fri, 8 Oct 2021 15:58:36 +0000 Subject: [PATCH 144/385] 8272756: Remove unnecessary explicit initialization of volatile variables in java.desktop Reviewed-by: jdv, aivanov --- .../classes/sun/lwawt/LWLightweightFramePeer.java | 4 ++-- .../macosx/classes/sun/lwawt/LWWindowPeer.java | 4 ++-- .../sun/lwawt/macosx/CCheckboxMenuItem.java | 4 ++-- .../sun/lwawt/macosx/CPlatformEmbeddedFrame.java | 4 ++-- .../classes/sun/lwawt/macosx/CWarningWindow.java | 2 +- .../com/sun/imageio/plugins/tiff/TIFFIFD.java | 4 ++-- .../com/sun/media/sound/DirectAudioDevice.java | 14 +++++++------- .../com/sun/media/sound/SoftAudioPusher.java | 6 +++--- .../com/sun/media/sound/SoftSynthesizer.java | 2 +- .../share/classes/java/awt/Component.java | 4 ++-- .../share/classes/java/awt/Container.java | 2 +- .../share/classes/java/awt/Dialog.java | 4 ++-- .../share/classes/java/awt/Window.java | 4 ++-- .../classes/java/awt/event/InvocationEvent.java | 2 +- .../share/classes/java/awt/font/NumericShaper.java | 2 +- .../share/classes/javax/swing/JComponent.java | 2 +- .../share/classes/sun/awt/AppContext.java | 2 +- .../classes/sun/awt/datatransfer/SunClipboard.java | 4 ++-- .../sun/awt/dnd/SunDragSourceContextPeer.java | 6 +++--- .../share/classes/sun/java2d/Disposer.java | 2 +- .../classes/sun/java2d/marlin/RendererStats.java | 2 +- .../classes/sun/awt/X11/GtkFileDialogPeer.java | 4 ++-- .../unix/classes/sun/awt/X11/ListHelper.java | 4 ++-- .../unix/classes/sun/awt/X11/XInputMethod.java | 4 ++-- .../classes/sun/awt/X11/XLightweightFramePeer.java | 4 ++-- .../unix/classes/sun/awt/X11/XWarningWindow.java | 4 ++-- .../classes/sun/awt/windows/ThemeReader.java | 4 ++-- .../classes/sun/awt/windows/WObjectPeer.java | 4 ++-- 28 files changed, 54 insertions(+), 54 deletions(-) diff --git a/src/java.desktop/macosx/classes/sun/lwawt/LWLightweightFramePeer.java b/src/java.desktop/macosx/classes/sun/lwawt/LWLightweightFramePeer.java index 1644c6b6e7b..41acd8ecab6 100644 --- a/src/java.desktop/macosx/classes/sun/lwawt/LWLightweightFramePeer.java +++ b/src/java.desktop/macosx/classes/sun/lwawt/LWLightweightFramePeer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -119,7 +119,7 @@ public class LWLightweightFramePeer extends LWWindowPeer implements OverrideNati } // SwingNode - private volatile long overriddenWindowHandle = 0L; + private volatile long overriddenWindowHandle; @Override public void overrideWindowHandle(final long handle) { diff --git a/src/java.desktop/macosx/classes/sun/lwawt/LWWindowPeer.java b/src/java.desktop/macosx/classes/sun/lwawt/LWWindowPeer.java index 6356f6d21c7..1796f5f3005 100644 --- a/src/java.desktop/macosx/classes/sun/lwawt/LWWindowPeer.java +++ b/src/java.desktop/macosx/classes/sun/lwawt/LWWindowPeer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -112,7 +112,7 @@ public class LWWindowPeer private volatile int windowState = Frame.NORMAL; // check that the mouse is over the window - private volatile boolean isMouseOver = false; + private volatile boolean isMouseOver; // A peer where the last mouse event came to. Used by cursor manager to // find the component under cursor diff --git a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CCheckboxMenuItem.java b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CCheckboxMenuItem.java index d21de341fb4..5cc8fad2a4a 100644 --- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CCheckboxMenuItem.java +++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CCheckboxMenuItem.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,7 +33,7 @@ import sun.awt.SunToolkit; public class CCheckboxMenuItem extends CMenuItem implements CheckboxMenuItemPeer { volatile boolean fAutoToggle = true; - volatile boolean fIsIndeterminate = false; + volatile boolean fIsIndeterminate; private native void nativeSetState(long modelPtr, boolean state); private native void nativeSetIsCheckbox(long modelPtr); diff --git a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformEmbeddedFrame.java b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformEmbeddedFrame.java index 72fe894db46..6a8076ee118 100644 --- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformEmbeddedFrame.java +++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformEmbeddedFrame.java @@ -50,8 +50,8 @@ public class CPlatformEmbeddedFrame implements PlatformWindow { private LWWindowPeer peer; private CEmbeddedFrame target; - private volatile int screenX = 0; - private volatile int screenY = 0; + private volatile int screenX; + private volatile int screenY; @Override // PlatformWindow public void initialize(Window target, final LWWindowPeer peer, PlatformWindow owner) { diff --git a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CWarningWindow.java b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CWarningWindow.java index 35d726f8f75..52e85e33841 100644 --- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CWarningWindow.java +++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CWarningWindow.java @@ -56,7 +56,7 @@ public final class CWarningWindow extends CPlatformWindow /** * Animation stage. */ - private volatile int currentIcon = 0; + private volatile int currentIcon; /* -1 - uninitialized. * 0 - 16x16 diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFIFD.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFIFD.java index 3d307e9ad1b..6f4475b670a 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFIFD.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFIFD.java @@ -56,12 +56,12 @@ public class TIFFIFD extends TIFFDirectory { // A set of tag numbers corresponding to tags essential to decoding // the image and metadata required to interpret its samples. // - private static volatile Set essentialTags = null; + private static volatile Set essentialTags; private static void initializeEssentialTags() { Set tags = essentialTags; if (tags == null) { - essentialTags = tags = Set.of( + essentialTags = Set.of( BaselineTIFFTagSet.TAG_BITS_PER_SAMPLE, BaselineTIFFTagSet.TAG_COLOR_MAP, BaselineTIFFTagSet.TAG_COMPRESSION, diff --git a/src/java.desktop/share/classes/com/sun/media/sound/DirectAudioDevice.java b/src/java.desktop/share/classes/com/sun/media/sound/DirectAudioDevice.java index e7aca8d3682..b261b6799ef 100644 --- a/src/java.desktop/share/classes/com/sun/media/sound/DirectAudioDevice.java +++ b/src/java.desktop/share/classes/com/sun/media/sound/DirectAudioDevice.java @@ -361,13 +361,13 @@ final class DirectAudioDevice extends AbstractMixer { protected final int deviceID; protected long id; protected int waitTime; - protected volatile boolean flushing = false; + protected volatile boolean flushing; protected final boolean isSource; // true for SourceDataLine, false for TargetDataLine protected volatile long bytePosition; - protected volatile boolean doIO = false; // true in between start() and stop() calls - protected volatile boolean stoppedWritten = false; // true if a write occurred in stopped state - protected volatile boolean drained = false; // set to true when drain function returns, set to false in write() - protected boolean monitoring = false; + protected volatile boolean doIO; // true in between start() and stop() calls + protected volatile boolean stoppedWritten; // true if a write occurred in stopped state + protected volatile boolean drained; // set to true when drain function returns, set to false in write() + protected boolean monitoring; // if native needs to manually swap samples/convert sign, this // is set to the framesize @@ -379,7 +379,7 @@ final class DirectAudioDevice extends AbstractMixer { private final Balance balanceControl = new Balance(); private final Pan panControl = new Pan(); private float leftGain, rightGain; - protected volatile boolean noService = false; // do not run the nService method + protected volatile boolean noService; // do not run the nService method // Guards all native calls. protected final Object lockNative = new Object(); @@ -975,7 +975,7 @@ final class DirectAudioDevice extends AbstractMixer { implements Clip, Runnable, AutoClosingClip { private volatile Thread thread; - private volatile byte[] audioData = null; + private volatile byte[] audioData; private volatile int frameSize; // size of one frame in bytes private volatile int m_lengthInFrames; private volatile int loopCount; diff --git a/src/java.desktop/share/classes/com/sun/media/sound/SoftAudioPusher.java b/src/java.desktop/share/classes/com/sun/media/sound/SoftAudioPusher.java index 4f9c9f21c5c..94f2a04466e 100644 --- a/src/java.desktop/share/classes/com/sun/media/sound/SoftAudioPusher.java +++ b/src/java.desktop/share/classes/com/sun/media/sound/SoftAudioPusher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2021, Oracle and/or its affiliates. All rights reserved. * 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,8 +37,8 @@ import javax.sound.sampled.SourceDataLine; */ public final class SoftAudioPusher implements Runnable { - private volatile boolean active = false; - private SourceDataLine sourceDataLine = null; + private volatile boolean active; + private SourceDataLine sourceDataLine; private Thread audiothread; private final AudioInputStream ais; private final byte[] buffer; diff --git a/src/java.desktop/share/classes/com/sun/media/sound/SoftSynthesizer.java b/src/java.desktop/share/classes/com/sun/media/sound/SoftSynthesizer.java index 1c8ff218077..9d73c68e6ad 100644 --- a/src/java.desktop/share/classes/com/sun/media/sound/SoftSynthesizer.java +++ b/src/java.desktop/share/classes/com/sun/media/sound/SoftSynthesizer.java @@ -76,7 +76,7 @@ public final class SoftSynthesizer implements AudioSynthesizer, public SoftAudioPusher pusher = null; public AudioInputStream jitter_stream = null; public SourceDataLine sourceDataLine = null; - public volatile long silent_samples = 0; + public volatile long silent_samples; private int framesize = 0; private final WeakReference weak_stream_link; private final AudioFloatConverter converter; diff --git a/src/java.desktop/share/classes/java/awt/Component.java b/src/java.desktop/share/classes/java/awt/Component.java index e5209c49ce2..d7c2340c564 100644 --- a/src/java.desktop/share/classes/java/awt/Component.java +++ b/src/java.desktop/share/classes/java/awt/Component.java @@ -395,7 +395,7 @@ public abstract class Component implements ImageObserver, MenuContainer, * @see #validate * @see #invalidate */ - private volatile boolean valid = false; + private volatile boolean valid; /** * The {@code DropTarget} associated with this component. @@ -9340,7 +9340,7 @@ public abstract class Component implements ImageObserver, MenuContainer, * to add/remove ComponentListener and FocusListener to track * target Component's state. */ - private transient volatile int propertyListenersCount = 0; + private transient volatile int propertyListenersCount; /** * A component listener to track show/hide/resize events diff --git a/src/java.desktop/share/classes/java/awt/Container.java b/src/java.desktop/share/classes/java/awt/Container.java index 1327b2fded9..68270d35ada 100644 --- a/src/java.desktop/share/classes/java/awt/Container.java +++ b/src/java.desktop/share/classes/java/awt/Container.java @@ -3861,7 +3861,7 @@ public class Container extends Component { * Number of PropertyChangeListener objects registered. It's used * to add/remove ContainerListener to track target Container's state. */ - private transient volatile int propertyListenersCount = 0; + private transient volatile int propertyListenersCount; /** * The handler to fire {@code PropertyChange} diff --git a/src/java.desktop/share/classes/java/awt/Dialog.java b/src/java.desktop/share/classes/java/awt/Dialog.java index 4132d7b050f..1a54d707306 100644 --- a/src/java.desktop/share/classes/java/awt/Dialog.java +++ b/src/java.desktop/share/classes/java/awt/Dialog.java @@ -301,7 +301,7 @@ public class Dialog extends Window { * @see #hideAndDisposeHandler() * @see #shouldBlock() */ - transient volatile boolean isInHide = false; + transient volatile boolean isInHide; /* * Indicates that this dialog is being disposed. This flag is set to true at @@ -312,7 +312,7 @@ public class Dialog extends Window { * @see #hideAndDisposeHandler() * @see #doDispose() */ - transient volatile boolean isInDispose = false; + transient volatile boolean isInDispose; private static final String base = "dialog"; private static int nameCounter = 0; diff --git a/src/java.desktop/share/classes/java/awt/Window.java b/src/java.desktop/share/classes/java/awt/Window.java index a14591d6670..3f5d3212720 100644 --- a/src/java.desktop/share/classes/java/awt/Window.java +++ b/src/java.desktop/share/classes/java/awt/Window.java @@ -404,8 +404,8 @@ public class Window extends Container implements Accessible { * These fields are initialized in the native peer code * or via AWTAccessor's WindowAccessor. */ - private transient volatile int securityWarningWidth = 0; - private transient volatile int securityWarningHeight = 0; + private transient volatile int securityWarningWidth; + private transient volatile int securityWarningHeight; static { /* ensure that the necessary native libraries are loaded */ diff --git a/src/java.desktop/share/classes/java/awt/event/InvocationEvent.java b/src/java.desktop/share/classes/java/awt/event/InvocationEvent.java index b2b8eb5b289..c73b77282d5 100644 --- a/src/java.desktop/share/classes/java/awt/event/InvocationEvent.java +++ b/src/java.desktop/share/classes/java/awt/event/InvocationEvent.java @@ -116,7 +116,7 @@ public class InvocationEvent extends AWTEvent implements ActiveEvent { * @see #isDispatched * @since 1.7 */ - private volatile boolean dispatched = false; + private volatile boolean dispatched; /** * Set to true if dispatch() catches Throwable and stores it in the diff --git a/src/java.desktop/share/classes/java/awt/font/NumericShaper.java b/src/java.desktop/share/classes/java/awt/font/NumericShaper.java index 5b2ebfe7784..da21e8fce23 100644 --- a/src/java.desktop/share/classes/java/awt/font/NumericShaper.java +++ b/src/java.desktop/share/classes/java/awt/font/NumericShaper.java @@ -1364,7 +1364,7 @@ public final class NumericShaper implements java.io.Serializable { // use a binary search with a cache - private transient volatile int stCache = 0; + private transient volatile int stCache; private boolean isStrongDirectional(char c) { int cachedIndex = stCache; diff --git a/src/java.desktop/share/classes/javax/swing/JComponent.java b/src/java.desktop/share/classes/javax/swing/JComponent.java index 5aa1a6a79bc..d028c00b98b 100644 --- a/src/java.desktop/share/classes/javax/swing/JComponent.java +++ b/src/java.desktop/share/classes/javax/swing/JComponent.java @@ -3752,7 +3752,7 @@ public abstract class JComponent extends Container implements Serializable, * to add/remove ContainerListener and FocusListener to track * target JComponent's state */ - private transient volatile int propertyListenersCount = 0; + private transient volatile int propertyListenersCount; /** * This field duplicates the function of the accessibleAWTFocusHandler field diff --git a/src/java.desktop/share/classes/sun/awt/AppContext.java b/src/java.desktop/share/classes/sun/awt/AppContext.java index da7dd5052ec..6ed0b2b325e 100644 --- a/src/java.desktop/share/classes/sun/awt/AppContext.java +++ b/src/java.desktop/share/classes/sun/awt/AppContext.java @@ -161,7 +161,7 @@ public final class AppContext { contained in another AppContext. It is implicitly created for standalone apps only (i.e. not applets) */ - private static volatile AppContext mainAppContext = null; + private static volatile AppContext mainAppContext; private static class GetAppContextLock {}; private static final Object getAppContextLock = new GetAppContextLock(); diff --git a/src/java.desktop/share/classes/sun/awt/datatransfer/SunClipboard.java b/src/java.desktop/share/classes/sun/awt/datatransfer/SunClipboard.java index fe1baa3e631..898cabd2855 100644 --- a/src/java.desktop/share/classes/sun/awt/datatransfer/SunClipboard.java +++ b/src/java.desktop/share/classes/sun/awt/datatransfer/SunClipboard.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -71,7 +71,7 @@ public abstract class SunClipboard extends Clipboard * A number of {@code FlavorListener}s currently registered * on this clipboard across all {@code AppContext}s. */ - private volatile int numberOfFlavorListeners = 0; + private volatile int numberOfFlavorListeners; /** * A set of {@code DataFlavor}s that is available on this clipboard. It is diff --git a/src/java.desktop/share/classes/sun/awt/dnd/SunDragSourceContextPeer.java b/src/java.desktop/share/classes/sun/awt/dnd/SunDragSourceContextPeer.java index 4dc0fd434d8..258cebd6616 100644 --- a/src/java.desktop/share/classes/sun/awt/dnd/SunDragSourceContextPeer.java +++ b/src/java.desktop/share/classes/sun/awt/dnd/SunDragSourceContextPeer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. * 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,8 +74,8 @@ public abstract class SunDragSourceContextPeer implements DragSourceContextPeer private DragSourceContext dragSourceContext; private int sourceActions; - private static volatile boolean dragDropInProgress = false; - private static volatile boolean discardingMouseEvents = false; + private static volatile boolean dragDropInProgress; + private static volatile boolean discardingMouseEvents; /* * dispatch constants diff --git a/src/java.desktop/share/classes/sun/java2d/Disposer.java b/src/java.desktop/share/classes/sun/java2d/Disposer.java index 6f359f7f87a..e57483e66ae 100644 --- a/src/java.desktop/share/classes/sun/java2d/Disposer.java +++ b/src/java.desktop/share/classes/sun/java2d/Disposer.java @@ -184,7 +184,7 @@ public class Disposer implements Runnable { /* * Set to indicate the queue is presently being polled. */ - public static volatile boolean pollingQueue = false; + public static volatile boolean pollingQueue; /* * The pollRemove() method is called back from a dispose method diff --git a/src/java.desktop/share/classes/sun/java2d/marlin/RendererStats.java b/src/java.desktop/share/classes/sun/java2d/marlin/RendererStats.java index 5185b245d73..fe2a337950e 100644 --- a/src/java.desktop/share/classes/sun/java2d/marlin/RendererStats.java +++ b/src/java.desktop/share/classes/sun/java2d/marlin/RendererStats.java @@ -334,7 +334,7 @@ public final class RendererStats implements MarlinConst { static final class RendererStatsHolder { // singleton - private static volatile RendererStatsHolder SINGLETON = null; + private static volatile RendererStatsHolder SINGLETON; static synchronized RendererStatsHolder getInstance() { if (SINGLETON == null) { diff --git a/src/java.desktop/unix/classes/sun/awt/X11/GtkFileDialogPeer.java b/src/java.desktop/unix/classes/sun/awt/X11/GtkFileDialogPeer.java index fb7688f9b8e..71263ec49f3 100644 --- a/src/java.desktop/unix/classes/sun/awt/X11/GtkFileDialogPeer.java +++ b/src/java.desktop/unix/classes/sun/awt/X11/GtkFileDialogPeer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,7 +40,7 @@ final class GtkFileDialogPeer extends XDialogPeer implements FileDialogPeer { private final FileDialog fd; // A pointer to the native GTK FileChooser widget - private volatile long widget = 0L; + private volatile long widget; private long standaloneWindow; private volatile boolean quit; diff --git a/src/java.desktop/unix/classes/sun/awt/X11/ListHelper.java b/src/java.desktop/unix/classes/sun/awt/X11/ListHelper.java index efa1460baa3..32d3ae46771 100644 --- a/src/java.desktop/unix/classes/sun/awt/X11/ListHelper.java +++ b/src/java.desktop/unix/classes/sun/awt/X11/ListHelper.java @@ -79,8 +79,8 @@ final class ListHelper implements XScrollbarClient { // Holds the true if mouse is dragging outside of the area of the list // The flag is used at the moment of the dragging and releasing mouse // See 6243382 for more information - private boolean mouseDraggedOutVertically = false; - private volatile boolean vsbVisibilityChanged = false; + private boolean mouseDraggedOutVertically; + private volatile boolean vsbVisibilityChanged; /* * Comment diff --git a/src/java.desktop/unix/classes/sun/awt/X11/XInputMethod.java b/src/java.desktop/unix/classes/sun/awt/X11/XInputMethod.java index cbc6ad46102..54912312c55 100644 --- a/src/java.desktop/unix/classes/sun/awt/X11/XInputMethod.java +++ b/src/java.desktop/unix/classes/sun/awt/X11/XInputMethod.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. * 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,7 +73,7 @@ public class XInputMethod extends X11InputMethod { } - private static volatile long xicFocus = 0; + private static volatile long xicFocus; protected void setXICFocus(ComponentPeer peer, boolean value, boolean active) { diff --git a/src/java.desktop/unix/classes/sun/awt/X11/XLightweightFramePeer.java b/src/java.desktop/unix/classes/sun/awt/X11/XLightweightFramePeer.java index 02c7706850f..c2089ea8018 100644 --- a/src/java.desktop/unix/classes/sun/awt/X11/XLightweightFramePeer.java +++ b/src/java.desktop/unix/classes/sun/awt/X11/XLightweightFramePeer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -82,7 +82,7 @@ public class XLightweightFramePeer extends XFramePeer implements OverrideNativeW getLwTarget().removeDropTarget(dt); } - private volatile long overriddenWindowHandle = 0L; + private volatile long overriddenWindowHandle; @Override public void overrideWindowHandle(final long handle) { diff --git a/src/java.desktop/unix/classes/sun/awt/X11/XWarningWindow.java b/src/java.desktop/unix/classes/sun/awt/X11/XWarningWindow.java index 81f7e84839a..ba7359dc5c4 100644 --- a/src/java.desktop/unix/classes/sun/awt/X11/XWarningWindow.java +++ b/src/java.desktop/unix/classes/sun/awt/X11/XWarningWindow.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. * 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 XWarningWindow extends XWindow { /** * Animation stage. */ - private volatile int currentIcon = 0; + private volatile int currentIcon; /* -1 - uninitialized. * 0 - 16x16 diff --git a/src/java.desktop/windows/classes/sun/awt/windows/ThemeReader.java b/src/java.desktop/windows/classes/sun/awt/windows/ThemeReader.java index 482a92fd885..63e9c8de698 100644 --- a/src/java.desktop/windows/classes/sun/awt/windows/ThemeReader.java +++ b/src/java.desktop/windows/classes/sun/awt/windows/ThemeReader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -53,7 +53,7 @@ public final class ThemeReader { new ReentrantReadWriteLock(); private static final Lock readLock = readWriteLock.readLock(); private static final Lock writeLock = readWriteLock.writeLock(); - private static volatile boolean valid = false; + private static volatile boolean valid; private static volatile boolean isThemed; static volatile boolean xpStyleEnabled; diff --git a/src/java.desktop/windows/classes/sun/awt/windows/WObjectPeer.java b/src/java.desktop/windows/classes/sun/awt/windows/WObjectPeer.java index a79864a0aea..c32e3e4e928 100644 --- a/src/java.desktop/windows/classes/sun/awt/windows/WObjectPeer.java +++ b/src/java.desktop/windows/classes/sun/awt/windows/WObjectPeer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,7 +43,7 @@ abstract class WObjectPeer { private volatile boolean disposed; // set from JNI if any errors in creating the peer occur - volatile Error createError = null; + volatile Error createError; // used to synchronize the state of this peer private final Object stateLock = new Object(); -- GitLab From ec199072c5867624d66840238cc8828e16ae8da7 Mon Sep 17 00:00:00 2001 From: Naoto Sato Date: Fri, 8 Oct 2021 16:11:22 +0000 Subject: [PATCH 145/385] 8274864: Remove Amman/Cairo hacks in ZoneInfoFile Reviewed-by: iris, joehw --- .../sun/util/calendar/ZoneInfoFile.java | 29 ------------------- 1 file changed, 29 deletions(-) diff --git a/src/java.base/share/classes/sun/util/calendar/ZoneInfoFile.java b/src/java.base/share/classes/sun/util/calendar/ZoneInfoFile.java index a25335e7d5e..9f78c46fd5b 100644 --- a/src/java.base/share/classes/sun/util/calendar/ZoneInfoFile.java +++ b/src/java.base/share/classes/sun/util/calendar/ZoneInfoFile.java @@ -618,34 +618,6 @@ public final class ZoneInfoFile { params[8] = endRule.secondOfDay * 1000; params[9] = toSTZTime[endRule.timeDefinition]; dstSavings = (startRule.offsetAfter - startRule.offsetBefore) * 1000; - - // Note: known mismatching -> Asia/Amman - // ZoneInfo : startDayOfWeek=5 <= Thursday - // startTime=86400000 <= 24 hours - // This: startDayOfWeek=6 - // startTime=0 - // Similar workaround needs to be applied to Africa/Cairo and - // its endDayOfWeek and endTime - // Below is the workarounds, it probably slows down everyone a little - if (params[2] == 6 && params[3] == 0 && - (zoneId.equals("Asia/Amman"))) { - params[2] = 5; - params[3] = 86400000; - } - // Additional check for startDayOfWeek=6 and starTime=86400000 - // is needed for Asia/Amman; - if (params[2] == 7 && params[3] == 0 && - (zoneId.equals("Asia/Amman"))) { - params[2] = 6; // Friday - params[3] = 86400000; // 24h - } - //endDayOfWeek and endTime workaround - if (params[7] == 6 && params[8] == 0 && - (zoneId.equals("Africa/Cairo"))) { - params[7] = 5; - params[8] = 86400000; - } - } else if (nTrans > 0) { // only do this if there is something in table already if (lastyear < LASTYEAR) { // ZoneInfo has an ending entry for 2037 @@ -918,7 +890,6 @@ public final class ZoneInfoFile { this.dow = dowByte == 0 ? -1 : dowByte; this.secondOfDay = timeByte == 31 ? in.readInt() : timeByte * 3600; this.timeDefinition = (data & (3 << 12)) >>> 12; - this.standardOffset = stdByte == 255 ? in.readInt() : (stdByte - 128) * 900; this.offsetBefore = beforeByte == 3 ? in.readInt() : standardOffset + beforeByte * 1800; this.offsetAfter = afterByte == 3 ? in.readInt() : standardOffset + afterByte * 1800; -- GitLab From 239a35aa9166d0cb0b20850e1b52ad23b653d8d0 Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Fri, 8 Oct 2021 16:43:16 +0000 Subject: [PATCH 146/385] 8233749: Files.exists javadoc doesn't mention eating IOException Reviewed-by: lancea, alanb --- src/java.base/share/classes/java/nio/file/Files.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/java.base/share/classes/java/nio/file/Files.java b/src/java.base/share/classes/java/nio/file/Files.java index 01f01e2679a..98efa051d11 100644 --- a/src/java.base/share/classes/java/nio/file/Files.java +++ b/src/java.base/share/classes/java/nio/file/Files.java @@ -2514,6 +2514,7 @@ public final class Files { * read access to the file. * * @see #notExists + * @see FileSystemProvider#checkAccess */ public static boolean exists(Path path, LinkOption... options) { if (options.length == 0) { -- GitLab From 3cb9724ed94a7267853c5cddb18b4ae868ecf2e9 Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Fri, 8 Oct 2021 21:10:42 +0000 Subject: [PATCH 147/385] 8274934: Attempting to acquire lock JNICritical_lock/41 out of order with lock MultiArray_lock/41 Reviewed-by: dcubed, iklam --- 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 abea2761572..acd2a067047 100644 --- a/src/hotspot/share/runtime/mutexLocker.cpp +++ b/src/hotspot/share/runtime/mutexLocker.cpp @@ -275,7 +275,6 @@ void mutex_init() { def(Terminator_lock , PaddedMonitor, safepoint, true); def(InitCompleted_lock , PaddedMonitor, nosafepoint, true); def(Notify_lock , PaddedMonitor, safepoint, true); - def(JNICritical_lock , PaddedMonitor, safepoint, true); // used for JNI critical regions def(AdapterHandlerLibrary_lock , PaddedMutex , safepoint, true); def(Heap_lock , PaddedMonitor, safepoint, false); // Doesn't safepoint check during termination. @@ -365,6 +364,7 @@ void mutex_init() { defl(OopMapCacheAlloc_lock , PaddedMutex , Threads_lock, true); defl(Module_lock , PaddedMutex , ClassLoaderDataGraph_lock, false); defl(SystemDictionary_lock , PaddedMonitor, Module_lock, true); + defl(JNICritical_lock , PaddedMonitor, MultiArray_lock, true); // used for JNI critical regions #if INCLUDE_JFR defl(JfrMsg_lock , PaddedMonitor, Module_lock, true); -- GitLab From 9c431dd168c8a752d4aa1bde2268db0425d76990 Mon Sep 17 00:00:00 2001 From: Andrey Turbanov Date: Fri, 8 Oct 2021 23:08:05 +0000 Subject: [PATCH 148/385] 8274900: Too weak variable type leads to unnecessary cast in jdk.javadoc Reviewed-by: prappo --- .../formats/html/SourceToHTMLConverter.java | 4 ++-- .../builders/SerializedFormBuilder.java | 3 +-- .../toolkit/util/SummaryAPIListBuilder.java | 21 +++++++++---------- 3 files changed, 13 insertions(+), 15 deletions(-) diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SourceToHTMLConverter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SourceToHTMLConverter.java index f032f89bb4a..7bc1f96b648 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SourceToHTMLConverter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SourceToHTMLConverter.java @@ -151,13 +151,13 @@ public class SourceToHTMLConverter { if (pkg == null) { return; } - for (Element te : utils.getAllClasses(pkg)) { + for (TypeElement te : utils.getAllClasses(pkg)) { // If -nodeprecated option is set and the class is marked as deprecated, // do not convert the package files to HTML. We do not check for // containing package deprecation since it is already check in // the calling method above. if (!(options.noDeprecated() && utils.isDeprecated(te))) - convertClass((TypeElement)te, outputdir); + convertClass(te, outputdir); } } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/SerializedFormBuilder.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/SerializedFormBuilder.java index 0e2134c0b73..e3de27c19f1 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/SerializedFormBuilder.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/SerializedFormBuilder.java @@ -233,8 +233,7 @@ public class SerializedFormBuilder extends AbstractBuilder { */ protected void buildSerialUIDInfo(Content classTree) { Content serialUidTree = writer.getSerialUIDInfoHeader(); - for (Element e : utils.getFieldsUnfiltered(currentTypeElement)) { - VariableElement field = (VariableElement)e; + for (VariableElement field : utils.getFieldsUnfiltered(currentTypeElement)) { if (field.getSimpleName().toString().compareTo(SERIAL_VERSION_UID) == 0 && field.getConstantValue() != null) { writer.addSerialUIDInfo(SERIAL_VERSION_UID_HEADER, diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/SummaryAPIListBuilder.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/SummaryAPIListBuilder.java index 05a35dee4d8..ae37bf93e70 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/SummaryAPIListBuilder.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/SummaryAPIListBuilder.java @@ -112,14 +112,13 @@ public class SummaryAPIListBuilder { handleElement(pe); } } - for (Element e : configuration.getIncludedTypeElements()) { - TypeElement te = (TypeElement)e; + for (TypeElement te : configuration.getIncludedTypeElements()) { SortedSet eset; - if (belongsToSummary.test(e)) { - switch (e.getKind()) { + if (belongsToSummary.test(te)) { + switch (te.getKind()) { case ANNOTATION_TYPE -> { eset = summaryMap.get(SummaryElementKind.ANNOTATION_TYPE); - eset.add(e); + eset.add(te); } case CLASS -> { if (utils.isError(te)) { @@ -129,19 +128,19 @@ public class SummaryAPIListBuilder { } else { eset = summaryMap.get(SummaryElementKind.CLASS); } - eset.add(e); + eset.add(te); } case INTERFACE -> { eset = summaryMap.get(SummaryElementKind.INTERFACE); - eset.add(e); + eset.add(te); } case ENUM -> { eset = summaryMap.get(SummaryElementKind.ENUM); - eset.add(e); + eset.add(te); } case RECORD -> { eset = summaryMap.get(SummaryElementKind.RECORD_CLASS); - eset.add(e); + eset.add(te); } } handleElement(te); @@ -152,7 +151,7 @@ public class SummaryAPIListBuilder { utils.getMethods(te)); composeSummaryList(summaryMap.get(SummaryElementKind.CONSTRUCTOR), utils.getConstructors(te)); - if (utils.isEnum(e)) { + if (utils.isEnum(te)) { composeSummaryList(summaryMap.get(SummaryElementKind.ENUM_CONSTANT), utils.getEnumConstants(te)); } @@ -165,7 +164,7 @@ public class SummaryAPIListBuilder { } } } - if (utils.isAnnotationType(e)) { + if (utils.isAnnotationType(te)) { composeSummaryList(summaryMap.get(SummaryElementKind.ANNOTATION_TYPE_MEMBER), utils.getAnnotationMembers(te)); -- GitLab From f640c7aaa852b6c0e9144654b7222a6777201370 Mon Sep 17 00:00:00 2001 From: Andrey Turbanov Date: Sat, 9 Oct 2021 00:46:20 +0000 Subject: [PATCH 149/385] 8274806: Simplify equals() call on nullable variable and a constant in java.desktop Reviewed-by: serb, pbansal --- .../macosx/classes/sun/lwawt/macosx/CMenuItem.java | 4 ++-- src/java.desktop/share/classes/java/awt/Window.java | 4 ++-- .../share/classes/javax/swing/DefaultDesktopManager.java | 6 +++--- .../share/classes/javax/swing/JLayeredPane.java | 4 ++-- .../classes/javax/swing/filechooser/FileSystemView.java | 2 +- .../share/classes/javax/swing/text/html/HTMLEditorKit.java | 2 +- .../share/classes/sun/java2d/SurfaceDataProxy.java | 3 +-- .../share/classes/sun/print/RasterPrinterJob.java | 2 +- src/java.desktop/unix/classes/sun/awt/X11/XTaskbarPeer.java | 2 +- src/java.desktop/unix/classes/sun/print/UnixPrintJob.java | 2 +- .../windows/classes/sun/awt/windows/WDesktopProperties.java | 2 +- 11 files changed, 16 insertions(+), 17 deletions(-) diff --git a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CMenuItem.java b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CMenuItem.java index c29268e0e9f..c4b2640efb8 100644 --- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CMenuItem.java +++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CMenuItem.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -55,7 +55,7 @@ public class CMenuItem extends CMenuComponent implements MenuItemPeer { private boolean isSeparator() { String label = ((MenuItem)getTarget()).getLabel(); - return (label != null && label.equals("-")); + return "-".equals(label); } @Override diff --git a/src/java.desktop/share/classes/java/awt/Window.java b/src/java.desktop/share/classes/java/awt/Window.java index 3f5d3212720..59e63abbb3c 100644 --- a/src/java.desktop/share/classes/java/awt/Window.java +++ b/src/java.desktop/share/classes/java/awt/Window.java @@ -417,11 +417,11 @@ public class Window extends Container implements Accessible { @SuppressWarnings("removal") String s = java.security.AccessController.doPrivileged( new GetPropertyAction("java.awt.syncLWRequests")); - systemSyncLWRequests = (s != null && s.equals("true")); + systemSyncLWRequests = "true".equals(s); @SuppressWarnings("removal") String s2 = java.security.AccessController.doPrivileged( new GetPropertyAction("java.awt.Window.locationByPlatform")); - locationByPlatformProp = (s2 != null && s2.equals("true")); + locationByPlatformProp = "true".equals(s2); } /** diff --git a/src/java.desktop/share/classes/javax/swing/DefaultDesktopManager.java b/src/java.desktop/share/classes/javax/swing/DefaultDesktopManager.java index a0ac9e9996a..0e6460abf20 100644 --- a/src/java.desktop/share/classes/javax/swing/DefaultDesktopManager.java +++ b/src/java.desktop/share/classes/javax/swing/DefaultDesktopManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -328,9 +328,9 @@ public class DefaultDesktopManager implements DesktopManager, java.io.Serializab Window window = SwingUtilities.getWindowAncestor(f); if (window != null && !window.isOpaque()) { dragMode = DEFAULT_DRAG_MODE; - } else if (mode != null && mode.equals("outline")) { + } else if ("outline".equals(mode)) { dragMode = OUTLINE_DRAG_MODE; - } else if (mode != null && mode.equals("faster") + } else if ("faster".equals(mode) && f instanceof JInternalFrame && ((JInternalFrame)f).isOpaque() && (parent == null || parent.isOpaque())) { diff --git a/src/java.desktop/share/classes/javax/swing/JLayeredPane.java b/src/java.desktop/share/classes/javax/swing/JLayeredPane.java index 4e4f0215f3e..3ff321dfcf2 100644 --- a/src/java.desktop/share/classes/javax/swing/JLayeredPane.java +++ b/src/java.desktop/share/classes/javax/swing/JLayeredPane.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -205,7 +205,7 @@ public class JLayeredPane extends JComponent implements Accessible { (layer = (Integer)((JComponent)c). getClientProperty(LAYER_PROPERTY)) != null)) { - if(layer != null && layer.equals(FRAME_CONTENT_LAYER)) + if (FRAME_CONTENT_LAYER.equals(layer)) continue; layeredComponentFound = true; break; diff --git a/src/java.desktop/share/classes/javax/swing/filechooser/FileSystemView.java b/src/java.desktop/share/classes/javax/swing/filechooser/FileSystemView.java index b1cbc21d60f..17a3b196b07 100644 --- a/src/java.desktop/share/classes/javax/swing/filechooser/FileSystemView.java +++ b/src/java.desktop/share/classes/javax/swing/filechooser/FileSystemView.java @@ -824,7 +824,7 @@ class UnixFileSystemView extends FileSystemView { public boolean isComputerNode(File dir) { if (dir != null) { String parent = dir.getParent(); - if (parent != null && parent.equals("/net")) { + if ("/net".equals(parent)) { return true; } } diff --git a/src/java.desktop/share/classes/javax/swing/text/html/HTMLEditorKit.java b/src/java.desktop/share/classes/javax/swing/text/html/HTMLEditorKit.java index 46a311c05a2..b6b0b789eef 100644 --- a/src/java.desktop/share/classes/javax/swing/text/html/HTMLEditorKit.java +++ b/src/java.desktop/share/classes/javax/swing/text/html/HTMLEditorKit.java @@ -1326,7 +1326,7 @@ public class HTMLEditorKit extends StyledEditorKit implements Accessible { } else if (kind == HTML.Tag.IMPLIED) { String ws = (String) elem.getAttributes().getAttribute( CSS.Attribute.WHITE_SPACE); - if ((ws != null) && ws.equals("pre")) { + if ("pre".equals(ws)) { return new LineView(elem); } return new javax.swing.text.html.ParagraphView(elem); diff --git a/src/java.desktop/share/classes/sun/java2d/SurfaceDataProxy.java b/src/java.desktop/share/classes/sun/java2d/SurfaceDataProxy.java index c0a599c5392..6a84c7fc22b 100644 --- a/src/java.desktop/share/classes/sun/java2d/SurfaceDataProxy.java +++ b/src/java.desktop/share/classes/sun/java2d/SurfaceDataProxy.java @@ -37,7 +37,6 @@ import sun.java2d.loops.SurfaceType; import sun.java2d.loops.Blit; import sun.java2d.loops.BlitBg; import sun.awt.image.SurfaceManager; -import sun.awt.image.SurfaceManager.FlushableCacheData; import java.security.AccessController; import sun.security.action.GetPropertyAction; @@ -74,7 +73,7 @@ public abstract class SurfaceDataProxy @SuppressWarnings("removal") String manimg = AccessController.doPrivileged( new GetPropertyAction("sun.java2d.managedimages")); - if (manimg != null && manimg.equals("false")) { + if ("false".equals(manimg)) { cachingAllowed = false; System.out.println("Disabling managed images"); } diff --git a/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java b/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java index 28f493c423e..075bdefb145 100644 --- a/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java +++ b/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java @@ -1547,7 +1547,7 @@ public abstract class RasterPrinterJob extends PrinterJob { * PrintRequestAttributeSet while calling print(attributes) */ JobSheets js = (JobSheets)psvc.getDefaultAttributeValue(JobSheets.class); - if (js != null && js.equals(JobSheets.NONE)) { + if (JobSheets.NONE.equals(js)) { noJobSheet = true; } diff --git a/src/java.desktop/unix/classes/sun/awt/X11/XTaskbarPeer.java b/src/java.desktop/unix/classes/sun/awt/X11/XTaskbarPeer.java index 0afdd500163..33bebe77de7 100644 --- a/src/java.desktop/unix/classes/sun/awt/X11/XTaskbarPeer.java +++ b/src/java.desktop/unix/classes/sun/awt/X11/XTaskbarPeer.java @@ -48,7 +48,7 @@ final class XTaskbarPeer implements TaskbarPeer { String de = AccessController.doPrivileged( (PrivilegedAction) () -> System.getenv("XDG_CURRENT_DESKTOP")); - isUnity = de != null && de.equals("Unity"); + isUnity = "Unity".equals(de); } private static void initWithLock() { diff --git a/src/java.desktop/unix/classes/sun/print/UnixPrintJob.java b/src/java.desktop/unix/classes/sun/print/UnixPrintJob.java index 89e76d20c57..2184e8a3fcf 100644 --- a/src/java.desktop/unix/classes/sun/print/UnixPrintJob.java +++ b/src/java.desktop/unix/classes/sun/print/UnixPrintJob.java @@ -128,7 +128,7 @@ public class UnixPrintJob implements CancelablePrintJob { mDestType = UnixPrintJob.DESTPRINTER; JobSheets js = (JobSheets)(service. getDefaultAttributeValue(JobSheets.class)); - if (js != null && js.equals(JobSheets.NONE)) { + if (JobSheets.NONE.equals(js)) { mNoJobSheet = true; } } diff --git a/src/java.desktop/windows/classes/sun/awt/windows/WDesktopProperties.java b/src/java.desktop/windows/classes/sun/awt/windows/WDesktopProperties.java index 131a1c701e1..d9b169160b4 100644 --- a/src/java.desktop/windows/classes/sun/awt/windows/WDesktopProperties.java +++ b/src/java.desktop/windows/classes/sun/awt/windows/WDesktopProperties.java @@ -268,7 +268,7 @@ final class WDesktopProperties { Boolean smoothingOn = (Boolean)map.get("win.text.fontSmoothingOn"); - if (smoothingOn != null && smoothingOn.equals(Boolean.TRUE)) { + if (Boolean.TRUE.equals(smoothingOn)) { Integer typeID = (Integer)map.get("win.text.fontSmoothingType"); /* "1" is GASP/Standard but we'll also use that if the return * value is anything other than "2" for LCD. -- GitLab From aac6c4ea707fa592b2bcd7586c1fe61a19e3725e Mon Sep 17 00:00:00 2001 From: Pankaj Bansal Date: Sat, 9 Oct 2021 03:52:53 +0000 Subject: [PATCH 150/385] 8272229: BasicSplitPaneDivider:oneTouchExpandableChanged() returns leftButton and rightButton as null with GTKLookAndFeel Reviewed-by: serb, jdv, kizune --- .../javax/swing/plaf/basic/BasicSplitPaneDivider.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicSplitPaneDivider.java b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicSplitPaneDivider.java index f03671bcc56..d6ffc2f3789 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicSplitPaneDivider.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicSplitPaneDivider.java @@ -376,9 +376,10 @@ public class BasicSplitPaneDivider extends Container /** * Messaged when the oneTouchExpandable value of the JSplitPane the - * receiver is contained in changes. Will create the - * leftButton and rightButton if they - * are null. invalidates the receiver as well. + * divider is contained in changes. Will create the + * leftButton and rightButton if they are null + * and corresponding JSplitPane supports oneTouchExpandable property. + * Invalidates the corresponding JSplitPane as well. */ protected void oneTouchExpandableChanged() { if (!DefaultLookup.getBoolean(splitPane, splitPaneUI, -- GitLab From 6d1d4d52928ed38bbc73ddcbede5389995a8e65f Mon Sep 17 00:00:00 2001 From: Wang Huang Date: Sat, 9 Oct 2021 08:19:17 +0000 Subject: [PATCH 151/385] 8268231: Aarch64: Use ldp in intrinsics for String.compareTo Co-authored-by: Wang Huang Co-authored-by: Sun Jianye Co-authored-by: Wu Yan Reviewed-by: ngasson, aph --- .../cpu/aarch64/stubGenerator_aarch64.cpp | 133 +++++++++--------- 1 file changed, 66 insertions(+), 67 deletions(-) diff --git a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp index 72e24e4fe61..fca580a1d2a 100644 --- a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp @@ -4839,18 +4839,6 @@ class StubGenerator: public StubCodeGenerator { return entry; } - // code for comparing 16 bytes of strings with same encoding - void compare_string_16_bytes_same(Label &DIFF1, Label &DIFF2) { - Register result = r0, str1 = r1, cnt1 = r2, str2 = r3, tmp1 = r10, tmp2 = r11; - __ ldr(rscratch1, Address(__ post(str1, 8))); - __ eor(rscratch2, tmp1, tmp2); - __ ldr(cnt1, Address(__ post(str2, 8))); - __ cbnz(rscratch2, DIFF1); - __ ldr(tmp1, Address(__ post(str1, 8))); - __ eor(rscratch2, rscratch1, cnt1); - __ ldr(tmp2, Address(__ post(str2, 8))); - __ cbnz(rscratch2, DIFF2); - } // code for comparing 16 characters of strings with Latin1 and Utf16 encoding void compare_string_16_x_LU(Register tmpL, Register tmpU, Label &DIFF1, @@ -5057,15 +5045,18 @@ class StubGenerator: public StubCodeGenerator { : "compare_long_string_same_encoding UU"); address entry = __ pc(); Register result = r0, str1 = r1, cnt1 = r2, str2 = r3, cnt2 = r4, - tmp1 = r10, tmp2 = r11; - Label SMALL_LOOP, LARGE_LOOP_PREFETCH, CHECK_LAST, DIFF2, TAIL, - LENGTH_DIFF, DIFF, LAST_CHECK_AND_LENGTH_DIFF, - DIFF_LAST_POSITION, DIFF_LAST_POSITION2; + tmp1 = r10, tmp2 = r11, tmp1h = rscratch1, tmp2h = rscratch2; + + Label LARGE_LOOP_PREFETCH, LOOP_COMPARE16, DIFF, LESS16, LESS8, CAL_DIFFERENCE, LENGTH_DIFF; + // exit from large loop when less than 64 bytes left to read or we're about // to prefetch memory behind array border int largeLoopExitCondition = MAX2(64, SoftwarePrefetchHintDistance)/(isLL ? 1 : 2); - // cnt1/cnt2 contains amount of characters to compare. cnt1 can be re-used - // update cnt2 counter with already loaded 8 bytes + + // before jumping to stub, pre-load 8 bytes already, so do comparison directly + __ eor(rscratch2, tmp1, tmp2); + __ cbnz(rscratch2, CAL_DIFFERENCE); + __ sub(cnt2, cnt2, wordSize/(isLL ? 1 : 2)); // update pointers, because of previous read __ add(str1, str1, wordSize); @@ -5074,80 +5065,88 @@ class StubGenerator: public StubCodeGenerator { __ bind(LARGE_LOOP_PREFETCH); __ prfm(Address(str1, SoftwarePrefetchHintDistance)); __ prfm(Address(str2, SoftwarePrefetchHintDistance)); - compare_string_16_bytes_same(DIFF, DIFF2); - compare_string_16_bytes_same(DIFF, DIFF2); + + __ align(OptoLoopAlignment); + for (int i = 0; i < 4; i++) { + __ ldp(tmp1, tmp1h, Address(str1, i * 16)); + __ ldp(tmp2, tmp2h, Address(str2, i * 16)); + __ cmp(tmp1, tmp2); + __ ccmp(tmp1h, tmp2h, 0, Assembler::EQ); + __ br(Assembler::NE, DIFF); + } __ sub(cnt2, cnt2, isLL ? 64 : 32); - compare_string_16_bytes_same(DIFF, DIFF2); + __ add(str1, str1, 64); + __ add(str2, str2, 64); __ subs(rscratch2, cnt2, largeLoopExitCondition); - compare_string_16_bytes_same(DIFF, DIFF2); - __ br(__ GT, LARGE_LOOP_PREFETCH); - __ cbz(cnt2, LAST_CHECK_AND_LENGTH_DIFF); // no more chars left? + __ br(Assembler::GE, LARGE_LOOP_PREFETCH); + __ cbz(cnt2, LENGTH_DIFF); // no more chars left? } - // less than 16 bytes left? - __ subs(cnt2, cnt2, isLL ? 16 : 8); - __ br(__ LT, TAIL); + + __ subs(rscratch1, cnt2, isLL ? 16 : 8); + __ br(Assembler::LE, LESS16); __ align(OptoLoopAlignment); - __ bind(SMALL_LOOP); - compare_string_16_bytes_same(DIFF, DIFF2); - __ subs(cnt2, cnt2, isLL ? 16 : 8); - __ br(__ GE, SMALL_LOOP); - __ bind(TAIL); - __ adds(cnt2, cnt2, isLL ? 16 : 8); - __ br(__ EQ, LAST_CHECK_AND_LENGTH_DIFF); + __ bind(LOOP_COMPARE16); + __ ldp(tmp1, tmp1h, Address(__ post(str1, 16))); + __ ldp(tmp2, tmp2h, Address(__ post(str2, 16))); + __ cmp(tmp1, tmp2); + __ ccmp(tmp1h, tmp2h, 0, Assembler::EQ); + __ br(Assembler::NE, DIFF); + __ sub(cnt2, cnt2, isLL ? 16 : 8); + __ subs(rscratch2, cnt2, isLL ? 16 : 8); + __ br(Assembler::LT, LESS16); + + __ ldp(tmp1, tmp1h, Address(__ post(str1, 16))); + __ ldp(tmp2, tmp2h, Address(__ post(str2, 16))); + __ cmp(tmp1, tmp2); + __ ccmp(tmp1h, tmp2h, 0, Assembler::EQ); + __ br(Assembler::NE, DIFF); + __ sub(cnt2, cnt2, isLL ? 16 : 8); + __ subs(rscratch2, cnt2, isLL ? 16 : 8); + __ br(Assembler::GE, LOOP_COMPARE16); + __ cbz(cnt2, LENGTH_DIFF); + + __ bind(LESS16); + // each 8 compare __ subs(cnt2, cnt2, isLL ? 8 : 4); - __ br(__ LE, CHECK_LAST); - __ eor(rscratch2, tmp1, tmp2); - __ cbnz(rscratch2, DIFF); + __ br(Assembler::LE, LESS8); __ ldr(tmp1, Address(__ post(str1, 8))); __ ldr(tmp2, Address(__ post(str2, 8))); + __ eor(rscratch2, tmp1, tmp2); + __ cbnz(rscratch2, CAL_DIFFERENCE); __ sub(cnt2, cnt2, isLL ? 8 : 4); - __ bind(CHECK_LAST); + + __ bind(LESS8); // directly load last 8 bytes if (!isLL) { - __ add(cnt2, cnt2, cnt2); // now in bytes + __ add(cnt2, cnt2, cnt2); } + __ ldr(tmp1, Address(str1, cnt2)); + __ ldr(tmp2, Address(str2, cnt2)); __ eor(rscratch2, tmp1, tmp2); - __ cbnz(rscratch2, DIFF); - __ ldr(rscratch1, Address(str1, cnt2)); - __ ldr(cnt1, Address(str2, cnt2)); - __ eor(rscratch2, rscratch1, cnt1); __ cbz(rscratch2, LENGTH_DIFF); - // Find the first different characters in the longwords and - // compute their difference. - __ bind(DIFF2); - __ rev(rscratch2, rscratch2); - __ clz(rscratch2, rscratch2); - __ andr(rscratch2, rscratch2, isLL ? -8 : -16); - __ lsrv(rscratch1, rscratch1, rscratch2); - if (isLL) { - __ lsrv(cnt1, cnt1, rscratch2); - __ uxtbw(rscratch1, rscratch1); - __ uxtbw(cnt1, cnt1); - } else { - __ lsrv(cnt1, cnt1, rscratch2); - __ uxthw(rscratch1, rscratch1); - __ uxthw(cnt1, cnt1); - } - __ subw(result, rscratch1, cnt1); - __ b(LENGTH_DIFF); + __ b(CAL_DIFFERENCE); + __ bind(DIFF); + __ cmp(tmp1, tmp2); + __ csel(tmp1, tmp1, tmp1h, Assembler::NE); + __ csel(tmp2, tmp2, tmp2h, Assembler::NE); + // reuse rscratch2 register for the result of eor instruction + __ eor(rscratch2, tmp1, tmp2); + + __ bind(CAL_DIFFERENCE); __ rev(rscratch2, rscratch2); __ clz(rscratch2, rscratch2); __ andr(rscratch2, rscratch2, isLL ? -8 : -16); __ lsrv(tmp1, tmp1, rscratch2); + __ lsrv(tmp2, tmp2, rscratch2); if (isLL) { - __ lsrv(tmp2, tmp2, rscratch2); __ uxtbw(tmp1, tmp1); __ uxtbw(tmp2, tmp2); } else { - __ lsrv(tmp2, tmp2, rscratch2); __ uxthw(tmp1, tmp1); __ uxthw(tmp2, tmp2); } __ subw(result, tmp1, tmp2); - __ b(LENGTH_DIFF); - __ bind(LAST_CHECK_AND_LENGTH_DIFF); - __ eor(rscratch2, tmp1, tmp2); - __ cbnz(rscratch2, DIFF); + __ bind(LENGTH_DIFF); __ ret(lr); return entry; -- GitLab From 2c83559eda410d268c6d8a56d7fd1c34f817cb83 Mon Sep 17 00:00:00 2001 From: Andrey Turbanov Date: Sun, 10 Oct 2021 08:41:52 +0000 Subject: [PATCH 152/385] 8274882: Cleanup redundant boxing in java.desktop Reviewed-by: serb, pbansal --- .../classes/com/sun/java/swing/plaf/gtk/Metacity.java | 2 +- .../share/classes/javax/swing/SwingUtilities.java | 2 +- .../classes/javax/swing/plaf/metal/MetalLookAndFeel.java | 7 +++---- src/java.desktop/share/classes/sun/awt/SunToolkit.java | 5 ++--- .../share/classes/sun/awt/image/VSyncedBSManager.java | 2 +- .../share/classes/sun/java2d/marlin/MarlinProperties.java | 2 +- .../unix/classes/sun/awt/X11/MotifColorUtilities.java | 6 +++--- .../sun/java/swing/plaf/windows/WindowsLookAndFeel.java | 3 +-- .../classes/sun/awt/windows/TranslucentWindowPainter.java | 4 ++-- 9 files changed, 15 insertions(+), 18 deletions(-) diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/Metacity.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/Metacity.java index 141184087d0..134cdd9a2dc 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/Metacity.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/Metacity.java @@ -1708,7 +1708,7 @@ class Metacity implements SynthConstants { protected boolean getBooleanAttr(Node node, String name, boolean fallback) { String str = getStringAttr(node, name); if (str != null) { - return Boolean.valueOf(str).booleanValue(); + return Boolean.parseBoolean(str); } return fallback; } diff --git a/src/java.desktop/share/classes/javax/swing/SwingUtilities.java b/src/java.desktop/share/classes/javax/swing/SwingUtilities.java index 7a8aa2e316e..35260056d7e 100644 --- a/src/java.desktop/share/classes/javax/swing/SwingUtilities.java +++ b/src/java.desktop/share/classes/javax/swing/SwingUtilities.java @@ -78,7 +78,7 @@ public class SwingUtilities implements SwingConstants @SuppressWarnings("removal") private static boolean getSuppressDropTarget() { if (!checkedSuppressDropSupport) { - suppressDropSupport = Boolean.valueOf( + suppressDropSupport = Boolean.parseBoolean( AccessController.doPrivileged( new GetPropertyAction("suppressSwingDropSupport"))); checkedSuppressDropSupport = true; diff --git a/src/java.desktop/share/classes/javax/swing/plaf/metal/MetalLookAndFeel.java b/src/java.desktop/share/classes/javax/swing/plaf/metal/MetalLookAndFeel.java index 4899ae0736b..4142a92eb96 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/metal/MetalLookAndFeel.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/metal/MetalLookAndFeel.java @@ -125,8 +125,7 @@ public class MetalLookAndFeel extends BasicLookAndFeel @SuppressWarnings("removal") String systemFonts = AccessController.doPrivileged( new GetPropertyAction("swing.useSystemFontSettings")); - useSystemFonts = (systemFonts != null && - (Boolean.valueOf(systemFonts).booleanValue())); + useSystemFonts = Boolean.parseBoolean(systemFonts); } checkedWindows = true; } @@ -1398,8 +1397,8 @@ public class MetalLookAndFeel extends BasicLookAndFeel "Tree.openIcon",(LazyValue) t -> MetalIconFactory.getTreeFolderIcon(), "Tree.closedIcon",(LazyValue) t -> MetalIconFactory.getTreeFolderIcon(), "Tree.leafIcon",(LazyValue) t -> MetalIconFactory.getTreeLeafIcon(), - "Tree.expandedIcon",(LazyValue) t -> MetalIconFactory.getTreeControlIcon(Boolean.valueOf(MetalIconFactory.DARK)), - "Tree.collapsedIcon",(LazyValue) t -> MetalIconFactory.getTreeControlIcon(Boolean.valueOf( MetalIconFactory.LIGHT )), + "Tree.expandedIcon",(LazyValue) t -> MetalIconFactory.getTreeControlIcon(MetalIconFactory.DARK), + "Tree.collapsedIcon",(LazyValue) t -> MetalIconFactory.getTreeControlIcon(MetalIconFactory.LIGHT), "Tree.line", primaryControl, // horiz lines "Tree.hash", primaryControl, // legs diff --git a/src/java.desktop/share/classes/sun/awt/SunToolkit.java b/src/java.desktop/share/classes/sun/awt/SunToolkit.java index bfe9daeff48..dfc3d24c579 100644 --- a/src/java.desktop/share/classes/sun/awt/SunToolkit.java +++ b/src/java.desktop/share/classes/sun/awt/SunToolkit.java @@ -127,7 +127,7 @@ public abstract class SunToolkit extends Toolkit if (AccessController.doPrivileged(new GetBooleanAction("sun.awt.nativedebug"))) { DebugSettings.init(); } - touchKeyboardAutoShowIsEnabled = Boolean.valueOf( + touchKeyboardAutoShowIsEnabled = Boolean.parseBoolean( GetPropertyAction.privilegedGetProperty( "awt.touchKeyboardAutoShowIsEnabled", "true")); }; @@ -1767,8 +1767,7 @@ public abstract class SunToolkit extends Toolkit new GetPropertyAction("awt.useSystemAAFontSettings")); } if (systemAAFonts != null) { - useSystemAAFontSettings = - Boolean.valueOf(systemAAFonts).booleanValue(); + useSystemAAFontSettings = Boolean.parseBoolean(systemAAFonts); /* If it is anything other than "true", then it may be * a hint name , or it may be "off, "default", etc. */ diff --git a/src/java.desktop/share/classes/sun/awt/image/VSyncedBSManager.java b/src/java.desktop/share/classes/sun/awt/image/VSyncedBSManager.java index abe6e4422e4..8bb34dd6279 100644 --- a/src/java.desktop/share/classes/sun/awt/image/VSyncedBSManager.java +++ b/src/java.desktop/share/classes/sun/awt/image/VSyncedBSManager.java @@ -37,7 +37,7 @@ public abstract class VSyncedBSManager { @SuppressWarnings("removal") private static final boolean vSyncLimit = - Boolean.valueOf(java.security.AccessController.doPrivileged( + Boolean.parseBoolean(java.security.AccessController.doPrivileged( new sun.security.action.GetPropertyAction( "sun.java2d.vsynclimit", "true"))); diff --git a/src/java.desktop/share/classes/sun/java2d/marlin/MarlinProperties.java b/src/java.desktop/share/classes/sun/java2d/marlin/MarlinProperties.java index 23bf5d1ec5d..15f21e57ef6 100644 --- a/src/java.desktop/share/classes/sun/java2d/marlin/MarlinProperties.java +++ b/src/java.desktop/share/classes/sun/java2d/marlin/MarlinProperties.java @@ -241,7 +241,7 @@ public final class MarlinProperties { // system property utilities @SuppressWarnings("removal") static boolean getBoolean(final String key, final String def) { - return Boolean.valueOf(AccessController.doPrivileged( + return Boolean.parseBoolean(AccessController.doPrivileged( new GetPropertyAction(key, def))); } diff --git a/src/java.desktop/unix/classes/sun/awt/X11/MotifColorUtilities.java b/src/java.desktop/unix/classes/sun/awt/X11/MotifColorUtilities.java index f42a180532e..a94faf279ad 100644 --- a/src/java.desktop/unix/classes/sun/awt/X11/MotifColorUtilities.java +++ b/src/java.desktop/unix/classes/sun/awt/X11/MotifColorUtilities.java @@ -428,9 +428,9 @@ class MotifColorUtilities { for (int i=0;i<8;i++) { temp = bfr.readLine(); color = temp.substring(1,temp.length()); - r = Integer.valueOf(color.substring(0,4),16).intValue() >> 8; - g = Integer.valueOf(color.substring(4,8),16).intValue() >> 8; - b = Integer.valueOf(color.substring(8,12),16).intValue() >> 8; + r = Integer.parseInt(color.substring(0, 4), 16) >> 8; + g = Integer.parseInt(color.substring(4, 8), 16) >> 8; + b = Integer.parseInt(color.substring(8, 12), 16) >> 8; colors[i] = 0xff000000 | r<<16 | g<<8 | b; // System.out.println("color["+i+"]="+Integer.toHexString(colors[i]) + "r = " +r + "g="+g+"b="+b); } diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsLookAndFeel.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsLookAndFeel.java index be5657fac81..e8ad9418cb3 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsLookAndFeel.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsLookAndFeel.java @@ -186,8 +186,7 @@ public class WindowsLookAndFeel extends BasicLookAndFeel @SuppressWarnings("removal") String systemFonts = java.security.AccessController.doPrivileged( new GetPropertyAction("swing.useSystemFontSettings")); - useSystemFontSettings = (systemFonts == null || - Boolean.valueOf(systemFonts).booleanValue()); + useSystemFontSettings = systemFonts == null || Boolean.parseBoolean(systemFonts); if (useSystemFontSettings) { Object value = UIManager.get("Application.useSystemFontSettings"); diff --git a/src/java.desktop/windows/classes/sun/awt/windows/TranslucentWindowPainter.java b/src/java.desktop/windows/classes/sun/awt/windows/TranslucentWindowPainter.java index 57278bd24a1..bc63a8169e6 100644 --- a/src/java.desktop/windows/classes/sun/awt/windows/TranslucentWindowPainter.java +++ b/src/java.desktop/windows/classes/sun/awt/windows/TranslucentWindowPainter.java @@ -68,11 +68,11 @@ abstract class TranslucentWindowPainter { // REMIND: we probably would want to remove this later @SuppressWarnings("removal") private static final boolean forceOpt = - Boolean.valueOf(AccessController.doPrivileged( + Boolean.parseBoolean(AccessController.doPrivileged( new GetPropertyAction("sun.java2d.twp.forceopt", "false"))); @SuppressWarnings("removal") private static final boolean forceSW = - Boolean.valueOf(AccessController.doPrivileged( + Boolean.parseBoolean(AccessController.doPrivileged( new GetPropertyAction("sun.java2d.twp.forcesw", "false"))); /** -- GitLab From 296f8537f71b84f194cf2718ac9b85ba6843cfa3 Mon Sep 17 00:00:00 2001 From: "lawrence.andrews" Date: Sun, 10 Oct 2021 08:46:04 +0000 Subject: [PATCH 153/385] 8274029: Remove jtreg tag manual=yesno for java/awt/print/Dialog/DialogOrient.java Reviewed-by: serb --- test/jdk/java/awt/print/Dialog/DialogOrient.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/jdk/java/awt/print/Dialog/DialogOrient.java b/test/jdk/java/awt/print/Dialog/DialogOrient.java index 7d9012c939d..92b3c65e642 100644 --- a/test/jdk/java/awt/print/Dialog/DialogOrient.java +++ b/test/jdk/java/awt/print/Dialog/DialogOrient.java @@ -25,7 +25,7 @@ @test @bug 6594374 @summary Confirm that the orientation is as specified. - @run main/manual=yesno DialogOrient + @run main/manual DialogOrient */ import java.awt.*; -- GitLab From 2ff3977a66c8d8b521cd0ad266ba954682a268ce Mon Sep 17 00:00:00 2001 From: Jie Fu Date: Sun, 10 Oct 2021 14:00:58 +0000 Subject: [PATCH 154/385] 8275004: CDS build failure with gcc11 Reviewed-by: shade --- src/hotspot/share/cds/cdsConstants.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hotspot/share/cds/cdsConstants.hpp b/src/hotspot/share/cds/cdsConstants.hpp index 72590dce657..d116fbf47ae 100644 --- a/src/hotspot/share/cds/cdsConstants.hpp +++ b/src/hotspot/share/cds/cdsConstants.hpp @@ -26,6 +26,7 @@ #define SHARE_CDS_CDSCONSTANTS_HPP #include "memory/allStatic.hpp" +#include "utilities/globalDefinitions.hpp" typedef struct { const char* _name; -- GitLab From 5ecc99bbf55e631b5bfa07e2c36b38e820682363 Mon Sep 17 00:00:00 2001 From: Lin Zang Date: Mon, 11 Oct 2021 01:56:34 +0000 Subject: [PATCH 155/385] 8274620: resourcehogs/serviceability/sa/TestHeapDumpForLargeArray.java is timing out Reviewed-by: cjplummer, dholmes --- .../classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java | 4 ++-- test/hotspot/jtreg/ProblemList.txt | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java index ce69cc5049c..c8afa4c1b2d 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java @@ -409,10 +409,10 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter { // open file stream and create buffered data output stream fos = new FileOutputStream(fileName); - hprofBufferedOut = fos; + hprofBufferedOut = new BufferedOutputStream(fos); if (useSegmentedHeapDump) { if (isCompression()) { - hprofBufferedOut = new GZIPOutputStream(fos) { + hprofBufferedOut = new GZIPOutputStream(hprofBufferedOut) { { this.def.setLevel(gzLevel); } diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index 3bf51607a35..988426e23ec 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -120,8 +120,6 @@ serviceability/sa/ClhsdbFindPC.java#xcomp-core 8269982 macosx-aarch64 serviceability/sa/ClhsdbFindPC.java#no-xcomp-core 8269982 macosx-aarch64 serviceability/sa/ClhsdbPstack.java#core 8269982 macosx-aarch64 -resourcehogs/serviceability/sa/TestHeapDumpForLargeArray.java 8274620 macosx-x64 - ############################################################################# # :hotspot_misc -- GitLab From a05873a225c40d12e60870794b9c993d1ea89cfe Mon Sep 17 00:00:00 2001 From: Ao Qi Date: Mon, 11 Oct 2021 02:17:56 +0000 Subject: [PATCH 156/385] 8274952: jdk/jfr/api/consumer/TestRecordedFrameType.java failed when c1 disabled Reviewed-by: egahlin, jiefu --- test/jdk/jdk/jfr/api/consumer/TestRecordedFrameType.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/jdk/jdk/jfr/api/consumer/TestRecordedFrameType.java b/test/jdk/jdk/jfr/api/consumer/TestRecordedFrameType.java index a74dc034591..7b2b96a4235 100644 --- a/test/jdk/jdk/jfr/api/consumer/TestRecordedFrameType.java +++ b/test/jdk/jdk/jfr/api/consumer/TestRecordedFrameType.java @@ -40,7 +40,7 @@ import sun.hotspot.WhiteBox; * @test * @summary Test jdk.jfr.consumer.RecordedFrame::getType() * @key jfr - * @requires vm.hasJFR + * @requires vm.hasJFR & vm.compiler1.enabled * @library /test/lib * @build sun.hotspot.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox -- GitLab From c032186b421c64b44397cb7aa101b40e5f93dfff Mon Sep 17 00:00:00 2001 From: Fei Gao Date: Mon, 11 Oct 2021 06:59:37 +0000 Subject: [PATCH 157/385] 8272968: AArch64: Remove redundant matching rules for commutative ops Reviewed-by: ngasson --- src/hotspot/cpu/aarch64/aarch64.ad | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/hotspot/cpu/aarch64/aarch64.ad b/src/hotspot/cpu/aarch64/aarch64.ad index e701e0a3a60..52d624a2de6 100644 --- a/src/hotspot/cpu/aarch64/aarch64.ad +++ b/src/hotspot/cpu/aarch64/aarch64.ad @@ -10893,7 +10893,6 @@ instruct msubI(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2, iRegIorL2I src3) instruct mnegI(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2, immI0 zero) %{ match(Set dst (MulI (SubI zero src1) src2)); - match(Set dst (MulI src1 (SubI zero src2))); ins_cost(INSN_COST * 3); format %{ "mneg $dst, $src1, $src2" %} @@ -10945,7 +10944,6 @@ instruct msubL(iRegLNoSp dst, iRegL src1, iRegL src2, iRegL src3) %{ instruct mnegL(iRegLNoSp dst, iRegL src1, iRegL src2, immL0 zero) %{ match(Set dst (MulL (SubL zero src1) src2)); - match(Set dst (MulL src1 (SubL zero src2))); ins_cost(INSN_COST * 5); format %{ "mneg $dst, $src1, $src2" %} @@ -10995,7 +10993,6 @@ instruct smsubL(iRegLNoSp dst, iRegIorL2I src1, iRegIorL2I src2, iRegLNoSp src3) instruct smnegL(iRegLNoSp dst, iRegIorL2I src1, iRegIorL2I src2, immL0 zero) %{ match(Set dst (MulL (SubL zero (ConvI2L src1)) (ConvI2L src2))); - match(Set dst (MulL (ConvI2L src1) (SubL zero (ConvI2L src2)))); ins_cost(INSN_COST * 3); format %{ "smnegl $dst, $src1, $src2" %} -- GitLab From 49f8ce6e9c797cd11ea586e3cf87398888bc8cf1 Mon Sep 17 00:00:00 2001 From: Martin Doerr Date: Mon, 11 Oct 2021 10:31:54 +0000 Subject: [PATCH 158/385] 8274773: [TESTBUG] UnsafeIntrinsicsTest intermittently fails on weak memory model platform Reviewed-by: eosterlund, goetz --- test/hotspot/jtreg/compiler/gcbarriers/UnsafeIntrinsicsTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/test/hotspot/jtreg/compiler/gcbarriers/UnsafeIntrinsicsTest.java b/test/hotspot/jtreg/compiler/gcbarriers/UnsafeIntrinsicsTest.java index 321f60ea8b7..c006bc608d1 100644 --- a/test/hotspot/jtreg/compiler/gcbarriers/UnsafeIntrinsicsTest.java +++ b/test/hotspot/jtreg/compiler/gcbarriers/UnsafeIntrinsicsTest.java @@ -289,6 +289,7 @@ class Runner implements Runnable { private Node mergeImplLoad(Node startNode, Node expectedNext, Node head) { // Atomic load version Node temp = (Node) UNSAFE.getReference(startNode, offset); + UNSAFE.storeFence(); // Make all new Node fields visible to concurrent readers. startNode.setNext(head); return temp; } -- GitLab From 3edee1e1feed564397ac47a32c0394d7798bac17 Mon Sep 17 00:00:00 2001 From: Roman Kennke Date: Mon, 11 Oct 2021 10:37:54 +0000 Subject: [PATCH 159/385] 8272723: Don't use Access API to access primitive fields Reviewed-by: stefank, eosterlund --- src/hotspot/share/classfile/javaClasses.cpp | 10 +- .../share/classfile/javaClasses.inline.hpp | 8 +- src/hotspot/share/jvmci/jvmciJavaClasses.cpp | 4 +- .../share/oops/instanceKlass.inline.hpp | 6 +- src/hotspot/share/oops/oop.cpp | 48 ++++----- src/hotspot/share/oops/oop.hpp | 7 +- src/hotspot/share/oops/oop.inline.hpp | 42 ++++---- .../share/oops/typeArrayOop.inline.hpp | 100 +++++------------- src/hotspot/share/prims/unsafe.cpp | 75 ++++--------- 9 files changed, 106 insertions(+), 194 deletions(-) diff --git a/src/hotspot/share/classfile/javaClasses.cpp b/src/hotspot/share/classfile/javaClasses.cpp index 6ec79035dda..ef0b5ad429a 100644 --- a/src/hotspot/share/classfile/javaClasses.cpp +++ b/src/hotspot/share/classfile/javaClasses.cpp @@ -4220,8 +4220,8 @@ void java_lang_invoke_MethodHandleNatives_CallSiteContext::serialize_offsets(Ser DependencyContext java_lang_invoke_MethodHandleNatives_CallSiteContext::vmdependencies(oop call_site) { assert(java_lang_invoke_MethodHandleNatives_CallSiteContext::is_instance(call_site), ""); - nmethodBucket* volatile* vmdeps_addr = (nmethodBucket* volatile*)call_site->field_addr(_vmdependencies_offset); - volatile uint64_t* last_cleanup_addr = (volatile uint64_t*)call_site->field_addr(_last_cleanup_offset); + nmethodBucket* volatile* vmdeps_addr = call_site->field_addr(_vmdependencies_offset); + volatile uint64_t* last_cleanup_addr = call_site->field_addr(_last_cleanup_offset); DependencyContext dep_ctx(vmdeps_addr, last_cleanup_addr); return dep_ctx; } @@ -4279,19 +4279,19 @@ int java_lang_ClassLoader::_parent_offset; ClassLoaderData* java_lang_ClassLoader::loader_data_acquire(oop loader) { assert(loader != NULL, "loader must not be NULL"); assert(oopDesc::is_oop(loader), "loader must be oop"); - return HeapAccess::load_at(loader, _loader_data_offset); + return Atomic::load_acquire(loader->field_addr(_loader_data_offset)); } ClassLoaderData* java_lang_ClassLoader::loader_data(oop loader) { assert(loader != NULL, "loader must not be NULL"); assert(oopDesc::is_oop(loader), "loader must be oop"); - return HeapAccess<>::load_at(loader, _loader_data_offset); + return *loader->field_addr(_loader_data_offset); } void java_lang_ClassLoader::release_set_loader_data(oop loader, ClassLoaderData* new_data) { assert(loader != NULL, "loader must not be NULL"); assert(oopDesc::is_oop(loader), "loader must be oop"); - HeapAccess::store_at(loader, _loader_data_offset, new_data); + Atomic::release_store(loader->field_addr(_loader_data_offset), new_data); } #define CLASSLOADER_FIELDS_DO(macro) \ diff --git a/src/hotspot/share/classfile/javaClasses.inline.hpp b/src/hotspot/share/classfile/javaClasses.inline.hpp index e8ee4fce25e..ef21f56d9a4 100644 --- a/src/hotspot/share/classfile/javaClasses.inline.hpp +++ b/src/hotspot/share/classfile/javaClasses.inline.hpp @@ -77,7 +77,7 @@ bool java_lang_String::is_latin1(oop java_string) { uint8_t* java_lang_String::flags_addr(oop java_string) { assert(_initialized, "Must be initialized"); assert(is_instance(java_string), "Must be java string"); - return java_string->obj_field_addr(_flags_offset); + return java_string->field_addr(_flags_offset); } bool java_lang_String::is_flag_set(oop java_string, uint8_t flag_mask) { @@ -146,7 +146,7 @@ void java_lang_ref_Reference::clear_referent(oop ref) { } HeapWord* java_lang_ref_Reference::referent_addr_raw(oop ref) { - return ref->obj_field_addr(_referent_offset); + return ref->field_addr(_referent_offset); } oop java_lang_ref_Reference::next(oop ref) { @@ -162,7 +162,7 @@ void java_lang_ref_Reference::set_next_raw(oop ref, oop value) { } HeapWord* java_lang_ref_Reference::next_addr_raw(oop ref) { - return ref->obj_field_addr(_next_offset); + return ref->field_addr(_next_offset); } oop java_lang_ref_Reference::discovered(oop ref) { @@ -178,7 +178,7 @@ void java_lang_ref_Reference::set_discovered_raw(oop ref, oop value) { } HeapWord* java_lang_ref_Reference::discovered_addr_raw(oop ref) { - return ref->obj_field_addr(_discovered_offset); + return ref->field_addr(_discovered_offset); } bool java_lang_ref_Reference::is_final(oop ref) { diff --git a/src/hotspot/share/jvmci/jvmciJavaClasses.cpp b/src/hotspot/share/jvmci/jvmciJavaClasses.cpp index ed99adb0450..32b1fdfcaab 100644 --- a/src/hotspot/share/jvmci/jvmciJavaClasses.cpp +++ b/src/hotspot/share/jvmci/jvmciJavaClasses.cpp @@ -231,13 +231,13 @@ void HotSpotJVMCI::compute_offsets(TRAPS) { assert(className::klass() != NULL && className::klass()->is_linked(), "Class not yet linked: " #className); \ InstanceKlass* ik = className::klass(); \ oop base = ik->static_field_base_raw(); \ - return HeapAccess<>::load_at(base, className::_##name##_offset); \ + return *base->field_addr(className::_##name##_offset); \ } \ void HotSpotJVMCI::className::set_##name(JVMCIEnv* env, jtypename x) { \ assert(className::klass() != NULL && className::klass()->is_linked(), "Class not yet linked: " #className); \ InstanceKlass* ik = className::klass(); \ oop base = ik->static_field_base_raw(); \ - HeapAccess<>::store_at(base, _##name##_offset, x); \ + *base->field_addr(className::_##name##_offset) = x; \ } #define STATIC_INT_FIELD(className, name) STATIC_PRIMITIVE_FIELD(className, name, jint) diff --git a/src/hotspot/share/oops/instanceKlass.inline.hpp b/src/hotspot/share/oops/instanceKlass.inline.hpp index 8b6e2c335b6..3522631f59b 100644 --- a/src/hotspot/share/oops/instanceKlass.inline.hpp +++ b/src/hotspot/share/oops/instanceKlass.inline.hpp @@ -84,7 +84,7 @@ inline void InstanceKlass::release_set_methods_jmethod_ids(jmethodID* jmeths) { template ALWAYSINLINE void InstanceKlass::oop_oop_iterate_oop_map(OopMapBlock* map, oop obj, OopClosureType* closure) { - T* p = (T*)obj->obj_field_addr(map->offset()); + T* p = obj->field_addr(map->offset()); T* const end = p + map->count(); for (; p < end; ++p) { @@ -94,7 +94,7 @@ ALWAYSINLINE void InstanceKlass::oop_oop_iterate_oop_map(OopMapBlock* map, oop o template ALWAYSINLINE void InstanceKlass::oop_oop_iterate_oop_map_reverse(OopMapBlock* map, oop obj, OopClosureType* closure) { - T* const start = (T*)obj->obj_field_addr(map->offset()); + T* const start = obj->field_addr(map->offset()); T* p = start + map->count(); while (start < p) { @@ -105,7 +105,7 @@ ALWAYSINLINE void InstanceKlass::oop_oop_iterate_oop_map_reverse(OopMapBlock* ma template ALWAYSINLINE void InstanceKlass::oop_oop_iterate_oop_map_bounded(OopMapBlock* map, oop obj, OopClosureType* closure, MemRegion mr) { - T* p = (T*)obj->obj_field_addr(map->offset()); + T* p = obj->field_addr(map->offset()); T* end = p + map->count(); T* const l = (T*)mr.start(); diff --git a/src/hotspot/share/oops/oop.cpp b/src/hotspot/share/oops/oop.cpp index 88601f1aa2b..14592997091 100644 --- a/src/hotspot/share/oops/oop.cpp +++ b/src/hotspot/share/oops/oop.cpp @@ -179,41 +179,41 @@ void oopDesc::obj_field_put_raw(int offset, oop value) { RawAcces void oopDesc::release_obj_field_put(int offset, oop value) { HeapAccess::oop_store_at(as_oop(), offset, value); } void oopDesc::obj_field_put_volatile(int offset, oop value) { HeapAccess::oop_store_at(as_oop(), offset, value); } -address oopDesc::address_field(int offset) const { return HeapAccess<>::load_at(as_oop(), offset); } -address oopDesc::address_field_acquire(int offset) const { return HeapAccess::load_at(as_oop(), offset); } +address oopDesc::address_field(int offset) const { return *field_addr
      (offset); } +address oopDesc::address_field_acquire(int offset) const { return Atomic::load_acquire(field_addr
      (offset)); } -void oopDesc::address_field_put(int offset, address value) { HeapAccess<>::store_at(as_oop(), offset, value); } -void oopDesc::release_address_field_put(int offset, address value) { HeapAccess::store_at(as_oop(), offset, value); } +void oopDesc::address_field_put(int offset, address value) { *field_addr
      (offset) = value; } +void oopDesc::release_address_field_put(int offset, address value) { Atomic::release_store(field_addr
      (offset), value); } -Metadata* oopDesc::metadata_field(int offset) const { return HeapAccess<>::load_at(as_oop(), offset); } -void oopDesc::metadata_field_put(int offset, Metadata* value) { HeapAccess<>::store_at(as_oop(), offset, value); } +Metadata* oopDesc::metadata_field(int offset) const { return *field_addr(offset); } +void oopDesc::metadata_field_put(int offset, Metadata* value) { *field_addr(offset) = value; } -Metadata* oopDesc::metadata_field_acquire(int offset) const { return HeapAccess::load_at(as_oop(), offset); } -void oopDesc::release_metadata_field_put(int offset, Metadata* value) { HeapAccess::store_at(as_oop(), offset, value); } +Metadata* oopDesc::metadata_field_acquire(int offset) const { return Atomic::load_acquire(field_addr(offset)); } +void oopDesc::release_metadata_field_put(int offset, Metadata* value) { Atomic::release_store(field_addr(offset), value); } -jbyte oopDesc::byte_field_acquire(int offset) const { return HeapAccess::load_at(as_oop(), offset); } -void oopDesc::release_byte_field_put(int offset, jbyte value) { HeapAccess::store_at(as_oop(), offset, value); } +jbyte oopDesc::byte_field_acquire(int offset) const { return Atomic::load_acquire(field_addr(offset)); } +void oopDesc::release_byte_field_put(int offset, jbyte value) { Atomic::release_store(field_addr(offset), value); } -jchar oopDesc::char_field_acquire(int offset) const { return HeapAccess::load_at(as_oop(), offset); } -void oopDesc::release_char_field_put(int offset, jchar value) { HeapAccess::store_at(as_oop(), offset, value); } +jchar oopDesc::char_field_acquire(int offset) const { return Atomic::load_acquire(field_addr(offset)); } +void oopDesc::release_char_field_put(int offset, jchar value) { Atomic::release_store(field_addr(offset), value); } -jboolean oopDesc::bool_field_acquire(int offset) const { return HeapAccess::load_at(as_oop(), offset); } -void oopDesc::release_bool_field_put(int offset, jboolean value) { HeapAccess::store_at(as_oop(), offset, jboolean(value & 1)); } +jboolean oopDesc::bool_field_acquire(int offset) const { return Atomic::load_acquire(field_addr(offset)); } +void oopDesc::release_bool_field_put(int offset, jboolean value) { Atomic::release_store(field_addr(offset), jboolean(value & 1)); } -jint oopDesc::int_field_acquire(int offset) const { return HeapAccess::load_at(as_oop(), offset); } -void oopDesc::release_int_field_put(int offset, jint value) { HeapAccess::store_at(as_oop(), offset, value); } +jint oopDesc::int_field_acquire(int offset) const { return Atomic::load_acquire(field_addr(offset)); } +void oopDesc::release_int_field_put(int offset, jint value) { Atomic::release_store(field_addr(offset), value); } -jshort oopDesc::short_field_acquire(int offset) const { return HeapAccess::load_at(as_oop(), offset); } -void oopDesc::release_short_field_put(int offset, jshort value) { HeapAccess::store_at(as_oop(), offset, value); } +jshort oopDesc::short_field_acquire(int offset) const { return Atomic::load_acquire(field_addr(offset)); } +void oopDesc::release_short_field_put(int offset, jshort value) { Atomic::release_store(field_addr(offset), value); } -jlong oopDesc::long_field_acquire(int offset) const { return HeapAccess::load_at(as_oop(), offset); } -void oopDesc::release_long_field_put(int offset, jlong value) { HeapAccess::store_at(as_oop(), offset, value); } +jlong oopDesc::long_field_acquire(int offset) const { return Atomic::load_acquire(field_addr(offset)); } +void oopDesc::release_long_field_put(int offset, jlong value) { Atomic::release_store(field_addr(offset), value); } -jfloat oopDesc::float_field_acquire(int offset) const { return HeapAccess::load_at(as_oop(), offset); } -void oopDesc::release_float_field_put(int offset, jfloat value) { HeapAccess::store_at(as_oop(), offset, value); } +jfloat oopDesc::float_field_acquire(int offset) const { return Atomic::load_acquire(field_addr(offset)); } +void oopDesc::release_float_field_put(int offset, jfloat value) { Atomic::release_store(field_addr(offset), value); } -jdouble oopDesc::double_field_acquire(int offset) const { return HeapAccess::load_at(as_oop(), offset); } -void oopDesc::release_double_field_put(int offset, jdouble value) { HeapAccess::store_at(as_oop(), offset, value); } +jdouble oopDesc::double_field_acquire(int offset) const { return Atomic::load_acquire(field_addr(offset)); } +void oopDesc::release_double_field_put(int offset, jdouble value) { Atomic::release_store(field_addr(offset), value); } #ifdef ASSERT void oopDesc::verify_forwardee(oop forwardee) { diff --git a/src/hotspot/share/oops/oop.hpp b/src/hotspot/share/oops/oop.hpp index 7a7608051a1..3232496bef4 100644 --- a/src/hotspot/share/oops/oop.hpp +++ b/src/hotspot/share/oops/oop.hpp @@ -124,11 +124,8 @@ class oopDesc { inline oop as_oop() const { return const_cast(this); } public: - // field addresses in oop - inline void* field_addr(int offset) const; - - // Need this as public for garbage collection. - template inline T* obj_field_addr(int offset) const; + template + inline T* field_addr(int offset) const; template inline size_t field_offset(T* p) const; diff --git a/src/hotspot/share/oops/oop.inline.hpp b/src/hotspot/share/oops/oop.inline.hpp index 84b43bf8ff8..ff1c6c56afa 100644 --- a/src/hotspot/share/oops/oop.inline.hpp +++ b/src/hotspot/share/oops/oop.inline.hpp @@ -208,10 +208,8 @@ bool oopDesc::is_array() const { return klass()->is_array_klass(); } bool oopDesc::is_objArray() const { return klass()->is_objArray_klass(); } bool oopDesc::is_typeArray() const { return klass()->is_typeArray_klass(); } -void* oopDesc::field_addr(int offset) const { return reinterpret_cast(cast_from_oop(as_oop()) + offset); } - -template -T* oopDesc::obj_field_addr(int offset) const { return (T*) field_addr(offset); } +template +T* oopDesc::field_addr(int offset) const { return reinterpret_cast(cast_from_oop(as_oop()) + offset); } template size_t oopDesc::field_offset(T* p) const { return pointer_delta((void*)p, (void*)this, 1); } @@ -222,30 +220,30 @@ inline oop oopDesc::obj_field(int offset) const { return Hea inline void oopDesc::obj_field_put(int offset, oop value) { HeapAccess<>::oop_store_at(as_oop(), offset, value); } -inline jbyte oopDesc::byte_field(int offset) const { return HeapAccess<>::load_at(as_oop(), offset); } -inline void oopDesc::byte_field_put(int offset, jbyte value) { HeapAccess<>::store_at(as_oop(), offset, value); } +inline jbyte oopDesc::byte_field(int offset) const { return *field_addr(offset); } +inline void oopDesc::byte_field_put(int offset, jbyte value) { *field_addr(offset) = value; } -inline jchar oopDesc::char_field(int offset) const { return HeapAccess<>::load_at(as_oop(), offset); } -inline void oopDesc::char_field_put(int offset, jchar value) { HeapAccess<>::store_at(as_oop(), offset, value); } +inline jchar oopDesc::char_field(int offset) const { return *field_addr(offset); } +inline void oopDesc::char_field_put(int offset, jchar value) { *field_addr(offset) = value; } -inline jboolean oopDesc::bool_field(int offset) const { return HeapAccess<>::load_at(as_oop(), offset); } -inline void oopDesc::bool_field_put(int offset, jboolean value) { HeapAccess<>::store_at(as_oop(), offset, jboolean(value & 1)); } -inline jboolean oopDesc::bool_field_volatile(int offset) const { return HeapAccess::load_at(as_oop(), offset); } -inline void oopDesc::bool_field_put_volatile(int offset, jboolean value) { HeapAccess::store_at(as_oop(), offset, jboolean(value & 1)); } -inline jshort oopDesc::short_field(int offset) const { return HeapAccess<>::load_at(as_oop(), offset); } -inline void oopDesc::short_field_put(int offset, jshort value) { HeapAccess<>::store_at(as_oop(), offset, value); } +inline jboolean oopDesc::bool_field(int offset) const { return *field_addr(offset); } +inline void oopDesc::bool_field_put(int offset, jboolean value) { *field_addr(offset) = jboolean(value & 1); } +inline jboolean oopDesc::bool_field_volatile(int offset) const { return RawAccess::load(field_addr(offset)); } +inline void oopDesc::bool_field_put_volatile(int offset, jboolean value) { RawAccess::store(field_addr(offset), jboolean(value & 1)); } +inline jshort oopDesc::short_field(int offset) const { return *field_addr(offset); } +inline void oopDesc::short_field_put(int offset, jshort value) { *field_addr(offset) = value; } -inline jint oopDesc::int_field(int offset) const { return HeapAccess<>::load_at(as_oop(), offset); } -inline void oopDesc::int_field_put(int offset, jint value) { HeapAccess<>::store_at(as_oop(), offset, value); } +inline jint oopDesc::int_field(int offset) const { return *field_addr(offset); } +inline void oopDesc::int_field_put(int offset, jint value) { *field_addr(offset) = value; } -inline jlong oopDesc::long_field(int offset) const { return HeapAccess<>::load_at(as_oop(), offset); } -inline void oopDesc::long_field_put(int offset, jlong value) { HeapAccess<>::store_at(as_oop(), offset, value); } +inline jlong oopDesc::long_field(int offset) const { return *field_addr(offset); } +inline void oopDesc::long_field_put(int offset, jlong value) { *field_addr(offset) = value; } -inline jfloat oopDesc::float_field(int offset) const { return HeapAccess<>::load_at(as_oop(), offset); } -inline void oopDesc::float_field_put(int offset, jfloat value) { HeapAccess<>::store_at(as_oop(), offset, value); } +inline jfloat oopDesc::float_field(int offset) const { return *field_addr(offset); } +inline void oopDesc::float_field_put(int offset, jfloat value) { *field_addr(offset) = value; } -inline jdouble oopDesc::double_field(int offset) const { return HeapAccess<>::load_at(as_oop(), offset); } -inline void oopDesc::double_field_put(int offset, jdouble value) { HeapAccess<>::store_at(as_oop(), offset, value); } +inline jdouble oopDesc::double_field(int offset) const { return *field_addr(offset); } +inline void oopDesc::double_field_put(int offset, jdouble value) { *field_addr(offset) = value; } bool oopDesc::is_locked() const { return mark().is_locked(); diff --git a/src/hotspot/share/oops/typeArrayOop.inline.hpp b/src/hotspot/share/oops/typeArrayOop.inline.hpp index cf4cfc6995e..5a23cd6eb28 100644 --- a/src/hotspot/share/oops/typeArrayOop.inline.hpp +++ b/src/hotspot/share/oops/typeArrayOop.inline.hpp @@ -90,113 +90,76 @@ inline jdouble* typeArrayOopDesc::double_at_addr(int which) const { } inline jbyte typeArrayOopDesc::byte_at(int which) const { - assert(is_within_bounds(which), "index %d out of bounds %d", which, length()); - ptrdiff_t offset = element_offset(which); - return HeapAccess::load_at(as_oop(), offset); + return *byte_at_addr(which); } inline void typeArrayOopDesc::byte_at_put(int which, jbyte contents) { - assert(is_within_bounds(which), "index %d out of bounds %d", which, length()); - ptrdiff_t offset = element_offset(which); - HeapAccess::store_at(as_oop(), offset, contents); + *byte_at_addr(which) = contents; } inline jboolean typeArrayOopDesc::bool_at(int which) const { - assert(is_within_bounds(which), "index %d out of bounds %d", which, length()); - ptrdiff_t offset = element_offset(which); - return HeapAccess::load_at(as_oop(), offset); + return *bool_at_addr(which); } inline void typeArrayOopDesc::bool_at_put(int which, jboolean contents) { - assert(is_within_bounds(which), "index %d out of bounds %d", which, length()); - ptrdiff_t offset = element_offset(which); - HeapAccess::store_at(as_oop(), offset, jboolean(contents & 1)); + *bool_at_addr(which) = jboolean(contents & 1); } inline jchar typeArrayOopDesc::char_at(int which) const { - assert(is_within_bounds(which), "index %d out of bounds %d", which, length()); - ptrdiff_t offset = element_offset(which); - return HeapAccess::load_at(as_oop(), offset); + return *char_at_addr(which); } inline void typeArrayOopDesc::char_at_put(int which, jchar contents) { - assert(is_within_bounds(which), "index %d out of bounds %d", which, length()); - ptrdiff_t offset = element_offset(which); - HeapAccess::store_at(as_oop(), offset, contents); + *char_at_addr(which) = contents; } inline jint typeArrayOopDesc::int_at(int which) const { - assert(is_within_bounds(which), "index %d out of bounds %d", which, length()); - ptrdiff_t offset = element_offset(which); - return HeapAccess::load_at(as_oop(), offset); + return *int_at_addr(which); } inline void typeArrayOopDesc::int_at_put(int which, jint contents) { - assert(is_within_bounds(which), "index %d out of bounds %d", which, length()); - ptrdiff_t offset = element_offset(which); - HeapAccess::store_at(as_oop(), offset, contents); + *int_at_addr(which) = contents; } inline jshort typeArrayOopDesc::short_at(int which) const { - assert(is_within_bounds(which), "index %d out of bounds %d", which, length()); - ptrdiff_t offset = element_offset(which); - return HeapAccess::load_at(as_oop(), offset); + return *short_at_addr(which); } inline void typeArrayOopDesc::short_at_put(int which, jshort contents) { - assert(is_within_bounds(which), "index %d out of bounds %d", which, length()); - ptrdiff_t offset = element_offset(which); - HeapAccess::store_at(as_oop(), offset, contents); + *short_at_addr(which) = contents; } inline jushort typeArrayOopDesc::ushort_at(int which) const { - assert(is_within_bounds(which), "index %d out of bounds %d", which, length()); - ptrdiff_t offset = element_offset(which); - return HeapAccess::load_at(as_oop(), offset); + return *ushort_at_addr(which); } + inline void typeArrayOopDesc::ushort_at_put(int which, jushort contents) { - assert(is_within_bounds(which), "index %d out of bounds %d", which, length()); - ptrdiff_t offset = element_offset(which); - HeapAccess::store_at(as_oop(), offset, contents); + *ushort_at_addr(which) = contents; } inline jlong typeArrayOopDesc::long_at(int which) const { - assert(is_within_bounds(which), "index %d out of bounds %d", which, length()); - ptrdiff_t offset = element_offset(which); - return HeapAccess::load_at(as_oop(), offset); + return *long_at_addr(which); } inline void typeArrayOopDesc::long_at_put(int which, jlong contents) { - assert(is_within_bounds(which), "index %d out of bounds %d", which, length()); - ptrdiff_t offset = element_offset(which); - HeapAccess::store_at(as_oop(), offset, contents); + *long_at_addr(which) = contents; } inline jfloat typeArrayOopDesc::float_at(int which) const { - assert(is_within_bounds(which), "index %d out of bounds %d", which, length()); - ptrdiff_t offset = element_offset(which); - return HeapAccess::load_at(as_oop(), offset); + return *float_at_addr(which); } + inline void typeArrayOopDesc::float_at_put(int which, jfloat contents) { - assert(is_within_bounds(which), "index %d out of bounds %d", which, length()); - ptrdiff_t offset = element_offset(which); - HeapAccess::store_at(as_oop(), offset, contents); + *float_at_addr(which) = contents; } inline jdouble typeArrayOopDesc::double_at(int which) const { - assert(is_within_bounds(which), "index %d out of bounds %d", which, length()); - ptrdiff_t offset = element_offset(which); - return HeapAccess::load_at(as_oop(), offset); + return *double_at_addr(which); } + inline void typeArrayOopDesc::double_at_put(int which, jdouble contents) { - assert(is_within_bounds(which), "index %d out of bounds %d", which, length()); - ptrdiff_t offset = element_offset(which); - HeapAccess::store_at(as_oop(), offset, contents); + *double_at_addr(which) = contents; } inline jbyte typeArrayOopDesc::byte_at_acquire(int which) const { - assert(is_within_bounds(which), "index %d out of bounds %d", which, length()); - ptrdiff_t offset = element_offset(which); - return HeapAccess::load_at(as_oop(), offset); + return Atomic::load_acquire(byte_at_addr(which)); } inline void typeArrayOopDesc::release_byte_at_put(int which, jbyte contents) { - assert(is_within_bounds(which), "index %d out of bounds %d", which, length()); - ptrdiff_t offset = element_offset(which); - HeapAccess::store_at(as_oop(), offset, contents); + Atomic::release_store(byte_at_addr(which), contents); } // Java thinks Symbol arrays are just arrays of either long or int, since @@ -204,25 +167,18 @@ inline void typeArrayOopDesc::release_byte_at_put(int which, jbyte contents) { // casting #ifdef _LP64 inline Symbol* typeArrayOopDesc::symbol_at(int which) const { - assert(is_within_bounds(which), "index %d out of bounds %d", which, length()); - ptrdiff_t offset = element_offset(which); - return (Symbol*)(jlong) HeapAccess::load_at(as_oop(), offset); + return *reinterpret_cast(long_at_addr(which)); } + inline void typeArrayOopDesc::symbol_at_put(int which, Symbol* contents) { - assert(is_within_bounds(which), "index %d out of bounds %d", which, length()); - ptrdiff_t offset = element_offset(which); - HeapAccess::store_at(as_oop(), offset, (jlong)contents); + *reinterpret_cast(long_at_addr(which)) = contents; } #else inline Symbol* typeArrayOopDesc::symbol_at(int which) const { - assert(is_within_bounds(which), "index %d out of bounds %d", which, length()); - ptrdiff_t offset = element_offset(which); - return (Symbol*)(jint) HeapAccess::load_at(as_oop(), offset); + return *reinterpret_cast(int_at_addr(which)); } inline void typeArrayOopDesc::symbol_at_put(int which, Symbol* contents) { - assert(is_within_bounds(which), "index %d out of bounds %d", which, length()); - ptrdiff_t offset = element_offset(which); - HeapAccess::store_at(as_oop(), offset, (jint)contents); + *reinterpret_cast(int_at_addr(which)) = contents; } #endif // _LP64 diff --git a/src/hotspot/share/prims/unsafe.cpp b/src/hotspot/share/prims/unsafe.cpp index ee6c218f533..ade9651bcb8 100644 --- a/src/hotspot/share/prims/unsafe.cpp +++ b/src/hotspot/share/prims/unsafe.cpp @@ -119,7 +119,7 @@ static inline void assert_field_offset_sane(oop p, jlong field_offset) { assert(byte_offset >= 0 && byte_offset <= (jlong)MAX_OBJECT_SIZE, "sane offset"); if (byte_offset == (jint)byte_offset) { void* ptr_plus_disp = cast_from_oop
      (p) + byte_offset; - assert(p->field_addr((jint)byte_offset) == ptr_plus_disp, + assert(p->field_addr((jint)byte_offset) == ptr_plus_disp, "raw [ptr+disp] must be consistent with oop::field_addr"); } jlong p_size = HeapWordSize * (jlong)(p->size()); @@ -218,44 +218,25 @@ public: } T get() { - if (_obj == NULL) { - GuardUnsafeAccess guard(_thread); - T ret = RawAccess<>::load(addr()); - return normalize_for_read(ret); - } else { - T ret = HeapAccess<>::load_at(_obj, _offset); - return normalize_for_read(ret); - } + GuardUnsafeAccess guard(_thread); + return normalize_for_read(*addr()); } void put(T x) { - if (_obj == NULL) { - GuardUnsafeAccess guard(_thread); - RawAccess<>::store(addr(), normalize_for_write(x)); - } else { - HeapAccess<>::store_at(_obj, _offset, normalize_for_write(x)); - } + GuardUnsafeAccess guard(_thread); + *addr() = normalize_for_write(x); } T get_volatile() { - if (_obj == NULL) { - GuardUnsafeAccess guard(_thread); - volatile T ret = RawAccess::load(addr()); - return normalize_for_read(ret); - } else { - T ret = HeapAccess::load_at(_obj, _offset); - return normalize_for_read(ret); - } + GuardUnsafeAccess guard(_thread); + volatile T ret = RawAccess::load(addr()); + return normalize_for_read(ret); } void put_volatile(T x) { - if (_obj == NULL) { - GuardUnsafeAccess guard(_thread); - RawAccess::store(addr(), normalize_for_write(x)); - } else { - HeapAccess::store_at(_obj, _offset, normalize_for_write(x)); - } + GuardUnsafeAccess guard(_thread); + RawAccess::store(addr(), normalize_for_write(x)); } }; @@ -745,24 +726,14 @@ UNSAFE_ENTRY(jobject, Unsafe_CompareAndExchangeReference(JNIEnv *env, jobject un UNSAFE_ENTRY(jint, Unsafe_CompareAndExchangeInt(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jint e, jint x)) { oop p = JNIHandles::resolve(obj); - if (p == NULL) { - volatile jint* addr = (volatile jint*)index_oop_from_field_offset_long(p, offset); - return RawAccess<>::atomic_cmpxchg(addr, e, x); - } else { - assert_field_offset_sane(p, offset); - return HeapAccess<>::atomic_cmpxchg_at(p, (ptrdiff_t)offset, e, x); - } + volatile jint* addr = (volatile jint*)index_oop_from_field_offset_long(p, offset); + return Atomic::cmpxchg(addr, e, x); } UNSAFE_END UNSAFE_ENTRY(jlong, Unsafe_CompareAndExchangeLong(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jlong e, jlong x)) { oop p = JNIHandles::resolve(obj); - if (p == NULL) { - volatile jlong* addr = (volatile jlong*)index_oop_from_field_offset_long(p, offset); - return RawAccess<>::atomic_cmpxchg(addr, e, x); - } else { - assert_field_offset_sane(p, offset); - return HeapAccess<>::atomic_cmpxchg_at(p, (ptrdiff_t)offset, e, x); - } + volatile jlong* addr = (volatile jlong*)index_oop_from_field_offset_long(p, offset); + return Atomic::cmpxchg(addr, e, x); } UNSAFE_END UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSetReference(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jobject e_h, jobject x_h)) { @@ -776,24 +747,14 @@ UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSetReference(JNIEnv *env, jobject unsafe UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSetInt(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jint e, jint x)) { oop p = JNIHandles::resolve(obj); - if (p == NULL) { - volatile jint* addr = (volatile jint*)index_oop_from_field_offset_long(p, offset); - return RawAccess<>::atomic_cmpxchg(addr, e, x) == e; - } else { - assert_field_offset_sane(p, offset); - return HeapAccess<>::atomic_cmpxchg_at(p, (ptrdiff_t)offset, e, x) == e; - } + volatile jint* addr = (volatile jint*)index_oop_from_field_offset_long(p, offset); + return Atomic::cmpxchg(addr, e, x) == e; } UNSAFE_END UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSetLong(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jlong e, jlong x)) { oop p = JNIHandles::resolve(obj); - if (p == NULL) { - volatile jlong* addr = (volatile jlong*)index_oop_from_field_offset_long(p, offset); - return RawAccess<>::atomic_cmpxchg(addr, e, x) == e; - } else { - assert_field_offset_sane(p, offset); - return HeapAccess<>::atomic_cmpxchg_at(p, (ptrdiff_t)offset, e, x) == e; - } + volatile jlong* addr = (volatile jlong*)index_oop_from_field_offset_long(p, offset); + return Atomic::cmpxchg(addr, e, x) == e; } UNSAFE_END static void post_thread_park_event(EventThreadPark* event, const oop obj, jlong timeout_nanos, jlong until_epoch_millis) { -- GitLab From c55dd365e3463670697b09de0ff70877203e5a69 Mon Sep 17 00:00:00 2001 From: Jie Fu Date: Mon, 11 Oct 2021 10:51:39 +0000 Subject: [PATCH 160/385] 8275008: gtest build failure due to stringop-overflow warning with gcc11 Reviewed-by: dholmes, ihse --- make/hotspot/lib/CompileGtest.gmk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/make/hotspot/lib/CompileGtest.gmk b/make/hotspot/lib/CompileGtest.gmk index 03c4de783cd..cb2bbccc168 100644 --- a/make/hotspot/lib/CompileGtest.gmk +++ b/make/hotspot/lib/CompileGtest.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -101,7 +101,7 @@ $(eval $(call SetupJdkLibrary, BUILD_GTEST_LIBJVM, \ CFLAGS_windows := -EHsc, \ CFLAGS_macosx := -DGTEST_OS_MAC=1, \ DISABLED_WARNINGS_gcc := $(DISABLED_WARNINGS_gcc) \ - undef, \ + undef stringop-overflow, \ DISABLED_WARNINGS_clang := $(DISABLED_WARNINGS_clang) \ undef switch format-nonliteral tautological-undefined-compare \ self-assign-overloaded, \ -- GitLab From aaf2401bc7d766dee5ffc623db86c4723c7e3760 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Mon, 11 Oct 2021 11:46:46 +0000 Subject: [PATCH 161/385] 8274927: Remove unnecessary G1ArchiveAllocator code Reviewed-by: kbarrett, ayang --- src/hotspot/share/gc/g1/g1Allocator.cpp | 2 -- src/hotspot/share/gc/g1/g1Allocator.hpp | 17 ------------- src/hotspot/share/gc/g1/g1CollectedHeap.cpp | 27 ++++++++------------- 3 files changed, 10 insertions(+), 36 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1Allocator.cpp b/src/hotspot/share/gc/g1/g1Allocator.cpp index 8f67d28cfcb..bf38b786f03 100644 --- a/src/hotspot/share/gc/g1/g1Allocator.cpp +++ b/src/hotspot/share/gc/g1/g1Allocator.cpp @@ -475,7 +475,6 @@ HeapWord* G1ArchiveAllocator::archive_mem_allocate(size_t word_size) { // Non-zero space; need to insert the filler size_t fill_size = free_words; CollectedHeap::fill_with_object(old_top, fill_size); - _summary_bytes_used += fill_size * HeapWordSize; } // Set the current chunk as "full" _allocation_region->set_top(_max); @@ -495,7 +494,6 @@ HeapWord* G1ArchiveAllocator::archive_mem_allocate(size_t word_size) { } assert(pointer_delta(_max, old_top) >= word_size, "enough space left"); _allocation_region->set_top(old_top + word_size); - _summary_bytes_used += word_size * HeapWordSize; return old_top; } diff --git a/src/hotspot/share/gc/g1/g1Allocator.hpp b/src/hotspot/share/gc/g1/g1Allocator.hpp index 2f84a6efb98..5014442845a 100644 --- a/src/hotspot/share/gc/g1/g1Allocator.hpp +++ b/src/hotspot/share/gc/g1/g1Allocator.hpp @@ -223,9 +223,6 @@ protected: // Regions allocated for the current archive range. GrowableArray _allocated_regions; - // The number of bytes used in the current range. - size_t _summary_bytes_used; - // Current allocation window within the current region. HeapWord* _bottom; HeapWord* _top; @@ -243,7 +240,6 @@ public: _allocated_regions((ResourceObj::set_allocation_type((address) &_allocated_regions, ResourceObj::C_HEAP), 2), mtGC), - _summary_bytes_used(0), _bottom(NULL), _top(NULL), _max(NULL) { } @@ -261,19 +257,6 @@ public: // aligning to the requested alignment. void complete_archive(GrowableArray* ranges, size_t end_alignment_in_bytes); - - // The number of bytes allocated by this allocator. - size_t used() { - return _summary_bytes_used; - } - - // Clear the count of bytes allocated in prior G1 regions. This - // must be done when recalculate_use is used to reset the counter - // for the generic allocator, since it counts bytes in all G1 - // regions, including those still associated with this allocator. - void clear_used() { - _summary_bytes_used = 0; - } }; #endif // SHARE_GC_G1_G1ALLOCATOR_HPP diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index 1e8e36d8aa3..fe38b0a49e6 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp @@ -498,9 +498,8 @@ HeapWord* G1CollectedHeap::attempt_allocation_slow(size_t word_size) { void G1CollectedHeap::begin_archive_alloc_range(bool open) { assert_at_safepoint_on_vm_thread(); - if (_archive_allocator == NULL) { - _archive_allocator = G1ArchiveAllocator::create_allocator(this, open); - } + assert(_archive_allocator == nullptr, "should not be initialized"); + _archive_allocator = G1ArchiveAllocator::create_allocator(this, open); } bool G1CollectedHeap::is_archive_alloc_too_large(size_t word_size) { @@ -512,9 +511,9 @@ bool G1CollectedHeap::is_archive_alloc_too_large(size_t word_size) { HeapWord* G1CollectedHeap::archive_mem_allocate(size_t word_size) { assert_at_safepoint_on_vm_thread(); - assert(_archive_allocator != NULL, "_archive_allocator not initialized"); + assert(_archive_allocator != nullptr, "_archive_allocator not initialized"); if (is_archive_alloc_too_large(word_size)) { - return NULL; + return nullptr; } return _archive_allocator->archive_mem_allocate(word_size); } @@ -522,13 +521,13 @@ HeapWord* G1CollectedHeap::archive_mem_allocate(size_t word_size) { void G1CollectedHeap::end_archive_alloc_range(GrowableArray* ranges, size_t end_alignment_in_bytes) { assert_at_safepoint_on_vm_thread(); - assert(_archive_allocator != NULL, "_archive_allocator not initialized"); + assert(_archive_allocator != nullptr, "_archive_allocator not initialized"); // Call complete_archive to do the real work, filling in the MemRegion // array with the archive regions. _archive_allocator->complete_archive(ranges, end_alignment_in_bytes); delete _archive_allocator; - _archive_allocator = NULL; + _archive_allocator = nullptr; } bool G1CollectedHeap::check_archive_addresses(MemRegion* ranges, size_t count) { @@ -1449,7 +1448,7 @@ G1CollectedHeap::G1CollectedHeap() : _verifier(NULL), _summary_bytes_used(0), _bytes_used_during_gc(0), - _archive_allocator(NULL), + _archive_allocator(nullptr), _survivor_evac_stats("Young", YoungPLABSize, PLABWeight), _old_evac_stats("Old", OldPLABSize, PLABWeight), _monitoring_support(nullptr), @@ -1861,9 +1860,7 @@ void G1CollectedHeap::iterate_hcc_closure(G1CardTableEntryClosure* cl, uint work // Computes the sum of the storage used by the various regions. size_t G1CollectedHeap::used() const { size_t result = _summary_bytes_used + _allocator->used_in_alloc_regions(); - if (_archive_allocator != NULL) { - result += _archive_allocator->used(); - } + assert(_archive_allocator == nullptr, "must be, should not contribute to used"); return result; } @@ -3197,9 +3194,7 @@ void G1CollectedHeap::rebuild_region_sets(bool free_list_only) { if (!free_list_only) { set_used(cl.total_used()); - if (_archive_allocator != NULL) { - _archive_allocator->clear_used(); - } + assert(_archive_allocator == nullptr, "must be, should not contribute to used"); } assert_used_and_recalculate_used_equal(this); } @@ -3393,9 +3388,7 @@ void G1CollectedHeap::update_used_after_gc(bool evacuation_failed) { set_used(recalculate_used()); - if (_archive_allocator != NULL) { - _archive_allocator->clear_used(); - } + assert(_archive_allocator == nullptr, "must be, should not contribute to used"); } else { // The "used" of the the collection set have already been subtracted // when they were freed. Add in the bytes used. -- GitLab From b7af890574b3c13122fe7de987a8c9458c05f625 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Mon, 11 Oct 2021 11:48:50 +0000 Subject: [PATCH 162/385] 8274430: Remove some debug error printing code added in JDK-8017163 Reviewed-by: sjohanss, ayang --- src/hotspot/share/gc/g1/heapRegion.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/hotspot/share/gc/g1/heapRegion.cpp b/src/hotspot/share/gc/g1/heapRegion.cpp index dbf3f42d4a4..71abe4a2d45 100644 --- a/src/hotspot/share/gc/g1/heapRegion.cpp +++ b/src/hotspot/share/gc/g1/heapRegion.cpp @@ -611,12 +611,11 @@ public: if (!_failures) { log.error("----------"); } - LogStream ls(log.error()); - to->rem_set()->print_info(&ls, p); log.error("Missing rem set entry:"); log.error("Field " PTR_FORMAT " of obj " PTR_FORMAT " in region " HR_FORMAT, p2i(p), p2i(_containing_obj), HR_FORMAT_PARAMS(from)); ResourceMark rm; + LogStream ls(log.error()); _containing_obj->print_on(&ls); log.error("points to obj " PTR_FORMAT " in region " HR_FORMAT " remset %s", p2i(obj), HR_FORMAT_PARAMS(to), to->rem_set()->get_state_str()); -- GitLab From 110e38ded8e09361f24c582c770d35f5cfdabf82 Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Mon, 11 Oct 2021 12:11:11 +0000 Subject: [PATCH 163/385] 8274753: ZGC: SEGV in MetaspaceShared::link_shared_classes 8274935: dumptime_table has stale entry Reviewed-by: eosterlund, iklam --- src/hotspot/share/cds/metaspaceShared.cpp | 13 ++++---- .../share/classfile/classLoaderData.cpp | 3 ++ .../DynamicLoaderConstraintsTest.java | 30 +++++++++++++++++-- 3 files changed, 37 insertions(+), 9 deletions(-) diff --git a/src/hotspot/share/cds/metaspaceShared.cpp b/src/hotspot/share/cds/metaspaceShared.cpp index 741e9cd680f..17e27a5372f 100644 --- a/src/hotspot/share/cds/metaspaceShared.cpp +++ b/src/hotspot/share/cds/metaspaceShared.cpp @@ -584,20 +584,19 @@ void VM_PopulateDumpSharedSpace::doit() { class CollectCLDClosure : public CLDClosure { GrowableArray _loaded_cld; - GrowableArray _loaded_cld_handles; // keep the CLDs alive + GrowableArray _loaded_cld_handles; // keep the CLDs alive Thread* _current_thread; public: CollectCLDClosure(Thread* thread) : _current_thread(thread) {} ~CollectCLDClosure() { - for (int i = 0; i < _loaded_cld.length(); i++) { - ClassLoaderData* cld = _loaded_cld.at(i); + for (int i = 0; i < _loaded_cld_handles.length(); i++) { + _loaded_cld_handles.at(i).release(Universe::vm_global()); } } void do_cld(ClassLoaderData* cld) { - if (!cld->is_unloading()) { - _loaded_cld.append(cld); - _loaded_cld_handles.append(Handle(_current_thread, cld->holder_phantom())); - } + assert(cld->is_alive(), "must be"); + _loaded_cld.append(cld); + _loaded_cld_handles.append(OopHandle(Universe::vm_global(), cld->holder_phantom())); } int nof_cld() const { return _loaded_cld.length(); } diff --git a/src/hotspot/share/classfile/classLoaderData.cpp b/src/hotspot/share/classfile/classLoaderData.cpp index 3f20c385bfb..fe702db9192 100644 --- a/src/hotspot/share/classfile/classLoaderData.cpp +++ b/src/hotspot/share/classfile/classLoaderData.cpp @@ -55,6 +55,7 @@ #include "classfile/packageEntry.hpp" #include "classfile/symbolTable.hpp" #include "classfile/systemDictionary.hpp" +#include "classfile/systemDictionaryShared.hpp" #include "classfile/vmClasses.hpp" #include "logging/log.hpp" #include "logging/logStream.hpp" @@ -884,6 +885,8 @@ void ClassLoaderData::free_deallocate_list_C_heap_structures() { // Remove the class so unloading events aren't triggered for // this class (scratch or error class) in do_unloading(). remove_class(ik); + // But still have to remove it from the dumptime_table. + SystemDictionaryShared::handle_class_unloading(ik); } } } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/loaderConstraints/DynamicLoaderConstraintsTest.java b/test/hotspot/jtreg/runtime/cds/appcds/loaderConstraints/DynamicLoaderConstraintsTest.java index 95edc901a35..e7e7197c43e 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/loaderConstraints/DynamicLoaderConstraintsTest.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/loaderConstraints/DynamicLoaderConstraintsTest.java @@ -52,6 +52,23 @@ * @run main/othervm/timeout=180 -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. DynamicLoaderConstraintsTest custom */ +/** + * @test id=custom-cl-zgc + * @requires vm.cds.custom.loaders + * @requires vm.gc.Z + * @summary Test dumptime_table entries are removed with zgc eager class unloading + * @bug 8274935 + * @library /test/lib + * /test/hotspot/jtreg/runtime/cds/appcds + * /test/hotspot/jtreg/runtime/cds/appcds/test-classes + * /test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive + * @modules java.base/jdk.internal.misc + * jdk.httpserver + * @build sun.hotspot.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm/timeout=180 -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. DynamicLoaderConstraintsTest custom-zgc + */ + import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpHandler; import jdk.test.lib.Asserts; @@ -83,9 +100,11 @@ public class DynamicLoaderConstraintsTest extends DynamicArchiveTestBase { * if false, LoaderConstraintsApp will be loaded by the built-in AppClassLoader. */ static boolean useCustomLoader; + static boolean useZGC; public static void main(String[] args) throws Exception { useCustomLoader = (args.length != 0); + useZGC = (args.length != 0 && args[0].equals("custom-zgc")); runTest(DynamicLoaderConstraintsTest::doTest); } @@ -124,8 +143,15 @@ public class DynamicLoaderConstraintsTest extends DynamicArchiveTestBase { }; if (useCustomLoader) { - cmdLine = TestCommon.concat(cmdLine, "-cp", loaderJar, - loaderMainClass, appJar); + if (useZGC) { + // Add options to force eager class unloading. + cmdLine = TestCommon.concat(cmdLine, "-cp", loaderJar, + "-XX:+UseZGC", "-XX:ZCollectionInterval=0.01", + loaderMainClass, appJar); + } else { + cmdLine = TestCommon.concat(cmdLine, "-cp", loaderJar, + loaderMainClass, appJar); + } } else { cmdLine = TestCommon.concat(cmdLine, "-cp", appJar); } -- GitLab From b870468bdc99938fbb19a41b0ede0a3e3769ace2 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Mon, 11 Oct 2021 12:38:08 +0000 Subject: [PATCH 164/385] 8274347: Passing a *nested* switch expression as a parameter causes an NPE during compile Reviewed-by: vromero --- .../com/sun/tools/javac/comp/Attr.java | 3 + .../tools/javac/api/TestGetScopeResult.java | 76 ++++++++++++++++++- .../switchexpr/ExpressionSwitchInfer.java | 12 ++- 3 files changed, 88 insertions(+), 3 deletions(-) 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 56b678f8472..df50d2486a1 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 @@ -1800,6 +1800,7 @@ public class Attr extends JCTree.Visitor { } addVars(c.stats, switchEnv.info.scope); + preFlow(c); c.completesNormally = flow.aliveAfter(caseEnv, c, make); prevBindings = c.caseKind == CaseTree.CaseKind.STATEMENT && c.completesNormally ? currentBindings @@ -5918,6 +5919,8 @@ public class Attr extends JCTree.Visitor { @Override public void visitBindingPattern(JCBindingPattern that) { + initTypeIfNeeded(that); + initTypeIfNeeded(that.var); if (that.var.sym == null) { that.var.sym = new BindingSymbol(0, that.var.name, that.var.type, syms.noSymbol); that.var.sym.adr = 0; diff --git a/test/langtools/tools/javac/api/TestGetScopeResult.java b/test/langtools/tools/javac/api/TestGetScopeResult.java index 545543511fb..d7964ecb5b4 100644 --- a/test/langtools/tools/javac/api/TestGetScopeResult.java +++ b/test/langtools/tools/javac/api/TestGetScopeResult.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 8205418 8207229 8207230 8230847 8245786 8247334 8248641 8240658 8246774 + * @bug 8205418 8207229 8207230 8230847 8245786 8247334 8248641 8240658 8246774 8274347 * @summary Test the outcomes from Trees.getScope * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.comp @@ -88,6 +88,7 @@ public class TestGetScopeResult { new TestGetScopeResult().testRecord(); new TestGetScopeResult().testLocalRecordAnnotation(); new TestGetScopeResult().testRuleCases(); + new TestGetScopeResult().testNestedSwitchExpression(); } public void run() throws IOException { @@ -751,6 +752,77 @@ public class TestGetScopeResult { } } + void testNestedSwitchExpression() throws IOException { + JavacTool c = JavacTool.create(); + try (StandardJavaFileManager fm = c.getStandardFileManager(null, null, null)) { + String code = """ + class Test { + void t(Object o1, Object o2) { + System.err.println(switch (o1) { + case String s -> switch (j) { + case Integer i -> { + int scopeHere; + yield ""; + } + default -> ""; + }; + default -> ""; + }); + } + } + """; + class MyFileObject extends SimpleJavaFileObject { + MyFileObject() { + super(URI.create("myfo:///Test.java"), SOURCE); + } + @Override + public String getCharContent(boolean ignoreEncodingErrors) { + return code; + } + } + Context ctx = new Context(); + TestAnalyzer.preRegister(ctx); + JavacTask t = (JavacTask) c.getTask(null, fm, null, null, null, + List.of(new MyFileObject()), ctx); + CompilationUnitTree cut = t.parse().iterator().next(); + t.analyze(); + + List> actual = new ArrayList<>(); + + new TreePathScanner() { + @Override + public Void visitVariable(VariableTree node, Void p) { + if (node.getName().contentEquals("scopeHere")) { + Scope scope = Trees.instance(t).getScope(getCurrentPath()); + actual.add(dumpScope(scope)); + JCTree body = getCaseBody(scope); + if (body == null) { + throw new AssertionError("Unexpected null body."); + } + } + return super.visitVariable(node, p); + } + JCTree getCaseBody(Scope scope) { + return ((JCCase) ((JavacScope) scope).getEnv().next.next.tree).body; + } + }.scan(cut, null); + + List> expected = + List.of(List.of("scopeHere:int", + "i:java.lang.Integer", + "s:java.lang.String", + "o2:java.lang.Object", + "o1:java.lang.Object", + "super:java.lang.Object", + "this:Test" + )); + + if (!expected.equals(actual)) { + throw new AssertionError("Unexpected Scope content: " + actual); + } + } + } + private List dumpScope(Scope scope) { List content = new ArrayList<>(); while (scope.getEnclosingClass() != null) { diff --git a/test/langtools/tools/javac/switchexpr/ExpressionSwitchInfer.java b/test/langtools/tools/javac/switchexpr/ExpressionSwitchInfer.java index a796411fc66..18074281e6a 100644 --- a/test/langtools/tools/javac/switchexpr/ExpressionSwitchInfer.java +++ b/test/langtools/tools/javac/switchexpr/ExpressionSwitchInfer.java @@ -1,6 +1,6 @@ /* * @test /nodynamiccopyright/ - * @bug 8206986 8254286 + * @bug 8206986 8254286 8274347 * @summary Check types inferred for switch expressions. * @compile/fail/ref=ExpressionSwitchInfer.out -XDrawDiagnostics ExpressionSwitchInfer.java */ @@ -83,4 +83,14 @@ public class ExpressionSwitchInfer { interface I1 extends I {} interface I2 extends I {} + void preflow(int i, int j) { + System.out.println(switch (i) { + case 1 -> switch (j) { + case 1 -> "one and one"; + default -> "one and many"; + }; + case 2 -> "two"; + default -> "many"; + }); + } } -- GitLab From 0d80f6cf82ddab85f2461c7cc663a93bb222e988 Mon Sep 17 00:00:00 2001 From: Patricio Chilano Mateo Date: Mon, 11 Oct 2021 13:34:42 +0000 Subject: [PATCH 165/385] 8274379: Allow process of unsafe access errors in check_special_condition_for_native_trans Reviewed-by: rehn, dholmes --- src/hotspot/share/prims/jvm.cpp | 2 +- src/hotspot/share/prims/jvmtiEnv.cpp | 2 +- src/hotspot/share/runtime/safepoint.hpp | 1 - src/hotspot/share/runtime/thread.cpp | 55 +++++++-------------- src/hotspot/share/runtime/thread.hpp | 39 +++++---------- src/hotspot/share/runtime/thread.inline.hpp | 15 ++++-- src/hotspot/share/runtime/vmStructs.cpp | 2 - 7 files changed, 42 insertions(+), 74 deletions(-) diff --git a/src/hotspot/share/prims/jvm.cpp b/src/hotspot/share/prims/jvm.cpp index 0e00986804d..acc64da5281 100644 --- a/src/hotspot/share/prims/jvm.cpp +++ b/src/hotspot/share/prims/jvm.cpp @@ -2961,7 +2961,7 @@ JVM_ENTRY(void, JVM_StopThread(JNIEnv* env, jobject jthread, jobject throwable)) THROW_OOP(java_throwable); } else { // Use a VM_Operation to throw the exception. - JavaThread::send_async_exception(java_thread, java_throwable); + JavaThread::send_async_exception(receiver, java_throwable); } } else { // Either: diff --git a/src/hotspot/share/prims/jvmtiEnv.cpp b/src/hotspot/share/prims/jvmtiEnv.cpp index f04dc7dd27c..5680e7d1670 100644 --- a/src/hotspot/share/prims/jvmtiEnv.cpp +++ b/src/hotspot/share/prims/jvmtiEnv.cpp @@ -1072,7 +1072,7 @@ JvmtiEnv::StopThread(JavaThread* java_thread, jobject exception) { oop e = JNIHandles::resolve_external_guard(exception); NULL_CHECK(e, JVMTI_ERROR_NULL_POINTER); - JavaThread::send_async_exception(java_thread->threadObj(), e); + JavaThread::send_async_exception(java_thread, e); return JVMTI_ERROR_NONE; diff --git a/src/hotspot/share/runtime/safepoint.hpp b/src/hotspot/share/runtime/safepoint.hpp index 2342b379b74..a2aaf381e8d 100644 --- a/src/hotspot/share/runtime/safepoint.hpp +++ b/src/hotspot/share/runtime/safepoint.hpp @@ -131,7 +131,6 @@ class SafepointSynchronize : AllStatic { switch(state) { case _thread_in_vm: case _thread_in_Java: // From compiled code - case _thread_in_native_trans: case _thread_blocked_trans: return true; default: diff --git a/src/hotspot/share/runtime/thread.cpp b/src/hotspot/share/runtime/thread.cpp index 0188420b0ce..a2a41754ede 100644 --- a/src/hotspot/share/runtime/thread.cpp +++ b/src/hotspot/share/runtime/thread.cpp @@ -1001,8 +1001,10 @@ JavaThread::JavaThread() : _monitor_chunks(nullptr), _suspend_flags(0), - _async_exception_condition(_no_async_condition), _pending_async_exception(nullptr), +#ifdef ASSERT + _is_unsafe_access_error(false), +#endif _thread_state(_thread_new), _saved_exception_pc(nullptr), @@ -1572,9 +1574,6 @@ void JavaThread::remove_monitor_chunk(MonitorChunk* chunk) { // Asynchronous exceptions support // -// Note: this function shouldn't block if it's called in -// _thread_in_native_trans state (such as from -// check_special_condition_for_native_trans()). void JavaThread::check_and_handle_async_exceptions() { if (has_last_Java_frame() && has_async_exception_condition()) { // If we are at a polling page safepoint (not a poll return) @@ -1600,21 +1599,12 @@ void JavaThread::check_and_handle_async_exceptions() { } } - AsyncExceptionCondition condition = clear_async_exception_condition(); - if (condition == _no_async_condition) { - // Conditions have changed since has_special_runtime_exit_condition() - // was called: - // - if we were here only because of an external suspend request, - // then that was taken care of above (or cancelled) so we are done - // - if we were here because of another async request, then it has - // been cleared between the has_special_runtime_exit_condition() - // and now so again we are done + if (!clear_async_exception_condition()) { return; } - // Check for pending async. exception if (_pending_async_exception != NULL) { - // Only overwrite an already pending exception, if it is not a threadDeath. + // Only overwrite an already pending exception if it is not a threadDeath. if (!has_pending_exception() || !pending_exception()->is_a(vmClasses::ThreadDeath_klass())) { // We cannot call Exceptions::_throw(...) here because we cannot block @@ -1631,25 +1621,23 @@ void JavaThread::check_and_handle_async_exceptions() { } ls.print_cr(" of type: %s", _pending_async_exception->klass()->external_name()); } - _pending_async_exception = NULL; - // Clear condition from _suspend_flags since we have finished processing it. - clear_suspend_flag(_has_async_exception); } - } + // Always null out the _pending_async_exception oop here since the async condition was + // already cleared above and thus considered handled. + _pending_async_exception = NULL; + } else { + assert(_is_unsafe_access_error, "must be"); + DEBUG_ONLY(_is_unsafe_access_error = false); - if (condition == _async_unsafe_access_error && !has_pending_exception()) { // We may be at method entry which requires we save the do-not-unlock flag. UnlockFlagSaver fs(this); switch (thread_state()) { case _thread_in_vm: { JavaThread* THREAD = this; Exceptions::throw_unsafe_access_internal_error(THREAD, __FILE__, __LINE__, "a fault occurred in an unsafe memory access operation"); - return; - } - case _thread_in_native: { - ThreadInVMfromNative tiv(this); - JavaThread* THREAD = this; - Exceptions::throw_unsafe_access_internal_error(THREAD, __FILE__, __LINE__, "a fault occurred in an unsafe memory access operation"); + // We might have blocked in a ThreadBlockInVM wrapper in the call above so make sure we process pending + // suspend requests and object reallocation operations if any since we might be going to Java after this. + SafepointMechanism::process_if_requested_with_exit_check(this, true /* check asyncs */); return; } case _thread_in_Java: { @@ -1662,8 +1650,6 @@ void JavaThread::check_and_handle_async_exceptions() { ShouldNotReachHere(); } } - - assert(has_pending_exception(), "must have handled the async condition if no exception"); } void JavaThread::handle_special_runtime_exit_condition(bool check_asyncs) { @@ -1696,9 +1682,8 @@ public: } }; -void JavaThread::send_async_exception(oop java_thread, oop java_throwable) { +void JavaThread::send_async_exception(JavaThread* target, oop java_throwable) { Handle throwable(Thread::current(), java_throwable); - JavaThread* target = java_lang_Thread::thread(java_thread); InstallAsyncExceptionClosure vm_stop(throwable); Handshake::execute(&vm_stop, target); } @@ -1847,21 +1832,17 @@ void JavaThread::check_special_condition_for_native_trans(JavaThread *thread) { assert(thread->thread_state() == _thread_in_native_trans, "wrong state"); assert(!thread->has_last_Java_frame() || thread->frame_anchor()->walkable(), "Unwalkable stack in native->Java transition"); + thread->set_thread_state(_thread_in_vm); + // Enable WXWrite: called directly from interpreter native wrapper. MACOS_AARCH64_ONLY(ThreadWXEnable wx(WXWrite, thread)); - SafepointMechanism::process_if_requested_with_exit_check(thread, false /* check asyncs */); + SafepointMechanism::process_if_requested_with_exit_check(thread, true /* check asyncs */); // After returning from native, it could be that the stack frames are not // yet safe to use. We catch such situations in the subsequent stack watermark // barrier, which will trap unsafe stack frames. StackWatermarkSet::before_unwind(thread); - - if (thread->has_async_exception_condition(false /* check unsafe access error */)) { - // We are in _thread_in_native_trans state, don't handle unsafe - // access error since that may block. - thread->check_and_handle_async_exceptions(); - } } #ifndef PRODUCT diff --git a/src/hotspot/share/runtime/thread.hpp b/src/hotspot/share/runtime/thread.hpp index 4882d3b453d..d0c9cd65072 100644 --- a/src/hotspot/share/runtime/thread.hpp +++ b/src/hotspot/share/runtime/thread.hpp @@ -802,37 +802,21 @@ class JavaThread: public Thread { // Asynchronous exceptions support private: - enum AsyncExceptionCondition { - _no_async_condition = 0, - _async_exception, - _async_unsafe_access_error - }; - AsyncExceptionCondition _async_exception_condition; - oop _pending_async_exception; - - void set_async_exception_condition(AsyncExceptionCondition aec) { _async_exception_condition = aec; } - AsyncExceptionCondition clear_async_exception_condition() { - AsyncExceptionCondition x = _async_exception_condition; - _async_exception_condition = _no_async_condition; - return x; - } + oop _pending_async_exception; +#ifdef ASSERT + bool _is_unsafe_access_error; +#endif + inline bool clear_async_exception_condition(); public: - bool has_async_exception_condition(bool check_unsafe_access_error = true) { - return check_unsafe_access_error ? _async_exception_condition != _no_async_condition - : _async_exception_condition == _async_exception; + bool has_async_exception_condition() { + return (_suspend_flags & _has_async_exception) != 0; } inline void set_pending_async_exception(oop e); - void set_pending_unsafe_access_error() { - // Don't overwrite an asynchronous exception sent by another thread - if (_async_exception_condition == _no_async_condition) { - set_async_exception_condition(_async_unsafe_access_error); - } - } - void check_and_handle_async_exceptions(); - // Installs a pending exception to be inserted later - static void send_async_exception(oop thread_oop, oop java_throwable); + inline void set_pending_unsafe_access_error(); + static void send_async_exception(JavaThread* jt, oop java_throwable); void send_thread_stop(oop throwable); + void check_and_handle_async_exceptions(); // Safepoint support public: // Expose _thread_state for SafeFetchInt() @@ -1177,8 +1161,7 @@ class JavaThread: public Thread { // Return true if JavaThread has an asynchronous condition or // if external suspension is requested. bool has_special_runtime_exit_condition() { - return (_async_exception_condition != _no_async_condition) || - (_suspend_flags & (_obj_deopt JFR_ONLY(| _trace_flag))) != 0; + return (_suspend_flags & (_has_async_exception | _obj_deopt JFR_ONLY(| _trace_flag))) != 0; } // Fast-locking support diff --git a/src/hotspot/share/runtime/thread.inline.hpp b/src/hotspot/share/runtime/thread.inline.hpp index 63101e77855..7d27a3bf257 100644 --- a/src/hotspot/share/runtime/thread.inline.hpp +++ b/src/hotspot/share/runtime/thread.inline.hpp @@ -122,15 +122,22 @@ inline void JavaThread::clear_obj_deopt_flag() { clear_suspend_flag(_obj_deopt); } +inline bool JavaThread::clear_async_exception_condition() { + bool ret = has_async_exception_condition(); + clear_suspend_flag(_has_async_exception); + return ret; +} + inline void JavaThread::set_pending_async_exception(oop e) { _pending_async_exception = e; - set_async_exception_condition(_async_exception); - // Set _suspend_flags too so we save a comparison in the transition from native to Java - // in the native wrappers. It will be cleared in check_and_handle_async_exceptions() - // when we actually install the exception. set_suspend_flag(_has_async_exception); } +inline void JavaThread::set_pending_unsafe_access_error() { + set_suspend_flag(_has_async_exception); + DEBUG_ONLY(_is_unsafe_access_error = true); +} + inline JavaThreadState JavaThread::thread_state() const { #if defined(PPC64) || defined (AARCH64) // Use membars when accessing volatile _thread_state. See diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index 28d34525f13..370b88165b4 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -717,7 +717,6 @@ nonstatic_field(JavaThread, _current_pending_monitor_is_from_java, bool) \ volatile_nonstatic_field(JavaThread, _current_waiting_monitor, ObjectMonitor*) \ volatile_nonstatic_field(JavaThread, _suspend_flags, uint32_t) \ - nonstatic_field(JavaThread, _async_exception_condition, JavaThread::AsyncExceptionCondition) \ nonstatic_field(JavaThread, _pending_async_exception, oop) \ volatile_nonstatic_field(JavaThread, _exception_oop, oop) \ volatile_nonstatic_field(JavaThread, _exception_pc, address) \ @@ -1951,7 +1950,6 @@ declare_toplevel_type(JavaThread*) \ declare_toplevel_type(JavaThread *const *const) \ declare_toplevel_type(java_lang_Class) \ - declare_integer_type(JavaThread::AsyncExceptionCondition) \ declare_integer_type(JavaThread::TerminatedTypes) \ declare_toplevel_type(jbyte*) \ declare_toplevel_type(jbyte**) \ -- GitLab From 3f07337722a0c8c6b452a44745598268d67c0864 Mon Sep 17 00:00:00 2001 From: Zhengyu Gu Date: Mon, 11 Oct 2021 15:10:57 +0000 Subject: [PATCH 166/385] 8273614: Shenandoah: intermittent timeout with ConcurrentGCBreakpoint tests Reviewed-by: shade --- .../gc/shenandoah/shenandoahConcurrentGC.cpp | 36 ++++++++++++------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp index 6f115eaa01c..d29cc683331 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp @@ -50,24 +50,37 @@ // Breakpoint support class ShenandoahBreakpointGCScope : public StackObj { +private: + const GCCause::Cause _cause; public: - ShenandoahBreakpointGCScope() { - ShenandoahBreakpoint::at_before_gc(); + ShenandoahBreakpointGCScope(GCCause::Cause cause) : _cause(cause) { + if (cause == GCCause::_wb_breakpoint) { + ShenandoahBreakpoint::start_gc(); + ShenandoahBreakpoint::at_before_gc(); + } } ~ShenandoahBreakpointGCScope() { - ShenandoahBreakpoint::at_after_gc(); + if (_cause == GCCause::_wb_breakpoint) { + ShenandoahBreakpoint::at_after_gc(); + } } }; class ShenandoahBreakpointMarkScope : public StackObj { +private: + const GCCause::Cause _cause; public: - ShenandoahBreakpointMarkScope() { - ShenandoahBreakpoint::at_after_marking_started(); + ShenandoahBreakpointMarkScope(GCCause::Cause cause) : _cause(cause) { + if (_cause == GCCause::_wb_breakpoint) { + ShenandoahBreakpoint::at_after_marking_started(); + } } ~ShenandoahBreakpointMarkScope() { - ShenandoahBreakpoint::at_before_marking_completed(); + if (_cause == GCCause::_wb_breakpoint) { + ShenandoahBreakpoint::at_before_marking_completed(); + } } }; @@ -86,10 +99,7 @@ void ShenandoahConcurrentGC::cancel() { bool ShenandoahConcurrentGC::collect(GCCause::Cause cause) { ShenandoahHeap* const heap = ShenandoahHeap::heap(); - if (cause == GCCause::_wb_breakpoint) { - ShenandoahBreakpoint::start_gc(); - } - ShenandoahBreakpointGCScope breakpoint_gc_scope; + ShenandoahBreakpointGCScope breakpoint_gc_scope(cause); // Reset for upcoming marking entry_reset(); @@ -98,7 +108,7 @@ bool ShenandoahConcurrentGC::collect(GCCause::Cause cause) { vmop_entry_init_mark(); { - ShenandoahBreakpointMarkScope breakpoint_mark_scope; + ShenandoahBreakpointMarkScope breakpoint_mark_scope(cause); // Concurrent mark roots entry_mark_roots(); if (check_cancellation_and_abort(ShenandoahDegenPoint::_degenerated_outside_cycle)) return false; @@ -657,7 +667,9 @@ void ShenandoahConcurrentGC::op_weak_refs() { assert(heap->is_concurrent_weak_root_in_progress(), "Only during this phase"); // Concurrent weak refs processing ShenandoahGCWorkerPhase worker_phase(ShenandoahPhaseTimings::conc_weak_refs); - ShenandoahBreakpoint::at_after_reference_processing_started(); + if (heap->gc_cause() == GCCause::_wb_breakpoint) { + ShenandoahBreakpoint::at_after_reference_processing_started(); + } heap->ref_processor()->process_references(ShenandoahPhaseTimings::conc_weak_refs, heap->workers(), true /* concurrent */); } -- GitLab From 3f01d03a10cb3f647735ed4bbea1768ff18bf8f2 Mon Sep 17 00:00:00 2001 From: Lin Zang Date: Mon, 11 Oct 2021 15:27:28 +0000 Subject: [PATCH 167/385] 8275021: Test serviceability/sa/TestJmapCore.java fails with: java.io.IOException: Stack frame 0x4 not found Reviewed-by: dholmes, dcubed --- .../classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java index c8afa4c1b2d..75f27fa5d73 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java @@ -615,6 +615,8 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter { } else { out.writeByte((byte)HPROF_HEAP_DUMP); out.writeInt(0); + // We must flush all data to the file before reading the current file position. + out.flush(); // record the current position in file, it will be use for calculating the size of written data currentSegmentStart = fos.getChannel().position(); // write dummy zero for length -- GitLab From 83c37719290039672cf261701028c8eb044a2e77 Mon Sep 17 00:00:00 2001 From: Thomas Stuefe Date: Mon, 11 Oct 2021 15:48:10 +0000 Subject: [PATCH 168/385] 8273881: Metaspace: test repeated deallocations Reviewed-by: dholmes, shade --- .../gtest/metaspace/test_metaspacearena.cpp | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/test/hotspot/gtest/metaspace/test_metaspacearena.cpp b/test/hotspot/gtest/metaspace/test_metaspacearena.cpp index 68d9800829a..3b4d0863805 100644 --- a/test/hotspot/gtest/metaspace/test_metaspacearena.cpp +++ b/test/hotspot/gtest/metaspace/test_metaspacearena.cpp @@ -739,3 +739,50 @@ TEST_VM(metaspace, MetaspaceArena_growth_boot_nc_not_inplace) { word_size_for_level(CHUNK_LEVEL_4M), false); } */ + +// Test that repeated allocation-deallocation cycles with the same block size +// do not increase metaspace usage after the initial allocation (the deallocated +// block should be reused by the next allocation). +static void test_repeatedly_allocate_and_deallocate(bool is_topmost) { + if (Settings::handle_deallocations()) { + // Test various sizes, including (important) the max. possible block size = 1 root chunk + for (size_t blocksize = Metaspace::max_allocation_word_size(); blocksize >= 1; blocksize /= 2) { + size_t used1 = 0, used2 = 0, committed1 = 0, committed2 = 0; + MetaWord* p = NULL, *p2 = NULL; + + MetaspaceGtestContext context; + MetaspaceArenaTestHelper helper(context, Metaspace::StandardMetaspaceType, false); + + // First allocation + helper.allocate_from_arena_with_tests_expect_success(&p, blocksize); + if (!is_topmost) { + // another one on top, size does not matter. + helper.allocate_from_arena_with_tests_expect_success(0x10); + } + + // Measure + helper.usage_numbers_with_test(&used1, &committed1, NULL); + + // Dealloc, alloc several times with the same size. + for (int i = 0; i < 5; i ++) { + helper.deallocate_with_tests(p, blocksize); + helper.allocate_from_arena_with_tests_expect_success(&p2, blocksize); + // We should get the same pointer back. + EXPECT_EQ(p2, p); + } + + // Measure again + helper.usage_numbers_with_test(&used2, &committed2, NULL); + EXPECT_EQ(used2, used1); + EXPECT_EQ(committed1, committed2); + } + } +} + +TEST_VM(metaspace, MetaspaceArena_test_repeatedly_allocate_and_deallocate_top_allocation) { + test_repeatedly_allocate_and_deallocate(true); +} + +TEST_VM(metaspace, MetaspaceArena_test_repeatedly_allocate_and_deallocate_nontop_allocation) { + test_repeatedly_allocate_and_deallocate(false); +} -- GitLab From 75f5145e21a1320c1a08080af861497ce7c3f266 Mon Sep 17 00:00:00 2001 From: Zhengyu Gu Date: Mon, 11 Oct 2021 16:58:53 +0000 Subject: [PATCH 169/385] 8274925: Shenandoah: shenandoah/TestAllocHumongousFragment.java test failed on lock rank check Reviewed-by: shade --- src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp index 7054c673fb8..b96ef09371a 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp @@ -47,8 +47,8 @@ ShenandoahControlThread::ShenandoahControlThread() : ConcurrentGCThread(), - _alloc_failure_waiters_lock(Mutex::safepoint, "ShenandoahAllocFailureGC_lock", true), - _gc_waiters_lock(Mutex::safepoint, "ShenandoahRequestedGC_lock", true), + _alloc_failure_waiters_lock(Mutex::safepoint-1, "ShenandoahAllocFailureGC_lock", true), + _gc_waiters_lock(Mutex::safepoint-1, "ShenandoahRequestedGC_lock", true), _periodic_task(this), _requested_gc_cause(GCCause::_no_cause_specified), _degen_point(ShenandoahGC::_degenerated_outside_cycle), -- GitLab From 829dea45c9ab90518f03a66aad7e681cd4fda8b3 Mon Sep 17 00:00:00 2001 From: Andrey Turbanov Date: Mon, 11 Oct 2021 19:19:39 +0000 Subject: [PATCH 170/385] 8274945: Cleanup unnecessary calls to Throwable.initCause() in java.desktop Reviewed-by: jdv, serb, pbansal --- .../com/sun/imageio/plugins/jpeg/MarkerSegment.java | 9 +++------ .../classes/javax/imageio/metadata/IIOMetadata.java | 5 +---- .../javax/imageio/spi/ImageReaderWriterSpi.java | 11 +---------- .../sun/awt/datatransfer/TransferableProxy.java | 2 +- 4 files changed, 6 insertions(+), 21 deletions(-) diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/MarkerSegment.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/MarkerSegment.java index 6f51fee8b8a..a0b4b871a04 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/MarkerSegment.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/MarkerSegment.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -98,11 +98,8 @@ class MarkerSegment implements Cloneable { try { data = (byte []) iioNode.getUserObject(); } catch (Exception e) { - IIOInvalidTreeException newGuy = - new IIOInvalidTreeException - ("Can't get User Object", node); - newGuy.initCause(e); - throw newGuy; + throw new IIOInvalidTreeException + ("Can't get User Object", e, node); } } else { throw new IIOInvalidTreeException diff --git a/src/java.desktop/share/classes/javax/imageio/metadata/IIOMetadata.java b/src/java.desktop/share/classes/javax/imageio/metadata/IIOMetadata.java index 90b0bfd8766..9952544b487 100644 --- a/src/java.desktop/share/classes/javax/imageio/metadata/IIOMetadata.java +++ b/src/java.desktop/share/classes/javax/imageio/metadata/IIOMetadata.java @@ -407,10 +407,7 @@ public abstract class IIOMetadata { Method meth = cls.getMethod("getInstance"); return (IIOMetadataFormat) meth.invoke(null); } catch (Exception e) { - RuntimeException ex = - new IllegalStateException ("Can't obtain format"); - ex.initCause(e); - throw ex; + throw new IllegalStateException("Can't obtain format", e); } } diff --git a/src/java.desktop/share/classes/javax/imageio/spi/ImageReaderWriterSpi.java b/src/java.desktop/share/classes/javax/imageio/spi/ImageReaderWriterSpi.java index 74912019c4f..29ed6de0d50 100644 --- a/src/java.desktop/share/classes/javax/imageio/spi/ImageReaderWriterSpi.java +++ b/src/java.desktop/share/classes/javax/imageio/spi/ImageReaderWriterSpi.java @@ -25,18 +25,12 @@ package javax.imageio.spi; -import java.io.IOException; -import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.security.AccessController; import java.security.PrivilegedAction; -import java.util.Arrays; -import java.util.Iterator; -import javax.imageio.ImageReader; import javax.imageio.metadata.IIOMetadata; import javax.imageio.metadata.IIOMetadataFormat; import javax.imageio.metadata.IIOMetadataFormatImpl; -import javax.imageio.stream.ImageInputStream; /** * A superclass containing instance variables and methods common to @@ -597,10 +591,7 @@ public abstract class ImageReaderWriterSpi extends IIOServiceProvider { Method meth = cls.getMethod("getInstance"); return (IIOMetadataFormat) meth.invoke(null); } catch (Exception e) { - RuntimeException ex = - new IllegalStateException ("Can't obtain format"); - ex.initCause(e); - throw ex; + throw new IllegalStateException("Can't obtain format", e); } } diff --git a/src/java.desktop/share/classes/sun/awt/datatransfer/TransferableProxy.java b/src/java.desktop/share/classes/sun/awt/datatransfer/TransferableProxy.java index 85111e3a453..cf8660fa8fa 100644 --- a/src/java.desktop/share/classes/sun/awt/datatransfer/TransferableProxy.java +++ b/src/java.desktop/share/classes/sun/awt/datatransfer/TransferableProxy.java @@ -91,7 +91,7 @@ public class TransferableProxy implements Transferable { oos.getClassLoaderMap()); data = ois.readObject(); } catch (ClassNotFoundException cnfe) { - throw (IOException)new IOException().initCause(cnfe); + throw new IOException(cnfe); } } -- GitLab From dd93c6e27b66acebb221583fd28d03c65bfc1f24 Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Tue, 12 Oct 2021 00:14:00 +0000 Subject: [PATCH 171/385] 8272167: AbsPathsInImage.java should skip *.dSYM directories Reviewed-by: ihse, erikj --- test/jdk/build/AbsPathsInImage.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/test/jdk/build/AbsPathsInImage.java b/test/jdk/build/AbsPathsInImage.java index cbcf342784e..3fd7dda239a 100644 --- a/test/jdk/build/AbsPathsInImage.java +++ b/test/jdk/build/AbsPathsInImage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,7 +32,6 @@ import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; import java.util.List; import java.util.Properties; -import java.util.stream.Collectors; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; @@ -144,6 +143,15 @@ public class AbsPathsInImage { private void scanFiles(Path root, List searchPatterns) throws IOException { Files.walkFileTree(root, new SimpleFileVisitor<>() { + @Override + public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { + String dirName = dir.toString(); + if (dirName.endsWith(".dSYM")) { + return FileVisitResult.SKIP_SUBTREE; + } + return super.preVisitDirectory(dir, attrs); + } + @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { String fileName = file.toString(); -- GitLab From 1e3069593e6f56714e1ee557b70930c2749d820c Mon Sep 17 00:00:00 2001 From: Hamlin Li Date: Tue, 12 Oct 2021 01:25:00 +0000 Subject: [PATCH 172/385] 8274466: G1: use field directly rather than method in G1CollectorState::in_mixed_phase Reviewed-by: ayang, sjohanss --- src/hotspot/share/gc/g1/g1CollectorState.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/gc/g1/g1CollectorState.hpp b/src/hotspot/share/gc/g1/g1CollectorState.hpp index 975d0873d08..b0248b63d98 100644 --- a/src/hotspot/share/gc/g1/g1CollectorState.hpp +++ b/src/hotspot/share/gc/g1/g1CollectorState.hpp @@ -98,7 +98,7 @@ public: // Phase getters bool in_young_only_phase() const { return _in_young_only_phase && !_in_full_gc; } - bool in_mixed_phase() const { return !in_young_only_phase() && !_in_full_gc; } + bool in_mixed_phase() const { return !_in_young_only_phase && !_in_full_gc; } // Specific pauses bool in_young_gc_before_mixed() const { return _in_young_gc_before_mixed; } -- GitLab From ef0922e88528bdf4fe75537ddf4e82123e3f58b3 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Tue, 12 Oct 2021 05:56:15 +0000 Subject: [PATCH 173/385] 8274560: JFR: Add test for OldObjectSample event when using Shenandoah Reviewed-by: mgronlun --- .../oldobject/TestObjectDescription.java | 2 +- .../jfr/event/oldobject/TestShenandoah.java | 79 +++++++++++++++++++ 2 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 test/jdk/jdk/jfr/event/oldobject/TestShenandoah.java diff --git a/test/jdk/jdk/jfr/event/oldobject/TestObjectDescription.java b/test/jdk/jdk/jfr/event/oldobject/TestObjectDescription.java index 4ad7b30d91b..d62b20bc995 100644 --- a/test/jdk/jdk/jfr/event/oldobject/TestObjectDescription.java +++ b/test/jdk/jdk/jfr/event/oldobject/TestObjectDescription.java @@ -41,7 +41,7 @@ import jdk.test.lib.jfr.Events; * @test * @key jfr * @requires vm.hasJFR - * @requires vm.gc != "Z" + * @requires vm.gc != "Z" & vm.gc != "Shenandoah" * @library /test/lib /test/jdk * @modules jdk.jfr/jdk.jfr.internal.test * @run main/othervm -XX:TLABSize=2k jdk.jfr.event.oldobject.TestObjectDescription diff --git a/test/jdk/jdk/jfr/event/oldobject/TestShenandoah.java b/test/jdk/jdk/jfr/event/oldobject/TestShenandoah.java new file mode 100644 index 00000000000..6d348391030 --- /dev/null +++ b/test/jdk/jdk/jfr/event/oldobject/TestShenandoah.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 jdk.jfr.event.oldobject; + +import java.util.ArrayList; +import java.util.List; + +import jdk.jfr.Recording; +import jdk.jfr.consumer.RecordedEvent; +import jdk.jfr.internal.test.WhiteBox; +import jdk.test.lib.jfr.EventNames; +import jdk.test.lib.jfr.Events; + +/** + * @test + * @key jfr + * @requires vm.hasJFR & vm.gc.Shenandoah + * @summary Test leak profiler with Shenandoah + * @library /test/lib /test/jdk + * @modules jdk.jfr/jdk.jfr.internal.test + * @run main/othervm -XX:TLABSize=2k -XX:+UseShenandoahGC jdk.jfr.event.oldobject.TestShenandoah + */ +public class TestShenandoah { + + static private class FindMe { + } + + public static List list = new ArrayList<>(OldObjects.MIN_SIZE); + + public static void main(String[] args) throws Exception { + WhiteBox.setWriteAllObjectSamples(true); + + while (true) { + try (Recording r = new Recording()) { + r.enable(EventNames.OldObjectSample).withStackTrace().with("cutoff", "infinity"); + r.start(); + allocateFindMe(); + System.gc(); + r.stop(); + List events = Events.fromRecording(r); + System.out.println(events); + if (OldObjects.countMatchingEvents(events, FindMe[].class, null, null, -1, "allocateFindMe") > 0) { + return; + } + System.out.println("Could not find leaking object, retrying..."); + } + list.clear(); + } + } + + public static void allocateFindMe() { + for (int i = 0; i < OldObjects.MIN_SIZE; i++) { + // Allocate array to trigger sampling code path for interpreter / c1 + list.add(new FindMe[0]); + } + } + +} -- GitLab From a5f09d1088d9dd610139370739e9fbd6e34416cb Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Tue, 12 Oct 2021 06:22:13 +0000 Subject: [PATCH 174/385] 8275031: runtime/ErrorHandling/MachCodeFramesInErrorFile.java fails when hsdis is present Reviewed-by: dholmes, dnsimon --- src/hotspot/share/code/nmethod.cpp | 3 +++ .../runtime/ErrorHandling/MachCodeFramesInErrorFile.java | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 239b0d611e2..f695f242231 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -2892,7 +2892,10 @@ void nmethod::decode2(outputStream* ost) const { //---< Print real disassembly >--- //---------------------------------- if (! use_compressed_format) { + st->print_cr("[Disassembly]"); Disassembler::decode(const_cast(this), st); + st->bol(); + st->print_cr("[/Disassembly]"); return; } #endif diff --git a/test/hotspot/jtreg/runtime/ErrorHandling/MachCodeFramesInErrorFile.java b/test/hotspot/jtreg/runtime/ErrorHandling/MachCodeFramesInErrorFile.java index 201cc177f54..4e56fdee93f 100644 --- a/test/hotspot/jtreg/runtime/ErrorHandling/MachCodeFramesInErrorFile.java +++ b/test/hotspot/jtreg/runtime/ErrorHandling/MachCodeFramesInErrorFile.java @@ -110,6 +110,12 @@ public class MachCodeFramesInErrorFile { List nativeFrames = extractNativeFrames(hsErr); int compiledJavaFrames = (int) nativeFrames.stream().filter(f -> f.startsWith("J ")).count(); + Matcher matcherDisasm = Pattern.compile("\\[Disassembly\\].*\\[/Disassembly\\]", Pattern.DOTALL).matcher(hsErr); + if (matcherDisasm.find()) { + // Real disassembly is present, no MachCode is expected. + return; + } + Matcher matcher = Pattern.compile("\\[MachCode\\]\\s*\\[Verified Entry Point\\]\\s* # \\{method\\} \\{[^}]*\\} '([^']+)' '([^']+)' in '([^']+)'", Pattern.DOTALL).matcher(hsErr); List machCodeHeaders = matcher.results().map(mr -> String.format("'%s' '%s' in '%s'", mr.group(1), mr.group(2), mr.group(3))).collect(Collectors.toList()); String message = "Mach code headers: " + machCodeHeaders + -- GitLab From cfe7471f1769eca2a4e623f5ba9cddceb005f0bf Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Tue, 12 Oct 2021 07:24:15 +0000 Subject: [PATCH 175/385] 8177814: jdk/editpad is not in jdk TEST.groups Reviewed-by: serb --- test/jdk/TEST.groups | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/jdk/TEST.groups b/test/jdk/TEST.groups index 58e7ac3f836..37dafa2e73a 100644 --- a/test/jdk/TEST.groups +++ b/test/jdk/TEST.groups @@ -382,6 +382,9 @@ jdk_accessibility = \ jfc_demo = \ demo/jfc +jdk_editpad = \ + jdk/editpad + jdk_desktop = \ :jdk_awt \ :jdk_2d \ @@ -391,7 +394,8 @@ jdk_desktop = \ :jdk_imageio \ :jdk_accessibility \ :jfc_demo \ - :jdk_client_sanity + :jdk_client_sanity \ + :jdk_editpad # SwingSet3 tests. jdk_client_sanity = \ -- GitLab From 7d2633f795c27edc2dfbbd7a9d9e44bdb23ec6a1 Mon Sep 17 00:00:00 2001 From: Andrey Turbanov Date: Tue, 12 Oct 2021 09:37:54 +0000 Subject: [PATCH 176/385] 8275002: Remove unused AbstractStringBuilder.MAX_ARRAY_SIZE Reviewed-by: prappo, jlaskey, martin --- .../classes/java/lang/AbstractStringBuilder.java | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/java.base/share/classes/java/lang/AbstractStringBuilder.java b/src/java.base/share/classes/java/lang/AbstractStringBuilder.java index 66c6c57d2d5..fce54fcb3d1 100644 --- a/src/java.base/share/classes/java/lang/AbstractStringBuilder.java +++ b/src/java.base/share/classes/java/lang/AbstractStringBuilder.java @@ -231,21 +231,13 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { } } - /** - * The maximum size of array to allocate (unless necessary). - * Some VMs reserve some header words in an array. - * Attempts to allocate larger arrays may result in - * OutOfMemoryError: Requested array size exceeds VM limit - */ - private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; - /** * Returns a capacity at least as large as the given minimum capacity. * Returns the current capacity increased by the current length + 2 if * that suffices. * Will not return a capacity greater than - * {@code (MAX_ARRAY_SIZE >> coder)} unless the given minimum capacity - * is greater than that. + * {@code (SOFT_MAX_ARRAY_LENGTH >> coder)} + * unless the given minimum capacity is greater than that. * * @param minCapacity the desired minimum capacity * @throws OutOfMemoryError if minCapacity is less than zero or -- GitLab From 8de26361f7d789c7b317536198c891756038a8ea Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Tue, 12 Oct 2021 09:40:35 +0000 Subject: [PATCH 177/385] 8274615: Support relaxed atomic add for linux-aarch64 Reviewed-by: aph, dholmes --- src/hotspot/cpu/aarch64/atomic_aarch64.hpp | 2 ++ .../cpu/aarch64/stubGenerator_aarch64.cpp | 29 +++++++++++++++---- .../linux_aarch64/atomic_linux_aarch64.S | 22 ++++++++++++++ .../linux_aarch64/atomic_linux_aarch64.hpp | 24 ++++++++++----- 4 files changed, 64 insertions(+), 13 deletions(-) diff --git a/src/hotspot/cpu/aarch64/atomic_aarch64.hpp b/src/hotspot/cpu/aarch64/atomic_aarch64.hpp index 6f9425e43ac..f1e1f04c244 100644 --- a/src/hotspot/cpu/aarch64/atomic_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/atomic_aarch64.hpp @@ -37,6 +37,8 @@ typedef uint64_t (*aarch64_atomic_stub_t)(volatile void *ptr, uint64_t arg1, uin // Pointers to stubs extern aarch64_atomic_stub_t aarch64_atomic_fetch_add_4_impl; extern aarch64_atomic_stub_t aarch64_atomic_fetch_add_8_impl; +extern aarch64_atomic_stub_t aarch64_atomic_fetch_add_4_relaxed_impl; +extern aarch64_atomic_stub_t aarch64_atomic_fetch_add_8_relaxed_impl; extern aarch64_atomic_stub_t aarch64_atomic_xchg_4_impl; extern aarch64_atomic_stub_t aarch64_atomic_xchg_8_impl; extern aarch64_atomic_stub_t aarch64_atomic_cmpxchg_1_impl; diff --git a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp index fca580a1d2a..0388bb73b91 100644 --- a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp @@ -6209,10 +6209,16 @@ class StubGenerator: public StubCodeGenerator { __ ret(lr); } - void gen_ldaddal_entry(Assembler::operand_size size) { + void gen_ldadd_entry(Assembler::operand_size size, atomic_memory_order order) { Register prev = r2, addr = c_rarg0, incr = c_rarg1; - __ ldaddal(size, incr, prev, addr); - __ membar(Assembler::StoreStore|Assembler::StoreLoad); + // If not relaxed, then default to conservative. Relaxed is the only + // case we use enough to be worth specializing. + if (order == memory_order_relaxed) { + __ ldadd(size, incr, prev, addr); + } else { + __ ldaddal(size, incr, prev, addr); + __ membar(Assembler::StoreStore|Assembler::StoreLoad); + } if (size == Assembler::xword) { __ mov(r0, prev); } else { @@ -6242,12 +6248,21 @@ class StubGenerator: public StubCodeGenerator { StubCodeMark mark(this, "StubRoutines", "atomic entry points"); address first_entry = __ pc(); - // All memory_order_conservative + // ADD, memory_order_conservative AtomicStubMark mark_fetch_add_4(_masm, &aarch64_atomic_fetch_add_4_impl); - gen_ldaddal_entry(Assembler::word); + gen_ldadd_entry(Assembler::word, memory_order_conservative); AtomicStubMark mark_fetch_add_8(_masm, &aarch64_atomic_fetch_add_8_impl); - gen_ldaddal_entry(Assembler::xword); + gen_ldadd_entry(Assembler::xword, memory_order_conservative); + + // ADD, memory_order_relaxed + AtomicStubMark mark_fetch_add_4_relaxed + (_masm, &aarch64_atomic_fetch_add_4_relaxed_impl); + gen_ldadd_entry(MacroAssembler::word, memory_order_relaxed); + AtomicStubMark mark_fetch_add_8_relaxed + (_masm, &aarch64_atomic_fetch_add_8_relaxed_impl); + gen_ldadd_entry(MacroAssembler::xword, memory_order_relaxed); + // XCHG, memory_order_conservative AtomicStubMark mark_xchg_4(_masm, &aarch64_atomic_xchg_4_impl); gen_swpal_entry(Assembler::word); AtomicStubMark mark_xchg_8_impl(_masm, &aarch64_atomic_xchg_8_impl); @@ -7447,6 +7462,8 @@ void StubGenerator_generate(CodeBuffer* code, bool all) { DEFAULT_ATOMIC_OP(fetch_add, 4, ) DEFAULT_ATOMIC_OP(fetch_add, 8, ) +DEFAULT_ATOMIC_OP(fetch_add, 4, _relaxed) +DEFAULT_ATOMIC_OP(fetch_add, 8, _relaxed) DEFAULT_ATOMIC_OP(xchg, 4, ) DEFAULT_ATOMIC_OP(xchg, 8, ) DEFAULT_ATOMIC_OP(cmpxchg, 1, ) diff --git a/src/hotspot/os_cpu/linux_aarch64/atomic_linux_aarch64.S b/src/hotspot/os_cpu/linux_aarch64/atomic_linux_aarch64.S index 3007587d9c2..9c91942cb33 100644 --- a/src/hotspot/os_cpu/linux_aarch64/atomic_linux_aarch64.S +++ b/src/hotspot/os_cpu/linux_aarch64/atomic_linux_aarch64.S @@ -47,6 +47,28 @@ aarch64_atomic_fetch_add_4_default_impl: mov w0, w2 ret + .global aarch64_atomic_fetch_add_8_relaxed_default_impl + .align 5 +aarch64_atomic_fetch_add_8_relaxed_default_impl: + prfm pstl1strm, [x0] +0: ldxr x2, [x0] + add x8, x2, x1 + stxr w9, x8, [x0] + cbnz w9, 0b + mov x0, x2 + ret + + .global aarch64_atomic_fetch_add_4_relaxed_default_impl + .align 5 +aarch64_atomic_fetch_add_4_relaxed_default_impl: + prfm pstl1strm, [x0] +0: ldxr w2, [x0] + add w8, w2, w1 + stxr w9, w8, [x0] + cbnz w9, 0b + mov w0, w2 + ret + .globl aarch64_atomic_xchg_4_default_impl .align 5 aarch64_atomic_xchg_4_default_impl: diff --git a/src/hotspot/os_cpu/linux_aarch64/atomic_linux_aarch64.hpp b/src/hotspot/os_cpu/linux_aarch64/atomic_linux_aarch64.hpp index 316e877ec1f..3208db5b4a6 100644 --- a/src/hotspot/os_cpu/linux_aarch64/atomic_linux_aarch64.hpp +++ b/src/hotspot/os_cpu/linux_aarch64/atomic_linux_aarch64.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2021, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -87,9 +87,14 @@ inline D Atomic::PlatformAdd<4>::fetch_and_add(D volatile* dest, I add_value, atomic_memory_order order) const { STATIC_ASSERT(4 == sizeof(I)); STATIC_ASSERT(4 == sizeof(D)); - D old_value - = atomic_fastcall(aarch64_atomic_fetch_add_4_impl, dest, add_value); - return old_value; + aarch64_atomic_stub_t stub; + switch (order) { + case memory_order_relaxed: + stub = aarch64_atomic_fetch_add_4_relaxed_impl; break; + default: + stub = aarch64_atomic_fetch_add_4_impl; break; + } + return atomic_fastcall(stub, dest, add_value); } template<> @@ -98,9 +103,14 @@ inline D Atomic::PlatformAdd<8>::fetch_and_add(D volatile* dest, I add_value, atomic_memory_order order) const { STATIC_ASSERT(8 == sizeof(I)); STATIC_ASSERT(8 == sizeof(D)); - D old_value - = atomic_fastcall(aarch64_atomic_fetch_add_8_impl, dest, add_value); - return old_value; + aarch64_atomic_stub_t stub; + switch (order) { + case memory_order_relaxed: + stub = aarch64_atomic_fetch_add_8_relaxed_impl; break; + default: + stub = aarch64_atomic_fetch_add_8_impl; break; + } + return atomic_fastcall(stub, dest, add_value); } template<> -- GitLab From 33050f8013366f5e3a01ab1a75ba3fee9cc73089 Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Tue, 12 Oct 2021 09:49:50 +0000 Subject: [PATCH 178/385] 8274986: max code printed in hs-err logs should be configurable Reviewed-by: never, dholmes --- src/hotspot/share/code/codeBlob.cpp | 7 +- .../share/runtime/flags/jvmFlagLimit.cpp | 1 + src/hotspot/share/runtime/globals.hpp | 4 + src/hotspot/share/utilities/vmError.cpp | 58 ++++--- src/hotspot/share/utilities/vmError.hpp | 3 + .../MachCodeFramesInErrorFile.java | 155 +++++++++--------- 6 files changed, 133 insertions(+), 95 deletions(-) diff --git a/src/hotspot/share/code/codeBlob.cpp b/src/hotspot/share/code/codeBlob.cpp index 05f56ff0e4a..a1fcea77e48 100644 --- a/src/hotspot/share/code/codeBlob.cpp +++ b/src/hotspot/share/code/codeBlob.cpp @@ -653,7 +653,12 @@ void CodeBlob::dump_for_addr(address addr, outputStream* st, bool verbose) const nm->method()->print_value_on(st); } st->cr(); - nm->print_nmethod(verbose); + if (verbose && st == tty) { + // verbose is only ever true when called from findpc in debug.cpp + nm->print_nmethod(true); + } else { + nm->print(st); + } return; } st->print_cr(INTPTR_FORMAT " is at code_begin+%d in ", p2i(addr), (int)(addr - code_begin())); diff --git a/src/hotspot/share/runtime/flags/jvmFlagLimit.cpp b/src/hotspot/share/runtime/flags/jvmFlagLimit.cpp index 5b81444eb84..bcc1565e165 100644 --- a/src/hotspot/share/runtime/flags/jvmFlagLimit.cpp +++ b/src/hotspot/share/runtime/flags/jvmFlagLimit.cpp @@ -34,6 +34,7 @@ #include "gc/shared/referenceProcessor.hpp" #include "oops/markWord.hpp" #include "runtime/task.hpp" +#include "utilities/vmError.hpp" //---------------------------------------------------------------------- // Build flagLimitTable[] diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp index d98d0ad5226..299613611c0 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -1336,6 +1336,10 @@ const intx ObjectAlignmentInBytes = 8; develop(intx, StackPrintLimit, 100, \ "number of stack frames to print in VM-level stack dump") \ \ + product(int, ErrorLogPrintCodeLimit, 3, DIAGNOSTIC, \ + "max number of compiled code units to print in error log") \ + range(0, VMError::max_error_log_print_code) \ + \ notproduct(intx, MaxElementPrintSize, 256, \ "maximum number of elements to print") \ \ diff --git a/src/hotspot/share/utilities/vmError.cpp b/src/hotspot/share/utilities/vmError.cpp index 29755fec2da..d6152164dbb 100644 --- a/src/hotspot/share/utilities/vmError.cpp +++ b/src/hotspot/share/utilities/vmError.cpp @@ -245,7 +245,8 @@ void VMError::print_stack_trace(outputStream* st, JavaThread* jt, /** * Adds `value` to `list` iff it's not already present and there is sufficient * capacity (i.e. length(list) < `list_capacity`). The length of the list - * is the index of the first nullptr entry. + * is the index of the first nullptr entry or `list_capacity` if there are + * no nullptr entries. * * @ return true if the value was added, false otherwise */ @@ -910,25 +911,44 @@ void VMError::report(outputStream* st, bool _verbose) { STEP("printing code blobs if possible") if (_verbose && _context) { - if (!_print_native_stack_used) { - // Only try print code of the crashing frame since - // we cannot walk the native stack using next_frame. - const int printed_capacity = 1; - address printed_singleton = nullptr; - address* printed = &printed_singleton; - print_code(st, _thread, _pc, true, printed, 1); - } else { - // Print up to the first 5 unique code units on the stack - const int printed_capacity = 5; - address printed[printed_capacity]; - printed[0] = nullptr; // length(list) == index of first nullptr - - frame fr = os::fetch_frame_from_context(_context); - for (int count = 0; count < printed_capacity && fr.pc() != nullptr; ) { - if (print_code(st, _thread, fr.pc(), fr.pc() == _pc, printed, printed_capacity)) { - count++; + const int printed_capacity = max_error_log_print_code; + address printed[printed_capacity]; + printed[0] = nullptr; + int printed_len = 0; + // Even though ErrorLogPrintCodeLimit is ranged checked + // during argument parsing, there's no way to prevent it + // subsequently (i.e., after parsing) being set to a + // value outside the range. + int limit = MIN2(ErrorLogPrintCodeLimit, printed_capacity); + if (limit > 0) { + // Scan the native stack + if (!_print_native_stack_used) { + // Only try to print code of the crashing frame since + // the native stack cannot be walked with next_frame. + if (print_code(st, _thread, _pc, true, printed, printed_capacity)) { + printed_len++; + } + } else { + frame fr = os::fetch_frame_from_context(_context); + while (printed_len < limit && fr.pc() != nullptr) { + if (print_code(st, _thread, fr.pc(), fr.pc() == _pc, printed, printed_capacity)) { + printed_len++; + } + fr = next_frame(fr, _thread); + } + } + + // Scan the Java stack + if (_thread != nullptr && _thread->is_Java_thread()) { + JavaThread* jt = JavaThread::cast(_thread); + if (jt->has_last_Java_frame()) { + for (StackFrameStream sfs(jt, true /* update */, true /* process_frames */); printed_len < limit && !sfs.is_done(); sfs.next()) { + address pc = sfs.current()->pc(); + if (print_code(st, _thread, pc, pc == _pc, printed, printed_capacity)) { + printed_len++; + } + } } - fr = next_frame(fr, _thread); } } } diff --git a/src/hotspot/share/utilities/vmError.hpp b/src/hotspot/share/utilities/vmError.hpp index 6a18ff9375d..736e354677c 100644 --- a/src/hotspot/share/utilities/vmError.hpp +++ b/src/hotspot/share/utilities/vmError.hpp @@ -185,6 +185,9 @@ public: // which is not NULL and contains bits in every word. static const intptr_t segfault_address = LP64_ONLY(0xABC0000000000ABCULL) NOT_LP64(0x00000ABC); + // Max value for the ErrorLogPrintCodeLimit flag. + static const int max_error_log_print_code = 10; + // Needed when printing signal handlers. NOT_WINDOWS(static const void* crash_handler_address;) diff --git a/test/hotspot/jtreg/runtime/ErrorHandling/MachCodeFramesInErrorFile.java b/test/hotspot/jtreg/runtime/ErrorHandling/MachCodeFramesInErrorFile.java index 4e56fdee93f..0095c835d2d 100644 --- a/test/hotspot/jtreg/runtime/ErrorHandling/MachCodeFramesInErrorFile.java +++ b/test/hotspot/jtreg/runtime/ErrorHandling/MachCodeFramesInErrorFile.java @@ -34,13 +34,17 @@ * @run driver MachCodeFramesInErrorFile */ +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.List; import java.util.ArrayList; -import java.util.stream.Stream; +import java.util.HashSet; +import java.util.List; +import java.util.Set; import java.util.stream.Collectors; +import java.util.stream.Stream; import java.util.regex.Pattern; import java.util.regex.Matcher; @@ -51,45 +55,73 @@ import jdk.test.lib.Asserts; import jdk.internal.misc.Unsafe; public class MachCodeFramesInErrorFile { + private static class Crasher { - // Need to make unsafe a compile-time constant so that - // C2 intrinsifies the call to Unsafe.getLong in method3. + // Make Crasher.unsafe a compile-time constant so that + // C2 intrinsifies calls to Unsafe intrinsics. private static final Unsafe unsafe = Unsafe.getUnsafe(); - public static void main(String[] args) { - method1(10); + + public static void main(String[] args) throws Exception { + if (args[0].equals("crashInJava")) { + // This test relies on Unsafe.putLong(Object, long, long) being intrinsified + if (!Stream.of(Unsafe.class.getDeclaredMethod("putLong", Object.class, long.class, long.class).getAnnotations()). + anyMatch(a -> a.annotationType().getName().equals("jdk.internal.vm.annotation.IntrinsicCandidate"))) { + throw new RuntimeException("Unsafe.putLong(Object, long, long) is not an intrinsic"); + } + crashInJava1(10); + } else { + assert args[0].equals("crashInVM"); + crashInNative1(10); + } } - static void method1(long address) { - System.out.println("in method1"); - method2(address); + static void crashInJava1(long address) { + System.out.println("in crashInJava1"); + crashInJava2(address); } - static void method2(long address) { - System.out.println("in method2"); - method3(address); + static void crashInJava2(long address) { + System.out.println("in crashInJava2"); + crashInJava3(address); } - static void method3(long address) { - System.out.println("in method3"); - // Keep chasing pointers until we crash - while (true) { - address = unsafe.getLong(address); - } + static void crashInJava3(long address) { + unsafe.putLong(null, address, 42); + System.out.println("wrote value to 0x" + Long.toHexString(address)); + } + + static void crashInNative1(long address) { + System.out.println("in crashInNative1"); + crashInNative2(address); + } + static void crashInNative2(long address) { + System.out.println("in crashInNative2"); + crashInNative3(address); } + static void crashInNative3(long address) { + System.out.println("read value " + unsafe.getLong(address) + " from 0x" + Long.toHexString(address)); + } + } + + public static void main(String[] args) throws Exception { + run(true); + run(false); } /** - * Runs Crasher and tries to force compile the methods in Crasher. The inner + * Runs Crasher in Xcomp mode. The inner * most method crashes the VM with Unsafe. The resulting hs-err log is * expected to have a min number of MachCode sections. */ - public static void main(String[] args) throws Exception { + private static void run(boolean crashInJava) throws Exception { ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( "-Xmx64m", "--add-exports=java.base/jdk.internal.misc=ALL-UNNAMED", "-XX:-CreateCoredumpOnCrash", "-Xcomp", - "-XX:-TieredCompilation", // ensure C2 compiles Crasher.method3 - "-XX:CompileCommand=compileonly,MachCodeFramesInErrorFile$Crasher.m*", - "-XX:CompileCommand=dontinline,MachCodeFramesInErrorFile$Crasher.m*", - Crasher.class.getName()); + "-XX:-TieredCompilation", + "-XX:CompileCommand=compileonly,MachCodeFramesInErrorFile$Crasher.crashIn*", + "-XX:CompileCommand=dontinline,MachCodeFramesInErrorFile$Crasher.crashIn*", + "-XX:CompileCommand=dontinline,*/Unsafe.getLong", // ensures VM call when crashInJava == false + Crasher.class.getName(), + crashInJava ? "crashInJava" : "crashInVM"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); // Extract hs_err_pid file. @@ -104,11 +136,17 @@ public class MachCodeFramesInErrorFile { throw new RuntimeException("hs_err_pid file missing at " + hsErrPath + ".\n"); } String hsErr = Files.readString(hsErrPath); - if (!crashedInCrasherMethod(hsErr)) { - return; + if (System.getenv("DEBUG") != null) { + System.err.println(hsErr); + } + Set frames = new HashSet<>(); + extractFrames(hsErr, frames, true); + if (!crashInJava) { + // A crash in native will have Java frames in the hs-err log + // as there is a Java frame anchor on the stack. + extractFrames(hsErr, frames, false); } - List nativeFrames = extractNativeFrames(hsErr); - int compiledJavaFrames = (int) nativeFrames.stream().filter(f -> f.startsWith("J ")).count(); + int compiledJavaFrames = (int) frames.stream().filter(f -> f.startsWith("J ")).count(); Matcher matcherDisasm = Pattern.compile("\\[Disassembly\\].*\\[/Disassembly\\]", Pattern.DOTALL).matcher(hsErr); if (matcherDisasm.find()) { @@ -118,63 +156,30 @@ public class MachCodeFramesInErrorFile { Matcher matcher = Pattern.compile("\\[MachCode\\]\\s*\\[Verified Entry Point\\]\\s* # \\{method\\} \\{[^}]*\\} '([^']+)' '([^']+)' in '([^']+)'", Pattern.DOTALL).matcher(hsErr); List machCodeHeaders = matcher.results().map(mr -> String.format("'%s' '%s' in '%s'", mr.group(1), mr.group(2), mr.group(3))).collect(Collectors.toList()); - String message = "Mach code headers: " + machCodeHeaders + - "\n\nExtracted MachCode:\n" + extractMachCode(hsErr) + - "\n\nExtracted native frames:\n" + String.join("\n", nativeFrames); int minExpectedMachCodeSections = Math.max(1, compiledJavaFrames); - Asserts.assertTrue(machCodeHeaders.size() >= minExpectedMachCodeSections, message); - } - - /** - * Checks whether the crashing frame is in {@code Crasher.method3}. - */ - private static boolean crashedInCrasherMethod(String hsErr) { - boolean checkProblematicFrame = false; - for (String line : hsErr.split(System.lineSeparator())) { - if (line.startsWith("# Problematic frame:")) { - checkProblematicFrame = true; - } else if (checkProblematicFrame) { - String crasherMethod = Crasher.class.getSimpleName() + ".method3"; - if (!line.contains(crasherMethod)) { - // There's any number of things that can subvert the attempt - // to crash in the expected method. - System.out.println("Crashed in method other than " + crasherMethod + "\n\n" + line + "\n\nSkipping rest of test."); - return false; - } - return true; - } + if (machCodeHeaders.size() < minExpectedMachCodeSections) { + Asserts.fail(machCodeHeaders.size() + " < " + minExpectedMachCodeSections); } - throw new RuntimeException("\"# Problematic frame:\" line missing in hs_err_pid file:\n" + hsErr); } /** - * Gets the lines in {@code hsErr} below the line starting with "Native frames:" up to the next blank line. + * Extracts the lines in {@code hsErr} below the line starting with + * "Native frames:" or "Java frames:" up to the next blank line + * and adds them to {@code frames}. */ - private static List extractNativeFrames(String hsErr) { - List res = new ArrayList<>(); - boolean inNativeFrames = false; + private static void extractFrames(String hsErr, Set frames, boolean nativeStack) { + String marker = (nativeStack ? "Native" : "Java") + " frames: "; + boolean seenMarker = false; for (String line : hsErr.split(System.lineSeparator())) { - if (line.startsWith("Native frames: ")) { - inNativeFrames = true; - } else if (inNativeFrames) { + if (line.startsWith(marker)) { + seenMarker = true; + } else if (seenMarker) { if (line.trim().isEmpty()) { - return res; + return; } - res.add(line); - } - } - throw new RuntimeException("\"Native frames:\" line missing in hs_err_pid file:\n" + hsErr); - } - - private static String extractMachCode(String hsErr) { - int start = hsErr.indexOf("[MachCode]"); - if (start != -1) { - int end = hsErr.lastIndexOf("[/MachCode]"); - if (end != -1) { - return hsErr.substring(start, end + "[/MachCode]".length()); + frames.add(line); } - return hsErr.substring(start); } - return null; + throw new RuntimeException("\"" + marker + "\" line missing in hs_err_pid file:\n" + hsErr); } } -- GitLab From d04d4ee2c193baf4339ee3025e3fbcd31d62f484 Mon Sep 17 00:00:00 2001 From: Andrey Turbanov Date: Tue, 12 Oct 2021 11:14:31 +0000 Subject: [PATCH 179/385] 8274894: Use Optional.empty() instead of ofNullable(null) in HttpResponse.BodySubscribers.discarding Reviewed-by: dfuchs --- .../share/classes/java/net/http/HttpResponse.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/java.net.http/share/classes/java/net/http/HttpResponse.java b/src/java.net.http/share/classes/java/net/http/HttpResponse.java index 57cf75882a8..a8af2070013 100644 --- a/src/java.net.http/share/classes/java/net/http/HttpResponse.java +++ b/src/java.net.http/share/classes/java/net/http/HttpResponse.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1273,7 +1273,7 @@ public interface HttpResponse { * @return a response body subscriber */ public static BodySubscriber discarding() { - return new ResponseSubscribers.NullSubscriber<>(Optional.ofNullable(null)); + return new ResponseSubscribers.NullSubscriber<>(Optional.empty()); } /** -- GitLab From b460d6ddafcd1be76bcf407254f843df6bbfb70b Mon Sep 17 00:00:00 2001 From: kabutz Date: Tue, 12 Oct 2021 11:38:21 +0000 Subject: [PATCH 180/385] 8275091: /src/jdk.management.jfr/share/classes/module-info.java has non-canonical order Reviewed-by: mgronlun --- src/jdk.management.jfr/share/classes/module-info.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jdk.management.jfr/share/classes/module-info.java b/src/jdk.management.jfr/share/classes/module-info.java index 6264ecac751..341d29d9cfe 100644 --- a/src/jdk.management.jfr/share/classes/module-info.java +++ b/src/jdk.management.jfr/share/classes/module-info.java @@ -30,10 +30,10 @@ * @since 9 */ module jdk.management.jfr { - requires transitive jdk.jfr; requires jdk.management; requires transitive java.management; + requires transitive jdk.jfr; exports jdk.management.jfr; -- GitLab From 1ab64143c06e33e23172dd77c39e434443347364 Mon Sep 17 00:00:00 2001 From: Zhengyu Gu Date: Tue, 12 Oct 2021 11:58:35 +0000 Subject: [PATCH 181/385] 8275051: Shenandoah: Correct ordering of requested gc cause and gc request flag Reviewed-by: shade --- .../gc/shenandoah/shenandoahControlThread.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp index b96ef09371a..9f5273a9750 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp @@ -97,8 +97,10 @@ void ShenandoahControlThread::run_service() { while (!in_graceful_shutdown() && !should_terminate()) { // Figure out if we have pending requests. bool alloc_failure_pending = _alloc_failure_gc.is_set(); - bool explicit_gc_requested = _gc_requested.is_set() && is_explicit_gc(_requested_gc_cause); - bool implicit_gc_requested = _gc_requested.is_set() && !is_explicit_gc(_requested_gc_cause); + bool is_gc_requested = _gc_requested.is_set(); + GCCause::Cause requested_gc_cause = _requested_gc_cause; + bool explicit_gc_requested = is_gc_requested && is_explicit_gc(requested_gc_cause); + bool implicit_gc_requested = is_gc_requested && !is_explicit_gc(requested_gc_cause); // This control loop iteration have seen this much allocations. size_t allocs_seen = Atomic::xchg(&_allocs_seen, (size_t)0, memory_order_relaxed); @@ -132,7 +134,7 @@ void ShenandoahControlThread::run_service() { } } else if (explicit_gc_requested) { - cause = _requested_gc_cause; + cause = requested_gc_cause; log_info(gc)("Trigger: Explicit GC request (%s)", GCCause::to_string(cause)); heuristics->record_requested_gc(); @@ -147,7 +149,7 @@ void ShenandoahControlThread::run_service() { mode = stw_full; } } else if (implicit_gc_requested) { - cause = _requested_gc_cause; + cause = requested_gc_cause; log_info(gc)("Trigger: Implicit GC request (%s)", GCCause::to_string(cause)); heuristics->record_requested_gc(); @@ -505,8 +507,11 @@ void ShenandoahControlThread::handle_requested_gc(GCCause::Cause cause) { size_t current_gc_id = get_gc_id(); size_t required_gc_id = current_gc_id + 1; while (current_gc_id < required_gc_id) { - _gc_requested.set(); + // Although setting gc request is under _gc_waiters_lock, but read side (run_service()) + // does not take the lock. We need to enforce following order, so that read side sees + // latest requested gc cause when the flag is set. _requested_gc_cause = cause; + _gc_requested.set(); if (cause != GCCause::_wb_breakpoint) { ml.wait(); -- GitLab From e16b93ad52c96fddd9097c2cb0fa78ae781c547b Mon Sep 17 00:00:00 2001 From: Martin Doerr Date: Tue, 12 Oct 2021 12:18:49 +0000 Subject: [PATCH 182/385] 8274770: [PPC64] resolve_jobject needs a generic implementation to support load barriers Reviewed-by: goetz, nradomski --- .../ppc/gc/shared/barrierSetAssembler_ppc.cpp | 18 +++++++++++++++--- .../shared/modRefBarrierSetAssembler_ppc.cpp | 15 +++++++++++++++ .../shared/modRefBarrierSetAssembler_ppc.hpp | 4 ++++ 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.cpp b/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.cpp index f60d1811823..3758cc2fcf7 100644 --- a/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.cpp @@ -111,16 +111,28 @@ void BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, } } +// Generic implementation. GCs can provide an optimized one. void BarrierSetAssembler::resolve_jobject(MacroAssembler* masm, Register value, Register tmp1, Register tmp2, MacroAssembler::PreservationLevel preservation_level) { - Label done; + Label done, not_weak, verify; __ cmpdi(CCR0, value, 0); __ beq(CCR0, done); // Use NULL as-is. - __ clrrdi(tmp1, value, JNIHandles::weak_tag_size); - __ ld(value, 0, tmp1); // Resolve (untagged) jobject. + __ andi_(tmp1, value, JNIHandles::weak_tag_mask); + __ beq(CCR0, not_weak); // Test for jweak tag. + // Resolve (untagged) jobject. + __ clrrdi(value, value, JNIHandles::weak_tag_size); + load_at(masm, IN_NATIVE | ON_PHANTOM_OOP_REF, T_OBJECT, + value, (intptr_t)0, value, tmp1, tmp2, preservation_level); + __ b(verify); + + __ bind(not_weak); + load_at(masm, IN_NATIVE, T_OBJECT, + value, (intptr_t)0, value, tmp1, tmp2, preservation_level); + + __ bind(verify); __ verify_oop(value, FILE_AND_LINE); __ bind(done); } diff --git a/src/hotspot/cpu/ppc/gc/shared/modRefBarrierSetAssembler_ppc.cpp b/src/hotspot/cpu/ppc/gc/shared/modRefBarrierSetAssembler_ppc.cpp index ed66c5f8929..1d1f923108f 100644 --- a/src/hotspot/cpu/ppc/gc/shared/modRefBarrierSetAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/gc/shared/modRefBarrierSetAssembler_ppc.cpp @@ -26,6 +26,7 @@ #include "precompiled.hpp" #include "asm/macroAssembler.inline.hpp" #include "gc/shared/modRefBarrierSetAssembler.hpp" +#include "runtime/jniHandles.hpp" #define __ masm-> @@ -74,3 +75,17 @@ void ModRefBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet deco preservation_level); } } + +void ModRefBarrierSetAssembler::resolve_jobject(MacroAssembler* masm, Register value, + Register tmp1, Register tmp2, + MacroAssembler::PreservationLevel preservation_level) { + Label done; + __ cmpdi(CCR0, value, 0); + __ beq(CCR0, done); // Use NULL as-is. + + __ clrrdi(tmp1, value, JNIHandles::weak_tag_size); + __ ld(value, 0, tmp1); // Resolve (untagged) jobject. + + __ verify_oop(value, FILE_AND_LINE); + __ bind(done); +} diff --git a/src/hotspot/cpu/ppc/gc/shared/modRefBarrierSetAssembler_ppc.hpp b/src/hotspot/cpu/ppc/gc/shared/modRefBarrierSetAssembler_ppc.hpp index eec82621280..5d105f6c048 100644 --- a/src/hotspot/cpu/ppc/gc/shared/modRefBarrierSetAssembler_ppc.hpp +++ b/src/hotspot/cpu/ppc/gc/shared/modRefBarrierSetAssembler_ppc.hpp @@ -57,6 +57,10 @@ public: Register base, RegisterOrConstant ind_or_offs, Register val, Register tmp1, Register tmp2, Register tmp3, MacroAssembler::PreservationLevel preservation_level); + + virtual void resolve_jobject(MacroAssembler* masm, Register value, + Register tmp1, Register tmp2, + MacroAssembler::PreservationLevel preservation_level); }; #endif // CPU_PPC_GC_SHARED_MODREFBARRIERSETASSEMBLER_PPC_HPP -- GitLab From e393c5ea9d9a254cdacbd311498c55c560e8ab25 Mon Sep 17 00:00:00 2001 From: Roman Kennke Date: Tue, 12 Oct 2021 13:16:20 +0000 Subject: [PATCH 183/385] 8275074: Cleanup unused code in JFR LeakProfiler Reviewed-by: mgronlun --- .../jfr/leakprofiler/chains/edgeUtils.cpp | 4 - .../jfr/leakprofiler/chains/edgeUtils.hpp | 1 - .../leakprofiler/utilities/saveRestore.cpp | 112 --------------- .../leakprofiler/utilities/saveRestore.hpp | 128 ------------------ 4 files changed, 245 deletions(-) delete mode 100644 src/hotspot/share/jfr/leakprofiler/utilities/saveRestore.cpp delete mode 100644 src/hotspot/share/jfr/leakprofiler/utilities/saveRestore.hpp diff --git a/src/hotspot/share/jfr/leakprofiler/chains/edgeUtils.cpp b/src/hotspot/share/jfr/leakprofiler/chains/edgeUtils.cpp index dff2e144220..31d7c4afaf2 100644 --- a/src/hotspot/share/jfr/leakprofiler/chains/edgeUtils.cpp +++ b/src/hotspot/share/jfr/leakprofiler/chains/edgeUtils.cpp @@ -35,10 +35,6 @@ #include "oops/oopsHierarchy.hpp" #include "runtime/handles.inline.hpp" -bool EdgeUtils::is_leak_edge(const Edge& edge) { - return (const Edge*)edge.pointee()->mark().to_pointer() == &edge; -} - static bool is_static_field(const oop ref_owner, const InstanceKlass* ik, int offset) { assert(ref_owner != NULL, "invariant"); assert(ik != NULL, "invariant"); diff --git a/src/hotspot/share/jfr/leakprofiler/chains/edgeUtils.hpp b/src/hotspot/share/jfr/leakprofiler/chains/edgeUtils.hpp index 36b447ff75a..c9a169e6edb 100644 --- a/src/hotspot/share/jfr/leakprofiler/chains/edgeUtils.hpp +++ b/src/hotspot/share/jfr/leakprofiler/chains/edgeUtils.hpp @@ -36,7 +36,6 @@ class EdgeUtils : public AllStatic { static const size_t root_context = 100; static const size_t max_ref_chain_depth = leak_context + root_context; - static bool is_leak_edge(const Edge& edge); static const Edge* root(const Edge& edge); static const Edge* ancestor(const Edge& edge, size_t distance); diff --git a/src/hotspot/share/jfr/leakprofiler/utilities/saveRestore.cpp b/src/hotspot/share/jfr/leakprofiler/utilities/saveRestore.cpp deleted file mode 100644 index 9de7d82f60d..00000000000 --- a/src/hotspot/share/jfr/leakprofiler/utilities/saveRestore.cpp +++ /dev/null @@ -1,112 +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. - * - */ - -#include "precompiled.hpp" -#include "classfile/classLoaderDataGraph.hpp" -#include "jfr/leakprofiler/utilities/saveRestore.hpp" -#include "oops/oop.inline.hpp" - -MarkWordContext::MarkWordContext() : _obj(NULL), _mark_word(markWord::zero()) {} - -MarkWordContext::MarkWordContext(const oop obj) : _obj(obj), _mark_word(obj->mark()) { - assert(_obj->mark() == _mark_word, "invariant"); - // now we will "poison" the mark word of the object - // to the intermediate monitor INFLATING state. - // This is an "impossible" state during a safepoint, - // hence we will use it to quickly identify objects - // during the reachability search from gc roots. - assert(markWord::zero() == markWord::INFLATING(), "invariant"); - _obj->set_mark(markWord::INFLATING()); - assert(markWord::zero() == obj->mark(), "invariant"); -} - -MarkWordContext::~MarkWordContext() { - if (_obj != NULL) { - _obj->set_mark(_mark_word); - assert(_obj->mark() == _mark_word, "invariant"); - } -} - -MarkWordContext::MarkWordContext(const MarkWordContext& rhs) : _obj(NULL), _mark_word(markWord::zero()) { - swap(const_cast(rhs)); -} - -void MarkWordContext::operator=(MarkWordContext rhs) { - swap(rhs); -} - -void MarkWordContext::swap(MarkWordContext& rhs) { - oop temp_obj = rhs._obj; - markWord temp_mark_word = rhs._mark_word; - rhs._obj = _obj; - rhs._mark_word = _mark_word; - _obj = temp_obj; - _mark_word = temp_mark_word; -} - -CLDClaimContext::CLDClaimContext() : _cld(NULL) {} - -CLDClaimContext::CLDClaimContext(ClassLoaderData* cld) : _cld(cld) { - assert(_cld->claimed(), "invariant"); - _cld->clear_claim(); -} - -CLDClaimContext::~CLDClaimContext() { - if (_cld != NULL) { - _cld->try_claim(ClassLoaderData::_claim_strong); - assert(_cld->claimed(), "invariant"); - } -} - -CLDClaimContext::CLDClaimContext(const CLDClaimContext& rhs) : _cld(NULL) { - swap(const_cast(rhs)); -} - -void CLDClaimContext::operator=(CLDClaimContext rhs) { - swap(rhs); -} - -void CLDClaimContext::swap(CLDClaimContext& rhs) { - ClassLoaderData* temp_cld = rhs._cld; - rhs._cld = _cld; - _cld = temp_cld; -} - -CLDClaimStateClosure::CLDClaimStateClosure() : CLDClosure(), _state() {} - -void CLDClaimStateClosure::do_cld(ClassLoaderData* cld) { - assert(cld != NULL, "invariant"); - if (cld->claimed()) { - _state.save(cld); - } -} - -SaveRestoreCLDClaimBits::SaveRestoreCLDClaimBits() : _claim_state_closure() { - // interferes with GC, so walk all oops that GC would. - ClassLoaderDataGraph::cld_do(&_claim_state_closure); -} - -SaveRestoreCLDClaimBits::~SaveRestoreCLDClaimBits() { - ClassLoaderDataGraph::clear_claimed_marks(); -} diff --git a/src/hotspot/share/jfr/leakprofiler/utilities/saveRestore.hpp b/src/hotspot/share/jfr/leakprofiler/utilities/saveRestore.hpp deleted file mode 100644 index 3e4013f86e1..00000000000 --- a/src/hotspot/share/jfr/leakprofiler/utilities/saveRestore.hpp +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef SHARE_JFR_LEAKPROFILER_UTILITIES_SAVERESTORE_HPP -#define SHARE_JFR_LEAKPROFILER_UTILITIES_SAVERESTORE_HPP - -#include "memory/allocation.hpp" -#include "memory/iterator.hpp" -#include "oops/markWord.hpp" -#include "utilities/growableArray.hpp" - -template -class SaveRestore { - private: - Impl _impl; - public: - SaveRestore() : _impl() { - _impl.setup(); - } - - void save(T const& value) { - _impl.save(value); - } - - ~SaveRestore() { - _impl.restore(); - } -}; - -template -class ContextStore { -private: - GrowableArray* _storage; -public: - ContextStore() : _storage(NULL) {} - - void setup() { - assert(_storage == NULL, "invariant"); - _storage = new GrowableArray(16); - } - - void save(T const& value) { - _storage->push(Context(value)); - } - - void restore() { - for (int i = 0; i < _storage->length(); ++i) { - _storage->at(i).~Context(); - } - } -}; - -/* -* This class will save the original mark oop of an object sample object. -* It will then install an "identifier" mark oop to be used for -* identification purposes in the search for reference chains. -* The destructor will restore the original mark oop. -*/ - -class MarkWordContext { - private: - oop _obj; - markWord _mark_word; - void swap(MarkWordContext& rhs); - public: - MarkWordContext(); - MarkWordContext(const oop obj); - MarkWordContext(const MarkWordContext& rhs); - void operator=(MarkWordContext rhs); - ~MarkWordContext(); -}; - -typedef SaveRestore > SaveRestoreMarkWords; - -class ClassLoaderData; - -class CLDClaimContext { - private: - ClassLoaderData* _cld; - void swap(CLDClaimContext& rhs); - public: - CLDClaimContext(); - CLDClaimContext(ClassLoaderData* cld); - CLDClaimContext(const CLDClaimContext& rhs); - void operator=(CLDClaimContext rhs); - ~CLDClaimContext(); -}; - -typedef SaveRestore > SaveRestoreCLDClaimState; - -class CLDClaimStateClosure : public CLDClosure { - private: - SaveRestoreCLDClaimState _state; - public: - CLDClaimStateClosure(); - void do_cld(ClassLoaderData* cld); -}; - -class SaveRestoreCLDClaimBits : public StackObj { - private: - CLDClaimStateClosure _claim_state_closure; - public: - SaveRestoreCLDClaimBits(); - ~SaveRestoreCLDClaimBits(); -}; - -#endif // SHARE_JFR_LEAKPROFILER_UTILITIES_SAVERESTORE_HPP -- GitLab From f62346066869b681d1cc9f63775393b11a48722a Mon Sep 17 00:00:00 2001 From: Christian Hagedorn Date: Tue, 12 Oct 2021 13:21:35 +0000 Subject: [PATCH 184/385] 8274911: testlibrary_tests/ir_framework/tests/TestIRMatching.java fails with "java.lang.RuntimeException: Should have thrown exception" Reviewed-by: kvn, thartmann --- .../lib/ir_framework/driver/IRMatcher.java | 2 +- .../ir_framework/tests/TestIRMatching.java | 146 +++++++++--------- .../ir_framework/tests/TestRunTests.java | 11 +- .../ir_framework/tests/Utils.java | 4 +- 4 files changed, 90 insertions(+), 73 deletions(-) diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/IRMatcher.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/IRMatcher.java index 88c28fbdf0b..db297bfb26d 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/IRMatcher.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/IRMatcher.java @@ -495,7 +495,7 @@ public class IRMatcher { // Do not throw an exception in this case (i.e. bailout). String compilations = compilationsBuilder.toString(); if (!compilations.contains(SAFEPOINT_WHILE_PRINTING_MESSAGE)) { - throw new IRViolationException(failuresBuilder.toString(), compilationsBuilder.toString()); + throw new IRViolationException(failuresBuilder.toString(), compilations); } else { System.out.println("Found " + SAFEPOINT_WHILE_PRINTING_MESSAGE + ", bail out of IR matching"); } diff --git a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestIRMatching.java b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestIRMatching.java index c2335717875..892f44bccd0 100644 --- a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestIRMatching.java +++ b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestIRMatching.java @@ -31,9 +31,7 @@ import sun.hotspot.WhiteBox; import java.io.ByteArrayOutputStream; import java.io.PrintStream; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; +import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -51,22 +49,32 @@ import java.util.regex.Pattern; public class TestIRMatching { - private static final List exceptions = new ArrayList<>(); + private static final Map exceptions = new LinkedHashMap<>(); + private static final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + private static final ByteArrayOutputStream baosErr = new ByteArrayOutputStream(); + private static final PrintStream ps = new PrintStream(baos); + private static final PrintStream psErr = new PrintStream(baosErr); + private static final PrintStream oldOut = System.out; + private static final PrintStream oldErr = System.err; private static void addException(Exception e) { - System.out.println(TestFramework.getLastTestVMOutput()); - exceptions.add(e); + System.out.flush(); + System.err.flush(); + exceptions.put(e, baos.toString() + System.lineSeparator() + baosErr.toString()); } public static void main(String[] args) { - runFailOnTestsArgs(BadFailOnConstraint.create(AndOr1.class, "test1(int)", 1, "CallStaticJava"), "-XX:TLABRefillWasteFraction=50", "-XX:+UsePerfData", "-XX:+UseTLAB"); - runFailOnTestsArgs(BadFailOnConstraint.create(AndOr1.class, "test2()", 1, "CallStaticJava"), "-XX:TLABRefillWasteFraction=50", "-XX:-UsePerfData", "-XX:+UseTLAB"); - + // Redirect System.out and System.err to reduce noise. + System.setOut(ps); + System.setErr(psErr); runWithArguments(AndOr1.class, "-XX:TLABRefillWasteFraction=52", "-XX:+UsePerfData", "-XX:+UseTLAB"); runWithArguments(CountComparisons.class, "-XX:TLABRefillWasteFraction=50"); runWithArguments(GoodCount.class, "-XX:TLABRefillWasteFraction=50"); runWithArguments(MultipleFailOnGood.class, "-XX:TLABRefillWasteFraction=50"); + runCheck(new String[] {"-XX:TLABRefillWasteFraction=50", "-XX:+UsePerfData", "-XX:+UseTLAB"}, BadFailOnConstraint.create(AndOr1.class, "test1(int)", 1, "CallStaticJava")); + runCheck(new String[] {"-XX:TLABRefillWasteFraction=50", "-XX:-UsePerfData", "-XX:+UseTLAB"}, BadFailOnConstraint.create(AndOr1.class, "test2()", 1, "CallStaticJava")); + String[] allocMatches = { "MyClass", "wrapper for: _new_instance_Java" }; runCheck(BadFailOnConstraint.create(MultipleFailOnBad.class, "fail1()", 1, 1, "Store"), BadFailOnConstraint.create(MultipleFailOnBad.class, "fail1()", 1, 3, "Store"), @@ -223,18 +231,12 @@ public class TestIRMatching { : BadFailOnConstraint.create(CheckCastArray.class, "arrayCopy(java.lang.Object[],java.lang.Class)", 1, "checkcast_arraycopy") ); - // Redirect stdout to stream and then check if we find required IR encoding read from socket. - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - PrintStream ps = new PrintStream(baos); - PrintStream old = System.out; - System.setOut(ps); - try { runWithArgumentsFail(CompilationOutputOfFails.class); - Utils.shouldHaveThrownException(); + Utils.shouldHaveThrownException(baos.toString()); } catch (IRViolationException e) { try { - boolean failed = false; + StringBuilder failures = new StringBuilder(); System.out.flush(); String output = baos.toString(); baos.reset(); @@ -242,36 +244,36 @@ public class TestIRMatching { Matcher matcher = pattern.matcher(output); long bothCount = matcher.results().count(); if (bothCount != 7L) { - exceptions.add(new RuntimeException("Could not find all both() methods, expected 7 but found " + bothCount)); - failed = true; + failures.append("- Could not find all both() methods, expected 7 but found ").append(bothCount).append(System.lineSeparator()); } pattern = Pattern.compile(">>> Compilation.*ideal\\d.*\\RPrintIdeal:(?:(?!>>> Compilation)[\\S\\s])+"); matcher = pattern.matcher(output); int count = 0; while (matcher.find()) { String match = matcher.group(); - Asserts.assertFalse(match.contains("PrintOptoAssembly"), "Cannot contain opto assembly: " + output); + if (match.contains("PrintOptoAssembly")) { + failures.append("Cannot contain opto assembly: ").append(System.lineSeparator()).append(match); + } count++; } if (count != 7) { - exceptions.add(new RuntimeException("Could not find all ideal() methods, expected 7 but found " + count)); - failed = true; + failures.append("- Could not find all ideal() methods, expected 7 but found ").append(count).append(System.lineSeparator()); } pattern = Pattern.compile(">>> Compilation.*opto\\d.*\\RPrintOptoAssembly:(?:(?!>>> Compilation)[\\S\\s])+"); matcher = pattern.matcher(output); count = 0; while (matcher.find()) { String match = matcher.group(); - Asserts.assertFalse(match.contains("PrintIdeal"), "Cannot contain opto assembly: " + output); + if (match.contains("PrintIdeal")) { + failures.append("Cannot contain print assembly: ").append(System.lineSeparator()).append(match); + } count++; } if (count != 7) { - exceptions.add(new RuntimeException("Could not find all opto() methods, expected 7 but found " + count)); - failed = true; + failures.append("- Could not find all opto() methods, expected 7 but found ").append(count).append(System.lineSeparator()); } - if (failed) { - System.err.println(TestFramework.getLastTestVMOutput()); - System.err.println(output); + if (!failures.isEmpty()) { + addException(new RuntimeException(failures.toString())); } } catch (Exception e1) { addException(e1); @@ -283,52 +285,80 @@ public class TestIRMatching { runWithArguments(FlagComparisons.class, "-XX:TLABRefillWasteFraction=50"); System.out.flush(); String output = baos.toString(); - baos.reset(); findIrIds(output, "testMatchAllIf50", 0, 21); findIrIds(output, "testMatchNoneIf50", -1, -1); runWithArguments(FlagComparisons.class, "-XX:TLABRefillWasteFraction=49"); System.out.flush(); output = baos.toString(); - baos.reset(); findIrIds(output, "testMatchAllIf50", 4, 6, 13, 18); findIrIds(output, "testMatchNoneIf50", 0, 3, 8, 10, 17, 22); runWithArguments(FlagComparisons.class, "-XX:TLABRefillWasteFraction=51"); System.out.flush(); output = baos.toString(); - baos.reset(); findIrIds(output, "testMatchAllIf50", 7, 12, 19, 21); findIrIds(output, "testMatchNoneIf50", 4, 7, 11, 16, 20, 22); - System.setOut(old); + System.setOut(oldOut); + System.setErr(oldErr); if (!exceptions.isEmpty()) { - System.err.println("TestIRMatching failed with one or more exceptions:"); - for (Exception e : exceptions) { - System.err.println(e.getMessage()); + System.err.println("TestIRMatching failed with " + exceptions.size() + " exception(s):"); + int i = 1; + System.err.println("************************"); + for (Map.Entry entry : exceptions.entrySet()) { + System.err.println("***** Exception " + String.format("%02d", i++) +" *****"); + System.err.println("************************"); + + Exception e = entry.getKey(); e.printStackTrace(System.err); - System.err.println("---------"); + System.err.println(); + System.err.println("===== OUTPUT ======"); + System.err.println(entry.getValue()); + System.err.println("MESSAGE: " + e.getMessage()); + System.err.println("************************"); } - throw new RuntimeException("TestIRMatching failed with one or more exceptions - check stderr and stdout"); + i = 1; + System.err.println("===================================="); + System.err.println("********************"); + System.err.println("***** OVERVIEW *****"); + System.err.println("********************"); + for (Map.Entry entry : exceptions.entrySet()) { + Exception e = entry.getKey(); + System.err.print((i++) + ") "); + entry.getKey().printStackTrace(System.err); + System.err.println("********************"); + } + throw new RuntimeException("TestIRMatching failed with " + exceptions.size() + " exception(s) - check stderr and stdout"); } } + private static void runFramework(TestFramework framework) { + baos.reset(); + baosErr.reset(); + framework.start(); + } + private static void runWithArguments(Class clazz, String... args) { try { - new TestFramework(clazz).addFlags(args).start(); + runFramework(new TestFramework(clazz).addFlags(args)); } catch (Exception e) { addException(e); } } private static void runWithArgumentsFail(Class clazz, String... args) { - new TestFramework(clazz).addFlags(args).start(); + runFramework(new TestFramework(clazz).addFlags(args)); } private static void runCheck(String[] args , Constraint... constraints) { try { - new TestFramework(constraints[0].getKlass()).addFlags(args).start(); // All constraints have the same class. - Utils.shouldHaveThrownException(); + TestFramework framework = new TestFramework(constraints[0].getKlass()); // All constraints have the same class. + if (args != null) { + framework.addFlags(args); + } + runFramework(framework); + Utils.shouldHaveThrownException(baos.toString()); } catch (IRViolationException e) { checkConstraints(e, constraints); } catch (Exception e) { @@ -337,14 +367,7 @@ public class TestIRMatching { } private static void runCheck(Constraint... constraints) { - try { - TestFramework.run(constraints[0].getKlass()); // All constraints have the same class. - Utils.shouldHaveThrownException(); - } catch (IRViolationException e) { - checkConstraints(e, constraints); - } catch (Exception e) { - addException(e); - } + runCheck(null, constraints); } private static void checkConstraints(IRViolationException e, Constraint[] constraints) { @@ -354,25 +377,9 @@ public class TestIRMatching { constraint.checkConstraint(e); } } catch (Exception e1) { - System.out.println(TestFramework.getLastTestVMOutput()); + System.out.println(e.getCompilations()); System.out.println(message); - exceptions.add(e1); - } - } - - // Single constraint - private static void runFailOnTestsArgs(Constraint constraint, String... args) { - try { - new TestFramework(constraint.getKlass()).addFlags(args).start(); // All constraints have the same class. - Utils.shouldHaveThrownException(); - } catch (IRViolationException e) { - try { - constraint.checkConstraint(e); - } catch (Exception e1) { - addException(e); - } - } catch (Exception e) { - addException(e); + addException(e1); } } @@ -387,8 +394,9 @@ public class TestIRMatching { builder.append(j); } } - Asserts.assertTrue(output.contains(builder.toString()), "Could not find encoding: \"" + builder.toString() - + System.lineSeparator()); + if (!output.contains(builder.toString())) { + addException(new RuntimeException("Could not find encoding: \"" + builder.toString() + System.lineSeparator())); + } } } diff --git a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestRunTests.java b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestRunTests.java index 21c4a4437f8..780075f50dd 100644 --- a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestRunTests.java +++ b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestRunTests.java @@ -28,6 +28,8 @@ import compiler.lib.ir_framework.driver.IRViolationException; import compiler.lib.ir_framework.shared.TestRunException; import jdk.test.lib.Asserts; +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; import java.util.Arrays; /* @@ -41,15 +43,22 @@ import java.util.Arrays; public class TestRunTests { public static void main(String[] args) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + PrintStream ps = new PrintStream(baos); + PrintStream oldOut = System.out; + System.setOut(ps); + TestFramework.run(); try { TestFramework.run(BadStandalone.class); - Utils.shouldHaveThrownException(); + Utils.shouldHaveThrownException(baos.toString()); } catch (IRViolationException e) { + System.setOut(oldOut); String[] matches = { "test(int)", "test2(int)", "Failed IR Rules (2)"}; Arrays.stream(matches).forEach(m -> Asserts.assertTrue(e.getExceptionInfo().contains(m))); Asserts.assertEQ(e.getExceptionInfo().split("STANDALONE mode", -1).length - 1, 2); } + System.setOut(oldOut); new TestFramework(SkipCompilation.class).addFlags("-XX:-UseCompiler").start(); new TestFramework(SkipCompilation.class).addFlags("-Xint").start(); new TestFramework(SkipC2Compilation.class).addFlags("-XX:TieredStopAtLevel=1").start(); diff --git a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/Utils.java b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/Utils.java index 4b0b8fa5e2b..2b4e76a6805 100644 --- a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/Utils.java +++ b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/Utils.java @@ -31,10 +31,10 @@ import jdk.test.lib.Asserts; import java.util.Arrays; public class Utils { - public static void shouldHaveThrownException() { + public static void shouldHaveThrownException(String s) { // Do not throw an exception if we hit a safepoint while printing which could possibly let the IR matching fail. // This happens very rarely. If there is a problem with the test, then we will catch that on the next test invocation. - if (!TestVMProcess.getLastTestVMOutput().contains(IRMatcher.SAFEPOINT_WHILE_PRINTING_MESSAGE)) { + if (!s.contains(IRMatcher.SAFEPOINT_WHILE_PRINTING_MESSAGE)) { Asserts.fail("Should have thrown exception"); } } -- GitLab From 07b1f1c282ee0a7df6a6b0f240962a032ea3a413 Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Tue, 12 Oct 2021 15:25:53 +0000 Subject: [PATCH 185/385] 8274548: (fc) FileChannel gathering write fails with IOException "Invalid argument" on macOS 11.6 Reviewed-by: alanb --- .../share/classes/sun/nio/ch/IOUtil.java | 19 ++- src/java.base/unix/native/libnio/ch/IOUtil.c | 26 +++- .../windows/native/libnio/ch/IOUtil.c | 6 + .../FileChannel/LargeGatheringWrite.java | 125 ++++++++++++++++++ 4 files changed, 172 insertions(+), 4 deletions(-) create mode 100644 test/jdk/java/nio/channels/FileChannel/LargeGatheringWrite.java diff --git a/src/java.base/share/classes/sun/nio/ch/IOUtil.java b/src/java.base/share/classes/sun/nio/ch/IOUtil.java index b9b320a194f..900bb4e4088 100644 --- a/src/java.base/share/classes/sun/nio/ch/IOUtil.java +++ b/src/java.base/share/classes/sun/nio/ch/IOUtil.java @@ -44,6 +44,11 @@ public class IOUtil { */ static final int IOV_MAX; + /** + * Max total number of bytes that writev supports + */ + static final long WRITEV_MAX; + private IOUtil() { } // No instantiation static int write(FileDescriptor fd, ByteBuffer src, long position, @@ -172,9 +177,10 @@ public class IOUtil { Runnable handleReleasers = null; try { // Iterate over buffers to populate native iovec array. + long writevLen = 0L; int count = offset + length; int i = offset; - while (i < count && iov_len < IOV_MAX) { + while (i < count && iov_len < IOV_MAX && writevLen < WRITEV_MAX) { ByteBuffer buf = bufs[i]; var h = acquireScope(buf, async); if (h != null) { @@ -188,6 +194,10 @@ public class IOUtil { Util.checkRemainingBufferSizeAligned(rem, alignment); if (rem > 0) { + long headroom = WRITEV_MAX - writevLen; + if (headroom < rem) + rem = (int)headroom; + vec.setBuffer(iov_len, buf, pos, rem); // allocate shadow buffer to ensure I/O is done with direct buffer @@ -197,10 +207,9 @@ public class IOUtil { shadow = Util.getTemporaryAlignedDirectBuffer(rem, alignment); else shadow = Util.getTemporaryDirectBuffer(rem); - shadow.put(buf); + shadow.put(shadow.position(), buf, pos, rem); shadow.flip(); vec.setShadow(iov_len, shadow); - buf.position(pos); // temporarily restore position in user buffer buf = shadow; pos = shadow.position(); } @@ -208,6 +217,7 @@ public class IOUtil { vec.putBase(iov_len, bufferAddress(buf) + pos); vec.putLen(iov_len, rem); iov_len++; + writevLen += rem; } i++; } @@ -580,6 +590,8 @@ public class IOUtil { static native int iovMax(); + static native long writevMax(); + static native void initIDs(); /** @@ -593,6 +605,7 @@ public class IOUtil { initIDs(); IOV_MAX = iovMax(); + WRITEV_MAX = writevMax(); } } diff --git a/src/java.base/unix/native/libnio/ch/IOUtil.c b/src/java.base/unix/native/libnio/ch/IOUtil.c index 930137ce031..dfa99658fa6 100644 --- a/src/java.base/unix/native/libnio/ch/IOUtil.c +++ b/src/java.base/unix/native/libnio/ch/IOUtil.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,6 +33,7 @@ #include "jlong.h" #include "sun_nio_ch_IOUtil.h" #include "java_lang_Integer.h" +#include "java_lang_Long.h" #include "nio.h" #include "nio_util.h" @@ -173,6 +174,29 @@ Java_sun_nio_ch_IOUtil_iovMax(JNIEnv *env, jclass this) return (jint)iov_max; } +JNIEXPORT jlong JNICALL +Java_sun_nio_ch_IOUtil_writevMax(JNIEnv *env, jclass this) +{ +#if defined(MACOSX) || defined(__linux__) + // + // The man pages of writev() on both Linux and macOS specify this + // constraint on the sum of all byte lengths in the iovec array: + // + // [EINVAL] The sum of the iov_len values in the iov array + // overflows a 32-bit integer. + // + // As of macOS 11 Big Sur, Darwin version 20, writev() started to + // actually enforce the constraint which had been previously ignored. + // + // In practice on Linux writev() has been observed not to write more + // than 0x7fff0000 (aarch64) or 0x7ffff000 (x64) bytes in one call. + // + return java_lang_Integer_MAX_VALUE; +#else + return java_lang_Long_MAX_VALUE; +#endif +} + /* Declared in nio_util.h for use elsewhere in NIO */ jint diff --git a/src/java.base/windows/native/libnio/ch/IOUtil.c b/src/java.base/windows/native/libnio/ch/IOUtil.c index ff581f04806..511fcdcadb2 100644 --- a/src/java.base/windows/native/libnio/ch/IOUtil.c +++ b/src/java.base/windows/native/libnio/ch/IOUtil.c @@ -31,6 +31,7 @@ #include "jvm.h" #include "jlong.h" +#include "java_lang_Long.h" #include "nio.h" #include "nio_util.h" #include "net_util.h" @@ -77,6 +78,11 @@ Java_sun_nio_ch_IOUtil_iovMax(JNIEnv *env, jclass this) return 16; } +JNIEXPORT jlong JNICALL +Java_sun_nio_ch_IOUtil_writevMax(JNIEnv *env, jclass this) +{ + return java_lang_Long_MAX_VALUE; +} jint convertReturnVal(JNIEnv *env, jint n, jboolean reading) diff --git a/test/jdk/java/nio/channels/FileChannel/LargeGatheringWrite.java b/test/jdk/java/nio/channels/FileChannel/LargeGatheringWrite.java new file mode 100644 index 00000000000..bbfe0f57d79 --- /dev/null +++ b/test/jdk/java/nio/channels/FileChannel/LargeGatheringWrite.java @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 8274548 + * @summary Test gathering write of more than INT_MAX bytes + * @library .. + * @library /test/lib + * @build jdk.test.lib.RandomFactory + * @run main/othervm -Xmx4G LargeGatheringWrite + * @key randomness + */ +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.Random; + +import jdk.test.lib.RandomFactory; + +import static java.nio.file.StandardOpenOption.CREATE; +import static java.nio.file.StandardOpenOption.READ; +import static java.nio.file.StandardOpenOption.WRITE; + +public class LargeGatheringWrite { + private static final int GB = 1024*1024*1024; + + private static final Random RND = RandomFactory.getRandom(); + + public static void main(String[] args) throws IOException { + // Create direct and heap buffers + ByteBuffer direct = ByteBuffer.allocateDirect(GB); + ByteBuffer heap = ByteBuffer.allocate(GB); + + // Load buffers with random values + assert heap.hasArray(); + RND.nextBytes(heap.array()); + direct.put(0, heap, 0, heap.capacity()); + + // Create an array of buffers derived from direct and heap + ByteBuffer[] bigBuffers = new ByteBuffer[] { + direct, + heap, + direct.slice(0, GB/2), + heap.slice(0, GB/2), + direct.slice(GB/2, GB/2), + heap.slice(GB/2, GB/2), + direct.slice(GB/4, GB/2), + heap.slice(GB/4, GB/2), + direct.slice(0, 1), + heap.slice(GB - 2, 1) + }; + + // Calculate the sum of all buffer capacities + long totalLength = 0L; + for(ByteBuffer buf : bigBuffers) + totalLength += buf.capacity(); + + // Write the data to a temporary file + Path tempFile = Files.createTempFile("LargeGatheringWrite", ".dat"); + + System.out.printf("Writing %d bytes of data...%n", totalLength); + try (FileChannel fcw = FileChannel.open(tempFile, CREATE, WRITE);) { + // Print size of individual writes and total number written + long bytesWritten = 0; + long n; + while ((n = fcw.write(bigBuffers)) > 0) { + System.out.printf("Wrote %d bytes\n", n); + bytesWritten += n; + } + System.out.printf("Total of %d bytes written\n", bytesWritten); + + // Verify the content written + try (FileChannel fcr = FileChannel.open(tempFile, READ);) { + byte[] bytes = null; + for (ByteBuffer buf : bigBuffers) { + // For each buffer read the corresponding number of bytes + buf.rewind(); + int length = buf.remaining(); + System.out.printf("Checking length %d%n", length); + if (bytes == null || bytes.length < length) + bytes = new byte[length]; + ByteBuffer dst = ByteBuffer.wrap(bytes).slice(0, length); + if (dst.remaining() != length) + throw new RuntimeException("remaining"); + if (fcr.read(dst) != length) + throw new RuntimeException("length"); + dst.rewind(); + + // Verify that the bytes read from the file match the buffer + int mismatch; + if ((mismatch = dst.mismatch(buf)) != -1) { + String msg = String.format("mismatch: %d%n", mismatch); + throw new RuntimeException(msg); + } + } + } + } finally { + Files.delete(tempFile); + } + } +} -- GitLab From 89999f70e06b41704c7c5b0f9a19582f90806a10 Mon Sep 17 00:00:00 2001 From: Dmitry Batrak Date: Tue, 12 Oct 2021 15:36:41 +0000 Subject: [PATCH 186/385] 8275131: Exceptions after a touchpad gesture on macOS Reviewed-by: dmarkov, prr --- src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.m index 05aee212e6d..150e82c6965 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.m @@ -128,7 +128,7 @@ AWT_NS_WINDOW_IMPLEMENTATION // send up to the GestureHandler to recursively dispatch on the AWT event thread DECLARE_CLASS(jc_GestureHandler, "com/apple/eawt/event/GestureHandler"); - DECLARE_METHOD(sjm_handleGestureFromNative, jc_GestureHandler, + DECLARE_STATIC_METHOD(sjm_handleGestureFromNative, jc_GestureHandler, "handleGestureFromNative", "(Ljava/awt/Window;IDDDD)V"); (*env)->CallStaticVoidMethod(env, jc_GestureHandler, sjm_handleGestureFromNative, awtWindow, type, (jdouble)loc.x, (jdouble)loc.y, (jdouble)a, (jdouble)b); -- GitLab From b8bd259bb83096f8727222a4e5cd84e80e096275 Mon Sep 17 00:00:00 2001 From: Evgeny Astigeevich Date: Tue, 12 Oct 2021 16:56:06 +0000 Subject: [PATCH 187/385] 8271737: Only normalize the cached user.dir property once Reviewed-by: phh --- src/java.base/windows/classes/java/io/WinNTFileSystem.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/java.base/windows/classes/java/io/WinNTFileSystem.java b/src/java.base/windows/classes/java/io/WinNTFileSystem.java index f30717f9ea6..0fc52d6299b 100644 --- a/src/java.base/windows/classes/java/io/WinNTFileSystem.java +++ b/src/java.base/windows/classes/java/io/WinNTFileSystem.java @@ -356,7 +356,7 @@ class WinNTFileSystem extends FileSystem { if (sm != null) { sm.checkPropertyAccess("user.dir"); } - return normalize(userDir); + return userDir; } private String getDrive(String path) { -- GitLab From 8657f77608f37d7ff5254032858f2f16c7c204d5 Mon Sep 17 00:00:00 2001 From: "Daniel D. Daugherty" Date: Tue, 12 Oct 2021 17:05:47 +0000 Subject: [PATCH 188/385] 8271514: support JFR use of new ThreadsList::Iterator Co-authored-by: Kim Barrett Reviewed-by: sspitsyn, mgronlun --- .../share/jfr/utilities/jfrThreadIterator.cpp | 35 +++++++++++-------- .../share/jfr/utilities/jfrThreadIterator.hpp | 12 ++++--- 2 files changed, 28 insertions(+), 19 deletions(-) diff --git a/src/hotspot/share/jfr/utilities/jfrThreadIterator.cpp b/src/hotspot/share/jfr/utilities/jfrThreadIterator.cpp index 433c2589380..c1c0775c530 100644 --- a/src/hotspot/share/jfr/utilities/jfrThreadIterator.cpp +++ b/src/hotspot/share/jfr/utilities/jfrThreadIterator.cpp @@ -26,6 +26,7 @@ #include "jfr/support/jfrThreadLocal.hpp" #include "jfr/utilities/jfrThreadIterator.hpp" #include "runtime/thread.inline.hpp" +#include "runtime/threadSMR.inline.hpp" static bool thread_inclusion_predicate(Thread* t) { assert(t != NULL, "invariant"); @@ -40,14 +41,6 @@ static bool java_thread_inclusion_predicate(JavaThread* jt, bool live_only) { return thread_inclusion_predicate(jt); } -static JavaThread* next_java_thread(JavaThreadIteratorWithHandle& iter, bool live_only) { - JavaThread* next = iter.next(); - while (next != NULL && !java_thread_inclusion_predicate(next, live_only)) { - next = iter.next(); - } - return next; -} - static NonJavaThread* next_non_java_thread(NonJavaThread::Iterator& iter) { while (!iter.end()) { NonJavaThread* next = iter.current(); @@ -60,15 +53,29 @@ static NonJavaThread* next_non_java_thread(NonJavaThread::Iterator& iter) { return NULL; } -JfrJavaThreadIteratorAdapter::JfrJavaThreadIteratorAdapter(bool live_only /* true */) : _iter(), - _next(next_java_thread(_iter, live_only)), - _live_only(live_only) {} +JfrJavaThreadIteratorAdapter::JfrJavaThreadIteratorAdapter(bool live_only /* true */) : + _tlist(), + _it(_tlist.begin()), + _end(_tlist.end()), + _live_only(live_only) +{ + skip_excluded(); +} + +bool JfrJavaThreadIteratorAdapter::has_next() const { + return _it != _end; +} + +void JfrJavaThreadIteratorAdapter::skip_excluded() { + while (has_next() && !java_thread_inclusion_predicate(*_it, _live_only)) { + ++_it; + } +} JavaThread* JfrJavaThreadIteratorAdapter::next() { assert(has_next(), "invariant"); - Type* const temp = _next; - _next = next_java_thread(_iter, _live_only); - assert(temp != _next, "invariant"); + Type* const temp = *_it++; + skip_excluded(); return temp; } diff --git a/src/hotspot/share/jfr/utilities/jfrThreadIterator.hpp b/src/hotspot/share/jfr/utilities/jfrThreadIterator.hpp index f45ed6bf4e3..a3144c8168a 100644 --- a/src/hotspot/share/jfr/utilities/jfrThreadIterator.hpp +++ b/src/hotspot/share/jfr/utilities/jfrThreadIterator.hpp @@ -47,15 +47,17 @@ class JfrThreadIterator : public AP { class JfrJavaThreadIteratorAdapter { private: - JavaThreadIteratorWithHandle _iter; - JavaThread* _next; + ThreadsListHandle _tlist; + ThreadsListHandle::Iterator _it; + ThreadsListHandle::Iterator _end; bool _live_only; + + void skip_excluded(); + public: typedef JavaThread Type; JfrJavaThreadIteratorAdapter(bool live_only = true); - bool has_next() const { - return _next != NULL; - } + bool has_next() const; Type* next(); }; -- GitLab From 124f82377ba93359bc59118ee315ba194080fa92 Mon Sep 17 00:00:00 2001 From: Sergey Tsypanov Date: Tue, 12 Oct 2021 19:13:17 +0000 Subject: [PATCH 189/385] 8268764: Use Long.hashCode() instead of int-cast where applicable Reviewed-by: kevinw, prr, kizune, serb --- .../share/classes/com/sun/media/sound/DLSSoundbank.java | 2 +- .../com/sun/media/sound/WaveExtensibleFileReader.java | 4 ++-- src/java.rmi/share/classes/java/rmi/server/ObjID.java | 3 ++- .../src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java | 4 ++-- src/jdk.jdi/share/classes/com/sun/tools/jdi/FieldImpl.java | 5 +++-- src/jdk.jdi/share/classes/com/sun/tools/jdi/MethodImpl.java | 5 +++-- .../share/classes/com/sun/tools/jdi/ObjectReferenceImpl.java | 5 +++-- .../share/classes/com/sun/tools/jdi/ReferenceTypeImpl.java | 3 ++- .../classes/com/sun/security/auth/NTNumericCredential.java | 5 +++-- 9 files changed, 21 insertions(+), 15 deletions(-) diff --git a/src/java.desktop/share/classes/com/sun/media/sound/DLSSoundbank.java b/src/java.desktop/share/classes/com/sun/media/sound/DLSSoundbank.java index c699b3e87a0..3d62b3ae5a6 100644 --- a/src/java.desktop/share/classes/com/sun/media/sound/DLSSoundbank.java +++ b/src/java.desktop/share/classes/com/sun/media/sound/DLSSoundbank.java @@ -105,7 +105,7 @@ public final class DLSSoundbank implements Soundbank { @Override public int hashCode() { - return (int)i1; + return Long.hashCode(i1); } @Override diff --git a/src/java.desktop/share/classes/com/sun/media/sound/WaveExtensibleFileReader.java b/src/java.desktop/share/classes/com/sun/media/sound/WaveExtensibleFileReader.java index 179fd8d9b76..d56d4d6242d 100644 --- a/src/java.desktop/share/classes/com/sun/media/sound/WaveExtensibleFileReader.java +++ b/src/java.desktop/share/classes/com/sun/media/sound/WaveExtensibleFileReader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -91,7 +91,7 @@ public final class WaveExtensibleFileReader extends SunFileReader { @Override public int hashCode() { - return (int) i1; + return Long.hashCode(i1); } @Override diff --git a/src/java.rmi/share/classes/java/rmi/server/ObjID.java b/src/java.rmi/share/classes/java/rmi/server/ObjID.java index f0bbc10ec40..335123b8e95 100644 --- a/src/java.rmi/share/classes/java/rmi/server/ObjID.java +++ b/src/java.rmi/share/classes/java/rmi/server/ObjID.java @@ -199,8 +199,9 @@ public final class ObjID implements Serializable { * * @return the hash code value for this object identifier */ + @Override public int hashCode() { - return (int) objNum; + return Long.hashCode(objNum); } /** diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java index 9d189797a6b..6599cb45d1c 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -175,7 +175,7 @@ final class HotSpotResolvedJavaMethodImpl extends HotSpotMethod implements HotSp @Override public int hashCode() { - return (int) getMetaspaceMethod(); + return Long.hashCode(getMetaspaceMethod()); } /** diff --git a/src/jdk.jdi/share/classes/com/sun/tools/jdi/FieldImpl.java b/src/jdk.jdi/share/classes/com/sun/tools/jdi/FieldImpl.java index aa5e6ba6ae8..1c3e83c1521 100644 --- a/src/jdk.jdi/share/classes/com/sun/tools/jdi/FieldImpl.java +++ b/src/jdk.jdi/share/classes/com/sun/tools/jdi/FieldImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -51,8 +51,9 @@ public class FieldImpl extends TypeComponentImpl } } + @Override public int hashCode() { - return (int)ref(); + return Long.hashCode(ref()); } public int compareTo(Field field) { diff --git a/src/jdk.jdi/share/classes/com/sun/tools/jdi/MethodImpl.java b/src/jdk.jdi/share/classes/com/sun/tools/jdi/MethodImpl.java index 33bbd3b0c1d..35a646ae495 100644 --- a/src/jdk.jdi/share/classes/com/sun/tools/jdi/MethodImpl.java +++ b/src/jdk.jdi/share/classes/com/sun/tools/jdi/MethodImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. * 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,8 +95,9 @@ public abstract class MethodImpl extends TypeComponentImpl } } + @Override public int hashCode() { - return (int)ref(); + return Long.hashCode(ref()); } public final List allLineLocations() diff --git a/src/jdk.jdi/share/classes/com/sun/tools/jdi/ObjectReferenceImpl.java b/src/jdk.jdi/share/classes/com/sun/tools/jdi/ObjectReferenceImpl.java index 31ad7e48320..3438ee10906 100644 --- a/src/jdk.jdi/share/classes/com/sun/tools/jdi/ObjectReferenceImpl.java +++ b/src/jdk.jdi/share/classes/com/sun/tools/jdi/ObjectReferenceImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -155,8 +155,9 @@ public class ObjectReferenceImpl extends ValueImpl } } + @Override public int hashCode() { - return(int)ref(); + return Long.hashCode(ref()); } public Type type() { diff --git a/src/jdk.jdi/share/classes/com/sun/tools/jdi/ReferenceTypeImpl.java b/src/jdk.jdi/share/classes/com/sun/tools/jdi/ReferenceTypeImpl.java index 96aba339f4b..dcb9ffcd0b1 100644 --- a/src/jdk.jdi/share/classes/com/sun/tools/jdi/ReferenceTypeImpl.java +++ b/src/jdk.jdi/share/classes/com/sun/tools/jdi/ReferenceTypeImpl.java @@ -150,8 +150,9 @@ public abstract class ReferenceTypeImpl extends TypeImpl implements ReferenceTyp } } + @Override public int hashCode() { - return(int)ref(); + return Long.hashCode(ref()); } public int compareTo(ReferenceType object) { diff --git a/src/jdk.security.auth/share/classes/com/sun/security/auth/NTNumericCredential.java b/src/jdk.security.auth/share/classes/com/sun/security/auth/NTNumericCredential.java index 22c186a4989..59d318b1a30 100644 --- a/src/jdk.security.auth/share/classes/com/sun/security/auth/NTNumericCredential.java +++ b/src/jdk.security.auth/share/classes/com/sun/security/auth/NTNumericCredential.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -100,7 +100,8 @@ public class NTNumericCredential { * * @return a hash code for this {@code NTNumericCredential}. */ + @Override public int hashCode() { - return (int)this.impersonationToken; + return Long.hashCode(this.impersonationToken); } } -- GitLab From 03c2b73e2112cdbcbd1230009de0a15a9bd31815 Mon Sep 17 00:00:00 2001 From: Magnus Ihse Bursie Date: Tue, 12 Oct 2021 23:28:53 +0000 Subject: [PATCH 190/385] 8275128: Build hsdis using normal build system Reviewed-by: erikj --- make/Hsdis.gmk | 118 +++++++++++++++ make/Main.gmk | 12 ++ make/autoconf/configure.ac | 1 + make/autoconf/help.m4 | 8 + make/autoconf/jdk-options.m4 | 142 ++++++++++++++++++ make/autoconf/spec.gmk.in | 4 + src/utils/hsdis/README | 124 +++++----------- src/utils/hsdis/hsdis-demo.c | 281 ----------------------------------- 8 files changed, 324 insertions(+), 366 deletions(-) create mode 100644 make/Hsdis.gmk delete mode 100644 src/utils/hsdis/hsdis-demo.c diff --git a/make/Hsdis.gmk b/make/Hsdis.gmk new file mode 100644 index 00000000000..2253da90679 --- /dev/null +++ b/make/Hsdis.gmk @@ -0,0 +1,118 @@ +# +# Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. +# 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. +# + +default: all + +include $(SPEC) +include MakeBase.gmk +include JdkNativeCompilation.gmk + +################################################################################ +# This makefile compiles and installs the hsdis library +# +################################################################################ + +HSDIS_OUTPUT_DIR := $(SUPPORT_OUTPUTDIR)/hsdis + +ifeq ($(call isTargetOs, windows), true) + INSTALLED_HSDIS_DIR := $(JDK_OUTPUTDIR)/bin + + # On windows, we need to "fake" a completely different toolchain using gcc + # instead of the normal microsoft toolchain. This is quite hacky... + + MINGW_BASE := x86_64-w64-mingw32 + + $(eval $(call DefineNativeToolchain, TOOLCHAIN_MINGW, \ + CC := $(MINGW_BASE)-gcc, \ + LD := $(MINGW_BASE)-ld, \ + OBJCOPY := $(MINGW_BASE)-objcopy, \ + RC := $(RC), \ + SYSROOT_CFLAGS := --sysroot=/usr/$(MINGW_BASE)/sys-root, \ + SYSROOT_LDFLAGS := --sysroot=/usr/$(MINGW_BASE)/sys-root, \ + )) + + TOOLCHAIN_TYPE := gcc + OPENJDK_TARGET_OS := linux + CC_OUT_OPTION := -o$(SPACE) + LD_OUT_OPTION := -o$(SPACE) + GENDEPS_FLAGS := -MMD -MF + CFLAGS_DEBUG_SYMBOLS := -g + DISABLED_WARNINGS := + DISABLE_WARNING_PREFIX := -Wno- + CFLAGS_WARNINGS_ARE_ERRORS := -Werror + SHARED_LIBRARY_FLAGS := -shared + + HSDIS_TOOLCHAIN := TOOLCHAIN_MINGW + HSDIS_TOOLCHAIN_CFLAGS := + HSDIS_TOOLCHAIN_LDFLAGS := -L/usr/lib/gcc/$(MINGW_BASE)/9.2.0 \ + -L/usr/$(MINGW_BASE)/sys-root/mingw/lib + MINGW_DLLCRT := /usr/$(MINGW_BASE)/sys-root/mingw/lib/dllcrt2.o + HSDIS_TOOLCHAIN_LIBS := $(MINGW_DLLCRT) -lmingw32 -lgcc -lgcc_eh -lmoldname \ + -lmingwex -lmsvcrt -lpthread -ladvapi32 -lshell32 -luser32 -lkernel32 +else + INSTALLED_HSDIS_DIR := $(JDK_OUTPUTDIR)/lib + + HSDIS_TOOLCHAIN := TOOLCHAIN_DEFAULT + HSDIS_TOOLCHAIN_CFLAGS := $(CFLAGS_JDKLIB) + HSDIS_TOOLCHAIN_LDFLAGS := $(LDFLAGS_JDKLIB) + HSDIS_TOOLCHAIN_LIBS := -ldl +endif + + +$(eval $(call SetupJdkLibrary, BUILD_HSDIS, \ + NAME := hsdis, \ + SRC := $(TOPDIR)/src/utils/hsdis, \ + TOOLCHAIN := $(HSDIS_TOOLCHAIN), \ + OUTPUT_DIR := $(HSDIS_OUTPUT_DIR), \ + OBJECT_DIR := $(HSDIS_OUTPUT_DIR), \ + DISABLED_WARNINGS_gcc := undef format-nonliteral sign-compare, \ + DISABLED_WARNINGS_clang := undef format-nonliteral, \ + CFLAGS := $(HSDIS_TOOLCHAIN_CFLAGS) $(HSDIS_CFLAGS), \ + LDFLAGS := $(HSDIS_TOOLCHAIN_LDFLAGS) $(SHARED_LIBRARY_FLAGS), \ + LIBS := $(HSDIS_LIBS) $(HSDIS_TOOLCHAIN_LIBS), \ +)) + +build: $(BUILD_HSDIS) + +TARGETS += build + +INSTALLED_HSDIS_NAME := hsdis-$(OPENJDK_TARGET_CPU_LEGACY_LIB)$(SHARED_LIBRARY_SUFFIX) + +INSTALLED_HSDIS := $(INSTALLED_HSDIS_DIR)/$(INSTALLED_HSDIS_NAME) + +$(INSTALLED_HSDIS): $(BUILD_HSDIS_TARGET) + $(call LogWarn, NOTE: The resulting build might not be redistributable. Seek legal advice before distibuting.) + $(install-file) + + +install: $(INSTALLED_HSDIS) + +TARGETS += install + +################################################################################ + +all: $(TARGETS) + +.PHONY: all default build install diff --git a/make/Main.gmk b/make/Main.gmk index cad3ecb3203..75eee65ba84 100644 --- a/make/Main.gmk +++ b/make/Main.gmk @@ -526,6 +526,18 @@ $(eval $(call SetupTarget, update-x11wrappers, \ DEPS := java.base-copy buildtools-jdk, \ )) +ifneq ($(HSDIS_BACKEND), none) + $(eval $(call SetupTarget, build-hsdis, \ + MAKEFILE := Hsdis, \ + TARGET := build, \ + )) + + $(eval $(call SetupTarget, install-hsdis, \ + MAKEFILE := Hsdis, \ + TARGET := install, \ + )) +endif + ################################################################################ # Cross compilation support diff --git a/make/autoconf/configure.ac b/make/autoconf/configure.ac index 0faec69738e..29ed3f206aa 100644 --- a/make/autoconf/configure.ac +++ b/make/autoconf/configure.ac @@ -249,6 +249,7 @@ JDKOPT_EXCLUDE_TRANSLATIONS JDKOPT_ENABLE_DISABLE_MANPAGES JDKOPT_ENABLE_DISABLE_CDS_ARCHIVE JDKOPT_ENABLE_DISABLE_COMPATIBLE_CDS_ALIGNMENT +JDKOPT_SETUP_HSDIS ############################################################################### # diff --git a/make/autoconf/help.m4 b/make/autoconf/help.m4 index 924cc425609..f36aa2819df 100644 --- a/make/autoconf/help.m4 +++ b/make/autoconf/help.m4 @@ -80,6 +80,14 @@ cygwin_help() { PKGHANDLER_COMMAND="( cd && cmd /c setup -q -P make )" HELP_MSG="You might be able to fix this by running '$PKGHANDLER_COMMAND'." ;; + i686-w64-mingw32-gcc) + PKGHANDLER_COMMAND="( cd && cmd /c setup -q -P gcc-core i686-w64-mingw32-gcc-core mingw64-i686-glib2.0 )" + HELP_MSG="You might be able to fix this by running '$PKGHANDLER_COMMAND'." + ;; + x86_64-w64-mingw32-gcc) + PKGHANDLER_COMMAND="( cd && cmd /c setup -q -P gcc-core x86_64-w64-mingw32-gcc-core mingw64-x86_64-glib2.0 )" + HELP_MSG="You might be able to fix this by running '$PKGHANDLER_COMMAND'." + ;; esac } diff --git a/make/autoconf/jdk-options.m4 b/make/autoconf/jdk-options.m4 index 299f76bd1e6..c937101c2c7 100644 --- a/make/autoconf/jdk-options.m4 +++ b/make/autoconf/jdk-options.m4 @@ -704,3 +704,145 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_REPRODUCIBLE_BUILD], AC_SUBST(SOURCE_DATE) AC_SUBST(ENABLE_REPRODUCIBLE_BUILD) ]) + +################################################################################ +# +# Helper function to build binutils from source. +# +AC_DEFUN([JDKOPT_BUILD_BINUTILS], +[ + BINUTILS_SRC="$with_binutils_src" + UTIL_FIXUP_PATH(BINUTILS_SRC) + + if ! test -d $BINUTILS_SRC; then + AC_MSG_ERROR([--with-binutils-src is not pointing to a directory]) + fi + if ! test -x $BINUTILS_SRC/configure; then + AC_MSG_ERROR([--with-binutils-src does not look like a binutils source directory]) + fi + + if test -e $BINUTILS_SRC/bfd/libbfd.a && \ + test -e $BINUTILS_SRC/opcodes/libopcodes.a && \ + test -e $BINUTILS_SRC/libiberty/libiberty.a && \ + test -e $BINUTILS_SRC/zlib/libz.a; then + AC_MSG_NOTICE([Found binutils binaries in binutils source directory -- not building]) + else + # On Windows, we cannot build with the normal Microsoft CL, but must instead use + # a separate mingw toolchain. + if test "x$OPENJDK_BUILD_OS" = xwindows; then + if test "x$OPENJDK_TARGET_CPU" = "xx86"; then + target_base="i686-w64-mingw32" + else + target_base="$OPENJDK_TARGET_CPU-w64-mingw32" + fi + binutils_cc="$target_base-gcc" + binutils_target="--host=$target_base --target=$target_base" + # Somehow the uint typedef is not included when building with mingw + binutils_cflags="-Duint=unsigned" + compiler_version=`$binutils_cc --version 2>&1` + if ! [ [[ "$compiler_version" =~ GCC ]] ]; then + AC_MSG_NOTICE([Could not find correct mingw compiler $binutils_cc.]) + HELP_MSG_MISSING_DEPENDENCY([$binutils_cc]) + AC_MSG_ERROR([Cannot continue. $HELP_MSG]) + else + AC_MSG_NOTICE([Using compiler $binutils_cc with version $compiler_version]) + fi + elif test "x$OPENJDK_BUILD_OS" = xmacosx; then + if test "x$OPENJDK_TARGET_CPU" = "xaarch64"; then + binutils_target="--enable-targets=aarch64-darwin" + else + binutils_target="" + fi + else + binutils_cc="$CC $SYSROOT_CFLAGS" + binutils_target="" + fi + binutils_cflags="$binutils_cflags $MACHINE_FLAG $JVM_PICFLAG $C_O_FLAG_NORM" + + AC_MSG_NOTICE([Running binutils configure]) + AC_MSG_NOTICE([configure command line: ./configure --disable-nls CFLAGS="$binutils_cflags" CC="$binutils_cc" $binutils_target]) + saved_dir=`pwd` + cd "$BINUTILS_SRC" + ./configure --disable-nls CFLAGS="$binutils_cflags" CC="$binutils_cc" $binutils_target + if test $? -ne 0 || ! test -e $BINUTILS_SRC/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 + 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 + cd $saved_dir + AC_MSG_NOTICE([Building of binutils done]) + fi + + BINUTILS_DIR="$BINUTILS_SRC" +]) + +################################################################################ +# +# Determine if hsdis should be built, and if so, with which backend. +# +AC_DEFUN_ONCE([JDKOPT_SETUP_HSDIS], +[ + AC_ARG_WITH([hsdis], [AS_HELP_STRING([--with-hsdis], + [what hsdis backend to use ('none', 'binutils') @<:@none@:>@])]) + + AC_ARG_WITH([binutils], [AS_HELP_STRING([--with-binutils], + [where to find the binutils files needed for hsdis/binutils])]) + + AC_ARG_WITH([binutils-src], [AS_HELP_STRING([--with-binutils-src], + [where to find the binutils source for building])]) + + AC_MSG_CHECKING([what hsdis backend to use]) + + if test "x$with_hsdis" = xyes; then + AC_MSG_ERROR([--with-hsdis must have a value]) + elif test "x$with_hsdis" = xnone || test "x$with_hsdis" = xno || test "x$with_hsdis" = x; then + HSDIS_BACKEND=none + AC_MSG_RESULT(['none', hsdis will not be built]) + elif test "x$with_hsdis" = xbinutils; then + HSDIS_BACKEND=binutils + AC_MSG_RESULT(['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. + JDKOPT_BUILD_BINUTILS + fi + + if test "x$with_binutils" != x; then + BINUTILS_DIR="$with_binutils" + fi + + AC_MSG_CHECKING([for binutils to use with hsdis]) + if 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; then + AC_MSG_RESULT([$BINUTILS_DIR]) + HSDIS_CFLAGS="-I$BINUTILS_DIR/include -I$BINUTILS_DIR/bfd -DLIBARCH_$OPENJDK_TARGET_CPU_LEGACY_LIB" + HSDIS_LIBS="$BINUTILS_DIR/bfd/libbfd.a $BINUTILS_DIR/opcodes/libopcodes.a $BINUTILS_DIR/libiberty/libiberty.a $BINUTILS_DIR/zlib/libz.a" + else + AC_MSG_RESULT([invalid]) + AC_MSG_ERROR([$BINUTILS_DIR does not contain a proper binutils installation]) + fi + else + AC_MSG_RESULT([missing]) + AC_MSG_NOTICE([--with-hsdis=binutils requires specifying a binutils installation.]) + AC_MSG_NOTICE([Download binutils from https://www.gnu.org/software/binutils and unpack it,]) + AC_MSG_NOTICE([and point --with-binutils-src to the resulting directory, or use]) + AC_MSG_NOTICE([--with-binutils to point to a pre-built binutils installation.]) + AC_MSG_ERROR([Cannot continue]) + fi + else + AC_MSG_RESULT([invalid]) + AC_MSG_ERROR([Incorrect hsdis backend "$with_hsdis"]) + fi + + AC_SUBST(HSDIS_BACKEND) + AC_SUBST(HSDIS_CFLAGS) + AC_SUBST(HSDIS_LIBS) +]) diff --git a/make/autoconf/spec.gmk.in b/make/autoconf/spec.gmk.in index bb7d63346f4..72be922f103 100644 --- a/make/autoconf/spec.gmk.in +++ b/make/autoconf/spec.gmk.in @@ -359,6 +359,10 @@ ENABLE_COMPATIBLE_CDS_ALIGNMENT := @ENABLE_COMPATIBLE_CDS_ALIGNMENT@ ALLOW_ABSOLUTE_PATHS_IN_OUTPUT := @ALLOW_ABSOLUTE_PATHS_IN_OUTPUT@ +HSDIS_BACKEND := @HSDIS_BACKEND@ +HSDIS_CFLAGS := @HSDIS_CFLAGS@ +HSDIS_LIBS := @HSDIS_LIBS@ + # The boot jdk to use. This is overridden in bootcycle-spec.gmk. Make sure to keep # it in sync. BOOT_JDK:=@BOOT_JDK@ diff --git a/src/utils/hsdis/README b/src/utils/hsdis/README index f2cf2f48b9f..aee40f6bd27 100644 --- a/src/utils/hsdis/README +++ b/src/utils/hsdis/README @@ -1,4 +1,4 @@ -Copyright (c) 2008, 2019, Oracle and/or its affiliates. All rights reserved. +Copyright (c) 2008, 2021, 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 @@ -43,102 +43,56 @@ questions. ________________________________________________________________________ -'hsdis': A HotSpot plugin for disassembling dynamically generated code. +'hsdis': A HotSpot plugin for disassembling dynamically generated code. -The files in this directory (Makefile, hsdis.[ch], hsdis-demo.c) -are built independently of the HotSpot JVM. - -To use the plugin with a JVM, you need a new version that can load it. -If the product mode of your JVM does not accept -XX:+PrintAssembly, -you do not have a version that is new enough. +The files in this directory are built independently of the HotSpot JVM. * Building -To build this project you need a copy of GNU binutils to build against. -It is known to work with binutils 2.29.1, 2.30, and 2.31.1. Building -against versions older than 2.29 is no longer supported. Download a -copy of the software from http://directory.fsf.org/project/binutils or -one of its mirrors. Builds targetting windows currently require the -use of a cross compiler. - -Binutils should be configured with the '--disable-nls' flag to disable -Native Language Support, otherwise you might get an "undefined -reference to `libintl_gettext'" if you try to load hsdis.so on systems -which don't have NLS by default. It also avoids build problems on -other configurations that don't include the full NLS support. - -The makefile looks for the sources in build/binutils or you can -specify its location to the makefile using BINUTILS=path. It will -configure binutils and build it first and then build and link the -disassembly adapter. Make all will build the default target for your -platform. If your platform supports both 32 and 64 simultaneously then -"make both" will build them both at once. "make all64" will -explicitly build the 64 bit version. By default this will build the -disassembler library only. If you build demo it will build a demo -program that attempts to exercise the library. - -With recent version of binutils (i.e. binutils-2.23.2) you may get the -following build error: - -WARNING: `makeinfo' is missing on your system. You should only need it if - you modified a `.texi' or `.texinfo' file, or any other file - ... - -This is because of "Bug 15345 - binutils-2.23.2 tarball doesn't build -without makeinfo" [2]. The easiest way to work around this problem is -by doing a "touch $BINUTILS/bfd/doc/bfd.info". - -Windows - -In theory this should be buildable on Windows but getting a working -GNU build environment on Windows has proven difficult. MINGW should -be able to do it but at the time of this writing I was unable to get -this working. Instead you can use the mingw cross compiler on linux -to produce the windows binaries. For 32-bit windows you can install -mingw32 using your package manager and it will be added to your path -automatically. For 64-bit you need to download the 64 bit mingw from -http://sourceforge.net/projects/mingw-w64. Grab a copy of the -complete toolchain and unpack it somewhere. Put the bin directory of -the toolchain in your path. The mingw installs contain cross compile -versions of gcc that are named with a prefix to indicate what they are -targeting and you must tell the Makefile which one to use. This -should either be i586-mingw32msvc or x86_64-pc-mingw32 depending on -which one you are targeting and there should be a version of gcc in -your path named i586-mingw32msvc-gcc or x86_64-pc-mingw32-gcc. Tell -the makefile what prefix to use to find the mingw tools by using -MINGW=. For example: - -make MINGW=i586-mingw32msvc BINUTILS=build/binutils-2.31.1 - -will build the Win32 cross compiled version of hsdis based on 2.31.1. +To build this project you need a copy of GNU binutils to build against. It is +known to work with binutils 2.37. Building against versions older than 2.29 is +not supported. Download a copy of the software from +http://directory.fsf.org/project/binutils or one of its mirrors. -* Installing +To build this library, you must enable building in configure by "bash configure +--with-hsdis=binutils". -Products are named like build/$OS-$LIBARCH/hsdis-$LIBARCH.so. You can -install them next to your libjvm.so inside your JRE/JDK or alternatively -put it anywhere on your LD_LIBRARY_PATH. The search path in the JVM is: +You must also specify where binutils is located. To facilitate building, you can +point to a place where the (unpacked) binutils sources are located using +"--with-binutils-src=", and configure will build binutils for you. On +repeated runs, you can keep this command line option, since configure will +figure out that the binutils binaries are already present and skip building, or +you can replace it with "--with-binutils=". -1. /lib//libhsdis-.so -2. /lib//hsdis-.so -3. /lib/hsdis-.so -4. hsdis-.so (using LD_LIBRARY_PATH) +If you have pre-built binutils binaries, you can point to them directly using +"--with-binutils=". -Now test: +When you have created a proper configuration, you can then build the hsdis +library using "make build-hsdis". - export LD_LIBRARY_PATH .../hsdis/build/$OS-$LIBARCH:$LD_LIBRARY_PATH - dargs='-XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly' - dargs=$dargs' -XX:PrintAssemblyOptions=hsdis-print-bytes' - java $dargs -Xbatch CompileCommand=print,*String.hashCode HelloWorld +* Building on Windows -If the product mode of the JVM does not accept -XX:+PrintAssembly, -you do not have a version new enough to use the hsdis plugin. +On Windows, the normal Microsoft Visual Studio toolchain cannot build binutils. +Instead we need to use the mingw compiler. This is available as a cygwin +package. You need to install the "gcc-core" and "mingw64-x86_64-gcc-core" +packages (or "mingw64-i686-gcc-core", if you want the 32-bit version) and +"mingw64-x86_64-glib2.0". + +* Installing -* Wiki +To build the hsdis library, run "make build-hsdis". This will build the library +in a separate directory, but not make it available to the JDK in the +configuration. To actually install it in the JDK, run "make install-hsdis". -More information can be found in the OpenJDK HotSpot Wiki [1]. +Note: The resulting build may not be distributable. Please get legal advice if +you intend to distribute the result of your build. +* Using the library -Resources: +The hsdis library will be automatically loaded by Hotspot when you use the +diagnostic option "-XX:+PrintAssembly". Note that since this is a diagnostic +option, you need to unlock these first, so in practice you activate it using +"-XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly". -[1] https://wiki.openjdk.java.net/display/HotSpot/PrintAssembly -[2] http://sourceware.org/bugzilla/show_bug.cgi?id=15345 +More information is available at the wiki +[https://wiki.openjdk.java.net/display/HotSpot/PrintAssembly]. diff --git a/src/utils/hsdis/hsdis-demo.c b/src/utils/hsdis/hsdis-demo.c deleted file mode 100644 index 0ab3018ed2b..00000000000 --- a/src/utils/hsdis/hsdis-demo.c +++ /dev/null @@ -1,281 +0,0 @@ -/* - * Copyright (c) 2008, 2012, 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 - * - * Subject to the condition set forth below, permission is hereby granted to - * any person obtaining a copy of this software, associated documentation - * and/or data (collectively the "Software"), free of charge and under any - * and all copyright rights in the Software, and any and all patent rights - * owned or freely licensable by each licensor hereunder covering either (i) - * the unmodified Software as contributed to or provided by such licensor, - * or (ii) the Larger Works (as defined below), to deal in both - * - * (a) the Software, and - * - * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file - * if one is included with the Software (each a "Larger Work" to which the - * Software is contributed by such licensors), - * - * without restriction, including without limitation the rights to copy, - * create derivative works of, display, perform, and distribute the Software - * and make, use, sell, offer for sale, import, export, have made, and have - * sold the Software and the Larger Work(s), and to sublicense the foregoing - * rights on either these or other terms. - * - * This license is subject to the following condition: - * - * The above copyright notice and either this complete permission notice or - * at a minimum a reference to the UPL must be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN - * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE - * USE OR OTHER DEALINGS IN THE SOFTWARE. - * - * 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. - * - */ - -/* hsdis-demo.c -- dump a range of addresses as native instructions - This demonstrates the protocol required by the HotSpot PrintAssembly option. -*/ - -#include -#include -#include -#include - -#include "hsdis.h" - - -void greet(const char*); -void disassemble(uintptr_t, uintptr_t); -void end_of_file(); - -const char* options = NULL; -int raw = 0; -int xml = 0; - -int main(int ac, char** av) { - int greeted = 0; - int i; - for (i = 1; i < ac; i++) { - const char* arg = av[i]; - if (arg[0] == '-') { - if (!strcmp(arg, "-xml")) - xml ^= 1; - else if (!strcmp(arg, "-raw")) - raw ^= 1; - else if (!strncmp(arg, "-options=", 9)) - options = arg+9; - else - { printf("Usage: %s [-xml] [name...]\n", av[0]); exit(2); } - continue; - } - greet(arg); - greeted = 1; - } - if (!greeted) - greet("world"); - printf("...And now for something completely different:\n"); - void *start = (void*) &main; - void *end = (void*) &end_of_file; -#if defined(__ia64) || (defined(__powerpc__) && !defined(ABI_ELFv2)) - /* On IA64 and PPC function pointers are pointers to function descriptors */ - start = *((void**)start); - end = *((void**)end); -#endif - disassemble(start, (end > start) ? end : start + 64); - printf("Cheers!\n"); -} - -void greet(const char* whom) { - printf("Hello, %s!\n", whom); -} - -void end_of_file() { } - -/* don't disassemble after this point... */ - -#include "dlfcn.h" - -#define DECODE_INSTRUCTIONS_VIRTUAL_NAME "decode_instructions_virtual" -#define DECODE_INSTRUCTIONS_NAME "decode_instructions" -#define HSDIS_NAME "hsdis" -static void* decode_instructions_pv = 0; -static void* decode_instructions_sv = 0; -static const char* hsdis_path[] = { - HSDIS_NAME"-"LIBARCH LIB_EXT, - "./" HSDIS_NAME"-"LIBARCH LIB_EXT, -#ifdef TARGET_DIR - TARGET_DIR"/"HSDIS_NAME"-"LIBARCH LIB_EXT, -#endif - NULL -}; - -static const char* load_decode_instructions() { - void* dllib = NULL; - const char* *next_in_path = hsdis_path; - while (1) { - decode_instructions_pv = dlsym(dllib, DECODE_INSTRUCTIONS_VIRTUAL_NAME); - decode_instructions_sv = dlsym(dllib, DECODE_INSTRUCTIONS_NAME); - if (decode_instructions_pv != NULL || decode_instructions_sv != NULL) - return NULL; - if (dllib != NULL) - return "plugin does not defined "DECODE_INSTRUCTIONS_VIRTUAL_NAME" and "DECODE_INSTRUCTIONS_NAME; - for (dllib = NULL; dllib == NULL; ) { - const char* next_lib = (*next_in_path++); - if (next_lib == NULL) - return "cannot find plugin "HSDIS_NAME LIB_EXT; - dllib = dlopen(next_lib, RTLD_LAZY); - } - } -} - - -static const char* lookup(void* addr) { -#if defined(__ia64) || defined(__powerpc__) - /* On IA64 and PPC function pointers are pointers to function descriptors */ -#define CHECK_NAME(fn) \ - if (addr == *((void**) &fn)) return #fn; -#else -#define CHECK_NAME(fn) \ - if (addr == (void*) &fn) return #fn; -#endif - - CHECK_NAME(main); - CHECK_NAME(greet); - return NULL; -} - -/* does the event match the tag, followed by a null, space, or slash? */ -#define MATCH(event, tag) \ - (!strncmp(event, tag, sizeof(tag)-1) && \ - (!event[sizeof(tag)-1] || strchr(" /", event[sizeof(tag)-1]))) - - -static const char event_cookie[] = "event_cookie"; /* demo placeholder */ -static void* simple_handle_event(void* cookie, const char* event, void* arg) { - if (MATCH(event, "/insn")) { - // follow each complete insn by a nice newline - printf("\n"); - } - return NULL; -} - -static void* handle_event(void* cookie, const char* event, void* arg) { -#define NS_DEMO "demo:" - if (cookie != event_cookie) - printf("*** bad event cookie %p != %p\n", cookie, event_cookie); - - if (xml) { - /* We could almost do a printf(event, arg), - but for the sake of a better demo, - we dress the result up as valid XML. - */ - const char* fmt = strchr(event, ' '); - int evlen = (fmt ? fmt - event : strlen(event)); - if (!fmt) { - if (event[0] != '/') { - printf("<"NS_DEMO"%.*s>", evlen, event); - } else { - printf("", evlen-1, event+1); - } - } else { - if (event[0] != '/') { - printf("<"NS_DEMO"%.*s", evlen, event); - printf(fmt, arg); - printf(">"); - } else { - printf("<"NS_DEMO"%.*s_done", evlen-1, event+1); - printf(fmt, arg); - printf("/>", evlen-1, event+1); - } - } - } - - if (MATCH(event, "insn")) { - const char* name = lookup(arg); - if (name) printf("%s:\n", name); - - /* basic action for : */ - printf(" %p\t", arg); - - } else if (MATCH(event, "/insn")) { - // follow each complete insn by a nice newline - printf("\n"); - } else if (MATCH(event, "mach")) { - printf("Decoding for CPU '%s'\n", (char*) arg); - - } else if (MATCH(event, "addr")) { - /* basic action for : */ - const char* name = lookup(arg); - if (name) { - printf("&%s (%p)", name, arg); - /* return non-null to notify hsdis not to print the addr */ - return arg; - } - } - - /* null return is always safe; can mean "I ignored it" */ - return NULL; -} - -#define fprintf_callback \ - (decode_instructions_printf_callback_ftype)&fprintf - -void disassemble(uintptr_t from, uintptr_t to) { - const char* err = load_decode_instructions(); - if (err != NULL) { - printf("%s: %s\n", err, dlerror()); - exit(1); - } - decode_func_vtype decode_instructions_v - = (decode_func_vtype) decode_instructions_pv; - decode_func_stype decode_instructions_s - = (decode_func_stype) decode_instructions_sv; - void* res; - if (decode_instructions_pv != NULL) { - printf("\nDecoding from %p to %p...with %s\n", from, to, DECODE_INSTRUCTIONS_VIRTUAL_NAME); - if (raw) { - res = (*decode_instructions_v)(from, to, - (unsigned char*)from, to - from, - simple_handle_event, stdout, - NULL, stdout, - options, 0); - } else { - res = (*decode_instructions_v)(from, to, - (unsigned char*)from, to - from, - handle_event, (void*) event_cookie, - fprintf_callback, stdout, - options, 0); - } - if (res != (void*)to) - printf("*** Result was %p!\n", res); - } - void* sres; - if (decode_instructions_sv != NULL) { - printf("\nDecoding from %p to %p...with old decode_instructions\n", from, to, DECODE_INSTRUCTIONS_NAME); - if (raw) { - sres = (*decode_instructions_s)(from, to, - simple_handle_event, stdout, - NULL, stdout, - options); - } else { - sres = (*decode_instructions_s)(from, to, - handle_event, (void*) event_cookie, - fprintf_callback, stdout, - options); - } - if (sres != (void *)to) - printf("*** Result of decode_instructions %p!\n", sres); - } -} -- GitLab From b1b83500a9c3a74bf39894e49eefd031d208b9b9 Mon Sep 17 00:00:00 2001 From: "Daniel D. Daugherty" Date: Tue, 12 Oct 2021 23:43:40 +0000 Subject: [PATCH 191/385] 8275171: ProblemList compiler/codegen/aes/TestAESMain.java on linux-x64 and windows-x64 in -Xcomp mode Reviewed-by: iignatyev --- 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 e2fa6527be8..b3196f6a601 100644 --- a/test/hotspot/jtreg/ProblemList-Xcomp.txt +++ b/test/hotspot/jtreg/ProblemList-Xcomp.txt @@ -41,3 +41,5 @@ serviceability/sa/TestJhsdbJstackMixed.java 8248675 linux-aarch64 compiler/vectorapi/VectorCastShape64Test.java 8274855 generic-x64 compiler/vectorapi/VectorCastShape128Test.java 8274855 generic-x64 + +compiler/codegen/aes/TestAESMain.java 8274323 linux-x64,windows-x64 -- GitLab From ab34cced3beae765fe9d6b6acfef7e6a7f3082cd Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Wed, 13 Oct 2021 05:26:33 +0000 Subject: [PATCH 192/385] 8275186: Suppress warnings on non-serializable array component types in xml Reviewed-by: joehw --- .../apache/bcel/internal/generic/TargetLostException.java | 1 + .../apache/xerces/internal/impl/dv/DatatypeException.java | 5 +++-- .../internal/impl/io/MalformedByteSequenceException.java | 1 + .../apache/xerces/internal/impl/xs/XMLSchemaException.java | 1 + .../internal/impl/xs/traversers/XSDComplexTypeTraverser.java | 3 ++- .../org/apache/xpath/internal/axes/UnionPathIterator.java | 5 +++-- 6 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/TargetLostException.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/TargetLostException.java index e0aa29747f5..22c676c0124 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/TargetLostException.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/TargetLostException.java @@ -51,6 +51,7 @@ package com.sun.org.apache.bcel.internal.generic; public final class TargetLostException extends Exception { private static final long serialVersionUID = -6857272667645328384L; + @SuppressWarnings("serial") // Array component type is not Serializable private final InstructionHandle[] targets; diff --git a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/dv/DatatypeException.java b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/dv/DatatypeException.java index 4e99689ab02..43c63e724ce 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/dv/DatatypeException.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/dv/DatatypeException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -35,7 +35,7 @@ import jdk.xml.internal.SecuritySupport; * * @author Sandy Gao, IBM * - * @LastModified: Sep 2017 + * @LastModified: Oct 2021 */ public class DatatypeException extends Exception { @@ -44,6 +44,7 @@ public class DatatypeException extends Exception { // used to store error code and error substitution arguments protected String key; + @SuppressWarnings("serial") // Array component type is not Serializable protected Object[] args; /** diff --git a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/io/MalformedByteSequenceException.java b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/io/MalformedByteSequenceException.java index fb5bd19de63..b2b8d1f6110 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/io/MalformedByteSequenceException.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/io/MalformedByteSequenceException.java @@ -58,6 +58,7 @@ public class MalformedByteSequenceException extends CharConversionException { private String fKey; /** replacement arguements for the error message **/ + @SuppressWarnings("serial") // Array component type is not Serializable private Object[] fArguments; /** message text for this message, initially null **/ diff --git a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xs/XMLSchemaException.java b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xs/XMLSchemaException.java index 73a1cfdace8..90d90019e4a 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xs/XMLSchemaException.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xs/XMLSchemaException.java @@ -36,6 +36,7 @@ public class XMLSchemaException extends Exception { // store a datatype error: error code plus the arguments String key; + @SuppressWarnings("serial") // Array component type is not Serializable Object[] args; // report an error diff --git a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xs/traversers/XSDComplexTypeTraverser.java b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xs/traversers/XSDComplexTypeTraverser.java index 3011e7db9d3..e58819e593f 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xs/traversers/XSDComplexTypeTraverser.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/xs/traversers/XSDComplexTypeTraverser.java @@ -62,7 +62,7 @@ import org.w3c.dom.Element; * * * @xerces.internal - * @LastModified: Apr 2019 + * @LastModified: Oct 2021 */ class XSDComplexTypeTraverser extends XSDAbstractParticleTraverser { @@ -131,6 +131,7 @@ class XSDComplexTypeTraverser extends XSDAbstractParticleTraverser { private static final long serialVersionUID = 6802729912091130335L; + @SuppressWarnings("serial") // Array component type is not Serializable Object[] errorSubstText=null; @SuppressWarnings("serial") // Type of field is not Serializable Element errorElem = null; diff --git a/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/axes/UnionPathIterator.java b/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/axes/UnionPathIterator.java index 0b67aed9046..175e6602e43 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/axes/UnionPathIterator.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/axes/UnionPathIterator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -39,7 +39,7 @@ import java.util.List; * As each node is iterated via nextNode(), the node is also stored * in the NodeVector, so that previousNode() can easily be done. * @xsl.usage advanced - * @LastModified: May 2020 + * @LastModified: Oct 2021 */ public class UnionPathIterator extends LocPathIterator implements Cloneable, DTMIterator, java.io.Serializable, PathComponent @@ -470,6 +470,7 @@ public class UnionPathIterator extends LocPathIterator * path contained in the union expression. * @serial */ + @SuppressWarnings("serial") // Array component type is not Serializable protected DTMIterator[] m_iterators; /** -- GitLab From cf828673a9b76fd3f26db9a3f714166861a65c9e Mon Sep 17 00:00:00 2001 From: Martin Doerr Date: Wed, 13 Oct 2021 07:12:52 +0000 Subject: [PATCH 193/385] 8275049: [ZGC] missing null check in ZNMethod::log_register Reviewed-by: nradomski, eosterlund, pliden --- src/hotspot/share/gc/z/zNMethod.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/gc/z/zNMethod.cpp b/src/hotspot/share/gc/z/zNMethod.cpp index d492a1b6609..71f510c2e81 100644 --- a/src/hotspot/share/gc/z/zNMethod.cpp +++ b/src/hotspot/share/gc/z/zNMethod.cpp @@ -126,8 +126,10 @@ void ZNMethod::log_register(const nmethod* nm) { oop* const begin = nm->oops_begin(); oop* const end = nm->oops_end(); for (oop* p = begin; p < end; p++) { + const oop o = Atomic::load(p); // C1 PatchingStub may replace it concurrently. + const char* external_name = (o == nullptr) ? "N/A" : o->klass()->external_name(); log_oops.print(" Oop[" SIZE_FORMAT "] " PTR_FORMAT " (%s)", - (p - begin), p2i(*p), (*p)->klass()->external_name()); + (p - begin), p2i(o), external_name); } } -- GitLab From 337b73a459ba24aa529b7b097617434be1d0030e Mon Sep 17 00:00:00 2001 From: Niklas Radomski Date: Wed, 13 Oct 2021 07:36:52 +0000 Subject: [PATCH 194/385] 8274851: [PPC64] Port zgc to linux on ppc64le Reviewed-by: ihse, pliden, mdoerr, eosterlund --- make/autoconf/jvm-features.m4 | 7 + make/hotspot/gensrc/GensrcAdlc.gmk | 1 + src/hotspot/cpu/ppc/assembler_ppc.hpp | 3 + .../cpu/ppc/gc/z/zBarrierSetAssembler_ppc.cpp | 567 ++++++++++++++++++ .../cpu/ppc/gc/z/zBarrierSetAssembler_ppc.hpp | 86 +++ src/hotspot/cpu/ppc/gc/z/zGlobals_ppc.cpp | 203 +++++++ src/hotspot/cpu/ppc/gc/z/zGlobals_ppc.hpp | 36 ++ src/hotspot/cpu/ppc/gc/z/z_ppc.ad | 298 +++++++++ src/hotspot/cpu/ppc/ppc.ad | 19 +- src/hotspot/cpu/ppc/vmreg_ppc.hpp | 19 +- .../linux_ppc/gc/z/zSyscall_linux_ppc.hpp | 42 ++ 11 files changed, 1273 insertions(+), 8 deletions(-) create mode 100644 src/hotspot/cpu/ppc/gc/z/zBarrierSetAssembler_ppc.cpp create mode 100644 src/hotspot/cpu/ppc/gc/z/zBarrierSetAssembler_ppc.hpp create mode 100644 src/hotspot/cpu/ppc/gc/z/zGlobals_ppc.cpp create mode 100644 src/hotspot/cpu/ppc/gc/z/zGlobals_ppc.hpp create mode 100644 src/hotspot/cpu/ppc/gc/z/z_ppc.ad create mode 100644 src/hotspot/os_cpu/linux_ppc/gc/z/zSyscall_linux_ppc.hpp diff --git a/make/autoconf/jvm-features.m4 b/make/autoconf/jvm-features.m4 index a4d0bf62ec2..1f76c323129 100644 --- a/make/autoconf/jvm-features.m4 +++ b/make/autoconf/jvm-features.m4 @@ -357,6 +357,13 @@ AC_DEFUN_ONCE([JVM_FEATURES_CHECK_ZGC], AC_MSG_RESULT([no, $OPENJDK_TARGET_OS-$OPENJDK_TARGET_CPU]) AVAILABLE=false fi + elif test "x$OPENJDK_TARGET_CPU" = "xppc64le"; then + if test "x$OPENJDK_TARGET_OS" = "xlinux"; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no, $OPENJDK_TARGET_OS-$OPENJDK_TARGET_CPU]) + AVAILABLE=false + fi else AC_MSG_RESULT([no, $OPENJDK_TARGET_OS-$OPENJDK_TARGET_CPU]) AVAILABLE=false diff --git a/make/hotspot/gensrc/GensrcAdlc.gmk b/make/hotspot/gensrc/GensrcAdlc.gmk index ba8165c2ff0..f9f1bb38688 100644 --- a/make/hotspot/gensrc/GensrcAdlc.gmk +++ b/make/hotspot/gensrc/GensrcAdlc.gmk @@ -155,6 +155,7 @@ ifeq ($(call check-jvm-feature, compiler2), true) ifeq ($(call check-jvm-feature, zgc), true) AD_SRC_FILES += $(call uniq, $(wildcard $(foreach d, $(AD_SRC_ROOTS), \ $d/cpu/$(HOTSPOT_TARGET_CPU_ARCH)/gc/z/z_$(HOTSPOT_TARGET_CPU).ad \ + $d/cpu/$(HOTSPOT_TARGET_CPU_ARCH)/gc/z/z_$(HOTSPOT_TARGET_CPU_ARCH).ad \ ))) endif diff --git a/src/hotspot/cpu/ppc/assembler_ppc.hpp b/src/hotspot/cpu/ppc/assembler_ppc.hpp index d6d58262de5..2f4287a9553 100644 --- a/src/hotspot/cpu/ppc/assembler_ppc.hpp +++ b/src/hotspot/cpu/ppc/assembler_ppc.hpp @@ -47,6 +47,9 @@ class Address { Address(Register b, address d = 0) : _base(b), _index(noreg), _disp((intptr_t)d) {} + Address(Register b, ByteSize d) + : _base(b), _index(noreg), _disp((intptr_t)d) {} + Address(Register b, intptr_t d) : _base(b), _index(noreg), _disp(d) {} diff --git a/src/hotspot/cpu/ppc/gc/z/zBarrierSetAssembler_ppc.cpp b/src/hotspot/cpu/ppc/gc/z/zBarrierSetAssembler_ppc.cpp new file mode 100644 index 00000000000..26c3bf371f3 --- /dev/null +++ b/src/hotspot/cpu/ppc/gc/z/zBarrierSetAssembler_ppc.cpp @@ -0,0 +1,567 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021 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. + */ + +#include "asm/register.hpp" +#include "precompiled.hpp" +#include "asm/macroAssembler.inline.hpp" +#include "code/codeBlob.hpp" +#include "code/vmreg.inline.hpp" +#include "gc/z/zBarrier.inline.hpp" +#include "gc/z/zBarrierSet.hpp" +#include "gc/z/zBarrierSetAssembler.hpp" +#include "gc/z/zBarrierSetRuntime.hpp" +#include "gc/z/zThreadLocalData.hpp" +#include "memory/resourceArea.hpp" +#include "register_ppc.hpp" +#include "runtime/sharedRuntime.hpp" +#include "utilities/globalDefinitions.hpp" +#include "utilities/macros.hpp" +#ifdef COMPILER1 +#include "c1/c1_LIRAssembler.hpp" +#include "c1/c1_MacroAssembler.hpp" +#include "gc/z/c1/zBarrierSetC1.hpp" +#endif // COMPILER1 +#ifdef COMPILER2 +#include "gc/z/c2/zBarrierSetC2.hpp" +#endif // COMPILER2 + +#undef __ +#define __ masm-> + +void ZBarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, + Register base, RegisterOrConstant ind_or_offs, Register dst, + Register tmp1, Register tmp2, + MacroAssembler::PreservationLevel preservation_level, Label *L_handle_null) { + __ block_comment("load_at (zgc) {"); + + // Check whether a special gc barrier is required for this particular load + // (e.g. whether it's a reference load or not) + if (!ZBarrierSet::barrier_needed(decorators, type)) { + BarrierSetAssembler::load_at(masm, decorators, type, base, ind_or_offs, dst, + tmp1, tmp2, preservation_level, L_handle_null); + return; + } + + if (ind_or_offs.is_register()) { + assert_different_registers(base, ind_or_offs.as_register(), tmp1, tmp2, R0, noreg); + assert_different_registers(dst, ind_or_offs.as_register(), tmp1, tmp2, R0, noreg); + } else { + assert_different_registers(base, tmp1, tmp2, R0, noreg); + assert_different_registers(dst, tmp1, tmp2, R0, noreg); + } + + /* ==== Load the pointer using the standard implementation for the actual heap access + and the decompression of compressed pointers ==== */ + // Result of 'load_at' (standard implementation) will be written back to 'dst'. + // As 'base' is required for the C-call, it must be reserved in case of a register clash. + Register saved_base = base; + if (base == dst) { + __ mr(tmp2, base); + saved_base = tmp2; + } + + BarrierSetAssembler::load_at(masm, decorators, type, base, ind_or_offs, dst, + tmp1, noreg, preservation_level, L_handle_null); + + /* ==== Check whether pointer is dirty ==== */ + Label skip_barrier; + + // Load bad mask into scratch register. + __ ld(tmp1, (intptr_t) ZThreadLocalData::address_bad_mask_offset(), R16_thread); + + // The color bits of the to-be-tested pointer do not have to be equivalent to the 'bad_mask' testing bits. + // A pointer is classified as dirty if any of the color bits that also match the bad mask is set. + // Conversely, it follows that the logical AND of the bad mask and the pointer must be zero + // if the pointer is not dirty. + // Only dirty pointers must be processed by this barrier, so we can skip it in case the latter condition holds true. + __ and_(tmp1, tmp1, dst); + __ beq(CCR0, skip_barrier); + + /* ==== Invoke barrier ==== */ + int nbytes_save = 0; + + const bool needs_frame = preservation_level >= MacroAssembler::PRESERVATION_FRAME_LR; + const bool preserve_gp_registers = preservation_level >= MacroAssembler::PRESERVATION_FRAME_LR_GP_REGS; + const bool preserve_fp_registers = preservation_level >= MacroAssembler::PRESERVATION_FRAME_LR_GP_FP_REGS; + + const bool preserve_R3 = dst != R3_ARG1; + + if (needs_frame) { + if (preserve_gp_registers) { + nbytes_save = (preserve_fp_registers + ? MacroAssembler::num_volatile_gp_regs + MacroAssembler::num_volatile_fp_regs + : MacroAssembler::num_volatile_gp_regs) * BytesPerWord; + nbytes_save -= preserve_R3 ? 0 : BytesPerWord; + __ save_volatile_gprs(R1_SP, -nbytes_save, preserve_fp_registers, preserve_R3); + } + + __ save_LR_CR(tmp1); + __ push_frame_reg_args(nbytes_save, tmp1); + } + + // Setup arguments + if (saved_base != R3_ARG1) { + __ mr_if_needed(R3_ARG1, dst); + __ add(R4_ARG2, ind_or_offs, saved_base); + } else if (dst != R4_ARG2) { + __ add(R4_ARG2, ind_or_offs, saved_base); + __ mr(R3_ARG1, dst); + } else { + __ add(R0, ind_or_offs, saved_base); + __ mr(R3_ARG1, dst); + __ mr(R4_ARG2, R0); + } + + __ call_VM_leaf(ZBarrierSetRuntime::load_barrier_on_oop_field_preloaded_addr(decorators)); + + Register result = R3_RET; + if (needs_frame) { + __ pop_frame(); + __ restore_LR_CR(tmp1); + + if (preserve_R3) { + __ mr(R0, R3_RET); + result = R0; + } + + if (preserve_gp_registers) { + __ restore_volatile_gprs(R1_SP, -nbytes_save, preserve_fp_registers, preserve_R3); + } + } + __ mr_if_needed(dst, result); + + __ bind(skip_barrier); + __ block_comment("} load_at (zgc)"); +} + +#ifdef ASSERT +// The Z store barrier only verifies the pointers it is operating on and is thus a sole debugging measure. +void ZBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, + Register base, RegisterOrConstant ind_or_offs, Register val, + Register tmp1, Register tmp2, Register tmp3, + MacroAssembler::PreservationLevel preservation_level) { + __ block_comment("store_at (zgc) {"); + + // If the 'val' register is 'noreg', the to-be-stored value is a null pointer. + if (is_reference_type(type) && val != noreg) { + __ ld(tmp1, in_bytes(ZThreadLocalData::address_bad_mask_offset()), R16_thread); + __ and_(tmp1, tmp1, val); + __ asm_assert_eq("Detected dirty pointer on the heap in Z store barrier"); + } + + // Store value + BarrierSetAssembler::store_at(masm, decorators, type, base, ind_or_offs, val, tmp1, tmp2, tmp3, preservation_level); + + __ block_comment("} store_at (zgc)"); +} +#endif // ASSERT + +void ZBarrierSetAssembler::arraycopy_prologue(MacroAssembler *masm, DecoratorSet decorators, BasicType component_type, + Register src, Register dst, Register count, + Register preserve1, Register preserve2) { + __ block_comment("arraycopy_prologue (zgc) {"); + + /* ==== Check whether a special gc barrier is required for this particular load ==== */ + if (!is_reference_type(component_type)) { + return; + } + + Label skip_barrier; + + // Fast path: Array is of length zero + __ cmpdi(CCR0, count, 0); + __ beq(CCR0, skip_barrier); + + /* ==== Ensure register sanity ==== */ + Register tmp_R11 = R11_scratch1; + + assert_different_registers(src, dst, count, tmp_R11, noreg); + if (preserve1 != noreg) { + // Not technically required, but unlikely being intended. + assert_different_registers(preserve1, preserve2); + } + + /* ==== Invoke barrier (slowpath) ==== */ + int nbytes_save = 0; + + { + assert(!noreg->is_volatile(), "sanity"); + + if (preserve1->is_volatile()) { + __ std(preserve1, -BytesPerWord * ++nbytes_save, R1_SP); + } + + if (preserve2->is_volatile() && preserve1 != preserve2) { + __ std(preserve2, -BytesPerWord * ++nbytes_save, R1_SP); + } + + __ std(src, -BytesPerWord * ++nbytes_save, R1_SP); + __ std(dst, -BytesPerWord * ++nbytes_save, R1_SP); + __ std(count, -BytesPerWord * ++nbytes_save, R1_SP); + + __ save_LR_CR(tmp_R11); + __ push_frame_reg_args(nbytes_save, tmp_R11); + } + + // ZBarrierSetRuntime::load_barrier_on_oop_array_addr(src, count) + if (count == R3_ARG1) { + if (src == R4_ARG2) { + // Arguments are provided in reverse order + __ mr(tmp_R11, count); + __ mr(R3_ARG1, src); + __ mr(R4_ARG2, tmp_R11); + } else { + __ mr(R4_ARG2, count); + __ mr(R3_ARG1, src); + } + } else { + __ mr_if_needed(R3_ARG1, src); + __ mr_if_needed(R4_ARG2, count); + } + + __ call_VM_leaf(ZBarrierSetRuntime::load_barrier_on_oop_array_addr()); + + __ pop_frame(); + __ restore_LR_CR(tmp_R11); + + { + __ ld(count, -BytesPerWord * nbytes_save--, R1_SP); + __ ld(dst, -BytesPerWord * nbytes_save--, R1_SP); + __ ld(src, -BytesPerWord * nbytes_save--, R1_SP); + + if (preserve2->is_volatile() && preserve1 != preserve2) { + __ ld(preserve2, -BytesPerWord * nbytes_save--, R1_SP); + } + + if (preserve1->is_volatile()) { + __ ld(preserve1, -BytesPerWord * nbytes_save--, R1_SP); + } + } + + __ bind(skip_barrier); + + __ block_comment("} arraycopy_prologue (zgc)"); +} + +void ZBarrierSetAssembler::try_resolve_jobject_in_native(MacroAssembler* masm, Register dst, Register jni_env, + Register obj, Register tmp, Label& slowpath) { + __ block_comment("try_resolve_jobject_in_native (zgc) {"); + + assert_different_registers(jni_env, obj, tmp); + + // Resolve the pointer using the standard implementation for weak tag handling and pointer verfication. + BarrierSetAssembler::try_resolve_jobject_in_native(masm, dst, jni_env, obj, tmp, slowpath); + + // Check whether pointer is dirty. + __ ld(tmp, + in_bytes(ZThreadLocalData::address_bad_mask_offset() - JavaThread::jni_environment_offset()), + jni_env); + + __ and_(tmp, obj, tmp); + __ bne(CCR0, slowpath); + + __ block_comment("} try_resolve_jobject_in_native (zgc)"); +} + +#undef __ + +#ifdef COMPILER1 +#define __ ce->masm()-> + +// Code emitted by LIR node "LIR_OpZLoadBarrierTest" which in turn is emitted by ZBarrierSetC1::load_barrier. +// The actual compare and branch instructions are represented as stand-alone LIR nodes. +void ZBarrierSetAssembler::generate_c1_load_barrier_test(LIR_Assembler* ce, + LIR_Opr ref) const { + __ block_comment("load_barrier_test (zgc) {"); + + __ ld(R0, in_bytes(ZThreadLocalData::address_bad_mask_offset()), R16_thread); + __ andr(R0, R0, ref->as_pointer_register()); + __ cmpdi(CCR5 /* as mandated by LIR node */, R0, 0); + + __ block_comment("} load_barrier_test (zgc)"); +} + +// Code emitted by code stub "ZLoadBarrierStubC1" which in turn is emitted by ZBarrierSetC1::load_barrier. +// Invokes the runtime stub which is defined just below. +void ZBarrierSetAssembler::generate_c1_load_barrier_stub(LIR_Assembler* ce, + ZLoadBarrierStubC1* stub) const { + __ block_comment("c1_load_barrier_stub (zgc) {"); + + __ bind(*stub->entry()); + + /* ==== Determine relevant data registers and ensure register sanity ==== */ + Register ref = stub->ref()->as_register(); + Register ref_addr = noreg; + + // Determine reference address + if (stub->tmp()->is_valid()) { + // 'tmp' register is given, so address might have an index or a displacement. + ce->leal(stub->ref_addr(), stub->tmp()); + ref_addr = stub->tmp()->as_pointer_register(); + } else { + // 'tmp' register is not given, so address must have neither an index nor a displacement. + // The address' base register is thus usable as-is. + assert(stub->ref_addr()->as_address_ptr()->disp() == 0, "illegal displacement"); + assert(!stub->ref_addr()->as_address_ptr()->index()->is_valid(), "illegal index"); + + ref_addr = stub->ref_addr()->as_address_ptr()->base()->as_pointer_register(); + } + + assert_different_registers(ref, ref_addr, R0, noreg); + + /* ==== Invoke stub ==== */ + // Pass arguments via stack. The stack pointer will be bumped by the stub. + __ std(ref, (intptr_t) -1 * BytesPerWord, R1_SP); + __ std(ref_addr, (intptr_t) -2 * BytesPerWord, R1_SP); + + __ load_const_optimized(R0, stub->runtime_stub()); + __ call_stub(R0); + + // The runtime stub passes the result via the R0 register, overriding the previously-loaded stub address. + __ mr_if_needed(ref, R0); + __ b(*stub->continuation()); + + __ block_comment("} c1_load_barrier_stub (zgc)"); +} + +#undef __ +#define __ sasm-> + +// Code emitted by runtime code stub which in turn is emitted by ZBarrierSetC1::generate_c1_runtime_stubs. +void ZBarrierSetAssembler::generate_c1_load_barrier_runtime_stub(StubAssembler* sasm, + DecoratorSet decorators) const { + __ block_comment("c1_load_barrier_runtime_stub (zgc) {"); + + const int stack_parameters = 2; + const int nbytes_save = (MacroAssembler::num_volatile_regs + stack_parameters) * BytesPerWord; + + __ save_volatile_gprs(R1_SP, -nbytes_save); + __ save_LR_CR(R0); + + // Load arguments back again from the stack. + __ ld(R3_ARG1, (intptr_t) -1 * BytesPerWord, R1_SP); // ref + __ ld(R4_ARG2, (intptr_t) -2 * BytesPerWord, R1_SP); // ref_addr + + __ push_frame_reg_args(nbytes_save, R0); + + __ call_VM_leaf(ZBarrierSetRuntime::load_barrier_on_oop_field_preloaded_addr(decorators)); + + __ verify_oop(R3_RET, "Bad pointer after barrier invocation"); + __ mr(R0, R3_RET); + + __ pop_frame(); + __ restore_LR_CR(R3_RET); + __ restore_volatile_gprs(R1_SP, -nbytes_save); + + __ blr(); + + __ block_comment("} c1_load_barrier_runtime_stub (zgc)"); +} + +#undef __ +#endif // COMPILER1 + +#ifdef COMPILER2 + +OptoReg::Name ZBarrierSetAssembler::refine_register(const Node* node, OptoReg::Name opto_reg) const { + if (!OptoReg::is_reg(opto_reg)) { + return OptoReg::Bad; + } + + VMReg vm_reg = OptoReg::as_VMReg(opto_reg); + if ((vm_reg->is_Register() || vm_reg ->is_FloatRegister()) && (opto_reg & 1) != 0) { + return OptoReg::Bad; + } + + return opto_reg; +} + +#define __ _masm-> + +class ZSaveLiveRegisters { + + private: + MacroAssembler* _masm; + RegMask _reg_mask; + Register _result_reg; + + public: + ZSaveLiveRegisters(MacroAssembler *masm, ZLoadBarrierStubC2 *stub) + : _masm(masm), _reg_mask(stub->live()), _result_reg(stub->ref()) { + + const int total_regs_amount = iterate_over_register_mask(ACTION_SAVE); + + __ save_LR_CR(R0); + __ push_frame_reg_args(total_regs_amount * BytesPerWord, R0); + } + + ~ZSaveLiveRegisters() { + __ pop_frame(); + __ restore_LR_CR(R0); + + iterate_over_register_mask(ACTION_RESTORE); + } + + private: + enum IterationAction : int { + ACTION_SAVE = 0, + ACTION_RESTORE = 1 + }; + + int iterate_over_register_mask(IterationAction action) { + int reg_save_index = 0; + RegMaskIterator live_regs_iterator(_reg_mask); + + while(live_regs_iterator.has_next()) { + const OptoReg::Name opto_reg = live_regs_iterator.next(); + + // Filter out stack slots (spilled registers, i.e., stack-allocated registers). + if (!OptoReg::is_reg(opto_reg)) { + continue; + } + + const VMReg vm_reg = OptoReg::as_VMReg(opto_reg); + if (vm_reg->is_Register()) { + Register std_reg = vm_reg->as_Register(); + + // '_result_reg' will hold the end result of the operation. Its content must thus not be preserved. + if (std_reg == _result_reg) { + continue; + } + + if (std_reg->encoding() >= R2->encoding() && std_reg->encoding() <= R12->encoding()) { + reg_save_index++; + + if (action == ACTION_SAVE) { + _masm->std(std_reg, (intptr_t) -reg_save_index * BytesPerWord, R1_SP); + } else if (action == ACTION_RESTORE) { + _masm->ld(std_reg, (intptr_t) -reg_save_index * BytesPerWord, R1_SP); + } else { + fatal("Sanity"); + } + } + } else if (vm_reg->is_FloatRegister()) { + FloatRegister fp_reg = vm_reg->as_FloatRegister(); + if (fp_reg->encoding() >= F0->encoding() && fp_reg->encoding() <= F13->encoding()) { + reg_save_index++; + + if (action == ACTION_SAVE) { + _masm->stfd(fp_reg, (intptr_t) -reg_save_index * BytesPerWord, R1_SP); + } else if (action == ACTION_RESTORE) { + _masm->lfd(fp_reg, (intptr_t) -reg_save_index * BytesPerWord, R1_SP); + } else { + fatal("Sanity"); + } + } + } else if (vm_reg->is_ConditionRegister()) { + // NOP. Conditions registers are covered by save_LR_CR + } else { + if (vm_reg->is_VectorRegister()) { + fatal("Vector registers are unsupported. Found register %s", vm_reg->name()); + } else if (vm_reg->is_SpecialRegister()) { + fatal("Special registers are unsupported. Found register %s", vm_reg->name()); + } else { + fatal("Register type is not known"); + } + } + } + + return reg_save_index; + } +}; + +#undef __ +#define __ _masm-> + +class ZSetupArguments { + private: + MacroAssembler* const _masm; + const Register _ref; + const Address _ref_addr; + + public: + ZSetupArguments(MacroAssembler* masm, ZLoadBarrierStubC2* stub) : + _masm(masm), + _ref(stub->ref()), + _ref_addr(stub->ref_addr()) { + + // Desired register/argument configuration: + // _ref: R3_ARG1 + // _ref_addr: R4_ARG2 + + // '_ref_addr' can be unspecified. In that case, the barrier will not heal the reference. + if (_ref_addr.base() == noreg) { + assert_different_registers(_ref, R0, noreg); + + __ mr_if_needed(R3_ARG1, _ref); + __ li(R4_ARG2, 0); + } else { + assert_different_registers(_ref, _ref_addr.base(), R0, noreg); + assert(!_ref_addr.index()->is_valid(), "reference addresses must not contain an index component"); + + if (_ref != R4_ARG2) { + // Calculate address first as the address' base register might clash with R4_ARG2 + __ add(R4_ARG2, (intptr_t) _ref_addr.disp(), _ref_addr.base()); + __ mr_if_needed(R3_ARG1, _ref); + } else if (_ref_addr.base() != R3_ARG1) { + __ mr(R3_ARG1, _ref); + __ add(R4_ARG2, (intptr_t) _ref_addr.disp(), _ref_addr.base()); // Cloberring _ref + } else { + // Arguments are provided in inverse order (i.e. _ref == R4_ARG2, _ref_addr == R3_ARG1) + __ mr(R0, _ref); + __ add(R4_ARG2, (intptr_t) _ref_addr.disp(), _ref_addr.base()); + __ mr(R3_ARG1, R0); + } + } + } +}; + +#undef __ +#define __ masm-> + +void ZBarrierSetAssembler::generate_c2_load_barrier_stub(MacroAssembler* masm, ZLoadBarrierStubC2* stub) const { + __ block_comment("generate_c2_load_barrier_stub (zgc) {"); + + __ bind(*stub->entry()); + + Register ref = stub->ref(); + Address ref_addr = stub->ref_addr(); + + assert_different_registers(ref, ref_addr.base()); + + { + ZSaveLiveRegisters save_live_registers(masm, stub); + ZSetupArguments setup_arguments(masm, stub); + + __ call_VM_leaf(stub->slow_path()); + __ mr_if_needed(ref, R3_RET); + } + + __ b(*stub->continuation()); + + __ block_comment("} generate_c2_load_barrier_stub (zgc)"); +} + +#undef __ +#endif // COMPILER2 diff --git a/src/hotspot/cpu/ppc/gc/z/zBarrierSetAssembler_ppc.hpp b/src/hotspot/cpu/ppc/gc/z/zBarrierSetAssembler_ppc.hpp new file mode 100644 index 00000000000..e2ff1bf53ae --- /dev/null +++ b/src/hotspot/cpu/ppc/gc/z/zBarrierSetAssembler_ppc.hpp @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021 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. + */ + +#ifndef CPU_PPC_GC_Z_ZBARRIERSETASSEMBLER_PPC_HPP +#define CPU_PPC_GC_Z_ZBARRIERSETASSEMBLER_PPC_HPP + +#include "code/vmreg.hpp" +#include "oops/accessDecorators.hpp" +#ifdef COMPILER2 +#include "opto/optoreg.hpp" +#endif // COMPILER2 + +#ifdef COMPILER1 +class LIR_Assembler; +class LIR_OprDesc; +typedef LIR_OprDesc* LIR_Opr; +class StubAssembler; +class ZLoadBarrierStubC1; +#endif // COMPILER1 + +#ifdef COMPILER2 +class Node; +class ZLoadBarrierStubC2; +#endif // COMPILER2 + +class ZBarrierSetAssembler : public ZBarrierSetAssemblerBase { +public: + virtual void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, + Register base, RegisterOrConstant ind_or_offs, Register dst, + Register tmp1, Register tmp2, + MacroAssembler::PreservationLevel preservation_level, Label *L_handle_null = NULL); + +#ifdef ASSERT + virtual void store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, + Register base, RegisterOrConstant ind_or_offs, Register val, + Register tmp1, Register tmp2, Register tmp3, + MacroAssembler::PreservationLevel preservation_level); +#endif // ASSERT + + virtual void arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, BasicType type, + Register src, Register dst, Register count, + Register preserve1, Register preserve2); + + virtual void try_resolve_jobject_in_native(MacroAssembler* masm, Register dst, Register jni_env, + Register obj, Register tmp, Label& slowpath); + +#ifdef COMPILER1 + void generate_c1_load_barrier_test(LIR_Assembler* ce, + LIR_Opr ref) const; + + void generate_c1_load_barrier_stub(LIR_Assembler* ce, + ZLoadBarrierStubC1* stub) const; + + void generate_c1_load_barrier_runtime_stub(StubAssembler* sasm, + DecoratorSet decorators) const; +#endif // COMPILER1 + +#ifdef COMPILER2 + OptoReg::Name refine_register(const Node* node, OptoReg::Name opto_reg) const; + + void generate_c2_load_barrier_stub(MacroAssembler* masm, ZLoadBarrierStubC2* stub) const; +#endif // COMPILER2 +}; + +#endif // CPU_AARCH64_GC_Z_ZBARRIERSETASSEMBLER_AARCH64_HPP diff --git a/src/hotspot/cpu/ppc/gc/z/zGlobals_ppc.cpp b/src/hotspot/cpu/ppc/gc/z/zGlobals_ppc.cpp new file mode 100644 index 00000000000..93c2f9b4dc4 --- /dev/null +++ b/src/hotspot/cpu/ppc/gc/z/zGlobals_ppc.cpp @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021 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. + */ + +#include "precompiled.hpp" +#include "gc/shared/gcLogPrecious.hpp" +#include "gc/shared/gc_globals.hpp" +#include "gc/z/zGlobals.hpp" +#include "runtime/globals.hpp" +#include "runtime/os.hpp" +#include "utilities/globalDefinitions.hpp" +#include "utilities/powerOfTwo.hpp" +#include + +#ifdef LINUX +#include +#endif // LINUX + +// +// The overall memory layouts across different power platforms are similar and only differ with regards to +// the position of the highest addressable bit; the position of the metadata bits and the size of the actual +// addressable heap address space are adjusted accordingly. +// +// The following memory schema shows an exemplary layout in which bit '45' is the highest addressable bit. +// It is assumed that this virtual memroy address space layout is predominant on the power platform. +// +// Standard Address Space & Pointer Layout +// --------------------------------------- +// +// +--------------------------------+ 0x00007FFFFFFFFFFF (127 TiB - 1) +// . . +// . . +// . . +// +--------------------------------+ 0x0000140000000000 (20 TiB) +// | Remapped View | +// +--------------------------------+ 0x0000100000000000 (16 TiB) +// . . +// +--------------------------------+ 0x00000c0000000000 (12 TiB) +// | Marked1 View | +// +--------------------------------+ 0x0000080000000000 (8 TiB) +// | Marked0 View | +// +--------------------------------+ 0x0000040000000000 (4 TiB) +// . . +// +--------------------------------+ 0x0000000000000000 +// +// 6 4 4 4 4 +// 3 6 5 2 1 0 +// +--------------------+----+-----------------------------------------------+ +// |00000000 00000000 00|1111|11 11111111 11111111 11111111 11111111 11111111| +// +--------------------+----+-----------------------------------------------+ +// | | | +// | | * 41-0 Object Offset (42-bits, 4TB address space) +// | | +// | * 45-42 Metadata Bits (4-bits) 0001 = Marked0 (Address view 4-8TB) +// | 0010 = Marked1 (Address view 8-12TB) +// | 0100 = Remapped (Address view 16-20TB) +// | 1000 = Finalizable (Address view N/A) +// | +// * 63-46 Fixed (18-bits, always zero) +// + +// Maximum value as per spec (Power ISA v2.07): 2 ^ 60 bytes, i.e. 1 EiB (exbibyte) +static const unsigned int MAXIMUM_MAX_ADDRESS_BIT = 60; + +// Most modern power processors provide an address space with not more than 45 bit addressable bit, +// that is an address space of 32 TiB in size. +static const unsigned int DEFAULT_MAX_ADDRESS_BIT = 45; + +// Minimum value returned, if probing fails: 64 GiB +static const unsigned int MINIMUM_MAX_ADDRESS_BIT = 36; + +// Determines the highest addressable bit of the virtual address space (depends on platform) +// by trying to interact with memory in that address range, +// i.e. by syncing existing mappings (msync) or by temporarily mapping the memory area (mmap). +// If one of those operations succeeds, it is proven that the targeted memory area is within the virtual address space. +// +// To reduce the number of required system calls to a bare minimum, the DEFAULT_MAX_ADDRESS_BIT is intentionally set +// lower than what the ABI would theoretically permit. +// Such an avoidance strategy, however, might impose unnecessary limits on processors that exceed this limit. +// If DEFAULT_MAX_ADDRESS_BIT is addressable, the next higher bit will be tested as well to ensure that +// the made assumption does not artificially restrict the memory availability. +static unsigned int probe_valid_max_address_bit(size_t init_bit, size_t min_bit) { + assert(init_bit >= min_bit, "Sanity"); + assert(init_bit <= MAXIMUM_MAX_ADDRESS_BIT, "Test bit is outside the assumed address space range"); + +#ifdef LINUX + unsigned int max_valid_address_bit = 0; + void* last_allocatable_address = nullptr; + + const unsigned int page_size = os::vm_page_size(); + + for (size_t i = init_bit; i >= min_bit; --i) { + void* base_addr = (void*) (((unsigned long) 1U) << i); + + /* ==== Try msync-ing already mapped memory page ==== */ + if (msync(base_addr, page_size, MS_ASYNC) == 0) { + // The page of the given address was synced by the linux kernel and must thus be both, mapped and valid. + max_valid_address_bit = i; + break; + } + if (errno != ENOMEM) { + // An unexpected error occurred, i.e. an error not indicating that the targeted memory page is unmapped, + // but pointing out another type of issue. + // Even though this should never happen, those issues may come up due to undefined behavior. +#ifdef ASSERT + fatal("Received '%s' while probing the address space for the highest valid bit", os::errno_name(errno)); +#else // ASSERT + log_warning_p(gc)("Received '%s' while probing the address space for the highest valid bit", os::errno_name(errno)); +#endif // ASSERT + continue; + } + + /* ==== Try mapping memory page on our own ==== */ + last_allocatable_address = mmap(base_addr, page_size, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE, -1, 0); + if (last_allocatable_address != MAP_FAILED) { + munmap(last_allocatable_address, page_size); + } + + if (last_allocatable_address == base_addr) { + // As the linux kernel mapped exactly the page we have requested, the address must be valid. + max_valid_address_bit = i; + break; + } + + log_info_p(gc, init)("Probe failed for bit '%zu'", i); + } + + if (max_valid_address_bit == 0) { + // Probing did not bring up any usable address bit. + // As an alternative, the VM evaluates the address returned by mmap as it is expected that the reserved page + // will be close to the probed address that was out-of-range. + // As per mmap(2), "the kernel [will take] [the address] as a hint about where to + // place the mapping; on Linux, the mapping will be created at a nearby page boundary". + // It should thus be a "close enough" approximation to the real virtual memory address space limit. + // + // This recovery strategy is only applied in production builds. + // In debug builds, an assertion in 'ZPlatformAddressOffsetBits' will bail out the VM to indicate that + // the assumed address space is no longer up-to-date. + if (last_allocatable_address != MAP_FAILED) { + const unsigned int bitpos = BitsPerSize_t - count_leading_zeros((size_t) last_allocatable_address) - 1; + log_info_p(gc, init)("Did not find any valid addresses within the range, using address '%u' instead", bitpos); + return bitpos; + } + +#ifdef ASSERT + fatal("Available address space can not be determined"); +#else // ASSERT + log_warning_p(gc)("Cannot determine available address space. Falling back to default value."); + return DEFAULT_MAX_ADDRESS_BIT; +#endif // ASSERT + } else { + if (max_valid_address_bit == init_bit) { + // An usable address bit has been found immediately. + // To ensure that the entire virtual address space is exploited, the next highest bit will be tested as well. + log_info_p(gc, init)("Hit valid address '%u' on first try, retrying with next higher bit", max_valid_address_bit); + return MAX2(max_valid_address_bit, probe_valid_max_address_bit(init_bit + 1, init_bit + 1)); + } + } + + log_info_p(gc, init)("Found valid address '%u'", max_valid_address_bit); + return max_valid_address_bit; +#else // LINUX + return DEFAULT_MAX_ADDRESS_BIT; +#endif // LINUX +} + +size_t ZPlatformAddressOffsetBits() { + const static unsigned int valid_max_address_offset_bits = + probe_valid_max_address_bit(DEFAULT_MAX_ADDRESS_BIT, MINIMUM_MAX_ADDRESS_BIT) + 1; + assert(valid_max_address_offset_bits >= MINIMUM_MAX_ADDRESS_BIT, + "Highest addressable bit is outside the assumed address space range"); + + const size_t max_address_offset_bits = valid_max_address_offset_bits - 3; + const size_t min_address_offset_bits = max_address_offset_bits - 2; + const size_t address_offset = round_up_power_of_2(MaxHeapSize * ZVirtualToPhysicalRatio); + const size_t address_offset_bits = log2i_exact(address_offset); + + return clamp(address_offset_bits, min_address_offset_bits, max_address_offset_bits); +} + +size_t ZPlatformAddressMetadataShift() { + return ZPlatformAddressOffsetBits(); +} diff --git a/src/hotspot/cpu/ppc/gc/z/zGlobals_ppc.hpp b/src/hotspot/cpu/ppc/gc/z/zGlobals_ppc.hpp new file mode 100644 index 00000000000..3657b16fc1a --- /dev/null +++ b/src/hotspot/cpu/ppc/gc/z/zGlobals_ppc.hpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021 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. + */ + +#ifndef CPU_PPC_GC_Z_ZGLOBALS_PPC_HPP +#define CPU_PPC_GC_Z_ZGLOBALS_PPC_HPP + +#include "globalDefinitions_ppc.hpp" +const size_t ZPlatformGranuleSizeShift = 21; // 2MB +const size_t ZPlatformHeapViews = 3; +const size_t ZPlatformCacheLineSize = DEFAULT_CACHE_LINE_SIZE; + +size_t ZPlatformAddressOffsetBits(); +size_t ZPlatformAddressMetadataShift(); + +#endif // CPU_PPC_GC_Z_ZGLOBALS_PPC_HPP diff --git a/src/hotspot/cpu/ppc/gc/z/z_ppc.ad b/src/hotspot/cpu/ppc/gc/z/z_ppc.ad new file mode 100644 index 00000000000..a8ce64ed1d9 --- /dev/null +++ b/src/hotspot/cpu/ppc/gc/z/z_ppc.ad @@ -0,0 +1,298 @@ +// +// Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. +// Copyright (c) 2021 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. +// + +source_hpp %{ + +#include "gc/shared/gc_globals.hpp" +#include "gc/z/c2/zBarrierSetC2.hpp" +#include "gc/z/zThreadLocalData.hpp" + +%} + +source %{ + +static void z_load_barrier(MacroAssembler& _masm, const MachNode* node, Address ref_addr, Register ref, + Register tmp, uint8_t barrier_data) { + if (barrier_data == ZLoadBarrierElided) { + return; + } + + ZLoadBarrierStubC2* const stub = ZLoadBarrierStubC2::create(node, ref_addr, ref, tmp, barrier_data); + __ ld(tmp, in_bytes(ZThreadLocalData::address_bad_mask_offset()), R16_thread); + __ and_(tmp, tmp, ref); + __ bne_far(CCR0, *stub->entry(), MacroAssembler::bc_far_optimize_on_relocate); + __ bind(*stub->continuation()); +} + +static void z_load_barrier_slow_path(MacroAssembler& _masm, const MachNode* node, Address ref_addr, Register ref, + Register tmp) { + ZLoadBarrierStubC2* const stub = ZLoadBarrierStubC2::create(node, ref_addr, ref, tmp, ZLoadBarrierStrong); + __ b(*stub->entry()); + __ bind(*stub->continuation()); +} + +static void z_compare_and_swap(MacroAssembler& _masm, const MachNode* node, + Register res, Register mem, Register oldval, Register newval, + Register tmp_xchg, Register tmp_mask, + bool weak, bool acquire) { + // z-specific load barrier requires strong CAS operations. + // Weak CAS operations are thus only emitted if the barrier is elided. + __ cmpxchgd(CCR0, tmp_xchg, oldval, newval, mem, + MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), res, NULL, true, + weak && node->barrier_data() == ZLoadBarrierElided); + + if (node->barrier_data() != ZLoadBarrierElided) { + Label skip_barrier; + + __ ld(tmp_mask, in_bytes(ZThreadLocalData::address_bad_mask_offset()), R16_thread); + __ and_(tmp_mask, tmp_mask, tmp_xchg); + __ beq(CCR0, skip_barrier); + + // CAS must have failed because pointer in memory is bad. + z_load_barrier_slow_path(_masm, node, Address(mem), tmp_xchg, res /* used as tmp */); + + __ cmpxchgd(CCR0, tmp_xchg, oldval, newval, mem, + MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), res, NULL, true, weak); + + __ bind(skip_barrier); + } + + if (acquire) { + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { + // Uses the isync instruction as an acquire barrier. + // This exploits the compare and the branch in the z load barrier (load, compare and branch, isync). + __ isync(); + } else { + __ sync(); + } + } +} + +static void z_compare_and_exchange(MacroAssembler& _masm, const MachNode* node, + Register res, Register mem, Register oldval, Register newval, Register tmp, + bool weak, bool acquire) { + // z-specific load barrier requires strong CAS operations. + // Weak CAS operations are thus only emitted if the barrier is elided. + __ cmpxchgd(CCR0, res, oldval, newval, mem, + MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), noreg, NULL, true, + weak && node->barrier_data() == ZLoadBarrierElided); + + if (node->barrier_data() != ZLoadBarrierElided) { + Label skip_barrier; + __ ld(tmp, in_bytes(ZThreadLocalData::address_bad_mask_offset()), R16_thread); + __ and_(tmp, tmp, res); + __ beq(CCR0, skip_barrier); + + z_load_barrier_slow_path(_masm, node, Address(mem), res, tmp); + + __ cmpxchgd(CCR0, res, oldval, newval, mem, + MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), noreg, NULL, true, weak); + + __ bind(skip_barrier); + } + + if (acquire) { + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { + // Uses the isync instruction as an acquire barrier. + // This exploits the compare and the branch in the z load barrier (load, compare and branch, isync). + __ isync(); + } else { + __ sync(); + } + } +} + +%} + +instruct zLoadP(iRegPdst dst, memoryAlg4 mem, iRegPdst tmp, flagsRegCR0 cr0) +%{ + match(Set dst (LoadP mem)); + effect(TEMP_DEF dst, TEMP tmp, KILL cr0); + ins_cost(MEMORY_REF_COST); + + predicate((UseZGC && n->as_Load()->barrier_data() != 0) + && (n->as_Load()->is_unordered() || followed_by_acquire(n))); + + format %{ "LD $dst, $mem" %} + ins_encode %{ + assert($mem$$index == 0, "sanity"); + __ ld($dst$$Register, $mem$$disp, $mem$$base$$Register); + z_load_barrier(_masm, this, Address($mem$$base$$Register, $mem$$disp), $dst$$Register, $tmp$$Register, barrier_data()); + %} + ins_pipe(pipe_class_default); +%} + +// Load Pointer Volatile +instruct zLoadP_acq(iRegPdst dst, memoryAlg4 mem, iRegPdst tmp, flagsRegCR0 cr0) +%{ + match(Set dst (LoadP mem)); + effect(TEMP_DEF dst, TEMP tmp, KILL cr0); + ins_cost(3 * MEMORY_REF_COST); + + // Predicate on instruction order is implicitly present due to the predicate of the cheaper zLoadP operation + predicate(UseZGC && n->as_Load()->barrier_data() != 0); + + format %{ "LD acq $dst, $mem" %} + ins_encode %{ + __ ld($dst$$Register, $mem$$disp, $mem$$base$$Register); + z_load_barrier(_masm, this, Address($mem$$base$$Register, $mem$$disp), $dst$$Register, $tmp$$Register, barrier_data()); + + // Uses the isync instruction as an acquire barrier. + // This exploits the compare and the branch in the z load barrier (load, compare and branch, isync). + __ isync(); + %} + ins_pipe(pipe_class_default); +%} + +instruct zCompareAndSwapP(iRegIdst res, iRegPdst mem, iRegPsrc oldval, iRegPsrc newval, + iRegPdst tmp_xchg, iRegPdst tmp_mask, flagsRegCR0 cr0) %{ + match(Set res (CompareAndSwapP mem (Binary oldval newval))); + effect(TEMP_DEF res, TEMP tmp_xchg, TEMP tmp_mask, KILL cr0); + + predicate((UseZGC && n->as_LoadStore()->barrier_data() == ZLoadBarrierStrong) + && (((CompareAndSwapNode*)n)->order() != MemNode::acquire && ((CompareAndSwapNode*) n)->order() != MemNode::seqcst)); + + format %{ "CMPXCHG $res, $mem, $oldval, $newval; as bool; ptr" %} + ins_encode %{ + z_compare_and_swap(_masm, this, + $res$$Register, $mem$$Register, $oldval$$Register, $newval$$Register, + $tmp_xchg$$Register, $tmp_mask$$Register, + false /* weak */, false /* acquire */); + %} + ins_pipe(pipe_class_default); +%} + +instruct zCompareAndSwapP_acq(iRegIdst res, iRegPdst mem, iRegPsrc oldval, iRegPsrc newval, + iRegPdst tmp_xchg, iRegPdst tmp_mask, flagsRegCR0 cr0) %{ + match(Set res (CompareAndSwapP mem (Binary oldval newval))); + effect(TEMP_DEF res, TEMP tmp_xchg, TEMP tmp_mask, KILL cr0); + + predicate((UseZGC && n->as_LoadStore()->barrier_data() == ZLoadBarrierStrong) + && (((CompareAndSwapNode*)n)->order() == MemNode::acquire || ((CompareAndSwapNode*) n)->order() == MemNode::seqcst)); + + format %{ "CMPXCHG acq $res, $mem, $oldval, $newval; as bool; ptr" %} + ins_encode %{ + z_compare_and_swap(_masm, this, + $res$$Register, $mem$$Register, $oldval$$Register, $newval$$Register, + $tmp_xchg$$Register, $tmp_mask$$Register, + false /* weak */, true /* acquire */); + %} + ins_pipe(pipe_class_default); +%} + +instruct zCompareAndSwapPWeak(iRegIdst res, iRegPdst mem, iRegPsrc oldval, iRegPsrc newval, + iRegPdst tmp_xchg, iRegPdst tmp_mask, flagsRegCR0 cr0) %{ + match(Set res (WeakCompareAndSwapP mem (Binary oldval newval))); + effect(TEMP_DEF res, TEMP tmp_xchg, TEMP tmp_mask, KILL cr0); + + predicate((UseZGC && n->as_LoadStore()->barrier_data() == ZLoadBarrierStrong) + && ((CompareAndSwapNode*)n)->order() != MemNode::acquire && ((CompareAndSwapNode*) n)->order() != MemNode::seqcst); + + format %{ "weak CMPXCHG $res, $mem, $oldval, $newval; as bool; ptr" %} + ins_encode %{ + z_compare_and_swap(_masm, this, + $res$$Register, $mem$$Register, $oldval$$Register, $newval$$Register, + $tmp_xchg$$Register, $tmp_mask$$Register, + true /* weak */, false /* acquire */); + %} + ins_pipe(pipe_class_default); +%} + +instruct zCompareAndSwapPWeak_acq(iRegIdst res, iRegPdst mem, iRegPsrc oldval, iRegPsrc newval, + iRegPdst tmp_xchg, iRegPdst tmp_mask, flagsRegCR0 cr0) %{ + match(Set res (WeakCompareAndSwapP mem (Binary oldval newval))); + effect(TEMP_DEF res, TEMP tmp_xchg, TEMP tmp_mask, KILL cr0); + + predicate((UseZGC && n->as_LoadStore()->barrier_data() == ZLoadBarrierStrong) + && (((CompareAndSwapNode*)n)->order() == MemNode::acquire || ((CompareAndSwapNode*) n)->order() == MemNode::seqcst)); + + format %{ "weak CMPXCHG acq $res, $mem, $oldval, $newval; as bool; ptr" %} + ins_encode %{ + z_compare_and_swap(_masm, this, + $res$$Register, $mem$$Register, $oldval$$Register, $newval$$Register, + $tmp_xchg$$Register, $tmp_mask$$Register, + true /* weak */, true /* acquire */); + %} + ins_pipe(pipe_class_default); +%} + +instruct zCompareAndExchangeP(iRegPdst res, iRegPdst mem, iRegPsrc oldval, iRegPsrc newval, + iRegPdst tmp, flagsRegCR0 cr0) %{ + match(Set res (CompareAndExchangeP mem (Binary oldval newval))); + effect(TEMP_DEF res, TEMP tmp, KILL cr0); + + predicate((UseZGC && n->as_LoadStore()->barrier_data() == ZLoadBarrierStrong) + && ( + ((CompareAndSwapNode*)n)->order() != MemNode::acquire + && ((CompareAndSwapNode*)n)->order() != MemNode::seqcst + )); + + format %{ "CMPXCHG $res, $mem, $oldval, $newval; as ptr; ptr" %} + ins_encode %{ + z_compare_and_exchange(_masm, this, + $res$$Register, $mem$$Register, $oldval$$Register, $newval$$Register, $tmp$$Register, + false /* weak */, false /* acquire */); + %} + ins_pipe(pipe_class_default); +%} + +instruct zCompareAndExchangeP_acq(iRegPdst res, iRegPdst mem, iRegPsrc oldval, iRegPsrc newval, + iRegPdst tmp, flagsRegCR0 cr0) %{ + match(Set res (CompareAndExchangeP mem (Binary oldval newval))); + effect(TEMP_DEF res, TEMP tmp, KILL cr0); + + predicate((UseZGC && n->as_LoadStore()->barrier_data() == ZLoadBarrierStrong) + && ( + ((CompareAndSwapNode*)n)->order() == MemNode::acquire + || ((CompareAndSwapNode*)n)->order() == MemNode::seqcst + )); + + format %{ "CMPXCHG acq $res, $mem, $oldval, $newval; as ptr; ptr" %} + ins_encode %{ + z_compare_and_exchange(_masm, this, + $res$$Register, $mem$$Register, $oldval$$Register, $newval$$Register, $tmp$$Register, + false /* weak */, true /* acquire */); + %} + ins_pipe(pipe_class_default); +%} + +instruct zGetAndSetP(iRegPdst res, iRegPdst mem, iRegPsrc newval, iRegPdst tmp, flagsRegCR0 cr0) %{ + match(Set res (GetAndSetP mem newval)); + effect(TEMP_DEF res, TEMP tmp, KILL cr0); + + predicate(UseZGC && n->as_LoadStore()->barrier_data() != 0); + + format %{ "GetAndSetP $res, $mem, $newval" %} + ins_encode %{ + __ getandsetd($res$$Register, $newval$$Register, $mem$$Register, MacroAssembler::cmpxchgx_hint_atomic_update()); + z_load_barrier(_masm, this, Address(noreg, (intptr_t) 0), $res$$Register, $tmp$$Register, barrier_data()); + + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { + __ isync(); + } else { + __ sync(); + } + %} + ins_pipe(pipe_class_default); +%} diff --git a/src/hotspot/cpu/ppc/ppc.ad b/src/hotspot/cpu/ppc/ppc.ad index ddb6e04918a..4a43aa2f12a 100644 --- a/src/hotspot/cpu/ppc/ppc.ad +++ b/src/hotspot/cpu/ppc/ppc.ad @@ -5531,7 +5531,7 @@ instruct loadN2P_klass_unscaled(iRegPdst dst, memory mem) %{ // Load Pointer instruct loadP(iRegPdst dst, memoryAlg4 mem) %{ match(Set dst (LoadP mem)); - predicate(n->as_Load()->is_unordered() || followed_by_acquire(n)); + predicate((n->as_Load()->is_unordered() || followed_by_acquire(n)) && n->as_Load()->barrier_data() == 0); ins_cost(MEMORY_REF_COST); format %{ "LD $dst, $mem \t// ptr" %} @@ -5545,6 +5545,8 @@ instruct loadP_ac(iRegPdst dst, memoryAlg4 mem) %{ match(Set dst (LoadP mem)); ins_cost(3*MEMORY_REF_COST); + predicate(n->as_Load()->barrier_data() == 0); + format %{ "LD $dst, $mem \t// ptr acquire\n\t" "TWI $dst\n\t" "ISYNC" %} @@ -5556,7 +5558,7 @@ instruct loadP_ac(iRegPdst dst, memoryAlg4 mem) %{ // LoadP + CastP2L instruct loadP2X(iRegLdst dst, memoryAlg4 mem) %{ match(Set dst (CastP2X (LoadP mem))); - predicate(_kids[0]->_leaf->as_Load()->is_unordered()); + predicate(_kids[0]->_leaf->as_Load()->is_unordered() && _kids[0]->_leaf->as_Load()->barrier_data() == 0); ins_cost(MEMORY_REF_COST); format %{ "LD $dst, $mem \t// ptr + p2x" %} @@ -7478,6 +7480,7 @@ instruct storeLConditional_regP_regL_regL(flagsReg crx, indirect mem_ptr, iRegLs instruct storePConditional_regP_regP_regP(flagsRegCR0 cr0, indirect mem_ptr, iRegPsrc oldVal, iRegPsrc newVal) %{ match(Set cr0 (StorePConditional mem_ptr (Binary oldVal newVal))); ins_cost(2*MEMORY_REF_COST); + predicate(n->as_LoadStore()->barrier_data() == 0); format %{ "STDCX_ if ($cr0 = ($oldVal == *$mem_ptr)) *mem_ptr = $newVal; as bool" %} ins_encode %{ @@ -7642,6 +7645,7 @@ instruct compareAndSwapL_regP_regL_regL(iRegIdst res, iRegPdst mem_ptr, iRegLsrc instruct compareAndSwapP_regP_regP_regP(iRegIdst res, iRegPdst mem_ptr, iRegPsrc src1, iRegPsrc src2, flagsRegCR0 cr0) %{ match(Set res (CompareAndSwapP mem_ptr (Binary src1 src2))); effect(TEMP_DEF res, TEMP cr0); // TEMP_DEF to avoid jump + predicate(n->as_LoadStore()->barrier_data() == 0); format %{ "CMPXCHGD $res, $mem_ptr, $src1, $src2; as bool; ptr" %} ins_encode %{ // CmpxchgX sets CCR0 to cmpX(src1, src2) and Rres to 'true'/'false'. @@ -7864,7 +7868,7 @@ instruct weakCompareAndSwapL_acq_regP_regL_regL(iRegIdst res, iRegPdst mem_ptr, instruct weakCompareAndSwapP_regP_regP_regP(iRegIdst res, iRegPdst mem_ptr, iRegPsrc src1, iRegPsrc src2, flagsRegCR0 cr0) %{ match(Set res (WeakCompareAndSwapP mem_ptr (Binary src1 src2))); - predicate(((CompareAndSwapNode*)n)->order() != MemNode::acquire && ((CompareAndSwapNode*)n)->order() != MemNode::seqcst); + predicate((((CompareAndSwapNode*)n)->order() != MemNode::acquire && ((CompareAndSwapNode*)n)->order() != MemNode::seqcst) && n->as_LoadStore()->barrier_data() == 0); effect(TEMP_DEF res, TEMP cr0); // TEMP_DEF to avoid jump format %{ "weak CMPXCHGD $res, $mem_ptr, $src1, $src2; as bool; ptr" %} ins_encode %{ @@ -7878,7 +7882,7 @@ instruct weakCompareAndSwapP_regP_regP_regP(iRegIdst res, iRegPdst mem_ptr, iReg instruct weakCompareAndSwapP_acq_regP_regP_regP(iRegIdst res, iRegPdst mem_ptr, iRegPsrc src1, iRegPsrc src2, flagsRegCR0 cr0) %{ match(Set res (WeakCompareAndSwapP mem_ptr (Binary src1 src2))); - predicate(((CompareAndSwapNode*)n)->order() == MemNode::acquire || ((CompareAndSwapNode*)n)->order() == MemNode::seqcst); + predicate((((CompareAndSwapNode*)n)->order() == MemNode::acquire || ((CompareAndSwapNode*)n)->order() == MemNode::seqcst) && n->as_LoadStore()->barrier_data() == 0); effect(TEMP_DEF res, TEMP cr0); // TEMP_DEF to avoid jump format %{ "weak CMPXCHGD acq $res, $mem_ptr, $src1, $src2; as bool; ptr" %} ins_encode %{ @@ -8134,7 +8138,8 @@ instruct compareAndExchangeL_acq_regP_regL_regL(iRegLdst res, iRegPdst mem_ptr, instruct compareAndExchangeP_regP_regP_regP(iRegPdst res, iRegPdst mem_ptr, iRegPsrc src1, iRegPsrc src2, flagsRegCR0 cr0) %{ match(Set res (CompareAndExchangeP mem_ptr (Binary src1 src2))); - predicate(((CompareAndSwapNode*)n)->order() != MemNode::acquire && ((CompareAndSwapNode*)n)->order() != MemNode::seqcst); + predicate((((CompareAndSwapNode*)n)->order() != MemNode::acquire && ((CompareAndSwapNode*)n)->order() != MemNode::seqcst) + && n->as_LoadStore()->barrier_data() == 0); effect(TEMP_DEF res, TEMP cr0); format %{ "CMPXCHGD $res, $mem_ptr, $src1, $src2; as ptr; ptr" %} ins_encode %{ @@ -8148,7 +8153,8 @@ instruct compareAndExchangeP_regP_regP_regP(iRegPdst res, iRegPdst mem_ptr, iReg instruct compareAndExchangeP_acq_regP_regP_regP(iRegPdst res, iRegPdst mem_ptr, iRegPsrc src1, iRegPsrc src2, flagsRegCR0 cr0) %{ match(Set res (CompareAndExchangeP mem_ptr (Binary src1 src2))); - predicate(((CompareAndSwapNode*)n)->order() == MemNode::acquire || ((CompareAndSwapNode*)n)->order() == MemNode::seqcst); + predicate((((CompareAndSwapNode*)n)->order() == MemNode::acquire || ((CompareAndSwapNode*)n)->order() == MemNode::seqcst) + && n->as_LoadStore()->barrier_data() == 0); effect(TEMP_DEF res, TEMP cr0); format %{ "CMPXCHGD acq $res, $mem_ptr, $src1, $src2; as ptr; ptr" %} ins_encode %{ @@ -8370,6 +8376,7 @@ instruct getAndSetL(iRegLdst res, iRegPdst mem_ptr, iRegLsrc src, flagsRegCR0 cr instruct getAndSetP(iRegPdst res, iRegPdst mem_ptr, iRegPsrc src, flagsRegCR0 cr0) %{ match(Set res (GetAndSetP mem_ptr src)); + predicate(n->as_LoadStore()->barrier_data() == 0); effect(TEMP_DEF res, TEMP cr0); format %{ "GetAndSetP $res, $mem_ptr, $src" %} ins_encode %{ diff --git a/src/hotspot/cpu/ppc/vmreg_ppc.hpp b/src/hotspot/cpu/ppc/vmreg_ppc.hpp index 090fe1d72a2..16f6799d046 100644 --- a/src/hotspot/cpu/ppc/vmreg_ppc.hpp +++ b/src/hotspot/cpu/ppc/vmreg_ppc.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2013 SAP SE. All rights reserved. + * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2021 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 @@ -35,6 +35,21 @@ inline bool is_FloatRegister() { value() < ConcreteRegisterImpl::max_fpr; } +inline bool is_VectorRegister() { + return value() >= ConcreteRegisterImpl::max_fpr && + value() < ConcreteRegisterImpl::max_vsr; +} + +inline bool is_ConditionRegister() { + return value() >= ConcreteRegisterImpl::max_vsr && + value() < ConcreteRegisterImpl::max_cnd; +} + +inline bool is_SpecialRegister() { + return value() >= ConcreteRegisterImpl::max_cnd && + value() < ConcreteRegisterImpl::max_spr; +} + inline Register as_Register() { assert(is_Register() && is_even(value()), "even-aligned GPR name"); return ::as_Register(value()>>1); diff --git a/src/hotspot/os_cpu/linux_ppc/gc/z/zSyscall_linux_ppc.hpp b/src/hotspot/os_cpu/linux_ppc/gc/z/zSyscall_linux_ppc.hpp new file mode 100644 index 00000000000..5950b52136d --- /dev/null +++ b/src/hotspot/os_cpu/linux_ppc/gc/z/zSyscall_linux_ppc.hpp @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021 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. + */ + +#ifndef OS_CPU_LINUX_PPC_GC_Z_ZSYSCALL_LINUX_PPC_HPP +#define OS_CPU_LINUX_PPC_GC_Z_ZSYSCALL_LINUX_PPC_HPP + +#include + +// +// Support for building on older Linux systems +// + + +#ifndef SYS_memfd_create +#define SYS_memfd_create 360 +#endif +#ifndef SYS_fallocate +#define SYS_fallocate 309 +#endif + +#endif // OS_CPU_LINUX_PPC_GC_Z_ZSYSCALL_LINUX_PPC_HPP -- GitLab From c3b75c6cdf03ffa3c887bf3db29e17668b228f79 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Wed, 13 Oct 2021 08:10:55 +0000 Subject: [PATCH 195/385] 8274516: [REDO] JDK-8271880: Tighten condition for excluding regions from collecting cards with cross-references Reviewed-by: sjohanss, ayang --- src/hotspot/share/gc/g1/g1CollectedHeap.cpp | 1 + src/hotspot/share/gc/g1/g1CollectedHeap.hpp | 1 + .../share/gc/g1/g1CollectedHeap.inline.hpp | 4 + src/hotspot/share/gc/g1/g1EvacFailure.cpp | 76 +------------------ src/hotspot/share/gc/g1/g1EvacFailure.hpp | 4 +- src/hotspot/share/gc/g1/g1HeapRegionAttr.hpp | 14 +++- src/hotspot/share/gc/g1/g1OopClosures.hpp | 4 +- .../share/gc/g1/g1ParScanThreadState.cpp | 23 +++++- .../share/gc/g1/g1ParScanThreadState.hpp | 2 +- .../gc/g1/g1ParScanThreadState.inline.hpp | 25 ++++-- src/hotspot/share/gc/g1/g1YoungCollector.cpp | 28 ++++++- src/hotspot/share/gc/g1/g1YoungCollector.hpp | 1 - .../gc/g1/g1YoungGCPostEvacuateTasks.cpp | 6 +- .../gc/g1/g1YoungGCPostEvacuateTasks.hpp | 1 - .../share/gc/shared/referenceProcessor.cpp | 22 +++--- .../share/gc/shared/referenceProcessor.hpp | 9 ++- 16 files changed, 113 insertions(+), 108 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index fe38b0a49e6..751680abc37 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp @@ -3272,6 +3272,7 @@ HeapRegion* G1CollectedHeap::new_gc_alloc_region(size_t word_size, G1HeapRegionA new_alloc_region->set_survivor(); _survivor.add(new_alloc_region); _verifier->check_bitmaps("Survivor Region Allocation", new_alloc_region); + register_new_survivor_region_with_region_attr(new_alloc_region); } else { new_alloc_region->set_old(); _verifier->check_bitmaps("Old Region Allocation", new_alloc_region); diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp index a89faf4c1fc..55c271f10c6 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp @@ -605,6 +605,7 @@ public: void register_young_region_with_region_attr(HeapRegion* r) { _region_attr.set_in_young(r->hrm_index()); } + inline void register_new_survivor_region_with_region_attr(HeapRegion* r); inline void register_region_with_region_attr(HeapRegion* r); inline void register_old_region_with_region_attr(HeapRegion* r); inline void register_optional_region_with_region_attr(HeapRegion* r); diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp b/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp index 4de285b980f..0fef0a94449 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp @@ -184,6 +184,10 @@ void G1CollectedHeap::register_humongous_region_with_region_attr(uint index) { _region_attr.set_humongous(index, region_at(index)->rem_set()->is_tracked()); } +void G1CollectedHeap::register_new_survivor_region_with_region_attr(HeapRegion* r) { + _region_attr.set_new_survivor_region(r->hrm_index()); +} + void G1CollectedHeap::register_region_with_region_attr(HeapRegion* r) { _region_attr.set_has_remset(r->hrm_index(), r->rem_set()->is_tracked()); } diff --git a/src/hotspot/share/gc/g1/g1EvacFailure.cpp b/src/hotspot/share/gc/g1/g1EvacFailure.cpp index b7b564abe49..d3b9b24bdd8 100644 --- a/src/hotspot/share/gc/g1/g1EvacFailure.cpp +++ b/src/hotspot/share/gc/g1/g1EvacFailure.cpp @@ -30,7 +30,6 @@ #include "gc/g1/g1EvacFailureRegions.hpp" #include "gc/g1/g1HeapVerifier.hpp" #include "gc/g1/g1OopClosures.inline.hpp" -#include "gc/g1/g1RedirtyCardsQueue.hpp" #include "gc/g1/heapRegion.hpp" #include "gc/g1/heapRegionRemSet.inline.hpp" #include "gc/shared/preservedMarks.inline.hpp" @@ -38,65 +37,23 @@ #include "oops/compressedOops.inline.hpp" #include "oops/oop.inline.hpp" -class UpdateLogBuffersDeferred : public BasicOopIterateClosure { -private: - G1CollectedHeap* _g1h; - G1RedirtyCardsLocalQueueSet* _rdc_local_qset; - G1CardTable* _ct; - - // Remember the last enqueued card to avoid enqueuing the same card over and over; - // since we only ever handle a card once, this is sufficient. - size_t _last_enqueued_card; - -public: - UpdateLogBuffersDeferred(G1RedirtyCardsLocalQueueSet* rdc_local_qset) : - _g1h(G1CollectedHeap::heap()), - _rdc_local_qset(rdc_local_qset), - _ct(_g1h->card_table()), - _last_enqueued_card(SIZE_MAX) {} - - virtual void do_oop(narrowOop* p) { do_oop_work(p); } - virtual void do_oop( oop* p) { do_oop_work(p); } - template void do_oop_work(T* p) { - assert(_g1h->heap_region_containing(p)->is_in_reserved(p), "paranoia"); - assert(!_g1h->heap_region_containing(p)->is_survivor(), "Unexpected evac failure in survivor region"); - - T const o = RawAccess<>::oop_load(p); - if (CompressedOops::is_null(o)) { - return; - } - - if (HeapRegion::is_in_same_region(p, CompressedOops::decode(o))) { - return; - } - size_t card_index = _ct->index_for(p); - if (card_index != _last_enqueued_card) { - _rdc_local_qset->enqueue(_ct->byte_for_index(card_index)); - _last_enqueued_card = card_index; - } - } -}; - class RemoveSelfForwardPtrObjClosure: public ObjectClosure { G1CollectedHeap* _g1h; G1ConcurrentMark* _cm; HeapRegion* _hr; size_t _marked_bytes; - UpdateLogBuffersDeferred* _log_buffer_cl; bool _during_concurrent_start; uint _worker_id; HeapWord* _last_forwarded_object_end; public: RemoveSelfForwardPtrObjClosure(HeapRegion* hr, - UpdateLogBuffersDeferred* log_buffer_cl, bool during_concurrent_start, uint worker_id) : _g1h(G1CollectedHeap::heap()), _cm(_g1h->concurrent_mark()), _hr(hr), _marked_bytes(0), - _log_buffer_cl(log_buffer_cl), _during_concurrent_start(during_concurrent_start), _worker_id(worker_id), _last_forwarded_object_end(hr->bottom()) { } @@ -141,20 +98,6 @@ public: _marked_bytes += (obj_size * HeapWordSize); PreservedMarks::init_forwarded_mark(obj); - // While we were processing RSet buffers during the collection, - // we actually didn't scan any cards on the collection set, - // since we didn't want to update remembered sets with entries - // that point into the collection set, given that live objects - // from the collection set are about to move and such entries - // will be stale very soon. - // This change also dealt with a reliability issue which - // involved scanning a card in the collection set and coming - // across an array that was being chunked and looking malformed. - // The problem is that, if evacuation fails, we might have - // remembered set entries missing given that we skipped cards on - // the collection set. So, we'll recreate such entries now. - obj->oop_iterate(_log_buffer_cl); - HeapWord* obj_end = obj_addr + obj_size; _last_forwarded_object_end = obj_end; _hr->alloc_block_in_bot(obj_addr, obj_end); @@ -203,33 +146,22 @@ class RemoveSelfForwardPtrHRClosure: public HeapRegionClosure { G1CollectedHeap* _g1h; uint _worker_id; - G1RedirtyCardsLocalQueueSet _rdc_local_qset; - UpdateLogBuffersDeferred _log_buffer_cl; - uint volatile* _num_failed_regions; G1EvacFailureRegions* _evac_failure_regions; public: - RemoveSelfForwardPtrHRClosure(G1RedirtyCardsQueueSet* rdcqs, - uint worker_id, + RemoveSelfForwardPtrHRClosure(uint worker_id, uint volatile* num_failed_regions, G1EvacFailureRegions* evac_failure_regions) : _g1h(G1CollectedHeap::heap()), _worker_id(worker_id), - _rdc_local_qset(rdcqs), - _log_buffer_cl(&_rdc_local_qset), _num_failed_regions(num_failed_regions), _evac_failure_regions(evac_failure_regions) { } - ~RemoveSelfForwardPtrHRClosure() { - _rdc_local_qset.flush(); - } - size_t remove_self_forward_ptr_by_walking_hr(HeapRegion* hr, bool during_concurrent_start) { RemoveSelfForwardPtrObjClosure rspc(hr, - &_log_buffer_cl, during_concurrent_start, _worker_id); hr->object_iterate(&rspc); @@ -268,17 +200,15 @@ public: } }; -G1ParRemoveSelfForwardPtrsTask::G1ParRemoveSelfForwardPtrsTask(G1RedirtyCardsQueueSet* rdcqs, - G1EvacFailureRegions* evac_failure_regions) : +G1ParRemoveSelfForwardPtrsTask::G1ParRemoveSelfForwardPtrsTask(G1EvacFailureRegions* evac_failure_regions) : AbstractGangTask("G1 Remove Self-forwarding Pointers"), _g1h(G1CollectedHeap::heap()), - _rdcqs(rdcqs), _hrclaimer(_g1h->workers()->active_workers()), _evac_failure_regions(evac_failure_regions), _num_failed_regions(0) { } void G1ParRemoveSelfForwardPtrsTask::work(uint worker_id) { - RemoveSelfForwardPtrHRClosure rsfp_cl(_rdcqs, worker_id, &_num_failed_regions, _evac_failure_regions); + RemoveSelfForwardPtrHRClosure rsfp_cl(worker_id, &_num_failed_regions, _evac_failure_regions); // Iterate through all regions that failed evacuation during the entire collection. _evac_failure_regions->par_iterate(&rsfp_cl, &_hrclaimer, worker_id); diff --git a/src/hotspot/share/gc/g1/g1EvacFailure.hpp b/src/hotspot/share/gc/g1/g1EvacFailure.hpp index cd587ac839d..b0387a3a24f 100644 --- a/src/hotspot/share/gc/g1/g1EvacFailure.hpp +++ b/src/hotspot/share/gc/g1/g1EvacFailure.hpp @@ -32,21 +32,19 @@ class G1CollectedHeap; class G1EvacFailureRegions; -class G1RedirtyCardsQueueSet; // Task to fixup self-forwarding pointers // installed as a result of an evacuation failure. class G1ParRemoveSelfForwardPtrsTask: public AbstractGangTask { protected: G1CollectedHeap* _g1h; - G1RedirtyCardsQueueSet* _rdcqs; HeapRegionClaimer _hrclaimer; G1EvacFailureRegions* _evac_failure_regions; uint volatile _num_failed_regions; public: - G1ParRemoveSelfForwardPtrsTask(G1RedirtyCardsQueueSet* rdcqs, G1EvacFailureRegions* evac_failure_regions); + G1ParRemoveSelfForwardPtrsTask(G1EvacFailureRegions* evac_failure_regions); void work(uint worker_id); diff --git a/src/hotspot/share/gc/g1/g1HeapRegionAttr.hpp b/src/hotspot/share/gc/g1/g1HeapRegionAttr.hpp index 2d8ae1fae40..3bb7c02b88d 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionAttr.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionAttr.hpp @@ -57,8 +57,9 @@ public: // // The other values are used for objects in regions requiring various special handling, // eager reclamation of humongous objects or optional regions. - static const region_type_t Optional = -3; // The region is optional not in the current collection set. - static const region_type_t Humongous = -2; // The region is a humongous candidate not in the current collection set. + static const region_type_t Optional = -4; // The region is optional not in the current collection set. + static const region_type_t Humongous = -3; // The region is a humongous candidate not in the current collection set. + static const region_type_t NewSurvivor = -2; // The region is a new (ly allocated) survivor region. static const region_type_t NotInCSet = -1; // The region is not in the collection set. static const region_type_t Young = 0; // The region is in the collection set and a young region. static const region_type_t Old = 1; // The region is in the collection set and an old region. @@ -76,6 +77,7 @@ public: switch (type()) { case Optional: return "Optional"; case Humongous: return "Humongous"; + case NewSurvivor: return "NewSurvivor"; case NotInCSet: return "NotInCSet"; case Young: return "Young"; case Old: return "Old"; @@ -85,6 +87,7 @@ public: bool needs_remset_update() const { return _needs_remset_update != 0; } + void set_new_survivor() { _type = NewSurvivor; } void set_old() { _type = Old; } void clear_humongous() { assert(is_humongous() || !is_in_cset(), "must be"); @@ -96,6 +99,7 @@ public: bool is_in_cset() const { return type() >= Young; } bool is_humongous() const { return type() == Humongous; } + bool is_new_survivor() const { return type() == NewSurvivor; } bool is_young() const { return type() == Young; } bool is_old() const { return type() == Old; } bool is_optional() const { return type() == Optional; } @@ -128,6 +132,12 @@ class G1HeapRegionAttrBiasedMappedArray : public G1BiasedMappedArrayset_new_survivor(); + } + void set_humongous(uintptr_t index, bool needs_remset_update) { assert(get_by_index(index).is_default(), "Region attributes at index " INTPTR_FORMAT " should be default but is %s", index, get_by_index(index).get_type_str()); diff --git a/src/hotspot/share/gc/g1/g1OopClosures.hpp b/src/hotspot/share/gc/g1/g1OopClosures.hpp index d8fff5721da..9f0c4a23a55 100644 --- a/src/hotspot/share/gc/g1/g1OopClosures.hpp +++ b/src/hotspot/share/gc/g1/g1OopClosures.hpp @@ -116,9 +116,9 @@ class G1SkipCardEnqueueSetter : public StackObj { G1ScanEvacuatedObjClosure* _closure; public: - G1SkipCardEnqueueSetter(G1ScanEvacuatedObjClosure* closure, bool new_value) : _closure(closure) { + G1SkipCardEnqueueSetter(G1ScanEvacuatedObjClosure* closure, bool skip_card_enqueue) : _closure(closure) { assert(_closure->_skip_card_enqueue == G1ScanEvacuatedObjClosure::Uninitialized, "Must not be set"); - _closure->_skip_card_enqueue = new_value ? G1ScanEvacuatedObjClosure::True : G1ScanEvacuatedObjClosure::False; + _closure->_skip_card_enqueue = skip_card_enqueue ? G1ScanEvacuatedObjClosure::True : G1ScanEvacuatedObjClosure::False; } ~G1SkipCardEnqueueSetter() { diff --git a/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp b/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp index 03540a95671..92772cc2db7 100644 --- a/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp +++ b/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp @@ -235,8 +235,8 @@ void G1ParScanThreadState::do_partial_array(PartialArrayScanTask task) { push_on_queue(ScannerTask(PartialArrayScanTask(from_obj))); } - HeapRegion* hr = _g1h->heap_region_containing(to_array); - G1SkipCardEnqueueSetter x(&_scanner, hr->is_young()); + G1HeapRegionAttr dest_attr = _g1h->region_attr(to_array); + G1SkipCardEnqueueSetter x(&_scanner, dest_attr.is_new_survivor()); // Process claimed task. The length of to_array is not correct, but // fortunately the iteration ignores the length field and just relies // on start/end. @@ -268,6 +268,11 @@ void G1ParScanThreadState::start_partial_objarray(G1HeapRegionAttr dest_attr, push_on_queue(ScannerTask(PartialArrayScanTask(from_obj))); } + // Skip the card enqueue iff the object (to_array) is in survivor region. + // However, HeapRegion::is_survivor() is too expensive here. + // Instead, we use dest_attr.is_young() because the two values are always + // equal: successfully allocated young regions must be survivor regions. + assert(dest_attr.is_young() == _g1h->heap_region_containing(to_array)->is_survivor(), "must be"); G1SkipCardEnqueueSetter x(&_scanner, dest_attr.is_young()); // Process the initial chunk. No need to process the type in the // klass, as it will already be handled by processing the built-in @@ -519,6 +524,11 @@ oop G1ParScanThreadState::do_copy_to_survivor_space(G1HeapRegionAttr const regio _string_dedup_requests.add(old); } + // Skip the card enqueue iff the object (obj) is in survivor region. + // However, HeapRegion::is_survivor() is too expensive here. + // Instead, we use dest_attr.is_young() because the two values are always + // equal: successfully allocated young regions must be survivor regions. + assert(dest_attr.is_young() == _g1h->heap_region_containing(obj)->is_survivor(), "must be"); G1SkipCardEnqueueSetter x(&_scanner, dest_attr.is_young()); obj->oop_iterate_backwards(&_scanner, klass); return obj; @@ -605,7 +615,14 @@ oop G1ParScanThreadState::handle_evacuation_failure_par(oop old, markWord m, siz _preserved_marks->push_if_necessary(old, m); _evacuation_failed_info.register_copy_failure(word_sz); - G1SkipCardEnqueueSetter x(&_scanner, r->is_young()); + // For iterating objects that failed evacuation currently we can reuse the + // existing closure to scan evacuated objects because: + // - for objects referring into the collection set we do not need to gather + // cards at this time. The regions they are in will be unconditionally turned + // to old regions without remembered sets. + // - since we are iterating from a collection set region (i.e. never a Survivor + // region), we always need to gather cards for this case. + G1SkipCardEnqueueSetter x(&_scanner, false /* skip_card_enqueue */); old->oop_iterate_backwards(&_scanner); return old; diff --git a/src/hotspot/share/gc/g1/g1ParScanThreadState.hpp b/src/hotspot/share/gc/g1/g1ParScanThreadState.hpp index ea4fb10f5bd..0ecc11f50a5 100644 --- a/src/hotspot/share/gc/g1/g1ParScanThreadState.hpp +++ b/src/hotspot/share/gc/g1/g1ParScanThreadState.hpp @@ -134,7 +134,7 @@ public: // Apply the post barrier to the given reference field. Enqueues the card of p // if the barrier does not filter out the reference for some reason (e.g. - // p and q are in the same region, p is in survivor) + // p and q are in the same region, p is in survivor, p is in collection set) // To be called during GC if nothing particular about p and obj are known. template void write_ref_field_post(T* p, oop obj); diff --git a/src/hotspot/share/gc/g1/g1ParScanThreadState.inline.hpp b/src/hotspot/share/gc/g1/g1ParScanThreadState.inline.hpp index 1184919dbf2..a3634737103 100644 --- a/src/hotspot/share/gc/g1/g1ParScanThreadState.inline.hpp +++ b/src/hotspot/share/gc/g1/g1ParScanThreadState.inline.hpp @@ -97,19 +97,34 @@ G1OopStarChunkedList* G1ParScanThreadState::oops_into_optional_region(const Heap } template void G1ParScanThreadState::write_ref_field_post(T* p, oop obj) { - assert(obj != NULL, "Must be"); + assert(obj != nullptr, "Must be"); if (HeapRegion::is_in_same_region(p, obj)) { return; } - HeapRegion* from = _g1h->heap_region_containing(p); - if (!from->is_young()) { - enqueue_card_if_tracked(_g1h->region_attr(obj), p, obj); + G1HeapRegionAttr from_attr = _g1h->region_attr(p); + // If this is a reference from (current) survivor regions, we do not need + // to track references from it. + if (from_attr.is_new_survivor()) { + return; + } + G1HeapRegionAttr dest_attr = _g1h->region_attr(obj); + // References to the current collection set are references to objects that failed + // evacuation. Currently these regions are always relabelled as old without + // remembered sets, so skip them. + assert(dest_attr.is_in_cset() == (obj->forwardee() == obj), + "Only evac-failed objects must be in the collection set here but " PTR_FORMAT " is not", p2i(obj)); + if (dest_attr.is_in_cset()) { + return; } + enqueue_card_if_tracked(dest_attr, p, obj); } template void G1ParScanThreadState::enqueue_card_if_tracked(G1HeapRegionAttr region_attr, T* p, oop o) { assert(!HeapRegion::is_in_same_region(p, o), "Should have filtered out cross-region references already."); - assert(!_g1h->heap_region_containing(p)->is_young(), "Should have filtered out from-young references already."); + assert(!_g1h->heap_region_containing(p)->is_survivor(), "Should have filtered out from-newly allocated survivor references already."); + // We relabel all regions that failed evacuation as old gen without remembered, + // and so pre-filter them out in the caller. + assert(!_g1h->heap_region_containing(o)->in_collection_set(), "Should not try to enqueue reference into collection set region"); #ifdef ASSERT HeapRegion* const hr_obj = _g1h->heap_region_containing(o); diff --git a/src/hotspot/share/gc/g1/g1YoungCollector.cpp b/src/hotspot/share/gc/g1/g1YoungCollector.cpp index 13296026a34..b81c0328d73 100644 --- a/src/hotspot/share/gc/g1/g1YoungCollector.cpp +++ b/src/hotspot/share/gc/g1/g1YoungCollector.cpp @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "classfile/classLoaderDataGraph.inline.hpp" +#include "classfile/javaClasses.inline.hpp" #include "compiler/oopMap.hpp" #include "gc/g1/g1Allocator.hpp" #include "gc/g1/g1CardSetMemory.hpp" @@ -911,6 +912,31 @@ class G1STWRefProcProxyTask : public RefProcProxyTask { TaskTerminator _terminator; G1ScannerTasksQueueSet& _task_queues; + // Special closure for enqueuing discovered fields: during enqueue the card table + // may not be in shape to properly handle normal barrier calls (e.g. card marks + // in regions that failed evacuation, scribbling of various values by card table + // scan code). Additionally the regular barrier enqueues into the "global" + // DCQS, but during GC we need these to-be-refined entries in the GC local queue + // so that after clearing the card table, the redirty cards phase will properly + // mark all dirty cards to be picked up by refinement. + class G1EnqueueDiscoveredFieldClosure : public EnqueueDiscoveredFieldClosure { + G1CollectedHeap* _g1h; + G1ParScanThreadState* _pss; + + public: + G1EnqueueDiscoveredFieldClosure(G1CollectedHeap* g1h, G1ParScanThreadState* pss) : _g1h(g1h), _pss(pss) { } + + void enqueue(HeapWord* discovered_field_addr, oop value) override { + assert(_g1h->is_in(discovered_field_addr), PTR_FORMAT " is not in heap ", p2i(discovered_field_addr)); + // Store the value first, whatever it is. + RawAccess<>::oop_store(discovered_field_addr, value); + if (value == nullptr) { + return; + } + _pss->write_ref_field_post(discovered_field_addr, value); + } + }; + public: G1STWRefProcProxyTask(uint max_workers, G1CollectedHeap& g1h, G1ParScanThreadStateSet& pss, G1ScannerTasksQueueSet& task_queues) : RefProcProxyTask("G1STWRefProcProxyTask", max_workers), @@ -928,7 +954,7 @@ public: G1STWIsAliveClosure is_alive(&_g1h); G1CopyingKeepAliveClosure keep_alive(&_g1h, pss); - BarrierEnqueueDiscoveredFieldClosure enqueue; + G1EnqueueDiscoveredFieldClosure enqueue(&_g1h, pss); G1ParEvacuateFollowersClosure complete_gc(&_g1h, pss, &_task_queues, _tm == RefProcThreadModel::Single ? nullptr : &_terminator, G1GCPhaseTimes::ObjCopy); _rp_task->rp_work(worker_id, &is_alive, &keep_alive, &enqueue, &complete_gc); diff --git a/src/hotspot/share/gc/g1/g1YoungCollector.hpp b/src/hotspot/share/gc/g1/g1YoungCollector.hpp index 94a5e1c091e..cc6370f1957 100644 --- a/src/hotspot/share/gc/g1/g1YoungCollector.hpp +++ b/src/hotspot/share/gc/g1/g1YoungCollector.hpp @@ -142,7 +142,6 @@ class G1YoungCollector { #endif // TASKQUEUE_STATS public: - G1YoungCollector(GCCause::Cause gc_cause, double target_pause_time_ms); void collect(); diff --git a/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp b/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp index 727c4538610..88c9cba3c60 100644 --- a/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp +++ b/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp @@ -102,9 +102,9 @@ class G1PostEvacuateCollectionSetCleanupTask1::RemoveSelfForwardPtrsTask : publi G1EvacFailureRegions* _evac_failure_regions; public: - RemoveSelfForwardPtrsTask(G1RedirtyCardsQueueSet* rdcqs, G1EvacFailureRegions* evac_failure_regions) : + RemoveSelfForwardPtrsTask(G1EvacFailureRegions* evac_failure_regions) : G1AbstractSubTask(G1GCPhaseTimes::RemoveSelfForwardingPtr), - _task(rdcqs, evac_failure_regions), + _task(evac_failure_regions), _evac_failure_regions(evac_failure_regions) { } ~RemoveSelfForwardPtrsTask() { @@ -135,7 +135,7 @@ G1PostEvacuateCollectionSetCleanupTask1::G1PostEvacuateCollectionSetCleanupTask1 add_serial_task(new SampleCollectionSetCandidatesTask()); } if (evacuation_failed) { - add_parallel_task(new RemoveSelfForwardPtrsTask(per_thread_states->rdcqs(), evac_failure_regions)); + add_parallel_task(new RemoveSelfForwardPtrsTask(evac_failure_regions)); } add_parallel_task(G1CollectedHeap::heap()->rem_set()->create_cleanup_after_scan_heap_roots_task()); } diff --git a/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.hpp b/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.hpp index 0201dc3a738..6613438e19b 100644 --- a/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.hpp +++ b/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.hpp @@ -34,7 +34,6 @@ class G1CollectedHeap; class G1EvacFailureRegions; class G1EvacInfo; class G1ParScanThreadStateSet; -class G1RedirtyCardsQueueSet; // First set of post evacuate collection set tasks containing ("s" means serial): // - Merge PSS (s) diff --git a/src/hotspot/share/gc/shared/referenceProcessor.cpp b/src/hotspot/share/gc/shared/referenceProcessor.cpp index c67447e0fe7..759811331d1 100644 --- a/src/hotspot/share/gc/shared/referenceProcessor.cpp +++ b/src/hotspot/share/gc/shared/referenceProcessor.cpp @@ -40,6 +40,7 @@ #include "oops/oop.inline.hpp" #include "runtime/java.hpp" #include "runtime/nonJavaThread.hpp" +#include "utilities/globalDefinitions.hpp" ReferencePolicy* ReferenceProcessor::_always_clear_soft_ref_policy = NULL; ReferencePolicy* ReferenceProcessor::_default_soft_ref_policy = NULL; @@ -218,10 +219,10 @@ ReferenceProcessorStats ReferenceProcessor::process_discovered_references(RefPro return stats; } -void BarrierEnqueueDiscoveredFieldClosure::enqueue(oop reference, oop value) { - HeapAccess::oop_store_at(reference, - java_lang_ref_Reference::discovered_offset(), - value); +void BarrierEnqueueDiscoveredFieldClosure::enqueue(HeapWord* discovered_field_addr, oop value) { + assert(Universe::heap()->is_in(discovered_field_addr), PTR_FORMAT " not in heap", p2i(discovered_field_addr)); + HeapAccess::oop_store(discovered_field_addr, + value); } void DiscoveredListIterator::load_ptrs(DEBUG_ONLY(bool allow_null_referent)) { @@ -255,9 +256,8 @@ void DiscoveredListIterator::remove() { } else { new_next = _next_discovered; } - // Remove Reference object from discovered list. Note that G1 does not need a - // pre-barrier here because we know the Reference has already been found/marked, - // that's how it ended up in the discovered list in the first place. + // Remove Reference object from discovered list. We do not need barriers here, + // as we only remove. We will do the barrier when we actually advance the cursor. RawAccess<>::oop_store(_prev_discovered_addr, new_next); _removed++; _refs_list.dec_length(1); @@ -277,7 +277,11 @@ void DiscoveredListIterator::clear_referent() { } void DiscoveredListIterator::enqueue() { - _enqueue->enqueue(_current_discovered, _next_discovered); + if (_prev_discovered_addr != _refs_list.adr_head()) { + _enqueue->enqueue(_prev_discovered_addr, _current_discovered); + } else { + RawAccess<>::oop_store(_prev_discovered_addr, _current_discovered); + } } void DiscoveredListIterator::complete_enqueue() { @@ -286,7 +290,7 @@ void DiscoveredListIterator::complete_enqueue() { // Swap refs_list into pending list and set obj's // discovered to what we read from the pending list. oop old = Universe::swap_reference_pending_list(_refs_list.head()); - _enqueue->enqueue(_prev_discovered, old); + _enqueue->enqueue(java_lang_ref_Reference::discovered_addr_raw(_prev_discovered), old); } } diff --git a/src/hotspot/share/gc/shared/referenceProcessor.hpp b/src/hotspot/share/gc/shared/referenceProcessor.hpp index 77e7ca23494..349cee8cb7d 100644 --- a/src/hotspot/share/gc/shared/referenceProcessor.hpp +++ b/src/hotspot/share/gc/shared/referenceProcessor.hpp @@ -47,15 +47,16 @@ class RefProcProxyTask; // at the point of invocation. class EnqueueDiscoveredFieldClosure { public: - // For the given j.l.ref.Reference reference, set the discovered field to value. - virtual void enqueue(oop reference, oop value) = 0; + // For the given j.l.ref.Reference discovered field address, set the discovered + // field to value and apply any barriers to it. + virtual void enqueue(HeapWord* discovered_field_addr, oop value) = 0; }; // EnqueueDiscoveredFieldClosure that executes the default barrier on the discovered -// field of the j.l.ref.Reference reference with the given value. +// field of the j.l.ref.Reference with the given value. class BarrierEnqueueDiscoveredFieldClosure : public EnqueueDiscoveredFieldClosure { public: - void enqueue(oop reference, oop value) override; + void enqueue(HeapWord* discovered_field_addr, oop value) override; }; // List of discovered references. -- GitLab From dcf428c7a74e568deaededfc11d3c4e1bf7821f2 Mon Sep 17 00:00:00 2001 From: Andrey Turbanov Date: Wed, 13 Oct 2021 09:07:07 +0000 Subject: [PATCH 196/385] 8275075: Remove unnecessary conversion to String in jdk.hotspot.agent Reviewed-by: sspitsyn, cjplummer --- .../share/classes/sun/jvm/hotspot/HSDB.java | 4 ++-- .../hotspot/interpreter/BytecodeLoadConstant.java | 12 ++++++------ .../sun/jvm/hotspot/runtime/PerfDataEntry.java | 3 +-- .../jvm/hotspot/ui/classbrowser/HTMLGenerator.java | 8 ++++---- 4 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HSDB.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HSDB.java index 02b66512353..973fd6c3d0b 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HSDB.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HSDB.java @@ -951,8 +951,8 @@ public class HSDB implements ObjectHistogramPanel.Listener, SAListener { SignalInfo sigInfo = (SignalInfo) interruptedFrameMap.get(curFrame); if (sigInfo != null) { // This frame took a signal and we need to report it. - anno = (anno + "\n*** INTERRUPTED BY SIGNAL " + Integer.toString(sigInfo.sigNum) + - " (" + sigInfo.sigName + ")"); + anno = anno + "\n*** INTERRUPTED BY SIGNAL " + sigInfo.sigNum + + " (" + sigInfo.sigName + ")"; } JavaVFrame nextVFrame = curVFrame; diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeLoadConstant.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeLoadConstant.java index 81994f65120..28697fe7685 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeLoadConstant.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/BytecodeLoadConstant.java @@ -147,13 +147,13 @@ public class BytecodeLoadConstant extends Bytecode { int cpIndex = poolIndex(); ConstantTag ctag = cpool.getTagAt(cpIndex); if (ctag.isInt()) { - return ""; + return ""; } else if (ctag.isLong()) { - return ""; + return ""; } else if (ctag.isFloat()) { - return ""; + return ""; } else if (ctag.isDouble()) { - return ""; + return ""; } else if (ctag.isString()) { // tag change from 'unresolved' to 'string' does not happen atomically. // We just look at the object at the corresponding index and @@ -178,8 +178,8 @@ public class BytecodeLoadConstant extends Bytecode { Oop x = getCachedConstant(); int refidx = cpool.getMethodHandleIndexAt(cpIndex); int refkind = cpool.getMethodHandleRefKindAt(cpIndex); - return ""; } else if (ctag.isMethodType()) { Oop x = getCachedConstant(); diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/PerfDataEntry.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/PerfDataEntry.java index 4f8159257d5..5f95bda78df 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/PerfDataEntry.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/PerfDataEntry.java @@ -25,7 +25,6 @@ package sun.jvm.hotspot.runtime; import java.nio.charset.StandardCharsets; -import java.util.*; import sun.jvm.hotspot.debugger.*; import sun.jvm.hotspot.oops.*; import sun.jvm.hotspot.types.*; @@ -333,7 +332,7 @@ public class PerfDataEntry extends VMObject { if (dataType == BasicType.getTBoolean()) { str = Boolean.toString(booleanValue()); } else if (dataType == BasicType.getTChar()) { - str = "'" + Character.toString(charValue()) + "'"; + str = "'" + charValue() + "'"; } else if (dataType == BasicType.getTByte()) { str = Byte.toString(byteValue()); } else if (dataType == BasicType.getTShort()) { diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java index bf2ddffcb83..a6823cf1160 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java @@ -675,9 +675,9 @@ public class HTMLGenerator implements /* imports */ ClassConstants { buf.beginTag("tr"); if (hasLineNumbers) { int lineNumber = method.getLineNumberFromBCI(curBci); - buf.cell(Integer.toString(lineNumber) + spaces); + buf.cell(lineNumber + spaces); } - buf.cell(Integer.toString(curBci) + spaces); + buf.cell(curBci + spaces); buf.beginTag("td"); String instrStr = null; @@ -983,7 +983,7 @@ public class HTMLGenerator implements /* imports */ ClassConstants { public void epilogue() { } - }; + } protected String genHTMLForRawDisassembly(sun.jvm.hotspot.debugger.Address addr, int size, @@ -1007,7 +1007,7 @@ public class HTMLGenerator implements /* imports */ ClassConstants { Formatter tmpBuf = new Formatter(genHTML); long startPc = addressToLong(addr); tmpBuf.append("0x"); - tmpBuf.append(Long.toHexString(startPc + visitor.getInstructionSize()).toString()); + tmpBuf.append(Long.toHexString(startPc + visitor.getInstructionSize())); tmpBuf.append(",0x"); tmpBuf.append(Long.toHexString(startPc)); if (prevPCs != null) { -- GitLab From b8cb76ad210cb3e7524c7f5b13cfe57746ac05d4 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Wed, 13 Oct 2021 10:15:54 +0000 Subject: [PATCH 197/385] 8273682: Upgrade Jline to 3.20.0 Reviewed-by: sundar --- .../internal/org/jline/reader/Candidate.java | 5 + .../org/jline/reader/CompletionMatcher.java | 48 ++ .../org/jline/reader/ConfigurationPath.java | 75 --- .../org/jline/reader/EndOfFileException.java | 12 +- .../internal/org/jline/reader/LineReader.java | 67 ++- .../org/jline/reader/LineReaderBuilder.java | 11 +- .../jdk/internal/org/jline/reader/Parser.java | 6 +- .../org/jline/reader/PrintAboveWriter.java | 42 ++ .../org/jline/reader/ScriptEngine.java | 153 ----- .../reader/impl/CompletionMatcherImpl.java | 210 +++++++ .../jline/reader/impl/DefaultHighlighter.java | 6 +- .../org/jline/reader/impl/DefaultParser.java | 81 +-- .../org/jline/reader/impl/LineReaderImpl.java | 557 ++++++++++-------- .../org/jline/reader/impl/ReaderUtils.java | 13 +- .../impl/completer/StringsCompleter.java | 13 +- .../impl/completer/SystemCompleter.java | 150 +++++ .../reader/impl/history/DefaultHistory.java | 41 +- .../internal/org/jline/terminal/Terminal.java | 7 + .../org/jline/terminal/TerminalBuilder.java | 355 +++++++---- .../jline/terminal/impl/AbstractTerminal.java | 25 +- .../impl/AbstractWindowsTerminal.java | 2 - .../org/jline/terminal/spi/JansiSupport.java | 7 +- .../org/jline/terminal/spi/JnaSupport.java | 7 +- .../jline/utils/AttributedCharSequence.java | 142 +++-- .../org/jline/utils/AttributedString.java | 12 +- .../jline/utils/AttributedStringBuilder.java | 20 +- .../org/jline/utils/AttributedStyle.java | 94 ++- .../org/jline/utils/ColorPalette.java | 262 ++++++++ .../jdk/internal/org/jline/utils/Colors.java | 121 ++-- .../jdk/internal/org/jline/utils/Curses.java | 75 ++- .../jdk/internal/org/jline/utils/Display.java | 4 + .../jdk/internal/org/jline/utils/InfoCmp.java | 2 +- .../jdk/internal/org/jline/utils/Log.java | 9 +- .../utils/NonBlockingPumpInputStream.java | 14 + .../jline/utils/NonBlockingPumpReader.java | 6 +- .../internal/org/jline/utils/PumpReader.java | 2 +- .../jdk/internal/org/jline/utils/Signals.java | 11 +- .../org/jline/utils/StyleResolver.java | 111 +++- .../internal/org/jline/utils/rxvt-basic.caps | 41 ++ .../jline/utils/rxvt-unicode-256color.caps | 44 ++ .../org/jline/utils/rxvt-unicode.caps | 44 ++ .../jdk/internal/org/jline/utils/rxvt.caps | 43 ++ src/jdk.internal.le/share/legal/jline.md | 2 +- .../terminal/impl/jna/JnaSupportImpl.java | 27 + .../impl/jna/win/JnaWinSysTerminal.java | 36 +- .../jline/AbstractWindowsTerminalTest.java | 7 +- .../jdk/internal/jline/KeyConversionTest.java | 9 +- 47 files changed, 2194 insertions(+), 837 deletions(-) create mode 100644 src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/CompletionMatcher.java delete mode 100644 src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/ConfigurationPath.java create mode 100644 src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/PrintAboveWriter.java delete mode 100644 src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/ScriptEngine.java create mode 100644 src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/CompletionMatcherImpl.java create mode 100644 src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/completer/SystemCompleter.java create mode 100644 src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/ColorPalette.java create mode 100644 src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/rxvt-basic.caps create mode 100644 src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/rxvt-unicode-256color.caps create mode 100644 src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/rxvt-unicode.caps create mode 100644 src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/rxvt.caps diff --git a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/Candidate.java b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/Candidate.java index 98a18cbca71..51f449f20ee 100644 --- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/Candidate.java +++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/Candidate.java @@ -137,4 +137,9 @@ public class Candidate implements Comparable { public int compareTo(Candidate o) { return value.compareTo(o.value); } + + @Override + public String toString() { + return "Candidate{" + value + "}"; + } } diff --git a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/CompletionMatcher.java b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/CompletionMatcher.java new file mode 100644 index 00000000000..3cfd73fa19a --- /dev/null +++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/CompletionMatcher.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2002-2020, the original author or authors. + * + * This software is distributable under the BSD license. See the terms of the + * BSD license in the documentation provided with this software. + * + * https://opensource.org/licenses/BSD-3-Clause + */ +package jdk.internal.org.jline.reader; + +import java.util.List; +import java.util.Map; + +public interface CompletionMatcher { + + /** + * Compiles completion matcher functions + * + * @param options LineReader options + * @param prefix invoked by complete-prefix or expand-or-complete-prefix widget + * @param line The parsed line within which completion has been requested + * @param caseInsensitive if completion is case insensitive or not + * @param errors number of errors accepted in matching + * @param originalGroupName value of JLineReader variable original-group-name + */ + void compile(Map options, boolean prefix, CompletingParsedLine line + , boolean caseInsensitive, int errors, String originalGroupName); + + /** + * + * @param candidates list of candidates + * @return a map of candidates that completion matcher matches + */ + List matches(List candidates); + + /** + * + * @return a candidate that have exact match, null if no exact match found + */ + Candidate exactMatch(); + + /** + * + * @return a common prefix of matched candidates + */ + String getCommonPrefix(); + +} diff --git a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/ConfigurationPath.java b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/ConfigurationPath.java deleted file mode 100644 index a8663e8b1bb..00000000000 --- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/ConfigurationPath.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2002-2019, the original author or authors. - * - * This software is distributable under the BSD license. See the terms of the - * BSD license in the documentation provided with this software. - * - * https://opensource.org/licenses/BSD-3-Clause - */ -package jdk.internal.org.jline.reader; - -import java.io.IOException; -import java.nio.file.Path; - -public class ConfigurationPath { - private Path appConfig; - private Path userConfig; - - /** - * Configuration class constructor. - * @param appConfig Application configuration directory - * @param userConfig User private configuration directory - */ - public ConfigurationPath(Path appConfig, Path userConfig) { - this.appConfig = appConfig; - this.userConfig = userConfig; - } - - /** - * Search configuration file first from userConfig and then appConfig directory. Returns null if file is not found. - * @param name Configuration file name. - * @return Configuration file. - * - */ - public Path getConfig(String name) { - Path out = null; - if (userConfig != null && userConfig.resolve(name).toFile().exists()) { - out = userConfig.resolve(name); - } else if (appConfig != null && appConfig.resolve(name).toFile().exists()) { - out = appConfig.resolve(name); - } - return out; - } - - /** - * Search configuration file from userConfig directory. Returns null if file is not found. - * @param name Configuration file name. - * @return Configuration file. - * @throws IOException When we do not have read access to the file or directory. - * - */ - public Path getUserConfig(String name) throws IOException { - return getUserConfig(name, false); - } - - /** - * Search configuration file from userConfig directory. Returns null if file is not found. - * @param name Configuration file name - * @param create When true configuration file is created if not found. - * @return Configuration file. - * @throws IOException When we do not have read/write access to the file or directory. - */ - public Path getUserConfig(String name, boolean create) throws IOException { - Path out = null; - if (userConfig != null) { - if (!userConfig.resolve(name).toFile().exists() && create) { - userConfig.resolve(name).toFile().createNewFile(); - } - if (userConfig.resolve(name).toFile().exists()) { - out = userConfig.resolve(name); - } - } - return out; - } - -} diff --git a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/EndOfFileException.java b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/EndOfFileException.java index 9f39b9e0e8b..9f70420d9df 100644 --- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/EndOfFileException.java +++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/EndOfFileException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002-2016, the original author or authors. + * Copyright (c) 2002-2020, the original author or authors. * * This software is distributable under the BSD license. See the terms of the * BSD license in the documentation provided with this software. @@ -15,6 +15,7 @@ package jdk.internal.org.jline.reader; public class EndOfFileException extends RuntimeException { private static final long serialVersionUID = 528485360925144689L; + private String partialLine; public EndOfFileException() { } @@ -34,4 +35,13 @@ public class EndOfFileException extends RuntimeException { public EndOfFileException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { super(message, cause, enableSuppression, writableStackTrace); } + + public EndOfFileException partialLine(String partialLine) { + this.partialLine = partialLine; + return this; + } + + public String getPartialLine() { + return partialLine; + } } diff --git a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/LineReader.java b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/LineReader.java index 4effefb8583..07b72668721 100644 --- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/LineReader.java +++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/LineReader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002-2019, the original author or authors. + * Copyright (c) 2002-2021, the original author or authors. * * This software is distributable under the BSD license. See the terms of the * BSD license in the documentation provided with this software. @@ -294,7 +294,13 @@ public interface LineReader { String COMMENT_BEGIN = "comment-begin"; String BELL_STYLE = "bell-style"; String PREFER_VISIBLE_BELL = "prefer-visible-bell"; + /** tab completion: if candidates are more than list-max a question will be asked before displaying them */ String LIST_MAX = "list-max"; + /** + * tab completion: if candidates are less than menu-list-max + * they are displayed in a list below the field to be completed + */ + String MENU_LIST_MAX = "menu-list-max"; String DISABLE_HISTORY = "disable-history"; String DISABLE_COMPLETION = "disable-completion"; String EDITING_MODE = "editing-mode"; @@ -303,6 +309,7 @@ public interface LineReader { String WORDCHARS = "WORDCHARS"; String REMOVE_SUFFIX_CHARS = "REMOVE_SUFFIX_CHARS"; String SEARCH_TERMINATORS = "search-terminators"; + /** Number of matching errors that are accepted by the completion matcher */ String ERRORS = "errors"; /** Property for the "others" group name */ String OTHERS_GROUP_NAME = "OTHERS_GROUP_NAME"; @@ -310,12 +317,19 @@ public interface LineReader { String ORIGINAL_GROUP_NAME = "ORIGINAL_GROUP_NAME"; /** Completion style for displaying groups name */ String COMPLETION_STYLE_GROUP = "COMPLETION_STYLE_GROUP"; + String COMPLETION_STYLE_LIST_GROUP = "COMPLETION_STYLE_LIST_GROUP"; /** Completion style for displaying the current selected item */ String COMPLETION_STYLE_SELECTION = "COMPLETION_STYLE_SELECTION"; + String COMPLETION_STYLE_LIST_SELECTION = "COMPLETION_STYLE_LIST_SELECTION"; /** Completion style for displaying the candidate description */ String COMPLETION_STYLE_DESCRIPTION = "COMPLETION_STYLE_DESCRIPTION"; + String COMPLETION_STYLE_LIST_DESCRIPTION = "COMPLETION_STYLE_LIST_DESCRIPTION"; /** Completion style for displaying the matching part of candidates */ String COMPLETION_STYLE_STARTING = "COMPLETION_STYLE_STARTING"; + String COMPLETION_STYLE_LIST_STARTING = "COMPLETION_STYLE_LIST_STARTING"; + /** Completion style for displaying the list */ + String COMPLETION_STYLE_BACKGROUND = "COMPLETION_STYLE_BACKGROUND"; + String COMPLETION_STYLE_LIST_BACKGROUND = "COMPLETION_STYLE_LIST_BACKGROUND"; /** * Set the template for prompts for secondary (continuation) lines. * This is a prompt template as described in the class header. @@ -370,10 +384,20 @@ public interface LineReader { */ String FEATURES_MAX_BUFFER_SIZE = "features-max-buffer-size"; + /** + * Min buffer size for tab auto-suggestions. + * For shorter buffer sizes auto-suggestions are not resolved. + */ + String SUGGESTIONS_MIN_BUFFER_SIZE = "suggestions-min-buffer-size"; + Map> defaultKeyMaps(); enum Option { COMPLETE_IN_WORD, + /** use camel case completion matcher */ + COMPLETE_MATCHER_CAMELCASE, + /** use type completion matcher */ + COMPLETE_MATCHER_TYPO(true), DISABLE_EVENT_EXPANSION, HISTORY_VERIFY, HISTORY_IGNORE_SPACE(true), @@ -386,9 +410,13 @@ public interface LineReader { AUTO_GROUP(true), AUTO_MENU(true), AUTO_LIST(true), + /** list candidates below the field to be completed */ + AUTO_MENU_LIST, RECOGNIZE_EXACT, /** display group name before each group (else display all group names first) */ GROUP(true), + /** when double tab to select candidate keep candidates grouped (else loose grouping) */ + GROUP_PERSIST, /** if completion is case insensitive or not */ CASE_INSENSITIVE, LIST_AMBIGUOUS, @@ -414,7 +442,8 @@ public interface LineReader { DELAY_LINE_WRAP, AUTO_PARAM_SLASH(true), AUTO_REMOVE_SLASH(true), - USE_FORWARD_SLASH(false), + /** FileNameCompleter: Use '/' character as a file directory separator */ + USE_FORWARD_SLASH, /** When hitting the <tab> key at the beginning of the line, insert a tabulation * instead of completing. This is mainly useful when {@link #BRACKETED_PASTE} is * disabled, so that copy/paste of indented text does not trigger completion. @@ -450,6 +479,11 @@ public interface LineReader { this.def = def; } + public final boolean isSet(Map options) { + Boolean b = options.get(this); + return b != null ? b : this.isDef(); + } + public boolean isDef() { return def; } @@ -489,8 +523,9 @@ public interface LineReader { * Equivalent to readLine(null, null, null). * * @return the line read - * @throws UserInterruptException If the call was interrupted by the user. - * @throws EndOfFileException If the end of the input stream was reached. + * @throws UserInterruptException if readLine was interrupted (using Ctrl-C for example) + * @throws EndOfFileException if an EOF has been found (using Ctrl-D for example) + * @throws java.io.IOError in case of other i/o errors */ String readLine() throws UserInterruptException, EndOfFileException; @@ -502,8 +537,9 @@ public interface LineReader { * * @param mask The mask character, null or 0. * @return A line that is read from the terminal, can never be null. - * @throws UserInterruptException If the call was interrupted by the user. - * @throws EndOfFileException If the end of the input stream was reached. + * @throws UserInterruptException if readLine was interrupted (using Ctrl-C for example) + * @throws EndOfFileException if an EOF has been found (using Ctrl-D for example) + * @throws java.io.IOError in case of other i/o errors */ String readLine(Character mask) throws UserInterruptException, EndOfFileException; @@ -515,8 +551,9 @@ public interface LineReader { * * @param prompt The prompt to issue to the terminal, may be null. * @return A line that is read from the terminal, can never be null. - * @throws UserInterruptException If the call was interrupted by the user. - * @throws EndOfFileException If the end of the input stream was reached. + * @throws UserInterruptException if readLine was interrupted (using Ctrl-C for example) + * @throws EndOfFileException if an EOF has been found (using Ctrl-D for example) + * @throws java.io.IOError in case of other i/o errors */ String readLine(String prompt) throws UserInterruptException, EndOfFileException; @@ -529,8 +566,9 @@ public interface LineReader { * @param prompt The prompt to issue to the terminal, may be null. * @param mask The mask character, null or 0. * @return A line that is read from the terminal, can never be null. - * @throws UserInterruptException If the call was interrupted by the user. - * @throws EndOfFileException If the end of the input stream was reached. + * @throws UserInterruptException if readLine was interrupted (using Ctrl-C for example) + * @throws EndOfFileException if an EOF has been found (using Ctrl-D for example) + * @throws java.io.IOError in case of other i/o errors */ String readLine(String prompt, Character mask) throws UserInterruptException, EndOfFileException; @@ -546,8 +584,9 @@ public interface LineReader { * @param mask The character mask, may be null. * @param buffer The default value presented to the user to edit, may be null. * @return A line that is read from the terminal, can never be null. - * @throws UserInterruptException If the call was interrupted by the user. - * @throws EndOfFileException If the end of the input stream was reached. + * @throws UserInterruptException if readLine was interrupted (using Ctrl-C for example) + * @throws EndOfFileException if an EOF has been found (using Ctrl-D for example) + * @throws java.io.IOError in case of other i/o errors */ String readLine(String prompt, Character mask, String buffer) throws UserInterruptException, EndOfFileException; @@ -568,8 +607,6 @@ public interface LineReader { * @throws UserInterruptException if readLine was interrupted (using Ctrl-C for example) * @throws EndOfFileException if an EOF has been found (using Ctrl-D for example) * @throws java.io.IOError in case of other i/o errors - * @throws UserInterruptException If the call was interrupted by the user. - * @throws EndOfFileException If the end of the input stream was reached. */ String readLine(String prompt, String rightPrompt, Character mask, String buffer) throws UserInterruptException, EndOfFileException; @@ -590,8 +627,6 @@ public interface LineReader { * @throws UserInterruptException if readLine was interrupted (using Ctrl-C for example) * @throws EndOfFileException if an EOF has been found (using Ctrl-D for example) * @throws java.io.IOError in case of other i/o errors - * @throws UserInterruptException If the call was interrupted by the user. - * @throws EndOfFileException If the end of the input stream was reached. */ String readLine(String prompt, String rightPrompt, MaskingCallback maskingCallback, String buffer) throws UserInterruptException, EndOfFileException; diff --git a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/LineReaderBuilder.java b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/LineReaderBuilder.java index 20a3f64a0a5..422561a86c5 100644 --- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/LineReaderBuilder.java +++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/LineReaderBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002-2018, the original author or authors. + * Copyright (c) 2002-2020, the original author or authors. * * This software is distributable under the BSD license. See the terms of the * BSD license in the documentation provided with this software. @@ -36,6 +36,7 @@ public final class LineReaderBuilder { Highlighter highlighter; Parser parser; Expander expander; + CompletionMatcher completionMatcher; private LineReaderBuilder() { } @@ -103,6 +104,11 @@ public final class LineReaderBuilder { return this; } + public LineReaderBuilder completionMatcher(CompletionMatcher completionMatcher) { + this.completionMatcher = completionMatcher; + return this; + } + public LineReader build() { Terminal terminal = this.terminal; if (terminal == null) { @@ -133,6 +139,9 @@ public final class LineReaderBuilder { if (expander != null) { reader.setExpander(expander); } + if (completionMatcher != null) { + reader.setCompletionMatcher(completionMatcher); + } for (Map.Entry e : options.entrySet()) { reader.option(e.getKey(), e.getValue()); } diff --git a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/Parser.java b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/Parser.java index 1f6a4c6c670..2e2ad8c24bc 100644 --- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/Parser.java +++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/Parser.java @@ -35,16 +35,12 @@ public interface Parser { default String getCommand(final String line) { String out = ""; - Pattern patternCommand = Pattern.compile("^\\s*" + REGEX_VARIABLE + "=(" + REGEX_COMMAND + ")(\\s+.*|$)"); + Pattern patternCommand = Pattern.compile("^\\s*" + REGEX_VARIABLE + "=(" + REGEX_COMMAND + ")(\\s+|$)"); Matcher matcher = patternCommand.matcher(line); if (matcher.find()) { out = matcher.group(1); } else { out = line.trim().split("\\s+")[0]; - int idx = out.indexOf("="); - if (idx > -1) { - out = out.substring(idx + 1); - } if (!out.matches(REGEX_COMMAND)) { out = ""; } diff --git a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/PrintAboveWriter.java b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/PrintAboveWriter.java new file mode 100644 index 00000000000..63c9decd194 --- /dev/null +++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/PrintAboveWriter.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2002-2021, the original author or authors. + * + * This software is distributable under the BSD license. See the terms of the + * BSD license in the documentation provided with this software. + * + * https://opensource.org/licenses/BSD-3-Clause + */ +package jdk.internal.org.jline.reader; + +import java.io.StringWriter; +import java.io.Writer; + +/** + * Redirects a {@link Writer} to a {@link LineReader}'s {@link LineReader#printAbove(String)} method, + * which draws output above the current prompt / input line. + * + *

      Example:

      + *
      + *     LineReader reader = LineReaderBuilder.builder().terminal(terminal).parser(parser).build();
      + *     PrintAboveWriter printAbove = new PrintAboveWriter(reader);
      + *     printAbove.write(new char[] { 'h', 'i', '!', '\n'});
      + * 
      + * + */ +public class PrintAboveWriter extends StringWriter { + private final LineReader reader; + + public PrintAboveWriter(LineReader reader) { + this.reader = reader; + } + + @Override + public void flush() { + StringBuffer buffer = getBuffer(); + int lastNewline = buffer.lastIndexOf("\n"); + if (lastNewline >= 0) { + reader.printAbove(buffer.substring(0, lastNewline + 1)); + buffer.delete(0, lastNewline + 1); + } + } +} diff --git a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/ScriptEngine.java b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/ScriptEngine.java deleted file mode 100644 index ab4f24e994d..00000000000 --- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/ScriptEngine.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright (c) 2002-2020, the original author or authors. - * - * This software is distributable under the BSD license. See the terms of the - * BSD license in the documentation provided with this software. - * - * https://opensource.org/licenses/BSD-3-Clause - */ -package jdk.internal.org.jline.reader; - -import java.io.File; -import java.nio.file.Path; -import java.util.*; - -/** - * Manage scriptEngine variables, statements and script execution. - * - * @author Matti Rinta-Nikkola - */ -public interface ScriptEngine { - - /** - * - * @return scriptEngine name - */ - String getEngineName(); - - /** - * - * @return script file name extensions - */ - Collection getExtensions(); - - /** - * Tests if console variable exists - * @param name - * @return true if variable exists - */ - boolean hasVariable(String name); - - /** - * Creates variable - * @param name of the variable - * @param value of the variable - */ - void put(String name, Object value); - - /** - * Gets variable value - * @param name of the variable - * @return value of the variable - */ - Object get(String name); - - /** - * Gets all variables with values - * @return map of the variables - */ - default Map find() { - return find(null); - } - - /** - * Gets all the variables that match the name. Name can contain * wild cards. - * @param name of the variable - * @return map of the variables - */ - Map find(String name); - - /** - * Deletes variables. Variable name cab contain * wild cards. - * @param vars - */ - void del(String... vars); - - /** - * Converts object to JSON string. - * @param object object to convert to JSON - * @return formatted JSON string - */ - String toJson(Object object); - - /** - * Converts object to string. - * @param object object to convert to string - * @return object string value - */ - String toString(Object object); - - /** - * Substitute variable reference with its value. - * @param variable - * @return Substituted variable - * @throws Exception - */ - default Object expandParameter(String variable) { - return expandParameter(variable, ""); - } - - /** - * Substitute variable reference with its value. - * @param variable - * @param format serialization format - * @return Substituted variable - * @throws Exception - */ - Object expandParameter(String variable, String format); - - /** - * Persists object value to file. - * @param file - * @param object - */ - default void persist(Path file, Object object) { - persist(file, object, "JSON"); - } - - /** - * Persists object value to file. - * @param file - * @param object - * @param format - */ - void persist(Path file, Object object, String format); - - /** - * Executes scriptEngine statement - * @param statement - * @return result - * @throws Exception - */ - Object execute(String statement) throws Exception; - - /** - * Executes scriptEngine script - * @param script - * @return result - * @throws Exception - */ - default Object execute(File script) throws Exception { - return execute(script, null); - } - - /** - * Executes scriptEngine script - * @param script - * @param args - * @return - * @throws Exception - */ - Object execute(File script, Object[] args) throws Exception; - -} diff --git a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/CompletionMatcherImpl.java b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/CompletionMatcherImpl.java new file mode 100644 index 00000000000..0d4ead5743d --- /dev/null +++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/CompletionMatcherImpl.java @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2002-2021, the original author or authors. + * + * This software is distributable under the BSD license. See the terms of the + * BSD license in the documentation provided with this software. + * + * https://opensource.org/licenses/BSD-3-Clause + */ +package jdk.internal.org.jline.reader.impl; + +import jdk.internal.org.jline.reader.Candidate; +import jdk.internal.org.jline.reader.CompletingParsedLine; +import jdk.internal.org.jline.reader.CompletionMatcher; +import jdk.internal.org.jline.reader.LineReader; +import jdk.internal.org.jline.utils.AttributedString; + +import java.util.*; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +public class CompletionMatcherImpl implements CompletionMatcher { + protected Predicate exact; + protected List>, Map>>> matchers; + private Map> matching; + private boolean caseInsensitive; + + public CompletionMatcherImpl() { + } + + protected void reset(boolean caseInsensitive) { + this.caseInsensitive = caseInsensitive; + exact = s -> false; + matchers = new ArrayList<>(); + matching = null; + } + + @Override + public void compile(Map options, boolean prefix, CompletingParsedLine line + , boolean caseInsensitive, int errors, String originalGroupName) { + reset(caseInsensitive); + defaultMatchers(options, prefix, line, caseInsensitive, errors, originalGroupName); + } + + @Override + public List matches(List candidates) { + matching = Collections.emptyMap(); + Map> sortedCandidates = sort(candidates); + for (Function>, + Map>> matcher : matchers) { + matching = matcher.apply(sortedCandidates); + if (!matching.isEmpty()) { + break; + } + } + return !matching.isEmpty() ? matching.entrySet().stream().flatMap(e -> e.getValue().stream()).collect(Collectors.toList()) + : new ArrayList<>(); + } + + @Override + public Candidate exactMatch() { + if (matching == null) { + throw new IllegalStateException(); + } + return matching.values().stream().flatMap(Collection::stream) + .filter(Candidate::complete) + .filter(c -> exact.test(c.value())) + .findFirst().orElse(null); + } + + @Override + public String getCommonPrefix() { + if (matching == null) { + throw new IllegalStateException(); + } + String commonPrefix = null; + for (String key : matching.keySet()) { + commonPrefix = commonPrefix == null ? key : getCommonStart(commonPrefix, key, caseInsensitive); + } + return commonPrefix; + } + + /** + * Default JLine matchers + */ + protected void defaultMatchers(Map options, boolean prefix, CompletingParsedLine line + , boolean caseInsensitive, int errors, String originalGroupName) { + // Find matchers + // TODO: glob completion + String wd = line.word(); + String wdi = caseInsensitive ? wd.toLowerCase() : wd; + String wp = wdi.substring(0, line.wordCursor()); + if (prefix) { + matchers = new ArrayList<>(Arrays.asList( + simpleMatcher(s -> (caseInsensitive ? s.toLowerCase() : s).startsWith(wp)), + simpleMatcher(s -> (caseInsensitive ? s.toLowerCase() : s).contains(wp)) + )); + if (LineReader.Option.COMPLETE_MATCHER_TYPO.isSet(options)) { + matchers.add(typoMatcher(wp, errors, caseInsensitive, originalGroupName)); + } + exact = s -> caseInsensitive ? s.equalsIgnoreCase(wp) : s.equals(wp); + } else if (!LineReader.Option.EMPTY_WORD_OPTIONS.isSet(options) && wd.length() == 0) { + matchers = new ArrayList<>(Collections.singletonList(simpleMatcher(s -> !s.startsWith("-")))); + exact = s -> caseInsensitive ? s.equalsIgnoreCase(wd) : s.equals(wd); + } else { + if (LineReader.Option.COMPLETE_IN_WORD.isSet(options)) { + String ws = wdi.substring(line.wordCursor()); + Pattern p1 = Pattern.compile(Pattern.quote(wp) + ".*" + Pattern.quote(ws) + ".*"); + Pattern p2 = Pattern.compile(".*" + Pattern.quote(wp) + ".*" + Pattern.quote(ws) + ".*"); + matchers = new ArrayList<>(Arrays.asList( + simpleMatcher(s -> p1.matcher(caseInsensitive ? s.toLowerCase() : s).matches()), + simpleMatcher(s -> p2.matcher(caseInsensitive ? s.toLowerCase() : s).matches()) + )); + } else { + matchers = new ArrayList<>(Arrays.asList( + simpleMatcher(s -> (caseInsensitive ? s.toLowerCase() : s).startsWith(wdi)), + simpleMatcher(s -> (caseInsensitive ? s.toLowerCase() : s).contains(wdi)) + )); + } + if (LineReader.Option.COMPLETE_MATCHER_CAMELCASE.isSet(options)) { + matchers.add(simpleMatcher(s -> camelMatch(wd, 0, s, 0))); + } + if (LineReader.Option.COMPLETE_MATCHER_TYPO.isSet(options)) { + matchers.add(typoMatcher(wdi, errors, caseInsensitive, originalGroupName)); + } + exact = s -> caseInsensitive ? s.equalsIgnoreCase(wd) : s.equals(wd); + } + } + + protected Function>, + Map>> simpleMatcher(Predicate predicate) { + return m -> m.entrySet().stream() + .filter(e -> predicate.test(e.getKey())) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + } + + protected Function>, + Map>> typoMatcher(String word, int errors, boolean caseInsensitive, String originalGroupName) { + return m -> { + Map> map = m.entrySet().stream() + .filter(e -> ReaderUtils.distance(word, caseInsensitive ? e.getKey().toLowerCase() : e.getKey()) < errors) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + if (map.size() > 1) { + map.computeIfAbsent(word, w -> new ArrayList<>()) + .add(new Candidate(word, word, originalGroupName, null, null, null, false)); + } + return map; + }; + } + + protected boolean camelMatch(String word, int i, String candidate, int j) { + if (word.length() <= i) { + return true; + } else if (candidate.length() <= j) { + return false; + } else { + char c = word.charAt(i); + if (c == candidate.charAt(j)) { + return camelMatch(word, i + 1, candidate, j + 1); + } else { + for (int j1 = j; j1 < candidate.length(); j1++) { + if (Character.isUpperCase(candidate.charAt(j1))) { + if (Character.toUpperCase(c) == candidate.charAt(j1)) { + if (camelMatch(word, i + 1, candidate, j1 + 1)) { + return true; + } + } + } + } + return false; + } + } + } + + private Map> sort(List candidates) { + // Build a list of sorted candidates + Map> sortedCandidates = new HashMap<>(); + for (Candidate candidate : candidates) { + sortedCandidates + .computeIfAbsent(AttributedString.fromAnsi(candidate.value()).toString(), s -> new ArrayList<>()) + .add(candidate); + } + return sortedCandidates; + } + + private String getCommonStart(String str1, String str2, boolean caseInsensitive) { + int[] s1 = str1.codePoints().toArray(); + int[] s2 = str2.codePoints().toArray(); + int len = 0; + while (len < Math.min(s1.length, s2.length)) { + int ch1 = s1[len]; + int ch2 = s2[len]; + if (ch1 != ch2 && caseInsensitive) { + ch1 = Character.toUpperCase(ch1); + ch2 = Character.toUpperCase(ch2); + if (ch1 != ch2) { + ch1 = Character.toLowerCase(ch1); + ch2 = Character.toLowerCase(ch2); + } + } + if (ch1 != ch2) { + break; + } + len++; + } + return new String(s1, 0, len); + } + +} \ No newline at end of file diff --git a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/DefaultHighlighter.java b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/DefaultHighlighter.java index 6dfff639d46..ac286ad734f 100644 --- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/DefaultHighlighter.java +++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/DefaultHighlighter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002-2019, the original author or authors. + * Copyright (c) 2002-2021, the original author or authors. * * This software is distributable under the BSD license. See the terms of the * BSD license in the documentation provided with this software. @@ -19,8 +19,8 @@ import jdk.internal.org.jline.utils.AttributedStyle; import jdk.internal.org.jline.utils.WCWidth; public class DefaultHighlighter implements Highlighter { - private Pattern errorPattern; - private int errorIndex = -1; + protected Pattern errorPattern; + protected int errorIndex = -1; @Override public void setErrorPattern(Pattern errorPattern) { diff --git a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/DefaultParser.java b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/DefaultParser.java index a7334ccea4a..4fb616f61dc 100644 --- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/DefaultParser.java +++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/DefaultParser.java @@ -24,7 +24,7 @@ public class DefaultParser implements Parser { ROUND, // () CURLY, // {} SQUARE, // [] - ANGLE; // <> + ANGLE // <> } private char[] quoteChars = {'\'', '"'}; @@ -39,8 +39,8 @@ public class DefaultParser implements Parser { private char[] closingBrackets = null; - private String regexVariable = "[a-zA-Z_]{1,}[a-zA-Z0-9_-]*((.|\\['|\\[\\\"|\\[)[a-zA-Z0-9_-]*(|'\\]|\\\"\\]|\\])){0,1}"; - private String regexCommand = "[:]{0,1}[a-zA-Z]{1,}[a-zA-Z0-9_-]*"; + private String regexVariable = "[a-zA-Z_]+[a-zA-Z0-9_-]*((\\.|\\['|\\[\"|\\[)[a-zA-Z0-9_-]*(|']|\"]|]))?"; + private String regexCommand = "[:]?[a-zA-Z]+[a-zA-Z0-9_-]*"; private int commandGroup = 4; // @@ -175,23 +175,25 @@ public class DefaultParser implements Parser { @Override public boolean validVariableName(String name) { - return name != null && name.matches(regexVariable); + return name != null && regexVariable != null && name.matches(regexVariable); } @Override public String getCommand(final String line) { String out = ""; - Pattern patternCommand = Pattern.compile("^\\s*" + regexVariable + "=(" + regexCommand + ")(\\s+.*|$)"); - Matcher matcher = patternCommand.matcher(line); - if (matcher.find()) { - out = matcher.group(commandGroup); - } else { - out = line.trim().split("\\s+")[0]; - int idx = out.indexOf("="); - if (idx > -1) { - out = out.substring(idx + 1); + boolean checkCommandOnly = regexVariable == null; + if (!checkCommandOnly) { + Pattern patternCommand = Pattern.compile("^\\s*" + regexVariable + "=(" + regexCommand + ")(\\s+|$)"); + Matcher matcher = patternCommand.matcher(line); + if (matcher.find()) { + out = matcher.group(commandGroup); + } else { + checkCommandOnly = true; } + } + if (checkCommandOnly) { + out = line.trim().split("\\s+")[0]; if (!out.matches(regexCommand)) { out = ""; } @@ -202,10 +204,12 @@ public class DefaultParser implements Parser { @Override public String getVariable(final String line) { String out = null; - Pattern patternCommand = Pattern.compile("^\\s*(" + regexVariable + ")\\s*=[^=~].*"); - Matcher matcher = patternCommand.matcher(line); - if (matcher.find()) { - out = matcher.group(1); + if (regexVariable != null) { + Pattern patternCommand = Pattern.compile("^\\s*(" + regexVariable + ")\\s*=[^=~].*"); + Matcher matcher = patternCommand.matcher(line); + if (matcher.find()) { + out = matcher.group(1); + } } return out; } @@ -289,7 +293,7 @@ public class DefaultParser implements Parser { rawWordLength = rawWordCursor; } - if (context != ParseContext.COMPLETE) { + if (context != ParseContext.COMPLETE && context != ParseContext.SPLIT_LINE) { if (eofOnEscapedNewLine && isEscapeChar(line, line.length() - 1)) { throw new EOFError(-1, -1, "Escaped new line", "newline"); } @@ -609,25 +613,28 @@ public class DefaultParser implements Parser { } } if (escapeChars != null) { - // Completion is protected by an opening quote: - // Delimiters (spaces) don't need to be escaped, nor do other quotes, but everything else does. - // Also, close the quote at the end - if (openingQuote != null) { - needToBeEscaped = i -> isRawEscapeChar(sb.charAt(i)) || String.valueOf(sb.charAt(i)).equals(openingQuote); - } - // Completion is protected by middle quotes: - // Delimiters (spaces) don't need to be escaped, nor do quotes, but everything else does. - else if (middleQuotes) { - needToBeEscaped = i -> isRawEscapeChar(sb.charAt(i)); - } - // No quote protection, need to escape everything: delimiter chars (spaces), quote chars - // and escapes themselves - else { - needToBeEscaped = i -> isDelimiterChar(sb, i) || isRawEscapeChar(sb.charAt(i)) || isRawQuoteChar(sb.charAt(i)); - } - for (int i = 0; i < sb.length(); i++) { - if (needToBeEscaped.test(i)) { - sb.insert(i++, escapeChars[0]); + if (escapeChars.length > 0) { + // Completion is protected by an opening quote: + // Delimiters (spaces) don't need to be escaped, nor do other quotes, but everything else does. + // Also, close the quote at the end + if (openingQuote != null) { + needToBeEscaped = i -> isRawEscapeChar(sb.charAt(i)) || String.valueOf(sb.charAt(i)).equals(openingQuote); + } + // Completion is protected by middle quotes: + // Delimiters (spaces) don't need to be escaped, nor do quotes, but everything else does. + else if (middleQuotes) { + needToBeEscaped = i -> isRawEscapeChar(sb.charAt(i)); + } + // No quote protection, need to escape everything: delimiter chars (spaces), quote chars + // and escapes themselves + else { + needToBeEscaped = i -> isDelimiterChar(sb, i) || isRawEscapeChar(sb.charAt(i)) + || isRawQuoteChar(sb.charAt(i)); + } + for (int i = 0; i < sb.length(); i++) { + if (needToBeEscaped.test(i)) { + sb.insert(i++, escapeChars[0]); + } } } } else if (openingQuote == null && !middleQuotes) { diff --git a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/LineReaderImpl.java b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/LineReaderImpl.java index b6592b68819..b32dde1d902 100644 --- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/LineReaderImpl.java +++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/LineReaderImpl.java @@ -20,7 +20,6 @@ import java.io.InterruptedIOException; import java.lang.reflect.Constructor; import java.time.Instant; import java.util.*; -import java.util.Map.Entry; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.locks.ReentrantLock; import java.util.function.*; @@ -46,9 +45,9 @@ import jdk.internal.org.jline.utils.AttributedStyle; import jdk.internal.org.jline.utils.Curses; import jdk.internal.org.jline.utils.Display; import jdk.internal.org.jline.utils.InfoCmp.Capability; -import jdk.internal.org.jline.utils.Levenshtein; import jdk.internal.org.jline.utils.Log; import jdk.internal.org.jline.utils.Status; +import jdk.internal.org.jline.utils.StyleResolver; import jdk.internal.org.jline.utils.WCWidth; import static jdk.internal.org.jline.keymap.KeyMap.alt; @@ -80,18 +79,26 @@ public class LineReaderImpl implements LineReader, Flushable public static final String DEFAULT_SEARCH_TERMINATORS = "\033\012"; public static final String DEFAULT_BELL_STYLE = ""; public static final int DEFAULT_LIST_MAX = 100; + public static final int DEFAULT_MENU_LIST_MAX = Integer.MAX_VALUE; public static final int DEFAULT_ERRORS = 2; public static final long DEFAULT_BLINK_MATCHING_PAREN = 500L; public static final long DEFAULT_AMBIGUOUS_BINDING = 1000L; public static final String DEFAULT_SECONDARY_PROMPT_PATTERN = "%M> "; public static final String DEFAULT_OTHERS_GROUP_NAME = "others"; public static final String DEFAULT_ORIGINAL_GROUP_NAME = "original"; - public static final String DEFAULT_COMPLETION_STYLE_STARTING = "36"; // cyan - public static final String DEFAULT_COMPLETION_STYLE_DESCRIPTION = "90"; // dark gray - public static final String DEFAULT_COMPLETION_STYLE_GROUP = "35;1"; // magenta - public static final String DEFAULT_COMPLETION_STYLE_SELECTION = "7"; // inverted + public static final String DEFAULT_COMPLETION_STYLE_STARTING = "fg:cyan"; + public static final String DEFAULT_COMPLETION_STYLE_DESCRIPTION = "fg:bright-black"; + public static final String DEFAULT_COMPLETION_STYLE_GROUP = "fg:bright-magenta,bold"; + public static final String DEFAULT_COMPLETION_STYLE_SELECTION = "inverse"; + public static final String DEFAULT_COMPLETION_STYLE_BACKGROUND = "bg:default"; + public static final String DEFAULT_COMPLETION_STYLE_LIST_STARTING = DEFAULT_COMPLETION_STYLE_STARTING; + public static final String DEFAULT_COMPLETION_STYLE_LIST_DESCRIPTION = DEFAULT_COMPLETION_STYLE_DESCRIPTION; + public static final String DEFAULT_COMPLETION_STYLE_LIST_GROUP = "fg:black,bold"; + public static final String DEFAULT_COMPLETION_STYLE_LIST_SELECTION = DEFAULT_COMPLETION_STYLE_SELECTION; + public static final String DEFAULT_COMPLETION_STYLE_LIST_BACKGROUND = "bg:bright-magenta"; public static final int DEFAULT_INDENTATION = 0; public static final int DEFAULT_FEATURES_MAX_BUFFER_SIZE = 1000; + public static final int DEFAULT_SUGGESTIONS_MIN_BUFFER_SIZE = 1; private static final int MIN_ROWS = 3; @@ -162,6 +169,7 @@ public class LineReaderImpl implements LineReader, Flushable protected Highlighter highlighter = new DefaultHighlighter(); protected Parser parser = new DefaultParser(); protected Expander expander = new DefaultExpander(); + protected CompletionMatcher completionMatcher = new CompletionMatcherImpl(); // // State variables @@ -270,6 +278,8 @@ public class LineReaderImpl implements LineReader, Flushable */ protected List commandsBuffer = new ArrayList<>(); + int candidateStartPosition = 0; + public LineReaderImpl(Terminal terminal) throws IOException { this(terminal, null, null); } @@ -419,6 +429,10 @@ public class LineReaderImpl implements LineReader, Flushable this.expander = expander; } + public void setCompletionMatcher(CompletionMatcher completionMatcher) { + this.completionMatcher = completionMatcher; + } + // // Line Reading // @@ -636,7 +650,7 @@ public class LineReaderImpl implements LineReader, Flushable } Binding o = readBinding(getKeys(), local); if (o == null) { - throw new EndOfFileException(); + throw new EndOfFileException().partialLine(buf.length() > 0 ? buf.toString() : null); } Log.trace("Binding: ", o); if (buf.length() == 0 && getLastBinding().charAt(0) == originalAttributes.getControlChar(ControlChar.VEOF)) { @@ -741,11 +755,7 @@ public class LineReaderImpl implements LineReader, Flushable size.copy(terminal.getBufferSize()); display = new Display(terminal, false); - if (size.getRows() == 0 || size.getColumns() == 0) { - display.resize(1, Integer.MAX_VALUE); - } else { - display.resize(size.getRows(), size.getColumns()); - } + display.resize(size.getRows(), size.getColumns()); if (isSet(Option.DELAY_LINE_WRAP)) display.setDelayLineWrap(true); } @@ -1049,8 +1059,7 @@ public class LineReaderImpl implements LineReader, Flushable @Override public boolean isSet(Option option) { - Boolean b = options.get(option); - return b != null ? b : option.isDef(); + return option.isSet(options); } @Override @@ -1070,10 +1079,13 @@ public class LineReaderImpl implements LineReader, Flushable @Override public void editAndAddInBuffer(File file) throws Exception { + if (isSet(Option.BRACKETED_PASTE)) { + terminal.writer().write(BRACKETED_PASTE_OFF); + } Constructor ctor = Class.forName("org.jline.builtins.Nano").getConstructor(Terminal.class, File.class); Editor editor = (Editor) ctor.newInstance(terminal, new File(file.getParent())); editor.setRestricted(true); - editor.open(Arrays.asList(file.getName())); + editor.open(Collections.singletonList(file.getName())); editor.run(); BufferedReader br = new BufferedReader(new FileReader(file)); String line; @@ -1344,7 +1356,7 @@ public class LineReaderImpl implements LineReader, Flushable protected boolean viForwardWord() { if (count < 0) { - return callNeg(this::backwardWord); + return callNeg(this::viBackwardWord); } while (count-- > 0) { if (isViAlphaNum(buf.currChar())) { @@ -1395,21 +1407,7 @@ public class LineReaderImpl implements LineReader, Flushable } protected boolean emacsForwardWord() { - if (count < 0) { - return callNeg(this::emacsBackwardWord); - } - while (count-- > 0) { - while (buf.cursor() < buf.length() && !isWord(buf.currChar())) { - buf.move(1); - } - if (isInViChangeOperation() && count == 0) { - return true; - } - while (buf.cursor() < buf.length() && isWord(buf.currChar())) { - buf.move(1); - } - } - return true; + return forwardWord(); } protected boolean viForwardBlankWordEnd() { @@ -1481,7 +1479,7 @@ public class LineReaderImpl implements LineReader, Flushable protected boolean viBackwardWord() { if (count < 0) { - return callNeg(this::backwardWord); + return callNeg(this::viForwardWord); } while (count-- > 0) { int nl = 0; @@ -1584,24 +1582,7 @@ public class LineReaderImpl implements LineReader, Flushable } protected boolean emacsBackwardWord() { - if (count < 0) { - return callNeg(this::emacsForwardWord); - } - while (count-- > 0) { - while (buf.cursor() > 0) { - buf.move(-1); - if (isWord(buf.currChar())) { - break; - } - } - while (buf.cursor() > 0) { - buf.move(-1); - if (!isWord(buf.currChar())) { - break; - } - } - } - return true; + return backwardWord(); } protected boolean backwardDeleteWord() { @@ -2557,7 +2538,7 @@ public class LineReaderImpl implements LineReader, Flushable } terminal.puts(Capability.keypad_local); terminal.trackMouse(Terminal.MouseTracking.Off); - if (isSet(Option.BRACKETED_PASTE)) + if (isSet(Option.BRACKETED_PASTE) && !isTerminalDumb()) terminal.writer().write(BRACKETED_PASTE_OFF); flush(); } @@ -2720,7 +2701,7 @@ public class LineReaderImpl implements LineReader, Flushable starts.add(new Pair<>(index, m.start())); } return starts; - } + } private String doGetSearchPattern() { StringBuilder sb = new StringBuilder(); @@ -3908,7 +3889,7 @@ public class LineReaderImpl implements LineReader, Flushable } List newLinesToDisplay = new ArrayList<>(); - int displaySize = size.getRows() - (status != null ? status.size() : 0); + int displaySize = displayRows(status); if (newLines.size() > displaySize && !isTerminalDumb()) { StringBuilder sb = new StringBuilder(">...."); // blanks are needed when displaying command completion candidate list @@ -3964,13 +3945,12 @@ public class LineReaderImpl implements LineReader, Flushable } History history = getHistory(); StringBuilder sb = new StringBuilder(); - char prev = '0'; - for (char c: buffer.toCharArray()) { - if ((c == '(' || c == ')' || c == '[' || c == ']' || c == '{' || c == '}' || c == '^') && prev != '\\' ) { + for (char c: buffer.replace("\\", "\\\\").toCharArray()) { + if (c == '(' || c == ')' || c == '[' || c == ']' || c == '{' || c == '}' || c == '^' || c == '*' + || c == '$' || c == '.' || c == '?' || c == '+') { sb.append('\\'); } sb.append(c); - prev = c; } Pattern pattern = Pattern.compile(sb.toString() + ".*", Pattern.DOTALL); Iterator iter = history.reverseIterator(history.last()); @@ -4002,7 +3982,7 @@ public class LineReaderImpl implements LineReader, Flushable AttributedStringBuilder full = new AttributedStringBuilder().tabs(TAB_WIDTH); full.append(prompt); full.append(tNewBuf); - if (doAutosuggestion) { + if (doAutosuggestion && !isTerminalDumb()) { String lastBinding = getLastBinding() != null ? getLastBinding() : ""; if (autosuggestion == SuggestionType.HISTORY) { AttributedStringBuilder sb = new AttributedStringBuilder(); @@ -4010,8 +3990,9 @@ public class LineReaderImpl implements LineReader, Flushable sb.styled(AttributedStyle::faint, tailTip); full.append(sb.toAttributedString()); } else if (autosuggestion == SuggestionType.COMPLETER) { - if (buf.length() > 0 && buf.length() == buf.cursor() - && (!lastBinding.equals("\t") || buf.prevChar() == ' ' || buf.prevChar() == '=')) { + if (buf.length() >= getInt(SUGGESTIONS_MIN_BUFFER_SIZE, DEFAULT_SUGGESTIONS_MIN_BUFFER_SIZE) + && buf.length() == buf.cursor() + && (!lastBinding.equals("\t") || buf.prevChar() == ' ' || buf.prevChar() == '=')) { clearChoices(); listChoices(true); } else if (!lastBinding.equals("\t")) { @@ -4184,6 +4165,9 @@ public class LineReaderImpl implements LineReader, Flushable List missings = new ArrayList<>(); if (computePrompts && secondaryPromptPattern.contains("%P")) { width = prompt.columnLength(); + if (width > size.getColumns() || prompt.contains('\n')) { + width = new TerminalLine(prompt.toString(), 0, size.getColumns()).getEndLine().length(); + } for (int line = 0; line < lines.size() - 1; line++) { AttributedString prompt; buf.append(lines.get(line)).append("\n"); @@ -4398,6 +4382,9 @@ public class LineReaderImpl implements LineReader, Flushable } } catch (Exception e) { Log.info("Error while finding completion candidates", e); + if (Log.isDebugEnabled()) { + e.printStackTrace(); + } return false; } @@ -4423,79 +4410,17 @@ public class LineReaderImpl implements LineReader, Flushable boolean caseInsensitive = isSet(Option.CASE_INSENSITIVE); int errors = getInt(ERRORS, DEFAULT_ERRORS); - // Build a list of sorted candidates - Map> sortedCandidates = new HashMap<>(); - for (Candidate cand : candidates) { - sortedCandidates - .computeIfAbsent(AttributedString.fromAnsi(cand.value()).toString(), s -> new ArrayList<>()) - .add(cand); - } - - // Find matchers - // TODO: glob completion - List>, - Map>>> matchers; - Predicate exact; - if (prefix) { - String wd = line.word(); - String wdi = caseInsensitive ? wd.toLowerCase() : wd; - String wp = wdi.substring(0, line.wordCursor()); - matchers = Arrays.asList( - simpleMatcher(s -> (caseInsensitive ? s.toLowerCase() : s).startsWith(wp)), - simpleMatcher(s -> (caseInsensitive ? s.toLowerCase() : s).contains(wp)), - typoMatcher(wp, errors, caseInsensitive) - ); - exact = s -> caseInsensitive ? s.equalsIgnoreCase(wp) : s.equals(wp); - } else if (isSet(Option.COMPLETE_IN_WORD)) { - String wd = line.word(); - String wdi = caseInsensitive ? wd.toLowerCase() : wd; - String wp = wdi.substring(0, line.wordCursor()); - String ws = wdi.substring(line.wordCursor()); - Pattern p1 = Pattern.compile(Pattern.quote(wp) + ".*" + Pattern.quote(ws) + ".*"); - Pattern p2 = Pattern.compile(".*" + Pattern.quote(wp) + ".*" + Pattern.quote(ws) + ".*"); - matchers = Arrays.asList( - simpleMatcher(s -> p1.matcher(caseInsensitive ? s.toLowerCase() : s).matches()), - simpleMatcher(s -> p2.matcher(caseInsensitive ? s.toLowerCase() : s).matches()), - typoMatcher(wdi, errors, caseInsensitive) - ); - exact = s -> caseInsensitive ? s.equalsIgnoreCase(wd) : s.equals(wd); - } else { - String wd = line.word(); - String wdi = caseInsensitive ? wd.toLowerCase() : wd; - if (isSet(Option.EMPTY_WORD_OPTIONS) || wd.length() > 0) { - matchers = Arrays.asList( - simpleMatcher(s -> (caseInsensitive ? s.toLowerCase() : s).startsWith(wdi)), - simpleMatcher(s -> (caseInsensitive ? s.toLowerCase() : s).contains(wdi)), - typoMatcher(wdi, errors, caseInsensitive) - ); - } else { - matchers = Arrays.asList( - simpleMatcher(s -> !s.startsWith("-")) - ); - } - exact = s -> caseInsensitive ? s.equalsIgnoreCase(wd) : s.equals(wd); - } + completionMatcher.compile(options, prefix, line, caseInsensitive, errors, getOriginalGroupName()); // Find matching candidates - Map> matching = Collections.emptyMap(); - for (Function>, - Map>> matcher : matchers) { - matching = matcher.apply(sortedCandidates); - if (!matching.isEmpty()) { - break; - } - } - + List possible = completionMatcher.matches(candidates); // If we have no matches, bail out - if (matching.isEmpty()) { + if (possible.isEmpty()) { return false; } size.copy(terminal.getSize()); try { // If we only need to display the list, do it now if (lst == CompletionType.List) { - List possible = matching.entrySet().stream() - .flatMap(e -> e.getValue().stream()) - .collect(Collectors.toList()); doList(possible, line.word(), false, line::escape, forSuggestion); return !possible.isEmpty(); } @@ -4503,16 +4428,12 @@ public class LineReaderImpl implements LineReader, Flushable // Check if there's a single possible match Candidate completion = null; // If there's a single possible completion - if (matching.size() == 1) { - completion = matching.values().stream().flatMap(Collection::stream) - .findFirst().orElse(null); + if (possible.size() == 1) { + completion = possible.get(0); } // Or if RECOGNIZE_EXACT is set, try to find an exact match else if (isSet(Option.RECOGNIZE_EXACT)) { - completion = matching.values().stream().flatMap(Collection::stream) - .filter(Candidate::complete) - .filter(c -> exact.test(c.value())) - .findFirst().orElse(null); + completion = completionMatcher.exactMatch(); } // Complete and exit if (completion != null && !completion.value().isEmpty()) { @@ -4531,6 +4452,9 @@ public class LineReaderImpl implements LineReader, Flushable } } if (completion.suffix() != null) { + if (autosuggestion == SuggestionType.COMPLETER) { + listChoices(true); + } redisplay(); Binding op = readBinding(getKeys()); if (op != null) { @@ -4549,10 +4473,6 @@ public class LineReaderImpl implements LineReader, Flushable return true; } - List possible = matching.entrySet().stream() - .flatMap(e -> e.getValue().stream()) - .collect(Collectors.toList()); - if (useMenu) { buf.move(line.word().length() - line.wordCursor()); buf.backspace(line.word().length()); @@ -4570,10 +4490,7 @@ public class LineReaderImpl implements LineReader, Flushable } // Now, we need to find the unambiguous completion // TODO: need to find common suffix - String commonPrefix = null; - for (String key : matching.keySet()) { - commonPrefix = commonPrefix == null ? key : getCommonStart(commonPrefix, key, caseInsensitive); - } + String commonPrefix = completionMatcher.getCommonPrefix(); boolean hasUnambiguous = commonPrefix.startsWith(current) && !commonPrefix.equals(current); if (hasUnambiguous) { @@ -4641,7 +4558,7 @@ public class LineReaderImpl implements LineReader, Flushable protected Comparator getCandidateComparator(boolean caseInsensitive, String word) { String wdi = caseInsensitive ? word.toLowerCase() : word; - ToIntFunction wordDistance = w -> distance(wdi, caseInsensitive ? w.toLowerCase() : w); + ToIntFunction wordDistance = w -> ReaderUtils.distance(wdi, caseInsensitive ? w.toLowerCase() : w); return Comparator .comparing(Candidate::value, Comparator.comparingInt(wordDistance)) .thenComparing(Comparator.naturalOrder()); @@ -4688,37 +4605,6 @@ public class LineReaderImpl implements LineReader, Flushable } } - private Function>, - Map>> simpleMatcher(Predicate pred) { - return m -> m.entrySet().stream() - .filter(e -> pred.test(e.getKey())) - .collect(Collectors.toMap(Entry::getKey, Entry::getValue)); - } - - private Function>, - Map>> typoMatcher(String word, int errors, boolean caseInsensitive) { - return m -> { - Map> map = m.entrySet().stream() - .filter(e -> distance(word, caseInsensitive ? e.getKey() : e.getKey().toLowerCase()) < errors) - .collect(Collectors.toMap(Entry::getKey, Entry::getValue)); - if (map.size() > 1) { - map.computeIfAbsent(word, w -> new ArrayList<>()) - .add(new Candidate(word, word, getOriginalGroupName(), null, null, null, false)); - } - return map; - }; - } - - private int distance(String word, String cand) { - if (word.length() < cand.length()) { - int d1 = Levenshtein.distance(word, cand.substring(0, Math.min(cand.length(), word.length()))); - int d2 = Levenshtein.distance(word, cand); - return Math.min(d1, d2); - } else { - return Levenshtein.distance(word, cand); - } - } - protected boolean nextBindingIsComplete() { redisplay(); KeyMap keyMap = keyMaps.get(MENU); @@ -4731,6 +4617,19 @@ public class LineReaderImpl implements LineReader, Flushable } } + private int displayRows() { + return displayRows(Status.getStatus(terminal, false)); + } + + private int displayRows(Status status) { + return size.getRows() - (status != null ? status.size() : 0); + } + + private int promptLines() { + AttributedString text = insertSecondaryPrompts(AttributedStringBuilder.append(prompt, buf.toString()), new ArrayList<>()); + return text.columnSplitLength(size.getColumns(), false, display.delayLineWrap()).size(); + } + private class MenuSupport implements Supplier { final List possible; final BiFunction escaper; @@ -4850,10 +4749,7 @@ public class LineReaderImpl implements LineReader, Flushable // Compute displayed prompt PostResult pr = computePost(possible, completion(), null, completed); - AttributedString text = insertSecondaryPrompts(AttributedStringBuilder.append(prompt, buf.toString()), new ArrayList<>()); - int promptLines = text.columnSplitLength(size.getColumns(), false, display.delayLineWrap()).size(); - Status status = Status.getStatus(terminal, false); - int displaySize = size.getRows() - (status != null ? status.size() : 0) - promptLines; + int displaySize = displayRows() - promptLines(); if (pr.lines > displaySize) { int displayed = displaySize - 1; if (pr.selectedLine >= 0) { @@ -4902,7 +4798,13 @@ public class LineReaderImpl implements LineReader, Flushable original.sort(getCandidateComparator(caseInsensitive, completed)); mergeCandidates(original); computePost(original, null, possible, completed); - + // candidate grouping is not supported by MenuSupport + boolean defaultAutoGroup = isSet(Option.AUTO_GROUP); + boolean defaultGroup = isSet(Option.GROUP); + if (!isSet(Option.GROUP_PERSIST)) { + option(Option.AUTO_GROUP, false); + option(Option.GROUP, false); + } // Build menu support MenuSupport menuSupport = new MenuSupport(original, completed, escaper); post = menuSupport; @@ -4959,17 +4861,21 @@ public class LineReaderImpl implements LineReader, Flushable pushBackBinding(true); } post = null; + option(Option.AUTO_GROUP, defaultAutoGroup); + option(Option.GROUP, defaultGroup); return true; } } doAutosuggestion = false; callWidget(REDISPLAY); } + option(Option.AUTO_GROUP, defaultAutoGroup); + option(Option.GROUP, defaultGroup); return false; } protected boolean clearChoices() { - return doList(new ArrayList(), "", false, null, false); + return doList(new ArrayList<>(), "", false, null, false); } protected boolean doList(List possible @@ -5009,14 +4915,14 @@ public class LineReaderImpl implements LineReader, Flushable boolean caseInsensitive = isSet(Option.CASE_INSENSITIVE); StringBuilder sb = new StringBuilder(); + candidateStartPosition = 0; while (true) { String current = completed + sb.toString(); List cands; if (sb.length() > 0) { - cands = possible.stream() - .filter(c -> caseInsensitive - ? c.value().toLowerCase().startsWith(current.toLowerCase()) - : c.value().startsWith(current)) + completionMatcher.compile(options, false, new CompletingWord(current), caseInsensitive, 0 + , null); + cands = completionMatcher.matches(possible).stream() .sorted(getCandidateComparator(caseInsensitive, current)) .collect(Collectors.toList()); } else { @@ -5024,6 +4930,9 @@ public class LineReaderImpl implements LineReader, Flushable .sorted(getCandidateComparator(caseInsensitive, current)) .collect(Collectors.toList()); } + if (isSet(Option.AUTO_MENU_LIST) && candidateStartPosition == 0) { + candidateStartPosition = candidateStartPosition(cands); + } post = () -> { AttributedString t = insertSecondaryPrompts(AttributedStringBuilder.append(prompt, buf.toString()), new ArrayList<>()); int pl = t.columnSplitLength(size.getColumns(), false, display.delayLineWrap()).size(); @@ -5035,10 +4944,11 @@ public class LineReaderImpl implements LineReader, Flushable redisplay(false); buf.cursor(oldCursor); println(); - List ls = postResult.post.columnSplitLength(size.getColumns(), false, display.delayLineWrap()); + List ls = pr.post.columnSplitLength(size.getColumns(), false, display.delayLineWrap()); Display d = new Display(terminal, false); d.resize(size.getRows(), size.getColumns()); d.update(ls, -1); + println(); redrawLine(); return new AttributedString(""); } @@ -5089,6 +4999,59 @@ public class LineReaderImpl implements LineReader, Flushable } } + private static class CompletingWord implements CompletingParsedLine { + private final String word; + + public CompletingWord(String word) { + this.word = word; + } + + @Override + public CharSequence escape(CharSequence candidate, boolean complete) { + return null; + } + + @Override + public int rawWordCursor() { + return word.length(); + } + + @Override + public int rawWordLength() { + return word.length(); + } + + @Override + public String word() { + return word; + } + + @Override + public int wordCursor() { + return word.length(); + } + + @Override + public int wordIndex() { + return 0; + } + + @Override + public List words() { + return null; + } + + @Override + public String line() { + return word; + } + + @Override + public int cursor() { + return word.length(); + } + } + protected static class PostResult { final AttributedString post; final int lines; @@ -5156,6 +5119,63 @@ public class LineReaderImpl implements LineReader, Flushable private static final String DESC_SUFFIX = ")"; private static final int MARGIN_BETWEEN_DISPLAY_AND_DESC = 1; private static final int MARGIN_BETWEEN_COLUMNS = 3; + private static final int MENU_LIST_WIDTH = 25; + + private static class TerminalLine { + private String endLine; + private int startPos; + + public TerminalLine(String line, int startPos, int width) { + this.startPos = startPos; + endLine = line.substring(line.lastIndexOf('\n') + 1); + boolean first = true; + while (endLine.length() + (first ? startPos : 0) > width) { + if (first) { + endLine = endLine.substring(width - startPos); + } else { + endLine = endLine.substring(width); + } + first = false; + } + if (!first) { + this.startPos = 0; + } + } + + public int getStartPos() { + return startPos; + } + + public String getEndLine() { + return endLine; + } + } + + private int candidateStartPosition(List cands) { + List values = cands.stream().map(c -> AttributedString.stripAnsi(c.displ())) + .filter(c -> !c.matches("\\w+") && c.length() > 1).collect(Collectors.toList()); + Set notDelimiters = new HashSet<>(); + values.forEach(v -> v.substring(0, v.length() - 1).chars() + .filter(c -> !Character.isDigit(c) && !Character.isAlphabetic(c)) + .forEach(c -> notDelimiters.add(Character.toString((char)c)))); + int width = size.getColumns(); + int promptLength = prompt != null ? prompt.length() : 0; + if (promptLength > 0) { + TerminalLine tp = new TerminalLine(prompt.toString(), 0, width); + promptLength = tp.getEndLine().length(); + } + TerminalLine tl = new TerminalLine(buf.substring(0, buf.cursor()), promptLength, width); + int out = tl.getStartPos(); + String buffer = tl.getEndLine(); + for (int i = buffer.length(); i > 0; i--) { + if (buffer.substring(0, i).matches(".*\\W") + && !notDelimiters.contains(buffer.substring(i - 1, i))) { + out += i; + break; + } + } + return out; + } @SuppressWarnings("unchecked") protected PostResult toColumns(List items, Candidate selection, String completed, Function wcwidth, int width, boolean rowsFirst) { @@ -5163,6 +5183,7 @@ public class LineReaderImpl implements LineReader, Flushable // TODO: support Option.LIST_PACKED // Compute column width int maxWidth = 0; + int listSize = 0; for (Object item : items) { if (item instanceof String) { int len = wcwidth.apply((String) item); @@ -5170,6 +5191,7 @@ public class LineReaderImpl implements LineReader, Flushable } else if (item instanceof List) { for (Candidate cand : (List) item) { + listSize++; int len = wcwidth.apply(cand.displ()); if (cand.descr() != null) { len += MARGIN_BETWEEN_DISPLAY_AND_DESC; @@ -5183,8 +5205,33 @@ public class LineReaderImpl implements LineReader, Flushable } // Build columns AttributedStringBuilder sb = new AttributedStringBuilder(); - for (Object list : items) { - toColumns(list, width, maxWidth, sb, selection, completed, rowsFirst, out); + if (listSize > 0) { + if (isSet(Option.AUTO_MENU_LIST) + && listSize < Math.min(getInt(MENU_LIST_MAX, DEFAULT_MENU_LIST_MAX), displayRows() - promptLines())) { + maxWidth = Math.max(maxWidth, MENU_LIST_WIDTH); + sb.tabs(Math.max(Math.min(candidateStartPosition, width - maxWidth - 1), 1)); + width = maxWidth + 2; + if (!isSet(Option.GROUP_PERSIST)) { + List list = new ArrayList<>(); + for (Object o : items) { + if (o instanceof Collection) { + list.addAll((Collection) o); + } + } + list = list.stream() + .sorted(getCandidateComparator(isSet(Option.CASE_INSENSITIVE), "")) + .collect(Collectors.toList()); + toColumns(list, width, maxWidth, sb, selection, completed, rowsFirst, true, out); + } else { + for (Object list : items) { + toColumns(list, width, maxWidth, sb, selection, completed, rowsFirst, true, out); + } + } + } else { + for (Object list : items) { + toColumns(list, width, maxWidth, sb, selection, completed, rowsFirst, false, out); + } + } } if (sb.length() > 0 && sb.charAt(sb.length() - 1) == '\n') { sb.setLength(sb.length() - 1); @@ -5193,16 +5240,29 @@ public class LineReaderImpl implements LineReader, Flushable } @SuppressWarnings("unchecked") - protected void toColumns(Object items, int width, int maxWidth, AttributedStringBuilder sb, Candidate selection, String completed, boolean rowsFirst, int[] out) { + protected void toColumns(Object items, int width, int maxWidth, AttributedStringBuilder sb, Candidate selection, String completed + , boolean rowsFirst, boolean doMenuList, int[] out) { if (maxWidth <= 0 || width <= 0) { return; } // This is a group if (items instanceof String) { - sb.style(getCompletionStyleGroup()) + if (doMenuList) { + sb.style(AttributedStyle.DEFAULT); + sb.append('\t'); + } + AttributedStringBuilder asb = new AttributedStringBuilder(); + asb.style(getCompletionStyleGroup(doMenuList)) .append((String) items) - .style(AttributedStyle.DEFAULT) - .append("\n"); + .style(AttributedStyle.DEFAULT); + if (doMenuList) { + for (int k = ((String) items).length(); k < maxWidth + 1; k++) { + asb.append(' '); + } + } + sb.style(getCompletionStyleBackground(doMenuList)); + sb.append(asb); + sb.append("\n"); out[0]++; } // This is a Candidate list @@ -5224,6 +5284,11 @@ public class LineReaderImpl implements LineReader, Flushable index = (i, j) -> j * lines + i; } for (int i = 0; i < lines; i++) { + if (doMenuList) { + sb.style(AttributedStyle.DEFAULT); + sb.append('\t'); + } + AttributedStringBuilder asb = new AttributedStringBuilder(); for (int j = 0; j < columns; j++) { int idx = index.applyAsInt(i, j); if (idx < candidates.size()) { @@ -5248,56 +5313,85 @@ public class LineReaderImpl implements LineReader, Flushable } if (cand == selection) { out[1] = i; - sb.style(getCompletionStyleSelection()); + asb.style(getCompletionStyleSelection(doMenuList)); if (left.toString().regionMatches( isSet(Option.CASE_INSENSITIVE), 0, completed, 0, completed.length())) { - sb.append(left.toString(), 0, completed.length()); - sb.append(left.toString(), completed.length(), left.length()); + asb.append(left.toString(), 0, completed.length()); + asb.append(left.toString(), completed.length(), left.length()); } else { - sb.append(left.toString()); + asb.append(left.toString()); } for (int k = 0; k < maxWidth - lw - rw; k++) { - sb.append(' '); + asb.append(' '); } if (right != null) { - sb.append(right); + asb.append(right); } - sb.style(AttributedStyle.DEFAULT); + asb.style(AttributedStyle.DEFAULT); } else { if (left.toString().regionMatches( isSet(Option.CASE_INSENSITIVE), 0, completed, 0, completed.length())) { - sb.style(getCompletionStyleStarting()); - sb.append(left, 0, completed.length()); - sb.style(AttributedStyle.DEFAULT); - sb.append(left, completed.length(), left.length()); + asb.style(getCompletionStyleStarting(doMenuList)); + asb.append(left, 0, completed.length()); + asb.style(AttributedStyle.DEFAULT); + asb.append(left, completed.length(), left.length()); } else { - sb.append(left); + asb.append(left); } if (right != null || hasRightItem) { for (int k = 0; k < maxWidth - lw - rw; k++) { - sb.append(' '); + asb.append(' '); } } if (right != null) { - sb.style(getCompletionStyleDescription()); - sb.append(right); - sb.style(AttributedStyle.DEFAULT); + asb.style(getCompletionStyleDescription(doMenuList)); + asb.append(right); + asb.style(AttributedStyle.DEFAULT); + } else if (doMenuList) { + for (int k = lw; k < maxWidth; k++) { + asb.append(' '); + } } } if (hasRightItem) { for (int k = 0; k < MARGIN_BETWEEN_COLUMNS; k++) { - sb.append(' '); + asb.append(' '); } } + if (doMenuList) { + asb.append(' '); + } } } + sb.style(getCompletionStyleBackground(doMenuList)); + sb.append(asb); sb.append('\n'); } out[0] += lines; } } - private AttributedStyle getCompletionStyleStarting() { + protected AttributedStyle getCompletionStyleStarting(boolean menuList) { + return menuList ? getCompletionStyleListStarting() : getCompletionStyleStarting(); + } + + protected AttributedStyle getCompletionStyleDescription(boolean menuList) { + return menuList ? getCompletionStyleListDescription() : getCompletionStyleDescription(); + } + + protected AttributedStyle getCompletionStyleGroup(boolean menuList) { + return menuList ? getCompletionStyleListGroup() : getCompletionStyleGroup(); + } + + protected AttributedStyle getCompletionStyleSelection(boolean menuList) { + return menuList ? getCompletionStyleListSelection() : getCompletionStyleSelection(); + } + + protected AttributedStyle getCompletionStyleBackground(boolean menuList) { + return menuList ? getCompletionStyleListBackground() : getCompletionStyleBackground(); + } + + protected AttributedStyle getCompletionStyleStarting() { return getCompletionStyle(COMPLETION_STYLE_STARTING, DEFAULT_COMPLETION_STYLE_STARTING); } @@ -5313,37 +5407,38 @@ public class LineReaderImpl implements LineReader, Flushable return getCompletionStyle(COMPLETION_STYLE_SELECTION, DEFAULT_COMPLETION_STYLE_SELECTION); } + protected AttributedStyle getCompletionStyleBackground() { + return getCompletionStyle(COMPLETION_STYLE_BACKGROUND, DEFAULT_COMPLETION_STYLE_BACKGROUND); + } + + protected AttributedStyle getCompletionStyleListStarting() { + return getCompletionStyle(COMPLETION_STYLE_LIST_STARTING, DEFAULT_COMPLETION_STYLE_LIST_STARTING); + } + + protected AttributedStyle getCompletionStyleListDescription() { + return getCompletionStyle(COMPLETION_STYLE_LIST_DESCRIPTION, DEFAULT_COMPLETION_STYLE_LIST_DESCRIPTION); + } + + protected AttributedStyle getCompletionStyleListGroup() { + return getCompletionStyle(COMPLETION_STYLE_LIST_GROUP, DEFAULT_COMPLETION_STYLE_LIST_GROUP); + } + + protected AttributedStyle getCompletionStyleListSelection() { + return getCompletionStyle(COMPLETION_STYLE_LIST_SELECTION, DEFAULT_COMPLETION_STYLE_LIST_SELECTION); + } + + protected AttributedStyle getCompletionStyleListBackground() { + return getCompletionStyle(COMPLETION_STYLE_LIST_BACKGROUND, DEFAULT_COMPLETION_STYLE_LIST_BACKGROUND); + } + protected AttributedStyle getCompletionStyle(String name, String value) { - return buildStyle(getString(name, value)); + return new StyleResolver(s -> getString(s, null)).resolve("." + name, value); } protected AttributedStyle buildStyle(String str) { return AttributedString.fromAnsi("\u001b[" + str + "m ").styleAt(0); } - private String getCommonStart(String str1, String str2, boolean caseInsensitive) { - int[] s1 = str1.codePoints().toArray(); - int[] s2 = str2.codePoints().toArray(); - int len = 0; - while (len < Math.min(s1.length, s2.length)) { - int ch1 = s1[len]; - int ch2 = s2[len]; - if (ch1 != ch2 && caseInsensitive) { - ch1 = Character.toUpperCase(ch1); - ch2 = Character.toUpperCase(ch2); - if (ch1 != ch2) { - ch1 = Character.toLowerCase(ch1); - ch2 = Character.toLowerCase(ch2); - } - } - if (ch1 != ch2) { - break; - } - len++; - } - return new String(s1, 0, len); - } - /** * Used in "vi" mode for argumented history move, to move a specific * number of history entries forward or back. diff --git a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/ReaderUtils.java b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/ReaderUtils.java index a8a419d066f..0ae9475bd57 100644 --- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/ReaderUtils.java +++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/ReaderUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002-2016, the original author or authors. + * Copyright (c) 2002-2020, the original author or authors. * * This software is distributable under the BSD license. See the terms of the * BSD license in the documentation provided with this software. @@ -9,6 +9,7 @@ package jdk.internal.org.jline.reader.impl; import jdk.internal.org.jline.reader.LineReader; +import jdk.internal.org.jline.utils.Levenshtein; public class ReaderUtils { @@ -67,4 +68,14 @@ public class ReaderUtils { return nb; } + public static int distance(String word, String cand) { + if (word.length() < cand.length()) { + int d1 = Levenshtein.distance(word, cand.substring(0, Math.min(cand.length(), word.length()))); + int d2 = Levenshtein.distance(word, cand); + return Math.min(d1, d2); + } else { + return Levenshtein.distance(word, cand); + } + } + } diff --git a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/completer/StringsCompleter.java b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/completer/StringsCompleter.java index b1ee32fe206..8baac657b93 100644 --- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/completer/StringsCompleter.java +++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/completer/StringsCompleter.java @@ -11,6 +11,7 @@ package jdk.internal.org.jline.reader.impl.completer; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.List; import java.util.function.Supplier; @@ -28,10 +29,11 @@ import jdk.internal.org.jline.utils.AttributedString; */ public class StringsCompleter implements Completer { - protected Collection candidates = new ArrayList<>(); + protected Collection candidates; protected Supplier> stringsSupplier; public StringsCompleter() { + this(Collections.emptyList()); } public StringsCompleter(Supplier> stringsSupplier) { @@ -46,6 +48,7 @@ public class StringsCompleter implements Completer public StringsCompleter(Iterable strings) { assert strings != null; + this.candidates = new ArrayList<>(); for (String string : strings) { candidates.add(new Candidate(AttributedString.stripAnsi(string), string, null, null, null, null, true)); } @@ -57,9 +60,10 @@ public class StringsCompleter implements Completer public StringsCompleter(Collection candidates) { assert candidates != null; - this.candidates.addAll(candidates); + this.candidates = new ArrayList<>(candidates); } + @Override public void complete(LineReader reader, final ParsedLine commandLine, final List candidates) { assert commandLine != null; assert candidates != null; @@ -72,4 +76,9 @@ public class StringsCompleter implements Completer } } + @Override + public String toString() { + String value = candidates != null ? candidates.toString() : "{" + stringsSupplier.toString() + "}"; + return "StringsCompleter" + value; + } } diff --git a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/completer/SystemCompleter.java b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/completer/SystemCompleter.java new file mode 100644 index 00000000000..691708e1389 --- /dev/null +++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/completer/SystemCompleter.java @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2002-2020, the original author or authors. + * + * This software is distributable under the BSD license. See the terms of the + * BSD license in the documentation provided with this software. + * + * https://opensource.org/licenses/BSD-3-Clause + */ +package jdk.internal.org.jline.reader.impl.completer; + +import java.util.*; + +import jdk.internal.org.jline.reader.Candidate; +import jdk.internal.org.jline.reader.Completer; +import jdk.internal.org.jline.reader.LineReader; +import jdk.internal.org.jline.reader.ParsedLine; +import jdk.internal.org.jline.utils.AttributedString; + +/** + * Completer which contains multiple completers and aggregates them together. + * + * @author Matti Rinta-Nikkola + */ +public class SystemCompleter implements Completer { + private Map> completers = new HashMap<>(); + private Map aliasCommand = new HashMap<>(); + private StringsCompleter commands; + private boolean compiled = false; + + public SystemCompleter() {} + + @Override + public void complete(LineReader reader, ParsedLine commandLine, List candidates) { + if (!compiled) { + throw new IllegalStateException(); + } + assert commandLine != null; + assert candidates != null; + if (commandLine.words().size() > 0) { + if (commandLine.words().size() == 1) { + String buffer = commandLine.words().get(0); + int eq = buffer.indexOf('='); + if (eq < 0) { + commands.complete(reader, commandLine, candidates); + } else if (reader.getParser().validVariableName(buffer.substring(0, eq))) { + String curBuf = buffer.substring(0, eq + 1); + for (String c: completers.keySet()) { + candidates.add(new Candidate(AttributedString.stripAnsi(curBuf+c) + , c, null, null, null, null, true)); + } + } + } else { + String cmd = reader.getParser().getCommand(commandLine.words().get(0)); + if (command(cmd) != null) { + completers.get(command(cmd)).get(0).complete(reader, commandLine, candidates); + } + } + } + } + + public boolean isCompiled() { + return compiled; + } + + private String command(String cmd) { + String out = null; + if (cmd != null) { + if (completers.containsKey(cmd)) { + out = cmd; + } else if (aliasCommand.containsKey(cmd)) { + out = aliasCommand.get(cmd); + } + } + return out; + } + + public void add(String command, List completers) { + for (Completer c : completers) { + add(command, c); + } + } + + public void add(List commands, Completer completer) { + for (String c: commands) { + add(c, completer); + } + } + + public void add(String command, Completer completer) { + Objects.requireNonNull(command); + if (compiled) { + throw new IllegalStateException(); + } + if (!completers.containsKey(command)) { + completers.put(command, new ArrayList()); + } + if (completer instanceof ArgumentCompleter) { + ((ArgumentCompleter) completer).setStrictCommand(false); + } + completers.get(command).add(completer); + } + + public void add(SystemCompleter other) { + if (other.isCompiled()) { + throw new IllegalStateException(); + } + for (Map.Entry> entry: other.getCompleters().entrySet()) { + for (Completer c: entry.getValue()) { + add(entry.getKey(), c); + } + } + addAliases(other.getAliases()); + } + + public void addAliases(Map aliasCommand) { + if (compiled) { + throw new IllegalStateException(); + } + this.aliasCommand.putAll(aliasCommand); + } + + private Map getAliases() { + return aliasCommand; + } + + public void compile() { + if (compiled) { + return; + } + Map> compiledCompleters = new HashMap<>(); + for (Map.Entry> entry: completers.entrySet()) { + if (entry.getValue().size() == 1) { + compiledCompleters.put(entry.getKey(), entry.getValue()); + } else { + compiledCompleters.put(entry.getKey(), new ArrayList()); + compiledCompleters.get(entry.getKey()).add(new AggregateCompleter(entry.getValue())); + } + } + completers = compiledCompleters; + Set cmds = new HashSet<>(completers.keySet()); + cmds.addAll(aliasCommand.keySet()); + commands = new StringsCompleter(cmds); + compiled = true; + } + + public Map> getCompleters() { + return completers; + } + +} diff --git a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/history/DefaultHistory.java b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/history/DefaultHistory.java index 46bbe1ba320..a2a0f575136 100644 --- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/history/DefaultHistory.java +++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/reader/impl/history/DefaultHistory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002-2018, the original author or authors. + * Copyright (c) 2002-2021, the original author or authors. * * This software is distributable under the BSD license. See the terms of the * BSD license in the documentation provided with this software. @@ -84,7 +84,7 @@ public class DefaultHistory implements History { try (BufferedReader reader = Files.newBufferedReader(path)) { internalClear(); reader.lines().forEach(line -> addHistoryLine(path, line)); - setHistoryFileData(path, new HistoryFileData(items.size(), items.size())); + setHistoryFileData(path, new HistoryFileData(items.size(), offset + items.size())); maybeResize(); } } @@ -105,7 +105,7 @@ public class DefaultHistory implements History { Log.trace("Reading history from: ", path); try (BufferedReader reader = Files.newBufferedReader(path)) { reader.lines().forEach(line -> addHistoryLine(path, line, incremental)); - setHistoryFileData(path, new HistoryFileData(items.size(), items.size())); + setHistoryFileData(path, new HistoryFileData(items.size(), offset + items.size())); maybeResize(); } } @@ -136,11 +136,7 @@ public class DefaultHistory implements History { private boolean isLineReaderHistory (Path path) throws IOException { Path lrp = getPath(); if (lrp == null) { - if (path != null) { - return false; - } else { - return true; - } + return path == null; } return Files.isSameFile(lrp, path); } @@ -226,7 +222,10 @@ public class DefaultHistory implements History { private void internalWrite(Path path, int from) throws IOException { if (path != null) { Log.trace("Saving history to: ", path); - Files.createDirectories(path.toAbsolutePath().getParent()); + Path parent = path.toAbsolutePath().getParent(); + if (!Files.exists(parent)) { + Files.createDirectories(parent); + } // Append new items to the history file try (BufferedWriter writer = Files.newBufferedWriter(path.toAbsolutePath(), StandardOpenOption.WRITE, StandardOpenOption.APPEND, StandardOpenOption.CREATE)) { @@ -258,11 +257,11 @@ public class DefaultHistory implements History { }); } // Remove duplicates - doTrimHistory(allItems, max); + List trimmedItems = doTrimHistory(allItems, max); // Write history Path temp = Files.createTempFile(path.toAbsolutePath().getParent(), path.getFileName().toString(), ".tmp"); try (BufferedWriter writer = Files.newBufferedWriter(temp, StandardOpenOption.WRITE)) { - for (Entry entry : allItems) { + for (Entry entry : trimmedItems) { writer.append(format(entry)); } } @@ -270,8 +269,8 @@ public class DefaultHistory implements History { // Keep items in memory if (isLineReaderHistory(path)) { internalClear(); - offset = allItems.get(0).index(); - items.addAll(allItems); + offset = trimmedItems.get(0).index(); + items.addAll(trimmedItems); setHistoryFileData(path, new HistoryFileData(items.size(), items.size())); } else { setEntriesInFile(path, allItems.size()); @@ -297,7 +296,7 @@ public class DefaultHistory implements History { items.clear(); } - static void doTrimHistory(List allItems, int max) { + static List doTrimHistory(List allItems, int max) { int idx = 0; while (idx < allItems.size()) { int ridx = allItems.size() - idx - 1; @@ -314,6 +313,12 @@ public class DefaultHistory implements History { while (allItems.size() > max) { allItems.remove(0); } + int index = allItems.get(allItems.size() - 1).index() - allItems.size() + 1; + List out = new ArrayList<>(); + for (Entry e : allItems) { + out.add(new EntryImpl(index++, e.time(), e.line())); + } + return out; } public int size() { @@ -338,7 +343,7 @@ public class DefaultHistory implements History { private String format(Entry entry) { if (reader.isSet(LineReader.Option.HISTORY_TIMESTAMPED)) { - return Long.toString(entry.time().toEpochMilli()) + ":" + escape(entry.line()) + "\n"; + return entry.time().toEpochMilli() + ":" + escape(entry.line()) + "\n"; } return escape(entry.line()) + "\n"; } @@ -398,6 +403,8 @@ public class DefaultHistory implements History { sb.append('|'); } else if (ch == '*') { sb.append('.').append('*'); + } else { + sb.append(ch); } } return line.matches(sb.toString()); @@ -441,7 +448,7 @@ public class DefaultHistory implements History { } public void resetIndex() { - index = index > items.size() ? items.size() : index; + index = Math.min(index, items.size()); } protected static class EntryImpl implements Entry { @@ -622,7 +629,7 @@ public class DefaultHistory implements History { return sb.toString(); } - private class HistoryFileData { + private static class HistoryFileData { private int lastLoaded = 0; private int entriesInFile = 0; diff --git a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/Terminal.java b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/Terminal.java index 7c82a32e4a2..38ffb029f60 100644 --- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/Terminal.java +++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/Terminal.java @@ -18,6 +18,7 @@ import java.util.function.IntConsumer; import java.util.function.IntSupplier; import jdk.internal.org.jline.terminal.impl.NativeSignalHandler; +import jdk.internal.org.jline.utils.ColorPalette; import jdk.internal.org.jline.utils.InfoCmp.Capability; import jdk.internal.org.jline.utils.NonBlockingReader; @@ -328,4 +329,10 @@ public interface Terminal extends Closeable, Flushable { * @return true if focus tracking is supported */ boolean trackFocus(boolean tracking); + + /** + * Color support + */ + ColorPalette getPalette(); + } diff --git a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/TerminalBuilder.java b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/TerminalBuilder.java index a50835867e7..88970b88592 100644 --- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/TerminalBuilder.java +++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/TerminalBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002-2019, the original author or authors. + * Copyright (c) 2002-2020, the original author or authors. * * This software is distributable under the BSD license. See the terms of the * BSD license in the documentation provided with this software. @@ -88,6 +88,7 @@ public final class TerminalBuilder { } private static final AtomicReference SYSTEM_TERMINAL = new AtomicReference<>(); + private static final AtomicReference TERMINAL_OVERRIDE = new AtomicReference<>(); private String name; private InputStream in; @@ -100,12 +101,13 @@ public final class TerminalBuilder { private Boolean jansi; private Boolean exec; private Boolean dumb; + private Boolean color; private Attributes attributes; private Size size; private boolean nativeSignals = false; + private Function inputStreamWrapper = in -> in; private Terminal.SignalHandler signalHandler = Terminal.SignalHandler.SIG_DFL; private boolean paused = false; - private Function inputStreamWrapper = in -> in; private TerminalBuilder() { } @@ -151,6 +153,11 @@ public final class TerminalBuilder { return this; } + public TerminalBuilder color(boolean color) { + this.color = color; + return this; + } + /** * Set the encoding to use for reading/writing from the console. * If {@code null} (the default value), JLine will automatically select @@ -205,8 +212,8 @@ public final class TerminalBuilder { /** * Attributes to use when creating a non system terminal, * i.e. when the builder has been given the input and - * outut streams using the {@link #streams(InputStream, OutputStream)} method - * or when {@link #system(boolean)} has been explicitely called with + * output streams using the {@link #streams(InputStream, OutputStream)} method + * or when {@link #system(boolean)} has been explicitly called with * false. * * @param attributes the attributes to use @@ -222,8 +229,8 @@ public final class TerminalBuilder { /** * Initial size to use when creating a non system terminal, * i.e. when the builder has been given the input and - * outut streams using the {@link #streams(InputStream, OutputStream)} method - * or when {@link #system(boolean)} has been explicitely called with + * output streams using the {@link #streams(InputStream, OutputStream)} method + * or when {@link #system(boolean)} has been explicitly called with * false. * * @param size the initial size @@ -246,6 +253,11 @@ public final class TerminalBuilder { return this; } + public TerminalBuilder inputStreamWrapper(Function wrapper) { + this.inputStreamWrapper = wrapper; + return this; + } + /** * Initial paused state of the terminal (defaults to false). * By default, the terminal is started, but in some cases, @@ -261,13 +273,12 @@ public final class TerminalBuilder { return this; } - public TerminalBuilder inputStreamWrapper(Function wrapper) { - this.inputStreamWrapper = wrapper; - return this; - } - public Terminal build() throws IOException { - Terminal terminal = doBuild(); + Terminal override = TERMINAL_OVERRIDE.get(); + Terminal terminal = override != null ? override : doBuild(); + if (override != null) { + Log.debug(() -> "Overriding terminal with global value set by TerminalBuilder.setTerminalOverride"); + } Log.debug(() -> "Using terminal " + terminal.getClass().getSimpleName()); if (terminal instanceof AbstractPosixTerminal) { Log.debug(() -> "Using pty " + ((AbstractPosixTerminal) terminal).getPty().getClass().getSimpleName()); @@ -318,117 +329,132 @@ public final class TerminalBuilder { dumb = getBoolean(PROP_DUMB, null); } if ((system != null && system) || (system == null && in == null && out == null)) { - if (attributes != null || size != null) { - Log.warn("Attributes and size fields are ignored when creating a system terminal"); + if (system != null && ((in != null && !in.equals(System.in)) || (out != null && !out.equals(System.out)))) { + throw new IllegalArgumentException("Cannot create a system terminal using non System streams"); } - IllegalStateException exception = new IllegalStateException("Unable to create a system terminal"); Terminal terminal = null; - if (OSUtils.IS_WINDOWS) { - boolean cygwinTerm = "cygwin".equals(System.getenv("TERM")); - boolean ansiPassThrough = OSUtils.IS_CONEMU; - // - // Cygwin support - // - if ((OSUtils.IS_CYGWIN || OSUtils.IS_MSYSTEM) && exec && !cygwinTerm) { - try { - Pty pty = ExecPty.current(); - // Cygwin defaults to XTERM, but actually supports 256 colors, - // so if the value comes from the environment, change it to xterm-256color - if ("xterm".equals(type) && this.type == null && System.getProperty(PROP_TYPE) == null) { - type = "xterm-256color"; + IllegalStateException exception = new IllegalStateException("Unable to create a system terminal"); + TerminalBuilderSupport tbs = new TerminalBuilderSupport(jna, jansi); + if (tbs.isConsoleInput() && tbs.isConsoleOutput()) { + if (attributes != null || size != null) { + Log.warn("Attributes and size fields are ignored when creating a system terminal"); + } + if (OSUtils.IS_WINDOWS) { + if (!OSUtils.IS_CYGWIN && !OSUtils.IS_MSYSTEM) { + boolean ansiPassThrough = OSUtils.IS_CONEMU; + if (tbs.hasJnaSupport()) { + try { + terminal = tbs.getJnaSupport().winSysTerminal(name, type, ansiPassThrough, encoding, codepage + , nativeSignals, signalHandler, paused, inputStreamWrapper); + } catch (Throwable t) { + Log.debug("Error creating JNA based terminal: ", t.getMessage(), t); + exception.addSuppressed(t); + } + } + if (terminal == null && tbs.hasJansiSupport()) { + try { + terminal = tbs.getJansiSupport().winSysTerminal(name, type, ansiPassThrough, encoding, codepage + , nativeSignals, signalHandler, paused); + } catch (Throwable t) { + Log.debug("Error creating JANSI based terminal: ", t.getMessage(), t); + exception.addSuppressed(t); + } + } + } else if (exec) { + // + // Cygwin support + // + try { + // Cygwin defaults to XTERM, but actually supports 256 colors, + // so if the value comes from the environment, change it to xterm-256color + if ("xterm".equals(type) && this.type == null && System.getProperty(PROP_TYPE) == null) { + type = "xterm-256color"; + } + Pty pty = tbs.getExecPty(); + terminal = new PosixSysTerminal(name, type, pty, inputStreamWrapper.apply(pty.getSlaveInput()), pty.getSlaveOutput(), encoding, nativeSignals, signalHandler); + } catch (IOException e) { + // Ignore if not a tty + Log.debug("Error creating EXEC based terminal: ", e.getMessage(), e); + exception.addSuppressed(e); } - terminal = new PosixSysTerminal(name, type, pty, inputStreamWrapper.apply(pty.getSlaveInput()), pty.getSlaveOutput(), encoding, nativeSignals, signalHandler); - } catch (IOException e) { - // Ignore if not a tty - Log.debug("Error creating EXEC based terminal: ", e.getMessage(), e); - exception.addSuppressed(e); } - } - if (jna) { - try { - terminal = load(JnaSupport.class).winSysTerminal(name, type, ansiPassThrough, encoding, codepage, nativeSignals, signalHandler, paused, inputStreamWrapper); - } catch (Throwable t) { - Log.debug("Error creating JNA based terminal: ", t.getMessage(), t); - exception.addSuppressed(t); + if (terminal == null && !jna && !jansi && (dumb == null || !dumb)) { + throw new IllegalStateException("Unable to create a system terminal. On windows, either " + + "JNA or JANSI library is required. Make sure to add one of those in the classpath."); } - } - if (jansi) { - try { - terminal = load(JansiSupport.class).winSysTerminal(name, type, ansiPassThrough, encoding, codepage, nativeSignals, signalHandler, paused); - } catch (Throwable t) { - Log.debug("Error creating JANSI based terminal: ", t.getMessage(), t); - exception.addSuppressed(t); + } else { + if (tbs.hasJnaSupport()) { + try { + Pty pty = tbs.getJnaSupport().current(); + terminal = new PosixSysTerminal(name, type, pty, inputStreamWrapper.apply(pty.getSlaveInput()), pty.getSlaveOutput(), encoding, nativeSignals, signalHandler); + } catch (Throwable t) { + // ignore + Log.debug("Error creating JNA based terminal: ", t.getMessage(), t); + exception.addSuppressed(t); + } } - } - } else { - if (jna) { - try { - Pty pty = load(JnaSupport.class).current(); - terminal = new PosixSysTerminal(name, type, pty, inputStreamWrapper.apply(pty.getSlaveInput()), pty.getSlaveOutput(), encoding, nativeSignals, signalHandler); - } catch (Throwable t) { - // ignore - Log.debug("Error creating JNA based terminal: ", t.getMessage(), t); - exception.addSuppressed(t); + if (terminal == null && tbs.hasJansiSupport()) { + try { + Pty pty = tbs.getJansiSupport().current(); + terminal = new PosixSysTerminal(name, type, pty, inputStreamWrapper.apply(pty.getSlaveInput()), pty.getSlaveOutput(), encoding, nativeSignals, signalHandler); + } catch (Throwable t) { + Log.debug("Error creating JANSI based terminal: ", t.getMessage(), t); + exception.addSuppressed(t); + } } - } - if (jansi) { - try { - Pty pty = load(JansiSupport.class).current(); - terminal = new PosixSysTerminal(name, type, pty, inputStreamWrapper.apply(pty.getSlaveInput()), pty.getSlaveOutput(), encoding, nativeSignals, signalHandler); - } catch (Throwable t) { - Log.debug("Error creating JANSI based terminal: ", t.getMessage(), t); - exception.addSuppressed(t); + if (terminal == null && exec) { + try { + Pty pty = tbs.getExecPty(); + terminal = new PosixSysTerminal(name, type, pty, inputStreamWrapper.apply(pty.getSlaveInput()), pty.getSlaveOutput(), encoding, nativeSignals, signalHandler); + } catch (Throwable t) { + // Ignore if not a tty + Log.debug("Error creating EXEC based terminal: ", t.getMessage(), t); + exception.addSuppressed(t); + } } } - if (exec) { - try { - Pty pty = ExecPty.current(); - terminal = new PosixSysTerminal(name, type, pty, inputStreamWrapper.apply(pty.getSlaveInput()), pty.getSlaveOutput(), encoding, nativeSignals, signalHandler); - } catch (Throwable t) { - // Ignore if not a tty - Log.debug("Error creating EXEC based terminal: ", t.getMessage(), t); - exception.addSuppressed(t); + if (terminal instanceof AbstractTerminal) { + AbstractTerminal t = (AbstractTerminal) terminal; + if (SYSTEM_TERMINAL.compareAndSet(null, t)) { + t.setOnClose(() -> SYSTEM_TERMINAL.compareAndSet(t, null)); + } else { + exception.addSuppressed(new IllegalStateException("A system terminal is already running. " + + "Make sure to use the created system Terminal on the LineReaderBuilder if you're using one " + + "or that previously created system Terminals have been correctly closed.")); + terminal.close(); + terminal = null; } } } - if (terminal instanceof AbstractTerminal) { - AbstractTerminal t = (AbstractTerminal) terminal; - if (SYSTEM_TERMINAL.compareAndSet(null, t)) { - t.setOnClose(new Runnable() { - @Override - public void run() { - SYSTEM_TERMINAL.compareAndSet(t, null); - } - }); - } else { - exception.addSuppressed(new IllegalStateException("A system terminal is already running. " + - "Make sure to use the created system Terminal on the LineReaderBuilder if you're using one " + - "or that previously created system Terminals have been correctly closed.")); - terminal.close(); - terminal = null; - } - } if (terminal == null && (dumb == null || dumb)) { // forced colored dumb terminal - boolean color = getBoolean(PROP_DUMB_COLOR, false); - // detect emacs using the env variable - if (!color) { - color = System.getenv("INSIDE_EMACS") != null; - } - // detect Intellij Idea - if (!color) { - String command = getParentProcessCommand(); - color = command != null && command.contains("idea"); - } - if (!color && dumb == null) { - if (Log.isDebugEnabled()) { - Log.warn("Creating a dumb terminal", exception); - } else { - Log.warn("Unable to create a system terminal, creating a dumb terminal (enable debug logging for more information)"); + Boolean color = this.color; + if (color == null) { + color = getBoolean(PROP_DUMB_COLOR, false); + // detect emacs using the env variable + if (!color) { + color = System.getenv("INSIDE_EMACS") != null; + } + // detect Intellij Idea + if (!color) { + String command = getParentProcessCommand(); + color = command != null && command.contains("idea"); + } + if (!color) { + color = tbs.isConsoleOutput() && System.getenv("TERM") != null; + } + if (!color && dumb == null) { + if (Log.isDebugEnabled()) { + Log.warn("input is tty: {}", tbs.isConsoleInput()); + Log.warn("output is tty: {}", tbs.isConsoleOutput()); + Log.warn("Creating a dumb terminal", exception); + } else { + Log.warn("Unable to create a system terminal, creating a dumb terminal (enable debug logging for more information)"); + } } } terminal = new DumbTerminal(name, color ? Terminal.TYPE_DUMB_COLOR : Terminal.TYPE_DUMB, - new FileInputStream(FileDescriptor.in), + inputStreamWrapper.apply(new FileInputStream(FileDescriptor.in)), new FileOutputStream(FileDescriptor.out), encoding, signalHandler); } @@ -440,7 +466,7 @@ public final class TerminalBuilder { if (jna) { try { Pty pty = load(JnaSupport.class).open(attributes, size); - return new PosixPtyTerminal(name, type, pty, in, out, encoding, signalHandler, paused); + return new PosixPtyTerminal(name, type, pty, inputStreamWrapper.apply(in), out, encoding, signalHandler, paused); } catch (Throwable t) { Log.debug("Error creating JNA based terminal: ", t.getMessage(), t); } @@ -448,12 +474,12 @@ public final class TerminalBuilder { if (jansi) { try { Pty pty = load(JansiSupport.class).open(attributes, size); - return new PosixPtyTerminal(name, type, pty, in, out, encoding, signalHandler, paused); + return new PosixPtyTerminal(name, type, pty, inputStreamWrapper.apply(in), out, encoding, signalHandler, paused); } catch (Throwable t) { Log.debug("Error creating JANSI based terminal: ", t.getMessage(), t); } } - return new ExternalTerminal(name, type, in, out, encoding, signalHandler, paused, attributes, size); + return new ExternalTerminal(name, type, inputStreamWrapper.apply(in), out, encoding, signalHandler, paused, attributes, size); } } @@ -482,7 +508,116 @@ public final class TerminalBuilder { return def; } - private S load(Class clazz) { + private static S load(Class clazz) { return ServiceLoader.load(clazz, clazz.getClassLoader()).iterator().next(); } + + /** + * Allows an application to override the result of {@link #build()}. The + * intended use case is to allow a container or server application to control + * an embedded application that uses a LineReader that uses Terminal + * constructed with TerminalBuilder.build but provides no public api for setting + * the LineReader of the {@link Terminal}. For example, the sbt + * build tool uses a LineReader to implement an interactive shell. + * One of its supported commands is console which invokes + * the scala REPL. The scala REPL also uses a LineReader and it + * is necessary to override the {@link Terminal} used by the the REPL to + * share the same {@link Terminal} instance used by sbt. + * + *

      + * When this method is called with a non-null {@link Terminal}, all subsequent + * calls to {@link #build()} will return the provided {@link Terminal} regardless + * of how the {@link TerminalBuilder} was constructed. The default behavior + * of {@link TerminalBuilder} can be restored by calling setTerminalOverride + * with a null {@link Terminal} + *

      + * + *

      + * Usage of setTerminalOverride should be restricted to cases where it + * isn't possible to update the api of the nested application to accept + * a {@link Terminal instance}. + *

      + * + * @param terminal the {@link Terminal} to globally override + */ + @Deprecated + public static void setTerminalOverride(final Terminal terminal) { + TERMINAL_OVERRIDE.set(terminal); + } + + private static class TerminalBuilderSupport { + private JansiSupport jansiSupport = null; + private JnaSupport jnaSupport = null; + private Pty pty = null; + private boolean consoleOutput; + + TerminalBuilderSupport(boolean jna, boolean jansi) { + if (jna) { + try { + jnaSupport = load(JnaSupport.class); + consoleOutput = jnaSupport.isConsoleOutput(); + } catch (Throwable e) { + jnaSupport = null; + Log.debug("jnaSupport.isConsoleOutput(): ", e); + } + } + if (jansi) { + try { + jansiSupport = load(JansiSupport.class); + consoleOutput = jansiSupport.isConsoleOutput(); + } catch (Throwable e) { + jansiSupport = null; + Log.debug("jansiSupport.isConsoleOutput(): ", e); + } + } + if (jnaSupport == null && jansiSupport == null) { + try { + pty = ExecPty.current(); + consoleOutput = true; + } catch (Exception e) { + Log.debug("ExecPty.current(): ", e); + } + } + } + + public boolean isConsoleOutput() { + return consoleOutput; + } + + public boolean isConsoleInput() { + if (pty != null) { + return true; + } else if (hasJnaSupport()) { + return jnaSupport.isConsoleInput(); + } else if (hasJansiSupport()) { + return jansiSupport.isConsoleInput(); + } else { + return false; + } + } + + public boolean hasJnaSupport() { + return jnaSupport != null; + } + + public boolean hasJansiSupport() { + return jansiSupport != null; + } + + public JnaSupport getJnaSupport() { + return jnaSupport; + } + + public JansiSupport getJansiSupport() { + return jansiSupport; + } + + public Pty getExecPty() throws IOException { + if (pty == null) { + pty = ExecPty.current(); + } + return pty; + } + + } } diff --git a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/AbstractTerminal.java b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/AbstractTerminal.java index 98c22c12a50..e92233c7b4f 100644 --- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/AbstractTerminal.java +++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/AbstractTerminal.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002-2018, the original author or authors. + * Copyright (c) 2002-2021, the original author or authors. * * This software is distributable under the BSD license. See the terms of the * BSD license in the documentation provided with this software. @@ -17,6 +17,7 @@ import java.util.HashSet; import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import java.util.function.IntConsumer; import java.util.function.IntSupplier; @@ -27,6 +28,7 @@ import jdk.internal.org.jline.terminal.Attributes.LocalFlag; import jdk.internal.org.jline.terminal.Cursor; import jdk.internal.org.jline.terminal.MouseEvent; import jdk.internal.org.jline.terminal.Terminal; +import jdk.internal.org.jline.utils.ColorPalette; import jdk.internal.org.jline.utils.Curses; import jdk.internal.org.jline.utils.InfoCmp; import jdk.internal.org.jline.utils.InfoCmp.Capability; @@ -38,10 +40,11 @@ public abstract class AbstractTerminal implements Terminal { protected final String name; protected final String type; protected final Charset encoding; - protected final Map handlers = new HashMap<>(); + protected final Map handlers = new ConcurrentHashMap<>(); protected final Set bools = new HashSet<>(); protected final Map ints = new HashMap<>(); protected final Map strings = new HashMap<>(); + protected final ColorPalette palette = new ColorPalette(this); protected Status status; protected Runnable onClose; @@ -51,7 +54,7 @@ public abstract class AbstractTerminal implements Terminal { public AbstractTerminal(String name, String type, Charset encoding, SignalHandler signalHandler) throws IOException { this.name = name; - this.type = type; + this.type = type != null ? type : "ansi"; this.encoding = encoding != null ? encoding : Charset.defaultCharset(); for (Signal signal : Signal.values()) { handlers.put(signal, signalHandler); @@ -197,12 +200,10 @@ public abstract class AbstractTerminal implements Terminal { protected void parseInfoCmp() { String capabilities = null; - if (type != null) { - try { - capabilities = InfoCmp.getInfoCmp(type); - } catch (Exception e) { - Log.warn("Unable to retrieve infocmp for type " + type, e); - } + try { + capabilities = InfoCmp.getInfoCmp(type); + } catch (Exception e) { + Log.warn("Unable to retrieve infocmp for type " + type, e); } if (capabilities == null) { capabilities = InfoCmp.getLoadedInfoCmp("ansi"); @@ -241,7 +242,7 @@ public abstract class AbstractTerminal implements Terminal { @Override public boolean hasFocusSupport() { - return type != null && type.startsWith("xterm"); + return type.startsWith("xterm"); } @Override @@ -283,4 +284,8 @@ public abstract class AbstractTerminal implements Terminal { return false; } + @Override + public ColorPalette getPalette() { + return palette; + } } diff --git a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/AbstractWindowsTerminal.java b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/AbstractWindowsTerminal.java index 9094d6caba4..5e21f034530 100644 --- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/AbstractWindowsTerminal.java +++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/impl/AbstractWindowsTerminal.java @@ -521,8 +521,6 @@ public abstract class AbstractWindowsTerminal extends AbstractTerminal { return true; } - protected abstract int getConsoleOutputCP(); - protected abstract int getConsoleMode(); protected abstract void setConsoleMode(int mode); diff --git a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/spi/JansiSupport.java b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/spi/JansiSupport.java index b6e42aa2196..750c8fc0712 100644 --- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/spi/JansiSupport.java +++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/spi/JansiSupport.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002-2019, the original author or authors. + * Copyright (c) 2002-2020, the original author or authors. * * This software is distributable under the BSD license. See the terms of the * BSD license in the documentation provided with this software. @@ -25,4 +25,9 @@ public interface JansiSupport { Terminal winSysTerminal(String name, String type, boolean ansiPassThrough, Charset encoding, int codepage, boolean nativeSignals, Terminal.SignalHandler signalHandler, boolean paused) throws IOException; + boolean isWindowsConsole(); + + boolean isConsoleOutput(); + + boolean isConsoleInput(); } diff --git a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/spi/JnaSupport.java b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/spi/JnaSupport.java index 017e97ee8ae..35f71a603f8 100644 --- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/spi/JnaSupport.java +++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/terminal/spi/JnaSupport.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002-2019, the original author or authors. + * Copyright (c) 2002-2020, the original author or authors. * * This software is distributable under the BSD license. See the terms of the * BSD license in the documentation provided with this software. @@ -29,4 +29,9 @@ public interface JnaSupport { Terminal winSysTerminal(String name, String type, boolean ansiPassThrough, Charset encoding, int codepage, boolean nativeSignals, Terminal.SignalHandler signalHandler, boolean paused, Function inputStreamWrapper) throws IOException; + boolean isWindowsConsole(); + + boolean isConsoleOutput(); + + boolean isConsoleInput(); } diff --git a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/AttributedCharSequence.java b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/AttributedCharSequence.java index 7e14db7fcf3..ccb0aaf689b 100644 --- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/AttributedCharSequence.java +++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/AttributedCharSequence.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002-2019, the original author or authors. + * Copyright (c) 2002-2021, the original author or authors. * * This software is distributable under the BSD license. See the terms of the * BSD license in the documentation provided with this software. @@ -20,12 +20,16 @@ import static jdk.internal.org.jline.utils.AttributedStyle.BG_COLOR_EXP; import static jdk.internal.org.jline.utils.AttributedStyle.FG_COLOR; import static jdk.internal.org.jline.utils.AttributedStyle.FG_COLOR_EXP; import static jdk.internal.org.jline.utils.AttributedStyle.F_BACKGROUND; +import static jdk.internal.org.jline.utils.AttributedStyle.F_BACKGROUND_IND; +import static jdk.internal.org.jline.utils.AttributedStyle.F_BACKGROUND_RGB; import static jdk.internal.org.jline.utils.AttributedStyle.F_BLINK; import static jdk.internal.org.jline.utils.AttributedStyle.F_BOLD; import static jdk.internal.org.jline.utils.AttributedStyle.F_CONCEAL; import static jdk.internal.org.jline.utils.AttributedStyle.F_CROSSED_OUT; import static jdk.internal.org.jline.utils.AttributedStyle.F_FAINT; import static jdk.internal.org.jline.utils.AttributedStyle.F_FOREGROUND; +import static jdk.internal.org.jline.utils.AttributedStyle.F_FOREGROUND_IND; +import static jdk.internal.org.jline.utils.AttributedStyle.F_FOREGROUND_RGB; import static jdk.internal.org.jline.utils.AttributedStyle.F_INVERSE; import static jdk.internal.org.jline.utils.AttributedStyle.F_ITALIC; import static jdk.internal.org.jline.utils.AttributedStyle.F_UNDERLINE; @@ -35,6 +39,15 @@ import static jdk.internal.org.jline.terminal.TerminalBuilder.PROP_DISABLE_ALTER public abstract class AttributedCharSequence implements CharSequence { + public static final int TRUE_COLORS = 0x1000000; + private static final int HIGH_COLORS = 0x7FFF; + + public enum ForceMode { + None, + Force256Colors, + ForceTrueColors + } + // cache the value here as we can't afford to get it each time static final boolean DISABLE_ALTERNATE_CHARSET = Boolean.getBoolean(PROP_DISABLE_ALTERNATE_CHARSET); @@ -55,33 +68,54 @@ public abstract class AttributedCharSequence implements CharSequence { return toString(); } int colors = 256; - boolean force256colors = false; + ForceMode forceMode = ForceMode.None; + ColorPalette palette = null; String alternateIn = null, alternateOut = null; if (terminal != null) { Integer max_colors = terminal.getNumericCapability(Capability.max_colors); if (max_colors != null) { colors = max_colors; } - force256colors = AbstractWindowsTerminal.TYPE_WINDOWS_256_COLOR.equals(terminal.getType()) - || AbstractWindowsTerminal.TYPE_WINDOWS_CONEMU.equals(terminal.getType()); + if (AbstractWindowsTerminal.TYPE_WINDOWS_256_COLOR.equals(terminal.getType()) + || AbstractWindowsTerminal.TYPE_WINDOWS_CONEMU.equals(terminal.getType())) { + forceMode = ForceMode.Force256Colors; + } + palette = terminal.getPalette(); if (!DISABLE_ALTERNATE_CHARSET) { alternateIn = Curses.tputs(terminal.getStringCapability(Capability.enter_alt_charset_mode)); alternateOut = Curses.tputs(terminal.getStringCapability(Capability.exit_alt_charset_mode)); } } - return toAnsi(colors, force256colors, alternateIn, alternateOut); + return toAnsi(colors, forceMode, palette, alternateIn, alternateOut); } + @Deprecated public String toAnsi(int colors, boolean force256colors) { return toAnsi(colors, force256colors, null, null); } + @Deprecated public String toAnsi(int colors, boolean force256colors, String altIn, String altOut) { + return toAnsi(colors, force256colors ? ForceMode.Force256Colors : ForceMode.None, null, altIn, altOut); + } + + public String toAnsi(int colors, ForceMode force) { + return toAnsi(colors, force, null, null, null); + } + + public String toAnsi(int colors, ForceMode force, ColorPalette palette) { + return toAnsi(colors, force, palette, null, null); + } + + public String toAnsi(int colors, ForceMode force, ColorPalette palette, String altIn, String altOut) { StringBuilder sb = new StringBuilder(); - int style = 0; - int foreground = -1; - int background = -1; + long style = 0; + long foreground = 0; + long background = 0; boolean alt = false; + if (palette == null) { + palette = ColorPalette.DEFAULT; + } for (int i = 0; i < length(); i++) { char c = charAt(i); if (altIn != null && altOut != null) { @@ -105,14 +139,14 @@ public abstract class AttributedCharSequence implements CharSequence { sb.append(alt ? altIn : altOut); } } - int s = styleCodeAt(i) & ~F_HIDDEN; // The hidden flag does not change the ansi styles + long s = styleCodeAt(i) & ~F_HIDDEN; // The hidden flag does not change the ansi styles if (style != s) { - int d = (style ^ s) & MASK; - int fg = (s & F_FOREGROUND) != 0 ? (s & FG_COLOR) >>> FG_COLOR_EXP : -1; - int bg = (s & F_BACKGROUND) != 0 ? (s & BG_COLOR) >>> BG_COLOR_EXP : -1; + long d = (style ^ s) & MASK; + long fg = (s & F_FOREGROUND) != 0 ? s & (FG_COLOR | F_FOREGROUND) : 0; + long bg = (s & F_BACKGROUND) != 0 ? s & (BG_COLOR | F_BACKGROUND) : 0; if (s == 0) { sb.append("\033[0m"); - foreground = background = -1; + foreground = background = 0; } else { sb.append("\033["); boolean first = true; @@ -135,18 +169,38 @@ public abstract class AttributedCharSequence implements CharSequence { first = attr(sb, (s & F_CROSSED_OUT) != 0 ? "9" : "29", first); } if (foreground != fg) { - if (fg >= 0) { - int rounded = Colors.roundColor(fg, colors); - if (rounded < 8 && !force256colors) { - first = attr(sb, "3" + Integer.toString(rounded), first); - // small hack to force setting bold again after a foreground color change - d |= (s & F_BOLD); - } else if (rounded < 16 && !force256colors) { - first = attr(sb, "9" + Integer.toString(rounded - 8), first); - // small hack to force setting bold again after a foreground color change - d |= (s & F_BOLD); - } else { - first = attr(sb, "38;5;" + Integer.toString(rounded), first); + if (fg > 0) { + int rounded = -1; + if ((fg & F_FOREGROUND_RGB) != 0) { + int r = (int)(fg >> (FG_COLOR_EXP + 16)) & 0xFF; + int g = (int)(fg >> (FG_COLOR_EXP + 8)) & 0xFF; + int b = (int)(fg >> FG_COLOR_EXP) & 0xFF; + if (colors >= HIGH_COLORS) { + first = attr(sb, "38;2;" + r + ";" + g + ";" + b, first); + } else { + rounded = palette.round(r, g, b); + } + } else if ((fg & F_FOREGROUND_IND) != 0) { + rounded = palette.round((int)(fg >> FG_COLOR_EXP) & 0xFF); + } + if (rounded >= 0) { + if (colors >= HIGH_COLORS && force == ForceMode.ForceTrueColors) { + int col = palette.getColor(rounded); + int r = (col >> 16) & 0xFF; + int g = (col >> 8) & 0xFF; + int b = col & 0xFF; + first = attr(sb, "38;2;" + r + ";" + g + ";" + b, first); + } else if (force == ForceMode.Force256Colors || rounded >= 16) { + first = attr(sb, "38;5;" + rounded, first); + } else if (rounded >= 8) { + first = attr(sb, "9" + (rounded - 8), first); + // small hack to force setting bold again after a foreground color change + d |= (s & F_BOLD); + } else { + first = attr(sb, "3" + rounded, first); + // small hack to force setting bold again after a foreground color change + d |= (s & F_BOLD); + } } } else { first = attr(sb, "39", first); @@ -154,14 +208,34 @@ public abstract class AttributedCharSequence implements CharSequence { foreground = fg; } if (background != bg) { - if (bg >= 0) { - int rounded = Colors.roundColor(bg, colors); - if (rounded < 8 && !force256colors) { - first = attr(sb, "4" + Integer.toString(rounded), first); - } else if (rounded < 16 && !force256colors) { - first = attr(sb, "10" + Integer.toString(rounded - 8), first); - } else { - first = attr(sb, "48;5;" + Integer.toString(rounded), first); + if (bg > 0) { + int rounded = -1; + if ((bg & F_BACKGROUND_RGB) != 0) { + int r = (int)(bg >> (BG_COLOR_EXP + 16)) & 0xFF; + int g = (int)(bg >> (BG_COLOR_EXP + 8)) & 0xFF; + int b = (int)(bg >> BG_COLOR_EXP) & 0xFF; + if (colors >= HIGH_COLORS) { + first = attr(sb, "48;2;" + r + ";" + g + ";" + b, first); + } else { + rounded = palette.round(r, g, b); + } + } else if ((bg & F_BACKGROUND_IND) != 0) { + rounded = palette.round((int)(bg >> BG_COLOR_EXP) & 0xFF); + } + if (rounded >= 0) { + if (colors >= HIGH_COLORS && force == ForceMode.ForceTrueColors) { + int col = palette.getColor(rounded); + int r = (col >> 16) & 0xFF; + int g = (col >> 8) & 0xFF; + int b = col & 0xFF; + first = attr(sb, "48;2;" + r + ";" + g + ";" + b, first); + } else if (force == ForceMode.Force256Colors || rounded >= 16) { + first = attr(sb, "48;5;" + rounded, first); + } else if (rounded >= 8) { + first = attr(sb, "10" + (rounded - 8), first); + } else { + first = attr(sb, "4" + rounded, first); + } } } else { first = attr(sb, "49", first); @@ -220,7 +294,7 @@ public abstract class AttributedCharSequence implements CharSequence { public abstract AttributedStyle styleAt(int index); - int styleCodeAt(int index) { + long styleCodeAt(int index) { return styleAt(index).getStyle(); } diff --git a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/AttributedString.java b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/AttributedString.java index eab4de35040..47492b72e76 100644 --- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/AttributedString.java +++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/AttributedString.java @@ -25,7 +25,7 @@ import java.util.regex.Pattern; public class AttributedString extends AttributedCharSequence { final char[] buffer; - final int[] style; + final long[] style; final int start; final int end; public static final AttributedString EMPTY = new AttributedString(""); @@ -78,7 +78,7 @@ public class AttributedString extends AttributedCharSequence { for (int i = 0; i < l; i++) { buffer[i] = str.charAt(start + i); } - style = new int[l]; + style = new long[l]; if (s != null) { Arrays.fill(style, s.getStyle()); } @@ -87,7 +87,7 @@ public class AttributedString extends AttributedCharSequence { } } - AttributedString(char[] buffer, int[] style, int start, int end) { + AttributedString(char[] buffer, long[] style, int start, int end) { this.buffer = buffer; this.style = style; this.start = start; @@ -142,7 +142,7 @@ public class AttributedString extends AttributedCharSequence { } @Override - int styleCodeAt(int index) { + long styleCodeAt(int index) { return style[start + index]; } @@ -155,7 +155,7 @@ public class AttributedString extends AttributedCharSequence { Matcher matcher = pattern.matcher(this); boolean result = matcher.find(); if (result) { - int[] newstyle = this.style.clone(); + long[] newstyle = this.style.clone(); do { for (int i = matcher.start(); i < matcher.end(); i++) { newstyle[this.start + i] = (newstyle[this.start + i] & ~style.getMask()) | style.getStyle(); @@ -185,7 +185,7 @@ public class AttributedString extends AttributedCharSequence { } return true; } - private boolean arrEq(int[] a1, int[] a2, int s1, int s2, int l) { + private boolean arrEq(long[] a1, long[] a2, int s1, int s2, int l) { for (int i = 0; i < l; i++) { if (a1[s1+i] != a2[s2+i]) { return false; diff --git a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/AttributedStringBuilder.java b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/AttributedStringBuilder.java index eebbce7bd08..779675348c9 100644 --- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/AttributedStringBuilder.java +++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/AttributedStringBuilder.java @@ -24,7 +24,7 @@ import java.util.regex.Pattern; public class AttributedStringBuilder extends AttributedCharSequence implements Appendable { private char[] buffer; - private int[] style; + private long[] style; private int length; private TabStops tabs = new TabStops(0); private int lastLineLength = 0; @@ -44,7 +44,7 @@ public class AttributedStringBuilder extends AttributedCharSequence implements A public AttributedStringBuilder(int capacity) { buffer = new char[capacity]; - style = new int[capacity]; + style = new long[capacity]; length = 0; } @@ -64,7 +64,7 @@ public class AttributedStringBuilder extends AttributedCharSequence implements A } @Override - int styleCodeAt(int index) { + long styleCodeAt(int index) { return style[index]; } @@ -89,11 +89,17 @@ public class AttributedStringBuilder extends AttributedCharSequence implements A @Override public AttributedStringBuilder append(CharSequence csq) { + if (csq == null) { + csq = "null"; // Required by Appendable.append + } return append(new AttributedString(csq, current)); } @Override public AttributedStringBuilder append(CharSequence csq, int start, int end) { + if (csq == null) { + csq = "null"; // Required by Appendable.append + } return append(csq.subSequence(start, end)); } @@ -152,7 +158,7 @@ public class AttributedStringBuilder extends AttributedCharSequence implements A ensureCapacity(length + end - start); for (int i = start; i < end; i++) { char c = str.charAt(i); - int s = str.styleCodeAt(i) & ~current.getMask() | current.getStyle(); + long s = str.styleCodeAt(i) & ~current.getMask() | current.getStyle(); if (tabs.defined() && c == '\t') { insertTab(new AttributedStyle(s, 0)); } else { @@ -286,12 +292,10 @@ public class AttributedStringBuilder extends AttributedCharSequence implements A int r = Integer.parseInt(params[++j]); int g = Integer.parseInt(params[++j]); int b = Integer.parseInt(params[++j]); - // convert to 256 colors - int col = 16 + (r >> 3) * 36 + (g >> 3) * 6 + (b >> 3); if (ansiParam == 38) { - current = current.foreground(col); + current = current.foreground(r, g, b); } else { - current = current.background(col); + current = current.background(r, g, b); } } } else if (ansiParam2 == 5) { diff --git a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/AttributedStyle.java b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/AttributedStyle.java index 254b07654b2..902e2e1f3b8 100644 --- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/AttributedStyle.java +++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/AttributedStyle.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002-2018, the original author or authors. + * Copyright (c) 2002-2021, the original author or authors. * * This software is distributable under the BSD license. See the terms of the * BSD license in the documentation provided with this software. @@ -26,24 +26,28 @@ public class AttributedStyle { public static final int BRIGHT = 8; - static final int F_BOLD = 0x00000001; - static final int F_FAINT = 0x00000002; - static final int F_ITALIC = 0x00000004; - static final int F_UNDERLINE = 0x00000008; - static final int F_BLINK = 0x00000010; - static final int F_INVERSE = 0x00000020; - static final int F_CONCEAL = 0x00000040; - static final int F_CROSSED_OUT = 0x00000080; - static final int F_FOREGROUND = 0x00000100; - static final int F_BACKGROUND = 0x00000200; - static final int F_HIDDEN = 0x00000400; - - static final int MASK = 0x000007FF; - - static final int FG_COLOR_EXP = 16; - static final int BG_COLOR_EXP = 24; - static final int FG_COLOR = 0xFF << FG_COLOR_EXP; - static final int BG_COLOR = 0xFF << BG_COLOR_EXP; + static final long F_BOLD = 0x00000001; + static final long F_FAINT = 0x00000002; + static final long F_ITALIC = 0x00000004; + static final long F_UNDERLINE = 0x00000008; + static final long F_BLINK = 0x00000010; + static final long F_INVERSE = 0x00000020; + static final long F_CONCEAL = 0x00000040; + static final long F_CROSSED_OUT = 0x00000080; + static final long F_FOREGROUND_IND = 0x00000100; + static final long F_FOREGROUND_RGB = 0x00000200; + static final long F_FOREGROUND = F_FOREGROUND_IND | F_FOREGROUND_RGB; + static final long F_BACKGROUND_IND = 0x00000400; + static final long F_BACKGROUND_RGB = 0x00000800; + static final long F_BACKGROUND = F_BACKGROUND_IND | F_BACKGROUND_RGB; + static final long F_HIDDEN = 0x00001000; + + static final long MASK = 0x00001FFF; + + static final int FG_COLOR_EXP = 15; + static final int BG_COLOR_EXP = 39; + static final long FG_COLOR = 0xFFFFFFL << FG_COLOR_EXP; + static final long BG_COLOR = 0xFFFFFFL << BG_COLOR_EXP; public static final AttributedStyle DEFAULT = new AttributedStyle(); public static final AttributedStyle BOLD = DEFAULT.bold(); @@ -53,8 +57,8 @@ public class AttributedStyle { public static final AttributedStyle HIDDEN = DEFAULT.hidden(); public static final AttributedStyle HIDDEN_OFF = DEFAULT.hiddenOff(); - final int style; - final int mask; + final long style; + final long mask; public AttributedStyle() { this(0, 0); @@ -64,7 +68,7 @@ public class AttributedStyle { this(s.style, s.mask); } - public AttributedStyle(int style, int mask) { + public AttributedStyle(long style, long mask) { this.style = style; this.mask = mask & MASK | ((style & F_FOREGROUND) != 0 ? FG_COLOR : 0) | ((style & F_BACKGROUND) != 0 ? BG_COLOR : 0); @@ -135,7 +139,7 @@ public class AttributedStyle { } public AttributedStyle inverseNeg() { - int s = (style & F_INVERSE) != 0 ? style & ~F_INVERSE : style | F_INVERSE; + long s = (style & F_INVERSE) != 0 ? style & ~F_INVERSE : style | F_INVERSE; return new AttributedStyle(s, mask | F_INVERSE); } @@ -172,7 +176,15 @@ public class AttributedStyle { } public AttributedStyle foreground(int color) { - return new AttributedStyle(style & ~FG_COLOR | F_FOREGROUND | ((color << FG_COLOR_EXP) & FG_COLOR), mask | F_FOREGROUND); + return new AttributedStyle(style & ~FG_COLOR | F_FOREGROUND_IND | (((long) color << FG_COLOR_EXP) & FG_COLOR), mask | F_FOREGROUND_IND); + } + + public AttributedStyle foreground(int r, int g, int b) { + return foregroundRgb(r << 16 | g << 8 | b); + } + + public AttributedStyle foregroundRgb(int color) { + return new AttributedStyle(style & ~FG_COLOR | F_FOREGROUND_RGB | ((((long) color & 0xFFFFFF) << FG_COLOR_EXP) & FG_COLOR), mask | F_FOREGROUND_RGB); } public AttributedStyle foregroundOff() { @@ -184,7 +196,15 @@ public class AttributedStyle { } public AttributedStyle background(int color) { - return new AttributedStyle(style & ~BG_COLOR | F_BACKGROUND | ((color << BG_COLOR_EXP) & BG_COLOR), mask | F_BACKGROUND); + return new AttributedStyle(style & ~BG_COLOR | F_BACKGROUND_IND | (((long) color << BG_COLOR_EXP) & BG_COLOR), mask | F_BACKGROUND_IND); + } + + public AttributedStyle background(int r, int g, int b) { + return backgroundRgb(r << 16 | g << 8 | b); + } + + public AttributedStyle backgroundRgb(int color) { + return new AttributedStyle(style & ~BG_COLOR | F_BACKGROUND_RGB | ((((long) color & 0xFFFFFF) << BG_COLOR_EXP) & BG_COLOR), mask | F_BACKGROUND_RGB); } public AttributedStyle backgroundOff() { @@ -214,11 +234,11 @@ public class AttributedStyle { return new AttributedStyle(style & ~F_HIDDEN, mask & ~F_HIDDEN); } - public int getStyle() { + public long getStyle() { return style; } - public int getMask() { + public long getMask() { return mask; } @@ -234,8 +254,22 @@ public class AttributedStyle { @Override public int hashCode() { - int result = style; - result = 31 * result + mask; - return result; + return 31 * Long.hashCode(style) + Long.hashCode(mask); + } + + public String toAnsi() { + AttributedStringBuilder sb = new AttributedStringBuilder(); + sb.styled(this, " "); + String s = sb.toAnsi(AttributedCharSequence.TRUE_COLORS, AttributedCharSequence.ForceMode.None); + return s.length() > 1 ? s.substring(2, s.indexOf('m')) : s; + } + + @Override + public String toString() { + return "AttributedStyle{" + + "style=" + style + + ", mask=" + mask + + ", ansi=" + toAnsi() + + '}'; } } diff --git a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/ColorPalette.java b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/ColorPalette.java new file mode 100644 index 00000000000..6f55273a7b9 --- /dev/null +++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/ColorPalette.java @@ -0,0 +1,262 @@ +/* + * Copyright (c) 2002-2020, the original author or authors. + * + * This software is distributable under the BSD license. See the terms of the + * BSD license in the documentation provided with this software. + * + * https://opensource.org/licenses/BSD-3-Clause + */ +package jdk.internal.org.jline.utils; + +import java.io.IOException; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import jdk.internal.org.jline.terminal.Terminal; + +/** + * Color palette + */ +public class ColorPalette { + + public static final String XTERM_INITC = "\\E]4;%p1%d;rgb\\:%p2%{255}%*%{1000}%/%2.2X/%p3%{255}%*%{1000}%/%2.2X/%p4%{255}%*%{1000}%/%2.2X\\E\\\\"; + + public static final ColorPalette DEFAULT = new ColorPalette(); + + private final Terminal terminal; + private String distanceName; + private Colors.Distance distance; + private boolean osc4; + private int[] palette; + + public ColorPalette() { + this.terminal = null; + this.distanceName = null; + this.palette = Colors.DEFAULT_COLORS_256; + } + + public ColorPalette(Terminal terminal) throws IOException { + this(terminal, null); + } + + public ColorPalette(Terminal terminal, String distance) throws IOException { + this.terminal = terminal; + this.distanceName = distance; + loadPalette(false); + } + + /** + * Get the name of the distance to use for rounding colors. + * @return the name of the color distance + */ + public String getDistanceName() { + return distanceName; + } + + /** + * Set the name of the color distance to use when rounding RGB colors to the palette. + * @param name the name of the color distance + */ + public void setDistance(String name) { + this.distanceName = name; + } + + /** + * Check if the terminal has the capability to change colors. + * @return true if the terminal can change colors + */ + public boolean canChange() { + return terminal != null && terminal.getBooleanCapability(InfoCmp.Capability.can_change); + } + + /** + * Load the palette from the terminal. + * If the palette has already been loaded, subsequent calls will simply return true. + * + * @return true if the palette has been successfully loaded. + * @throws IOException + */ + public boolean loadPalette() throws IOException { + if (!osc4) { + loadPalette(true); + } + return osc4; + } + + protected void loadPalette(boolean doLoad) throws IOException { + if (terminal != null) { + int[] pal = doLoad ? doLoad(terminal) : null; + if (pal != null) { + this.palette = pal; + this.osc4 = true; + } else { + Integer cols = terminal.getNumericCapability(InfoCmp.Capability.max_colors); + if (cols != null) { + if (cols == Colors.DEFAULT_COLORS_88.length) { + this.palette = Colors.DEFAULT_COLORS_88; + } else { + this.palette = Arrays.copyOf(Colors.DEFAULT_COLORS_256, Math.min(cols, 256)); + } + } else { + this.palette = Arrays.copyOf(Colors.DEFAULT_COLORS_256, 256); + } + this.osc4 = false; + } + } else { + this.palette = Colors.DEFAULT_COLORS_256; + this.osc4 = false; + } + } + + /** + * Get the palette length + * @return the palette length + */ + public int getLength() { + return this.palette.length; + } + + /** + * Get a specific color in the palette + * @param index the index of the color + * @return the color at the given index + */ + public int getColor(int index) { + return palette[index]; + } + + /** + * Change the color of the palette + * @param index the index of the color + * @param color the new color value + */ + public void setColor(int index, int color) { + palette[index] = color; + if (canChange()) { + String initc = terminal.getStringCapability(InfoCmp.Capability.initialize_color); + if (initc != null || osc4) { + // initc expects color in 0..1000 range + int r = (((color >> 16) & 0xFF) * 1000) / 255 + 1; + int g = (((color >> 8) & 0xFF) * 1000) / 255 + 1; + int b = ((color & 0xFF) * 1000) / 255 + 1; + if (initc == null) { + // This is the xterm version + initc = XTERM_INITC; + } + Curses.tputs(terminal.writer(), initc, index, r, g, b); + terminal.writer().flush(); + } + } + } + + public boolean isReal() { + return osc4; + } + + public int round(int r, int g, int b) { + return Colors.roundColor((r << 16) + (g << 8) + b, palette, palette.length, getDist()); + } + + public int round(int col) { + if (col >= palette.length) { + col = Colors.roundColor(DEFAULT.getColor(col), palette, palette.length, getDist()); + } + return col; + } + + protected Colors.Distance getDist() { + if (distance == null) { + distance = Colors.getDistance(distanceName); + } + return distance; + } + + private static int[] doLoad(Terminal terminal) throws IOException { + PrintWriter writer = terminal.writer(); + NonBlockingReader reader = terminal.reader(); + + int[] palette = new int[256]; + for (int i = 0; i < 16; i++) { + StringBuilder req = new StringBuilder(1024); + req.append("\033]4"); + for (int j = 0; j < 16; j++) { + req.append(';').append(i * 16 + j).append(";?"); + } + req.append("\033\\"); + writer.write(req.toString()); + writer.flush(); + + boolean black = true; + for (int j = 0; j < 16; j++) { + if (reader.peek(50) < 0) { + break; + } + if (reader.read(10) != '\033' + || reader.read(10) != ']' + || reader.read(10) != '4' + || reader.read(10) != ';') { + return null; + } + int idx = 0; + int c; + while (true) { + c = reader.read(10); + if (c >= '0' && c <= '9') { + idx = idx * 10 + (c - '0'); + } else if (c == ';') { + break; + } else { + return null; + } + } + if (idx > 255) { + return null; + } + if (reader.read(10) != 'r' + || reader.read(10) != 'g' + || reader.read(10) != 'b' + || reader.read(10) != ':') { + return null; + } + StringBuilder sb = new StringBuilder(16); + List rgb = new ArrayList<>(); + while (true) { + c = reader.read(10); + if (c == '\007') { + rgb.add(sb.toString()); + break; + } else if (c == '\033') { + c = reader.read(10); + if (c == '\\') { + rgb.add(sb.toString()); + break; + } else { + return null; + } + } else if (c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z') { + sb.append((char) c); + } else if (c == '/') { + rgb.add(sb.toString()); + sb.setLength(0); + } + } + if (rgb.size() != 3) { + return null; + } + double r = Integer.parseInt(rgb.get(0), 16) / ((1 << (4 * rgb.get(0).length())) - 1.0); + double g = Integer.parseInt(rgb.get(1), 16) / ((1 << (4 * rgb.get(1).length())) - 1.0); + double b = Integer.parseInt(rgb.get(2), 16) / ((1 << (4 * rgb.get(2).length())) - 1.0); + palette[idx] = (int)((Math.round(r * 255) << 16) + (Math.round(g * 255) << 8) + Math.round(b * 255)); + black &= palette[idx] == 0; + } + if (black) { + break; + } + } + int max = 256; + while (max > 0 && palette[--max] == 0); + return Arrays.copyOfRange(palette, 0, max + 1); + } +} diff --git a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/Colors.java b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/Colors.java index 2cca97c54be..19550366944 100644 --- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/Colors.java +++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/Colors.java @@ -25,42 +25,92 @@ public class Colors { * Default 256 colors palette */ public static final int[] DEFAULT_COLORS_256 = { + // 16 ansi 0x000000, 0x800000, 0x008000, 0x808000, 0x000080, 0x800080, 0x008080, 0xc0c0c0, 0x808080, 0xff0000, 0x00ff00, 0xffff00, 0x0000ff, 0xff00ff, 0x00ffff, 0xffffff, - 0x000000, 0x00005f, 0x000087, 0x0000af, 0x0000d7, 0x0000ff, 0x005f00, 0x005f5f, - 0x005f87, 0x005faf, 0x005fd7, 0x005fff, 0x008700, 0x00875f, 0x008787, 0x0087af, - 0x0087d7, 0x0087ff, 0x00af00, 0x00af5f, 0x00af87, 0x00afaf, 0x00afd7, 0x00afff, - 0x00d700, 0x00d75f, 0x00d787, 0x00d7af, 0x00d7d7, 0x00d7ff, 0x00ff00, 0x00ff5f, - 0x00ff87, 0x00ffaf, 0x00ffd7, 0x00ffff, 0x5f0000, 0x5f005f, 0x5f0087, 0x5f00af, - 0x5f00d7, 0x5f00ff, 0x5f5f00, 0x5f5f5f, 0x5f5f87, 0x5f5faf, 0x5f5fd7, 0x5f5fff, - 0x5f8700, 0x5f875f, 0x5f8787, 0x5f87af, 0x5f87d7, 0x5f87ff, 0x5faf00, 0x5faf5f, - 0x5faf87, 0x5fafaf, 0x5fafd7, 0x5fafff, 0x5fd700, 0x5fd75f, 0x5fd787, 0x5fd7af, - 0x5fd7d7, 0x5fd7ff, 0x5fff00, 0x5fff5f, 0x5fff87, 0x5fffaf, 0x5fffd7, 0x5fffff, - 0x870000, 0x87005f, 0x870087, 0x8700af, 0x8700d7, 0x8700ff, 0x875f00, 0x875f5f, - 0x875f87, 0x875faf, 0x875fd7, 0x875fff, 0x878700, 0x87875f, 0x878787, 0x8787af, - 0x8787d7, 0x8787ff, 0x87af00, 0x87af5f, 0x87af87, 0x87afaf, 0x87afd7, 0x87afff, - 0x87d700, 0x87d75f, 0x87d787, 0x87d7af, 0x87d7d7, 0x87d7ff, 0x87ff00, 0x87ff5f, - 0x87ff87, 0x87ffaf, 0x87ffd7, 0x87ffff, 0xaf0000, 0xaf005f, 0xaf0087, 0xaf00af, - 0xaf00d7, 0xaf00ff, 0xaf5f00, 0xaf5f5f, 0xaf5f87, 0xaf5faf, 0xaf5fd7, 0xaf5fff, - 0xaf8700, 0xaf875f, 0xaf8787, 0xaf87af, 0xaf87d7, 0xaf87ff, 0xafaf00, 0xafaf5f, - 0xafaf87, 0xafafaf, 0xafafd7, 0xafafff, 0xafd700, 0xafd75f, 0xafd787, 0xafd7af, - 0xafd7d7, 0xafd7ff, 0xafff00, 0xafff5f, 0xafff87, 0xafffaf, 0xafffd7, 0xafffff, - 0xd70000, 0xd7005f, 0xd70087, 0xd700af, 0xd700d7, 0xd700ff, 0xd75f00, 0xd75f5f, - 0xd75f87, 0xd75faf, 0xd75fd7, 0xd75fff, 0xd78700, 0xd7875f, 0xd78787, 0xd787af, - 0xd787d7, 0xd787ff, 0xd7af00, 0xd7af5f, 0xd7af87, 0xd7afaf, 0xd7afd7, 0xd7afff, - 0xd7d700, 0xd7d75f, 0xd7d787, 0xd7d7af, 0xd7d7d7, 0xd7d7ff, 0xd7ff00, 0xd7ff5f, - 0xd7ff87, 0xd7ffaf, 0xd7ffd7, 0xd7ffff, 0xff0000, 0xff005f, 0xff0087, 0xff00af, - 0xff00d7, 0xff00ff, 0xff5f00, 0xff5f5f, 0xff5f87, 0xff5faf, 0xff5fd7, 0xff5fff, - 0xff8700, 0xff875f, 0xff8787, 0xff87af, 0xff87d7, 0xff87ff, 0xffaf00, 0xffaf5f, - 0xffaf87, 0xffafaf, 0xffafd7, 0xffafff, 0xffd700, 0xffd75f, 0xffd787, 0xffd7af, - 0xffd7d7, 0xffd7ff, 0xffff00, 0xffff5f, 0xffff87, 0xffffaf, 0xffffd7, 0xffffff, - + // 6x6x6 color cube + 0x000000, 0x00005f, 0x000087, 0x0000af, 0x0000d7, 0x0000ff, + 0x005f00, 0x005f5f, 0x005f87, 0x005faf, 0x005fd7, 0x005fff, + 0x008700, 0x00875f, 0x008787, 0x0087af, 0x0087d7, 0x0087ff, + 0x00af00, 0x00af5f, 0x00af87, 0x00afaf, 0x00afd7, 0x00afff, + 0x00d700, 0x00d75f, 0x00d787, 0x00d7af, 0x00d7d7, 0x00d7ff, + 0x00ff00, 0x00ff5f, 0x00ff87, 0x00ffaf, 0x00ffd7, 0x00ffff, + + 0x5f0000, 0x5f005f, 0x5f0087, 0x5f00af, 0x5f00d7, 0x5f00ff, + 0x5f5f00, 0x5f5f5f, 0x5f5f87, 0x5f5faf, 0x5f5fd7, 0x5f5fff, + 0x5f8700, 0x5f875f, 0x5f8787, 0x5f87af, 0x5f87d7, 0x5f87ff, + 0x5faf00, 0x5faf5f, 0x5faf87, 0x5fafaf, 0x5fafd7, 0x5fafff, + 0x5fd700, 0x5fd75f, 0x5fd787, 0x5fd7af, 0x5fd7d7, 0x5fd7ff, + 0x5fff00, 0x5fff5f, 0x5fff87, 0x5fffaf, 0x5fffd7, 0x5fffff, + + 0x870000, 0x87005f, 0x870087, 0x8700af, 0x8700d7, 0x8700ff, + 0x875f00, 0x875f5f, 0x875f87, 0x875faf, 0x875fd7, 0x875fff, + 0x878700, 0x87875f, 0x878787, 0x8787af, 0x8787d7, 0x8787ff, + 0x87af00, 0x87af5f, 0x87af87, 0x87afaf, 0x87afd7, 0x87afff, + 0x87d700, 0x87d75f, 0x87d787, 0x87d7af, 0x87d7d7, 0x87d7ff, + 0x87ff00, 0x87ff5f, 0x87ff87, 0x87ffaf, 0x87ffd7, 0x87ffff, + + 0xaf0000, 0xaf005f, 0xaf0087, 0xaf00af, 0xaf00d7, 0xaf00ff, + 0xaf5f00, 0xaf5f5f, 0xaf5f87, 0xaf5faf, 0xaf5fd7, 0xaf5fff, + 0xaf8700, 0xaf875f, 0xaf8787, 0xaf87af, 0xaf87d7, 0xaf87ff, + 0xafaf00, 0xafaf5f, 0xafaf87, 0xafafaf, 0xafafd7, 0xafafff, + 0xafd700, 0xafd75f, 0xafd787, 0xafd7af, 0xafd7d7, 0xafd7ff, + 0xafff00, 0xafff5f, 0xafff87, 0xafffaf, 0xafffd7, 0xafffff, + + 0xd70000, 0xd7005f, 0xd70087, 0xd700af, 0xd700d7, 0xd700ff, + 0xd75f00, 0xd75f5f, 0xd75f87, 0xd75faf, 0xd75fd7, 0xd75fff, + 0xd78700, 0xd7875f, 0xd78787, 0xd787af, 0xd787d7, 0xd787ff, + 0xd7af00, 0xd7af5f, 0xd7af87, 0xd7afaf, 0xd7afd7, 0xd7afff, + 0xd7d700, 0xd7d75f, 0xd7d787, 0xd7d7af, 0xd7d7d7, 0xd7d7ff, + 0xd7ff00, 0xd7ff5f, 0xd7ff87, 0xd7ffaf, 0xd7ffd7, 0xd7ffff, + + 0xff0000, 0xff005f, 0xff0087, 0xff00af, 0xff00d7, 0xff00ff, + 0xff5f00, 0xff5f5f, 0xff5f87, 0xff5faf, 0xff5fd7, 0xff5fff, + 0xff8700, 0xff875f, 0xff8787, 0xff87af, 0xff87d7, 0xff87ff, + 0xffaf00, 0xffaf5f, 0xffaf87, 0xffafaf, 0xffafd7, 0xffafff, + 0xffd700, 0xffd75f, 0xffd787, 0xffd7af, 0xffd7d7, 0xffd7ff, + 0xffff00, 0xffff5f, 0xffff87, 0xffffaf, 0xffffd7, 0xffffff, + + // 24 grey ramp 0x080808, 0x121212, 0x1c1c1c, 0x262626, 0x303030, 0x3a3a3a, 0x444444, 0x4e4e4e, 0x585858, 0x626262, 0x6c6c6c, 0x767676, 0x808080, 0x8a8a8a, 0x949494, 0x9e9e9e, 0xa8a8a8, 0xb2b2b2, 0xbcbcbc, 0xc6c6c6, 0xd0d0d0, 0xdadada, 0xe4e4e4, 0xeeeeee, }; + /** + * Default 88 colors palette + */ + public static final int[] DEFAULT_COLORS_88 = { + // 16 ansi + 0x000000, 0x800000, 0x008000, 0x808000, 0x000080, 0x800080, 0x008080, 0xc0c0c0, + 0x808080, 0xff0000, 0x00ff00, 0xffff00, 0x0000ff, 0xff00ff, 0x00ffff, 0xffffff, + + // 4x4x4 color cube + 0x000000, 0x00008b, 0x0000cd, 0x0000ff, + 0x008b00, 0x008b8b, 0x008bcd, 0x008bff, + 0x00cd00, 0x00cd8b, 0x00cdcd, 0x00cdff, + 0x00ff00, 0x00ff8b, 0x00ffcd, 0x00ffff, + + 0x8b0000, 0x8b008b, 0x8b00cd, 0x8b00ff, + 0x8b8b00, 0x8b8b8b, 0x8b8bcd, 0x8b8bff, + 0x8bcd00, 0x8bcd8b, 0x8bcdcd, 0x8bcdff, + 0x8bff00, 0x8bff8b, 0x8bffcd, 0x8bffff, + + 0xcd0000, 0xcd008b, 0xcd00cd, 0xcd00ff, + 0xcd8b00, 0xcd8b8b, 0xcd8bcd, 0xcd8bff, + 0xcdcd00, 0xcdcd8b, 0xcdcdcd, 0xcdcdff, + 0xcdff00, 0xcdff8b, 0xcdffcd, 0xcdffff, + + 0xff0000, 0xff008b, 0xff00cd, 0xff00ff, + 0xff8b00, 0xff8b8b, 0xff8bcd, 0xff8bff, + 0xffcd00, 0xffcd8b, 0xffcdcd, 0xffcdff, + 0xffff00, 0xffff8b, 0xffffcd, 0xffffff, + + // 8 grey ramp + 0x2e2e2e, 0x5c5c5c, 0x737373, 0x8b8b8b, 0xa2a2a2, 0xb9b9b9, 0xd0d0d0, 0xe7e7e7, + }; + /** D50 illuminant for CAM color spaces */ public static final double[] D50 = new double[] { 96.422f, 100.0f, 82.521f }; /** D65 illuminant for CAM color spaces */ @@ -74,11 +124,11 @@ public class Colors { public static final double[] darkSurrounding = new double[] { 0.8, 0.525, 0.8 }; /** sRGB encoding environment */ - public static final double[] sRGB_encoding_environment = vc(D50, 64.0, 64/5, dimSurrounding); + public static final double[] sRGB_encoding_environment = vc(D50, 64.0, 64.0/5, dimSurrounding); /** sRGB typical environment */ - public static final double[] sRGB_typical_environment = vc(D50, 200.0, 200/5, averageSurrounding); + public static final double[] sRGB_typical_environment = vc(D50, 200.0, 200.0/5, averageSurrounding); /** Adobe RGB environment */ - public static final double[] AdobeRGB_environment = vc(D65, 160.0, 160/5, averageSurrounding); + public static final double[] AdobeRGB_environment = vc(D65, 160.0, 160.0/5, averageSurrounding); private static int[] COLORS_256 = DEFAULT_COLORS_256; @@ -130,15 +180,16 @@ public class Colors { return roundColor((r << 16) + (g << 8) + b, COLORS_256, max, (String) null); } - private static int roundColor(int color, int[] colors, int max, String dist) { + static int roundColor(int color, int[] colors, int max, String dist) { return roundColor(color, colors, max, getDistance(dist)); } - private interface Distance { + @FunctionalInterface + interface Distance { double compute(int c1, int c2); } - private static int roundColor(int color, int[] colors, int max, Distance distance) { + static int roundColor(int color, int[] colors, int max, Distance distance) { double best_distance = Integer.MAX_VALUE; int best_index = Integer.MAX_VALUE; for (int idx = 0; idx < max; idx++) { @@ -151,7 +202,7 @@ public class Colors { return best_index; } - private static Distance getDistance(String dist) { + static Distance getDistance(String dist) { if (dist == null) { dist = System.getProperty(PROP_COLOR_DISTANCE, "cie76"); } diff --git a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/Curses.java b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/Curses.java index b07ceacd59e..4589c6b79bd 100644 --- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/Curses.java +++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/Curses.java @@ -352,11 +352,82 @@ public final class Curses { out.append(Integer.toString(toInteger(stack.pop()))); break; default: - throw new UnsupportedOperationException(); + if (ch == ':') { + ch = str.charAt(index++); + } + boolean alternate = false; + boolean left = false; + boolean space = false; + boolean plus = false; + int width = 0; + int prec = -1; + int cnv; + while ("-+# ".indexOf(ch) >= 0) { + switch (ch) { + case '-': left = true; break; + case '+': plus = true; break; + case '#': alternate = true; break; + case ' ': space = true; break; + } + ch = str.charAt(index++); + } + if ("123456789".indexOf(ch) >= 0) { + do { + width = width * 10 + (ch - '0'); + ch = str.charAt(index++); + } while ("0123456789".indexOf(ch) >= 0); + } + if (ch == '.') { + prec = 0; + ch = str.charAt(index++); + } + if ("0123456789".indexOf(ch) >= 0) { + do { + prec = prec * 10 + (ch - '0'); + ch = str.charAt(index++); + } while ("0123456789".indexOf(ch) >= 0); + } + if ("cdoxXs".indexOf(ch) < 0) { + throw new IllegalArgumentException(); + } + cnv = ch; + if (exec) { + String res; + if (cnv == 's') { + res = (String) stack.pop(); + if (prec >= 0) { + res = res.substring(0, prec); + } + } else { + int p = toInteger(stack.pop()); + StringBuilder fmt = new StringBuilder(16); + fmt.append('%'); + if (alternate) { + fmt.append('#'); + } + if (plus) { + fmt.append('+'); + } + if (space) { + fmt.append(' '); + } + if (prec >= 0) { + fmt.append('0'); + fmt.append(prec); + } + fmt.append((char) cnv); + res = String.format(fmt.toString(), p); + } + if (width > res.length()) { + res = String.format("%" + (left ? "-" : "") + width + "s", res); + } + out.append(res); + } + break; } break; case '$': - if (str.charAt(index) == '<') { + if (index < length && str.charAt(index) == '<') { // We don't honour delays, just skip int nb = 0; while ((ch = str.charAt(++index)) != '>') { diff --git a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/Display.java b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/Display.java index aa7425ce175..61e0736b5b4 100644 --- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/Display.java +++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/Display.java @@ -72,6 +72,10 @@ public class Display { public void setDelayLineWrap(boolean v) { delayLineWrap = v; } public void resize(int rows, int columns) { + if (rows == 0 || columns == 0) { + columns = Integer.MAX_VALUE - 1; + rows = 1; + } if (this.rows != rows || this.columns != columns) { this.rows = rows; this.columns = columns; diff --git a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/InfoCmp.java b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/InfoCmp.java index 8744a931caf..68f77f638b7 100644 --- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/InfoCmp.java +++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/InfoCmp.java @@ -619,7 +619,7 @@ public final class InfoCmp { static { for (String s : Arrays.asList("dumb", "dumb-color", "ansi", "xterm", "xterm-256color", "windows", "windows-256color", "windows-conemu", "windows-vtp", - "screen", "screen-256color")) { + "screen", "screen-256color", "rxvt-unicode", "rxvt-unicode-256color", "rxvt-basic", "rxvt")) { setDefaultInfoCmp(s, () -> loadDefaultInfoCmp(s)); } } diff --git a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/Log.java b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/Log.java index 1f5f7cf7dd3..91f18755e25 100644 --- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/Log.java +++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/Log.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002-2016, the original author or authors. + * Copyright (c) 2002-2020, the original author or authors. * * This software is distributable under the BSD license. See the terms of the * BSD license in the documentation provided with this software. @@ -22,8 +22,9 @@ import java.util.function.Supplier; * @author Guillaume Nodet * @since 2.0 */ -public final class Log -{ +public final class Log { +// private static final Logger logger = Logger.getLogger("org.jline"); + public static void trace(final Object... messages) { // log(Level.FINEST, messages); } @@ -110,7 +111,6 @@ public final class Log // } // // static void logr(final Level level, final Supplier record) { -// Logger logger = Logger.getLogger("org.jline"); // if (logger.isLoggable(level)) { // // inform record of the logger-name // LogRecord tmp = record.get(); @@ -120,7 +120,6 @@ public final class Log // } // // static boolean isEnabled(Level level) { -// Logger logger = Logger.getLogger("org.jline"); // return logger.isLoggable(level); // } diff --git a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/NonBlockingPumpInputStream.java b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/NonBlockingPumpInputStream.java index 311b4c796b3..a48be007e24 100644 --- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/NonBlockingPumpInputStream.java +++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/NonBlockingPumpInputStream.java @@ -106,6 +106,20 @@ public class NonBlockingPumpInputStream extends NonBlockingInputStream { return res; } + @Override + public synchronized int readBuffered(byte[] b) throws IOException { + checkIoException(); + int res = wait(readBuffer, 0L); + if (res >= 0) { + res = 0; + while (res < b.length && readBuffer.hasRemaining()) { + b[res++] = (byte) (readBuffer.get() & 0x00FF); + } + } + rewind(readBuffer, writeBuffer); + return res; + } + public synchronized void setIoException(IOException exception) { this.ioException = exception; notifyAll(); diff --git a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/NonBlockingPumpReader.java b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/NonBlockingPumpReader.java index 4c3bcbad07c..5f152c16e64 100644 --- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/NonBlockingPumpReader.java +++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/NonBlockingPumpReader.java @@ -74,7 +74,11 @@ public class NonBlockingPumpReader extends NonBlockingReader { // Blocks until more input is available or the reader is closed. if (!closed && count == 0) { try { - notEmpty.await(timeout, TimeUnit.MILLISECONDS); + if (timeout > 0L) { + notEmpty.await(timeout, TimeUnit.MILLISECONDS); + } else { + notEmpty.await(); + } } catch (InterruptedException e) { throw (IOException) new InterruptedIOException().initCause(e); } 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 642bcbabb59..fa40360a689 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 @@ -183,7 +183,7 @@ public class PumpReader extends Reader { } @Override - public int read(CharBuffer target) throws IOException { + public synchronized int read(CharBuffer target) throws IOException { if (!target.hasRemaining()) { return 0; } diff --git a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/Signals.java b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/Signals.java index 9c6a1c55285..b94f1fa318e 100644 --- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/Signals.java +++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/Signals.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002-2016, the original author or authors. + * Copyright (c) 2002-2020, the original author or authors. * * This software is distributable under the BSD license. See the terms of the * BSD license in the documentation provided with this software. @@ -9,6 +9,7 @@ package jdk.internal.org.jline.utils; import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Proxy; import java.util.Objects; @@ -91,8 +92,12 @@ public final class Signals { Object signal; try { signal = constructor.newInstance(name); - } catch (IllegalArgumentException e) { - Log.trace(() -> "Ignoring unsupported signal " + name); + } catch (InvocationTargetException e) { + if (e.getCause() instanceof IllegalArgumentException) { + Log.trace(() -> "Ignoring unsupported signal " + name); + } else { + Log.debug("Error registering handler for signal ", name, e); + } return null; } Class signalHandlerClass = Class.forName("sun.misc.SignalHandler"); diff --git a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/StyleResolver.java b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/StyleResolver.java index a12a09889a5..f2cc61e80a5 100644 --- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/StyleResolver.java +++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/StyleResolver.java @@ -32,6 +32,38 @@ public class StyleResolver { this.source = requireNonNull(source); } + /** + * Returns the RGB color for the given name. + *

      + * Bright color can be specified with: {@code !} or {@code bright-}. + *

      + * Full xterm256 color can be specified with: {@code ~}. + * RGB colors can be specified with: {@code x} or {@code #} where {@code rgb} is + * a 24 bits hexadecimal color. + * + * @param name the name of the color + * @return color code, or {@code null} if unable to determine. + */ + private static Integer colorRgb(String name) { + name = name.toLowerCase(Locale.US); + // check hexadecimal color + if (name.charAt(0) == 'x' || name.charAt(0) == '#') { + try { + return Integer.parseInt(name.substring(1), 16); + } catch (NumberFormatException e) { +// log.warning("Invalid hexadecimal color: " + name); + return null; + } + } else { + // load indexed color + Integer color = color(name); + if (color != null && color != -1) { + color = Colors.DEFAULT_COLORS_256[color]; + } + return color; + } + } + /** * Returns the color identifier for the given name. *

      @@ -44,21 +76,20 @@ public class StyleResolver { */ private static Integer color(String name) { int flags = 0; - name = name.toLowerCase(Locale.US); + if (name.equals("default")) { + return -1; + } // extract bright flag from color name - if (name.charAt(0) == '!') { - name = name.substring(1, name.length()); + else if (name.charAt(0) == '!') { + name = name.substring(1); flags = BRIGHT; } else if (name.startsWith("bright-")) { - name = name.substring(7, name.length()); + name = name.substring(7); flags = BRIGHT; } else if (name.charAt(0) == '~') { + name = name.substring(1); try { - // TODO: if the palette is not the default one, should be - // TODO: translate into 24-bits first and let the #toAnsi() call - // TODO: round with the current palette ? - name = name.substring(1, name.length()); return Colors.rgbColor(name); } catch (IllegalArgumentException e) { // log.warning("Invalid style-color name: " + name); @@ -297,25 +328,51 @@ public class StyleResolver { String colorName = parts[1].trim(); // resolve the color-name - Integer color = color(colorName); - if (color == null) { -// log.warning("Invalid color-name: " + colorName); - } else { - // resolve and apply color-mode - switch (colorMode.toLowerCase(Locale.US)) { - case "foreground": - case "fg": - case "f": - return style.foreground(color); - - case "background": - case "bg": - case "b": - return style.background(color); - - default: -// log.warning("Invalid color-mode: " + colorMode); - } + Integer color; + // resolve and apply color-mode + switch (colorMode.toLowerCase(Locale.US)) { + case "foreground": + case "fg": + case "f": + color = color(colorName); + if (color == null) { +// log.warning("Invalid color-name: " + colorName); + break; + } + return color >= 0 ? style.foreground(color) : style.foregroundDefault(); + + case "background": + case "bg": + case "b": + color = color(colorName); + if (color == null) { +// log.warning("Invalid color-name: " + colorName); + break; + } + return color >= 0 ? style.background(color) : style.backgroundDefault(); + + case "foreground-rgb": + case "fg-rgb": + case "f-rgb": + color = colorRgb(colorName); + if (color == null) { +// log.warning("Invalid color-name: " + colorName); + break; + } + return color >= 0 ? style.foregroundRgb(color) : style.foregroundDefault(); + + case "background-rgb": + case "bg-rgb": + case "b-rgb": + color = colorRgb(colorName); + if (color == null) { +// log.warning("Invalid color-name: " + colorName); + break; + } + return color >= 0 ? style.backgroundRgb(color) : style.backgroundDefault(); + + default: +// log.warning("Invalid color-mode: " + colorMode); } return style; } diff --git a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/rxvt-basic.caps b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/rxvt-basic.caps new file mode 100644 index 00000000000..c00219cfbf9 --- /dev/null +++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/rxvt-basic.caps @@ -0,0 +1,41 @@ +# Reconstructed via infocmp from file: /lib/terminfo/r/rxvt-basic +rxvt-basic|rxvt-m|rxvt terminal base (X Window System), + am, bce, eo, km, mir, msgr, xenl, xon, + cols#80, it#8, lines#24, + acsc=``aaffggjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~, + bel=^G, blink=\E[5m, bold=\E[1m, civis=\E[?25l, + clear=\E[H\E[2J, cnorm=\E[?25h, cr=\r, + csr=\E[%i%p1%d;%p2%dr, cub=\E[%p1%dD, cub1=^H, + cud=\E[%p1%dB, cud1=\n, cuf=\E[%p1%dC, cuf1=\E[C, + cup=\E[%i%p1%d;%p2%dH, cuu=\E[%p1%dA, cuu1=\E[A, + dl=\E[%p1%dM, dl1=\E[M, ed=\E[J, el=\E[K, el1=\E[1K, + enacs=\E(B\E)0, flash=\E[?5h\E[?5l, home=\E[H, + hpa=\E[%i%p1%dG, ht=^I, hts=\EH, ich=\E[%p1%d@, ich1=\E[@, + il=\E[%p1%dL, il1=\E[L, ind=\n, is1=\E[?47l\E=\E[?1l, + is2=\E[r\E[m\E[2J\E[H\E[?7h\E[?1;3;4;6l\E[4l, + kDC=\E[3$, kEND=\E[8$, kHOM=\E[7$, kLFT=\E[d, kNXT=\E[6$, + kPRV=\E[5$, kRIT=\E[c, ka1=\EOw, ka3=\EOy, kb2=\EOu, kbs=^?, + kc1=\EOq, kc3=\EOs, kcbt=\E[Z, kcub1=\E[D, kcud1=\E[B, + kcuf1=\E[C, kcuu1=\E[A, kdch1=\E[3~, kel=\E[8\^, + kend=\E[8~, kent=\EOM, kf1=\E[11~, kf10=\E[21~, + kf11=\E[23~, kf12=\E[24~, kf13=\E[25~, kf14=\E[26~, + kf15=\E[28~, kf16=\E[29~, kf17=\E[31~, kf18=\E[32~, + kf19=\E[33~, kf2=\E[12~, kf20=\E[34~, kf21=\E[23$, + kf22=\E[24$, kf23=\E[11\^, kf24=\E[12\^, kf25=\E[13\^, + kf26=\E[14\^, kf27=\E[15\^, kf28=\E[17\^, kf29=\E[18\^, + kf3=\E[13~, kf30=\E[19\^, kf31=\E[20\^, kf32=\E[21\^, + kf33=\E[23\^, kf34=\E[24\^, kf35=\E[25\^, kf36=\E[26\^, + kf37=\E[28\^, kf38=\E[29\^, kf39=\E[31\^, kf4=\E[14~, + kf40=\E[32\^, kf41=\E[33\^, kf42=\E[34\^, kf43=\E[23@, + kf44=\E[24@, kf5=\E[15~, kf6=\E[17~, kf7=\E[18~, + kf8=\E[19~, kf9=\E[20~, kfnd=\E[1~, khome=\E[7~, + kich1=\E[2~, kmous=\E[M, knp=\E[6~, kpp=\E[5~, kslt=\E[4~, + rc=\E8, rev=\E[7m, ri=\EM, rmacs=^O, rmcup=\E[2J\E[?47l\E8, + rmir=\E[4l, rmkx=\E>, rmso=\E[27m, rmul=\E[24m, + rs1=\E>\E[1;3;4;5;6l\E[?7h\E[m\E[r\E[2J\E[H, + rs2=\E[r\E[m\E[2J\E[H\E[?7h\E[?1;3;4;6l\E[4l\E=\E[?1000l\E[?25h, + s0ds=\E(B, s1ds=\E(0, sc=\E7, + sgr=\E[0%?%p6%t;1%;%?%p2%t;4%;%?%p1%p3%|%t;7%;%?%p4%t;5%;m%?%p9%t\016%e\017%;, + sgr0=\E[0m\017, smacs=^N, smcup=\E7\E[?47h, smir=\E[4h, + smkx=\E=, smso=\E[7m, smul=\E[4m, tbc=\E[3g, + vpa=\E[%i%p1%dd, diff --git a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/rxvt-unicode-256color.caps b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/rxvt-unicode-256color.caps new file mode 100644 index 00000000000..fdaaadb2fb5 --- /dev/null +++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/rxvt-unicode-256color.caps @@ -0,0 +1,44 @@ +# Reconstructed via infocmp from file: /lib/terminfo/r/rxvt-unicode-256color +rxvt-unicode-256color|rxvt-unicode terminal with 256 colors (X Window System), + am, bce, bw, ccc, eo, hs, km, mc5i, mir, msgr, npc, xenl, xon, + btns#5, colors#0x100, cols#80, it#8, lines#24, lm#0, ncv#0, + pairs#0x7fff, + acsc=+C\,D-A.B0E``aaffgghFiGjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~, + bel=^G, blink=\E[5m, bold=\E[1m, civis=\E[?25l, + clear=\E[H\E[2J, cnorm=\E[?12l\E[?25h, cr=\r, + csr=\E[%i%p1%d;%p2%dr, cub=\E[%p1%dD, cub1=^H, + cud=\E[%p1%dB, cud1=\n, cuf=\E[%p1%dC, cuf1=\E[C, + cup=\E[%i%p1%d;%p2%dH, cuu=\E[%p1%dA, cuu1=\E[A, + cvvis=\E[?12;25h, dch=\E[%p1%dP, dch1=\E[P, dl=\E[%p1%dM, + dl1=\E[M, dsl=\E]2;\007, ech=\E[%p1%dX, ed=\E[J, el=\E[K, + el1=\E[1K, enacs=, flash=\E[?5h$<20/>\E[?5l, fsl=^G, + home=\E[H, hpa=\E[%i%p1%dG, ht=^I, hts=\EH, ich=\E[%p1%d@, + ich1=\E[@, il=\E[%p1%dL, il1=\E[L, ind=\n, indn=\E[%p1%dS, + initc=\E]4;%p1%d;rgb\:%p2%{65535}%*%{1000}%/%4.4X/%p3%{65535}%*%{1000}%/%4.4X/%p4%{65535}%*%{1000}%/%4.4X\E\\, + is1=\E[!p, + is2=\E[r\E[m\E[2J\E[?7;25h\E[?1;3;4;5;6;9;66;1000;1001;1049l\E[4l, + kDC=\E[3$, kEND=\E[8$, kFND=\E[1$, kHOM=\E[7$, kIC=\E[2$, + kLFT=\E[d, kNXT=\E[6$, kPRV=\E[5$, kRIT=\E[c, ka1=\EOw, + ka3=\EOy, kb2=\EOu, kbs=^?, kc1=\EOq, kc3=\EOs, kcbt=\E[Z, + kcub1=\E[D, kcud1=\E[B, kcuf1=\E[C, kcuu1=\E[A, + kdch1=\E[3~, kel=\E[8\^, kend=\E[8~, kent=\EOM, kf1=\E[11~, + kf10=\E[21~, kf11=\E[23~, kf12=\E[24~, kf13=\E[25~, + kf14=\E[26~, kf15=\E[28~, kf16=\E[29~, kf17=\E[31~, + kf18=\E[32~, kf19=\E[33~, kf2=\E[12~, kf20=\E[34~, + kf3=\E[13~, kf4=\E[14~, kf5=\E[15~, kf6=\E[17~, kf7=\E[18~, + kf8=\E[19~, kf9=\E[20~, kfnd=\E[1~, khome=\E[7~, + kich1=\E[2~, kmous=\E[M, knp=\E[6~, kpp=\E[5~, kslt=\E[4~, + mc0=\E[i, mc4=\E[4i, mc5=\E[5i, op=\E[39;49m, rc=\E8, + rev=\E[7m, ri=\EM, rin=\E[%p1%dT, ritm=\E[23m, rmacs=\E(B, + rmam=\E[?7l, rmcup=\E[r\E[?1049l, rmir=\E[4l, rmkx=\E>, + rmso=\E[27m, rmul=\E[24m, rs1=\Ec, + rs2=\E[r\E[m\E[?7;25h\E[?1;3;4;5;6;9;66;1000;1001;1049l\E[4l, + s0ds=\E(B, s1ds=\E(0, s2ds=\E*B, s3ds=\E+B, sc=\E7, + setab=\E[48;5;%p1%dm, setaf=\E[38;5;%p1%dm, + setb=%?%p1%{7}%>%t\E[48;5;%p1%dm%e\E[4%?%p1%{1}%=%t4%e%p1%{3}%=%t6%e%p1%{4}%=%t1%e%p1%{6}%=%t3%e%p1%d%;m%;, + setf=%?%p1%{7}%>%t\E[38;5;%p1%dm%e\E[3%?%p1%{1}%=%t4%e%p1%{3}%=%t6%e%p1%{4}%=%t1%e%p1%{6}%=%t3%e%p1%d%;m%;, + sgr=\E[%?%p6%t;1%;%?%p2%t;4%;%?%p1%p3%|%t;7%;%?%p4%t;5%;%?%p7%t;8%;m%?%p9%t\E(0%e\E(B%;, + sgr0=\E[m\E(B, sitm=\E[3m, smacs=\E(0, smam=\E[?7h, + smcup=\E[?1049h, smir=\E[4h, smkx=\E=, smso=\E[7m, + smul=\E[4m, tbc=\E[3g, tsl=\E]2;, u6=\E[%i%d;%dR, u7=\E[6n, + u8=\E[?1;2c, u9=\E[c, vpa=\E[%i%p1%dd, diff --git a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/rxvt-unicode.caps b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/rxvt-unicode.caps new file mode 100644 index 00000000000..3ff3455e253 --- /dev/null +++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/rxvt-unicode.caps @@ -0,0 +1,44 @@ +# Reconstructed via infocmp from file: /lib/terminfo/r/rxvt-unicode +rxvt-unicode|rxvt-unicode terminal (X Window System), + am, bce, bw, ccc, eo, hs, km, mc5i, mir, msgr, npc, xenl, xon, + btns#5, colors#88, cols#80, it#8, lines#24, lm#0, ncv#0, + pairs#7744, + acsc=+C\,D-A.B0E``aaffgghFiGjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~, + bel=^G, blink=\E[5m, bold=\E[1m, civis=\E[?25l, + clear=\E[H\E[2J, cnorm=\E[?12l\E[?25h, cr=\r, + csr=\E[%i%p1%d;%p2%dr, cub=\E[%p1%dD, cub1=^H, + cud=\E[%p1%dB, cud1=\n, cuf=\E[%p1%dC, cuf1=\E[C, + cup=\E[%i%p1%d;%p2%dH, cuu=\E[%p1%dA, cuu1=\E[A, + cvvis=\E[?12;25h, dch=\E[%p1%dP, dch1=\E[P, dl=\E[%p1%dM, + dl1=\E[M, dsl=\E]2;\007, ech=\E[%p1%dX, ed=\E[J, el=\E[K, + el1=\E[1K, enacs=, flash=\E[?5h$<20/>\E[?5l, fsl=^G, + home=\E[H, hpa=\E[%i%p1%dG, ht=^I, hts=\EH, ich=\E[%p1%d@, + ich1=\E[@, il=\E[%p1%dL, il1=\E[L, ind=\n, indn=\E[%p1%dS, + initc=\E]4;%p1%d;rgb\:%p2%{65535}%*%{1000}%/%4.4X/%p3%{65535}%*%{1000}%/%4.4X/%p4%{65535}%*%{1000}%/%4.4X\E\\, + is1=\E[!p, + is2=\E[r\E[m\E[2J\E[?7;25h\E[?1;3;4;5;6;9;66;1000;1001;1049l\E[4l, + kDC=\E[3$, kEND=\E[8$, kFND=\E[1$, kHOM=\E[7$, kIC=\E[2$, + kLFT=\E[d, kNXT=\E[6$, kPRV=\E[5$, kRIT=\E[c, ka1=\EOw, + ka3=\EOy, kb2=\EOu, kbs=^?, kc1=\EOq, kc3=\EOs, kcbt=\E[Z, + kcub1=\E[D, kcud1=\E[B, kcuf1=\E[C, kcuu1=\E[A, + kdch1=\E[3~, kel=\E[8\^, kend=\E[8~, kent=\EOM, kf1=\E[11~, + kf10=\E[21~, kf11=\E[23~, kf12=\E[24~, kf13=\E[25~, + kf14=\E[26~, kf15=\E[28~, kf16=\E[29~, kf17=\E[31~, + kf18=\E[32~, kf19=\E[33~, kf2=\E[12~, kf20=\E[34~, + kf3=\E[13~, kf4=\E[14~, kf5=\E[15~, kf6=\E[17~, kf7=\E[18~, + kf8=\E[19~, kf9=\E[20~, kfnd=\E[1~, khome=\E[7~, + kich1=\E[2~, kmous=\E[M, knp=\E[6~, kpp=\E[5~, kslt=\E[4~, + mc0=\E[i, mc4=\E[4i, mc5=\E[5i, op=\E[39;49m, rc=\E8, + rev=\E[7m, ri=\EM, rin=\E[%p1%dT, ritm=\E[23m, rmacs=\E(B, + rmam=\E[?7l, rmcup=\E[r\E[?1049l, rmir=\E[4l, rmkx=\E>, + rmso=\E[27m, rmul=\E[24m, rs1=\Ec, + rs2=\E[r\E[m\E[?7;25h\E[?1;3;4;5;6;9;66;1000;1001;1049l\E[4l, + s0ds=\E(B, s1ds=\E(0, s2ds=\E*B, s3ds=\E+B, sc=\E7, + setab=\E[48;5;%p1%dm, setaf=\E[38;5;%p1%dm, + setb=%?%p1%{7}%>%t\E[48;5;%p1%dm%e\E[4%?%p1%{1}%=%t4%e%p1%{3}%=%t6%e%p1%{4}%=%t1%e%p1%{6}%=%t3%e%p1%d%;m%;, + setf=%?%p1%{7}%>%t\E[38;5;%p1%dm%e\E[3%?%p1%{1}%=%t4%e%p1%{3}%=%t6%e%p1%{4}%=%t1%e%p1%{6}%=%t3%e%p1%d%;m%;, + sgr=\E[%?%p6%t;1%;%?%p2%t;4%;%?%p1%p3%|%t;7%;%?%p4%t;5%;%?%p7%t;8%;m%?%p9%t\E(0%e\E(B%;, + sgr0=\E[m\E(B, sitm=\E[3m, smacs=\E(0, smam=\E[?7h, + smcup=\E[?1049h, smir=\E[4h, smkx=\E=, smso=\E[7m, + smul=\E[4m, tbc=\E[3g, tsl=\E]2;, u6=\E[%i%d;%dR, u7=\E[6n, + u8=\E[?1;2c, u9=\E[c, vpa=\E[%i%p1%dd, diff --git a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/rxvt.caps b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/rxvt.caps new file mode 100644 index 00000000000..3c266218d09 --- /dev/null +++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/rxvt.caps @@ -0,0 +1,43 @@ +# Reconstructed via infocmp from file: /lib/terminfo/r/rxvt +rxvt|rxvt terminal emulator (X Window System), + am, bce, eo, km, mir, msgr, xenl, xon, + colors#8, cols#80, it#8, lines#24, ncv@, pairs#64, + acsc=``aaffggjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~, + bel=^G, blink=\E[5m, bold=\E[1m, civis=\E[?25l, + clear=\E[H\E[2J, cnorm=\E[?25h, cr=\r, + csr=\E[%i%p1%d;%p2%dr, cub=\E[%p1%dD, cub1=^H, + cud=\E[%p1%dB, cud1=\n, cuf=\E[%p1%dC, cuf1=\E[C, + cup=\E[%i%p1%d;%p2%dH, cuu=\E[%p1%dA, cuu1=\E[A, + dl=\E[%p1%dM, dl1=\E[M, ed=\E[J, el=\E[K, el1=\E[1K, + enacs=\E(B\E)0, flash=\E[?5h\E[?5l, home=\E[H, + hpa=\E[%i%p1%dG, ht=^I, hts=\EH, ich=\E[%p1%d@, ich1=\E[@, + il=\E[%p1%dL, il1=\E[L, ind=\n, is1=\E[?47l\E=\E[?1l, + is2=\E[r\E[m\E[2J\E[H\E[?7h\E[?1;3;4;6l\E[4l, + kDC=\E[3$, kEND=\E[8$, kHOM=\E[7$, kLFT=\E[d, kNXT=\E[6$, + kPRV=\E[5$, kRIT=\E[c, ka1=\EOw, ka3=\EOy, kb2=\EOu, kbs=^?, + kc1=\EOq, kc3=\EOs, kcbt=\E[Z, kcub1=\E[D, kcud1=\E[B, + kcuf1=\E[C, kcuu1=\E[A, kdch1=\E[3~, kel=\E[8\^, + kend=\E[8~, kent=\EOM, kf1=\E[11~, kf10=\E[21~, + kf11=\E[23~, kf12=\E[24~, kf13=\E[25~, kf14=\E[26~, + kf15=\E[28~, kf16=\E[29~, kf17=\E[31~, kf18=\E[32~, + kf19=\E[33~, kf2=\E[12~, kf20=\E[34~, kf21=\E[23$, + kf22=\E[24$, kf23=\E[11\^, kf24=\E[12\^, kf25=\E[13\^, + kf26=\E[14\^, kf27=\E[15\^, kf28=\E[17\^, kf29=\E[18\^, + kf3=\E[13~, kf30=\E[19\^, kf31=\E[20\^, kf32=\E[21\^, + kf33=\E[23\^, kf34=\E[24\^, kf35=\E[25\^, kf36=\E[26\^, + kf37=\E[28\^, kf38=\E[29\^, kf39=\E[31\^, kf4=\E[14~, + kf40=\E[32\^, kf41=\E[33\^, kf42=\E[34\^, kf43=\E[23@, + kf44=\E[24@, kf5=\E[15~, kf6=\E[17~, kf7=\E[18~, + kf8=\E[19~, kf9=\E[20~, kfnd=\E[1~, khome=\E[7~, + kich1=\E[2~, kmous=\E[M, knp=\E[6~, kpp=\E[5~, kslt=\E[4~, + op=\E[39;49m, rc=\E8, rev=\E[7m, ri=\EM, rmacs=^O, + rmcup=\E[2J\E[?47l\E8, rmir=\E[4l, rmkx=\E>, rmso=\E[27m, + rmul=\E[24m, + rs1=\E>\E[1;3;4;5;6l\E[?7h\E[m\E[r\E[2J\E[H, + rs2=\E[r\E[m\E[2J\E[H\E[?7h\E[?1;3;4;6l\E[4l\E=\E[?1000l\E[?25h, + s0ds=\E(B, s1ds=\E(0, sc=\E7, setab=\E[4%p1%dm, + setaf=\E[3%p1%dm, + sgr=\E[0%?%p6%t;1%;%?%p2%t;4%;%?%p1%p3%|%t;7%;%?%p4%t;5%;m%?%p9%t\016%e\017%;, + sgr0=\E[m\017, smacs=^N, smcup=\E7\E[?47h, smir=\E[4h, + smkx=\E=, smso=\E[7m, smul=\E[4m, tbc=\E[3g, + vpa=\E[%i%p1%dd, diff --git a/src/jdk.internal.le/share/legal/jline.md b/src/jdk.internal.le/share/legal/jline.md index 86fad6f5f83..69e8ab745ab 100644 --- a/src/jdk.internal.le/share/legal/jline.md +++ b/src/jdk.internal.le/share/legal/jline.md @@ -1,4 +1,4 @@ -## JLine v3.14.0 +## JLine v3.20.0 ### JLine License

      diff --git a/src/jdk.internal.le/windows/classes/jdk/internal/org/jline/terminal/impl/jna/JnaSupportImpl.java b/src/jdk.internal.le/windows/classes/jdk/internal/org/jline/terminal/impl/jna/JnaSupportImpl.java
      index 7f4fa568a29..061952063cf 100644
      --- a/src/jdk.internal.le/windows/classes/jdk/internal/org/jline/terminal/impl/jna/JnaSupportImpl.java
      +++ b/src/jdk.internal.le/windows/classes/jdk/internal/org/jline/terminal/impl/jna/JnaSupportImpl.java
      @@ -14,6 +14,7 @@ import jdk.internal.org.jline.terminal.Terminal;
       import jdk.internal.org.jline.terminal.impl.jna.win.JnaWinSysTerminal;
       import jdk.internal.org.jline.terminal.spi.JnaSupport;
       import jdk.internal.org.jline.terminal.spi.Pty;
      +import jdk.internal.org.jline.utils.OSUtils;
       
       import java.io.IOException;
       import java.io.InputStream;
      @@ -47,4 +48,30 @@ public class JnaSupportImpl implements JnaSupport {
           public Terminal winSysTerminal(String name, String type, boolean ansiPassThrough, Charset encoding, int codepage, boolean nativeSignals, Terminal.SignalHandler signalHandler, boolean paused, Function inputStreamWrapper) throws IOException {
               return JnaWinSysTerminal.createTerminal(name, type, ansiPassThrough, encoding, codepage, nativeSignals, signalHandler, paused, inputStreamWrapper);
           }
      +
      +    @Override
      +    public boolean isWindowsConsole() {
      +        return JnaWinSysTerminal.isWindowsConsole();
      +    }
      +
      +    @Override
      +    public boolean isConsoleOutput() {
      +        if (OSUtils.IS_CYGWIN || OSUtils.IS_MSYSTEM) {
      +            throw new UnsupportedOperationException();
      +        } else if (OSUtils.IS_WINDOWS) {
      +            return JnaWinSysTerminal.isConsoleOutput();
      +        }
      +        throw new UnsupportedOperationException();
      +    }
      +
      +    @Override
      +    public boolean isConsoleInput() {
      +        if (OSUtils.IS_CYGWIN || OSUtils.IS_MSYSTEM) {
      +            throw new UnsupportedOperationException();
      +        } else if (OSUtils.IS_WINDOWS) {
      +            return JnaWinSysTerminal.isConsoleInput();
      +        }
      +        throw new UnsupportedOperationException();
      +    }
      +
       }
      diff --git a/src/jdk.internal.le/windows/classes/jdk/internal/org/jline/terminal/impl/jna/win/JnaWinSysTerminal.java b/src/jdk.internal.le/windows/classes/jdk/internal/org/jline/terminal/impl/jna/win/JnaWinSysTerminal.java
      index 83a2362fdd1..39e4d219f17 100644
      --- a/src/jdk.internal.le/windows/classes/jdk/internal/org/jline/terminal/impl/jna/win/JnaWinSysTerminal.java
      +++ b/src/jdk.internal.le/windows/classes/jdk/internal/org/jline/terminal/impl/jna/win/JnaWinSysTerminal.java
      @@ -70,16 +70,42 @@ public class JnaWinSysTerminal extends AbstractWindowsTerminal {
               return terminal;
           }
       
      +    public static boolean isWindowsConsole() {
      +        try {
      +            IntByReference mode = new IntByReference();
      +            Kernel32.INSTANCE.GetConsoleMode(consoleOut, mode);
      +            Kernel32.INSTANCE.GetConsoleMode(consoleIn, mode);
      +            return true;
      +        } catch (LastErrorException e) {
      +            return false;
      +        }
      +    }
      +
      +    public static boolean isConsoleOutput() {
      +        try {
      +            IntByReference mode = new IntByReference();
      +            Kernel32.INSTANCE.GetConsoleMode(consoleOut, mode);
      +            return true;
      +        } catch (LastErrorException e) {
      +            return false;
      +        }
      +    }
      +
      +    public static boolean isConsoleInput() {
      +        try {
      +            IntByReference mode = new IntByReference();
      +            Kernel32.INSTANCE.GetConsoleMode(consoleIn, mode);
      +            return true;
      +        } catch (LastErrorException e) {
      +            return false;
      +        }
      +    }
      +
           JnaWinSysTerminal(Writer writer, String name, String type, Charset encoding, int codepage, boolean nativeSignals, SignalHandler signalHandler, Function inputStreamWrapper) throws IOException {
               super(writer, name, type, encoding, codepage, nativeSignals, signalHandler, inputStreamWrapper);
               strings.put(InfoCmp.Capability.key_mouse, "\\E[M");
           }
       
      -    @Override
      -    protected int getConsoleOutputCP() {
      -        return Kernel32.INSTANCE.GetConsoleOutputCP();
      -    }
      -
           @Override
           protected int getConsoleMode() {
               IntByReference mode = new IntByReference();
      diff --git a/test/jdk/jdk/internal/jline/AbstractWindowsTerminalTest.java b/test/jdk/jdk/internal/jline/AbstractWindowsTerminalTest.java
      index 500ea5d2548..fa4f44162db 100644
      --- a/test/jdk/jdk/internal/jline/AbstractWindowsTerminalTest.java
      +++ b/test/jdk/jdk/internal/jline/AbstractWindowsTerminalTest.java
      @@ -1,5 +1,5 @@
       /*
      - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
      + * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved.
        * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
        *
        * This code is free software; you can redistribute it and/or modify it
      @@ -57,11 +57,6 @@ public class AbstractWindowsTerminalTest {
                   }
               };
               var t = new AbstractWindowsTerminal(out, "test", "vt100", null, -1, false, SignalHandler.SIG_DFL, isWrapper) {
      -            @Override
      -            protected int getConsoleOutputCP() {
      -                throw new UnsupportedOperationException("unexpected.");
      -            }
      -
                   @Override
                   protected int getConsoleMode() {
                       return -1;
      diff --git a/test/jdk/jdk/internal/jline/KeyConversionTest.java b/test/jdk/jdk/internal/jline/KeyConversionTest.java
      index e65e8765698..4eadb9a1bf3 100644
      --- a/test/jdk/jdk/internal/jline/KeyConversionTest.java
      +++ b/test/jdk/jdk/internal/jline/KeyConversionTest.java
      @@ -1,5 +1,5 @@
       /*
      - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
      + * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.
        * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
        *
        * This code is free software; you can redistribute it and/or modify it
      @@ -34,6 +34,7 @@ import java.io.StringWriter;
       import java.nio.charset.Charset;
       
       import jdk.internal.org.jline.terminal.Size;
      +import jdk.internal.org.jline.terminal.Terminal.SignalHandler;
       import jdk.internal.org.jline.terminal.impl.AbstractWindowsTerminal;
       
       public class KeyConversionTest {
      @@ -58,11 +59,7 @@ public class KeyConversionTest {
           void checkKeyConversion(KeyEvent event, String expected) throws IOException {
               StringBuilder result = new StringBuilder();
               new AbstractWindowsTerminal(new StringWriter(), "", "windows", Charset.forName("UTF-8"),
      -                                    0, true, null, in -> in) {
      -            @Override
      -            protected int getConsoleOutputCP() {
      -                throw new UnsupportedOperationException("Not supported yet.");
      -            }
      +                                    0, true, SignalHandler.SIG_DFL, in -> in) {
                   @Override
                   protected int getConsoleMode() {
                       return 0;
      -- 
      GitLab
      
      
      From 5ffb5d100f3383f9afaf20c8a659971522153505 Mon Sep 17 00:00:00 2001
      From: Andrey Turbanov 
      Date: Wed, 13 Oct 2021 11:34:24 +0000
      Subject: [PATCH 198/385] 8272992: Replace usages of Collections.sort with
       List.sort call in jdk.* modules
      
      Reviewed-by: cjplummer, prappo
      ---
       .../internal/doclets/formats/html/ClassUseWriter.java      | 4 +---
       .../jdk/javadoc/internal/doclets/toolkit/util/Group.java   | 6 +++---
       .../share/classes/sun/tools/jstat/JStatLogger.java         | 7 +++----
       src/jdk.jcmd/share/classes/sun/tools/jstat/Jstat.java      | 4 ++--
       .../sun/tools/jconsole/inspector/XOpenTypeViewer.java      | 4 ++--
       5 files changed, 11 insertions(+), 14 deletions(-)
      
      diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassUseWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassUseWriter.java
      index 83efb64ba4e..f91b06105a3 100644
      --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassUseWriter.java
      +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassUseWriter.java
      @@ -26,7 +26,6 @@
       package jdk.javadoc.internal.doclets.formats.html;
       
       import java.util.ArrayList;
      -import java.util.Collections;
       import java.util.HashMap;
       import java.util.List;
       import java.util.Map;
      @@ -44,7 +43,6 @@ import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
       import jdk.javadoc.internal.doclets.formats.html.markup.TagName;
       import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
       import jdk.javadoc.internal.doclets.formats.html.Navigation.PageMode;
      -import jdk.javadoc.internal.doclets.formats.html.markup.Text;
       import jdk.javadoc.internal.doclets.toolkit.Content;
       import jdk.javadoc.internal.doclets.toolkit.util.ClassTree;
       import jdk.javadoc.internal.doclets.toolkit.util.ClassUseMapper;
      @@ -178,7 +176,7 @@ public class ClassUseWriter extends SubWriterHolderWriter {
               Map> map = new HashMap<>();
               List elements = (List) classMap.get(typeElement);
               if (elements != null) {
      -            Collections.sort(elements, comparators.makeClassUseComparator());
      +            elements.sort(comparators.makeClassUseComparator());
                   for (Element e : elements) {
                       PackageElement pkg = utils.containingPackage(e);
                       pkgSet.add(pkg);
      diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Group.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Group.java
      index 0d8565a0f51..eee89265551 100644
      --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Group.java
      +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Group.java
      @@ -1,5 +1,5 @@
       /*
      - * Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved.
      + * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved.
        * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
        *
        * This code is free software; you can redistribute it and/or modify it
      @@ -147,7 +147,7 @@ public class Group {
                       elementNameGroupMap.put(mdlPattern, groupname);
                   }
               }
      -        Collections.sort(sortedRegExpList, new MapKeyComparator());
      +        sortedRegExpList.sort(new MapKeyComparator());
               return true;
           }
       
      @@ -193,7 +193,7 @@ public class Group {
                       elementNameGroupMap.put(pkgPattern, groupname);
                   }
               }
      -        Collections.sort(sortedRegExpList, new MapKeyComparator());
      +        sortedRegExpList.sort(new MapKeyComparator());
               return true;
           }
       
      diff --git a/src/jdk.jcmd/share/classes/sun/tools/jstat/JStatLogger.java b/src/jdk.jcmd/share/classes/sun/tools/jstat/JStatLogger.java
      index 4d08daa3ae3..ec2a2f1fdd3 100644
      --- a/src/jdk.jcmd/share/classes/sun/tools/jstat/JStatLogger.java
      +++ b/src/jdk.jcmd/share/classes/sun/tools/jstat/JStatLogger.java
      @@ -1,5 +1,5 @@
       /*
      - * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
      + * Copyright (c) 2004, 2021, Oracle and/or its affiliates. All rights reserved.
        * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
        *
        * This code is free software; you can redistribute it and/or modify it
      @@ -28,7 +28,6 @@ package sun.tools.jstat;
       import java.util.*;
       import java.io.*;
       import sun.jvmstat.monitor.*;
      -import sun.jvmstat.monitor.event.*;
       import java.util.regex.PatternSyntaxException;
       
       /**
      @@ -56,7 +55,7 @@ public class JStatLogger {
       
               // get the set of all monitors
               List items = monitoredVm.findByPattern(names);
      -        Collections.sort(items, comparator);
      +        items.sort(comparator);
       
               for (Monitor m: items) {
                   if (!(m.isSupported() || showUnsupported)) {
      @@ -76,7 +75,7 @@ public class JStatLogger {
       
               // get the set of all monitors
               List items = monitoredVm.findByPattern(names);
      -        Collections.sort(items, comparator);
      +        items.sort(comparator);
       
               printList(items, verbose, showUnsupported, out);
           }
      diff --git a/src/jdk.jcmd/share/classes/sun/tools/jstat/Jstat.java b/src/jdk.jcmd/share/classes/sun/tools/jstat/Jstat.java
      index 259ef107e93..0306dc6aaa9 100644
      --- a/src/jdk.jcmd/share/classes/sun/tools/jstat/Jstat.java
      +++ b/src/jdk.jcmd/share/classes/sun/tools/jstat/Jstat.java
      @@ -1,5 +1,5 @@
       /*
      - * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
      + * Copyright (c) 2004, 2021, Oracle and/or its affiliates. All rights reserved.
        * 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,7 +113,7 @@ public class Jstat {
                   formatter = new OptionOutputFormatter(monitoredVm, format);
               } else {
                   List logged = monitoredVm.findByPattern(arguments.counterNames());
      -            Collections.sort(logged, arguments.comparator());
      +            logged.sort(arguments.comparator());
                   List constants = new ArrayList();
       
                   for (Iterator i = logged.iterator(); i.hasNext(); /* empty */) {
      diff --git a/src/jdk.jconsole/share/classes/sun/tools/jconsole/inspector/XOpenTypeViewer.java b/src/jdk.jconsole/share/classes/sun/tools/jconsole/inspector/XOpenTypeViewer.java
      index 456ffce1408..0b85152b048 100644
      --- a/src/jdk.jconsole/share/classes/sun/tools/jconsole/inspector/XOpenTypeViewer.java
      +++ b/src/jdk.jconsole/share/classes/sun/tools/jconsole/inspector/XOpenTypeViewer.java
      @@ -1,5 +1,5 @@
       /*
      - * Copyright (c) 2004, 2014, Oracle and/or its affiliates. All rights reserved.
      + * Copyright (c) 2004, 2021, Oracle and/or its affiliates. All rights reserved.
        * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
        *
        * This code is free software; you can redistribute it and/or modify it
      @@ -281,7 +281,7 @@ public class XOpenTypeViewer extends JPanel implements ActionListener {
                       // Order tabular data elements using index names
                       List data = new ArrayList(
                               (Collection) tabular.values());
      -                Collections.sort(data, new TabularDataComparator(type));
      +                data.sort(new TabularDataComparator(type));
                       elements = data.toArray();
                       loadCompositeData((CompositeData) elements[0]);
                   } else {
      -- 
      GitLab
      
      
      From 451a296510994ff9fe1e0381900ffa9a8a1caa54 Mon Sep 17 00:00:00 2001
      From: Jie Fu 
      Date: Wed, 13 Oct 2021 14:30:11 +0000
      Subject: [PATCH 199/385] 8275173:
       testlibrary_tests/ir_framework/tests/TestCheckedTests.java fails after
       JDK-8274911
      
      Reviewed-by: chagedorn, thartmann
      ---
       .../ir_framework/tests/TestCheckedTests.java       | 14 ++++++++++++--
       1 file changed, 12 insertions(+), 2 deletions(-)
      
      diff --git a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestCheckedTests.java b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestCheckedTests.java
      index b6e28cb3bea..6a8d5c50c6a 100644
      --- a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestCheckedTests.java
      +++ b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestCheckedTests.java
      @@ -26,6 +26,8 @@ package ir_framework.tests;
       import compiler.lib.ir_framework.*;
       import compiler.lib.ir_framework.driver.IRViolationException;
       import compiler.lib.ir_framework.driver.TestVMException;
      +import java.io.ByteArrayOutputStream;
      +import java.io.PrintStream;
       import jdk.test.lib.Asserts;
       
       /*
      @@ -41,11 +43,17 @@ public class TestCheckedTests {
           public int iFld;
       
           public static void main(String[] args) {
      +        ByteArrayOutputStream baos = new ByteArrayOutputStream();
      +        PrintStream ps = new PrintStream(baos);
      +        PrintStream oldOut = System.out;
      +        System.setOut(ps);
      +
               TestFramework.run();
               try {
                   TestFramework.run(BadIRAndRuntimeCheckedTests.class);
      -            Utils.shouldHaveThrownException();
      +            Utils.shouldHaveThrownException(baos.toString());
               } catch (TestVMException e) {
      +            System.setOut(oldOut);
                   Asserts.assertTrue(e.getExceptionInfo().contains("Test Failures (2)"));
                   Asserts.assertTrue(e.getExceptionInfo().contains("checkTestBad3"));
                   Asserts.assertTrue(e.getExceptionInfo().contains("checkTestBad5"));
      @@ -53,10 +61,12 @@ public class TestCheckedTests {
                   Asserts.assertFalse(e.getExceptionInfo().contains("Failed IR Rules"));
               }
       
      +        System.setOut(ps);
               try {
                   TestFramework.run(BadIRCheckedTests.class);
      -            Utils.shouldHaveThrownException();
      +            Utils.shouldHaveThrownException(baos.toString());
               } catch (IRViolationException e) {
      +            System.setOut(oldOut);
                   Asserts.assertTrue(e.getExceptionInfo().contains("Failed IR Rules (3)"));
               }
           }
      -- 
      GitLab
      
      
      From d8f6b6c19a591512ff4e956823cb87a83e088ae8 Mon Sep 17 00:00:00 2001
      From: Fairoz Matte 
      Date: Wed, 13 Oct 2021 15:38:36 +0000
      Subject: [PATCH 200/385] 8274718: runtime/cds/appcds/LambdaEagerInit.java
       fails with -XX:-CompactStrings
      
      Reviewed-by: iklam, ccheung
      ---
       .../jtreg/runtime/cds/appcds/LambdaEagerInit.java  | 14 +++++++++-----
       1 file changed, 9 insertions(+), 5 deletions(-)
      
      diff --git a/test/hotspot/jtreg/runtime/cds/appcds/LambdaEagerInit.java b/test/hotspot/jtreg/runtime/cds/appcds/LambdaEagerInit.java
      index 28296d4c905..bf4541e8ee1 100644
      --- a/test/hotspot/jtreg/runtime/cds/appcds/LambdaEagerInit.java
      +++ b/test/hotspot/jtreg/runtime/cds/appcds/LambdaEagerInit.java
      @@ -1,5 +1,5 @@
       /*
      - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
      + * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
        * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
        *
        * This code is free software; you can redistribute it and/or modify it
      @@ -109,6 +109,7 @@ public class LambdaEagerInit {
           static void testDefaultArchiveWithEagerInitializationEnabled() throws Exception {
               // run with default CDS archive with the -Djdk.internal.lambda.disableEagerInitialization=true property
               CDSOptions runOpts = (new CDSOptions())
      +            .setXShareMode("auto")
                   .addPrefix("-cp", appJar, testProperty,  "-Xlog:class+load,cds=debug")
                   .setUseSystemArchive(true)
                   .setUseVersion(false)
      @@ -122,13 +123,16 @@ public class LambdaEagerInit {
           static void testDefaultArchiveWithEagerInitializationDisabled() throws Exception {
               // run with default CDS archive without the -Djdk.internal.lambda.disableEagerInitialization=true property
               CDSOptions runOpts = (new CDSOptions())
      +            .setXShareMode("auto")
                   .addPrefix("-cp", appJar, "-Xlog:class+load,cds=debug")
                   .setUseSystemArchive(true)
                   .setUseVersion(false)
      -            .addSuffix(mainClass);
      +            .addSuffix("-showversion", mainClass);
               OutputAnalyzer output = CDSTestUtils.runWithArchive(runOpts);
      -        output.shouldMatch(lambdaLoadedFromArchive)
      -              .shouldMatch(cdsLoadedLambdaProxy)
      -              .shouldHaveExitValue(0);
      +        if (output.getStderr().contains("sharing")) {
      +            output.shouldMatch(lambdaLoadedFromArchive)
      +                  .shouldMatch(cdsLoadedLambdaProxy);
      +        }
      +        output.shouldHaveExitValue(0);
           }
       }
      -- 
      GitLab
      
      
      From d15fbc28afc3f2d509b4e46e70877a4650fafdc2 Mon Sep 17 00:00:00 2001
      From: Joe Darcy 
      Date: Wed, 13 Oct 2021 16:53:46 +0000
      Subject: [PATCH 201/385] 8275187: Suppress warnings on non-serializable array
       component types in java.sql.rowset
      
      Reviewed-by: lancea
      ---
       .../share/classes/com/sun/rowset/internal/BaseRow.java         | 3 ++-
       .../classes/com/sun/rowset/internal/CachedRowSetWriter.java    | 1 +
       .../share/classes/com/sun/rowset/internal/Row.java             | 3 ++-
       3 files changed, 5 insertions(+), 2 deletions(-)
      
      diff --git a/src/java.sql.rowset/share/classes/com/sun/rowset/internal/BaseRow.java b/src/java.sql.rowset/share/classes/com/sun/rowset/internal/BaseRow.java
      index 1b4067c835a..678d9782f29 100644
      --- a/src/java.sql.rowset/share/classes/com/sun/rowset/internal/BaseRow.java
      +++ b/src/java.sql.rowset/share/classes/com/sun/rowset/internal/BaseRow.java
      @@ -1,5 +1,5 @@
       /*
      - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
      + * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.
        * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
        *
        * This code is free software; you can redistribute it and/or modify it
      @@ -61,6 +61,7 @@ private static final long serialVersionUID = 4152013523511412238L;
        * object.
        * @serial
        */
      +    @SuppressWarnings("serial") // Array component type is not Serializable
           protected Object[] origVals;
       
       /**
      diff --git a/src/java.sql.rowset/share/classes/com/sun/rowset/internal/CachedRowSetWriter.java b/src/java.sql.rowset/share/classes/com/sun/rowset/internal/CachedRowSetWriter.java
      index 47a8bc7c7c1..a588c1dd94a 100644
      --- a/src/java.sql.rowset/share/classes/com/sun/rowset/internal/CachedRowSetWriter.java
      +++ b/src/java.sql.rowset/share/classes/com/sun/rowset/internal/CachedRowSetWriter.java
      @@ -147,6 +147,7 @@ public class CachedRowSetWriter implements TransactionalWriter, Serializable {
        *
        * @serial
        */
      +    @SuppressWarnings("serial") // Array component type is not Serializable
           private Object[] params;
       
       /**
      diff --git a/src/java.sql.rowset/share/classes/com/sun/rowset/internal/Row.java b/src/java.sql.rowset/share/classes/com/sun/rowset/internal/Row.java
      index 1fa4b767b02..2167effa109 100644
      --- a/src/java.sql.rowset/share/classes/com/sun/rowset/internal/Row.java
      +++ b/src/java.sql.rowset/share/classes/com/sun/rowset/internal/Row.java
      @@ -1,5 +1,5 @@
       /*
      - * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
      + * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.
        * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
        *
        * This code is free software; you can redistribute it and/or modify it
      @@ -53,6 +53,7 @@ static final long serialVersionUID = 5047859032611314762L;
        * object.
        * @serial
        */
      +    @SuppressWarnings("serial") // Array component type is not Serializable
           private Object[] currentVals;
       
       /**
      -- 
      GitLab
      
      
      From 1e0184d142deb18e719fc28814a293b44bab6c63 Mon Sep 17 00:00:00 2001
      From: "lawrence.andrews" 
      Date: Wed, 13 Oct 2021 20:04:30 +0000
      Subject: [PATCH 202/385] 8275234:
       java/awt/GraphicsDevice/DisplayModes/CycleDMImage.java is entered twice in
       ProblemList
      
      Reviewed-by: serb, pbansal
      ---
       test/jdk/ProblemList.txt | 3 +--
       1 file changed, 1 insertion(+), 2 deletions(-)
      
      diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt
      index 300127bec0a..781147ad09b 100644
      --- a/test/jdk/ProblemList.txt
      +++ b/test/jdk/ProblemList.txt
      @@ -503,7 +503,7 @@ java/awt/Frame/DisposeParentGC/DisposeParentGC.java 8079786 macosx-all
       java/awt/FullScreen/NoResizeEventOnDMChangeTest/NoResizeEventOnDMChangeTest.java 8169468 macosx-all
       java/awt/TextArea/AutoScrollOnSelectAndAppend/AutoScrollOnSelectAndAppend.java 8213120 macosx-all
       
      -java/awt/GraphicsDevice/DisplayModes/CycleDMImage.java 7099223 linux-all,windows-all
      +java/awt/GraphicsDevice/DisplayModes/CycleDMImage.java 7099223,8274106 macosx-aarch64,linux-all,windows-all
       java/awt/Window/WindowResizing/DoubleClickTitleBarTest.java 8233557 macosx-all
       java/awt/Window/WindowOwnedByEmbeddedFrameTest/WindowOwnedByEmbeddedFrameTest.java 8233558 macosx-all
       java/awt/keyboard/AllKeyCode/AllKeyCode.java 8242930 macosx-all
      @@ -750,7 +750,6 @@ javax/swing/JButton/8151303/PressedIconTest.java 8266246 macosx-aarch64
       javax/swing/JMenuItem/ActionListenerCalledTwice/ActionListenerCalledTwiceTest.java 8273573 macosx-all
       
       # Several tests which fail on some hidpi systems
      -java/awt/GraphicsDevice/DisplayModes/CycleDMImage.java 8274106 macosx-aarch64
       java/awt/Window/8159168/SetShapeTest.java 8274106 macosx-aarch64
       java/awt/image/multiresolution/MultiResolutionJOptionPaneIconTest.java 8274106 macosx-aarch64
       javax/swing/JFrame/8175301/ScaledFrameBackgroundTest.java 8274106 macosx-aarch64
      -- 
      GitLab
      
      
      From 7dc2db4aacfeea0caffcc76fd352eabf64ee34c4 Mon Sep 17 00:00:00 2001
      From: "lawrence.andrews" 
      Date: Wed, 13 Oct 2021 20:06:35 +0000
      Subject: [PATCH 203/385] 8274032: Remove jtreg tag manual=yesno for
       java/awt/print/PrinterJob/ImagePrinting/ImageTypes.java & show test UI
      
      Reviewed-by: serb, pbansal
      ---
       .../PrinterJob/ImagePrinting/ImageTypes.java  | 189 +++++++++++-------
       1 file changed, 114 insertions(+), 75 deletions(-)
      
      diff --git a/test/jdk/java/awt/print/PrinterJob/ImagePrinting/ImageTypes.java b/test/jdk/java/awt/print/PrinterJob/ImagePrinting/ImageTypes.java
      index b8536c09e9c..c33dc0f6718 100644
      --- a/test/jdk/java/awt/print/PrinterJob/ImagePrinting/ImageTypes.java
      +++ b/test/jdk/java/awt/print/PrinterJob/ImagePrinting/ImageTypes.java
      @@ -1,5 +1,5 @@
       /*
      - * Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved.
      + * Copyright (c) 2006, 2021, Oracle and/or its affiliates. All rights reserved.
        * 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,85 +21,133 @@
        * questions.
        */
       
      -/**
      - *
      +/*
        * @test
        * @bug 4521945 7006865
        * @summary Test printing images of different types.
        * @author prr
      - * @run main/manual=yesno/timeout=900 ImageTypes
      + * @run main/manual ImageTypes
        */
       
      -import java.io.*;
      +import java.awt.Button;
      +import java.awt.Color;
      +import java.awt.Component;
      +import java.awt.Dimension;
      +import java.awt.Font;
      +import java.awt.FontMetrics;
      +import java.awt.Frame;
      +import java.awt.GradientPaint;
      +import java.awt.Graphics;
      +import java.awt.Graphics2D;
      +import java.awt.GridLayout;
      +import java.awt.Panel;
      +import java.awt.TextArea;
      +import java.awt.event.ActionEvent;
      +import java.awt.event.ActionListener;
      +import java.awt.image.BufferedImage;
      +import java.awt.image.DataBuffer;
      +import java.awt.image.IndexColorModel;
      +import java.awt.print.PageFormat;
      +import java.awt.print.Printable;
      +import java.awt.print.PrinterException;
      +import java.awt.print.PrinterJob;
      +import java.util.concurrent.CountDownLatch;
      +import java.util.concurrent.TimeUnit;
      +import javax.print.attribute.HashPrintRequestAttributeSet;
      +import javax.print.attribute.PrintRequestAttributeSet;
      +
       import static java.awt.Color.*;
      -import java.awt.*;
      -import java.awt.geom.*;
      -import java.awt.event.*;
      -import java.awt.print.*;
      -import java.awt.image.*;
       import static java.awt.image.BufferedImage.*;
      -import javax.print.*;
      -import javax.print.attribute.*;
      -import javax.print.attribute.standard.*;
       
      -public class ImageTypes extends Frame implements ActionListener {
      +public class ImageTypes {
       
      -    private ImageCanvas c;
      +    private static Frame testFrame;
      +    private static ImageCanvas imageCanvas;
      +    private static volatile boolean testResult;
      +    private static final CountDownLatch countDownLatch = new CountDownLatch(1);
       
      -    public static void main(String args[]) {
      -
      -        ImageTypes f = new ImageTypes();
      -        f.show();
      +    public static void main(String[] args) throws InterruptedException {
      +        createTestUI();
      +        if (!countDownLatch.await(10, TimeUnit.MINUTES)) {
      +            throw new RuntimeException("Timeout : No action was performed on the test UI.");
      +        }
      +        if (!testResult) {
      +            throw new RuntimeException("Test failed!");
      +        }
           }
       
      -    public ImageTypes () {
      -        super("Image Types Printing Test");
      -        c = new ImageCanvas();
      -        add("Center", c);
      -
      -        Button printThisButton = new Button("Print");
      -        printThisButton.addActionListener(this);
      -        Panel p = new Panel();
      -        p.add(printThisButton);
      -        add("South", p);
      -        add("North", getInstructions());
      -        addWindowListener(new WindowAdapter() {
      -                public void windowClosing(WindowEvent e) {
      -                    System.exit(0);
      +    public static void createTestUI() {
      +        testFrame = new Frame("Image Types Printing Test");
      +        imageCanvas = new ImageCanvas();
      +        testFrame.add("Center", imageCanvas);
      +
      +        Button printButton = new Button("Print");
      +        printButton.addActionListener(new ActionListener() {
      +            @Override
      +            public void actionPerformed(ActionEvent e) {
      +                PrinterJob pj = PrinterJob.getPrinterJob();
      +                if (pj.getPrintService() == null) {
      +                    System.out.println("No printers. Test cannot continue. Install " +
      +                            "printer and restart the test.");
      +                    return;
                       }
      -            });
      -
      -        pack();
      +                PrintRequestAttributeSet attrs = new HashPrintRequestAttributeSet();
      +                if (pj != null && pj.printDialog(attrs)) {
      +                    pj.setPrintable(imageCanvas);
      +                    try {
      +                        pj.print(attrs);
      +                    } catch (PrinterException pe) {
      +                        pe.printStackTrace();
      +                        throw new RuntimeException("Exception whilst printing.");
      +                    } finally {
      +                        System.out.println("PRINT RETURNED OK.");
      +                    }
      +                }
      +            }
      +        });
      +
      +        Button passButton = new Button("Pass");
      +        passButton.addActionListener(new ActionListener() {
      +            @Override
      +            public void actionPerformed(ActionEvent e) {
      +                testResult = true;
      +                countDownLatch.countDown();
      +                testFrame.dispose();
      +            }
      +        });
      +
      +        Button failButton = new Button("Fail");
      +        failButton.addActionListener(new ActionListener() {
      +            @Override
      +            public void actionPerformed(ActionEvent e) {
      +                testResult = false;
      +                countDownLatch.countDown();
      +                testFrame.dispose();
      +            }
      +        });
      +
      +        Panel buttonPanel = new Panel(new GridLayout(1,3));
      +        buttonPanel.add(printButton);
      +        buttonPanel.add(passButton);
      +        buttonPanel.add(failButton);
      +        testFrame.add("South", buttonPanel);
      +        testFrame.add("North", getInstructions());
      +        testFrame.pack();
      +        testFrame.setVisible(true);
           }
       
      -    private TextArea getInstructions() {
      -        TextArea ta = new TextArea(10, 60);
      +    private static TextArea getInstructions() {
      +        String testInstruction = "This is a manual test as it requires that you compare "+
      +                "the on-screen rendering with the printed output.\n"+
      +                "Select the 'Print' button to print out the test.\n"+
      +                "For each image compare the printed one to the on-screen one.\n"+
      +                "Press Pass button if the onscreen and printed rendering " +
      +                "match else Press fail button";
      +        TextArea ta = new TextArea(testInstruction,7, 60,
      +                TextArea.SCROLLBARS_NONE);
               ta.setFont(new Font("Dialog", Font.PLAIN, 11));
      -        ta.setText
      -            ("This is a manual test as it requires that you compare "+
      -             "the on-screen rendering with the printed output.\n"+
      -             "Select the 'Print' button to print out the test.\n"+
      -             "For each image compare the printed one to the on-screen one.\n"+
      -             "The test PASSES if the onscreen and printed rendering match.");
               return ta;
           }
      -
      -    public void actionPerformed(ActionEvent e) {
      -        PrinterJob pj = PrinterJob.getPrinterJob();
      -
      -        PrintRequestAttributeSet attrs = new HashPrintRequestAttributeSet();
      -        if (pj != null && pj.printDialog(attrs)) {
      -            pj.setPrintable(c);
      -            try {
      -                pj.print(attrs);
      -            } catch (PrinterException pe) {
      -                pe.printStackTrace();
      -                throw new RuntimeException("Exception whilst printing.");
      -            } finally {
      -                System.out.println("PRINT RETURNED OK.");
      -            }
      -        }
      -    }
       }
       
       class ImageCanvas extends Component implements Printable {
      @@ -111,7 +159,6 @@ class ImageCanvas extends Component implements Printable {
           int sw=99, sh=99;
       
           void paintImage(BufferedImage bi, Color c1, Color c2) {
      -
               GradientPaint tp= new GradientPaint(0.0f, 0.0f, c1, 10f, 8f, c2, true);
               Graphics2D g2d = (Graphics2D)bi.getGraphics();
               g2d.setPaint(tp);
      @@ -132,7 +179,6 @@ class ImageCanvas extends Component implements Printable {
           }
       
           ImageCanvas() {
      -
               opaqueImg = new BufferedImage(sw, sh, TYPE_INT_RGB);
               Color o1 = new Color(0, 0, 0);
               Color o2 = new Color(255, 255, 255);
      @@ -171,9 +217,7 @@ class ImageCanvas extends Component implements Printable {
       
           }
       
      -
           public int print(Graphics g, PageFormat pgFmt, int pgIndex) {
      -
               if (pgIndex > 0) {
                   return Printable.NO_SUCH_PAGE;
               }
      @@ -184,7 +228,6 @@ class ImageCanvas extends Component implements Printable {
           }
       
           private void drawImage(Graphics g, int biType, IndexColorModel icm) {
      -
               BufferedImage bi;
               if (icm != null) {
                   bi = new BufferedImage(sw, sh, biType, icm);
      @@ -202,7 +245,6 @@ class ImageCanvas extends Component implements Printable {
           }
       
           public void paint(Graphics g) {
      -
               int incX = sw+10, incY = sh+10;
       
               g.translate(10, 10);
      @@ -259,14 +301,11 @@ class ImageCanvas extends Component implements Printable {
               g.translate(incX, 0);
           }
       
      -
      -
      -     /* Size is chosen to match default imageable width of a NA letter
      -      * page. This means there will be clipping, what is clipped will
      -      * depend on PageFormat orientation.
      -      */
      -     public Dimension getPreferredSize() {
      +    /* Size is chosen to match default imageable width of a NA letter
      +     * page. This means there will be clipping, what is clipped will
      +     * depend on PageFormat orientation.
      +     */
      +    public Dimension getPreferredSize() {
               return new Dimension(468, 600);
           }
      -
       }
      -- 
      GitLab
      
      
      From d9e03e42afbb2e5115b67accfffad4938b8314b1 Mon Sep 17 00:00:00 2001
      From: Joe Darcy 
      Date: Wed, 13 Oct 2021 20:19:04 +0000
      Subject: [PATCH 204/385] 8275244: Suppress warnings on non-serializable array
       component types in jdk.management
      
      Reviewed-by: alanb
      ---
       .../classes/com/sun/management/internal/GcInfoCompositeData.java | 1 +
       1 file changed, 1 insertion(+)
      
      diff --git a/src/jdk.management/share/classes/com/sun/management/internal/GcInfoCompositeData.java b/src/jdk.management/share/classes/com/sun/management/internal/GcInfoCompositeData.java
      index fdf64ebaeb2..fc99cb6737f 100644
      --- a/src/jdk.management/share/classes/com/sun/management/internal/GcInfoCompositeData.java
      +++ b/src/jdk.management/share/classes/com/sun/management/internal/GcInfoCompositeData.java
      @@ -55,6 +55,7 @@ public class GcInfoCompositeData extends LazyCompositeData {
           private final GcInfo info;
           @SuppressWarnings("serial") // Type of field is not Serializable
           private final GcInfoBuilder builder;
      +    @SuppressWarnings("serial") // Array component type is not Serializable
           private final Object[] gcExtItemValues;
       
           public GcInfoCompositeData(GcInfo info,
      -- 
      GitLab
      
      
      From 8b1b6f9fb375bbc2de339ad8f526ca4d5f83dc70 Mon Sep 17 00:00:00 2001
      From: TatWai Chong 
      Date: Thu, 14 Oct 2021 05:27:12 +0000
      Subject: [PATCH 205/385] 8269559: AArch64: Implement string_compare intrinsic
       in SVE
      
      Reviewed-by: ngasson, aph
      ---
       src/hotspot/cpu/aarch64/aarch64.ad            |  41 +++--
       src/hotspot/cpu/aarch64/aarch64_sve.ad        |  99 +++++++++++
       src/hotspot/cpu/aarch64/aarch64_sve_ad.m4     |  37 ++++
       .../cpu/aarch64/c2_MacroAssembler_aarch64.cpp |   3 +-
       .../cpu/aarch64/c2_MacroAssembler_aarch64.hpp |   3 +-
       src/hotspot/cpu/aarch64/register_aarch64.hpp  |   2 +
       .../aarch64/register_definitions_aarch64.cpp  |   4 +-
       .../cpu/aarch64/stubGenerator_aarch64.cpp     | 107 +++++++++++
       test/hotspot/gtest/aarch64/aarch64-asmtest.py |   2 +
       test/hotspot/gtest/aarch64/asmtest.out.h      | 166 +++++++++---------
       .../lang/StringCompareToDifferentLength.java  | 148 ++++++++++++++++
       11 files changed, 516 insertions(+), 96 deletions(-)
       create mode 100644 test/micro/org/openjdk/bench/java/lang/StringCompareToDifferentLength.java
      
      diff --git a/src/hotspot/cpu/aarch64/aarch64.ad b/src/hotspot/cpu/aarch64/aarch64.ad
      index 52d624a2de6..d5995a109f7 100644
      --- a/src/hotspot/cpu/aarch64/aarch64.ad
      +++ b/src/hotspot/cpu/aarch64/aarch64.ad
      @@ -1199,6 +1199,9 @@ reg_class gov_pr (
           // P7, non-allocatable, preserved with all elements preset to TRUE.
       );
       
      +reg_class p0_reg(P0);
      +reg_class p1_reg(P1);
      +
       // Singleton class for condition codes
       reg_class int_flags(RFLAGS);
       
      @@ -5537,6 +5540,24 @@ operand pRegGov()
         interface(REG_INTER);
       %}
       
      +operand pRegGov_P0()
      +%{
      +  constraint(ALLOC_IN_RC(p0_reg));
      +  match(RegVectMask);
      +  op_cost(0);
      +  format %{ %}
      +  interface(REG_INTER);
      +%}
      +
      +operand pRegGov_P1()
      +%{
      +  constraint(ALLOC_IN_RC(p1_reg));
      +  match(RegVectMask);
      +  op_cost(0);
      +  format %{ %}
      +  interface(REG_INTER);
      +%}
      +
       // Flags register, used as output of signed compare instructions
       
       // note that on AArch64 we also use this register as the output for
      @@ -16491,7 +16512,7 @@ instruct partialSubtypeCheckVsZero(iRegP_R4 sub, iRegP_R0 super, iRegP_R2 temp,
       instruct string_compareU(iRegP_R1 str1, iRegI_R2 cnt1, iRegP_R3 str2, iRegI_R4 cnt2,
                               iRegI_R0 result, iRegP_R10 tmp1, iRegL_R11 tmp2, rFlagsReg cr)
       %{
      -  predicate(((StrCompNode*)n)->encoding() == StrIntrinsicNode::UU);
      +  predicate((UseSVE == 0) && (((StrCompNode*)n)->encoding() == StrIntrinsicNode::UU));
         match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2)));
         effect(KILL tmp1, KILL tmp2, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL cr);
       
      @@ -16501,7 +16522,7 @@ instruct string_compareU(iRegP_R1 str1, iRegI_R2 cnt1, iRegP_R3 str2, iRegI_R4 c
           __ string_compare($str1$$Register, $str2$$Register,
                             $cnt1$$Register, $cnt2$$Register, $result$$Register,
                             $tmp1$$Register, $tmp2$$Register,
      -                      fnoreg, fnoreg, fnoreg, StrIntrinsicNode::UU);
      +                      fnoreg, fnoreg, fnoreg, pnoreg, pnoreg, StrIntrinsicNode::UU);
         %}
         ins_pipe(pipe_class_memory);
       %}
      @@ -16509,7 +16530,7 @@ instruct string_compareU(iRegP_R1 str1, iRegI_R2 cnt1, iRegP_R3 str2, iRegI_R4 c
       instruct string_compareL(iRegP_R1 str1, iRegI_R2 cnt1, iRegP_R3 str2, iRegI_R4 cnt2,
                               iRegI_R0 result, iRegP_R10 tmp1, iRegL_R11 tmp2, rFlagsReg cr)
       %{
      -  predicate(((StrCompNode*)n)->encoding() == StrIntrinsicNode::LL);
      +  predicate((UseSVE == 0) && (((StrCompNode*)n)->encoding() == StrIntrinsicNode::LL));
         match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2)));
         effect(KILL tmp1, KILL tmp2, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL cr);
       
      @@ -16518,7 +16539,7 @@ instruct string_compareL(iRegP_R1 str1, iRegI_R2 cnt1, iRegP_R3 str2, iRegI_R4 c
           __ string_compare($str1$$Register, $str2$$Register,
                             $cnt1$$Register, $cnt2$$Register, $result$$Register,
                             $tmp1$$Register, $tmp2$$Register,
      -                      fnoreg, fnoreg, fnoreg, StrIntrinsicNode::LL);
      +                      fnoreg, fnoreg, fnoreg, pnoreg, pnoreg, StrIntrinsicNode::LL);
         %}
         ins_pipe(pipe_class_memory);
       %}
      @@ -16527,7 +16548,7 @@ instruct string_compareUL(iRegP_R1 str1, iRegI_R2 cnt1, iRegP_R3 str2, iRegI_R4
                               iRegI_R0 result, iRegP_R10 tmp1, iRegL_R11 tmp2,
                               vRegD_V0 vtmp1, vRegD_V1 vtmp2, vRegD_V2 vtmp3, rFlagsReg cr)
       %{
      -  predicate(((StrCompNode*)n)->encoding() == StrIntrinsicNode::UL);
      +  predicate((UseSVE == 0) && (((StrCompNode*)n)->encoding() == StrIntrinsicNode::UL));
         match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2)));
         effect(KILL tmp1, KILL tmp2, KILL vtmp1, KILL vtmp2, KILL vtmp3,
                USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL cr);
      @@ -16537,8 +16558,8 @@ instruct string_compareUL(iRegP_R1 str1, iRegI_R2 cnt1, iRegP_R3 str2, iRegI_R4
           __ string_compare($str1$$Register, $str2$$Register,
                             $cnt1$$Register, $cnt2$$Register, $result$$Register,
                             $tmp1$$Register, $tmp2$$Register,
      -                      $vtmp1$$FloatRegister, $vtmp2$$FloatRegister,
      -                      $vtmp3$$FloatRegister, StrIntrinsicNode::UL);
      +                      $vtmp1$$FloatRegister, $vtmp2$$FloatRegister, $vtmp3$$FloatRegister,
      +                      pnoreg, pnoreg, StrIntrinsicNode::UL);
         %}
         ins_pipe(pipe_class_memory);
       %}
      @@ -16547,7 +16568,7 @@ instruct string_compareLU(iRegP_R1 str1, iRegI_R2 cnt1, iRegP_R3 str2, iRegI_R4
                               iRegI_R0 result, iRegP_R10 tmp1, iRegL_R11 tmp2,
                               vRegD_V0 vtmp1, vRegD_V1 vtmp2, vRegD_V2 vtmp3, rFlagsReg cr)
       %{
      -  predicate(((StrCompNode*)n)->encoding() == StrIntrinsicNode::LU);
      +  predicate((UseSVE == 0) && (((StrCompNode*)n)->encoding() == StrIntrinsicNode::LU));
         match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2)));
         effect(KILL tmp1, KILL tmp2, KILL vtmp1, KILL vtmp2, KILL vtmp3,
                USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL cr);
      @@ -16557,8 +16578,8 @@ instruct string_compareLU(iRegP_R1 str1, iRegI_R2 cnt1, iRegP_R3 str2, iRegI_R4
           __ string_compare($str1$$Register, $str2$$Register,
                             $cnt1$$Register, $cnt2$$Register, $result$$Register,
                             $tmp1$$Register, $tmp2$$Register,
      -                      $vtmp1$$FloatRegister, $vtmp2$$FloatRegister,
      -                      $vtmp3$$FloatRegister,StrIntrinsicNode::LU);
      +                      $vtmp1$$FloatRegister, $vtmp2$$FloatRegister, $vtmp3$$FloatRegister,
      +                      pnoreg, pnoreg, StrIntrinsicNode::LU);
         %}
         ins_pipe(pipe_class_memory);
       %}
      diff --git a/src/hotspot/cpu/aarch64/aarch64_sve.ad b/src/hotspot/cpu/aarch64/aarch64_sve.ad
      index 1910ef42b25..0610f54819c 100644
      --- a/src/hotspot/cpu/aarch64/aarch64_sve.ad
      +++ b/src/hotspot/cpu/aarch64/aarch64_sve.ad
      @@ -3810,6 +3810,105 @@ instruct stringU_indexof_char_sve(iRegP_R1 str1, iRegI_R2 cnt1, iRegI_R3 ch,
         ins_pipe(pipe_class_memory);
       %}
       
      +// Intrisics for String.compareTo()
      +
      +// Note that Z registers alias the corresponding NEON registers, we declare the vector operands of
      +// these string_compare variants as NEON register type for convenience so that the prototype of
      +// string_compare can be shared with all variants.
      +
      +
      +instruct string_compareLL_sve(iRegP_R1 str1, iRegI_R2 cnt1, iRegP_R3 str2, iRegI_R4 cnt2,
      +                              iRegI_R0 result, iRegP_R10 tmp1, iRegL_R11 tmp2,
      +                              vRegD_V0 vtmp1, vRegD_V1 vtmp2, pRegGov_P0 pgtmp1,
      +                              pRegGov_P1 pgtmp2, rFlagsReg cr)
      +%{
      +  predicate((UseSVE > 0) && (((StrCompNode*)n)->encoding() == StrIntrinsicNode::LL));
      +  match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2)));
      +  effect(TEMP tmp1, TEMP tmp2, TEMP vtmp1, TEMP vtmp2, TEMP pgtmp1, TEMP pgtmp2,
      +         USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL cr);
      +
      +  format %{ "String Compare $str1,$cnt1,$str2,$cnt2 -> $result   # USE sve" %}
      +  ins_encode %{
      +    // Count is in 8-bit bytes; non-Compact chars are 16 bits.
      +    __ string_compare($str1$$Register, $str2$$Register,
      +                      $cnt1$$Register, $cnt2$$Register, $result$$Register,
      +                      $tmp1$$Register, $tmp2$$Register,
      +                      $vtmp1$$FloatRegister, $vtmp2$$FloatRegister, fnoreg,
      +                      as_PRegister($pgtmp1$$reg), as_PRegister($pgtmp2$$reg),
      +                      StrIntrinsicNode::LL);
      +  %}
      +  ins_pipe(pipe_class_memory);
      +%}
      +
      +instruct string_compareLU_sve(iRegP_R1 str1, iRegI_R2 cnt1, iRegP_R3 str2, iRegI_R4 cnt2,
      +                              iRegI_R0 result, iRegP_R10 tmp1, iRegL_R11 tmp2,
      +                              vRegD_V0 vtmp1, vRegD_V1 vtmp2, pRegGov_P0 pgtmp1,
      +                              pRegGov_P1 pgtmp2, rFlagsReg cr)
      +%{
      +  predicate((UseSVE > 0) && (((StrCompNode*)n)->encoding() == StrIntrinsicNode::LU));
      +  match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2)));
      +  effect(TEMP tmp1, TEMP tmp2, TEMP vtmp1, TEMP vtmp2, TEMP pgtmp1, TEMP pgtmp2,
      +         USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL cr);
      +
      +  format %{ "String Compare $str1,$cnt1,$str2,$cnt2 -> $result   # USE sve" %}
      +  ins_encode %{
      +    // Count is in 8-bit bytes; non-Compact chars are 16 bits.
      +    __ string_compare($str1$$Register, $str2$$Register,
      +                      $cnt1$$Register, $cnt2$$Register, $result$$Register,
      +                      $tmp1$$Register, $tmp2$$Register,
      +                      $vtmp1$$FloatRegister, $vtmp2$$FloatRegister, fnoreg,
      +                      as_PRegister($pgtmp1$$reg), as_PRegister($pgtmp2$$reg),
      +                      StrIntrinsicNode::LU);
      +  %}
      +  ins_pipe(pipe_class_memory);
      +%}
      +
      +instruct string_compareUL_sve(iRegP_R1 str1, iRegI_R2 cnt1, iRegP_R3 str2, iRegI_R4 cnt2,
      +                              iRegI_R0 result, iRegP_R10 tmp1, iRegL_R11 tmp2,
      +                              vRegD_V0 vtmp1, vRegD_V1 vtmp2, pRegGov_P0 pgtmp1,
      +                              pRegGov_P1 pgtmp2, rFlagsReg cr)
      +%{
      +  predicate((UseSVE > 0) && (((StrCompNode*)n)->encoding() == StrIntrinsicNode::UL));
      +  match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2)));
      +  effect(TEMP tmp1, TEMP tmp2, TEMP vtmp1, TEMP vtmp2, TEMP pgtmp1, TEMP pgtmp2,
      +         USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL cr);
      +
      +  format %{ "String Compare $str1,$cnt1,$str2,$cnt2 -> $result   # USE sve" %}
      +  ins_encode %{
      +    // Count is in 8-bit bytes; non-Compact chars are 16 bits.
      +    __ string_compare($str1$$Register, $str2$$Register,
      +                      $cnt1$$Register, $cnt2$$Register, $result$$Register,
      +                      $tmp1$$Register, $tmp2$$Register,
      +                      $vtmp1$$FloatRegister, $vtmp2$$FloatRegister, fnoreg,
      +                      as_PRegister($pgtmp1$$reg), as_PRegister($pgtmp2$$reg),
      +                      StrIntrinsicNode::UL);
      +  %}
      +  ins_pipe(pipe_class_memory);
      +%}
      +
      +instruct string_compareUU_sve(iRegP_R1 str1, iRegI_R2 cnt1, iRegP_R3 str2, iRegI_R4 cnt2,
      +                              iRegI_R0 result, iRegP_R10 tmp1, iRegL_R11 tmp2,
      +                              vRegD_V0 vtmp1, vRegD_V1 vtmp2, pRegGov_P0 pgtmp1,
      +                              pRegGov_P1 pgtmp2, rFlagsReg cr)
      +%{
      +  predicate((UseSVE > 0) && (((StrCompNode*)n)->encoding() == StrIntrinsicNode::UU));
      +  match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2)));
      +  effect(TEMP tmp1, TEMP tmp2, TEMP vtmp1, TEMP vtmp2, TEMP pgtmp1, TEMP pgtmp2,
      +         USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL cr);
      +
      +  format %{ "String Compare $str1,$cnt1,$str2,$cnt2 -> $result   # USE sve" %}
      +  ins_encode %{
      +    // Count is in 8-bit bytes; non-Compact chars are 16 bits.
      +    __ string_compare($str1$$Register, $str2$$Register,
      +                      $cnt1$$Register, $cnt2$$Register, $result$$Register,
      +                      $tmp1$$Register, $tmp2$$Register,
      +                      $vtmp1$$FloatRegister, $vtmp2$$FloatRegister, fnoreg,
      +                      as_PRegister($pgtmp1$$reg), as_PRegister($pgtmp2$$reg),
      +                      StrIntrinsicNode::UU);
      +  %}
      +  ins_pipe(pipe_class_memory);
      +%}
      +
       // ---------------------------- Vector mask reductions ---------------------------
       
       instruct vmask_truecount(iRegINoSp dst, vReg src, pReg ptmp, rFlagsReg cr) %{
      diff --git a/src/hotspot/cpu/aarch64/aarch64_sve_ad.m4 b/src/hotspot/cpu/aarch64/aarch64_sve_ad.m4
      index dfdc6a2fda9..25195a0b1f3 100644
      --- a/src/hotspot/cpu/aarch64/aarch64_sve_ad.m4
      +++ b/src/hotspot/cpu/aarch64/aarch64_sve_ad.m4
      @@ -2513,6 +2513,43 @@ dnl                 $1 $2      $3
       STRING_INDEXOF_CHAR(L, Latin1, true)
       STRING_INDEXOF_CHAR(U, UTF16,  false)
       
      +// Intrisics for String.compareTo()
      +
      +// Note that Z registers alias the corresponding NEON registers, we declare the vector operands of
      +// these string_compare variants as NEON register type for convenience so that the prototype of
      +// string_compare can be shared with all variants.
      +
      +dnl
      +define(`STRING_COMPARETO', `
      +instruct string_compare$1_sve(iRegP_R1 str1, iRegI_R2 cnt1, iRegP_R3 str2, iRegI_R4 cnt2,
      +                              iRegI_R0 result, iRegP_R10 tmp1, iRegL_R11 tmp2,
      +                              vRegD_V0 vtmp1, vRegD_V1 vtmp2, pRegGov_P0 pgtmp1,
      +                              pRegGov_P1 pgtmp2, rFlagsReg cr)
      +%{
      +  predicate((UseSVE > 0) && (((StrCompNode*)n)->encoding() == StrIntrinsicNode::$1));
      +  match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2)));
      +  effect(TEMP tmp1, TEMP tmp2, TEMP vtmp1, TEMP vtmp2, TEMP pgtmp1, TEMP pgtmp2,
      +         USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL cr);
      +
      +  format %{ "String Compare $str1,$cnt1,$str2,$cnt2 -> $result   # USE sve" %}
      +  ins_encode %{
      +    // Count is in 8-bit bytes; non-Compact chars are 16 bits.
      +    __ string_compare($str1$$Register, $str2$$Register,
      +                      $cnt1$$Register, $cnt2$$Register, $result$$Register,
      +                      $tmp1$$Register, $tmp2$$Register,
      +                      $vtmp1$$FloatRegister, $vtmp2$$FloatRegister, fnoreg,
      +                      as_PRegister($pgtmp1$$reg), as_PRegister($pgtmp2$$reg),
      +                      StrIntrinsicNode::$1);
      +  %}
      +  ins_pipe(pipe_class_memory);
      +%}')dnl
      +dnl              $1
      +STRING_COMPARETO(LL)
      +STRING_COMPARETO(LU)
      +STRING_COMPARETO(UL)
      +STRING_COMPARETO(UU)
      +dnl
      +
       dnl
       dnl VMASK_REDUCTION($1,     $2,      $3  )
       dnl VMASK_REDUCTION(suffix, op_name, cost)
      diff --git a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp
      index 2713576bf4c..cb8a6e316f5 100644
      --- a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp
      +++ b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp
      @@ -676,7 +676,8 @@ void C2_MacroAssembler::stringL_indexof_char(Register str1, Register cnt1,
       // Compare strings.
       void C2_MacroAssembler::string_compare(Register str1, Register str2,
           Register cnt1, Register cnt2, Register result, Register tmp1, Register tmp2,
      -    FloatRegister vtmp1, FloatRegister vtmp2, FloatRegister vtmp3, int ae) {
      +    FloatRegister vtmp1, FloatRegister vtmp2, FloatRegister vtmp3,
      +    PRegister pgtmp1, PRegister pgtmp2, int ae) {
         Label DONE, SHORT_LOOP, SHORT_STRING, SHORT_LAST, TAIL, STUB,
             DIFF, NEXT_WORD, SHORT_LOOP_TAIL, SHORT_LAST2, SHORT_LAST_INIT,
             SHORT_LOOP_START, TAIL_CHECK;
      diff --git a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp
      index fb0fbabea9e..0b2a6583d68 100644
      --- a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp
      +++ b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp
      @@ -32,7 +32,8 @@
         void string_compare(Register str1, Register str2,
                             Register cnt1, Register cnt2, Register result,
                             Register tmp1, Register tmp2, FloatRegister vtmp1,
      -                      FloatRegister vtmp2, FloatRegister vtmp3, int ae);
      +                      FloatRegister vtmp2, FloatRegister vtmp3,
      +                      PRegister pgtmp1, PRegister pgtmp2, int ae);
       
         void string_indexof(Register str1, Register str2,
                             Register cnt1, Register cnt2,
      diff --git a/src/hotspot/cpu/aarch64/register_aarch64.hpp b/src/hotspot/cpu/aarch64/register_aarch64.hpp
      index 479bd1f37c4..029bfeeb672 100644
      --- a/src/hotspot/cpu/aarch64/register_aarch64.hpp
      +++ b/src/hotspot/cpu/aarch64/register_aarch64.hpp
      @@ -263,6 +263,8 @@ class PRegisterImpl: public AbstractRegisterImpl {
       };
       
       // The predicate registers of SVE.
      +CONSTANT_REGISTER_DECLARATION(PRegister, pnoreg, (-1));
      +
       CONSTANT_REGISTER_DECLARATION(PRegister, p0,  ( 0));
       CONSTANT_REGISTER_DECLARATION(PRegister, p1,  ( 1));
       CONSTANT_REGISTER_DECLARATION(PRegister, p2,  ( 2));
      diff --git a/src/hotspot/cpu/aarch64/register_definitions_aarch64.cpp b/src/hotspot/cpu/aarch64/register_definitions_aarch64.cpp
      index f48c70d09e6..32358a0b154 100644
      --- a/src/hotspot/cpu/aarch64/register_definitions_aarch64.cpp
      +++ b/src/hotspot/cpu/aarch64/register_definitions_aarch64.cpp
      @@ -1,5 +1,5 @@
       /*
      - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved.
      + * Copyright (c) 2002, 2021, Oracle and/or its affiliates. All rights reserved.
        * Copyright (c) 2014, Red Hat Inc. All rights reserved.
        * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
        *
      @@ -188,6 +188,8 @@ REGISTER_DEFINITION(FloatRegister, z29);
       REGISTER_DEFINITION(FloatRegister, z30);
       REGISTER_DEFINITION(FloatRegister, z31);
       
      +REGISTER_DEFINITION(PRegister, pnoreg);
      +
       REGISTER_DEFINITION(PRegister, p0);
       REGISTER_DEFINITION(PRegister, p1);
       REGISTER_DEFINITION(PRegister, p2);
      diff --git a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp
      index 0388bb73b91..bde9676f631 100644
      --- a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp
      +++ b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp
      @@ -4879,6 +4879,11 @@ class StubGenerator: public StubCodeGenerator {
         // r4  = cnt2
         // r10 = tmp1
         // r11 = tmp2
      +  // r12 = tmp3
      +  // r14 = tmp4
      +  // v0  = vtmp1
      +  // v1  = vtmp2
      +  // v2  = vtmp3
         address generate_compare_long_string_different_encoding(bool isLU) {
           __ align(CodeEntryAlignment);
           StubCodeMark mark(this, "StubRoutines", isLU
      @@ -5031,6 +5036,97 @@ class StubGenerator: public StubCodeGenerator {
           return start;
         }
       
      +  enum string_compare_mode {
      +    LL,
      +    LU,
      +    UL,
      +    UU,
      +  };
      +
      +  // The following registers are declared in aarch64.ad
      +  // r0  = result
      +  // r1  = str1
      +  // r2  = cnt1
      +  // r3  = str2
      +  // r4  = cnt2
      +  // r10 = tmp1
      +  // r11 = tmp2
      +  // z0  = ztmp1
      +  // z1  = ztmp2
      +  // p0  = pgtmp1
      +  // p1  = pgtmp2
      +  address generate_compare_long_string_sve(string_compare_mode mode) {
      +    __ align(CodeEntryAlignment);
      +    address entry = __ pc();
      +    Register result = r0, str1 = r1, cnt1 = r2, str2 = r3, cnt2 = r4,
      +             tmp1 = r10, tmp2 = r11;
      +
      +    Label LOOP, MATCH, DONE, NOMATCH;
      +    Register vec_len = tmp1;
      +    Register idx = tmp2;
      +    // The minimum of the string lengths has been stored in cnt2.
      +    Register cnt = cnt2;
      +    FloatRegister ztmp1 = z0, ztmp2 = z1;
      +    PRegister pgtmp1 = p0, pgtmp2 = p1;
      +
      +    if (mode == LL) {
      +      __ sve_cntb(vec_len);
      +    } else {
      +      __ sve_cnth(vec_len);
      +    }
      +
      +    __ mov(idx, 0);
      +    __ sve_whilelt(pgtmp1, mode == LL ? __ B : __ H, idx, cnt);
      +
      +    __ bind(LOOP);
      +      switch (mode) {
      +        case LL:
      +          __ sve_ld1b(ztmp1, __ B, pgtmp1, Address(str1, idx));
      +          __ sve_ld1b(ztmp2, __ B, pgtmp1, Address(str2, idx));
      +          break;
      +        case LU:
      +          __ sve_ld1b(ztmp1, __ H, pgtmp1, Address(str1, idx));
      +          __ sve_ld1h(ztmp2, __ H, pgtmp1, Address(str2, idx, Address::lsl(1)));
      +          break;
      +        case UL:
      +          __ sve_ld1h(ztmp1, __ H, pgtmp1, Address(str1, idx, Address::lsl(1)));
      +          __ sve_ld1b(ztmp2, __ H, pgtmp1, Address(str2, idx));
      +          break;
      +        case UU:
      +          __ sve_ld1h(ztmp1, __ H, pgtmp1, Address(str1, idx, Address::lsl(1)));
      +          __ sve_ld1h(ztmp2, __ H, pgtmp1, Address(str2, idx, Address::lsl(1)));
      +          break;
      +        default: ShouldNotReachHere();
      +      }
      +      __ add(idx, idx, vec_len);
      +
      +      // Compare strings.
      +      __ sve_cmp(Assembler::NE, pgtmp2, mode == LL ? __ B : __ H, pgtmp1, ztmp1, ztmp2);
      +      __ br(__ NE, MATCH);
      +      __ sve_whilelt(pgtmp1, mode == LL ? __ B : __ H, idx, cnt);
      +      __ br(__ LT, LOOP);
      +
      +      // The result has been computed in the caller prior to entering this stub.
      +      __ b(DONE);
      +
      +    __ bind(MATCH);
      +
      +      // Crop the vector to find its location.
      +      __ sve_brkb(pgtmp2, pgtmp1, pgtmp2, false /* isMerge */);
      +
      +      // Extract the first different characters of each string.
      +      __ sve_lasta(rscratch1, mode == LL ? __ B : __ H, pgtmp2, ztmp1);
      +      __ sve_lasta(rscratch2, mode == LL ? __ B : __ H, pgtmp2, ztmp2);
      +
      +      // Compute the difference of the first different characters.
      +      __ sub(result, rscratch1, rscratch2);
      +
      +    __ bind(DONE);
      +      __ ret(lr);
      +
      +    return entry;
      +  }
      +
         // r0  = result
         // r1  = str1
         // r2  = cnt1
      @@ -5153,6 +5249,7 @@ class StubGenerator: public StubCodeGenerator {
         }
       
         void generate_compare_long_strings() {
      +    if (!UseSVE) {
             StubRoutines::aarch64::_compare_long_string_LL
                 = generate_compare_long_string_same_encoding(true);
             StubRoutines::aarch64::_compare_long_string_UU
      @@ -5161,6 +5258,16 @@ class StubGenerator: public StubCodeGenerator {
                 = generate_compare_long_string_different_encoding(true);
             StubRoutines::aarch64::_compare_long_string_UL
                 = generate_compare_long_string_different_encoding(false);
      +    } else {
      +      StubRoutines::aarch64::_compare_long_string_LL
      +          = generate_compare_long_string_sve(LL);
      +      StubRoutines::aarch64::_compare_long_string_UU
      +          = generate_compare_long_string_sve(UU);
      +      StubRoutines::aarch64::_compare_long_string_LU
      +          = generate_compare_long_string_sve(LU);
      +      StubRoutines::aarch64::_compare_long_string_UL
      +          = generate_compare_long_string_sve(UL);
      +    }
         }
       
         // R0 = result
      diff --git a/test/hotspot/gtest/aarch64/aarch64-asmtest.py b/test/hotspot/gtest/aarch64/aarch64-asmtest.py
      index f77560ca7eb..df23b64b05e 100644
      --- a/test/hotspot/gtest/aarch64/aarch64-asmtest.py
      +++ b/test/hotspot/gtest/aarch64/aarch64-asmtest.py
      @@ -1567,6 +1567,8 @@ generate(SpecialCases, [["ccmn",   "__ ccmn(zr, zr, 3u, Assembler::LE);",
                               ["ld1b",    "__ sve_ld1b(z0, __ S, p2, Address(sp, r8));",        "ld1b\t{z0.s}, p2/z, [sp, x8]"],
                               ["ld1b",    "__ sve_ld1b(z0, __ D, p3, Address(sp, 7));",         "ld1b\t{z0.d}, p3/z, [sp, #7, MUL VL]"],
                               ["ld1h",    "__ sve_ld1h(z10, __ H, p1, Address(sp, -8));",       "ld1h\t{z10.h}, p1/z, [sp, #-8, MUL VL]"],
      +                        ["ld1h",
      +                         "__ sve_ld1h(z10, __ H, p0, Address(r4, r2, Address::lsl(1)));", "ld1h\t{z10.h}, p0/z, [x4, x2, LSL 1]"],
                               ["ld1w",    "__ sve_ld1w(z20, __ S, p2, Address(r0, 7));",        "ld1w\t{z20.s}, p2/z, [x0, #7, MUL VL]"],
                               ["ld1b",    "__ sve_ld1b(z30, __ B, p3, Address(sp, r8));",       "ld1b\t{z30.b}, p3/z, [sp, x8]"],
                               ["ld1w",    "__ sve_ld1w(z0, __ S, p4, Address(sp, r28));",       "ld1w\t{z0.s}, p4/z, [sp, x28, LSL #2]"],
      diff --git a/test/hotspot/gtest/aarch64/asmtest.out.h b/test/hotspot/gtest/aarch64/asmtest.out.h
      index 661471e67e0..3dab7fca957 100644
      --- a/test/hotspot/gtest/aarch64/asmtest.out.h
      +++ b/test/hotspot/gtest/aarch64/asmtest.out.h
      @@ -756,6 +756,7 @@
           __ sve_ld1b(z0, __ S, p2, Address(sp, r8));        //       ld1b    {z0.s}, p2/z, [sp, x8]
           __ sve_ld1b(z0, __ D, p3, Address(sp, 7));         //       ld1b    {z0.d}, p3/z, [sp, #7, MUL VL]
           __ sve_ld1h(z10, __ H, p1, Address(sp, -8));       //       ld1h    {z10.h}, p1/z, [sp, #-8, MUL VL]
      +    __ sve_ld1h(z10, __ H, p0, Address(r4, r2, Address::lsl(1))); //    ld1h    {z10.h}, p0/z, [x4, x2, LSL 1]
           __ sve_ld1w(z20, __ S, p2, Address(r0, 7));        //       ld1w    {z20.s}, p2/z, [x0, #7, MUL VL]
           __ sve_ld1b(z30, __ B, p3, Address(sp, r8));       //       ld1b    {z30.b}, p3/z, [sp, x8]
           __ sve_ld1w(z0, __ S, p4, Address(sp, r28));       //       ld1w    {z0.s}, p4/z, [sp, x28, LSL #2]
      @@ -1042,30 +1043,30 @@
           0x9101a1a0,     0xb10a5cc8,     0xd10810aa,     0xf10fd061,
           0x120cb166,     0x321764bc,     0x52174681,     0x720c0227,
           0x9241018e,     0xb25a2969,     0xd278b411,     0xf26aad01,
      -    0x14000000,     0x17ffffd7,     0x1400034c,     0x94000000,
      -    0x97ffffd4,     0x94000349,     0x3400000a,     0x34fffa2a,
      -    0x340068ca,     0x35000008,     0x35fff9c8,     0x35006868,
      -    0xb400000b,     0xb4fff96b,     0xb400680b,     0xb500001d,
      -    0xb5fff91d,     0xb50067bd,     0x10000013,     0x10fff8b3,
      -    0x10006753,     0x90000013,     0x36300016,     0x3637f836,
      -    0x363066d6,     0x3758000c,     0x375ff7cc,     0x3758666c,
      +    0x14000000,     0x17ffffd7,     0x1400034d,     0x94000000,
      +    0x97ffffd4,     0x9400034a,     0x3400000a,     0x34fffa2a,
      +    0x340068ea,     0x35000008,     0x35fff9c8,     0x35006888,
      +    0xb400000b,     0xb4fff96b,     0xb400682b,     0xb500001d,
      +    0xb5fff91d,     0xb50067dd,     0x10000013,     0x10fff8b3,
      +    0x10006773,     0x90000013,     0x36300016,     0x3637f836,
      +    0x363066f6,     0x3758000c,     0x375ff7cc,     0x3758668c,
           0x128313a0,     0x528a32c7,     0x7289173b,     0x92ab3acc,
           0xd2a0bf94,     0xf2c285e8,     0x9358722f,     0x330e652f,
           0x53067f3b,     0x93577c53,     0xb34a1aac,     0xd35a4016,
           0x13946c63,     0x93c3dbc8,     0x54000000,     0x54fff5a0,
      -    0x54006440,     0x54000001,     0x54fff541,     0x540063e1,
      -    0x54000002,     0x54fff4e2,     0x54006382,     0x54000002,
      -    0x54fff482,     0x54006322,     0x54000003,     0x54fff423,
      -    0x540062c3,     0x54000003,     0x54fff3c3,     0x54006263,
      -    0x54000004,     0x54fff364,     0x54006204,     0x54000005,
      -    0x54fff305,     0x540061a5,     0x54000006,     0x54fff2a6,
      -    0x54006146,     0x54000007,     0x54fff247,     0x540060e7,
      -    0x54000008,     0x54fff1e8,     0x54006088,     0x54000009,
      -    0x54fff189,     0x54006029,     0x5400000a,     0x54fff12a,
      -    0x54005fca,     0x5400000b,     0x54fff0cb,     0x54005f6b,
      -    0x5400000c,     0x54fff06c,     0x54005f0c,     0x5400000d,
      -    0x54fff00d,     0x54005ead,     0x5400000e,     0x54ffefae,
      -    0x54005e4e,     0x5400000f,     0x54ffef4f,     0x54005def,
      +    0x54006460,     0x54000001,     0x54fff541,     0x54006401,
      +    0x54000002,     0x54fff4e2,     0x540063a2,     0x54000002,
      +    0x54fff482,     0x54006342,     0x54000003,     0x54fff423,
      +    0x540062e3,     0x54000003,     0x54fff3c3,     0x54006283,
      +    0x54000004,     0x54fff364,     0x54006224,     0x54000005,
      +    0x54fff305,     0x540061c5,     0x54000006,     0x54fff2a6,
      +    0x54006166,     0x54000007,     0x54fff247,     0x54006107,
      +    0x54000008,     0x54fff1e8,     0x540060a8,     0x54000009,
      +    0x54fff189,     0x54006049,     0x5400000a,     0x54fff12a,
      +    0x54005fea,     0x5400000b,     0x54fff0cb,     0x54005f8b,
      +    0x5400000c,     0x54fff06c,     0x54005f2c,     0x5400000d,
      +    0x54fff00d,     0x54005ecd,     0x5400000e,     0x54ffefae,
      +    0x54005e6e,     0x5400000f,     0x54ffef4f,     0x54005e0f,
           0xd40658e1,     0xd4014d22,     0xd4046543,     0xd4273f60,
           0xd44cad80,     0xd503201f,     0xd69f03e0,     0xd6bf03e0,
           0xd5033fdf,     0xd5033e9f,     0xd50332bf,     0xd61f0200,
      @@ -1097,7 +1098,7 @@
           0x791f226d,     0xf95aa2f3,     0xb9587bb7,     0x395f7176,
           0x795d9143,     0x399e7e08,     0x799a2697,     0x79df3422,
           0xb99c2624,     0xfd5c2374,     0xbd5fa1d9,     0xfd1d595a,
      -    0xbd1b1869,     0x58004e3b,     0x1800000b,     0xf8945060,
      +    0xbd1b1869,     0x58004e5b,     0x1800000b,     0xf8945060,
           0xd8000000,     0xf8ae6ba0,     0xf99a0080,     0x1a070035,
           0x3a0700a8,     0x5a0e0367,     0x7a11009b,     0x9a000380,
           0xba1e030c,     0xda0f0320,     0xfa030301,     0x0b340b11,
      @@ -1193,67 +1194,66 @@
           0x25208028,     0x2538cfe0,     0x2578d001,     0x25b8efe2,
           0x25f8f007,     0x2538dfea,     0x25b8dfeb,     0xa400a3e0,
           0xa420a7e0,     0xa4484be0,     0xa467afe0,     0xa4a8a7ea,
      -    0xa547a814,     0xa4084ffe,     0xa55c53e0,     0xa5e1540b,
      -    0xe400fbf6,     0xe408ffff,     0xe420e7e0,     0xe4484be0,
      -    0xe460efe0,     0xe547e400,     0xe4014be0,     0xe4a84fe0,
      -    0xe5f15000,     0x858043e0,     0x85a043ff,     0xe59f5d08,
      -    0x0420e3e9,     0x0460e3ea,     0x04a0e3eb,     0x04e0e3ec,
      -    0x25104042,     0x25104871,     0x25904861,     0x25904c92,
      -    0x05344020,     0x05744041,     0x05b44062,     0x05f44083,
      -    0x252c8840,     0x253c1420,     0x25681572,     0x25a21ce3,
      -    0x25ea1e34,     0x0522c020,     0x05e6c0a4,     0x2401a001,
      -    0x2443a051,     0x24858881,     0x24c78cd1,     0x24850891,
      -    0x24c70cc1,     0x250f9001,     0x25508051,     0x25802491,
      -    0x25df28c1,     0x25850c81,     0x251e10d1,     0x65816001,
      -    0x65c36051,     0x65854891,     0x65c74cc1,     0x05733820,
      -    0x05b238a4,     0x05f138e6,     0x0570396a,     0x65d0a001,
      -    0x65d6a443,     0x65d4a826,     0x6594ac26,     0x6554ac26,
      -    0x6556ac26,     0x6552ac26,     0x65cbac85,     0x65caac01,
      -    0x65dea833,     0x659ca509,     0x65d8a801,     0x65dcac01,
      -    0x655cb241,     0x0520a1e0,     0x0521a601,     0x052281e0,
      -    0x05238601,     0x04a14026,     0x0568aca7,     0x05b23230,
      -    0x853040af,     0xc5b040af,     0xe57080af,     0xe5b080af,
      -    0x1e601000,     0x1e603000,     0x1e621000,     0x1e623000,
      -    0x1e641000,     0x1e643000,     0x1e661000,     0x1e663000,
      -    0x1e681000,     0x1e683000,     0x1e6a1000,     0x1e6a3000,
      -    0x1e6c1000,     0x1e6c3000,     0x1e6e1000,     0x1e6e3000,
      -    0x1e701000,     0x1e703000,     0x1e721000,     0x1e723000,
      -    0x1e741000,     0x1e743000,     0x1e761000,     0x1e763000,
      -    0x1e781000,     0x1e783000,     0x1e7a1000,     0x1e7a3000,
      -    0x1e7c1000,     0x1e7c3000,     0x1e7e1000,     0x1e7e3000,
      -    0xf8208193,     0xf83101b6,     0xf83c13fe,     0xf821239a,
      -    0xf824309e,     0xf826535e,     0xf8304109,     0xf82c7280,
      -    0xf8216058,     0xf8a08309,     0xf8ba03d0,     0xf8a312ea,
      -    0xf8aa21e4,     0xf8a2310b,     0xf8aa522f,     0xf8a2418a,
      -    0xf8ac71af,     0xf8a26287,     0xf8fa8090,     0xf8e20184,
      -    0xf8f01215,     0xf8f022ab,     0xf8f7334c,     0xf8f751dc,
      -    0xf8eb4038,     0xf8ec715f,     0xf8f06047,     0xf863826d,
      -    0xf8710070,     0xf86113cb,     0xf86521e8,     0xf87d301e,
      -    0xf8745287,     0xf87742bc,     0xf87b70b9,     0xf8616217,
      -    0xb83f8185,     0xb82901fc,     0xb83d13f6,     0xb83320bf,
      -    0xb82e33f0,     0xb830529b,     0xb830416c,     0xb82973c6,
      -    0xb831639b,     0xb8be8147,     0xb8b4008a,     0xb8b81231,
      -    0xb8b623a3,     0xb8af3276,     0xb8b35056,     0xb8af4186,
      -    0xb8b071ab,     0xb8b763c1,     0xb8f38225,     0xb8e202d0,
      -    0xb8ed12aa,     0xb8fd219b,     0xb8fb3023,     0xb8ff5278,
      -    0xb8f14389,     0xb8fb70ef,     0xb8f563f7,     0xb87983e2,
      -    0xb87b0150,     0xb8771073,     0xb8702320,     0xb87a3057,
      -    0xb870508c,     0xb87c43be,     0xb87070db,     0xb86961fd,
      -    0xce273c87,     0xce080ac9,     0xce7e8e9b,     0xce808b45,
      -    0xce79806e,     0xce758768,     0xcec0835a,     0xce608ad8,
      -    0x043100c4,     0x046105e3,     0x65c900a6,     0x65d60a87,
      -    0x65c80545,     0x0416a63e,     0x04001f8b,     0x0450979a,
      -    0x04dabe0d,     0x045381a5,     0x04918b4f,     0x049006cb,
      -    0x0497a264,     0x045eadd1,     0x04881062,     0x040a04d7,
      -    0x04810f71,     0x04dca450,     0x65c084c3,     0x65cd8d93,
      -    0x65c69a68,     0x65878ae0,     0x65c29db3,     0x049da0e6,
      -    0x6582b911,     0x65c0b6d6,     0x65c1a1e2,     0x65cda494,
      -    0x65c18107,     0x65af1493,     0x65e52b36,     0x65ab4ed0,
      -    0x65f06a8d,     0x0451448f,     0x049c7c86,     0x0429335d,
      -    0x04bc3162,     0x047a3027,     0x04e831d1,     0x05a56b15,
      -    0x05b66e35,     0x041a367d,     0x041832e4,     0x04d926f3,
      -    0x04482113,     0x04ca3a2e,     0x658727d5,     0x6586358a,
      -    0x65d82709,     0x044138c4,
      +    0xa4a2408a,     0xa547a814,     0xa4084ffe,     0xa55c53e0,
      +    0xa5e1540b,     0xe400fbf6,     0xe408ffff,     0xe420e7e0,
      +    0xe4484be0,     0xe460efe0,     0xe547e400,     0xe4014be0,
      +    0xe4a84fe0,     0xe5f15000,     0x858043e0,     0x85a043ff,
      +    0xe59f5d08,     0x0420e3e9,     0x0460e3ea,     0x04a0e3eb,
      +    0x04e0e3ec,     0x25104042,     0x25104871,     0x25904861,
      +    0x25904c92,     0x05344020,     0x05744041,     0x05b44062,
      +    0x05f44083,     0x252c8840,     0x253c1420,     0x25681572,
      +    0x25a21ce3,     0x25ea1e34,     0x0522c020,     0x05e6c0a4,
      +    0x2401a001,     0x2443a051,     0x24858881,     0x24c78cd1,
      +    0x24850891,     0x24c70cc1,     0x250f9001,     0x25508051,
      +    0x25802491,     0x25df28c1,     0x25850c81,     0x251e10d1,
      +    0x65816001,     0x65c36051,     0x65854891,     0x65c74cc1,
      +    0x05733820,     0x05b238a4,     0x05f138e6,     0x0570396a,
      +    0x65d0a001,     0x65d6a443,     0x65d4a826,     0x6594ac26,
      +    0x6554ac26,     0x6556ac26,     0x6552ac26,     0x65cbac85,
      +    0x65caac01,     0x65dea833,     0x659ca509,     0x65d8a801,
      +    0x65dcac01,     0x655cb241,     0x0520a1e0,     0x0521a601,
      +    0x052281e0,     0x05238601,     0x04a14026,     0x0568aca7,
      +    0x05b23230,     0x853040af,     0xc5b040af,     0xe57080af,
      +    0xe5b080af,     0x1e601000,     0x1e603000,     0x1e621000,
      +    0x1e623000,     0x1e641000,     0x1e643000,     0x1e661000,
      +    0x1e663000,     0x1e681000,     0x1e683000,     0x1e6a1000,
      +    0x1e6a3000,     0x1e6c1000,     0x1e6c3000,     0x1e6e1000,
      +    0x1e6e3000,     0x1e701000,     0x1e703000,     0x1e721000,
      +    0x1e723000,     0x1e741000,     0x1e743000,     0x1e761000,
      +    0x1e763000,     0x1e781000,     0x1e783000,     0x1e7a1000,
      +    0x1e7a3000,     0x1e7c1000,     0x1e7c3000,     0x1e7e1000,
      +    0x1e7e3000,     0xf8208193,     0xf83101b6,     0xf83c13fe,
      +    0xf821239a,     0xf824309e,     0xf826535e,     0xf8304109,
      +    0xf82c7280,     0xf8216058,     0xf8a08309,     0xf8ba03d0,
      +    0xf8a312ea,     0xf8aa21e4,     0xf8a2310b,     0xf8aa522f,
      +    0xf8a2418a,     0xf8ac71af,     0xf8a26287,     0xf8fa8090,
      +    0xf8e20184,     0xf8f01215,     0xf8f022ab,     0xf8f7334c,
      +    0xf8f751dc,     0xf8eb4038,     0xf8ec715f,     0xf8f06047,
      +    0xf863826d,     0xf8710070,     0xf86113cb,     0xf86521e8,
      +    0xf87d301e,     0xf8745287,     0xf87742bc,     0xf87b70b9,
      +    0xf8616217,     0xb83f8185,     0xb82901fc,     0xb83d13f6,
      +    0xb83320bf,     0xb82e33f0,     0xb830529b,     0xb830416c,
      +    0xb82973c6,     0xb831639b,     0xb8be8147,     0xb8b4008a,
      +    0xb8b81231,     0xb8b623a3,     0xb8af3276,     0xb8b35056,
      +    0xb8af4186,     0xb8b071ab,     0xb8b763c1,     0xb8f38225,
      +    0xb8e202d0,     0xb8ed12aa,     0xb8fd219b,     0xb8fb3023,
      +    0xb8ff5278,     0xb8f14389,     0xb8fb70ef,     0xb8f563f7,
      +    0xb87983e2,     0xb87b0150,     0xb8771073,     0xb8702320,
      +    0xb87a3057,     0xb870508c,     0xb87c43be,     0xb87070db,
      +    0xb86961fd,     0xce273c87,     0xce080ac9,     0xce7e8e9b,
      +    0xce808b45,     0xce79806e,     0xce758768,     0xcec0835a,
      +    0xce608ad8,     0x043100c4,     0x046105e3,     0x65c900a6,
      +    0x65d60a87,     0x65c80545,     0x0416a63e,     0x04001f8b,
      +    0x0450979a,     0x04dabe0d,     0x045381a5,     0x04918b4f,
      +    0x049006cb,     0x0497a264,     0x045eadd1,     0x04881062,
      +    0x040a04d7,     0x04810f71,     0x04dca450,     0x65c084c3,
      +    0x65cd8d93,     0x65c69a68,     0x65878ae0,     0x65c29db3,
      +    0x049da0e6,     0x6582b911,     0x65c0b6d6,     0x65c1a1e2,
      +    0x65cda494,     0x65c18107,     0x65af1493,     0x65e52b36,
      +    0x65ab4ed0,     0x65f06a8d,     0x0451448f,     0x049c7c86,
      +    0x0429335d,     0x04bc3162,     0x047a3027,     0x04e831d1,
      +    0x05a56b15,     0x05b66e35,     0x041a367d,     0x041832e4,
      +    0x04d926f3,     0x04482113,     0x04ca3a2e,     0x658727d5,
      +    0x6586358a,     0x65d82709,     0x044138c4,
         };
       // END  Generated code -- do not edit
      -
      diff --git a/test/micro/org/openjdk/bench/java/lang/StringCompareToDifferentLength.java b/test/micro/org/openjdk/bench/java/lang/StringCompareToDifferentLength.java
      new file mode 100644
      index 00000000000..fb08e32efac
      --- /dev/null
      +++ b/test/micro/org/openjdk/bench/java/lang/StringCompareToDifferentLength.java
      @@ -0,0 +1,148 @@
      +/*
      + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
      + * Copyright (c) 2021, BELLSOFT. All rights reserved.
      + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      + *
      + * This code is free software; you can redistribute it and/or modify it
      + * under the terms of the GNU General Public License version 2 only, as
      + * published by the Free Software Foundation.
      + *
      + * This code is distributed in the hope that it will be useful, but WITHOUT
      + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      + * version 2 for more details (a copy is included in the LICENSE file that
      + * accompanied this code).
      + *
      + * You should have received a copy of the GNU General Public License version
      + * 2 along with this work; if not, write to the Free Software Foundation,
      + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
      + *
      + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
      + * or visit www.oracle.com if you need additional information or have any
      + * questions.
      + */
      +
      +package com.arm.benchmarks.intrinsics;
      +
      +import java.util.concurrent.TimeUnit;
      +
      +import org.openjdk.jmh.annotations.Benchmark;
      +import org.openjdk.jmh.annotations.BenchmarkMode;
      +import org.openjdk.jmh.annotations.CompilerControl;
      +import org.openjdk.jmh.annotations.Fork;
      +import org.openjdk.jmh.annotations.Level;
      +import org.openjdk.jmh.annotations.Measurement;
      +import org.openjdk.jmh.annotations.Mode;
      +import org.openjdk.jmh.annotations.OutputTimeUnit;
      +import org.openjdk.jmh.annotations.Param;
      +import org.openjdk.jmh.annotations.Scope;
      +import org.openjdk.jmh.annotations.Setup;
      +import org.openjdk.jmh.annotations.State;
      +import org.openjdk.jmh.annotations.Warmup;
      +
      +import org.openjdk.jmh.infra.Blackhole;
      +
      +/**
      + * This benchmark modified from test/hotspot/jtreg/compiler/intrinsics/string/TestStringCompareToDifferentLength.java
      + * This benchmark can be used to measure performance of compareTo() in
      + * (Latin1, Latin1), (Latin1, UTF16), (UTF16, Latin1), and (UTF16, UTF16)
      + * comparisons.
      + */
      +
      +@BenchmarkMode(Mode.AverageTime)
      +@OutputTimeUnit(TimeUnit.MILLISECONDS)
      +@State(Scope.Benchmark)
      +@Measurement(iterations = 3, time = 1000, timeUnit = TimeUnit.MILLISECONDS)
      +@Warmup(iterations = 3, time = 1000, timeUnit = TimeUnit.MILLISECONDS)
      +@CompilerControl(CompilerControl.Mode.DONT_INLINE)
      +public class StringCompareToDifferentLength {
      +
      +    @State(Scope.Benchmark)
      +    public static class Input {
      +        @Param({"24", "36", "72", "128", "256", "512"})
      +        public int size;
      +
      +        @Param({"2"})
      +        public int delta;
      +
      +        int count = 100000;
      +        String longLatin1;
      +        String shortLatin1;
      +        String longUTF16FirstChar;
      +        String shortUTF16FirstChar;
      +        String longUTF16LastChar;
      +        String shortUTF16LastChar;
      +
      +        /**
      +         * Initialize. New array objects and set initial values.
      +         */
      +        @Setup(Level.Trial)
      +        public void setup() throws Exception {
      +            char[] strsrc = new char[size + delta];
      +            // generate ASCII string
      +            for (int i = 0; i < size + delta; i++) {
      +                strsrc[i] = (char) ('a' + (i % 26));
      +            }
      +
      +            longLatin1 = new String(strsrc);
      +            shortLatin1 = longLatin1.substring(0, size);
      +            longUTF16LastChar = longLatin1.substring(0, longLatin1.length() - 1) + '\ubeef';
      +            longUTF16FirstChar = '\ubeef' + longLatin1.substring(1, longLatin1.length());
      +            shortUTF16LastChar = shortLatin1.substring(0, shortLatin1.length() - 1) + '\ubeef';
      +            shortUTF16FirstChar = longUTF16FirstChar.substring(0, size);
      +        }
      +    }
      +
      +    private int runCompareTo(String str2, String str1) {
      +        return str1.compareTo(str2);
      +    }
      +
      +    /**
      +     * latin1-latin1
      +     */
      +    @Benchmark
      +    public void compareToLL(Input in, Blackhole blackhole) {
      +        int res = 0;
      +        for (int i = 0; i < in.count; ++i) {
      +            res += runCompareTo(in.longLatin1, in.shortLatin1);
      +        }
      +        blackhole.consume(res);
      +    }
      +
      +    /**
      +     * UTF16-UTF16
      +     */
      +    @Benchmark
      +    public void compareToUU(Input in, Blackhole blackhole) {
      +        int res = 0;
      +        for (int i = 0; i < in.count; ++i) {
      +            res += runCompareTo(in.longUTF16FirstChar, in.shortUTF16FirstChar);
      +        }
      +        blackhole.consume(res);
      +    }
      +
      +    /**
      +     * latin1-UTF16
      +     */
      +    @Benchmark
      +    public void compareToLU(Input in, Blackhole blackhole) {
      +        int res = 0;
      +        for (int i = 0; i < in.count; ++i) {
      +            res += runCompareTo(in.longUTF16LastChar, in.shortLatin1);
      +        }
      +        blackhole.consume(res);
      +    }
      +
      +    /**
      +     * UTF16-latin1
      +     */
      +    @Benchmark
      +    public void compareToUL(Input in, Blackhole blackhole) {
      +        int res = 0;
      +        for (int i = 0; i < in.count; ++i) {
      +            res += runCompareTo(in.longLatin1, in.shortUTF16LastChar);
      +        }
      +        blackhole.consume(res);
      +    }
      +}
      +
      -- 
      GitLab
      
      
      From 333c4692d898d582fe162cc9621acd3e1c242d67 Mon Sep 17 00:00:00 2001
      From: Nick Gasson 
      Date: Thu, 14 Oct 2021 09:35:48 +0000
      Subject: [PATCH 206/385] 8275262: [BACKOUT] AArch64: Implement string_compare
       intrinsic in SVE
      
      Reviewed-by: dholmes, tschatzl
      ---
       src/hotspot/cpu/aarch64/aarch64.ad            |  41 ++---
       src/hotspot/cpu/aarch64/aarch64_sve.ad        |  99 -----------
       src/hotspot/cpu/aarch64/aarch64_sve_ad.m4     |  37 ----
       .../cpu/aarch64/c2_MacroAssembler_aarch64.cpp |   3 +-
       .../cpu/aarch64/c2_MacroAssembler_aarch64.hpp |   3 +-
       src/hotspot/cpu/aarch64/register_aarch64.hpp  |   2 -
       .../aarch64/register_definitions_aarch64.cpp  |   4 +-
       .../cpu/aarch64/stubGenerator_aarch64.cpp     | 107 -----------
       test/hotspot/gtest/aarch64/aarch64-asmtest.py |   2 -
       test/hotspot/gtest/aarch64/asmtest.out.h      | 166 +++++++++---------
       .../lang/StringCompareToDifferentLength.java  | 148 ----------------
       11 files changed, 96 insertions(+), 516 deletions(-)
       delete mode 100644 test/micro/org/openjdk/bench/java/lang/StringCompareToDifferentLength.java
      
      diff --git a/src/hotspot/cpu/aarch64/aarch64.ad b/src/hotspot/cpu/aarch64/aarch64.ad
      index d5995a109f7..52d624a2de6 100644
      --- a/src/hotspot/cpu/aarch64/aarch64.ad
      +++ b/src/hotspot/cpu/aarch64/aarch64.ad
      @@ -1199,9 +1199,6 @@ reg_class gov_pr (
           // P7, non-allocatable, preserved with all elements preset to TRUE.
       );
       
      -reg_class p0_reg(P0);
      -reg_class p1_reg(P1);
      -
       // Singleton class for condition codes
       reg_class int_flags(RFLAGS);
       
      @@ -5540,24 +5537,6 @@ operand pRegGov()
         interface(REG_INTER);
       %}
       
      -operand pRegGov_P0()
      -%{
      -  constraint(ALLOC_IN_RC(p0_reg));
      -  match(RegVectMask);
      -  op_cost(0);
      -  format %{ %}
      -  interface(REG_INTER);
      -%}
      -
      -operand pRegGov_P1()
      -%{
      -  constraint(ALLOC_IN_RC(p1_reg));
      -  match(RegVectMask);
      -  op_cost(0);
      -  format %{ %}
      -  interface(REG_INTER);
      -%}
      -
       // Flags register, used as output of signed compare instructions
       
       // note that on AArch64 we also use this register as the output for
      @@ -16512,7 +16491,7 @@ instruct partialSubtypeCheckVsZero(iRegP_R4 sub, iRegP_R0 super, iRegP_R2 temp,
       instruct string_compareU(iRegP_R1 str1, iRegI_R2 cnt1, iRegP_R3 str2, iRegI_R4 cnt2,
                               iRegI_R0 result, iRegP_R10 tmp1, iRegL_R11 tmp2, rFlagsReg cr)
       %{
      -  predicate((UseSVE == 0) && (((StrCompNode*)n)->encoding() == StrIntrinsicNode::UU));
      +  predicate(((StrCompNode*)n)->encoding() == StrIntrinsicNode::UU);
         match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2)));
         effect(KILL tmp1, KILL tmp2, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL cr);
       
      @@ -16522,7 +16501,7 @@ instruct string_compareU(iRegP_R1 str1, iRegI_R2 cnt1, iRegP_R3 str2, iRegI_R4 c
           __ string_compare($str1$$Register, $str2$$Register,
                             $cnt1$$Register, $cnt2$$Register, $result$$Register,
                             $tmp1$$Register, $tmp2$$Register,
      -                      fnoreg, fnoreg, fnoreg, pnoreg, pnoreg, StrIntrinsicNode::UU);
      +                      fnoreg, fnoreg, fnoreg, StrIntrinsicNode::UU);
         %}
         ins_pipe(pipe_class_memory);
       %}
      @@ -16530,7 +16509,7 @@ instruct string_compareU(iRegP_R1 str1, iRegI_R2 cnt1, iRegP_R3 str2, iRegI_R4 c
       instruct string_compareL(iRegP_R1 str1, iRegI_R2 cnt1, iRegP_R3 str2, iRegI_R4 cnt2,
                               iRegI_R0 result, iRegP_R10 tmp1, iRegL_R11 tmp2, rFlagsReg cr)
       %{
      -  predicate((UseSVE == 0) && (((StrCompNode*)n)->encoding() == StrIntrinsicNode::LL));
      +  predicate(((StrCompNode*)n)->encoding() == StrIntrinsicNode::LL);
         match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2)));
         effect(KILL tmp1, KILL tmp2, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL cr);
       
      @@ -16539,7 +16518,7 @@ instruct string_compareL(iRegP_R1 str1, iRegI_R2 cnt1, iRegP_R3 str2, iRegI_R4 c
           __ string_compare($str1$$Register, $str2$$Register,
                             $cnt1$$Register, $cnt2$$Register, $result$$Register,
                             $tmp1$$Register, $tmp2$$Register,
      -                      fnoreg, fnoreg, fnoreg, pnoreg, pnoreg, StrIntrinsicNode::LL);
      +                      fnoreg, fnoreg, fnoreg, StrIntrinsicNode::LL);
         %}
         ins_pipe(pipe_class_memory);
       %}
      @@ -16548,7 +16527,7 @@ instruct string_compareUL(iRegP_R1 str1, iRegI_R2 cnt1, iRegP_R3 str2, iRegI_R4
                               iRegI_R0 result, iRegP_R10 tmp1, iRegL_R11 tmp2,
                               vRegD_V0 vtmp1, vRegD_V1 vtmp2, vRegD_V2 vtmp3, rFlagsReg cr)
       %{
      -  predicate((UseSVE == 0) && (((StrCompNode*)n)->encoding() == StrIntrinsicNode::UL));
      +  predicate(((StrCompNode*)n)->encoding() == StrIntrinsicNode::UL);
         match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2)));
         effect(KILL tmp1, KILL tmp2, KILL vtmp1, KILL vtmp2, KILL vtmp3,
                USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL cr);
      @@ -16558,8 +16537,8 @@ instruct string_compareUL(iRegP_R1 str1, iRegI_R2 cnt1, iRegP_R3 str2, iRegI_R4
           __ string_compare($str1$$Register, $str2$$Register,
                             $cnt1$$Register, $cnt2$$Register, $result$$Register,
                             $tmp1$$Register, $tmp2$$Register,
      -                      $vtmp1$$FloatRegister, $vtmp2$$FloatRegister, $vtmp3$$FloatRegister,
      -                      pnoreg, pnoreg, StrIntrinsicNode::UL);
      +                      $vtmp1$$FloatRegister, $vtmp2$$FloatRegister,
      +                      $vtmp3$$FloatRegister, StrIntrinsicNode::UL);
         %}
         ins_pipe(pipe_class_memory);
       %}
      @@ -16568,7 +16547,7 @@ instruct string_compareLU(iRegP_R1 str1, iRegI_R2 cnt1, iRegP_R3 str2, iRegI_R4
                               iRegI_R0 result, iRegP_R10 tmp1, iRegL_R11 tmp2,
                               vRegD_V0 vtmp1, vRegD_V1 vtmp2, vRegD_V2 vtmp3, rFlagsReg cr)
       %{
      -  predicate((UseSVE == 0) && (((StrCompNode*)n)->encoding() == StrIntrinsicNode::LU));
      +  predicate(((StrCompNode*)n)->encoding() == StrIntrinsicNode::LU);
         match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2)));
         effect(KILL tmp1, KILL tmp2, KILL vtmp1, KILL vtmp2, KILL vtmp3,
                USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL cr);
      @@ -16578,8 +16557,8 @@ instruct string_compareLU(iRegP_R1 str1, iRegI_R2 cnt1, iRegP_R3 str2, iRegI_R4
           __ string_compare($str1$$Register, $str2$$Register,
                             $cnt1$$Register, $cnt2$$Register, $result$$Register,
                             $tmp1$$Register, $tmp2$$Register,
      -                      $vtmp1$$FloatRegister, $vtmp2$$FloatRegister, $vtmp3$$FloatRegister,
      -                      pnoreg, pnoreg, StrIntrinsicNode::LU);
      +                      $vtmp1$$FloatRegister, $vtmp2$$FloatRegister,
      +                      $vtmp3$$FloatRegister,StrIntrinsicNode::LU);
         %}
         ins_pipe(pipe_class_memory);
       %}
      diff --git a/src/hotspot/cpu/aarch64/aarch64_sve.ad b/src/hotspot/cpu/aarch64/aarch64_sve.ad
      index 0610f54819c..1910ef42b25 100644
      --- a/src/hotspot/cpu/aarch64/aarch64_sve.ad
      +++ b/src/hotspot/cpu/aarch64/aarch64_sve.ad
      @@ -3810,105 +3810,6 @@ instruct stringU_indexof_char_sve(iRegP_R1 str1, iRegI_R2 cnt1, iRegI_R3 ch,
         ins_pipe(pipe_class_memory);
       %}
       
      -// Intrisics for String.compareTo()
      -
      -// Note that Z registers alias the corresponding NEON registers, we declare the vector operands of
      -// these string_compare variants as NEON register type for convenience so that the prototype of
      -// string_compare can be shared with all variants.
      -
      -
      -instruct string_compareLL_sve(iRegP_R1 str1, iRegI_R2 cnt1, iRegP_R3 str2, iRegI_R4 cnt2,
      -                              iRegI_R0 result, iRegP_R10 tmp1, iRegL_R11 tmp2,
      -                              vRegD_V0 vtmp1, vRegD_V1 vtmp2, pRegGov_P0 pgtmp1,
      -                              pRegGov_P1 pgtmp2, rFlagsReg cr)
      -%{
      -  predicate((UseSVE > 0) && (((StrCompNode*)n)->encoding() == StrIntrinsicNode::LL));
      -  match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2)));
      -  effect(TEMP tmp1, TEMP tmp2, TEMP vtmp1, TEMP vtmp2, TEMP pgtmp1, TEMP pgtmp2,
      -         USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL cr);
      -
      -  format %{ "String Compare $str1,$cnt1,$str2,$cnt2 -> $result   # USE sve" %}
      -  ins_encode %{
      -    // Count is in 8-bit bytes; non-Compact chars are 16 bits.
      -    __ string_compare($str1$$Register, $str2$$Register,
      -                      $cnt1$$Register, $cnt2$$Register, $result$$Register,
      -                      $tmp1$$Register, $tmp2$$Register,
      -                      $vtmp1$$FloatRegister, $vtmp2$$FloatRegister, fnoreg,
      -                      as_PRegister($pgtmp1$$reg), as_PRegister($pgtmp2$$reg),
      -                      StrIntrinsicNode::LL);
      -  %}
      -  ins_pipe(pipe_class_memory);
      -%}
      -
      -instruct string_compareLU_sve(iRegP_R1 str1, iRegI_R2 cnt1, iRegP_R3 str2, iRegI_R4 cnt2,
      -                              iRegI_R0 result, iRegP_R10 tmp1, iRegL_R11 tmp2,
      -                              vRegD_V0 vtmp1, vRegD_V1 vtmp2, pRegGov_P0 pgtmp1,
      -                              pRegGov_P1 pgtmp2, rFlagsReg cr)
      -%{
      -  predicate((UseSVE > 0) && (((StrCompNode*)n)->encoding() == StrIntrinsicNode::LU));
      -  match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2)));
      -  effect(TEMP tmp1, TEMP tmp2, TEMP vtmp1, TEMP vtmp2, TEMP pgtmp1, TEMP pgtmp2,
      -         USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL cr);
      -
      -  format %{ "String Compare $str1,$cnt1,$str2,$cnt2 -> $result   # USE sve" %}
      -  ins_encode %{
      -    // Count is in 8-bit bytes; non-Compact chars are 16 bits.
      -    __ string_compare($str1$$Register, $str2$$Register,
      -                      $cnt1$$Register, $cnt2$$Register, $result$$Register,
      -                      $tmp1$$Register, $tmp2$$Register,
      -                      $vtmp1$$FloatRegister, $vtmp2$$FloatRegister, fnoreg,
      -                      as_PRegister($pgtmp1$$reg), as_PRegister($pgtmp2$$reg),
      -                      StrIntrinsicNode::LU);
      -  %}
      -  ins_pipe(pipe_class_memory);
      -%}
      -
      -instruct string_compareUL_sve(iRegP_R1 str1, iRegI_R2 cnt1, iRegP_R3 str2, iRegI_R4 cnt2,
      -                              iRegI_R0 result, iRegP_R10 tmp1, iRegL_R11 tmp2,
      -                              vRegD_V0 vtmp1, vRegD_V1 vtmp2, pRegGov_P0 pgtmp1,
      -                              pRegGov_P1 pgtmp2, rFlagsReg cr)
      -%{
      -  predicate((UseSVE > 0) && (((StrCompNode*)n)->encoding() == StrIntrinsicNode::UL));
      -  match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2)));
      -  effect(TEMP tmp1, TEMP tmp2, TEMP vtmp1, TEMP vtmp2, TEMP pgtmp1, TEMP pgtmp2,
      -         USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL cr);
      -
      -  format %{ "String Compare $str1,$cnt1,$str2,$cnt2 -> $result   # USE sve" %}
      -  ins_encode %{
      -    // Count is in 8-bit bytes; non-Compact chars are 16 bits.
      -    __ string_compare($str1$$Register, $str2$$Register,
      -                      $cnt1$$Register, $cnt2$$Register, $result$$Register,
      -                      $tmp1$$Register, $tmp2$$Register,
      -                      $vtmp1$$FloatRegister, $vtmp2$$FloatRegister, fnoreg,
      -                      as_PRegister($pgtmp1$$reg), as_PRegister($pgtmp2$$reg),
      -                      StrIntrinsicNode::UL);
      -  %}
      -  ins_pipe(pipe_class_memory);
      -%}
      -
      -instruct string_compareUU_sve(iRegP_R1 str1, iRegI_R2 cnt1, iRegP_R3 str2, iRegI_R4 cnt2,
      -                              iRegI_R0 result, iRegP_R10 tmp1, iRegL_R11 tmp2,
      -                              vRegD_V0 vtmp1, vRegD_V1 vtmp2, pRegGov_P0 pgtmp1,
      -                              pRegGov_P1 pgtmp2, rFlagsReg cr)
      -%{
      -  predicate((UseSVE > 0) && (((StrCompNode*)n)->encoding() == StrIntrinsicNode::UU));
      -  match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2)));
      -  effect(TEMP tmp1, TEMP tmp2, TEMP vtmp1, TEMP vtmp2, TEMP pgtmp1, TEMP pgtmp2,
      -         USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL cr);
      -
      -  format %{ "String Compare $str1,$cnt1,$str2,$cnt2 -> $result   # USE sve" %}
      -  ins_encode %{
      -    // Count is in 8-bit bytes; non-Compact chars are 16 bits.
      -    __ string_compare($str1$$Register, $str2$$Register,
      -                      $cnt1$$Register, $cnt2$$Register, $result$$Register,
      -                      $tmp1$$Register, $tmp2$$Register,
      -                      $vtmp1$$FloatRegister, $vtmp2$$FloatRegister, fnoreg,
      -                      as_PRegister($pgtmp1$$reg), as_PRegister($pgtmp2$$reg),
      -                      StrIntrinsicNode::UU);
      -  %}
      -  ins_pipe(pipe_class_memory);
      -%}
      -
       // ---------------------------- Vector mask reductions ---------------------------
       
       instruct vmask_truecount(iRegINoSp dst, vReg src, pReg ptmp, rFlagsReg cr) %{
      diff --git a/src/hotspot/cpu/aarch64/aarch64_sve_ad.m4 b/src/hotspot/cpu/aarch64/aarch64_sve_ad.m4
      index 25195a0b1f3..dfdc6a2fda9 100644
      --- a/src/hotspot/cpu/aarch64/aarch64_sve_ad.m4
      +++ b/src/hotspot/cpu/aarch64/aarch64_sve_ad.m4
      @@ -2513,43 +2513,6 @@ dnl                 $1 $2      $3
       STRING_INDEXOF_CHAR(L, Latin1, true)
       STRING_INDEXOF_CHAR(U, UTF16,  false)
       
      -// Intrisics for String.compareTo()
      -
      -// Note that Z registers alias the corresponding NEON registers, we declare the vector operands of
      -// these string_compare variants as NEON register type for convenience so that the prototype of
      -// string_compare can be shared with all variants.
      -
      -dnl
      -define(`STRING_COMPARETO', `
      -instruct string_compare$1_sve(iRegP_R1 str1, iRegI_R2 cnt1, iRegP_R3 str2, iRegI_R4 cnt2,
      -                              iRegI_R0 result, iRegP_R10 tmp1, iRegL_R11 tmp2,
      -                              vRegD_V0 vtmp1, vRegD_V1 vtmp2, pRegGov_P0 pgtmp1,
      -                              pRegGov_P1 pgtmp2, rFlagsReg cr)
      -%{
      -  predicate((UseSVE > 0) && (((StrCompNode*)n)->encoding() == StrIntrinsicNode::$1));
      -  match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2)));
      -  effect(TEMP tmp1, TEMP tmp2, TEMP vtmp1, TEMP vtmp2, TEMP pgtmp1, TEMP pgtmp2,
      -         USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL cr);
      -
      -  format %{ "String Compare $str1,$cnt1,$str2,$cnt2 -> $result   # USE sve" %}
      -  ins_encode %{
      -    // Count is in 8-bit bytes; non-Compact chars are 16 bits.
      -    __ string_compare($str1$$Register, $str2$$Register,
      -                      $cnt1$$Register, $cnt2$$Register, $result$$Register,
      -                      $tmp1$$Register, $tmp2$$Register,
      -                      $vtmp1$$FloatRegister, $vtmp2$$FloatRegister, fnoreg,
      -                      as_PRegister($pgtmp1$$reg), as_PRegister($pgtmp2$$reg),
      -                      StrIntrinsicNode::$1);
      -  %}
      -  ins_pipe(pipe_class_memory);
      -%}')dnl
      -dnl              $1
      -STRING_COMPARETO(LL)
      -STRING_COMPARETO(LU)
      -STRING_COMPARETO(UL)
      -STRING_COMPARETO(UU)
      -dnl
      -
       dnl
       dnl VMASK_REDUCTION($1,     $2,      $3  )
       dnl VMASK_REDUCTION(suffix, op_name, cost)
      diff --git a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp
      index cb8a6e316f5..2713576bf4c 100644
      --- a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp
      +++ b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp
      @@ -676,8 +676,7 @@ void C2_MacroAssembler::stringL_indexof_char(Register str1, Register cnt1,
       // Compare strings.
       void C2_MacroAssembler::string_compare(Register str1, Register str2,
           Register cnt1, Register cnt2, Register result, Register tmp1, Register tmp2,
      -    FloatRegister vtmp1, FloatRegister vtmp2, FloatRegister vtmp3,
      -    PRegister pgtmp1, PRegister pgtmp2, int ae) {
      +    FloatRegister vtmp1, FloatRegister vtmp2, FloatRegister vtmp3, int ae) {
         Label DONE, SHORT_LOOP, SHORT_STRING, SHORT_LAST, TAIL, STUB,
             DIFF, NEXT_WORD, SHORT_LOOP_TAIL, SHORT_LAST2, SHORT_LAST_INIT,
             SHORT_LOOP_START, TAIL_CHECK;
      diff --git a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp
      index 0b2a6583d68..fb0fbabea9e 100644
      --- a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp
      +++ b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp
      @@ -32,8 +32,7 @@
         void string_compare(Register str1, Register str2,
                             Register cnt1, Register cnt2, Register result,
                             Register tmp1, Register tmp2, FloatRegister vtmp1,
      -                      FloatRegister vtmp2, FloatRegister vtmp3,
      -                      PRegister pgtmp1, PRegister pgtmp2, int ae);
      +                      FloatRegister vtmp2, FloatRegister vtmp3, int ae);
       
         void string_indexof(Register str1, Register str2,
                             Register cnt1, Register cnt2,
      diff --git a/src/hotspot/cpu/aarch64/register_aarch64.hpp b/src/hotspot/cpu/aarch64/register_aarch64.hpp
      index 029bfeeb672..479bd1f37c4 100644
      --- a/src/hotspot/cpu/aarch64/register_aarch64.hpp
      +++ b/src/hotspot/cpu/aarch64/register_aarch64.hpp
      @@ -263,8 +263,6 @@ class PRegisterImpl: public AbstractRegisterImpl {
       };
       
       // The predicate registers of SVE.
      -CONSTANT_REGISTER_DECLARATION(PRegister, pnoreg, (-1));
      -
       CONSTANT_REGISTER_DECLARATION(PRegister, p0,  ( 0));
       CONSTANT_REGISTER_DECLARATION(PRegister, p1,  ( 1));
       CONSTANT_REGISTER_DECLARATION(PRegister, p2,  ( 2));
      diff --git a/src/hotspot/cpu/aarch64/register_definitions_aarch64.cpp b/src/hotspot/cpu/aarch64/register_definitions_aarch64.cpp
      index 32358a0b154..f48c70d09e6 100644
      --- a/src/hotspot/cpu/aarch64/register_definitions_aarch64.cpp
      +++ b/src/hotspot/cpu/aarch64/register_definitions_aarch64.cpp
      @@ -1,5 +1,5 @@
       /*
      - * Copyright (c) 2002, 2021, Oracle and/or its affiliates. All rights reserved.
      + * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved.
        * Copyright (c) 2014, Red Hat Inc. All rights reserved.
        * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
        *
      @@ -188,8 +188,6 @@ REGISTER_DEFINITION(FloatRegister, z29);
       REGISTER_DEFINITION(FloatRegister, z30);
       REGISTER_DEFINITION(FloatRegister, z31);
       
      -REGISTER_DEFINITION(PRegister, pnoreg);
      -
       REGISTER_DEFINITION(PRegister, p0);
       REGISTER_DEFINITION(PRegister, p1);
       REGISTER_DEFINITION(PRegister, p2);
      diff --git a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp
      index bde9676f631..0388bb73b91 100644
      --- a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp
      +++ b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp
      @@ -4879,11 +4879,6 @@ class StubGenerator: public StubCodeGenerator {
         // r4  = cnt2
         // r10 = tmp1
         // r11 = tmp2
      -  // r12 = tmp3
      -  // r14 = tmp4
      -  // v0  = vtmp1
      -  // v1  = vtmp2
      -  // v2  = vtmp3
         address generate_compare_long_string_different_encoding(bool isLU) {
           __ align(CodeEntryAlignment);
           StubCodeMark mark(this, "StubRoutines", isLU
      @@ -5036,97 +5031,6 @@ class StubGenerator: public StubCodeGenerator {
           return start;
         }
       
      -  enum string_compare_mode {
      -    LL,
      -    LU,
      -    UL,
      -    UU,
      -  };
      -
      -  // The following registers are declared in aarch64.ad
      -  // r0  = result
      -  // r1  = str1
      -  // r2  = cnt1
      -  // r3  = str2
      -  // r4  = cnt2
      -  // r10 = tmp1
      -  // r11 = tmp2
      -  // z0  = ztmp1
      -  // z1  = ztmp2
      -  // p0  = pgtmp1
      -  // p1  = pgtmp2
      -  address generate_compare_long_string_sve(string_compare_mode mode) {
      -    __ align(CodeEntryAlignment);
      -    address entry = __ pc();
      -    Register result = r0, str1 = r1, cnt1 = r2, str2 = r3, cnt2 = r4,
      -             tmp1 = r10, tmp2 = r11;
      -
      -    Label LOOP, MATCH, DONE, NOMATCH;
      -    Register vec_len = tmp1;
      -    Register idx = tmp2;
      -    // The minimum of the string lengths has been stored in cnt2.
      -    Register cnt = cnt2;
      -    FloatRegister ztmp1 = z0, ztmp2 = z1;
      -    PRegister pgtmp1 = p0, pgtmp2 = p1;
      -
      -    if (mode == LL) {
      -      __ sve_cntb(vec_len);
      -    } else {
      -      __ sve_cnth(vec_len);
      -    }
      -
      -    __ mov(idx, 0);
      -    __ sve_whilelt(pgtmp1, mode == LL ? __ B : __ H, idx, cnt);
      -
      -    __ bind(LOOP);
      -      switch (mode) {
      -        case LL:
      -          __ sve_ld1b(ztmp1, __ B, pgtmp1, Address(str1, idx));
      -          __ sve_ld1b(ztmp2, __ B, pgtmp1, Address(str2, idx));
      -          break;
      -        case LU:
      -          __ sve_ld1b(ztmp1, __ H, pgtmp1, Address(str1, idx));
      -          __ sve_ld1h(ztmp2, __ H, pgtmp1, Address(str2, idx, Address::lsl(1)));
      -          break;
      -        case UL:
      -          __ sve_ld1h(ztmp1, __ H, pgtmp1, Address(str1, idx, Address::lsl(1)));
      -          __ sve_ld1b(ztmp2, __ H, pgtmp1, Address(str2, idx));
      -          break;
      -        case UU:
      -          __ sve_ld1h(ztmp1, __ H, pgtmp1, Address(str1, idx, Address::lsl(1)));
      -          __ sve_ld1h(ztmp2, __ H, pgtmp1, Address(str2, idx, Address::lsl(1)));
      -          break;
      -        default: ShouldNotReachHere();
      -      }
      -      __ add(idx, idx, vec_len);
      -
      -      // Compare strings.
      -      __ sve_cmp(Assembler::NE, pgtmp2, mode == LL ? __ B : __ H, pgtmp1, ztmp1, ztmp2);
      -      __ br(__ NE, MATCH);
      -      __ sve_whilelt(pgtmp1, mode == LL ? __ B : __ H, idx, cnt);
      -      __ br(__ LT, LOOP);
      -
      -      // The result has been computed in the caller prior to entering this stub.
      -      __ b(DONE);
      -
      -    __ bind(MATCH);
      -
      -      // Crop the vector to find its location.
      -      __ sve_brkb(pgtmp2, pgtmp1, pgtmp2, false /* isMerge */);
      -
      -      // Extract the first different characters of each string.
      -      __ sve_lasta(rscratch1, mode == LL ? __ B : __ H, pgtmp2, ztmp1);
      -      __ sve_lasta(rscratch2, mode == LL ? __ B : __ H, pgtmp2, ztmp2);
      -
      -      // Compute the difference of the first different characters.
      -      __ sub(result, rscratch1, rscratch2);
      -
      -    __ bind(DONE);
      -      __ ret(lr);
      -
      -    return entry;
      -  }
      -
         // r0  = result
         // r1  = str1
         // r2  = cnt1
      @@ -5249,7 +5153,6 @@ class StubGenerator: public StubCodeGenerator {
         }
       
         void generate_compare_long_strings() {
      -    if (!UseSVE) {
             StubRoutines::aarch64::_compare_long_string_LL
                 = generate_compare_long_string_same_encoding(true);
             StubRoutines::aarch64::_compare_long_string_UU
      @@ -5258,16 +5161,6 @@ class StubGenerator: public StubCodeGenerator {
                 = generate_compare_long_string_different_encoding(true);
             StubRoutines::aarch64::_compare_long_string_UL
                 = generate_compare_long_string_different_encoding(false);
      -    } else {
      -      StubRoutines::aarch64::_compare_long_string_LL
      -          = generate_compare_long_string_sve(LL);
      -      StubRoutines::aarch64::_compare_long_string_UU
      -          = generate_compare_long_string_sve(UU);
      -      StubRoutines::aarch64::_compare_long_string_LU
      -          = generate_compare_long_string_sve(LU);
      -      StubRoutines::aarch64::_compare_long_string_UL
      -          = generate_compare_long_string_sve(UL);
      -    }
         }
       
         // R0 = result
      diff --git a/test/hotspot/gtest/aarch64/aarch64-asmtest.py b/test/hotspot/gtest/aarch64/aarch64-asmtest.py
      index df23b64b05e..f77560ca7eb 100644
      --- a/test/hotspot/gtest/aarch64/aarch64-asmtest.py
      +++ b/test/hotspot/gtest/aarch64/aarch64-asmtest.py
      @@ -1567,8 +1567,6 @@ generate(SpecialCases, [["ccmn",   "__ ccmn(zr, zr, 3u, Assembler::LE);",
                               ["ld1b",    "__ sve_ld1b(z0, __ S, p2, Address(sp, r8));",        "ld1b\t{z0.s}, p2/z, [sp, x8]"],
                               ["ld1b",    "__ sve_ld1b(z0, __ D, p3, Address(sp, 7));",         "ld1b\t{z0.d}, p3/z, [sp, #7, MUL VL]"],
                               ["ld1h",    "__ sve_ld1h(z10, __ H, p1, Address(sp, -8));",       "ld1h\t{z10.h}, p1/z, [sp, #-8, MUL VL]"],
      -                        ["ld1h",
      -                         "__ sve_ld1h(z10, __ H, p0, Address(r4, r2, Address::lsl(1)));", "ld1h\t{z10.h}, p0/z, [x4, x2, LSL 1]"],
                               ["ld1w",    "__ sve_ld1w(z20, __ S, p2, Address(r0, 7));",        "ld1w\t{z20.s}, p2/z, [x0, #7, MUL VL]"],
                               ["ld1b",    "__ sve_ld1b(z30, __ B, p3, Address(sp, r8));",       "ld1b\t{z30.b}, p3/z, [sp, x8]"],
                               ["ld1w",    "__ sve_ld1w(z0, __ S, p4, Address(sp, r28));",       "ld1w\t{z0.s}, p4/z, [sp, x28, LSL #2]"],
      diff --git a/test/hotspot/gtest/aarch64/asmtest.out.h b/test/hotspot/gtest/aarch64/asmtest.out.h
      index 3dab7fca957..661471e67e0 100644
      --- a/test/hotspot/gtest/aarch64/asmtest.out.h
      +++ b/test/hotspot/gtest/aarch64/asmtest.out.h
      @@ -756,7 +756,6 @@
           __ sve_ld1b(z0, __ S, p2, Address(sp, r8));        //       ld1b    {z0.s}, p2/z, [sp, x8]
           __ sve_ld1b(z0, __ D, p3, Address(sp, 7));         //       ld1b    {z0.d}, p3/z, [sp, #7, MUL VL]
           __ sve_ld1h(z10, __ H, p1, Address(sp, -8));       //       ld1h    {z10.h}, p1/z, [sp, #-8, MUL VL]
      -    __ sve_ld1h(z10, __ H, p0, Address(r4, r2, Address::lsl(1))); //    ld1h    {z10.h}, p0/z, [x4, x2, LSL 1]
           __ sve_ld1w(z20, __ S, p2, Address(r0, 7));        //       ld1w    {z20.s}, p2/z, [x0, #7, MUL VL]
           __ sve_ld1b(z30, __ B, p3, Address(sp, r8));       //       ld1b    {z30.b}, p3/z, [sp, x8]
           __ sve_ld1w(z0, __ S, p4, Address(sp, r28));       //       ld1w    {z0.s}, p4/z, [sp, x28, LSL #2]
      @@ -1043,30 +1042,30 @@
           0x9101a1a0,     0xb10a5cc8,     0xd10810aa,     0xf10fd061,
           0x120cb166,     0x321764bc,     0x52174681,     0x720c0227,
           0x9241018e,     0xb25a2969,     0xd278b411,     0xf26aad01,
      -    0x14000000,     0x17ffffd7,     0x1400034d,     0x94000000,
      -    0x97ffffd4,     0x9400034a,     0x3400000a,     0x34fffa2a,
      -    0x340068ea,     0x35000008,     0x35fff9c8,     0x35006888,
      -    0xb400000b,     0xb4fff96b,     0xb400682b,     0xb500001d,
      -    0xb5fff91d,     0xb50067dd,     0x10000013,     0x10fff8b3,
      -    0x10006773,     0x90000013,     0x36300016,     0x3637f836,
      -    0x363066f6,     0x3758000c,     0x375ff7cc,     0x3758668c,
      +    0x14000000,     0x17ffffd7,     0x1400034c,     0x94000000,
      +    0x97ffffd4,     0x94000349,     0x3400000a,     0x34fffa2a,
      +    0x340068ca,     0x35000008,     0x35fff9c8,     0x35006868,
      +    0xb400000b,     0xb4fff96b,     0xb400680b,     0xb500001d,
      +    0xb5fff91d,     0xb50067bd,     0x10000013,     0x10fff8b3,
      +    0x10006753,     0x90000013,     0x36300016,     0x3637f836,
      +    0x363066d6,     0x3758000c,     0x375ff7cc,     0x3758666c,
           0x128313a0,     0x528a32c7,     0x7289173b,     0x92ab3acc,
           0xd2a0bf94,     0xf2c285e8,     0x9358722f,     0x330e652f,
           0x53067f3b,     0x93577c53,     0xb34a1aac,     0xd35a4016,
           0x13946c63,     0x93c3dbc8,     0x54000000,     0x54fff5a0,
      -    0x54006460,     0x54000001,     0x54fff541,     0x54006401,
      -    0x54000002,     0x54fff4e2,     0x540063a2,     0x54000002,
      -    0x54fff482,     0x54006342,     0x54000003,     0x54fff423,
      -    0x540062e3,     0x54000003,     0x54fff3c3,     0x54006283,
      -    0x54000004,     0x54fff364,     0x54006224,     0x54000005,
      -    0x54fff305,     0x540061c5,     0x54000006,     0x54fff2a6,
      -    0x54006166,     0x54000007,     0x54fff247,     0x54006107,
      -    0x54000008,     0x54fff1e8,     0x540060a8,     0x54000009,
      -    0x54fff189,     0x54006049,     0x5400000a,     0x54fff12a,
      -    0x54005fea,     0x5400000b,     0x54fff0cb,     0x54005f8b,
      -    0x5400000c,     0x54fff06c,     0x54005f2c,     0x5400000d,
      -    0x54fff00d,     0x54005ecd,     0x5400000e,     0x54ffefae,
      -    0x54005e6e,     0x5400000f,     0x54ffef4f,     0x54005e0f,
      +    0x54006440,     0x54000001,     0x54fff541,     0x540063e1,
      +    0x54000002,     0x54fff4e2,     0x54006382,     0x54000002,
      +    0x54fff482,     0x54006322,     0x54000003,     0x54fff423,
      +    0x540062c3,     0x54000003,     0x54fff3c3,     0x54006263,
      +    0x54000004,     0x54fff364,     0x54006204,     0x54000005,
      +    0x54fff305,     0x540061a5,     0x54000006,     0x54fff2a6,
      +    0x54006146,     0x54000007,     0x54fff247,     0x540060e7,
      +    0x54000008,     0x54fff1e8,     0x54006088,     0x54000009,
      +    0x54fff189,     0x54006029,     0x5400000a,     0x54fff12a,
      +    0x54005fca,     0x5400000b,     0x54fff0cb,     0x54005f6b,
      +    0x5400000c,     0x54fff06c,     0x54005f0c,     0x5400000d,
      +    0x54fff00d,     0x54005ead,     0x5400000e,     0x54ffefae,
      +    0x54005e4e,     0x5400000f,     0x54ffef4f,     0x54005def,
           0xd40658e1,     0xd4014d22,     0xd4046543,     0xd4273f60,
           0xd44cad80,     0xd503201f,     0xd69f03e0,     0xd6bf03e0,
           0xd5033fdf,     0xd5033e9f,     0xd50332bf,     0xd61f0200,
      @@ -1098,7 +1097,7 @@
           0x791f226d,     0xf95aa2f3,     0xb9587bb7,     0x395f7176,
           0x795d9143,     0x399e7e08,     0x799a2697,     0x79df3422,
           0xb99c2624,     0xfd5c2374,     0xbd5fa1d9,     0xfd1d595a,
      -    0xbd1b1869,     0x58004e5b,     0x1800000b,     0xf8945060,
      +    0xbd1b1869,     0x58004e3b,     0x1800000b,     0xf8945060,
           0xd8000000,     0xf8ae6ba0,     0xf99a0080,     0x1a070035,
           0x3a0700a8,     0x5a0e0367,     0x7a11009b,     0x9a000380,
           0xba1e030c,     0xda0f0320,     0xfa030301,     0x0b340b11,
      @@ -1194,66 +1193,67 @@
           0x25208028,     0x2538cfe0,     0x2578d001,     0x25b8efe2,
           0x25f8f007,     0x2538dfea,     0x25b8dfeb,     0xa400a3e0,
           0xa420a7e0,     0xa4484be0,     0xa467afe0,     0xa4a8a7ea,
      -    0xa4a2408a,     0xa547a814,     0xa4084ffe,     0xa55c53e0,
      -    0xa5e1540b,     0xe400fbf6,     0xe408ffff,     0xe420e7e0,
      -    0xe4484be0,     0xe460efe0,     0xe547e400,     0xe4014be0,
      -    0xe4a84fe0,     0xe5f15000,     0x858043e0,     0x85a043ff,
      -    0xe59f5d08,     0x0420e3e9,     0x0460e3ea,     0x04a0e3eb,
      -    0x04e0e3ec,     0x25104042,     0x25104871,     0x25904861,
      -    0x25904c92,     0x05344020,     0x05744041,     0x05b44062,
      -    0x05f44083,     0x252c8840,     0x253c1420,     0x25681572,
      -    0x25a21ce3,     0x25ea1e34,     0x0522c020,     0x05e6c0a4,
      -    0x2401a001,     0x2443a051,     0x24858881,     0x24c78cd1,
      -    0x24850891,     0x24c70cc1,     0x250f9001,     0x25508051,
      -    0x25802491,     0x25df28c1,     0x25850c81,     0x251e10d1,
      -    0x65816001,     0x65c36051,     0x65854891,     0x65c74cc1,
      -    0x05733820,     0x05b238a4,     0x05f138e6,     0x0570396a,
      -    0x65d0a001,     0x65d6a443,     0x65d4a826,     0x6594ac26,
      -    0x6554ac26,     0x6556ac26,     0x6552ac26,     0x65cbac85,
      -    0x65caac01,     0x65dea833,     0x659ca509,     0x65d8a801,
      -    0x65dcac01,     0x655cb241,     0x0520a1e0,     0x0521a601,
      -    0x052281e0,     0x05238601,     0x04a14026,     0x0568aca7,
      -    0x05b23230,     0x853040af,     0xc5b040af,     0xe57080af,
      -    0xe5b080af,     0x1e601000,     0x1e603000,     0x1e621000,
      -    0x1e623000,     0x1e641000,     0x1e643000,     0x1e661000,
      -    0x1e663000,     0x1e681000,     0x1e683000,     0x1e6a1000,
      -    0x1e6a3000,     0x1e6c1000,     0x1e6c3000,     0x1e6e1000,
      -    0x1e6e3000,     0x1e701000,     0x1e703000,     0x1e721000,
      -    0x1e723000,     0x1e741000,     0x1e743000,     0x1e761000,
      -    0x1e763000,     0x1e781000,     0x1e783000,     0x1e7a1000,
      -    0x1e7a3000,     0x1e7c1000,     0x1e7c3000,     0x1e7e1000,
      -    0x1e7e3000,     0xf8208193,     0xf83101b6,     0xf83c13fe,
      -    0xf821239a,     0xf824309e,     0xf826535e,     0xf8304109,
      -    0xf82c7280,     0xf8216058,     0xf8a08309,     0xf8ba03d0,
      -    0xf8a312ea,     0xf8aa21e4,     0xf8a2310b,     0xf8aa522f,
      -    0xf8a2418a,     0xf8ac71af,     0xf8a26287,     0xf8fa8090,
      -    0xf8e20184,     0xf8f01215,     0xf8f022ab,     0xf8f7334c,
      -    0xf8f751dc,     0xf8eb4038,     0xf8ec715f,     0xf8f06047,
      -    0xf863826d,     0xf8710070,     0xf86113cb,     0xf86521e8,
      -    0xf87d301e,     0xf8745287,     0xf87742bc,     0xf87b70b9,
      -    0xf8616217,     0xb83f8185,     0xb82901fc,     0xb83d13f6,
      -    0xb83320bf,     0xb82e33f0,     0xb830529b,     0xb830416c,
      -    0xb82973c6,     0xb831639b,     0xb8be8147,     0xb8b4008a,
      -    0xb8b81231,     0xb8b623a3,     0xb8af3276,     0xb8b35056,
      -    0xb8af4186,     0xb8b071ab,     0xb8b763c1,     0xb8f38225,
      -    0xb8e202d0,     0xb8ed12aa,     0xb8fd219b,     0xb8fb3023,
      -    0xb8ff5278,     0xb8f14389,     0xb8fb70ef,     0xb8f563f7,
      -    0xb87983e2,     0xb87b0150,     0xb8771073,     0xb8702320,
      -    0xb87a3057,     0xb870508c,     0xb87c43be,     0xb87070db,
      -    0xb86961fd,     0xce273c87,     0xce080ac9,     0xce7e8e9b,
      -    0xce808b45,     0xce79806e,     0xce758768,     0xcec0835a,
      -    0xce608ad8,     0x043100c4,     0x046105e3,     0x65c900a6,
      -    0x65d60a87,     0x65c80545,     0x0416a63e,     0x04001f8b,
      -    0x0450979a,     0x04dabe0d,     0x045381a5,     0x04918b4f,
      -    0x049006cb,     0x0497a264,     0x045eadd1,     0x04881062,
      -    0x040a04d7,     0x04810f71,     0x04dca450,     0x65c084c3,
      -    0x65cd8d93,     0x65c69a68,     0x65878ae0,     0x65c29db3,
      -    0x049da0e6,     0x6582b911,     0x65c0b6d6,     0x65c1a1e2,
      -    0x65cda494,     0x65c18107,     0x65af1493,     0x65e52b36,
      -    0x65ab4ed0,     0x65f06a8d,     0x0451448f,     0x049c7c86,
      -    0x0429335d,     0x04bc3162,     0x047a3027,     0x04e831d1,
      -    0x05a56b15,     0x05b66e35,     0x041a367d,     0x041832e4,
      -    0x04d926f3,     0x04482113,     0x04ca3a2e,     0x658727d5,
      -    0x6586358a,     0x65d82709,     0x044138c4,
      +    0xa547a814,     0xa4084ffe,     0xa55c53e0,     0xa5e1540b,
      +    0xe400fbf6,     0xe408ffff,     0xe420e7e0,     0xe4484be0,
      +    0xe460efe0,     0xe547e400,     0xe4014be0,     0xe4a84fe0,
      +    0xe5f15000,     0x858043e0,     0x85a043ff,     0xe59f5d08,
      +    0x0420e3e9,     0x0460e3ea,     0x04a0e3eb,     0x04e0e3ec,
      +    0x25104042,     0x25104871,     0x25904861,     0x25904c92,
      +    0x05344020,     0x05744041,     0x05b44062,     0x05f44083,
      +    0x252c8840,     0x253c1420,     0x25681572,     0x25a21ce3,
      +    0x25ea1e34,     0x0522c020,     0x05e6c0a4,     0x2401a001,
      +    0x2443a051,     0x24858881,     0x24c78cd1,     0x24850891,
      +    0x24c70cc1,     0x250f9001,     0x25508051,     0x25802491,
      +    0x25df28c1,     0x25850c81,     0x251e10d1,     0x65816001,
      +    0x65c36051,     0x65854891,     0x65c74cc1,     0x05733820,
      +    0x05b238a4,     0x05f138e6,     0x0570396a,     0x65d0a001,
      +    0x65d6a443,     0x65d4a826,     0x6594ac26,     0x6554ac26,
      +    0x6556ac26,     0x6552ac26,     0x65cbac85,     0x65caac01,
      +    0x65dea833,     0x659ca509,     0x65d8a801,     0x65dcac01,
      +    0x655cb241,     0x0520a1e0,     0x0521a601,     0x052281e0,
      +    0x05238601,     0x04a14026,     0x0568aca7,     0x05b23230,
      +    0x853040af,     0xc5b040af,     0xe57080af,     0xe5b080af,
      +    0x1e601000,     0x1e603000,     0x1e621000,     0x1e623000,
      +    0x1e641000,     0x1e643000,     0x1e661000,     0x1e663000,
      +    0x1e681000,     0x1e683000,     0x1e6a1000,     0x1e6a3000,
      +    0x1e6c1000,     0x1e6c3000,     0x1e6e1000,     0x1e6e3000,
      +    0x1e701000,     0x1e703000,     0x1e721000,     0x1e723000,
      +    0x1e741000,     0x1e743000,     0x1e761000,     0x1e763000,
      +    0x1e781000,     0x1e783000,     0x1e7a1000,     0x1e7a3000,
      +    0x1e7c1000,     0x1e7c3000,     0x1e7e1000,     0x1e7e3000,
      +    0xf8208193,     0xf83101b6,     0xf83c13fe,     0xf821239a,
      +    0xf824309e,     0xf826535e,     0xf8304109,     0xf82c7280,
      +    0xf8216058,     0xf8a08309,     0xf8ba03d0,     0xf8a312ea,
      +    0xf8aa21e4,     0xf8a2310b,     0xf8aa522f,     0xf8a2418a,
      +    0xf8ac71af,     0xf8a26287,     0xf8fa8090,     0xf8e20184,
      +    0xf8f01215,     0xf8f022ab,     0xf8f7334c,     0xf8f751dc,
      +    0xf8eb4038,     0xf8ec715f,     0xf8f06047,     0xf863826d,
      +    0xf8710070,     0xf86113cb,     0xf86521e8,     0xf87d301e,
      +    0xf8745287,     0xf87742bc,     0xf87b70b9,     0xf8616217,
      +    0xb83f8185,     0xb82901fc,     0xb83d13f6,     0xb83320bf,
      +    0xb82e33f0,     0xb830529b,     0xb830416c,     0xb82973c6,
      +    0xb831639b,     0xb8be8147,     0xb8b4008a,     0xb8b81231,
      +    0xb8b623a3,     0xb8af3276,     0xb8b35056,     0xb8af4186,
      +    0xb8b071ab,     0xb8b763c1,     0xb8f38225,     0xb8e202d0,
      +    0xb8ed12aa,     0xb8fd219b,     0xb8fb3023,     0xb8ff5278,
      +    0xb8f14389,     0xb8fb70ef,     0xb8f563f7,     0xb87983e2,
      +    0xb87b0150,     0xb8771073,     0xb8702320,     0xb87a3057,
      +    0xb870508c,     0xb87c43be,     0xb87070db,     0xb86961fd,
      +    0xce273c87,     0xce080ac9,     0xce7e8e9b,     0xce808b45,
      +    0xce79806e,     0xce758768,     0xcec0835a,     0xce608ad8,
      +    0x043100c4,     0x046105e3,     0x65c900a6,     0x65d60a87,
      +    0x65c80545,     0x0416a63e,     0x04001f8b,     0x0450979a,
      +    0x04dabe0d,     0x045381a5,     0x04918b4f,     0x049006cb,
      +    0x0497a264,     0x045eadd1,     0x04881062,     0x040a04d7,
      +    0x04810f71,     0x04dca450,     0x65c084c3,     0x65cd8d93,
      +    0x65c69a68,     0x65878ae0,     0x65c29db3,     0x049da0e6,
      +    0x6582b911,     0x65c0b6d6,     0x65c1a1e2,     0x65cda494,
      +    0x65c18107,     0x65af1493,     0x65e52b36,     0x65ab4ed0,
      +    0x65f06a8d,     0x0451448f,     0x049c7c86,     0x0429335d,
      +    0x04bc3162,     0x047a3027,     0x04e831d1,     0x05a56b15,
      +    0x05b66e35,     0x041a367d,     0x041832e4,     0x04d926f3,
      +    0x04482113,     0x04ca3a2e,     0x658727d5,     0x6586358a,
      +    0x65d82709,     0x044138c4,
         };
       // END  Generated code -- do not edit
      +
      diff --git a/test/micro/org/openjdk/bench/java/lang/StringCompareToDifferentLength.java b/test/micro/org/openjdk/bench/java/lang/StringCompareToDifferentLength.java
      deleted file mode 100644
      index fb08e32efac..00000000000
      --- a/test/micro/org/openjdk/bench/java/lang/StringCompareToDifferentLength.java
      +++ /dev/null
      @@ -1,148 +0,0 @@
      -/*
      - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
      - * Copyright (c) 2021, BELLSOFT. All rights reserved.
      - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      - *
      - * This code is free software; you can redistribute it and/or modify it
      - * under the terms of the GNU General Public License version 2 only, as
      - * published by the Free Software Foundation.
      - *
      - * This code is distributed in the hope that it will be useful, but WITHOUT
      - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      - * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      - * version 2 for more details (a copy is included in the LICENSE file that
      - * accompanied this code).
      - *
      - * You should have received a copy of the GNU General Public License version
      - * 2 along with this work; if not, write to the Free Software Foundation,
      - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
      - *
      - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
      - * or visit www.oracle.com if you need additional information or have any
      - * questions.
      - */
      -
      -package com.arm.benchmarks.intrinsics;
      -
      -import java.util.concurrent.TimeUnit;
      -
      -import org.openjdk.jmh.annotations.Benchmark;
      -import org.openjdk.jmh.annotations.BenchmarkMode;
      -import org.openjdk.jmh.annotations.CompilerControl;
      -import org.openjdk.jmh.annotations.Fork;
      -import org.openjdk.jmh.annotations.Level;
      -import org.openjdk.jmh.annotations.Measurement;
      -import org.openjdk.jmh.annotations.Mode;
      -import org.openjdk.jmh.annotations.OutputTimeUnit;
      -import org.openjdk.jmh.annotations.Param;
      -import org.openjdk.jmh.annotations.Scope;
      -import org.openjdk.jmh.annotations.Setup;
      -import org.openjdk.jmh.annotations.State;
      -import org.openjdk.jmh.annotations.Warmup;
      -
      -import org.openjdk.jmh.infra.Blackhole;
      -
      -/**
      - * This benchmark modified from test/hotspot/jtreg/compiler/intrinsics/string/TestStringCompareToDifferentLength.java
      - * This benchmark can be used to measure performance of compareTo() in
      - * (Latin1, Latin1), (Latin1, UTF16), (UTF16, Latin1), and (UTF16, UTF16)
      - * comparisons.
      - */
      -
      -@BenchmarkMode(Mode.AverageTime)
      -@OutputTimeUnit(TimeUnit.MILLISECONDS)
      -@State(Scope.Benchmark)
      -@Measurement(iterations = 3, time = 1000, timeUnit = TimeUnit.MILLISECONDS)
      -@Warmup(iterations = 3, time = 1000, timeUnit = TimeUnit.MILLISECONDS)
      -@CompilerControl(CompilerControl.Mode.DONT_INLINE)
      -public class StringCompareToDifferentLength {
      -
      -    @State(Scope.Benchmark)
      -    public static class Input {
      -        @Param({"24", "36", "72", "128", "256", "512"})
      -        public int size;
      -
      -        @Param({"2"})
      -        public int delta;
      -
      -        int count = 100000;
      -        String longLatin1;
      -        String shortLatin1;
      -        String longUTF16FirstChar;
      -        String shortUTF16FirstChar;
      -        String longUTF16LastChar;
      -        String shortUTF16LastChar;
      -
      -        /**
      -         * Initialize. New array objects and set initial values.
      -         */
      -        @Setup(Level.Trial)
      -        public void setup() throws Exception {
      -            char[] strsrc = new char[size + delta];
      -            // generate ASCII string
      -            for (int i = 0; i < size + delta; i++) {
      -                strsrc[i] = (char) ('a' + (i % 26));
      -            }
      -
      -            longLatin1 = new String(strsrc);
      -            shortLatin1 = longLatin1.substring(0, size);
      -            longUTF16LastChar = longLatin1.substring(0, longLatin1.length() - 1) + '\ubeef';
      -            longUTF16FirstChar = '\ubeef' + longLatin1.substring(1, longLatin1.length());
      -            shortUTF16LastChar = shortLatin1.substring(0, shortLatin1.length() - 1) + '\ubeef';
      -            shortUTF16FirstChar = longUTF16FirstChar.substring(0, size);
      -        }
      -    }
      -
      -    private int runCompareTo(String str2, String str1) {
      -        return str1.compareTo(str2);
      -    }
      -
      -    /**
      -     * latin1-latin1
      -     */
      -    @Benchmark
      -    public void compareToLL(Input in, Blackhole blackhole) {
      -        int res = 0;
      -        for (int i = 0; i < in.count; ++i) {
      -            res += runCompareTo(in.longLatin1, in.shortLatin1);
      -        }
      -        blackhole.consume(res);
      -    }
      -
      -    /**
      -     * UTF16-UTF16
      -     */
      -    @Benchmark
      -    public void compareToUU(Input in, Blackhole blackhole) {
      -        int res = 0;
      -        for (int i = 0; i < in.count; ++i) {
      -            res += runCompareTo(in.longUTF16FirstChar, in.shortUTF16FirstChar);
      -        }
      -        blackhole.consume(res);
      -    }
      -
      -    /**
      -     * latin1-UTF16
      -     */
      -    @Benchmark
      -    public void compareToLU(Input in, Blackhole blackhole) {
      -        int res = 0;
      -        for (int i = 0; i < in.count; ++i) {
      -            res += runCompareTo(in.longUTF16LastChar, in.shortLatin1);
      -        }
      -        blackhole.consume(res);
      -    }
      -
      -    /**
      -     * UTF16-latin1
      -     */
      -    @Benchmark
      -    public void compareToUL(Input in, Blackhole blackhole) {
      -        int res = 0;
      -        for (int i = 0; i < in.count; ++i) {
      -            res += runCompareTo(in.longLatin1, in.shortUTF16LastChar);
      -        }
      -        blackhole.consume(res);
      -    }
      -}
      -
      -- 
      GitLab
      
      
      From 8d9004b7f4fd9b53d3f2240b382e7d71d7399125 Mon Sep 17 00:00:00 2001
      From: =?UTF-8?q?Hannes=20Walln=C3=B6fer?= 
      Date: Thu, 14 Oct 2021 12:19:26 +0000
      Subject: [PATCH 207/385] 8274781: Use monospace font for enclosing interface
      
      Reviewed-by: prappo
      ---
       .../internal/doclets/formats/html/ClassWriterImpl.java     | 7 ++-----
       .../jdk/javadoc/doclet/testHiddenTag/TestHiddenTag.java    | 2 +-
       .../jdk/javadoc/doclet/testLinkTaglet/TestLinkTaglet.java  | 5 +++--
       3 files changed, 6 insertions(+), 8 deletions(-)
      
      diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriterImpl.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriterImpl.java
      index 1e0d7286276..40db035c8b9 100644
      --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriterImpl.java
      +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriterImpl.java
      @@ -381,10 +381,7 @@ public class ClassWriterImpl extends SubWriterHolderWriter implements ClassWrite
                       dl.add(HtmlTree.DT(utils.isInterface(e)
                               ? contents.enclosingInterfaceLabel
                               : contents.enclosingClassLabel));
      -                Content dd = new HtmlTree(TagName.DD);
      -                dd.add(getLink(new HtmlLinkInfo(configuration,
      -                        HtmlLinkInfo.Kind.CLASS, e)));
      -                dl.add(dd);
      +                dl.add(HtmlTree.DD(getClassLinks(HtmlLinkInfo.Kind.CLASS, List.of(e))));
                       classInfoTree.add(dl);
                       return null;
                   }
      @@ -404,7 +401,7 @@ public class ClassWriterImpl extends SubWriterHolderWriter implements ClassWrite
           }
       
           public boolean isFunctionalInterface() {
      -        List annotationMirrors = ((Element) typeElement).getAnnotationMirrors();
      +        List annotationMirrors = typeElement.getAnnotationMirrors();
               for (AnnotationMirror anno : annotationMirrors) {
                   if (utils.isFunctionalInterface(anno)) {
                       return true;
      diff --git a/test/langtools/jdk/javadoc/doclet/testHiddenTag/TestHiddenTag.java b/test/langtools/jdk/javadoc/doclet/testHiddenTag/TestHiddenTag.java
      index a4d1f75ae40..75b38453614 100644
      --- a/test/langtools/jdk/javadoc/doclet/testHiddenTag/TestHiddenTag.java
      +++ b/test/langtools/jdk/javadoc/doclet/testHiddenTag/TestHiddenTag.java
      @@ -143,7 +143,7 @@ public class TestHiddenTag extends JavadocTester {
               checkOutput("pkg1/InvisibleParent.VisibleInner.html", true,
                       """
                           
      Enclosing class:
      -
      pkg1.InvisibleParent<T extends pkg1.InvisibleParent>
      +
      pkg1.InvisibleParent<T extends pkg1.InvisibleParent>
      """); checkOutput("pkg1/package-summary.html", false, "A.InvisibleInner"); diff --git a/test/langtools/jdk/javadoc/doclet/testLinkTaglet/TestLinkTaglet.java b/test/langtools/jdk/javadoc/doclet/testLinkTaglet/TestLinkTaglet.java index 3c3868b932a..5f294ce9748 100644 --- a/test/langtools/jdk/javadoc/doclet/testLinkTaglet/TestLinkTaglet.java +++ b/test/langtools/jdk/javadoc/doclet/testLinkTaglet/TestLinkTaglet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2021, Oracle and/or its affiliates. All rights reserved. * 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,7 @@ /* * @test * @bug 4732864 6280605 7064544 8014636 8016328 8025633 8071982 8182765 + * 8274781 * @summary Make sure that you can link from one member to another using * non-qualified name, furthermore, ensure the right one is linked. * @library ../../lib @@ -70,7 +71,7 @@ public class TestLinkTaglet extends JavadocTester { """
      Enclosing class:
      -
      C
      +
      C
      """); checkOutput(Output.OUT, false, -- GitLab From 3b0b6adc3d547fcf4b971536d2404c342d18046f Mon Sep 17 00:00:00 2001 From: Zhengyu Gu Date: Thu, 14 Oct 2021 12:52:12 +0000 Subject: [PATCH 208/385] 8275226: Shenandoah: Relax memory constraint for worker claiming tasks/ranges Reviewed-by: shade --- src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.cpp | 2 +- src/hotspot/share/gc/shenandoah/shenandoahNMethod.cpp | 4 ++-- .../share/gc/shenandoah/shenandoahReferenceProcessor.cpp | 4 ++-- src/hotspot/share/gc/shenandoah/shenandoahTaskqueue.hpp | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.cpp b/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.cpp index f829b16cebc..b29633d7ff4 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.cpp @@ -87,7 +87,7 @@ void ShenandoahParallelCodeHeapIterator::parallel_blobs_do(CodeBlobClosure* f) { int current = count++; if ((current & stride_mask) == 0) { process_block = (current >= _claimed_idx) && - (Atomic::cmpxchg(&_claimed_idx, current, current + stride) == current); + (Atomic::cmpxchg(&_claimed_idx, current, current + stride, memory_order_relaxed) == current); } if (process_block) { if (cb->is_alive()) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahNMethod.cpp b/src/hotspot/share/gc/shenandoah/shenandoahNMethod.cpp index a35d54259dd..755e29ce57e 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahNMethod.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahNMethod.cpp @@ -493,7 +493,7 @@ void ShenandoahNMethodTableSnapshot::parallel_blobs_do(CodeBlobClosure *f) { size_t max = (size_t)_limit; while (_claimed < max) { - size_t cur = Atomic::fetch_and_add(&_claimed, stride); + size_t cur = Atomic::fetch_and_add(&_claimed, stride, memory_order_relaxed); size_t start = cur; size_t end = MIN2(cur + stride, max); if (start >= max) break; @@ -520,7 +520,7 @@ void ShenandoahNMethodTableSnapshot::concurrent_nmethods_do(NMethodClosure* cl) ShenandoahNMethod** list = _list->list(); size_t max = (size_t)_limit; while (_claimed < max) { - size_t cur = Atomic::fetch_and_add(&_claimed, stride); + size_t cur = Atomic::fetch_and_add(&_claimed, stride, memory_order_relaxed); size_t start = cur; size_t end = MIN2(cur + stride, max); if (start >= max) break; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.cpp b/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.cpp index 2d185e2066a..e843f3b250b 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.cpp @@ -453,14 +453,14 @@ void ShenandoahReferenceProcessor::process_references(ShenandoahRefProcThreadLoc void ShenandoahReferenceProcessor::work() { // Process discovered references uint max_workers = ShenandoahHeap::heap()->max_workers(); - uint worker_id = Atomic::add(&_iterate_discovered_list_id, 1U) - 1; + uint worker_id = Atomic::add(&_iterate_discovered_list_id, 1U, memory_order_relaxed) - 1; while (worker_id < max_workers) { if (UseCompressedOops) { process_references(_ref_proc_thread_locals[worker_id], worker_id); } else { process_references(_ref_proc_thread_locals[worker_id], worker_id); } - worker_id = Atomic::add(&_iterate_discovered_list_id, 1U) - 1; + worker_id = Atomic::add(&_iterate_discovered_list_id, 1U, memory_order_relaxed) - 1; } } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahTaskqueue.hpp b/src/hotspot/share/gc/shenandoah/shenandoahTaskqueue.hpp index bc38a0936eb..5ce731e6fcc 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahTaskqueue.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahTaskqueue.hpp @@ -337,7 +337,7 @@ T* ParallelClaimableQueueSet::claim_next() { return NULL; } - jint index = Atomic::add(&_claimed_index, 1); + jint index = Atomic::add(&_claimed_index, 1, memory_order_relaxed); if (index <= size) { return GenericTaskQueueSet::queue((uint)index - 1); -- GitLab From 54b887076612c0eaa410a849178f8ba0c4ed3eeb Mon Sep 17 00:00:00 2001 From: Per Liden Date: Thu, 14 Oct 2021 14:05:36 +0000 Subject: [PATCH 209/385] 8275035: Clean up worker thread infrastructure Reviewed-by: stefank, ayang --- .../share/gc/epsilon/epsilonArguments.cpp | 1 + src/hotspot/share/gc/epsilon/epsilonHeap.cpp | 1 + ...1BatchedGangTask.cpp => g1BatchedTask.cpp} | 20 +- ...1BatchedGangTask.hpp => g1BatchedTask.hpp} | 30 +- src/hotspot/share/gc/g1/g1CollectedHeap.cpp | 8 +- src/hotspot/share/gc/g1/g1CollectedHeap.hpp | 16 +- .../share/gc/g1/g1CollectionSetCandidates.hpp | 2 +- .../share/gc/g1/g1CollectionSetChooser.cpp | 6 +- .../share/gc/g1/g1CollectionSetChooser.hpp | 4 +- src/hotspot/share/gc/g1/g1ConcurrentMark.cpp | 50 +-- src/hotspot/share/gc/g1/g1ConcurrentMark.hpp | 15 +- src/hotspot/share/gc/g1/g1EvacFailure.cpp | 2 +- src/hotspot/share/gc/g1/g1EvacFailure.hpp | 4 +- src/hotspot/share/gc/g1/g1FullCollector.cpp | 6 +- src/hotspot/share/gc/g1/g1FullCollector.hpp | 4 +- src/hotspot/share/gc/g1/g1FullGCTask.hpp | 6 +- src/hotspot/share/gc/g1/g1HeapVerifier.cpp | 4 +- .../share/gc/g1/g1PageBasedVirtualSpace.cpp | 6 +- .../share/gc/g1/g1PageBasedVirtualSpace.hpp | 4 +- .../share/gc/g1/g1ParallelCleaning.cpp | 2 +- .../share/gc/g1/g1ParallelCleaning.hpp | 2 +- .../share/gc/g1/g1RegionToSpaceMapper.cpp | 8 +- .../share/gc/g1/g1RegionToSpaceMapper.hpp | 4 +- src/hotspot/share/gc/g1/g1RemSet.cpp | 16 +- src/hotspot/share/gc/g1/g1RemSet.hpp | 6 +- src/hotspot/share/gc/g1/g1YoungCollector.cpp | 26 +- src/hotspot/share/gc/g1/g1YoungCollector.hpp | 12 +- .../gc/g1/g1YoungGCPostEvacuateTasks.cpp | 6 +- .../gc/g1/g1YoungGCPostEvacuateTasks.hpp | 6 +- src/hotspot/share/gc/g1/heapRegionManager.cpp | 32 +- src/hotspot/share/gc/g1/heapRegionManager.hpp | 16 +- .../share/gc/parallel/mutableNUMASpace.cpp | 4 +- .../share/gc/parallel/mutableNUMASpace.hpp | 2 +- .../share/gc/parallel/mutableSpace.cpp | 6 +- .../share/gc/parallel/mutableSpace.hpp | 4 +- .../gc/parallel/parallelScavengeHeap.cpp | 2 +- .../gc/parallel/parallelScavengeHeap.hpp | 8 +- .../share/gc/parallel/psCompactionManager.cpp | 8 +- src/hotspot/share/gc/parallel/psOldGen.cpp | 2 +- .../share/gc/parallel/psParallelCompact.cpp | 19 +- src/hotspot/share/gc/parallel/psScavenge.cpp | 11 +- src/hotspot/share/gc/parallel/psYoungGen.cpp | 4 +- src/hotspot/share/gc/shared/collectedHeap.hpp | 6 +- .../share/gc/shared/genCollectedHeap.cpp | 2 +- .../share/gc/shared/genCollectedHeap.hpp | 2 +- .../share/gc/shared/parallelCleaning.hpp | 2 +- .../share/gc/shared/preservedMarks.cpp | 11 +- .../share/gc/shared/preservedMarks.hpp | 10 +- src/hotspot/share/gc/shared/pretouchTask.cpp | 11 +- src/hotspot/share/gc/shared/pretouchTask.hpp | 6 +- .../share/gc/shared/referenceProcessor.cpp | 10 +- .../share/gc/shared/referenceProcessor.hpp | 6 +- src/hotspot/share/gc/shared/space.hpp | 2 +- src/hotspot/share/gc/shared/weakProcessor.cpp | 2 +- src/hotspot/share/gc/shared/weakProcessor.hpp | 10 +- .../share/gc/shared/weakProcessor.inline.hpp | 30 +- src/hotspot/share/gc/shared/workerManager.hpp | 113 ------ src/hotspot/share/gc/shared/workerThread.cpp | 161 ++++++++ src/hotspot/share/gc/shared/workerThread.hpp | 164 ++++++++ src/hotspot/share/gc/shared/workerUtils.cpp | 136 +++++++ src/hotspot/share/gc/shared/workerUtils.hpp | 148 ++++++++ src/hotspot/share/gc/shared/workgroup.cpp | 351 ------------------ src/hotspot/share/gc/shared/workgroup.hpp | 328 ---------------- .../gc/shenandoah/shenandoahCodeRoots.cpp | 16 +- .../gc/shenandoah/shenandoahCodeRoots.hpp | 6 +- .../gc/shenandoah/shenandoahConcurrentGC.cpp | 12 +- .../shenandoah/shenandoahConcurrentMark.cpp | 16 +- .../share/gc/shenandoah/shenandoahFullGC.cpp | 24 +- .../share/gc/shenandoah/shenandoahGC.cpp | 8 +- .../share/gc/shenandoah/shenandoahHeap.cpp | 30 +- .../share/gc/shenandoah/shenandoahHeap.hpp | 10 +- .../gc/shenandoah/shenandoahHeap.inline.hpp | 4 +- .../shenandoah/shenandoahParallelCleaning.cpp | 2 +- .../shenandoah/shenandoahParallelCleaning.hpp | 6 +- .../shenandoahParallelCleaning.inline.hpp | 2 +- .../shenandoahReferenceProcessor.cpp | 6 +- .../shenandoahReferenceProcessor.hpp | 4 +- .../share/gc/shenandoah/shenandoahSTWMark.cpp | 6 +- .../gc/shenandoah/shenandoahVerifier.cpp | 8 +- .../gc/shenandoah/shenandoahWorkGroup.cpp | 14 +- .../gc/shenandoah/shenandoahWorkGroup.hpp | 20 +- src/hotspot/share/gc/z/zCollectedHeap.cpp | 2 +- src/hotspot/share/gc/z/zCollectedHeap.hpp | 2 +- src/hotspot/share/gc/z/zRuntimeWorkers.cpp | 14 +- src/hotspot/share/gc/z/zRuntimeWorkers.hpp | 6 +- src/hotspot/share/gc/z/zTask.cpp | 18 +- src/hotspot/share/gc/z/zTask.hpp | 12 +- src/hotspot/share/gc/z/zWorkers.cpp | 24 +- src/hotspot/share/gc/z/zWorkers.hpp | 4 +- src/hotspot/share/logging/logPrefix.hpp | 3 +- src/hotspot/share/logging/logTag.hpp | 3 +- src/hotspot/share/memory/heapInspection.cpp | 15 +- src/hotspot/share/memory/heapInspection.hpp | 6 +- src/hotspot/share/runtime/nonJavaThread.hpp | 25 -- src/hotspot/share/runtime/safepoint.cpp | 9 +- src/hotspot/share/runtime/sweeper.cpp | 2 +- src/hotspot/share/runtime/thread.hpp | 1 - src/hotspot/share/services/heapDumper.cpp | 14 +- .../gtest/gc/g1/test_g1BatchedGangTask.cpp | 40 +- test/hotspot/gtest/gc/g1/test_g1CardSet.cpp | 16 +- .../gtest/gc/g1/test_stressCommitUncommit.cpp | 26 +- .../gtest/gc/shared/test_oopStorage.cpp | 28 +- .../gc/shared/test_oopStorage_parperf.cpp | 24 +- 103 files changed, 1096 insertions(+), 1298 deletions(-) rename src/hotspot/share/gc/g1/{g1BatchedGangTask.cpp => g1BatchedTask.cpp} (84%) rename src/hotspot/share/gc/g1/{g1BatchedGangTask.hpp => g1BatchedTask.hpp} (85%) delete mode 100644 src/hotspot/share/gc/shared/workerManager.hpp create mode 100644 src/hotspot/share/gc/shared/workerThread.cpp create mode 100644 src/hotspot/share/gc/shared/workerThread.hpp create mode 100644 src/hotspot/share/gc/shared/workerUtils.cpp create mode 100644 src/hotspot/share/gc/shared/workerUtils.hpp delete mode 100644 src/hotspot/share/gc/shared/workgroup.cpp delete mode 100644 src/hotspot/share/gc/shared/workgroup.hpp diff --git a/src/hotspot/share/gc/epsilon/epsilonArguments.cpp b/src/hotspot/share/gc/epsilon/epsilonArguments.cpp index 17c4783d5c8..9196d49e18b 100644 --- a/src/hotspot/share/gc/epsilon/epsilonArguments.cpp +++ b/src/hotspot/share/gc/epsilon/epsilonArguments.cpp @@ -27,6 +27,7 @@ #include "gc/epsilon/epsilonHeap.hpp" #include "gc/shared/gcArguments.hpp" #include "gc/shared/tlab_globals.hpp" +#include "logging/log.hpp" #include "runtime/globals.hpp" #include "runtime/globals_extension.hpp" diff --git a/src/hotspot/share/gc/epsilon/epsilonHeap.cpp b/src/hotspot/share/gc/epsilon/epsilonHeap.cpp index d4b2d4e6bfa..332b5f792ca 100644 --- a/src/hotspot/share/gc/epsilon/epsilonHeap.cpp +++ b/src/hotspot/share/gc/epsilon/epsilonHeap.cpp @@ -29,6 +29,7 @@ #include "gc/epsilon/epsilonThreadLocalData.hpp" #include "gc/shared/gcArguments.hpp" #include "gc/shared/locationPrinter.inline.hpp" +#include "logging/log.hpp" #include "memory/allocation.hpp" #include "memory/allocation.inline.hpp" #include "memory/metaspaceUtils.hpp" diff --git a/src/hotspot/share/gc/g1/g1BatchedGangTask.cpp b/src/hotspot/share/gc/g1/g1BatchedTask.cpp similarity index 84% rename from src/hotspot/share/gc/g1/g1BatchedGangTask.cpp rename to src/hotspot/share/gc/g1/g1BatchedTask.cpp index 0c108d8d86f..9ab47e9c4c9 100644 --- a/src/hotspot/share/gc/g1/g1BatchedGangTask.cpp +++ b/src/hotspot/share/gc/g1/g1BatchedTask.cpp @@ -24,7 +24,7 @@ #include "precompiled.hpp" -#include "gc/g1/g1BatchedGangTask.hpp" +#include "gc/g1/g1BatchedTask.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1GCParPhaseTimesTracker.hpp" #include "runtime/atomic.hpp" @@ -40,30 +40,30 @@ const char* G1AbstractSubTask::name() const { return g1h->phase_times()->phase_name(_tag); } -bool G1BatchedGangTask::try_claim_serial_task(int& task) { +bool G1BatchedTask::try_claim_serial_task(int& task) { task = Atomic::fetch_and_add(&_num_serial_tasks_done, 1); return task < _serial_tasks.length(); } -void G1BatchedGangTask::add_serial_task(G1AbstractSubTask* task) { +void G1BatchedTask::add_serial_task(G1AbstractSubTask* task) { assert(task != nullptr, "must be"); _serial_tasks.push(task); } -void G1BatchedGangTask::add_parallel_task(G1AbstractSubTask* task) { +void G1BatchedTask::add_parallel_task(G1AbstractSubTask* task) { assert(task != nullptr, "must be"); _parallel_tasks.push(task); } -G1BatchedGangTask::G1BatchedGangTask(const char* name, G1GCPhaseTimes* phase_times) : - AbstractGangTask(name), +G1BatchedTask::G1BatchedTask(const char* name, G1GCPhaseTimes* phase_times) : + WorkerTask(name), _num_serial_tasks_done(0), _phase_times(phase_times), _serial_tasks(), _parallel_tasks() { } -uint G1BatchedGangTask::num_workers_estimate() const { +uint G1BatchedTask::num_workers_estimate() const { double sum = 0.0; for (G1AbstractSubTask* task : _serial_tasks) { sum += task->worker_cost(); @@ -74,7 +74,7 @@ uint G1BatchedGangTask::num_workers_estimate() const { return ceil(sum); } -void G1BatchedGangTask::set_max_workers(uint max_workers) { +void G1BatchedTask::set_max_workers(uint max_workers) { for (G1AbstractSubTask* task : _serial_tasks) { task->set_max_workers(max_workers); } @@ -83,7 +83,7 @@ void G1BatchedGangTask::set_max_workers(uint max_workers) { } } -void G1BatchedGangTask::work(uint worker_id) { +void G1BatchedTask::work(uint worker_id) { int t = 0; while (try_claim_serial_task(t)) { G1AbstractSubTask* task = _serial_tasks.at(t); @@ -96,7 +96,7 @@ void G1BatchedGangTask::work(uint worker_id) { } } -G1BatchedGangTask::~G1BatchedGangTask() { +G1BatchedTask::~G1BatchedTask() { assert(Atomic::load(&_num_serial_tasks_done) >= _serial_tasks.length(), "Only %d tasks of %d claimed", Atomic::load(&_num_serial_tasks_done), _serial_tasks.length()); diff --git a/src/hotspot/share/gc/g1/g1BatchedGangTask.hpp b/src/hotspot/share/gc/g1/g1BatchedTask.hpp similarity index 85% rename from src/hotspot/share/gc/g1/g1BatchedGangTask.hpp rename to src/hotspot/share/gc/g1/g1BatchedTask.hpp index 30917402ae4..0a627c3a4c9 100644 --- a/src/hotspot/share/gc/g1/g1BatchedGangTask.hpp +++ b/src/hotspot/share/gc/g1/g1BatchedTask.hpp @@ -22,18 +22,18 @@ * */ -#ifndef SHARE_GC_G1_G1BATCHEDGANGTASK_HPP -#define SHARE_GC_G1_G1BATCHEDGANGTASK_HPP +#ifndef SHARE_GC_G1_G1BATCHEDTASK_HPP +#define SHARE_GC_G1_G1BATCHEDTASK_HPP #include "gc/g1/g1GCPhaseTimes.hpp" -#include "gc/shared/workgroup.hpp" +#include "gc/shared/workerThread.hpp" #include "memory/allocation.hpp" template class GrowableArrayCHeap; // G1AbstractSubTask represents a task to be performed either within a -// G1BatchedGangTask running on a single worker ("serially") or multiple workers +// G1BatchedTask running on a single worker ("serially") or multiple workers // ("in parallel"). A G1AbstractSubTask is always associated with a phase tag // that is used to automatically store timing information. // @@ -46,7 +46,7 @@ class GrowableArrayCHeap; // splits across the heap in some way. Current examples would be clearing the // card table. // -// See G1BatchedGangTask for information on execution. +// See G1BatchedTask for information on execution. class G1AbstractSubTask : public CHeapObj { G1GCPhaseTimes::GCParPhases _tag; @@ -65,10 +65,10 @@ public: // How many workers (threads) would this task be able to keep busy for at least // as long as to amortize worker startup costs. - // Called by G1BatchedGangTask to determine total number of workers. + // Called by G1BatchedTask to determine total number of workers. virtual double worker_cost() const = 0; - // Called by G1BatchedGangTask to provide information about the the maximum + // Called by G1BatchedTask to provide information about the the maximum // number of workers for all subtasks after it has been determined. virtual void set_max_workers(uint max_workers) { } @@ -81,7 +81,7 @@ public: const char* name() const; }; -// G1BatchedGangTask runs a set of G1AbstractSubTask using a work gang. +// G1BatchedTask runs a set of G1AbstractSubTask using workers. // // Subclasses of this class add their G1AbstractSubTasks into either the list // of "serial" or the list of "parallel" tasks. They are supposed to be the owners @@ -94,7 +94,7 @@ public: // add_parallel_task(new SomeOtherSubTask()); // [...] // -// During execution in the work gang, this class will make sure that the "serial" +// During execution in workers, this class will make sure that the "serial" // tasks are executed by a single worker exactly once, but different "serial" // tasks may be executed in parallel using different workers. "Parallel" tasks' // do_work() method may be called by different workers passing a different @@ -119,13 +119,13 @@ public: // 4) T::do_work() // potentially in parallel with any other registered G1AbstractSubTask // 5) ~T() // -class G1BatchedGangTask : public AbstractGangTask { +class G1BatchedTask : public WorkerTask { volatile int _num_serial_tasks_done; G1GCPhaseTimes* _phase_times; bool try_claim_serial_task(int& task); - NONCOPYABLE(G1BatchedGangTask); + NONCOPYABLE(G1BatchedTask); GrowableArrayCHeap _serial_tasks; GrowableArrayCHeap _parallel_tasks; @@ -134,19 +134,19 @@ protected: void add_serial_task(G1AbstractSubTask* task); void add_parallel_task(G1AbstractSubTask* task); - G1BatchedGangTask(const char* name, G1GCPhaseTimes* phase_times); + G1BatchedTask(const char* name, G1GCPhaseTimes* phase_times); public: void work(uint worker_id) override; - // How many workers can this gang task keep busy and should be started for + // How many workers can this task keep busy and should be started for // "optimal" performance. uint num_workers_estimate() const; // Informs the G1AbstractSubTasks about that we will start execution with the // given number of workers. void set_max_workers(uint max_workers); - ~G1BatchedGangTask(); + ~G1BatchedTask(); }; -#endif // SHARE_GC_G1_G1BATCHEDGANGTASK_HPP \ No newline at end of file +#endif // SHARE_GC_G1_G1BATCHEDTASK_HPP diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index 751680abc37..816d7016f8a 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp @@ -32,7 +32,7 @@ #include "gc/g1/g1Allocator.inline.hpp" #include "gc/g1/g1Arguments.hpp" #include "gc/g1/g1BarrierSet.hpp" -#include "gc/g1/g1BatchedGangTask.hpp" +#include "gc/g1/g1BatchedTask.hpp" #include "gc/g1/g1CardSetFreeMemoryTask.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1CollectionSet.hpp" @@ -138,7 +138,7 @@ void G1RegionMappingChangedListener::on_commit(uint start_idx, size_t num_region reset_from_card_cache(start_idx, num_regions); } -void G1CollectedHeap::run_batch_task(G1BatchedGangTask* cl) { +void G1CollectedHeap::run_batch_task(G1BatchedTask* cl) { uint num_workers = MAX2(1u, MIN2(cl->num_workers_estimate(), workers()->active_workers())); cl->set_max_workers(num_workers); workers()->run_task(cl, num_workers); @@ -1273,7 +1273,7 @@ HeapWord* G1CollectedHeap::expand_and_allocate(size_t word_size) { return NULL; } -bool G1CollectedHeap::expand(size_t expand_bytes, WorkGang* pretouch_workers, double* expand_time_ms) { +bool G1CollectedHeap::expand(size_t expand_bytes, WorkerThreads* pretouch_workers, double* expand_time_ms) { size_t aligned_expand_bytes = ReservedSpace::page_align_size_up(expand_bytes); aligned_expand_bytes = align_up(aligned_expand_bytes, HeapRegion::GrainBytes); @@ -1682,7 +1682,7 @@ jint G1CollectedHeap::initialize() { _humongous_reclaim_candidates.initialize(reserved(), granularity); } - _workers = new WorkGang("GC Thread", ParallelGCThreads); + _workers = new WorkerThreads("GC Thread", ParallelGCThreads); if (_workers == NULL) { return JNI_ENOMEM; } diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp index 55c271f10c6..fe3a0fe4dae 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp @@ -64,7 +64,7 @@ // Forward declarations class G1Allocator; class G1ArchiveAllocator; -class G1BatchedGangTask; +class G1BatchedTask; class G1CardTableEntryClosure; class G1ConcurrentMark; class G1ConcurrentMarkThread; @@ -83,7 +83,7 @@ class MemoryPool; class nmethod; class ReferenceProcessor; class STWGCTimer; -class WorkGang; +class WorkerThreads; typedef OverflowTaskQueue G1ScannerTasksQueue; typedef GenericTaskQueueSet G1ScannerTasksQueueSet; @@ -145,7 +145,7 @@ private: G1ServiceTask* _periodic_gc_task; G1CardSetFreeMemoryTask* _free_card_set_memory_task; - WorkGang* _workers; + WorkerThreads* _workers; G1CardTable* _card_table; Ticks _collection_pause_end; @@ -538,10 +538,10 @@ public: G1ServiceThread* service_thread() const { return _service_thread; } - WorkGang* workers() const { return _workers; } + WorkerThreads* workers() const { return _workers; } - // Run the given batch task using the work gang. - void run_batch_task(G1BatchedGangTask* cl); + // Run the given batch task using the workers. + void run_batch_task(G1BatchedTask* cl); G1Allocator* allocator() { return _allocator; @@ -572,7 +572,7 @@ public: // Returns true if the heap was expanded by the requested amount; // false otherwise. // (Rounds up to a HeapRegion boundary.) - bool expand(size_t expand_bytes, WorkGang* pretouch_workers = NULL, double* expand_time_ms = NULL); + bool expand(size_t expand_bytes, WorkerThreads* pretouch_workers = NULL, double* expand_time_ms = NULL); bool expand_single_region(uint node_index); // Returns the PLAB statistics for a given destination. @@ -1317,7 +1317,7 @@ public: // WhiteBox testing support. virtual bool supports_concurrent_gc_breakpoints() const; - virtual WorkGang* safepoint_workers() { return _workers; } + virtual WorkerThreads* safepoint_workers() { return _workers; } virtual bool is_archived_object(oop object) const; diff --git a/src/hotspot/share/gc/g1/g1CollectionSetCandidates.hpp b/src/hotspot/share/gc/g1/g1CollectionSetCandidates.hpp index 3086cff0903..e4acef5c2f3 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSetCandidates.hpp +++ b/src/hotspot/share/gc/g1/g1CollectionSetCandidates.hpp @@ -26,7 +26,7 @@ #define SHARE_GC_G1_G1COLLECTIONSETCANDIDATES_HPP #include "gc/g1/g1CollectionSetCandidates.hpp" -#include "gc/shared/workgroup.hpp" +#include "gc/shared/workerThread.hpp" #include "memory/allocation.hpp" #include "runtime/globals.hpp" diff --git a/src/hotspot/share/gc/g1/g1CollectionSetChooser.cpp b/src/hotspot/share/gc/g1/g1CollectionSetChooser.cpp index 9136144f6cc..e7c78220943 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSetChooser.cpp +++ b/src/hotspot/share/gc/g1/g1CollectionSetChooser.cpp @@ -69,7 +69,7 @@ static int order_regions(HeapRegion* hr1, HeapRegion* hr2) { // put them into some work area unsorted. At the end the array is sorted and // copied into the G1CollectionSetCandidates instance; the caller will be the new // owner of this object. -class G1BuildCandidateRegionsTask : public AbstractGangTask { +class G1BuildCandidateRegionsTask : public WorkerTask { // Work area for building the set of collection set candidates. Contains references // to heap regions with their GC efficiencies calculated. To reduce contention @@ -223,7 +223,7 @@ class G1BuildCandidateRegionsTask : public AbstractGangTask { public: G1BuildCandidateRegionsTask(uint max_num_regions, uint chunk_size, uint num_workers) : - AbstractGangTask("G1 Build Candidate Regions"), + WorkerTask("G1 Build Candidate Regions"), _g1h(G1CollectedHeap::heap()), _hrclaimer(num_workers), _num_regions_added(0), @@ -311,7 +311,7 @@ void G1CollectionSetChooser::prune(G1CollectionSetCandidates* candidates) { } } -G1CollectionSetCandidates* G1CollectionSetChooser::build(WorkGang* workers, uint max_num_regions) { +G1CollectionSetCandidates* G1CollectionSetChooser::build(WorkerThreads* workers, uint max_num_regions) { uint num_workers = workers->active_workers(); uint chunk_size = calculate_work_chunk_size(num_workers, max_num_regions); diff --git a/src/hotspot/share/gc/g1/g1CollectionSetChooser.hpp b/src/hotspot/share/gc/g1/g1CollectionSetChooser.hpp index 2fadcd8945b..5692a0c407e 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSetChooser.hpp +++ b/src/hotspot/share/gc/g1/g1CollectionSetChooser.hpp @@ -30,7 +30,7 @@ #include "runtime/globals.hpp" class G1CollectionSetCandidates; -class WorkGang; +class WorkerThreads; // Helper class to calculate collection set candidates, and containing some related // methods. @@ -59,7 +59,7 @@ public: // Build and return set of collection set candidates sorted by decreasing gc // efficiency. - static G1CollectionSetCandidates* build(WorkGang* workers, uint max_num_regions); + static G1CollectionSetCandidates* build(WorkerThreads* workers, uint max_num_regions); }; #endif // SHARE_GC_G1_G1COLLECTIONSETCHOOSER_HPP diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp index e9a52f02c83..33bd3352f2d 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp @@ -27,7 +27,7 @@ #include "classfile/systemDictionary.hpp" #include "code/codeCache.hpp" #include "gc/g1/g1BarrierSet.hpp" -#include "gc/g1/g1BatchedGangTask.hpp" +#include "gc/g1/g1BatchedTask.hpp" #include "gc/g1/g1CardSetMemory.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1CollectorState.hpp" @@ -432,7 +432,7 @@ G1ConcurrentMark::G1ConcurrentMark(G1CollectedHeap* g1h, _num_concurrent_workers = ConcGCThreads; _max_concurrent_workers = _num_concurrent_workers; - _concurrent_workers = new WorkGang("G1 Conc", _max_concurrent_workers); + _concurrent_workers = new WorkerThreads("G1 Conc", _max_concurrent_workers); _concurrent_workers->initialize_workers(); if (!_global_mark_stack.initialize(MarkStackSize, MarkStackSizeMax)) { @@ -580,7 +580,7 @@ G1ConcurrentMark::~G1ConcurrentMark() { ShouldNotReachHere(); } -class G1ClearBitMapTask : public AbstractGangTask { +class G1ClearBitMapTask : public WorkerTask { public: static size_t chunk_size() { return M; } @@ -674,7 +674,7 @@ private: public: G1ClearBitMapTask(G1ConcurrentMark* cm, uint n_workers, bool suspendible) : - AbstractGangTask("G1 Clear Bitmap"), + WorkerTask("G1 Clear Bitmap"), _cl(cm, suspendible), _hr_claimer(n_workers), _suspendible(suspendible) @@ -690,7 +690,7 @@ public: } }; -void G1ConcurrentMark::clear_next_bitmap(WorkGang* workers, bool may_yield) { +void G1ConcurrentMark::clear_next_bitmap(WorkerThreads* workers, bool may_yield) { assert(may_yield || SafepointSynchronize::is_at_safepoint(), "Non-yielding bitmap clear only allowed at safepoint."); size_t const num_bytes_to_clear = (HeapRegion::GrainBytes * _g1h->num_regions()) / G1CMBitMap::heap_map_factor(); @@ -723,17 +723,17 @@ void G1ConcurrentMark::cleanup_for_next_mark() { guarantee(!_g1h->collector_state()->mark_or_rebuild_in_progress(), "invariant"); } -void G1ConcurrentMark::clear_next_bitmap(WorkGang* workers) { +void G1ConcurrentMark::clear_next_bitmap(WorkerThreads* workers) { assert_at_safepoint_on_vm_thread(); // To avoid fragmentation the full collection requesting to clear the bitmap // might use fewer workers than available. To ensure the bitmap is cleared // as efficiently as possible the number of active workers are temporarily // increased to include all currently created workers. - WithUpdatedActiveWorkers update(workers, workers->created_workers()); + WithActiveWorkers update(workers, workers->created_workers()); clear_next_bitmap(workers, false); } -class G1PreConcurrentStartTask : public G1BatchedGangTask { +class G1PreConcurrentStartTask : public G1BatchedTask { // Concurrent start needs claim bits to keep track of the marked-through CLDs. class CLDClearClaimedMarksTask; // Reset marking state. @@ -805,7 +805,7 @@ void G1PreConcurrentStartTask::NoteStartOfMarkTask::set_max_workers(uint max_wor } G1PreConcurrentStartTask::G1PreConcurrentStartTask(GCCause::Cause cause, G1ConcurrentMark* cm) : - G1BatchedGangTask("Pre Concurrent Start", G1CollectedHeap::heap()->phase_times()) { + G1BatchedTask("Pre Concurrent Start", G1CollectedHeap::heap()->phase_times()) { add_serial_task(new CLDClearClaimedMarksTask()); add_serial_task(new ResetMarkingStateTask(cm)); add_parallel_task(new NoteStartOfMarkTask()); @@ -889,7 +889,7 @@ void G1ConcurrentMark::enter_second_sync_barrier(uint worker_id) { // at this point everything should be re-initialized and ready to go } -class G1CMConcurrentMarkingTask : public AbstractGangTask { +class G1CMConcurrentMarkingTask : public WorkerTask { G1ConcurrentMark* _cm; public: @@ -923,7 +923,7 @@ public: } G1CMConcurrentMarkingTask(G1ConcurrentMark* cm) : - AbstractGangTask("Concurrent Mark"), _cm(cm) { } + WorkerTask("Concurrent Mark"), _cm(cm) { } ~G1CMConcurrentMarkingTask() { } }; @@ -971,11 +971,11 @@ void G1ConcurrentMark::scan_root_region(const MemRegion* region, uint worker_id) } } -class G1CMRootRegionScanTask : public AbstractGangTask { +class G1CMRootRegionScanTask : public WorkerTask { G1ConcurrentMark* _cm; public: G1CMRootRegionScanTask(G1ConcurrentMark* cm) : - AbstractGangTask("G1 Root Region Scan"), _cm(cm) { } + WorkerTask("G1 Root Region Scan"), _cm(cm) { } void work(uint worker_id) { G1CMRootMemRegions* root_regions = _cm->root_regions(); @@ -1046,8 +1046,8 @@ void G1ConcurrentMark::mark_from_roots() { // Setting active workers is not guaranteed since fewer // worker threads may currently exist and more may not be // available. - active_workers = _concurrent_workers->update_active_workers(active_workers); - log_info(gc, task)("Using %u workers of %u for marking", active_workers, _concurrent_workers->total_workers()); + active_workers = _concurrent_workers->set_active_workers(active_workers); + log_info(gc, task)("Using %u workers of %u for marking", active_workers, _concurrent_workers->max_workers()); // Parallel task terminator is set in "set_concurrency_and_phase()" set_concurrency_and_phase(active_workers, true /* concurrent */); @@ -1075,7 +1075,7 @@ void G1ConcurrentMark::verify_during_pause(G1HeapVerifier::G1VerifyType type, Ve verifier->check_bitmaps(caller); } -class G1UpdateRemSetTrackingBeforeRebuildTask : public AbstractGangTask { +class G1UpdateRemSetTrackingBeforeRebuildTask : public WorkerTask { G1CollectedHeap* _g1h; G1ConcurrentMark* _cm; HeapRegionClaimer _hrclaimer; @@ -1176,7 +1176,7 @@ class G1UpdateRemSetTrackingBeforeRebuildTask : public AbstractGangTask { public: G1UpdateRemSetTrackingBeforeRebuildTask(G1CollectedHeap* g1h, G1ConcurrentMark* cm, uint num_workers) : - AbstractGangTask("G1 Update RemSet Tracking Before Rebuild"), + WorkerTask("G1 Update RemSet Tracking Before Rebuild"), _g1h(g1h), _cm(cm), _hrclaimer(num_workers), _total_selected_for_rebuild(0), _cl("Post-Marking") { } virtual void work(uint worker_id) { @@ -1307,7 +1307,7 @@ void G1ConcurrentMark::remark() { policy->record_concurrent_mark_remark_end(); } -class G1ReclaimEmptyRegionsTask : public AbstractGangTask { +class G1ReclaimEmptyRegionsTask : public WorkerTask { // Per-region work during the Cleanup pause. class G1ReclaimEmptyRegionsClosure : public HeapRegionClosure { G1CollectedHeap* _g1h; @@ -1362,7 +1362,7 @@ class G1ReclaimEmptyRegionsTask : public AbstractGangTask { public: G1ReclaimEmptyRegionsTask(G1CollectedHeap* g1h, FreeRegionList* cleanup_list, uint n_workers) : - AbstractGangTask("G1 Cleanup"), + WorkerTask("G1 Cleanup"), _g1h(g1h), _cleanup_list(cleanup_list), _hrclaimer(n_workers) { @@ -1389,7 +1389,7 @@ public: }; void G1ConcurrentMark::reclaim_empty_regions() { - WorkGang* workers = _g1h->workers(); + WorkerThreads* workers = _g1h->workers(); FreeRegionList empty_regions_list("Empty Regions After Mark List"); G1ReclaimEmptyRegionsTask cl(_g1h, &empty_regions_list, workers->active_workers()); @@ -1613,7 +1613,7 @@ void G1ConcurrentMark::weak_refs_work() { // We need at least one active thread. If reference processing // is not multi-threaded we use the current (VMThread) thread, - // otherwise we use the work gang from the G1CollectedHeap and + // otherwise we use the workers from the G1CollectedHeap and // we utilize all the worker threads we can. uint active_workers = (ParallelRefProcEnabled ? _g1h->workers()->active_workers() : 1U); active_workers = clamp(active_workers, 1u, _max_num_tasks); @@ -1802,7 +1802,7 @@ class G1RemarkThreadsClosure : public ThreadClosure { } }; -class G1CMRemarkTask : public AbstractGangTask { +class G1CMRemarkTask : public WorkerTask { G1ConcurrentMark* _cm; public: void work(uint worker_id) { @@ -1826,7 +1826,7 @@ public: } G1CMRemarkTask(G1ConcurrentMark* cm, uint active_workers) : - AbstractGangTask("Par Remark"), _cm(cm) { + WorkerTask("Par Remark"), _cm(cm) { _cm->terminator()->reset_for_reuse(active_workers); } }; @@ -1842,7 +1842,7 @@ void G1ConcurrentMark::finalize_marking() { // Leave _parallel_marking_threads at it's // value originally calculated in the G1ConcurrentMark // constructor and pass values of the active workers - // through the gang in the task. + // through the task. { StrongRootsScope srs(active_workers); @@ -2561,7 +2561,7 @@ bool G1ConcurrentMark::try_stealing(uint worker_id, G1TaskQueueEntry& task_entry processing closures. The value of is_serial must be false when do_marking_step is - being called by any of the worker threads in a work gang. + being called by any of the worker threads. Examples include the concurrent marking code (CMMarkingTask), the MT remark code, and the MT reference processing closures. diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp index 054fc39e6b9..28752225f13 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp @@ -34,7 +34,8 @@ #include "gc/shared/taskTerminator.hpp" #include "gc/shared/taskqueue.hpp" #include "gc/shared/verifyOption.hpp" -#include "gc/shared/workgroup.hpp" +#include "gc/shared/workerThread.hpp" +#include "gc/shared/workerUtils.hpp" #include "memory/allocation.hpp" #include "utilities/compilerWarnings.hpp" #include "utilities/numberSeq.hpp" @@ -325,8 +326,8 @@ class G1ConcurrentMark : public CHeapObj { // ensure, that no task starts doing work before all data // structures (local and global) have been re-initialized. When they // exit it, they are free to start working again. - WorkGangBarrierSync _first_overflow_barrier_sync; - WorkGangBarrierSync _second_overflow_barrier_sync; + WorkerThreadsBarrierSync _first_overflow_barrier_sync; + WorkerThreadsBarrierSync _second_overflow_barrier_sync; // This is set by any task, when an overflow on the global data // structures is detected @@ -354,7 +355,7 @@ class G1ConcurrentMark : public CHeapObj { double* _accum_task_vtime; // Accumulated task vtime - WorkGang* _concurrent_workers; + WorkerThreads* _concurrent_workers; uint _num_concurrent_workers; // The number of marking worker threads we're using uint _max_concurrent_workers; // Maximum number of marking worker threads @@ -440,9 +441,9 @@ class G1ConcurrentMark : public CHeapObj { void enter_first_sync_barrier(uint worker_id); void enter_second_sync_barrier(uint worker_id); - // Clear the next marking bitmap in parallel using the given WorkGang. If may_yield is + // Clear the next marking bitmap in parallel using the given WorkerThreads. If may_yield is // true, periodically insert checks to see if this method should exit prematurely. - void clear_next_bitmap(WorkGang* workers, bool may_yield); + void clear_next_bitmap(WorkerThreads* workers, bool may_yield); // Region statistics gathered during marking. G1RegionMarkStats* _region_mark_stats; @@ -534,7 +535,7 @@ public: void cleanup_for_next_mark(); // Clear the next marking bitmap during safepoint. - void clear_next_bitmap(WorkGang* workers); + void clear_next_bitmap(WorkerThreads* workers); // These two methods do the work that needs to be done at the start and end of the // concurrent start pause. diff --git a/src/hotspot/share/gc/g1/g1EvacFailure.cpp b/src/hotspot/share/gc/g1/g1EvacFailure.cpp index d3b9b24bdd8..71a7714d120 100644 --- a/src/hotspot/share/gc/g1/g1EvacFailure.cpp +++ b/src/hotspot/share/gc/g1/g1EvacFailure.cpp @@ -201,7 +201,7 @@ public: }; G1ParRemoveSelfForwardPtrsTask::G1ParRemoveSelfForwardPtrsTask(G1EvacFailureRegions* evac_failure_regions) : - AbstractGangTask("G1 Remove Self-forwarding Pointers"), + WorkerTask("G1 Remove Self-forwarding Pointers"), _g1h(G1CollectedHeap::heap()), _hrclaimer(_g1h->workers()->active_workers()), _evac_failure_regions(evac_failure_regions), diff --git a/src/hotspot/share/gc/g1/g1EvacFailure.hpp b/src/hotspot/share/gc/g1/g1EvacFailure.hpp index b0387a3a24f..facb1c7b203 100644 --- a/src/hotspot/share/gc/g1/g1EvacFailure.hpp +++ b/src/hotspot/share/gc/g1/g1EvacFailure.hpp @@ -27,7 +27,7 @@ #include "gc/g1/g1OopClosures.hpp" #include "gc/g1/heapRegionManager.hpp" -#include "gc/shared/workgroup.hpp" +#include "gc/shared/workerThread.hpp" #include "utilities/globalDefinitions.hpp" class G1CollectedHeap; @@ -35,7 +35,7 @@ class G1EvacFailureRegions; // Task to fixup self-forwarding pointers // installed as a result of an evacuation failure. -class G1ParRemoveSelfForwardPtrsTask: public AbstractGangTask { +class G1ParRemoveSelfForwardPtrsTask: public WorkerTask { protected: G1CollectedHeap* _g1h; HeapRegionClaimer _hrclaimer; diff --git a/src/hotspot/share/gc/g1/g1FullCollector.cpp b/src/hotspot/share/gc/g1/g1FullCollector.cpp index 386158ae172..603b3818029 100644 --- a/src/hotspot/share/gc/g1/g1FullCollector.cpp +++ b/src/hotspot/share/gc/g1/g1FullCollector.cpp @@ -75,7 +75,7 @@ ReferenceProcessor* G1FullCollector::reference_processor() { uint G1FullCollector::calc_active_workers() { G1CollectedHeap* heap = G1CollectedHeap::heap(); - uint max_worker_count = heap->workers()->total_workers(); + uint max_worker_count = heap->workers()->max_workers(); // Only calculate number of workers if UseDynamicNumberOfGCThreads // is enabled, otherwise use max. if (!UseDynamicNumberOfGCThreads) { @@ -102,7 +102,7 @@ uint G1FullCollector::calc_active_workers() { log_debug(gc, task)("Requesting %u active workers for full compaction (waste limited workers: %u, " "adaptive workers: %u, used limited workers: %u)", worker_count, heap_waste_worker_limit, active_worker_limit, used_worker_limit); - worker_count = heap->workers()->update_active_workers(worker_count); + worker_count = heap->workers()->set_active_workers(worker_count); log_info(gc, task)("Using %u workers of %u for full compaction", worker_count, max_worker_count); return worker_count; @@ -332,7 +332,7 @@ void G1FullCollector::restore_marks() { _preserved_marks_set.reclaim(); } -void G1FullCollector::run_task(AbstractGangTask* task) { +void G1FullCollector::run_task(WorkerTask* task) { _heap->workers()->run_task(task, _num_workers); } diff --git a/src/hotspot/share/gc/g1/g1FullCollector.hpp b/src/hotspot/share/gc/g1/g1FullCollector.hpp index 1f9c12abd24..c4d019629dd 100644 --- a/src/hotspot/share/gc/g1/g1FullCollector.hpp +++ b/src/hotspot/share/gc/g1/g1FullCollector.hpp @@ -39,7 +39,7 @@ #include "memory/allocation.hpp" #include "oops/oopsHierarchy.hpp" -class AbstractGangTask; +class WorkerTask; class G1CMBitMap; class G1FullGCMarker; class G1FullGCScope; @@ -134,7 +134,7 @@ private: void restore_marks(); void verify_after_marking(); - void run_task(AbstractGangTask* task); + void run_task(WorkerTask* task); }; diff --git a/src/hotspot/share/gc/g1/g1FullGCTask.hpp b/src/hotspot/share/gc/g1/g1FullGCTask.hpp index b1d85a2db8a..4bb62e5eb53 100644 --- a/src/hotspot/share/gc/g1/g1FullGCTask.hpp +++ b/src/hotspot/share/gc/g1/g1FullGCTask.hpp @@ -25,17 +25,17 @@ #ifndef SHARE_GC_G1_G1FULLGCTASK_HPP #define SHARE_GC_G1_G1FULLGCTASK_HPP -#include "gc/shared/workgroup.hpp" +#include "gc/shared/workerThread.hpp" #include "utilities/ticks.hpp" class G1FullCollector; -class G1FullGCTask : public AbstractGangTask { +class G1FullGCTask : public WorkerTask { G1FullCollector* _collector; protected: G1FullGCTask(const char* name, G1FullCollector* collector) : - AbstractGangTask(name), + WorkerTask(name), _collector(collector) { } G1FullCollector* collector() { return _collector; } diff --git a/src/hotspot/share/gc/g1/g1HeapVerifier.cpp b/src/hotspot/share/gc/g1/g1HeapVerifier.cpp index 22d547b911b..2c18b4a7346 100644 --- a/src/hotspot/share/gc/g1/g1HeapVerifier.cpp +++ b/src/hotspot/share/gc/g1/g1HeapVerifier.cpp @@ -426,7 +426,7 @@ public: // This is the task used for parallel verification of the heap regions -class G1ParVerifyTask: public AbstractGangTask { +class G1ParVerifyTask: public WorkerTask { private: G1CollectedHeap* _g1h; VerifyOption _vo; @@ -438,7 +438,7 @@ public: // _vo == UseNextMarking -> use "next" marking information, // _vo == UseFullMarking -> use "next" marking bitmap but no TAMS G1ParVerifyTask(G1CollectedHeap* g1h, VerifyOption vo) : - AbstractGangTask("Parallel verify task"), + WorkerTask("Parallel verify task"), _g1h(g1h), _vo(vo), _failures(false), diff --git a/src/hotspot/share/gc/g1/g1PageBasedVirtualSpace.cpp b/src/hotspot/share/gc/g1/g1PageBasedVirtualSpace.cpp index 1afa9ebe5d0..7a164e6461f 100644 --- a/src/hotspot/share/gc/g1/g1PageBasedVirtualSpace.cpp +++ b/src/hotspot/share/gc/g1/g1PageBasedVirtualSpace.cpp @@ -25,7 +25,7 @@ #include "precompiled.hpp" #include "gc/g1/g1PageBasedVirtualSpace.hpp" #include "gc/shared/pretouchTask.hpp" -#include "gc/shared/workgroup.hpp" +#include "gc/shared/workerThread.hpp" #include "oops/markWord.hpp" #include "oops/oop.inline.hpp" #include "runtime/atomic.hpp" @@ -233,10 +233,10 @@ void G1PageBasedVirtualSpace::uncommit(size_t start_page, size_t size_in_pages) _committed.par_clear_range(start_page, end_page, BitMap::unknown_range); } -void G1PageBasedVirtualSpace::pretouch(size_t start_page, size_t size_in_pages, WorkGang* pretouch_gang) { +void G1PageBasedVirtualSpace::pretouch(size_t start_page, size_t size_in_pages, WorkerThreads* pretouch_workers) { PretouchTask::pretouch("G1 PreTouch", page_start(start_page), bounded_end_addr(start_page + size_in_pages), - _page_size, pretouch_gang); + _page_size, pretouch_workers); } bool G1PageBasedVirtualSpace::contains(const void* p) const { diff --git a/src/hotspot/share/gc/g1/g1PageBasedVirtualSpace.hpp b/src/hotspot/share/gc/g1/g1PageBasedVirtualSpace.hpp index 0bfb8c4dd77..8b68ad60e56 100644 --- a/src/hotspot/share/gc/g1/g1PageBasedVirtualSpace.hpp +++ b/src/hotspot/share/gc/g1/g1PageBasedVirtualSpace.hpp @@ -30,7 +30,7 @@ #include "utilities/align.hpp" #include "utilities/bitMap.hpp" -class WorkGang; +class WorkerThreads; // Virtual space management helper for a virtual space with an OS page allocation // granularity. @@ -117,7 +117,7 @@ class G1PageBasedVirtualSpace { // Uncommit the given area of pages starting at start being size_in_pages large. void uncommit(size_t start_page, size_t size_in_pages); - void pretouch(size_t start_page, size_t size_in_pages, WorkGang* pretouch_gang = NULL); + void pretouch(size_t start_page, size_t size_in_pages, WorkerThreads* pretouch_workers = NULL); // Initialize the given reserved space with the given base address and the size // actually used. diff --git a/src/hotspot/share/gc/g1/g1ParallelCleaning.cpp b/src/hotspot/share/gc/g1/g1ParallelCleaning.cpp index abe06f71f7a..b528afffa02 100644 --- a/src/hotspot/share/gc/g1/g1ParallelCleaning.cpp +++ b/src/hotspot/share/gc/g1/g1ParallelCleaning.cpp @@ -54,7 +54,7 @@ void JVMCICleaningTask::work(bool unloading_occurred) { G1ParallelCleaningTask::G1ParallelCleaningTask(BoolObjectClosure* is_alive, uint num_workers, bool unloading_occurred) : - AbstractGangTask("G1 Parallel Cleaning"), + WorkerTask("G1 Parallel Cleaning"), _unloading_occurred(unloading_occurred), _code_cache_task(num_workers, is_alive, unloading_occurred), JVMCI_ONLY(_jvmci_cleaning_task() COMMA) diff --git a/src/hotspot/share/gc/g1/g1ParallelCleaning.hpp b/src/hotspot/share/gc/g1/g1ParallelCleaning.hpp index c87c7e22e43..b8556b49398 100644 --- a/src/hotspot/share/gc/g1/g1ParallelCleaning.hpp +++ b/src/hotspot/share/gc/g1/g1ParallelCleaning.hpp @@ -43,7 +43,7 @@ private: // Do cleanup of some weakly held data in the same parallel task. // Assumes a non-moving context. -class G1ParallelCleaningTask : public AbstractGangTask { +class G1ParallelCleaningTask : public WorkerTask { private: bool _unloading_occurred; CodeCacheUnloadingTask _code_cache_task; diff --git a/src/hotspot/share/gc/g1/g1RegionToSpaceMapper.cpp b/src/hotspot/share/gc/g1/g1RegionToSpaceMapper.cpp index 2a78f259335..b8f1f5de153 100644 --- a/src/hotspot/share/gc/g1/g1RegionToSpaceMapper.cpp +++ b/src/hotspot/share/gc/g1/g1RegionToSpaceMapper.cpp @@ -89,7 +89,7 @@ class G1RegionsLargerThanCommitSizeMapper : public G1RegionToSpaceMapper { return _region_commit_map.get_next_one_offset(start_idx, end) == end; } - virtual void commit_regions(uint start_idx, size_t num_regions, WorkGang* pretouch_gang) { + virtual void commit_regions(uint start_idx, size_t num_regions, WorkerThreads* pretouch_workers) { guarantee(is_range_uncommitted(start_idx, num_regions), "Range not uncommitted, start: %u, num_regions: " SIZE_FORMAT, start_idx, num_regions); @@ -105,7 +105,7 @@ class G1RegionsLargerThanCommitSizeMapper : public G1RegionToSpaceMapper { } } if (AlwaysPreTouch) { - _storage.pretouch(start_page, size_in_pages, pretouch_gang); + _storage.pretouch(start_page, size_in_pages, pretouch_workers); } _region_commit_map.par_set_range(start_idx, start_idx + num_regions, BitMap::unknown_range); fire_on_commit(start_idx, num_regions, zero_filled); @@ -172,7 +172,7 @@ class G1RegionsSmallerThanCommitSizeMapper : public G1RegionToSpaceMapper { guarantee((page_size * commit_factor) >= alloc_granularity, "allocation granularity smaller than commit granularity"); } - virtual void commit_regions(uint start_idx, size_t num_regions, WorkGang* pretouch_gang) { + virtual void commit_regions(uint start_idx, size_t num_regions, WorkerThreads* pretouch_workers) { uint region_limit = (uint)(start_idx + num_regions); assert(num_regions > 0, "Must commit at least one region"); assert(_region_commit_map.get_next_one_offset(start_idx, region_limit) == region_limit, @@ -219,7 +219,7 @@ class G1RegionsSmallerThanCommitSizeMapper : public G1RegionToSpaceMapper { } if (AlwaysPreTouch && num_committed > 0) { - _storage.pretouch(first_committed, num_committed, pretouch_gang); + _storage.pretouch(first_committed, num_committed, pretouch_workers); } fire_on_commit(start_idx, num_regions, all_zero_filled); diff --git a/src/hotspot/share/gc/g1/g1RegionToSpaceMapper.hpp b/src/hotspot/share/gc/g1/g1RegionToSpaceMapper.hpp index 22dea6153c8..eeda48838df 100644 --- a/src/hotspot/share/gc/g1/g1RegionToSpaceMapper.hpp +++ b/src/hotspot/share/gc/g1/g1RegionToSpaceMapper.hpp @@ -29,7 +29,7 @@ #include "memory/allocation.hpp" #include "utilities/debug.hpp" -class WorkGang; +class WorkerThreads; class G1MappingChangedListener { public: @@ -70,7 +70,7 @@ class G1RegionToSpaceMapper : public CHeapObj { virtual ~G1RegionToSpaceMapper() {} - virtual void commit_regions(uint start_idx, size_t num_regions = 1, WorkGang* pretouch_workers = NULL) = 0; + virtual void commit_regions(uint start_idx, size_t num_regions = 1, WorkerThreads* pretouch_workers = NULL) = 0; virtual void uncommit_regions(uint start_idx, size_t num_regions = 1) = 0; // Creates an appropriate G1RegionToSpaceMapper for the given parameters. diff --git a/src/hotspot/share/gc/g1/g1RemSet.cpp b/src/hotspot/share/gc/g1/g1RemSet.cpp index 467b9d864f8..30eabfa957a 100644 --- a/src/hotspot/share/gc/g1/g1RemSet.cpp +++ b/src/hotspot/share/gc/g1/g1RemSet.cpp @@ -24,7 +24,7 @@ #include "precompiled.hpp" #include "gc/g1/g1BarrierSet.hpp" -#include "gc/g1/g1BatchedGangTask.hpp" +#include "gc/g1/g1BatchedTask.hpp" #include "gc/g1/g1BlockOffsetTable.inline.hpp" #include "gc/g1/g1CardSet.inline.hpp" #include "gc/g1/g1CardTable.inline.hpp" @@ -406,7 +406,7 @@ public: G1CollectedHeap* g1h = G1CollectedHeap::heap(); - WorkGang* workers = g1h->workers(); + WorkerThreads* workers = g1h->workers(); uint const max_workers = workers->active_workers(); uint const start_pos = num_regions * worker_id / max_workers; @@ -1102,7 +1102,7 @@ public: } }; -class G1MergeHeapRootsTask : public AbstractGangTask { +class G1MergeHeapRootsTask : public WorkerTask { class G1MergeCardSetStats { size_t _merged[G1GCPhaseTimes::MergeRSContainersSentinel]; @@ -1371,7 +1371,7 @@ class G1MergeHeapRootsTask : public AbstractGangTask { public: G1MergeHeapRootsTask(G1RemSetScanState* scan_state, uint num_workers, bool initial_evacuation) : - AbstractGangTask("G1 Merge Heap Roots"), + WorkerTask("G1 Merge Heap Roots"), _hr_claimer(num_workers), _scan_state(scan_state), _dirty_card_buffers(), @@ -1490,7 +1490,7 @@ void G1RemSet::merge_heap_roots(bool initial_evacuation) { } } - WorkGang* workers = g1h->workers(); + WorkerThreads* workers = g1h->workers(); size_t const increment_length = g1h->collection_set()->increment_length(); uint const num_workers = initial_evacuation ? workers->active_workers() : @@ -1738,7 +1738,7 @@ void G1RemSet::print_summary_info() { } } -class G1RebuildRemSetTask: public AbstractGangTask { +class G1RebuildRemSetTask: public WorkerTask { // Aggregate the counting data that was constructed concurrently // with marking. class G1RebuildRemSetHeapRegionClosure : public HeapRegionClosure { @@ -1974,7 +1974,7 @@ public: G1RebuildRemSetTask(G1ConcurrentMark* cm, uint n_workers, uint worker_id_offset) : - AbstractGangTask("G1 Rebuild Remembered Set"), + WorkerTask("G1 Rebuild Remembered Set"), _hr_claimer(n_workers), _cm(cm), _worker_id_offset(worker_id_offset) { @@ -1991,7 +1991,7 @@ public: }; void G1RemSet::rebuild_rem_set(G1ConcurrentMark* cm, - WorkGang* workers, + WorkerThreads* workers, uint worker_id_offset) { uint num_workers = workers->active_workers(); diff --git a/src/hotspot/share/gc/g1/g1RemSet.hpp b/src/hotspot/share/gc/g1/g1RemSet.hpp index 7bc463650f0..89ce4f6e5ac 100644 --- a/src/hotspot/share/gc/g1/g1RemSet.hpp +++ b/src/hotspot/share/gc/g1/g1RemSet.hpp @@ -113,7 +113,7 @@ public: // Print coarsening stats. void print_coarsen_stats(); - // Creates a gang task for cleaining up temporary data structures and the + // Creates a task for cleaining up temporary data structures and the // card table, removing temporary duplicate detection information. G1AbstractSubTask* create_cleanup_after_scan_heap_roots_task(); // Excludes the given region from heap root scanning. @@ -149,8 +149,8 @@ public: void print_periodic_summary_info(const char* header, uint period_count); // Rebuilds the remembered set by scanning from bottom to TARS for all regions - // using the given work gang. - void rebuild_rem_set(G1ConcurrentMark* cm, WorkGang* workers, uint worker_id_offset); + // using the given workers. + void rebuild_rem_set(G1ConcurrentMark* cm, WorkerThreads* workers, uint worker_id_offset); }; #endif // SHARE_GC_G1_G1REMSET_HPP diff --git a/src/hotspot/share/gc/g1/g1YoungCollector.cpp b/src/hotspot/share/gc/g1/g1YoungCollector.cpp index b81c0328d73..2adee5b4d13 100644 --- a/src/hotspot/share/gc/g1/g1YoungCollector.cpp +++ b/src/hotspot/share/gc/g1/g1YoungCollector.cpp @@ -54,7 +54,7 @@ #include "gc/shared/referenceProcessor.hpp" #include "gc/shared/weakProcessor.inline.hpp" #include "gc/shared/workerPolicy.hpp" -#include "gc/shared/workgroup.hpp" +#include "gc/shared/workerThread.hpp" #include "jfr/jfrEvents.hpp" #include "memory/resourceArea.hpp" #include "utilities/ticks.hpp" @@ -270,7 +270,7 @@ ReferenceProcessor* G1YoungCollector::ref_processor_stw() const { return _g1h->ref_processor_stw(); } -WorkGang* G1YoungCollector::workers() const { +WorkerThreads* G1YoungCollector::workers() const { return _g1h->workers(); } @@ -323,7 +323,7 @@ void G1YoungCollector::calculate_collection_set(G1EvacInfo* evacuation_info, dou } } -class G1PrepareEvacuationTask : public AbstractGangTask { +class G1PrepareEvacuationTask : public WorkerTask { class G1PrepareRegionsClosure : public HeapRegionClosure { G1CollectedHeap* _g1h; G1PrepareEvacuationTask* _parent_task; @@ -460,7 +460,7 @@ class G1PrepareEvacuationTask : public AbstractGangTask { public: G1PrepareEvacuationTask(G1CollectedHeap* g1h) : - AbstractGangTask("Prepare Evacuation"), + WorkerTask("Prepare Evacuation"), _g1h(g1h), _claimer(_g1h->workers()->active_workers()), _humongous_total(0), @@ -495,18 +495,18 @@ public: } }; -Tickspan G1YoungCollector::run_task_timed(AbstractGangTask* task) { +Tickspan G1YoungCollector::run_task_timed(WorkerTask* task) { Ticks start = Ticks::now(); workers()->run_task(task); return Ticks::now() - start; } void G1YoungCollector::set_young_collection_default_active_worker_threads(){ - uint active_workers = WorkerPolicy::calc_active_workers(workers()->total_workers(), + uint active_workers = WorkerPolicy::calc_active_workers(workers()->max_workers(), workers()->active_workers(), Threads::number_of_non_daemon_threads()); - active_workers = workers()->update_active_workers(active_workers); - log_info(gc,task)("Using %u workers of %u for evacuation", active_workers, workers()->total_workers()); + active_workers = workers()->set_active_workers(active_workers); + log_info(gc,task)("Using %u workers of %u for evacuation", active_workers, workers()->max_workers()); } void G1YoungCollector::pre_evacuate_collection_set(G1EvacInfo* evacuation_info, G1ParScanThreadStateSet* per_thread_states) { @@ -625,7 +625,7 @@ public: size_t term_attempts() const { return _term_attempts; } }; -class G1EvacuateRegionsBaseTask : public AbstractGangTask { +class G1EvacuateRegionsBaseTask : public WorkerTask { protected: G1CollectedHeap* _g1h; G1ParScanThreadStateSet* _per_thread_states; @@ -673,7 +673,7 @@ public: G1ParScanThreadStateSet* per_thread_states, G1ScannerTasksQueueSet* task_queues, uint num_workers) : - AbstractGangTask(name), + WorkerTask(name), _g1h(G1CollectedHeap::heap()), _per_thread_states(per_thread_states), _task_queues(task_queues), @@ -757,7 +757,7 @@ void G1YoungCollector::evacuate_initial_collection_set(G1ParScanThreadStateSet* has_optional_evacuation_work); task_time = run_task_timed(&g1_par_task); // Closing the inner scope will execute the destructor for the - // G1RootProcessor object. By subtracting the WorkGang task from the total + // G1RootProcessor object. By subtracting the WorkerThreads task from the total // time of this scope, we get the "NMethod List Cleanup" time. This list is // constructed during "STW two-phase nmethod root processing", see more in // nmethod.hpp @@ -1104,12 +1104,12 @@ void G1YoungCollector::collect() { // Young GC internal pause timing G1YoungGCNotifyPauseMark npm(this); - // Verification may use the gang workers, so they must be set up before. + // Verification may use the workers, so they must be set up before. // Individual parallel phases may override this. set_young_collection_default_active_worker_threads(); // Wait for root region scan here to make sure that it is done before any - // use of the STW work gang to maximize cpu use (i.e. all cores are available + // use of the STW workers to maximize cpu use (i.e. all cores are available // just to do that). wait_for_root_region_scanning(); diff --git a/src/hotspot/share/gc/g1/g1YoungCollector.hpp b/src/hotspot/share/gc/g1/g1YoungCollector.hpp index cc6370f1957..4bc1eaf1942 100644 --- a/src/hotspot/share/gc/g1/g1YoungCollector.hpp +++ b/src/hotspot/share/gc/g1/g1YoungCollector.hpp @@ -30,9 +30,9 @@ #include "gc/shared/gcCause.hpp" #include "gc/shared/taskqueue.hpp" -class AbstractGangTask; +class WorkerTask; class G1Allocator; -class G1BatchedGangTask; +class G1BatchedTask; class G1CardSetMemoryStats; class G1CollectedHeap; class G1CollectionSet; @@ -52,7 +52,7 @@ class G1RemSet; class G1SurvivorRegions; class G1YoungGCEvacFailureInjector; class STWGCTimer; -class WorkGang; +class WorkerThreads; class outputStream; @@ -78,7 +78,7 @@ class G1YoungCollector { G1ScannerTasksQueueSet* task_queues() const; G1SurvivorRegions* survivor_regions() const; ReferenceProcessor* ref_processor_stw() const; - WorkGang* workers() const; + WorkerThreads* workers() const; G1YoungGCEvacFailureInjector* evac_failure_injector() const; GCCause::Cause _gc_cause; @@ -89,9 +89,9 @@ class G1YoungCollector { // Evacuation failure tracking. G1EvacFailureRegions _evac_failure_regions; - // Runs the given AbstractGangTask with the current active workers, + // Runs the given WorkerTask with the current active workers, // returning the total time taken. - Tickspan run_task_timed(AbstractGangTask* task); + Tickspan run_task_timed(WorkerTask* task); void wait_for_root_region_scanning(); diff --git a/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp b/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp index 88c9cba3c60..bfe47d1c7ea 100644 --- a/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp +++ b/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp @@ -125,7 +125,7 @@ public: G1PostEvacuateCollectionSetCleanupTask1::G1PostEvacuateCollectionSetCleanupTask1(G1ParScanThreadStateSet* per_thread_states, G1EvacFailureRegions* evac_failure_regions) : - G1BatchedGangTask("Post Evacuate Cleanup 1", G1CollectedHeap::heap()->phase_times()) + G1BatchedTask("Post Evacuate Cleanup 1", G1CollectedHeap::heap()->phase_times()) { bool evacuation_failed = evac_failure_regions->evacuation_failed(); @@ -306,7 +306,7 @@ public: class G1PostEvacuateCollectionSetCleanupTask2::RestorePreservedMarksTask : public G1AbstractSubTask { PreservedMarksSet* _preserved_marks; - AbstractGangTask* _task; + WorkerTask* _task; public: RestorePreservedMarksTask(PreservedMarksSet* preserved_marks) : @@ -672,7 +672,7 @@ public: G1PostEvacuateCollectionSetCleanupTask2::G1PostEvacuateCollectionSetCleanupTask2(G1ParScanThreadStateSet* per_thread_states, G1EvacInfo* evacuation_info, G1EvacFailureRegions* evac_failure_regions) : - G1BatchedGangTask("Post Evacuate Cleanup 2", G1CollectedHeap::heap()->phase_times()) + G1BatchedTask("Post Evacuate Cleanup 2", G1CollectedHeap::heap()->phase_times()) { add_serial_task(new ResetHotCardCacheTask()); add_serial_task(new PurgeCodeRootsTask()); diff --git a/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.hpp b/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.hpp index 6613438e19b..2de66094853 100644 --- a/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.hpp +++ b/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.hpp @@ -25,7 +25,7 @@ #ifndef SHARE_GC_G1_G1YOUNGGCPOSTEVACUATETASKS_HPP #define SHARE_GC_G1_G1YOUNGGCPOSTEVACUATETASKS_HPP -#include "gc/g1/g1BatchedGangTask.hpp" +#include "gc/g1/g1BatchedTask.hpp" #include "gc/g1/g1EvacFailure.hpp" class FreeCSetStats; @@ -41,7 +41,7 @@ class G1ParScanThreadStateSet; // - Sample Collection Set Candidates (s) // - Remove Self Forwards (on evacuation failure) // - Clear Card Table -class G1PostEvacuateCollectionSetCleanupTask1 : public G1BatchedGangTask { +class G1PostEvacuateCollectionSetCleanupTask1 : public G1BatchedTask { class MergePssTask; class RecalculateUsedTask; class SampleCollectionSetCandidatesTask; @@ -60,7 +60,7 @@ public: // - Redirty Logged Cards // - Restore Preserved Marks (on evacuation failure) // - Free Collection Set -class G1PostEvacuateCollectionSetCleanupTask2 : public G1BatchedGangTask { +class G1PostEvacuateCollectionSetCleanupTask2 : public G1BatchedTask { class EagerlyReclaimHumongousObjectsTask; class PurgeCodeRootsTask; class ResetHotCardCacheTask; diff --git a/src/hotspot/share/gc/g1/heapRegionManager.cpp b/src/hotspot/share/gc/g1/heapRegionManager.cpp index 28e5403de1c..1f5459e15df 100644 --- a/src/hotspot/share/gc/g1/heapRegionManager.cpp +++ b/src/hotspot/share/gc/g1/heapRegionManager.cpp @@ -166,8 +166,8 @@ HeapRegion* HeapRegionManager::new_heap_region(uint hrm_index) { return g1h->new_heap_region(hrm_index, mr); } -void HeapRegionManager::expand(uint start, uint num_regions, WorkGang* pretouch_gang) { - commit_regions(start, num_regions, pretouch_gang); +void HeapRegionManager::expand(uint start, uint num_regions, WorkerThreads* pretouch_workers) { + commit_regions(start, num_regions, pretouch_workers); for (uint i = start; i < start + num_regions; i++) { HeapRegion* hr = _regions.get_by_index(i); if (hr == NULL) { @@ -181,21 +181,21 @@ void HeapRegionManager::expand(uint start, uint num_regions, WorkGang* pretouch_ activate_regions(start, num_regions); } -void HeapRegionManager::commit_regions(uint index, size_t num_regions, WorkGang* pretouch_gang) { +void HeapRegionManager::commit_regions(uint index, size_t num_regions, WorkerThreads* pretouch_workers) { guarantee(num_regions > 0, "Must commit more than zero regions"); guarantee(num_regions <= available(), "Cannot commit more than the maximum amount of regions"); - _heap_mapper->commit_regions(index, num_regions, pretouch_gang); + _heap_mapper->commit_regions(index, num_regions, pretouch_workers); // Also commit auxiliary data - _prev_bitmap_mapper->commit_regions(index, num_regions, pretouch_gang); - _next_bitmap_mapper->commit_regions(index, num_regions, pretouch_gang); + _prev_bitmap_mapper->commit_regions(index, num_regions, pretouch_workers); + _next_bitmap_mapper->commit_regions(index, num_regions, pretouch_workers); - _bot_mapper->commit_regions(index, num_regions, pretouch_gang); - _cardtable_mapper->commit_regions(index, num_regions, pretouch_gang); + _bot_mapper->commit_regions(index, num_regions, pretouch_workers); + _cardtable_mapper->commit_regions(index, num_regions, pretouch_workers); - _card_counts_mapper->commit_regions(index, num_regions, pretouch_gang); + _card_counts_mapper->commit_regions(index, num_regions, pretouch_workers); } void HeapRegionManager::uncommit_regions(uint start, uint num_regions) { @@ -346,7 +346,7 @@ uint HeapRegionManager::expand_inactive(uint num_regions) { return expanded; } -uint HeapRegionManager::expand_any(uint num_regions, WorkGang* pretouch_workers) { +uint HeapRegionManager::expand_any(uint num_regions, WorkerThreads* pretouch_workers) { assert(num_regions > 0, "Must expand at least 1 region"); uint offset = 0; @@ -368,7 +368,7 @@ uint HeapRegionManager::expand_any(uint num_regions, WorkGang* pretouch_workers) return expanded; } -uint HeapRegionManager::expand_by(uint num_regions, WorkGang* pretouch_workers) { +uint HeapRegionManager::expand_by(uint num_regions, WorkerThreads* pretouch_workers) { assert(num_regions > 0, "Must expand at least 1 region"); // First "undo" any requests to uncommit memory concurrently by @@ -384,7 +384,7 @@ uint HeapRegionManager::expand_by(uint num_regions, WorkGang* pretouch_workers) return expanded; } -void HeapRegionManager::expand_exact(uint start, uint num_regions, WorkGang* pretouch_workers) { +void HeapRegionManager::expand_exact(uint start, uint num_regions, WorkerThreads* pretouch_workers) { assert(num_regions != 0, "Need to request at least one region"); uint end = start + num_regions; @@ -555,7 +555,7 @@ uint HeapRegionManager::find_highest_free(bool* expanded) { return G1_NO_HRM_INDEX; } -bool HeapRegionManager::allocate_containing_regions(MemRegion range, size_t* commit_count, WorkGang* pretouch_workers) { +bool HeapRegionManager::allocate_containing_regions(MemRegion range, size_t* commit_count, WorkerThreads* pretouch_workers) { size_t commits = 0; uint start_index = (uint)_regions.get_index_by_address(range.start()); uint last_index = (uint)_regions.get_index_by_address(range.last()); @@ -760,7 +760,7 @@ bool HeapRegionClaimer::claim_region(uint region_index) { return old_val == Unclaimed; } -class G1RebuildFreeListTask : public AbstractGangTask { +class G1RebuildFreeListTask : public WorkerTask { HeapRegionManager* _hrm; FreeRegionList* _worker_freelists; uint _worker_chunk_size; @@ -768,7 +768,7 @@ class G1RebuildFreeListTask : public AbstractGangTask { public: G1RebuildFreeListTask(HeapRegionManager* hrm, uint num_workers) : - AbstractGangTask("G1 Rebuild Free List Task"), + WorkerTask("G1 Rebuild Free List Task"), _hrm(hrm), _worker_freelists(NEW_C_HEAP_ARRAY(FreeRegionList, num_workers, mtGC)), _worker_chunk_size((_hrm->reserved_length() + num_workers - 1) / num_workers), @@ -818,7 +818,7 @@ public: } }; -void HeapRegionManager::rebuild_free_list(WorkGang* workers) { +void HeapRegionManager::rebuild_free_list(WorkerThreads* workers) { // Abandon current free list to allow a rebuild. _free_list.abandon(); diff --git a/src/hotspot/share/gc/g1/heapRegionManager.hpp b/src/hotspot/share/gc/g1/heapRegionManager.hpp index 04f799899a7..5846171ce91 100644 --- a/src/hotspot/share/gc/g1/heapRegionManager.hpp +++ b/src/hotspot/share/gc/g1/heapRegionManager.hpp @@ -36,7 +36,7 @@ class HeapRegion; class HeapRegionClosure; class HeapRegionClaimer; class FreeRegionList; -class WorkGang; +class WorkerThreads; class G1HeapRegionTable : public G1BiasedMappedArray { protected: @@ -89,7 +89,7 @@ class HeapRegionManager: public CHeapObj { HeapWord* heap_end() const {return _regions.end_address_mapped(); } // Pass down commit calls to the VirtualSpace. - void commit_regions(uint index, size_t num_regions = 1, WorkGang* pretouch_gang = NULL); + void commit_regions(uint index, size_t num_regions = 1, WorkerThreads* pretouch_workers = NULL); // Initialize the HeapRegions in the range and put them on the free list. void initialize_regions(uint start, uint num_regions); @@ -127,7 +127,7 @@ class HeapRegionManager: public CHeapObj { G1RegionToSpaceMapper* _next_bitmap_mapper; FreeRegionList _free_list; - void expand(uint index, uint num_regions, WorkGang* pretouch_gang = NULL); + void expand(uint index, uint num_regions, WorkerThreads* pretouch_workers = NULL); // G1RegionCommittedMap helpers. These functions do the work that comes with // the state changes tracked by G1CommittedRegionMap. To make sure this is @@ -147,11 +147,11 @@ class HeapRegionManager: public CHeapObj { HeapRegion* allocate_humongous_allow_expand(uint num_regions); // Expand helper for cases when the regions to expand are well defined. - void expand_exact(uint start, uint num_regions, WorkGang* pretouch_workers); + void expand_exact(uint start, uint num_regions, WorkerThreads* pretouch_workers); // Expand helper activating inactive regions rather than committing new ones. uint expand_inactive(uint num_regions); // Expand helper finding new regions to commit. - uint expand_any(uint num_regions, WorkGang* pretouch_workers); + uint expand_any(uint num_regions, WorkerThreads* pretouch_workers); #ifdef ASSERT public: @@ -197,7 +197,7 @@ public: inline void insert_into_free_list(HeapRegion* hr); // Rebuild the free region list from scratch. - void rebuild_free_list(WorkGang* workers); + void rebuild_free_list(WorkerThreads* workers); // Insert the given region list into the global free region list. void insert_list_into_free_list(FreeRegionList* list) { @@ -253,7 +253,7 @@ public: // HeapRegions, or re-use existing ones. Returns the number of regions the // sequence was expanded by. If a HeapRegion allocation fails, the resulting // number of regions might be smaller than what's desired. - uint expand_by(uint num_regions, WorkGang* pretouch_workers); + uint expand_by(uint num_regions, WorkerThreads* pretouch_workers); // Try to expand on the given node index, returning the index of the new region. uint expand_on_preferred_node(uint node_index); @@ -268,7 +268,7 @@ public: // Allocate the regions that contain the address range specified, committing the // regions if necessary. Return false if any of the regions is already committed // and not free, and return the number of regions newly committed in commit_count. - bool allocate_containing_regions(MemRegion range, size_t* commit_count, WorkGang* pretouch_workers); + bool allocate_containing_regions(MemRegion range, size_t* commit_count, WorkerThreads* pretouch_workers); // Apply blk->do_heap_region() on all committed regions in address order, // terminating the iteration early if do_heap_region() returns true. diff --git a/src/hotspot/share/gc/parallel/mutableNUMASpace.cpp b/src/hotspot/share/gc/parallel/mutableNUMASpace.cpp index c00890d38e1..e359d0f9a39 100644 --- a/src/hotspot/share/gc/parallel/mutableNUMASpace.cpp +++ b/src/hotspot/share/gc/parallel/mutableNUMASpace.cpp @@ -27,7 +27,7 @@ #include "gc/shared/collectedHeap.hpp" #include "gc/shared/gc_globals.hpp" #include "gc/shared/spaceDecorator.hpp" -#include "gc/shared/workgroup.hpp" +#include "gc/shared/workerThread.hpp" #include "memory/allocation.inline.hpp" #include "oops/oop.inline.hpp" #include "oops/typeArrayOop.hpp" @@ -577,7 +577,7 @@ void MutableNUMASpace::initialize(MemRegion mr, bool clear_space, bool mangle_space, bool setup_pages, - WorkGang* pretouch_gang) { + WorkerThreads* pretouch_workers) { assert(clear_space, "Reallocation will destroy data!"); assert(lgrp_spaces()->length() > 0, "There should be at least one space"); diff --git a/src/hotspot/share/gc/parallel/mutableNUMASpace.hpp b/src/hotspot/share/gc/parallel/mutableNUMASpace.hpp index a27601c66fe..881f280c4b4 100644 --- a/src/hotspot/share/gc/parallel/mutableNUMASpace.hpp +++ b/src/hotspot/share/gc/parallel/mutableNUMASpace.hpp @@ -201,7 +201,7 @@ class MutableNUMASpace : public MutableSpace { bool clear_space, bool mangle_space, bool setup_pages = SetupPages, - WorkGang* pretouch_gang = NULL); + WorkerThreads* pretouch_workers = NULL); // Update space layout if necessary. Do all adaptive resizing job. virtual void update(); // Update allocation rate averages. diff --git a/src/hotspot/share/gc/parallel/mutableSpace.cpp b/src/hotspot/share/gc/parallel/mutableSpace.cpp index 363e115d10d..e28a71e5691 100644 --- a/src/hotspot/share/gc/parallel/mutableSpace.cpp +++ b/src/hotspot/share/gc/parallel/mutableSpace.cpp @@ -72,7 +72,7 @@ void MutableSpace::initialize(MemRegion mr, bool clear_space, bool mangle_space, bool setup_pages, - WorkGang* pretouch_gang) { + WorkerThreads* pretouch_workers) { assert(Universe::on_page_boundary(mr.start()) && Universe::on_page_boundary(mr.end()), "invalid space boundaries"); @@ -122,10 +122,10 @@ void MutableSpace::initialize(MemRegion mr, size_t page_size = UseLargePages ? os::large_page_size() : os::vm_page_size(); PretouchTask::pretouch("ParallelGC PreTouch head", (char*)head.start(), (char*)head.end(), - page_size, pretouch_gang); + page_size, pretouch_workers); PretouchTask::pretouch("ParallelGC PreTouch tail", (char*)tail.start(), (char*)tail.end(), - page_size, pretouch_gang); + page_size, pretouch_workers); } // Remember where we stopped so that we can continue later. diff --git a/src/hotspot/share/gc/parallel/mutableSpace.hpp b/src/hotspot/share/gc/parallel/mutableSpace.hpp index b6bb131828f..548b6a4949e 100644 --- a/src/hotspot/share/gc/parallel/mutableSpace.hpp +++ b/src/hotspot/share/gc/parallel/mutableSpace.hpp @@ -32,7 +32,7 @@ #include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" -class WorkGang; +class WorkerThreads; // A MutableSpace supports the concept of allocation. This includes the // concepts that a space may be only partially full, and the query methods @@ -102,7 +102,7 @@ class MutableSpace: public CHeapObj { bool clear_space, bool mangle_space, bool setup_pages = SetupPages, - WorkGang* pretouch_gang = NULL); + WorkerThreads* pretouch_workers = NULL); virtual void clear(bool mangle_space); virtual void update() { } diff --git a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp index 567ae94b839..0013007a923 100644 --- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp +++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp @@ -85,7 +85,7 @@ jint ParallelScavengeHeap::initialize() { ReservedSpace young_rs = heap_rs.last_part(MaxOldSize); assert(young_rs.size() == MaxNewSize, "Didn't reserve all of the heap"); - // Set up WorkGang + // Set up WorkerThreads _workers.initialize_workers(); // Create and initialize the generations. diff --git a/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp b/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp index b8df770a276..9d8368fc3a4 100644 --- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp +++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp @@ -37,7 +37,7 @@ #include "gc/shared/referenceProcessor.hpp" #include "gc/shared/softRefPolicy.hpp" #include "gc/shared/strongRootsScope.hpp" -#include "gc/shared/workgroup.hpp" +#include "gc/shared/workerThread.hpp" #include "logging/log.hpp" #include "utilities/growableArray.hpp" #include "utilities/ostream.hpp" @@ -91,7 +91,7 @@ class ParallelScavengeHeap : public CollectedHeap { MemoryPool* _survivor_pool; MemoryPool* _old_pool; - WorkGang _workers; + WorkerThreads _workers; virtual void initialize_serviceability(); @@ -243,7 +243,7 @@ class ParallelScavengeHeap : public CollectedHeap { virtual void gc_threads_do(ThreadClosure* tc) const; virtual void print_tracing_info() const; - virtual WorkGang* safepoint_workers() { return &_workers; } + virtual WorkerThreads* safepoint_workers() { return &_workers; } PreGenGCValues get_pre_gc_values() const; void print_heap_change(const PreGenGCValues& pre_gc_values) const; @@ -270,7 +270,7 @@ class ParallelScavengeHeap : public CollectedHeap { GCMemoryManager* old_gc_manager() const { return _old_manager; } GCMemoryManager* young_gc_manager() const { return _young_manager; } - WorkGang& workers() { + WorkerThreads& workers() { return _workers; } }; diff --git a/src/hotspot/share/gc/parallel/psCompactionManager.cpp b/src/hotspot/share/gc/parallel/psCompactionManager.cpp index 4025a5a4b18..0a71ec80e3b 100644 --- a/src/hotspot/share/gc/parallel/psCompactionManager.cpp +++ b/src/hotspot/share/gc/parallel/psCompactionManager.cpp @@ -67,7 +67,7 @@ void ParCompactionManager::initialize(ParMarkBitMap* mbm) { _mark_bitmap = mbm; - uint parallel_gc_threads = ParallelScavengeHeap::heap()->workers().total_workers(); + uint parallel_gc_threads = ParallelScavengeHeap::heap()->workers().max_workers(); assert(_manager_array == NULL, "Attempt to initialize twice"); _manager_array = NEW_C_HEAP_ARRAY(ParCompactionManager*, parallel_gc_threads+1, mtGC); @@ -87,7 +87,7 @@ void ParCompactionManager::initialize(ParMarkBitMap* mbm) { // The VMThread gets its own ParCompactionManager, which is not available // for work stealing. _manager_array[parallel_gc_threads] = new ParCompactionManager(); - assert(ParallelScavengeHeap::heap()->workers().total_workers() != 0, + assert(ParallelScavengeHeap::heap()->workers().max_workers() != 0, "Not initialized?"); _shadow_region_array = new (ResourceObj::C_HEAP, mtGC) GrowableArray(10, mtGC); @@ -96,14 +96,14 @@ void ParCompactionManager::initialize(ParMarkBitMap* mbm) { } void ParCompactionManager::reset_all_bitmap_query_caches() { - uint parallel_gc_threads = ParallelScavengeHeap::heap()->workers().total_workers(); + uint parallel_gc_threads = ParallelScavengeHeap::heap()->workers().max_workers(); for (uint i=0; i<=parallel_gc_threads; i++) { _manager_array[i]->reset_bitmap_query_cache(); } } void ParCompactionManager::flush_all_string_dedup_requests() { - uint parallel_gc_threads = ParallelScavengeHeap::heap()->workers().total_workers(); + uint parallel_gc_threads = ParallelScavengeHeap::heap()->workers().max_workers(); for (uint i=0; i<=parallel_gc_threads; i++) { _manager_array[i]->flush_string_dedup_requests(); } diff --git a/src/hotspot/share/gc/parallel/psOldGen.cpp b/src/hotspot/share/gc/parallel/psOldGen.cpp index a8b871f2011..4f689ec7251 100644 --- a/src/hotspot/share/gc/parallel/psOldGen.cpp +++ b/src/hotspot/share/gc/parallel/psOldGen.cpp @@ -359,7 +359,7 @@ void PSOldGen::post_resize() { start_array()->set_covered_region(new_memregion); ParallelScavengeHeap::heap()->card_table()->resize_covered_region(new_memregion); - WorkGang* workers = Thread::current()->is_VM_thread() ? + WorkerThreads* workers = Thread::current()->is_VM_thread() ? &ParallelScavengeHeap::heap()->workers() : NULL; // The update of the space's end is done by this call. As that diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.cpp b/src/hotspot/share/gc/parallel/psParallelCompact.cpp index f24d849c964..4de272e8829 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.cpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.cpp @@ -60,7 +60,8 @@ #include "gc/shared/taskTerminator.hpp" #include "gc/shared/weakProcessor.inline.hpp" #include "gc/shared/workerPolicy.hpp" -#include "gc/shared/workgroup.hpp" +#include "gc/shared/workerThread.hpp" +#include "gc/shared/workerUtils.hpp" #include "logging/log.hpp" #include "memory/iterator.inline.hpp" #include "memory/metaspaceUtils.hpp" @@ -1765,10 +1766,10 @@ bool PSParallelCompact::invoke_no_policy(bool maximum_heap_compaction) { { const uint active_workers = - WorkerPolicy::calc_active_workers(ParallelScavengeHeap::heap()->workers().total_workers(), + WorkerPolicy::calc_active_workers(ParallelScavengeHeap::heap()->workers().max_workers(), ParallelScavengeHeap::heap()->workers().active_workers(), Threads::number_of_non_daemon_threads()); - ParallelScavengeHeap::heap()->workers().update_active_workers(active_workers); + ParallelScavengeHeap::heap()->workers().set_active_workers(active_workers); GCTraceCPUTime tcpu; GCTraceTime(Info, gc) tm("Pause Full", NULL, gc_cause, true); @@ -2016,7 +2017,7 @@ void steal_marking_work(TaskTerminator& terminator, uint worker_id) { } while (!terminator.offer_termination()); } -class MarkFromRootsTask : public AbstractGangTask { +class MarkFromRootsTask : public WorkerTask { StrongRootsScope _strong_roots_scope; // needed for Threads::possibly_parallel_threads_do OopStorageSetStrongParState _oop_storage_set_par_state; SequentialSubTasksDone _subtasks; @@ -2025,7 +2026,7 @@ class MarkFromRootsTask : public AbstractGangTask { public: MarkFromRootsTask(uint active_workers) : - AbstractGangTask("MarkFromRootsTask"), + WorkerTask("MarkFromRootsTask"), _strong_roots_scope(active_workers), _subtasks(ParallelRootType::sentinel), _terminator(active_workers, ParCompactionManager::oop_task_queues()), @@ -2152,7 +2153,7 @@ void PCAdjustPointerClosure::verify_cm(ParCompactionManager* cm) { } #endif -class PSAdjustTask final : public AbstractGangTask { +class PSAdjustTask final : public WorkerTask { SubTasksDone _sub_tasks; WeakProcessor::Task _weak_proc_task; OopStorageSetStrongParState _oop_storage_iter; @@ -2168,7 +2169,7 @@ class PSAdjustTask final : public AbstractGangTask { public: PSAdjustTask(uint nworkers) : - AbstractGangTask("PSAdjust task"), + WorkerTask("PSAdjust task"), _sub_tasks(PSAdjustSubTask_num_elements), _weak_proc_task(nworkers), _nworkers(nworkers) { @@ -2491,14 +2492,14 @@ static void compaction_with_stealing_work(TaskTerminator* terminator, uint worke } } -class UpdateDensePrefixAndCompactionTask: public AbstractGangTask { +class UpdateDensePrefixAndCompactionTask: public WorkerTask { TaskQueue& _tq; TaskTerminator _terminator; uint _active_workers; public: UpdateDensePrefixAndCompactionTask(TaskQueue& tq, uint active_workers) : - AbstractGangTask("UpdateDensePrefixAndCompactionTask"), + WorkerTask("UpdateDensePrefixAndCompactionTask"), _tq(tq), _terminator(active_workers, ParCompactionManager::region_task_queues()), _active_workers(active_workers) { diff --git a/src/hotspot/share/gc/parallel/psScavenge.cpp b/src/hotspot/share/gc/parallel/psScavenge.cpp index 3a63ccde5db..293ca5b3810 100644 --- a/src/hotspot/share/gc/parallel/psScavenge.cpp +++ b/src/hotspot/share/gc/parallel/psScavenge.cpp @@ -54,7 +54,8 @@ #include "gc/shared/taskTerminator.hpp" #include "gc/shared/weakProcessor.inline.hpp" #include "gc/shared/workerPolicy.hpp" -#include "gc/shared/workgroup.hpp" +#include "gc/shared/workerThread.hpp" +#include "gc/shared/workerUtils.hpp" #include "memory/iterator.hpp" #include "memory/resourceArea.hpp" #include "memory/universe.hpp" @@ -277,7 +278,7 @@ public: } }; -class ScavengeRootsTask : public AbstractGangTask { +class ScavengeRootsTask : public WorkerTask { StrongRootsScope _strong_roots_scope; // needed for Threads::possibly_parallel_threads_do OopStorageSetStrongParState _oop_storage_strong_par_state; SequentialSubTasksDone _subtasks; @@ -292,7 +293,7 @@ public: HeapWord* gen_top, uint active_workers, bool is_empty) : - AbstractGangTask("ScavengeRootsTask"), + WorkerTask("ScavengeRootsTask"), _strong_roots_scope(active_workers), _subtasks(ParallelRootType::sentinel), _old_gen(old_gen), @@ -463,10 +464,10 @@ bool PSScavenge::invoke_no_policy() { HeapWord* old_top = old_gen->object_space()->top(); const uint active_workers = - WorkerPolicy::calc_active_workers(ParallelScavengeHeap::heap()->workers().total_workers(), + WorkerPolicy::calc_active_workers(ParallelScavengeHeap::heap()->workers().max_workers(), ParallelScavengeHeap::heap()->workers().active_workers(), Threads::number_of_non_daemon_threads()); - ParallelScavengeHeap::heap()->workers().update_active_workers(active_workers); + ParallelScavengeHeap::heap()->workers().set_active_workers(active_workers); PSPromotionManager::pre_scavenge(); diff --git a/src/hotspot/share/gc/parallel/psYoungGen.cpp b/src/hotspot/share/gc/parallel/psYoungGen.cpp index a4ebea468de..9a09bfbd917 100644 --- a/src/hotspot/share/gc/parallel/psYoungGen.cpp +++ b/src/hotspot/share/gc/parallel/psYoungGen.cpp @@ -189,7 +189,7 @@ void PSYoungGen::set_space_boundaries(size_t eden_size, size_t survivor_size) { MemRegion to_mr ((HeapWord*)to_start, (HeapWord*)from_start); MemRegion from_mr((HeapWord*)from_start, (HeapWord*)from_end); - WorkGang& pretouch_workers = ParallelScavengeHeap::heap()->workers(); + WorkerThreads& pretouch_workers = ParallelScavengeHeap::heap()->workers(); eden_space()->initialize(eden_mr, true, ZapUnusedHeapArea, MutableSpace::SetupPages, &pretouch_workers); to_space()->initialize(to_mr , true, ZapUnusedHeapArea, MutableSpace::SetupPages, &pretouch_workers); from_space()->initialize(from_mr, true, ZapUnusedHeapArea, MutableSpace::SetupPages, &pretouch_workers); @@ -638,7 +638,7 @@ void PSYoungGen::resize_spaces(size_t requested_eden_size, to_space()->check_mangled_unused_area(limit); } - WorkGang* workers = &ParallelScavengeHeap::heap()->workers(); + WorkerThreads* workers = &ParallelScavengeHeap::heap()->workers(); // When an existing space is being initialized, it is not // mangled because the space has been previously mangled. diff --git a/src/hotspot/share/gc/shared/collectedHeap.hpp b/src/hotspot/share/gc/shared/collectedHeap.hpp index 6e78724c133..8db274070e4 100644 --- a/src/hotspot/share/gc/shared/collectedHeap.hpp +++ b/src/hotspot/share/gc/shared/collectedHeap.hpp @@ -44,7 +44,7 @@ // class defines the functions that a heap must implement, and contains // infrastructure common to all heaps. -class AbstractGangTask; +class WorkerTask; class AdaptiveSizePolicy; class BarrierSet; class GCHeapLog; @@ -59,7 +59,7 @@ class SoftRefPolicy; class Thread; class ThreadClosure; class VirtualSpaceSummary; -class WorkGang; +class WorkerThreads; class nmethod; class ParallelObjectIterator : public CHeapObj { @@ -469,7 +469,7 @@ class CollectedHeap : public CHeapObj { // concurrent marking) for an intermittent non-GC safepoint. // If this method returns NULL, SafepointSynchronize will // perform cleanup tasks serially in the VMThread. - virtual WorkGang* safepoint_workers() { return NULL; } + virtual WorkerThreads* safepoint_workers() { return NULL; } // Support for object pinning. This is used by JNI Get*Critical() // and Release*Critical() family of functions. If supported, the GC diff --git a/src/hotspot/share/gc/shared/genCollectedHeap.cpp b/src/hotspot/share/gc/shared/genCollectedHeap.cpp index c392f14d4a3..18658dd9edf 100644 --- a/src/hotspot/share/gc/shared/genCollectedHeap.cpp +++ b/src/hotspot/share/gc/shared/genCollectedHeap.cpp @@ -55,7 +55,7 @@ #include "gc/shared/space.hpp" #include "gc/shared/strongRootsScope.hpp" #include "gc/shared/weakProcessor.hpp" -#include "gc/shared/workgroup.hpp" +#include "gc/shared/workerThread.hpp" #include "memory/iterator.hpp" #include "memory/metaspaceCounters.hpp" #include "memory/metaspaceUtils.hpp" diff --git a/src/hotspot/share/gc/shared/genCollectedHeap.hpp b/src/hotspot/share/gc/shared/genCollectedHeap.hpp index 2dfe006cc54..28ed627b80f 100644 --- a/src/hotspot/share/gc/shared/genCollectedHeap.hpp +++ b/src/hotspot/share/gc/shared/genCollectedHeap.hpp @@ -37,7 +37,7 @@ class GCPolicyCounters; class GenerationSpec; class StrongRootsScope; class SubTasksDone; -class WorkGang; +class WorkerThreads; // A "GenCollectedHeap" is a CollectedHeap that uses generational // collection. It has two generations, young and old. diff --git a/src/hotspot/share/gc/shared/parallelCleaning.hpp b/src/hotspot/share/gc/shared/parallelCleaning.hpp index 12c0382d2a3..c600dbb563e 100644 --- a/src/hotspot/share/gc/shared/parallelCleaning.hpp +++ b/src/hotspot/share/gc/shared/parallelCleaning.hpp @@ -28,7 +28,7 @@ #include "classfile/classLoaderDataGraph.hpp" #include "code/codeCache.hpp" #include "gc/shared/oopStorageParState.hpp" -#include "gc/shared/workgroup.hpp" +#include "gc/shared/workerThread.hpp" class CodeCacheUnloadingTask { diff --git a/src/hotspot/share/gc/shared/preservedMarks.cpp b/src/hotspot/share/gc/shared/preservedMarks.cpp index 8dfd7cf0ff4..718f97085f6 100644 --- a/src/hotspot/share/gc/shared/preservedMarks.cpp +++ b/src/hotspot/share/gc/shared/preservedMarks.cpp @@ -24,7 +24,8 @@ #include "precompiled.hpp" #include "gc/shared/preservedMarks.inline.hpp" -#include "gc/shared/workgroup.hpp" +#include "gc/shared/workerThread.hpp" +#include "gc/shared/workerUtils.hpp" #include "memory/allocation.inline.hpp" #include "memory/resourceArea.hpp" #include "oops/oop.inline.hpp" @@ -92,7 +93,7 @@ void PreservedMarksSet::init(uint num) { assert_empty(); } -class RestorePreservedMarksTask : public AbstractGangTask { +class RestorePreservedMarksTask : public WorkerTask { PreservedMarksSet* const _preserved_marks_set; SequentialSubTasksDone _sub_tasks; volatile size_t _total_size; @@ -109,7 +110,7 @@ public: } RestorePreservedMarksTask(PreservedMarksSet* preserved_marks_set) - : AbstractGangTask("Restore Preserved Marks"), + : WorkerTask("Restore Preserved Marks"), _preserved_marks_set(preserved_marks_set), _sub_tasks(preserved_marks_set->num()), _total_size(0) @@ -129,7 +130,7 @@ public: } }; -void PreservedMarksSet::restore(WorkGang* workers) { +void PreservedMarksSet::restore(WorkerThreads* workers) { { RestorePreservedMarksTask cl(this); if (workers == nullptr) { @@ -142,7 +143,7 @@ void PreservedMarksSet::restore(WorkGang* workers) { assert_empty(); } -AbstractGangTask* PreservedMarksSet::create_task() { +WorkerTask* PreservedMarksSet::create_task() { return new RestorePreservedMarksTask(this); } diff --git a/src/hotspot/share/gc/shared/preservedMarks.hpp b/src/hotspot/share/gc/shared/preservedMarks.hpp index d04d22ef3c9..21b40903e7f 100644 --- a/src/hotspot/share/gc/shared/preservedMarks.hpp +++ b/src/hotspot/share/gc/shared/preservedMarks.hpp @@ -30,9 +30,9 @@ #include "oops/oop.hpp" #include "utilities/stack.hpp" -class AbstractGangTask; +class WorkerTask; class PreservedMarksSet; -class WorkGang; +class WorkerThreads; class PreservedMarks { private: @@ -110,11 +110,11 @@ public: void init(uint num); // Iterate over all stacks, restore all preserved marks, and reclaim - // the memory taken up by the stack segments using the given WorkGang. If the WorkGang + // the memory taken up by the stack segments using the given WorkerThreads. If the WorkerThreads // is NULL, perform the work serially in the current thread. - void restore(WorkGang* workers); + void restore(WorkerThreads* workers); - AbstractGangTask* create_task(); + WorkerTask* create_task(); // Reclaim stack array. void reclaim(); diff --git a/src/hotspot/share/gc/shared/pretouchTask.cpp b/src/hotspot/share/gc/shared/pretouchTask.cpp index 244c7282cf7..13200756574 100644 --- a/src/hotspot/share/gc/shared/pretouchTask.cpp +++ b/src/hotspot/share/gc/shared/pretouchTask.cpp @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "gc/shared/gc_globals.hpp" #include "gc/shared/pretouchTask.hpp" +#include "logging/log.hpp" #include "runtime/atomic.hpp" #include "runtime/globals.hpp" #include "runtime/os.hpp" @@ -34,7 +35,7 @@ PretouchTask::PretouchTask(const char* task_name, char* end_address, size_t page_size, size_t chunk_size) : - AbstractGangTask(task_name), + WorkerTask(task_name), _cur_addr(start_address), _end_addr(end_address), _page_size(page_size), @@ -62,7 +63,7 @@ void PretouchTask::work(uint worker_id) { } void PretouchTask::pretouch(const char* task_name, char* start_address, char* end_address, - size_t page_size, WorkGang* pretouch_gang) { + size_t page_size, WorkerThreads* pretouch_workers) { // Chunk size should be at least (unmodified) page size as using multiple threads // pretouch on a single page can decrease performance. size_t chunk_size = MAX2(PretouchTask::chunk_size(), page_size); @@ -79,14 +80,14 @@ void PretouchTask::pretouch(const char* task_name, char* start_address, char* en return; } - if (pretouch_gang != NULL) { + if (pretouch_workers != NULL) { size_t num_chunks = (total_bytes + chunk_size - 1) / chunk_size; - uint num_workers = (uint)MIN2(num_chunks, (size_t)pretouch_gang->total_workers()); + uint num_workers = (uint)MIN2(num_chunks, (size_t)pretouch_workers->max_workers()); log_debug(gc, heap)("Running %s with %u workers for " SIZE_FORMAT " work units pre-touching " SIZE_FORMAT "B.", task.name(), num_workers, num_chunks, total_bytes); - pretouch_gang->run_task(&task, num_workers); + pretouch_workers->run_task(&task, num_workers); } else { log_debug(gc, heap)("Running %s pre-touching " SIZE_FORMAT "B.", task.name(), total_bytes); diff --git a/src/hotspot/share/gc/shared/pretouchTask.hpp b/src/hotspot/share/gc/shared/pretouchTask.hpp index c6883220372..7c66c8b717c 100644 --- a/src/hotspot/share/gc/shared/pretouchTask.hpp +++ b/src/hotspot/share/gc/shared/pretouchTask.hpp @@ -25,9 +25,9 @@ #ifndef SHARE_GC_SHARED_PRETOUCH_HPP #define SHARE_GC_SHARED_PRETOUCH_HPP -#include "gc/shared/workgroup.hpp" +#include "gc/shared/workerThread.hpp" -class PretouchTask : public AbstractGangTask { +class PretouchTask : public WorkerTask { char* volatile _cur_addr; char* const _end_addr; size_t _page_size; @@ -41,7 +41,7 @@ public: static size_t chunk_size(); static void pretouch(const char* task_name, char* start_address, char* end_address, - size_t page_size, WorkGang* pretouch_gang); + size_t page_size, WorkerThreads* pretouch_workers); }; diff --git a/src/hotspot/share/gc/shared/referenceProcessor.cpp b/src/hotspot/share/gc/shared/referenceProcessor.cpp index 759811331d1..48d5280b664 100644 --- a/src/hotspot/share/gc/shared/referenceProcessor.cpp +++ b/src/hotspot/share/gc/shared/referenceProcessor.cpp @@ -705,12 +705,12 @@ void ReferenceProcessor::run_task(RefProcTask& task, RefProcProxyTask& proxy_tas proxy_task.prepare_run_task(task, num_queues(), processing_is_mt() ? RefProcThreadModel::Multi : RefProcThreadModel::Single, marks_oops_alive); if (processing_is_mt()) { - WorkGang* gang = Universe::heap()->safepoint_workers(); - assert(gang != NULL, "can not dispatch multi threaded without a work gang"); - assert(gang->active_workers() >= num_queues(), + WorkerThreads* workers = Universe::heap()->safepoint_workers(); + assert(workers != NULL, "can not dispatch multi threaded without workers"); + assert(workers->active_workers() >= num_queues(), "Ergonomically chosen workers(%u) should be less than or equal to active workers(%u)", - num_queues(), gang->active_workers()); - gang->run_task(&proxy_task, num_queues()); + num_queues(), workers->active_workers()); + workers->run_task(&proxy_task, num_queues()); } else { for (unsigned i = 0; i < _max_num_queues; ++i) { proxy_task.work(i); diff --git a/src/hotspot/share/gc/shared/referenceProcessor.hpp b/src/hotspot/share/gc/shared/referenceProcessor.hpp index 349cee8cb7d..f95ec84e06b 100644 --- a/src/hotspot/share/gc/shared/referenceProcessor.hpp +++ b/src/hotspot/share/gc/shared/referenceProcessor.hpp @@ -28,7 +28,7 @@ #include "gc/shared/referenceDiscoverer.hpp" #include "gc/shared/referencePolicy.hpp" #include "gc/shared/referenceProcessorStats.hpp" -#include "gc/shared/workgroup.hpp" +#include "gc/shared/workerThread.hpp" #include "memory/referenceType.hpp" #include "oops/instanceRefKlass.hpp" @@ -589,7 +589,7 @@ public: * of RefProcTask that will handle reference processing in a generic way for Serial, * Parallel and G1. This proxy will add the relevant closures, task terminators etc. */ -class RefProcProxyTask : public AbstractGangTask { +class RefProcProxyTask : public WorkerTask { protected: const uint _max_workers; RefProcTask* _rp_task; @@ -598,7 +598,7 @@ protected: bool _marks_oops_alive; public: - RefProcProxyTask(const char* name, uint max_workers) : AbstractGangTask(name), _max_workers(max_workers), _rp_task(nullptr),_tm(RefProcThreadModel::Single), _queue_count(0), _marks_oops_alive(false) {} + RefProcProxyTask(const char* name, uint max_workers) : WorkerTask(name), _max_workers(max_workers), _rp_task(nullptr),_tm(RefProcThreadModel::Single), _queue_count(0), _marks_oops_alive(false) {} void prepare_run_task(RefProcTask& rp_task, uint queue_count, RefProcThreadModel tm, bool marks_oops_alive) { _rp_task = &rp_task; diff --git a/src/hotspot/share/gc/shared/space.hpp b/src/hotspot/share/gc/shared/space.hpp index 48e44febcc1..f2a9c24904e 100644 --- a/src/hotspot/share/gc/shared/space.hpp +++ b/src/hotspot/share/gc/shared/space.hpp @@ -27,7 +27,7 @@ #include "gc/shared/blockOffsetTable.hpp" #include "gc/shared/cardTable.hpp" -#include "gc/shared/workgroup.hpp" +#include "gc/shared/workerThread.hpp" #include "memory/allocation.hpp" #include "memory/iterator.hpp" #include "memory/memRegion.hpp" diff --git a/src/hotspot/share/gc/shared/weakProcessor.cpp b/src/hotspot/share/gc/shared/weakProcessor.cpp index 374661edf48..aa7c8a719a1 100644 --- a/src/hotspot/share/gc/shared/weakProcessor.cpp +++ b/src/hotspot/share/gc/shared/weakProcessor.cpp @@ -125,6 +125,6 @@ void WeakProcessor::Task::report_num_dead() { _storage_states.report_num_dead(); } -void WeakProcessor::GangTask::work(uint worker_id) { +void WeakProcessor::WeakOopsDoTask::work(uint worker_id) { _erased_do_work(this, worker_id); } diff --git a/src/hotspot/share/gc/shared/weakProcessor.hpp b/src/hotspot/share/gc/shared/weakProcessor.hpp index 600f2520691..5eb2c59f3f2 100644 --- a/src/hotspot/share/gc/shared/weakProcessor.hpp +++ b/src/hotspot/share/gc/shared/weakProcessor.hpp @@ -27,11 +27,11 @@ #include "gc/shared/oopStorageParState.hpp" #include "gc/shared/oopStorageSetParState.hpp" -#include "gc/shared/workgroup.hpp" +#include "gc/shared/workerThread.hpp" #include "memory/allocation.hpp" class WeakProcessorTimes; -class WorkGang; +class WorkerThreads; // Helper class to aid in root scanning and cleaning of weak oops in the VM. // @@ -53,7 +53,7 @@ public: // IsAlive must be derived from BoolObjectClosure. // KeepAlive must be derived from OopClosure. template - static void weak_oops_do(WorkGang* workers, + static void weak_oops_do(WorkerThreads* workers, IsAlive* is_alive, KeepAlive* keep_alive, WeakProcessorTimes* times); @@ -64,7 +64,7 @@ public: // IsAlive must be derived from BoolObjectClosure. // KeepAlive must be derived from OopClosure. template - static void weak_oops_do(WorkGang* workers, + static void weak_oops_do(WorkerThreads* workers, IsAlive* is_alive, KeepAlive* keep_alive, uint indent_log); @@ -79,7 +79,7 @@ private: template class CountingClosure; - class GangTask; + class WeakOopsDoTask; }; class WeakProcessor::Task { diff --git a/src/hotspot/share/gc/shared/weakProcessor.inline.hpp b/src/hotspot/share/gc/shared/weakProcessor.inline.hpp index f1b8e6f92b0..edb1bf4471d 100644 --- a/src/hotspot/share/gc/shared/weakProcessor.inline.hpp +++ b/src/hotspot/share/gc/shared/weakProcessor.inline.hpp @@ -32,7 +32,7 @@ #include "gc/shared/oopStorageParState.inline.hpp" #include "gc/shared/oopStorageSet.hpp" #include "gc/shared/weakProcessorTimes.hpp" -#include "gc/shared/workgroup.hpp" +#include "gc/shared/workerThread.hpp" #include "prims/resolvedMethodTable.hpp" #include "utilities/debug.hpp" #include "utilities/enumIterator.hpp" @@ -96,14 +96,14 @@ void WeakProcessor::Task::work(uint worker_id, } } -class WeakProcessor::GangTask : public AbstractGangTask { +class WeakProcessor::WeakOopsDoTask : public WorkerTask { Task _task; BoolObjectClosure* _is_alive; OopClosure* _keep_alive; - void (*_erased_do_work)(GangTask* task, uint worker_id); + void (*_erased_do_work)(WeakOopsDoTask* task, uint worker_id); template - static void erased_do_work(GangTask* task, uint worker_id) { + static void erased_do_work(WeakOopsDoTask* task, uint worker_id) { task->_task.work(worker_id, static_cast(task->_is_alive), static_cast(task->_keep_alive)); @@ -111,12 +111,12 @@ class WeakProcessor::GangTask : public AbstractGangTask { public: template - GangTask(const char* name, - IsAlive* is_alive, - KeepAlive* keep_alive, - WeakProcessorTimes* times, - uint nworkers) : - AbstractGangTask(name), + WeakOopsDoTask(const char* name, + IsAlive* is_alive, + KeepAlive* keep_alive, + WeakProcessorTimes* times, + uint nworkers) : + WorkerTask(name), _task(times, nworkers), _is_alive(is_alive), _keep_alive(keep_alive), @@ -128,26 +128,26 @@ public: }; template -void WeakProcessor::weak_oops_do(WorkGang* workers, +void WeakProcessor::weak_oops_do(WorkerThreads* workers, IsAlive* is_alive, KeepAlive* keep_alive, WeakProcessorTimes* times) { WeakProcessorTimeTracker tt(times); - uint nworkers = ergo_workers(MIN2(workers->total_workers(), + uint nworkers = ergo_workers(MIN2(workers->max_workers(), times->max_threads())); - GangTask task("Weak Processor", is_alive, keep_alive, times, nworkers); + WeakOopsDoTask task("Weak Processor", is_alive, keep_alive, times, nworkers); workers->run_task(&task, nworkers); task.report_num_dead(); } template -void WeakProcessor::weak_oops_do(WorkGang* workers, +void WeakProcessor::weak_oops_do(WorkerThreads* workers, IsAlive* is_alive, KeepAlive* keep_alive, uint indent_log) { - uint nworkers = ergo_workers(workers->total_workers()); + uint nworkers = ergo_workers(workers->max_workers()); WeakProcessorTimes times(nworkers); weak_oops_do(workers, is_alive, keep_alive, ×); times.log_subtotals(indent_log); // Caller logs total if desired. diff --git a/src/hotspot/share/gc/shared/workerManager.hpp b/src/hotspot/share/gc/shared/workerManager.hpp deleted file mode 100644 index d9698b0d823..00000000000 --- a/src/hotspot/share/gc/shared/workerManager.hpp +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef SHARE_GC_SHARED_WORKERMANAGER_HPP -#define SHARE_GC_SHARED_WORKERMANAGER_HPP - -#include "gc/shared/gc_globals.hpp" -#include "logging/log.hpp" -#include "memory/allocation.hpp" -#include "runtime/os.hpp" -#include "runtime/thread.hpp" -#include "utilities/globalDefinitions.hpp" - -class WorkerManager : public AllStatic { - public: - // Create additional workers as needed. - // active_workers - number of workers being requested for an upcoming - // parallel task. - // total_workers - total number of workers. This is the maximum - // number possible. - // created_workers - number of workers already created. This maybe - // less than, equal to, or greater than active workers. If greater than - // or equal to active_workers, nothing is done. - // worker_type - type of thread. - // initializing - true if this is called to get the initial number of - // GC workers. - // If initializing is true, do a vm exit if the workers cannot be created. - // The initializing = true case is for JVM start up and failing to - // create all the worker at start should considered a problem so exit. - // If initializing = false, there are already some number of worker - // threads and a failure would not be optimal but should not be fatal. - static uint add_workers (WorkGang* workers, - uint active_workers, - uint total_workers, - uint created_workers, - os::ThreadType worker_type, - bool initializing); - - // Log (at trace level) a change in the number of created workers. - static void log_worker_creation(WorkGang* workers, - uint previous_created_workers, - uint active_workers, - uint created_workers, - bool initializing); -}; - -uint WorkerManager::add_workers(WorkGang* workers, - uint active_workers, - uint total_workers, - uint created_workers, - os::ThreadType worker_type, - bool initializing) { - uint start = created_workers; - uint end = MIN2(active_workers, total_workers); - for (uint worker_id = start; worker_id < end; worker_id += 1) { - WorkerThread* new_worker = NULL; - if (initializing || !InjectGCWorkerCreationFailure) { - new_worker = workers->install_worker(worker_id); - } - if (new_worker == NULL || !os::create_thread(new_worker, worker_type)) { - log_trace(gc, task)("WorkerManager::add_workers() : " - "creation failed due to failed allocation of native %s", - new_worker == NULL ? "memory" : "thread"); - delete new_worker; - if (initializing) { - vm_exit_out_of_memory(0, OOM_MALLOC_ERROR, "Cannot create worker GC thread. Out of system resources."); - } - break; - } - created_workers++; - os::start_thread(new_worker); - } - - log_trace(gc, task)("WorkerManager::add_workers() : " - "created_workers: %u", created_workers); - - return created_workers; -} - -void WorkerManager::log_worker_creation(WorkGang* workers, - uint previous_created_workers, - uint active_workers, - uint created_workers, - bool initializing) { - if (previous_created_workers < created_workers) { - const char* initializing_msg = initializing ? "Adding initial" : "Creating additional"; - log_trace(gc, task)("%s %s(s) previously created workers %u active workers %u total created workers %u", - initializing_msg, workers->group_name(), previous_created_workers, active_workers, created_workers); - } -} - -#endif // SHARE_GC_SHARED_WORKERMANAGER_HPP diff --git a/src/hotspot/share/gc/shared/workerThread.cpp b/src/hotspot/share/gc/shared/workerThread.cpp new file mode 100644 index 00000000000..183349ef245 --- /dev/null +++ b/src/hotspot/share/gc/shared/workerThread.cpp @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "gc/shared/gc_globals.hpp" +#include "gc/shared/workerThread.hpp" +#include "logging/log.hpp" +#include "runtime/atomic.hpp" +#include "runtime/init.hpp" +#include "runtime/java.hpp" +#include "runtime/os.hpp" + +WorkerTaskDispatcher::WorkerTaskDispatcher() : + _task(NULL), + _started(0), + _not_finished(0), + _start_semaphore(), + _end_semaphore() {} + +void WorkerTaskDispatcher::coordinator_distribute_task(WorkerTask* task, uint num_workers) { + // No workers are allowed to read the state variables until they have been signaled. + _task = task; + _not_finished = num_workers; + + // Dispatch 'num_workers' number of tasks. + _start_semaphore.signal(num_workers); + + // Wait for the last worker to signal the coordinator. + _end_semaphore.wait(); + + // No workers are allowed to read the state variables after the coordinator has been signaled. + assert(_not_finished == 0, "%d not finished workers?", _not_finished); + _task = NULL; + _started = 0; +} + +void WorkerTaskDispatcher::worker_run_task() { + // Wait for the coordinator to dispatch a task. + _start_semaphore.wait(); + + // Get worker id. + const uint worker_id = Atomic::fetch_and_add(&_started, 1u); + + // Run task. + GCIdMark gc_id_mark(_task->gc_id()); + _task->work(worker_id); + + // Mark that the worker is done with the task. + // The worker is not allowed to read the state variables after this line. + const uint not_finished = Atomic::sub(&_not_finished, 1u); + + // The last worker signals to the coordinator that all work is completed. + if (not_finished == 0) { + _end_semaphore.signal(); + } +} + +WorkerThreads::WorkerThreads(const char* name, uint max_workers) : + _name(name), + _workers(NEW_C_HEAP_ARRAY(WorkerThread*, max_workers, mtInternal)), + _max_workers(max_workers), + _created_workers(0), + _active_workers(0), + _dispatcher() {} + +void WorkerThreads::initialize_workers() { + const uint initial_active_workers = UseDynamicNumberOfGCThreads ? 1 : _max_workers; + if (set_active_workers(initial_active_workers) != initial_active_workers) { + vm_exit_during_initialization(); + } +} + +WorkerThread* WorkerThreads::create_worker(uint id) { + if (is_init_completed() && InjectGCWorkerCreationFailure) { + return NULL; + } + + WorkerThread* const worker = new WorkerThread(_name, id, &_dispatcher); + + if (!os::create_thread(worker, os::gc_thread)) { + delete worker; + return NULL; + } + + os::start_thread(worker); + + return worker; +} + +uint WorkerThreads::set_active_workers(uint num_workers) { + assert(num_workers > 0 && num_workers <= _max_workers, + "Invalid number of active workers %u (should be 1-%u)", + num_workers, _max_workers); + + while (_created_workers < num_workers) { + WorkerThread* const worker = create_worker(_created_workers); + if (worker == NULL) { + log_error(gc, task)("Failed to create worker thread"); + break; + } + + _workers[_created_workers] = worker; + _created_workers++; + } + + _active_workers = MIN2(_created_workers, num_workers); + + log_trace(gc, task)("%s: using %d out of %d workers", _name, _active_workers, _max_workers); + + return _active_workers; +} + +void WorkerThreads::threads_do(ThreadClosure* tc) const { + for (uint i = 0; i < _created_workers; i++) { + tc->do_thread(_workers[i]); + } +} + +void WorkerThreads::run_task(WorkerTask* task) { + _dispatcher.coordinator_distribute_task(task, _active_workers); +} + +void WorkerThreads::run_task(WorkerTask* task, uint num_workers) { + WithActiveWorkers with_active_workers(this, num_workers); + run_task(task); +} + +WorkerThread::WorkerThread(const char* name_prefix, uint id, WorkerTaskDispatcher* dispatcher) : + _dispatcher(dispatcher), + _id(id) { + set_name("%s#%d", name_prefix, id); +} + +void WorkerThread::run() { + os::set_priority(this, NearMaxPriority); + + while (true) { + _dispatcher->worker_run_task(); + } +} diff --git a/src/hotspot/share/gc/shared/workerThread.hpp b/src/hotspot/share/gc/shared/workerThread.hpp new file mode 100644 index 00000000000..d4c16c246f0 --- /dev/null +++ b/src/hotspot/share/gc/shared/workerThread.hpp @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2002, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_GC_SHARED_WORKERTHREAD_HPP +#define SHARE_GC_SHARED_WORKERTHREAD_HPP + +#include "gc/shared/gcId.hpp" +#include "memory/allocation.hpp" +#include "runtime/nonJavaThread.hpp" +#include "runtime/semaphore.hpp" +#include "utilities/debug.hpp" +#include "utilities/globalDefinitions.hpp" + +class ThreadClosure; +class WorkerTaskDispatcher; +class WorkerThread; + +// An task to be worked on by worker threads +class WorkerTask : public CHeapObj { +private: + const char* _name; + const uint _gc_id; + + public: + explicit WorkerTask(const char* name) : + _name(name), + _gc_id(GCId::current_or_undefined()) {} + + const char* name() const { return _name; } + const uint gc_id() const { return _gc_id; } + + virtual void work(uint worker_id) = 0; +}; + +// WorkerThreads dispatcher implemented with semaphores +class WorkerTaskDispatcher { + // The task currently being dispatched to the WorkerThreads. + WorkerTask* _task; + + volatile uint _started; + volatile uint _not_finished; + + // Semaphore used to start the WorkerThreads. + Semaphore _start_semaphore; + // Semaphore used to notify the coordinator that all workers are done. + Semaphore _end_semaphore; + +public: + WorkerTaskDispatcher(); + + // Coordinator API. + + // Distributes the task out to num_workers workers. + // Returns when the task has been completed by all workers. + void coordinator_distribute_task(WorkerTask* task, uint num_workers); + + // Worker API. + + // Waits for a task to become available to the worker and runs it. + void worker_run_task(); +}; + +// A set of worker threads to execute tasks +class WorkerThreads : public CHeapObj { +private: + const char* const _name; + WorkerThread** _workers; + const uint _max_workers; + uint _created_workers; + uint _active_workers; + WorkerTaskDispatcher _dispatcher; + +protected: + virtual WorkerThread* create_worker(uint id); + +public: + WorkerThreads(const char* name, uint max_workers); + + void initialize_workers(); + + uint max_workers() const { return _max_workers; } + uint created_workers() const { return _created_workers; } + uint active_workers() const { return _active_workers; } + + uint set_active_workers(uint num_workers); + + void threads_do(ThreadClosure* tc) const; + + const char* name() const { return _name; } + + // Run a task using the current active number of workers, returns when the task is done. + void run_task(WorkerTask* task); + + // Run a task with the given number of workers, returns when the task is done. + void run_task(WorkerTask* task, uint num_workers); +}; + +class WorkerThread : public NamedThread { +private: + WorkerTaskDispatcher* const _dispatcher; + const uint _id; + +public: + static WorkerThread* current() { + return WorkerThread::cast(Thread::current()); + } + + static WorkerThread* cast(Thread* t) { + assert(t->is_Worker_thread(), "incorrect cast to WorkerThread"); + return static_cast(t); + } + + WorkerThread(const char* name_prefix, uint id, WorkerTaskDispatcher* dispatcher); + + uint id() const { return _id; } + + bool is_Worker_thread() const override { return true; } + const char* type_name() const override { return "WorkerThread"; } + + void run() override; +}; + +// Temporarily try to set the number of active workers. +// It's not guaranteed that it succeeds, and users need to +// query the number of active workers. +class WithActiveWorkers : public StackObj { +private: + WorkerThreads* const _workers; + const uint _prev_active_workers; + +public: + WithActiveWorkers(WorkerThreads* workers, uint num_workers) : + _workers(workers), + _prev_active_workers(workers->active_workers()) { + _workers->set_active_workers(num_workers); + } + + ~WithActiveWorkers() { + _workers->set_active_workers(_prev_active_workers); + } +}; + +#endif // SHARE_GC_SHARED_WORKERTHREAD_HPP diff --git a/src/hotspot/share/gc/shared/workerUtils.cpp b/src/hotspot/share/gc/shared/workerUtils.cpp new file mode 100644 index 00000000000..a9b771a299f --- /dev/null +++ b/src/hotspot/share/gc/shared/workerUtils.cpp @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "gc/shared/workerUtils.hpp" +#include "runtime/atomic.hpp" +#include "runtime/mutexLocker.hpp" + +// *** WorkerThreadsBarrierSync + +WorkerThreadsBarrierSync::WorkerThreadsBarrierSync() + : _monitor(Mutex::nosafepoint, "WorkerThreadsBarrierSync_lock"), + _n_workers(0), _n_completed(0), _should_reset(false), _aborted(false) { +} + +void WorkerThreadsBarrierSync::set_n_workers(uint n_workers) { + _n_workers = n_workers; + _n_completed = 0; + _should_reset = false; + _aborted = false; +} + +bool WorkerThreadsBarrierSync::enter() { + MonitorLocker ml(monitor(), Mutex::_no_safepoint_check_flag); + if (should_reset()) { + // The should_reset() was set and we are the first worker to enter + // the sync barrier. We will zero the n_completed() count which + // effectively resets the barrier. + zero_completed(); + set_should_reset(false); + } + inc_completed(); + if (n_completed() == n_workers()) { + // At this point we would like to reset the barrier to be ready in + // case it is used again. However, we cannot set n_completed() to + // 0, even after the notify_all(), given that some other workers + // might still be waiting for n_completed() to become == + // n_workers(). So, if we set n_completed() to 0, those workers + // will get stuck (as they will wake up, see that n_completed() != + // n_workers() and go back to sleep). Instead, we raise the + // should_reset() flag and the barrier will be reset the first + // time a worker enters it again. + set_should_reset(true); + ml.notify_all(); + } else { + while (n_completed() != n_workers() && !aborted()) { + ml.wait(); + } + } + return !aborted(); +} + +void WorkerThreadsBarrierSync::abort() { + MutexLocker x(monitor(), Mutex::_no_safepoint_check_flag); + set_aborted(); + monitor()->notify_all(); +} + +// SubTasksDone functions. + +SubTasksDone::SubTasksDone(uint n) : + _tasks(NULL), _n_tasks(n) { + _tasks = NEW_C_HEAP_ARRAY(bool, n, mtInternal); + for (uint i = 0; i < _n_tasks; i++) { + _tasks[i] = false; + } +} + +#ifdef ASSERT +void SubTasksDone::all_tasks_claimed_impl(uint skipped[], size_t skipped_size) { + if (Atomic::cmpxchg(&_verification_done, false, true)) { + // another thread has done the verification + return; + } + // all non-skipped tasks are claimed + for (uint i = 0; i < _n_tasks; ++i) { + if (!_tasks[i]) { + auto is_skipped = false; + for (size_t j = 0; j < skipped_size; ++j) { + if (i == skipped[j]) { + is_skipped = true; + break; + } + } + assert(is_skipped, "%d not claimed.", i); + } + } + // all skipped tasks are *not* claimed + for (size_t i = 0; i < skipped_size; ++i) { + auto task_index = skipped[i]; + assert(task_index < _n_tasks, "Array in range."); + assert(!_tasks[task_index], "%d is both claimed and skipped.", task_index); + } +} +#endif + +bool SubTasksDone::try_claim_task(uint t) { + assert(t < _n_tasks, "bad task id."); + return !_tasks[t] && !Atomic::cmpxchg(&_tasks[t], false, true); +} + +SubTasksDone::~SubTasksDone() { + assert(_verification_done, "all_tasks_claimed must have been called."); + FREE_C_HEAP_ARRAY(bool, _tasks); +} + +// *** SequentialSubTasksDone + +bool SequentialSubTasksDone::try_claim_task(uint& t) { + t = _num_claimed; + if (t < _num_tasks) { + t = Atomic::add(&_num_claimed, 1u) - 1; + } + return t < _num_tasks; +} diff --git a/src/hotspot/share/gc/shared/workerUtils.hpp b/src/hotspot/share/gc/shared/workerUtils.hpp new file mode 100644 index 00000000000..223dfb34eb2 --- /dev/null +++ b/src/hotspot/share/gc/shared/workerUtils.hpp @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2002, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_GC_SHARED_WORKERUTILS_HPP +#define SHARE_GC_SHARED_WORKERUTILS_HPP + +#include "memory/allocation.hpp" +#include "metaprogramming/enableIf.hpp" +#include "metaprogramming/logical.hpp" +#include "runtime/mutex.hpp" +#include "utilities/debug.hpp" +#include "utilities/globalDefinitions.hpp" + +// A class that acts as a synchronisation barrier. Workers enter +// the barrier and must wait until all other workers have entered +// before any of them may leave. + +class WorkerThreadsBarrierSync : public StackObj { +protected: + Monitor _monitor; + uint _n_workers; + uint _n_completed; + bool _should_reset; + bool _aborted; + + Monitor* monitor() { return &_monitor; } + uint n_workers() { return _n_workers; } + uint n_completed() { return _n_completed; } + bool should_reset() { return _should_reset; } + bool aborted() { return _aborted; } + + void zero_completed() { _n_completed = 0; } + void inc_completed() { _n_completed++; } + void set_aborted() { _aborted = true; } + void set_should_reset(bool v) { _should_reset = v; } + +public: + WorkerThreadsBarrierSync(); + + // Set the number of workers that will use the barrier. + // Must be called before any of the workers start running. + void set_n_workers(uint n_workers); + + // Enter the barrier. A worker that enters the barrier will + // not be allowed to leave until all other threads have + // also entered the barrier or the barrier is aborted. + // Returns false if the barrier was aborted. + bool enter(); + + // Aborts the barrier and wakes up any threads waiting for + // the barrier to complete. The barrier will remain in the + // aborted state until the next call to set_n_workers(). + void abort(); +}; + +// A class to manage claiming of subtasks within a group of tasks. The +// subtasks will be identified by integer indices, usually elements of an +// enumeration type. + +class SubTasksDone: public CHeapObj { + volatile bool* _tasks; + uint _n_tasks; + + // make sure verification logic is run exactly once to avoid duplicate assertion failures + DEBUG_ONLY(volatile bool _verification_done = false;) + void all_tasks_claimed_impl(uint skipped[], size_t skipped_size) NOT_DEBUG_RETURN; + + NONCOPYABLE(SubTasksDone); + +public: + // Initializes "this" to a state in which there are "n" tasks to be + // processed, none of the which are originally claimed. + SubTasksDone(uint n); + + // Attempt to claim the task "t", returning true if successful, + // false if it has already been claimed. The task "t" is required + // to be within the range of "this". + bool try_claim_task(uint t); + + // The calling thread asserts that it has attempted to claim all the tasks + // that it will try to claim. Tasks that are meant to be skipped must be + // explicitly passed as extra arguments. Every thread in the parallel task + // must execute this. + template...>::value)> + void all_tasks_claimed(T0 first_skipped, Ts... more_skipped) { + static_assert(std::is_convertible::value, "not convertible"); + uint skipped[] = { static_cast(first_skipped), static_cast(more_skipped)... }; + all_tasks_claimed_impl(skipped, ARRAY_SIZE(skipped)); + } + // if there are no skipped tasks. + void all_tasks_claimed() { + all_tasks_claimed_impl(nullptr, 0); + } + + // Destructor. + ~SubTasksDone(); +}; + +// As above, but for sequential tasks, i.e. instead of claiming +// sub-tasks from a set (possibly an enumeration), claim sub-tasks +// in sequential order. This is ideal for claiming dynamically +// partitioned tasks (like striding in the parallel remembered +// set scanning). + +class SequentialSubTasksDone : public CHeapObj { + + uint _num_tasks; // Total number of tasks available. + volatile uint _num_claimed; // Number of tasks claimed. + + NONCOPYABLE(SequentialSubTasksDone); + +public: + SequentialSubTasksDone(uint num_tasks) : _num_tasks(num_tasks), _num_claimed(0) { } + ~SequentialSubTasksDone() { + // Claiming may try to claim more tasks than there are. + assert(_num_claimed >= _num_tasks, "Claimed %u tasks of %u", _num_claimed, _num_tasks); + } + + // Attempt to claim the next unclaimed task in the sequence, + // returning true if successful, with t set to the index of the + // claimed task. Returns false if there are no more unclaimed tasks + // in the sequence. In this case t is undefined. + bool try_claim_task(uint& t); +}; + +#endif // SHARE_GC_SHARED_WORKERUTILS_HPP diff --git a/src/hotspot/share/gc/shared/workgroup.cpp b/src/hotspot/share/gc/shared/workgroup.cpp deleted file mode 100644 index 54f592234c8..00000000000 --- a/src/hotspot/share/gc/shared/workgroup.cpp +++ /dev/null @@ -1,351 +0,0 @@ -/* - * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#include "precompiled.hpp" -#include "gc/shared/gcId.hpp" -#include "gc/shared/workgroup.hpp" -#include "gc/shared/workerManager.hpp" -#include "memory/allocation.hpp" -#include "memory/allocation.inline.hpp" -#include "memory/iterator.hpp" -#include "runtime/atomic.hpp" -#include "runtime/os.hpp" -#include "runtime/semaphore.hpp" -#include "runtime/thread.inline.hpp" - -// WorkGang dispatcher implemented with semaphores. -// -// Semaphores don't require the worker threads to re-claim the lock when they wake up. -// This helps lowering the latency when starting and stopping the worker threads. -class GangTaskDispatcher : public CHeapObj { - // The task currently being dispatched to the GangWorkers. - AbstractGangTask* _task; - - volatile uint _started; - volatile uint _not_finished; - - // Semaphore used to start the GangWorkers. - Semaphore* _start_semaphore; - // Semaphore used to notify the coordinator that all workers are done. - Semaphore* _end_semaphore; - -public: - GangTaskDispatcher() : - _task(NULL), - _started(0), - _not_finished(0), - _start_semaphore(new Semaphore()), - _end_semaphore(new Semaphore()) -{ } - - ~GangTaskDispatcher() { - delete _start_semaphore; - delete _end_semaphore; - } - - // Coordinator API. - - // Distributes the task out to num_workers workers. - // Returns when the task has been completed by all workers. - void coordinator_execute_on_workers(AbstractGangTask* task, uint num_workers) { - // No workers are allowed to read the state variables until they have been signaled. - _task = task; - _not_finished = num_workers; - - // Dispatch 'num_workers' number of tasks. - _start_semaphore->signal(num_workers); - - // Wait for the last worker to signal the coordinator. - _end_semaphore->wait(); - - // No workers are allowed to read the state variables after the coordinator has been signaled. - assert(_not_finished == 0, "%d not finished workers?", _not_finished); - _task = NULL; - _started = 0; - - } - - // Worker API. - - // Waits for a task to become available to the worker. - // Returns when the worker has been assigned a task. - WorkData worker_wait_for_task() { - // Wait for the coordinator to dispatch a task. - _start_semaphore->wait(); - - uint num_started = Atomic::add(&_started, 1u); - - // Subtract one to get a zero-indexed worker id. - uint worker_id = num_started - 1; - - return WorkData(_task, worker_id); - } - - // Signal to the coordinator that the worker is done with the assigned task. - void worker_done_with_task() { - // Mark that the worker is done with the task. - // The worker is not allowed to read the state variables after this line. - uint not_finished = Atomic::sub(&_not_finished, 1u); - - // The last worker signals to the coordinator that all work is completed. - if (not_finished == 0) { - _end_semaphore->signal(); - } - } -}; -// Definitions of WorkGang methods. - -WorkGang::WorkGang(const char* name, uint workers) : - _workers(NULL), - _total_workers(workers), - _active_workers(UseDynamicNumberOfGCThreads ? 1U : workers), - _created_workers(0), - _name(name), - _dispatcher(new GangTaskDispatcher()) - { } - -WorkGang::~WorkGang() { - delete _dispatcher; -} - -// The current implementation will exit if the allocation -// of any worker fails. -void WorkGang::initialize_workers() { - log_develop_trace(gc, workgang)("Constructing work gang %s with %u threads", name(), total_workers()); - _workers = NEW_C_HEAP_ARRAY(GangWorker*, total_workers(), mtInternal); - add_workers(true); -} - - -GangWorker* WorkGang::install_worker(uint worker_id) { - GangWorker* new_worker = allocate_worker(worker_id); - set_thread(worker_id, new_worker); - return new_worker; -} - -void WorkGang::add_workers(bool initializing) { - uint previous_created_workers = _created_workers; - - _created_workers = WorkerManager::add_workers(this, - _active_workers, - _total_workers, - _created_workers, - os::gc_thread, - initializing); - _active_workers = MIN2(_created_workers, _active_workers); - - WorkerManager::log_worker_creation(this, previous_created_workers, _active_workers, _created_workers, initializing); -} - -GangWorker* WorkGang::worker(uint i) const { - // Array index bounds checking. - GangWorker* result = NULL; - assert(_workers != NULL, "No workers for indexing"); - assert(i < total_workers(), "Worker index out of bounds"); - result = _workers[i]; - assert(result != NULL, "Indexing to null worker"); - return result; -} - -void WorkGang::threads_do(ThreadClosure* tc) const { - assert(tc != NULL, "Null ThreadClosure"); - uint workers = created_workers(); - for (uint i = 0; i < workers; i++) { - tc->do_thread(worker(i)); - } -} - -GangWorker* WorkGang::allocate_worker(uint worker_id) { - return new GangWorker(this, worker_id); -} - -void WorkGang::run_task(AbstractGangTask* task) { - run_task(task, active_workers()); -} - -void WorkGang::run_task(AbstractGangTask* task, uint num_workers) { - guarantee(num_workers <= total_workers(), - "Trying to execute task %s with %u workers which is more than the amount of total workers %u.", - task->name(), num_workers, total_workers()); - guarantee(num_workers > 0, "Trying to execute task %s with zero workers", task->name()); - uint old_num_workers = _active_workers; - update_active_workers(num_workers); - _dispatcher->coordinator_execute_on_workers(task, num_workers); - update_active_workers(old_num_workers); -} - -GangWorker::GangWorker(WorkGang* gang, uint id) { - _gang = gang; - set_id(id); - set_name("%s#%d", gang->name(), id); -} - -void GangWorker::run() { - initialize(); - loop(); -} - -void GangWorker::initialize() { - assert(_gang != NULL, "No gang to run in"); - os::set_priority(this, NearMaxPriority); - log_develop_trace(gc, workgang)("Running gang worker for gang %s id %u", gang()->name(), id()); - assert(!Thread::current()->is_VM_thread(), "VM thread should not be part" - " of a work gang"); -} - -WorkData GangWorker::wait_for_task() { - return gang()->dispatcher()->worker_wait_for_task(); -} - -void GangWorker::signal_task_done() { - gang()->dispatcher()->worker_done_with_task(); -} - -void GangWorker::run_task(WorkData data) { - GCIdMark gc_id_mark(data._task->gc_id()); - log_develop_trace(gc, workgang)("Running work gang: %s task: %s worker: %u", name(), data._task->name(), data._worker_id); - - data._task->work(data._worker_id); - - log_develop_trace(gc, workgang)("Finished work gang: %s task: %s worker: %u thread: " PTR_FORMAT, - name(), data._task->name(), data._worker_id, p2i(Thread::current())); -} - -void GangWorker::loop() { - while (true) { - WorkData data = wait_for_task(); - - run_task(data); - - signal_task_done(); - } -} - -// *** WorkGangBarrierSync - -WorkGangBarrierSync::WorkGangBarrierSync() - : _monitor(Mutex::nosafepoint, "WorkGangBarrierSync_lock"), - _n_workers(0), _n_completed(0), _should_reset(false), _aborted(false) { -} - -void WorkGangBarrierSync::set_n_workers(uint n_workers) { - _n_workers = n_workers; - _n_completed = 0; - _should_reset = false; - _aborted = false; -} - -bool WorkGangBarrierSync::enter() { - MonitorLocker ml(monitor(), Mutex::_no_safepoint_check_flag); - if (should_reset()) { - // The should_reset() was set and we are the first worker to enter - // the sync barrier. We will zero the n_completed() count which - // effectively resets the barrier. - zero_completed(); - set_should_reset(false); - } - inc_completed(); - if (n_completed() == n_workers()) { - // At this point we would like to reset the barrier to be ready in - // case it is used again. However, we cannot set n_completed() to - // 0, even after the notify_all(), given that some other workers - // might still be waiting for n_completed() to become == - // n_workers(). So, if we set n_completed() to 0, those workers - // will get stuck (as they will wake up, see that n_completed() != - // n_workers() and go back to sleep). Instead, we raise the - // should_reset() flag and the barrier will be reset the first - // time a worker enters it again. - set_should_reset(true); - ml.notify_all(); - } else { - while (n_completed() != n_workers() && !aborted()) { - ml.wait(); - } - } - return !aborted(); -} - -void WorkGangBarrierSync::abort() { - MutexLocker x(monitor(), Mutex::_no_safepoint_check_flag); - set_aborted(); - monitor()->notify_all(); -} - -// SubTasksDone functions. - -SubTasksDone::SubTasksDone(uint n) : - _tasks(NULL), _n_tasks(n) { - _tasks = NEW_C_HEAP_ARRAY(bool, n, mtInternal); - for (uint i = 0; i < _n_tasks; i++) { - _tasks[i] = false; - } -} - -#ifdef ASSERT -void SubTasksDone::all_tasks_claimed_impl(uint skipped[], size_t skipped_size) { - if (Atomic::cmpxchg(&_verification_done, false, true)) { - // another thread has done the verification - return; - } - // all non-skipped tasks are claimed - for (uint i = 0; i < _n_tasks; ++i) { - if (!_tasks[i]) { - auto is_skipped = false; - for (size_t j = 0; j < skipped_size; ++j) { - if (i == skipped[j]) { - is_skipped = true; - break; - } - } - assert(is_skipped, "%d not claimed.", i); - } - } - // all skipped tasks are *not* claimed - for (size_t i = 0; i < skipped_size; ++i) { - auto task_index = skipped[i]; - assert(task_index < _n_tasks, "Array in range."); - assert(!_tasks[task_index], "%d is both claimed and skipped.", task_index); - } -} -#endif - -bool SubTasksDone::try_claim_task(uint t) { - assert(t < _n_tasks, "bad task id."); - return !_tasks[t] && !Atomic::cmpxchg(&_tasks[t], false, true); -} - -SubTasksDone::~SubTasksDone() { - assert(_verification_done, "all_tasks_claimed must have been called."); - FREE_C_HEAP_ARRAY(bool, _tasks); -} - -// *** SequentialSubTasksDone - -bool SequentialSubTasksDone::try_claim_task(uint& t) { - t = _num_claimed; - if (t < _num_tasks) { - t = Atomic::add(&_num_claimed, 1u) - 1; - } - return t < _num_tasks; -} diff --git a/src/hotspot/share/gc/shared/workgroup.hpp b/src/hotspot/share/gc/shared/workgroup.hpp deleted file mode 100644 index d6446bb1dd3..00000000000 --- a/src/hotspot/share/gc/shared/workgroup.hpp +++ /dev/null @@ -1,328 +0,0 @@ -/* - * Copyright (c) 2002, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef SHARE_GC_SHARED_WORKGROUP_HPP -#define SHARE_GC_SHARED_WORKGROUP_HPP - -#include "memory/allocation.hpp" -#include "metaprogramming/enableIf.hpp" -#include "metaprogramming/logical.hpp" -#include "runtime/globals.hpp" -#include "runtime/nonJavaThread.hpp" -#include "runtime/thread.hpp" -#include "gc/shared/gcId.hpp" -#include "logging/log.hpp" -#include "utilities/debug.hpp" -#include "utilities/globalDefinitions.hpp" - -// Task class hierarchy: -// AbstractGangTask -// -// Gang/Group class hierarchy: -// WorkGang -// -// Worker class hierarchy: -// GangWorker (subclass of WorkerThread) - -// Forward declarations of classes defined here - -class GangWorker; -class Semaphore; -class ThreadClosure; -class GangTaskDispatcher; - -// An abstract task to be worked on by a gang. -// You subclass this to supply your own work() method -class AbstractGangTask : public CHeapObj { - const char* _name; - const uint _gc_id; - - public: - explicit AbstractGangTask(const char* name) : - _name(name), - _gc_id(GCId::current_or_undefined()) - {} - - // The abstract work method. - // The argument tells you which member of the gang you are. - virtual void work(uint worker_id) = 0; - - // Debugging accessor for the name. - const char* name() const { return _name; } - const uint gc_id() const { return _gc_id; } -}; - -struct WorkData { - AbstractGangTask* _task; - uint _worker_id; - WorkData(AbstractGangTask* task, uint worker_id) : _task(task), _worker_id(worker_id) {} -}; - -// The work gang is the collection of workers to execute tasks. -// The number of workers run for a task is "_active_workers" -// while "_total_workers" is the number of available workers. -class WorkGang : public CHeapObj { - // The array of worker threads for this gang. - GangWorker** _workers; - // The count of the number of workers in the gang. - uint _total_workers; - // The currently active workers in this gang. - uint _active_workers; - // The count of created workers in the gang. - uint _created_workers; - // Printing support. - const char* _name; - - // To get access to the GangTaskDispatcher instance. - friend class GangWorker; - GangTaskDispatcher* const _dispatcher; - - GangTaskDispatcher* dispatcher() const { return _dispatcher; } - - void set_thread(uint worker_id, GangWorker* worker) { - _workers[worker_id] = worker; - } - - // Add GC workers when _created_workers < _active_workers; otherwise, no-op. - // If there's no memory/thread allocation failure, _created_worker is - // adjusted to match _active_workers (_created_worker == _active_workers). - void add_workers(bool initializing); - - GangWorker* allocate_worker(uint which); - - public: - WorkGang(const char* name, uint workers); - - ~WorkGang(); - - // Initialize workers in the gang. Return true if initialization succeeded. - void initialize_workers(); - - uint total_workers() const { return _total_workers; } - - uint created_workers() const { - return _created_workers; - } - - uint active_workers() const { - assert(_active_workers != 0, "zero active workers"); - assert(_active_workers <= _total_workers, - "_active_workers: %u > _total_workers: %u", _active_workers, _total_workers); - return _active_workers; - } - - uint update_active_workers(uint v) { - assert(v <= _total_workers, - "Trying to set more workers active than there are"); - assert(v != 0, "Trying to set active workers to 0"); - _active_workers = v; - add_workers(false /* initializing */); - log_trace(gc, task)("%s: using %d out of %d workers", name(), _active_workers, _total_workers); - return _active_workers; - } - - // Return the Ith worker. - GangWorker* worker(uint i) const; - - // Base name (without worker id #) of threads. - const char* group_name() { return name(); } - - void threads_do(ThreadClosure* tc) const; - - // Create a GC worker and install it into the work gang. - virtual GangWorker* install_worker(uint which); - - // Debugging. - const char* name() const { return _name; } - - // Run a task using the current active number of workers, returns when the task is done. - void run_task(AbstractGangTask* task); - - // Run a task with the given number of workers, returns - // when the task is done. The number of workers must be at most the number of - // active workers. Additional workers may be created if an insufficient - // number currently exists. - void run_task(AbstractGangTask* task, uint num_workers); -}; - -// Temporarily try to set the number of active workers. -// It's not guaranteed that it succeeds, and users need to -// query the number of active workers. -class WithUpdatedActiveWorkers : public StackObj { -private: - WorkGang* const _gang; - const uint _old_active_workers; - -public: - WithUpdatedActiveWorkers(WorkGang* gang, uint requested_num_workers) : - _gang(gang), - _old_active_workers(gang->active_workers()) { - uint capped_num_workers = MIN2(requested_num_workers, gang->total_workers()); - gang->update_active_workers(capped_num_workers); - } - - ~WithUpdatedActiveWorkers() { - _gang->update_active_workers(_old_active_workers); - } -}; - -// Several instances of this class run in parallel as workers for a gang. -class GangWorker: public WorkerThread { -private: - WorkGang* _gang; - - void initialize(); - void loop(); - - WorkGang* gang() const { return _gang; } - - WorkData wait_for_task(); - void run_task(WorkData work); - void signal_task_done(); - -protected: - // The only real method: run a task for the gang. - void run() override; - -public: - GangWorker(WorkGang* gang, uint id); - - // Printing - const char* type_name() const override { return "GCTaskThread"; } -}; - -// A class that acts as a synchronisation barrier. Workers enter -// the barrier and must wait until all other workers have entered -// before any of them may leave. - -class WorkGangBarrierSync : public StackObj { -protected: - Monitor _monitor; - uint _n_workers; - uint _n_completed; - bool _should_reset; - bool _aborted; - - Monitor* monitor() { return &_monitor; } - uint n_workers() { return _n_workers; } - uint n_completed() { return _n_completed; } - bool should_reset() { return _should_reset; } - bool aborted() { return _aborted; } - - void zero_completed() { _n_completed = 0; } - void inc_completed() { _n_completed++; } - void set_aborted() { _aborted = true; } - void set_should_reset(bool v) { _should_reset = v; } - -public: - WorkGangBarrierSync(); - - // Set the number of workers that will use the barrier. - // Must be called before any of the workers start running. - void set_n_workers(uint n_workers); - - // Enter the barrier. A worker that enters the barrier will - // not be allowed to leave until all other threads have - // also entered the barrier or the barrier is aborted. - // Returns false if the barrier was aborted. - bool enter(); - - // Aborts the barrier and wakes up any threads waiting for - // the barrier to complete. The barrier will remain in the - // aborted state until the next call to set_n_workers(). - void abort(); -}; - -// A class to manage claiming of subtasks within a group of tasks. The -// subtasks will be identified by integer indices, usually elements of an -// enumeration type. - -class SubTasksDone: public CHeapObj { - volatile bool* _tasks; - uint _n_tasks; - - // make sure verification logic is run exactly once to avoid duplicate assertion failures - DEBUG_ONLY(volatile bool _verification_done = false;) - void all_tasks_claimed_impl(uint skipped[], size_t skipped_size) NOT_DEBUG_RETURN; - - NONCOPYABLE(SubTasksDone); - -public: - // Initializes "this" to a state in which there are "n" tasks to be - // processed, none of the which are originally claimed. - SubTasksDone(uint n); - - // Attempt to claim the task "t", returning true if successful, - // false if it has already been claimed. The task "t" is required - // to be within the range of "this". - bool try_claim_task(uint t); - - // The calling thread asserts that it has attempted to claim all the tasks - // that it will try to claim. Tasks that are meant to be skipped must be - // explicitly passed as extra arguments. Every thread in the parallel task - // must execute this. - template...>::value)> - void all_tasks_claimed(T0 first_skipped, Ts... more_skipped) { - static_assert(std::is_convertible::value, "not convertible"); - uint skipped[] = { static_cast(first_skipped), static_cast(more_skipped)... }; - all_tasks_claimed_impl(skipped, ARRAY_SIZE(skipped)); - } - // if there are no skipped tasks. - void all_tasks_claimed() { - all_tasks_claimed_impl(nullptr, 0); - } - - // Destructor. - ~SubTasksDone(); -}; - -// As above, but for sequential tasks, i.e. instead of claiming -// sub-tasks from a set (possibly an enumeration), claim sub-tasks -// in sequential order. This is ideal for claiming dynamically -// partitioned tasks (like striding in the parallel remembered -// set scanning). - -class SequentialSubTasksDone : public CHeapObj { - - uint _num_tasks; // Total number of tasks available. - volatile uint _num_claimed; // Number of tasks claimed. - - NONCOPYABLE(SequentialSubTasksDone); - -public: - SequentialSubTasksDone(uint num_tasks) : _num_tasks(num_tasks), _num_claimed(0) { } - ~SequentialSubTasksDone() { - // Claiming may try to claim more tasks than there are. - assert(_num_claimed >= _num_tasks, "Claimed %u tasks of %u", _num_claimed, _num_tasks); - } - - // Attempt to claim the next unclaimed task in the sequence, - // returning true if successful, with t set to the index of the - // claimed task. Returns false if there are no more unclaimed tasks - // in the sequence. In this case t is undefined. - bool try_claim_task(uint& t); -}; - -#endif // SHARE_GC_SHARED_WORKGROUP_HPP diff --git a/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.cpp b/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.cpp index b29633d7ff4..e5282dc9c53 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.cpp @@ -153,14 +153,14 @@ public: } }; -class ShenandoahDisarmNMethodsTask : public AbstractGangTask { +class ShenandoahDisarmNMethodsTask : public WorkerTask { private: ShenandoahDisarmNMethodClosure _cl; ShenandoahConcurrentNMethodIterator _iterator; public: ShenandoahDisarmNMethodsTask() : - AbstractGangTask("Shenandoah Disarm NMethods"), + WorkerTask("Shenandoah Disarm NMethods"), _iterator(ShenandoahCodeRoots::table()) { assert(SafepointSynchronize::is_at_safepoint(), "Only at a safepoint"); MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); @@ -258,7 +258,7 @@ public: } }; -class ShenandoahUnlinkTask : public AbstractGangTask { +class ShenandoahUnlinkTask : public WorkerTask { private: ShenandoahNMethodUnlinkClosure _cl; ICRefillVerifier* _verifier; @@ -266,7 +266,7 @@ private: public: ShenandoahUnlinkTask(bool unloading_occurred, ICRefillVerifier* verifier) : - AbstractGangTask("Shenandoah Unlink NMethods"), + WorkerTask("Shenandoah Unlink NMethods"), _cl(unloading_occurred), _verifier(verifier), _iterator(ShenandoahCodeRoots::table()) { @@ -289,7 +289,7 @@ public: } }; -void ShenandoahCodeRoots::unlink(WorkGang* workers, bool unloading_occurred) { +void ShenandoahCodeRoots::unlink(WorkerThreads* workers, bool unloading_occurred) { assert(ShenandoahHeap::heap()->unload_classes(), "Only when running concurrent class unloading"); for (;;) { @@ -320,14 +320,14 @@ public: } }; -class ShenandoahNMethodPurgeTask : public AbstractGangTask { +class ShenandoahNMethodPurgeTask : public WorkerTask { private: ShenandoahNMethodPurgeClosure _cl; ShenandoahConcurrentNMethodIterator _iterator; public: ShenandoahNMethodPurgeTask() : - AbstractGangTask("Shenandoah Purge NMethods"), + WorkerTask("Shenandoah Purge NMethods"), _cl(), _iterator(ShenandoahCodeRoots::table()) { MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); @@ -344,7 +344,7 @@ public: } }; -void ShenandoahCodeRoots::purge(WorkGang* workers) { +void ShenandoahCodeRoots::purge(WorkerThreads* workers) { assert(ShenandoahHeap::heap()->unload_classes(), "Only when running concurrent class unloading"); ShenandoahNMethodPurgeTask task; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.hpp b/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.hpp index 16c0485bf48..17bc5b78934 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.hpp @@ -37,7 +37,7 @@ class ShenandoahHeap; class ShenandoahHeapRegion; class ShenandoahNMethodTable; class ShenandoahNMethodTableSnapshot; -class WorkGang; +class WorkerThreads; class ShenandoahParallelCodeHeapIterator { friend class CodeCache; @@ -95,8 +95,8 @@ public: } // Concurrent nmethod unloading support - static void unlink(WorkGang* workers, bool unloading_occurred); - static void purge(WorkGang* workers); + static void unlink(WorkerThreads* workers, bool unloading_occurred); + static void purge(WorkerThreads* workers); static void arm_nmethods(); static void disarm_nmethods(); static int disarmed_value() { return _disarmed_value; } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp index d29cc683331..fed6b3f0a7f 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp @@ -635,13 +635,13 @@ void ShenandoahConcurrentEvacThreadClosure::do_thread(Thread* thread) { StackWatermarkSet::finish_processing(jt, _oops, StackWatermarkKind::gc); } -class ShenandoahConcurrentEvacUpdateThreadTask : public AbstractGangTask { +class ShenandoahConcurrentEvacUpdateThreadTask : public WorkerTask { private: ShenandoahJavaThreadsIterator _java_threads; public: ShenandoahConcurrentEvacUpdateThreadTask(uint n_workers) : - AbstractGangTask("Shenandoah Evacuate/Update Concurrent Thread Roots"), + WorkerTask("Shenandoah Evacuate/Update Concurrent Thread Roots"), _java_threads(ShenandoahPhaseTimings::conc_thread_roots, n_workers) { } @@ -732,7 +732,7 @@ public: // This task not only evacuates/updates marked weak roots, but also "NULL" // dead weak roots. -class ShenandoahConcurrentWeakRootsEvacUpdateTask : public AbstractGangTask { +class ShenandoahConcurrentWeakRootsEvacUpdateTask : public WorkerTask { private: ShenandoahVMWeakRoots _vm_roots; @@ -744,7 +744,7 @@ private: public: ShenandoahConcurrentWeakRootsEvacUpdateTask(ShenandoahPhaseTimings::Phase phase) : - AbstractGangTask("Shenandoah Evacuate/Update Concurrent Weak Roots"), + WorkerTask("Shenandoah Evacuate/Update Concurrent Weak Roots"), _vm_roots(phase), _cld_roots(phase, ShenandoahHeap::heap()->workers()->active_workers(), false /*heap iteration*/), _nmethod_itr(ShenandoahCodeRoots::table()), @@ -846,7 +846,7 @@ public: } }; -class ShenandoahConcurrentRootsEvacUpdateTask : public AbstractGangTask { +class ShenandoahConcurrentRootsEvacUpdateTask : public WorkerTask { private: ShenandoahPhaseTimings::Phase _phase; ShenandoahVMRoots _vm_roots; @@ -856,7 +856,7 @@ private: public: ShenandoahConcurrentRootsEvacUpdateTask(ShenandoahPhaseTimings::Phase phase) : - AbstractGangTask("Shenandoah Evacuate/Update Concurrent Strong Roots"), + WorkerTask("Shenandoah Evacuate/Update Concurrent Strong Roots"), _phase(phase), _vm_roots(phase), _cld_roots(phase, ShenandoahHeap::heap()->workers()->active_workers(), false /*heap iteration*/), diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp index ed1ff8c26c7..310c46f44f4 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp @@ -42,14 +42,14 @@ #include "memory/iterator.inline.hpp" #include "memory/resourceArea.hpp" -class ShenandoahConcurrentMarkingTask : public AbstractGangTask { +class ShenandoahConcurrentMarkingTask : public WorkerTask { private: ShenandoahConcurrentMark* const _cm; TaskTerminator* const _terminator; public: ShenandoahConcurrentMarkingTask(ShenandoahConcurrentMark* cm, TaskTerminator* terminator) : - AbstractGangTask("Shenandoah Concurrent Mark"), _cm(cm), _terminator(terminator) { + WorkerTask("Shenandoah Concurrent Mark"), _cm(cm), _terminator(terminator) { } void work(uint worker_id) { @@ -93,7 +93,7 @@ public: } }; -class ShenandoahFinalMarkingTask : public AbstractGangTask { +class ShenandoahFinalMarkingTask : public WorkerTask { private: ShenandoahConcurrentMark* _cm; TaskTerminator* _terminator; @@ -101,7 +101,7 @@ private: public: ShenandoahFinalMarkingTask(ShenandoahConcurrentMark* cm, TaskTerminator* terminator, bool dedup_string) : - AbstractGangTask("Shenandoah Final Mark"), _cm(cm), _terminator(terminator), _dedup_string(dedup_string) { + WorkerTask("Shenandoah Final Mark"), _cm(cm), _terminator(terminator), _dedup_string(dedup_string) { } void work(uint worker_id) { @@ -137,7 +137,7 @@ ShenandoahConcurrentMark::ShenandoahConcurrentMark() : ShenandoahMark() {} // Mark concurrent roots during concurrent phases -class ShenandoahMarkConcurrentRootsTask : public AbstractGangTask { +class ShenandoahMarkConcurrentRootsTask : public WorkerTask { private: SuspendibleThreadSetJoiner _sts_joiner; ShenandoahConcurrentRootScanner _root_scanner; @@ -156,7 +156,7 @@ ShenandoahMarkConcurrentRootsTask::ShenandoahMarkConcurrentRootsTask(ShenandoahO ShenandoahReferenceProcessor* rp, ShenandoahPhaseTimings::Phase phase, uint nworkers) : - AbstractGangTask("Shenandoah Concurrent Mark Roots"), + WorkerTask("Shenandoah Concurrent Mark Roots"), _root_scanner(nworkers, phase), _queue_set(qs), _rp(rp) { @@ -176,7 +176,7 @@ void ShenandoahConcurrentMark::mark_concurrent_roots() { TASKQUEUE_STATS_ONLY(task_queues()->reset_taskqueue_stats()); - WorkGang* workers = heap->workers(); + WorkerThreads* workers = heap->workers(); ShenandoahReferenceProcessor* rp = heap->ref_processor(); task_queues()->reserve(workers->active_workers()); ShenandoahMarkConcurrentRootsTask task(task_queues(), rp, ShenandoahPhaseTimings::conc_mark_roots, workers->active_workers()); @@ -199,7 +199,7 @@ public: void ShenandoahConcurrentMark::concurrent_mark() { ShenandoahHeap* const heap = ShenandoahHeap::heap(); - WorkGang* workers = heap->workers(); + WorkerThreads* workers = heap->workers(); uint nworkers = workers->active_workers(); task_queues()->reserve(nworkers); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp index b37b488cc18..dfa696e6a5b 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp @@ -28,6 +28,7 @@ #include "gc/shared/gcTraceTime.inline.hpp" #include "gc/shared/preservedMarks.inline.hpp" #include "gc/shared/tlab_globals.hpp" +#include "gc/shared/workerThread.hpp" #include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp" #include "gc/shenandoah/shenandoahConcurrentGC.hpp" #include "gc/shenandoah/shenandoahCollectionSet.hpp" @@ -59,7 +60,6 @@ #include "utilities/copy.hpp" #include "utilities/events.hpp" #include "utilities/growableArray.hpp" -#include "gc/shared/workgroup.hpp" ShenandoahFullGC::ShenandoahFullGC() : _gc_timer(ShenandoahHeap::heap()->gc_timer()), @@ -363,7 +363,7 @@ public: } }; -class ShenandoahPrepareForCompactionTask : public AbstractGangTask { +class ShenandoahPrepareForCompactionTask : public WorkerTask { private: PreservedMarksSet* const _preserved_marks; ShenandoahHeap* const _heap; @@ -371,7 +371,7 @@ private: public: ShenandoahPrepareForCompactionTask(PreservedMarksSet *preserved_marks, ShenandoahHeapRegionSet **worker_slices) : - AbstractGangTask("Shenandoah Prepare For Compaction"), + WorkerTask("Shenandoah Prepare For Compaction"), _preserved_marks(preserved_marks), _heap(ShenandoahHeap::heap()), _worker_slices(worker_slices) { } @@ -757,14 +757,14 @@ public: } }; -class ShenandoahAdjustPointersTask : public AbstractGangTask { +class ShenandoahAdjustPointersTask : public WorkerTask { private: ShenandoahHeap* const _heap; ShenandoahRegionIterator _regions; public: ShenandoahAdjustPointersTask() : - AbstractGangTask("Shenandoah Adjust Pointers"), + WorkerTask("Shenandoah Adjust Pointers"), _heap(ShenandoahHeap::heap()) { } @@ -781,13 +781,13 @@ public: } }; -class ShenandoahAdjustRootPointersTask : public AbstractGangTask { +class ShenandoahAdjustRootPointersTask : public WorkerTask { private: ShenandoahRootAdjuster* _rp; PreservedMarksSet* _preserved_marks; public: ShenandoahAdjustRootPointersTask(ShenandoahRootAdjuster* rp, PreservedMarksSet* preserved_marks) : - AbstractGangTask("Shenandoah Adjust Root Pointers"), + WorkerTask("Shenandoah Adjust Root Pointers"), _rp(rp), _preserved_marks(preserved_marks) {} @@ -805,7 +805,7 @@ void ShenandoahFullGC::phase3_update_references() { ShenandoahHeap* heap = ShenandoahHeap::heap(); - WorkGang* workers = heap->workers(); + WorkerThreads* workers = heap->workers(); uint nworkers = workers->active_workers(); { #if COMPILER2_OR_JVMCI @@ -845,14 +845,14 @@ public: } }; -class ShenandoahCompactObjectsTask : public AbstractGangTask { +class ShenandoahCompactObjectsTask : public WorkerTask { private: ShenandoahHeap* const _heap; ShenandoahHeapRegionSet** const _worker_slices; public: ShenandoahCompactObjectsTask(ShenandoahHeapRegionSet** worker_slices) : - AbstractGangTask("Shenandoah Compact Objects"), + WorkerTask("Shenandoah Compact Objects"), _heap(ShenandoahHeap::heap()), _worker_slices(worker_slices) { } @@ -995,13 +995,13 @@ void ShenandoahFullGC::compact_humongous_objects() { // cannot be iterated over using oop->size(). The only way to safely iterate over those is using // a valid marking bitmap and valid TAMS pointer. This class only resets marking // bitmaps for un-pinned regions, and later we only reset TAMS for unpinned regions. -class ShenandoahMCResetCompleteBitmapTask : public AbstractGangTask { +class ShenandoahMCResetCompleteBitmapTask : public WorkerTask { private: ShenandoahRegionIterator _regions; public: ShenandoahMCResetCompleteBitmapTask() : - AbstractGangTask("Shenandoah Reset Bitmap") { + WorkerTask("Shenandoah Reset Bitmap") { } void work(uint worker_id) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGC.cpp index c0ab9a61f81..fa193880293 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGC.cpp @@ -25,7 +25,7 @@ #include "precompiled.hpp" #include "compiler/oopMap.hpp" -#include "gc/shared/workgroup.hpp" +#include "gc/shared/workerThread.hpp" #include "gc/shenandoah/shenandoahClosures.inline.hpp" #include "gc/shenandoah/shenandoahGC.hpp" #include "gc/shenandoah/shenandoahHeap.hpp" @@ -51,13 +51,13 @@ const char* ShenandoahGC::degen_point_to_string(ShenandoahDegenPoint point) { } } -class ShenandoahUpdateRootsTask : public AbstractGangTask { +class ShenandoahUpdateRootsTask : public WorkerTask { private: ShenandoahRootUpdater* _root_updater; bool _check_alive; public: ShenandoahUpdateRootsTask(ShenandoahRootUpdater* root_updater, bool check_alive) : - AbstractGangTask("Shenandoah Update Roots"), + WorkerTask("Shenandoah Update Roots"), _root_updater(root_updater), _check_alive(check_alive){ } @@ -95,7 +95,7 @@ void ShenandoahGC::update_roots(bool full_gc) { #endif ShenandoahHeap* const heap = ShenandoahHeap::heap(); - WorkGang* workers = heap->workers(); + WorkerThreads* workers = heap->workers(); uint nworkers = workers->active_workers(); ShenandoahRootUpdater root_updater(nworkers, p); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index 34b87173290..7cd9a61b29f 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -88,13 +88,13 @@ #include "utilities/events.hpp" #include "utilities/powerOfTwo.hpp" -class ShenandoahPretouchHeapTask : public AbstractGangTask { +class ShenandoahPretouchHeapTask : public WorkerTask { private: ShenandoahRegionIterator _regions; const size_t _page_size; public: ShenandoahPretouchHeapTask(size_t page_size) : - AbstractGangTask("Shenandoah Pretouch Heap"), + WorkerTask("Shenandoah Pretouch Heap"), _page_size(page_size) {} virtual void work(uint worker_id) { @@ -108,7 +108,7 @@ public: } }; -class ShenandoahPretouchBitmapTask : public AbstractGangTask { +class ShenandoahPretouchBitmapTask : public WorkerTask { private: ShenandoahRegionIterator _regions; char* _bitmap_base; @@ -116,7 +116,7 @@ private: const size_t _page_size; public: ShenandoahPretouchBitmapTask(char* bitmap_base, size_t bitmap_size, size_t page_size) : - AbstractGangTask("Shenandoah Pretouch Bitmap"), + WorkerTask("Shenandoah Pretouch Bitmap"), _bitmap_base(bitmap_base), _bitmap_size(bitmap_size), _page_size(page_size) {} @@ -495,7 +495,7 @@ ShenandoahHeap::ShenandoahHeap(ShenandoahCollectorPolicy* policy) : BarrierSet::set_barrier_set(new ShenandoahBarrierSet(this)); _max_workers = MAX2(_max_workers, 1U); - _workers = new ShenandoahWorkGang("Shenandoah GC Threads", _max_workers); + _workers = new ShenandoahWorkerThreads("Shenandoah GC Threads", _max_workers); if (_workers == NULL) { vm_exit_during_initialization("Failed necessary allocation."); } else { @@ -503,7 +503,7 @@ ShenandoahHeap::ShenandoahHeap(ShenandoahCollectorPolicy* policy) : } if (ParallelGCThreads > 1) { - _safepoint_workers = new ShenandoahWorkGang("Safepoint Cleanup Thread", + _safepoint_workers = new ShenandoahWorkerThreads("Safepoint Cleanup Thread", ParallelGCThreads); _safepoint_workers->initialize_workers(); } @@ -513,13 +513,13 @@ ShenandoahHeap::ShenandoahHeap(ShenandoahCollectorPolicy* policy) : #pragma warning( pop ) #endif -class ShenandoahResetBitmapTask : public AbstractGangTask { +class ShenandoahResetBitmapTask : public WorkerTask { private: ShenandoahRegionIterator _regions; public: ShenandoahResetBitmapTask() : - AbstractGangTask("Shenandoah Reset Bitmap") {} + WorkerTask("Shenandoah Reset Bitmap") {} void work(uint worker_id) { ShenandoahHeapRegion* region = _regions.next(); @@ -612,7 +612,7 @@ void ShenandoahHeap::post_initialize() { _workers->threads_do(&init_gclabs); // gclab can not be initialized early during VM startup, as it can not determinate its max_size. - // Now, we will let WorkGang to initialize gclab when new worker is created. + // Now, we will let WorkerThreads to initialize gclab when new worker is created. _workers->set_initialize_gclab(); if (_safepoint_workers != NULL) { _safepoint_workers->threads_do(&init_gclabs); @@ -953,7 +953,7 @@ public: } }; -class ShenandoahEvacuationTask : public AbstractGangTask { +class ShenandoahEvacuationTask : public WorkerTask { private: ShenandoahHeap* const _sh; ShenandoahCollectionSet* const _cs; @@ -962,7 +962,7 @@ public: ShenandoahEvacuationTask(ShenandoahHeap* sh, ShenandoahCollectionSet* cs, bool concurrent) : - AbstractGangTask("Shenandoah Evacuation"), + WorkerTask("Shenandoah Evacuation"), _sh(sh), _cs(cs), _concurrent(concurrent) @@ -1483,7 +1483,7 @@ void ShenandoahHeap::heap_region_iterate(ShenandoahHeapRegionClosure* blk) const } } -class ShenandoahParallelHeapRegionTask : public AbstractGangTask { +class ShenandoahParallelHeapRegionTask : public WorkerTask { private: ShenandoahHeap* const _heap; ShenandoahHeapRegionClosure* const _blk; @@ -1494,7 +1494,7 @@ private: public: ShenandoahParallelHeapRegionTask(ShenandoahHeapRegionClosure* blk) : - AbstractGangTask("Shenandoah Parallel Region Operation"), + WorkerTask("Shenandoah Parallel Region Operation"), _heap(ShenandoahHeap::heap()), _blk(blk), _index(0) {} void work(uint worker_id) { @@ -2010,13 +2010,13 @@ ShenandoahVerifier* ShenandoahHeap::verifier() { } template -class ShenandoahUpdateHeapRefsTask : public AbstractGangTask { +class ShenandoahUpdateHeapRefsTask : public WorkerTask { private: ShenandoahHeap* _heap; ShenandoahRegionIterator* _regions; public: ShenandoahUpdateHeapRefsTask(ShenandoahRegionIterator* regions) : - AbstractGangTask("Shenandoah Update References"), + WorkerTask("Shenandoah Update References"), _heap(ShenandoahHeap::heap()), _regions(regions) { } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp index 3eea61e1691..79afeb37ab5 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp @@ -61,7 +61,7 @@ class ShenandoahMonitoringSupport; class ShenandoahPacer; class ShenandoahReferenceProcessor; class ShenandoahVerifier; -class ShenandoahWorkGang; +class ShenandoahWorkerThreads; class VMStructs; // Used for buffering per-region liveness data. @@ -207,15 +207,15 @@ public: // private: uint _max_workers; - ShenandoahWorkGang* _workers; - ShenandoahWorkGang* _safepoint_workers; + ShenandoahWorkerThreads* _workers; + ShenandoahWorkerThreads* _safepoint_workers; public: uint max_workers(); void assert_gc_workers(uint nworker) NOT_DEBUG_RETURN; - WorkGang* workers() const; - WorkGang* safepoint_workers(); + WorkerThreads* workers() const; + WorkerThreads* safepoint_workers(); void gc_threads_do(ThreadClosure* tcl) const; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp index be00a011185..59f5af45b93 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp @@ -64,11 +64,11 @@ inline bool ShenandoahHeap::has_forwarded_objects() const { return _gc_state.is_set(HAS_FORWARDED); } -inline WorkGang* ShenandoahHeap::workers() const { +inline WorkerThreads* ShenandoahHeap::workers() const { return _workers; } -inline WorkGang* ShenandoahHeap::safepoint_workers() { +inline WorkerThreads* ShenandoahHeap::safepoint_workers() { return _safepoint_workers; } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahParallelCleaning.cpp b/src/hotspot/share/gc/shenandoah/shenandoahParallelCleaning.cpp index 8f4659c3eb2..2390c4470f4 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahParallelCleaning.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahParallelCleaning.cpp @@ -35,7 +35,7 @@ ShenandoahClassUnloadingTask::ShenandoahClassUnloadingTask(ShenandoahPhaseTiming BoolObjectClosure* is_alive, uint num_workers, bool unloading_occurred) : - AbstractGangTask("Shenandoah Class Unloading"), + WorkerTask("Shenandoah Class Unloading"), _phase(phase), _unloading_occurred(unloading_occurred), _code_cache_task(num_workers, is_alive, unloading_occurred), diff --git a/src/hotspot/share/gc/shenandoah/shenandoahParallelCleaning.hpp b/src/hotspot/share/gc/shenandoah/shenandoahParallelCleaning.hpp index c4ca0afb9bb..9e0ebe548b9 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahParallelCleaning.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahParallelCleaning.hpp @@ -27,13 +27,13 @@ #include "gc/shared/parallelCleaning.hpp" #include "gc/shared/weakProcessor.hpp" -#include "gc/shared/workgroup.hpp" +#include "gc/shared/workerThread.hpp" #include "gc/shenandoah/shenandoahPhaseTimings.hpp" #include "memory/iterator.hpp" // Perform weak root cleaning at a pause template -class ShenandoahParallelWeakRootsCleaningTask : public AbstractGangTask { +class ShenandoahParallelWeakRootsCleaningTask : public WorkerTask { protected: ShenandoahPhaseTimings::Phase const _phase; WeakProcessor::Task _weak_processing_task; @@ -51,7 +51,7 @@ public: }; // Perform class unloading at a pause -class ShenandoahClassUnloadingTask : public AbstractGangTask { +class ShenandoahClassUnloadingTask : public WorkerTask { private: ShenandoahPhaseTimings::Phase const _phase; bool _unloading_occurred; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahParallelCleaning.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahParallelCleaning.inline.hpp index f88e9bb394c..f764c7f9763 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahParallelCleaning.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahParallelCleaning.inline.hpp @@ -38,7 +38,7 @@ ShenandoahParallelWeakRootsCleaningTask::ShenandoahParallelW IsAlive* is_alive, KeepAlive* keep_alive, uint num_workers) : - AbstractGangTask("Shenandoah Weak Root Cleaning"), + WorkerTask("Shenandoah Weak Root Cleaning"), _phase(phase), _weak_processing_task(num_workers), _is_alive(is_alive), diff --git a/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.cpp b/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.cpp index e843f3b250b..72a87a9d3de 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.cpp @@ -464,7 +464,7 @@ void ShenandoahReferenceProcessor::work() { } } -class ShenandoahReferenceProcessorTask : public AbstractGangTask { +class ShenandoahReferenceProcessorTask : public WorkerTask { private: bool const _concurrent; ShenandoahPhaseTimings::Phase const _phase; @@ -472,7 +472,7 @@ private: public: ShenandoahReferenceProcessorTask(ShenandoahPhaseTimings::Phase phase, bool concurrent, ShenandoahReferenceProcessor* reference_processor) : - AbstractGangTask("ShenandoahReferenceProcessorTask"), + WorkerTask("ShenandoahReferenceProcessorTask"), _concurrent(concurrent), _phase(phase), _reference_processor(reference_processor) { @@ -491,7 +491,7 @@ public: } }; -void ShenandoahReferenceProcessor::process_references(ShenandoahPhaseTimings::Phase phase, WorkGang* workers, bool concurrent) { +void ShenandoahReferenceProcessor::process_references(ShenandoahPhaseTimings::Phase phase, WorkerThreads* workers, bool concurrent) { Atomic::release_store_fence(&_iterate_discovered_list_id, 0U); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.hpp b/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.hpp index b1c26972c21..597b0a8ba5b 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.hpp @@ -33,7 +33,7 @@ #include "memory/allocation.hpp" class ShenandoahMarkRefsSuperClosure; -class WorkGang; +class WorkerThreads; static const size_t reference_type_count = REF_PHANTOM + 1; typedef size_t Counters[reference_type_count]; @@ -179,7 +179,7 @@ public: bool discover_reference(oop obj, ReferenceType type) override; - void process_references(ShenandoahPhaseTimings::Phase phase, WorkGang* workers, bool concurrent); + void process_references(ShenandoahPhaseTimings::Phase phase, WorkerThreads* workers, bool concurrent); const ReferenceProcessorStats& reference_process_stats() { return _stats; } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp index 09fea5b8487..7e64c556476 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp @@ -27,7 +27,7 @@ #include "gc/shared/strongRootsScope.hpp" #include "gc/shared/taskTerminator.hpp" -#include "gc/shared/workgroup.hpp" +#include "gc/shared/workerThread.hpp" #include "gc/shenandoah/shenandoahClosures.inline.hpp" #include "gc/shenandoah/shenandoahMark.inline.hpp" #include "gc/shenandoah/shenandoahOopClosures.inline.hpp" @@ -60,7 +60,7 @@ void ShenandoahInitMarkRootsClosure::do_oop_work(T* p) { ShenandoahMark::mark_through_ref(p, _queue, _mark_context, false); } -class ShenandoahSTWMarkTask : public AbstractGangTask { +class ShenandoahSTWMarkTask : public WorkerTask { private: ShenandoahSTWMark* const _mark; @@ -70,7 +70,7 @@ public: }; ShenandoahSTWMarkTask::ShenandoahSTWMarkTask(ShenandoahSTWMark* mark) : - AbstractGangTask("Shenandoah STW mark"), + WorkerTask("Shenandoah STW mark"), _mark(mark) { } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp index 4748688b2da..07f1dec2b17 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp @@ -421,7 +421,7 @@ public: } }; -class ShenandoahVerifierReachableTask : public AbstractGangTask { +class ShenandoahVerifierReachableTask : public WorkerTask { private: const char* _label; ShenandoahVerifier::VerifyOptions _options; @@ -435,7 +435,7 @@ public: ShenandoahLivenessData* ld, const char* label, ShenandoahVerifier::VerifyOptions options) : - AbstractGangTask("Shenandoah Verifier Reachable Objects"), + WorkerTask("Shenandoah Verifier Reachable Objects"), _label(label), _options(options), _heap(ShenandoahHeap::heap()), @@ -484,7 +484,7 @@ public: } }; -class ShenandoahVerifierMarkedRegionTask : public AbstractGangTask { +class ShenandoahVerifierMarkedRegionTask : public WorkerTask { private: const char* _label; ShenandoahVerifier::VerifyOptions _options; @@ -499,7 +499,7 @@ public: ShenandoahLivenessData* ld, const char* label, ShenandoahVerifier::VerifyOptions options) : - AbstractGangTask("Shenandoah Verifier Marked Objects"), + WorkerTask("Shenandoah Verifier Marked Objects"), _label(label), _options(options), _heap(ShenandoahHeap::heap()), diff --git a/src/hotspot/share/gc/shenandoah/shenandoahWorkGroup.cpp b/src/hotspot/share/gc/shenandoah/shenandoahWorkGroup.cpp index f41331d1d82..34202dac657 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahWorkGroup.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahWorkGroup.cpp @@ -31,11 +31,11 @@ #include "logging/log.hpp" -ShenandoahWorkerScope::ShenandoahWorkerScope(WorkGang* workers, uint nworkers, const char* msg, bool check) : +ShenandoahWorkerScope::ShenandoahWorkerScope(WorkerThreads* workers, uint nworkers, const char* msg, bool check) : _workers(workers) { assert(msg != NULL, "Missing message"); - _n_workers = _workers->update_active_workers(nworkers); + _n_workers = _workers->set_active_workers(nworkers); assert(_n_workers <= nworkers, "Must be"); log_info(gc, task)("Using %u of %u workers for %s", @@ -51,10 +51,10 @@ ShenandoahWorkerScope::~ShenandoahWorkerScope() { "Active workers can not be changed within this scope"); } -ShenandoahPushWorkerScope::ShenandoahPushWorkerScope(WorkGang* workers, uint nworkers, bool check) : +ShenandoahPushWorkerScope::ShenandoahPushWorkerScope(WorkerThreads* workers, uint nworkers, bool check) : _old_workers(workers->active_workers()), _workers(workers) { - _n_workers = _workers->update_active_workers(nworkers); + _n_workers = _workers->set_active_workers(nworkers); assert(_n_workers <= nworkers, "Must be"); // bypass concurrent/parallel protocol check for non-regular paths, e.g. verifier, etc. @@ -67,12 +67,12 @@ ShenandoahPushWorkerScope::~ShenandoahPushWorkerScope() { assert(_workers->active_workers() == _n_workers, "Active workers can not be changed within this scope"); // Restore old worker value - uint nworkers = _workers->update_active_workers(_old_workers); + uint nworkers = _workers->set_active_workers(_old_workers); assert(nworkers == _old_workers, "Must be able to restore"); } -GangWorker* ShenandoahWorkGang::install_worker(uint which) { - GangWorker* worker = WorkGang::install_worker(which); +WorkerThread* ShenandoahWorkerThreads::create_worker(uint id) { + WorkerThread* worker = WorkerThreads::create_worker(id); ShenandoahThreadLocalData::create(worker); if (_initialize_gclab) { ShenandoahThreadLocalData::initialize_gclab(worker); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahWorkGroup.hpp b/src/hotspot/share/gc/shenandoah/shenandoahWorkGroup.hpp index 5ccd87773a3..f5bd3ea0e48 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahWorkGroup.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahWorkGroup.hpp @@ -25,7 +25,7 @@ #ifndef SHARE_GC_SHENANDOAH_SHENANDOAHWORKGROUP_HPP #define SHARE_GC_SHENANDOAH_SHENANDOAHWORKGROUP_HPP -#include "gc/shared/workgroup.hpp" +#include "gc/shared/workerThread.hpp" #include "gc/shenandoah/shenandoahTaskqueue.hpp" #include "memory/allocation.hpp" @@ -34,9 +34,9 @@ class ShenandoahObjToScanQueueSet; class ShenandoahWorkerScope : public StackObj { private: uint _n_workers; - WorkGang* _workers; + WorkerThreads* _workers; public: - ShenandoahWorkerScope(WorkGang* workers, uint nworkers, const char* msg, bool do_check = true); + ShenandoahWorkerScope(WorkerThreads* workers, uint nworkers, const char* msg, bool do_check = true); ~ShenandoahWorkerScope(); }; @@ -44,25 +44,25 @@ class ShenandoahPushWorkerScope : StackObj { protected: uint _n_workers; uint _old_workers; - WorkGang* _workers; + WorkerThreads* _workers; public: - ShenandoahPushWorkerScope(WorkGang* workers, uint nworkers, bool do_check = true); + ShenandoahPushWorkerScope(WorkerThreads* workers, uint nworkers, bool do_check = true); ~ShenandoahPushWorkerScope(); }; -class ShenandoahWorkGang : public WorkGang { +class ShenandoahWorkerThreads : public WorkerThreads { private: bool _initialize_gclab; public: - ShenandoahWorkGang(const char* name, + ShenandoahWorkerThreads(const char* name, uint workers) : - WorkGang(name, workers), _initialize_gclab(false) { + WorkerThreads(name, workers), _initialize_gclab(false) { } - // Create a GC worker and install it into the work gang. + // Create a GC worker. // We need to initialize gclab for dynamic allocated workers - GangWorker* install_worker(uint which); + WorkerThread* create_worker(uint id); void set_initialize_gclab() { assert(!_initialize_gclab, "Can only enable once"); _initialize_gclab = true; } }; diff --git a/src/hotspot/share/gc/z/zCollectedHeap.cpp b/src/hotspot/share/gc/z/zCollectedHeap.cpp index 0e31f859275..af546dd35e9 100644 --- a/src/hotspot/share/gc/z/zCollectedHeap.cpp +++ b/src/hotspot/share/gc/z/zCollectedHeap.cpp @@ -266,7 +266,7 @@ void ZCollectedHeap::verify_nmethod(nmethod* nm) { // Does nothing } -WorkGang* ZCollectedHeap::safepoint_workers() { +WorkerThreads* ZCollectedHeap::safepoint_workers() { return _runtime_workers.workers(); } diff --git a/src/hotspot/share/gc/z/zCollectedHeap.hpp b/src/hotspot/share/gc/z/zCollectedHeap.hpp index 91c78420995..ff6c09a9384 100644 --- a/src/hotspot/share/gc/z/zCollectedHeap.hpp +++ b/src/hotspot/share/gc/z/zCollectedHeap.hpp @@ -104,7 +104,7 @@ public: virtual void flush_nmethod(nmethod* nm); virtual void verify_nmethod(nmethod* nmethod); - virtual WorkGang* safepoint_workers(); + virtual WorkerThreads* safepoint_workers(); virtual void gc_threads_do(ThreadClosure* tc) const; diff --git a/src/hotspot/share/gc/z/zRuntimeWorkers.cpp b/src/hotspot/share/gc/z/zRuntimeWorkers.cpp index 59d3029fec5..568b9b778ce 100644 --- a/src/hotspot/share/gc/z/zRuntimeWorkers.cpp +++ b/src/hotspot/share/gc/z/zRuntimeWorkers.cpp @@ -30,7 +30,7 @@ #include "gc/z/zThread.hpp" #include "runtime/java.hpp" -class ZRuntimeWorkersInitializeTask : public AbstractGangTask { +class ZRuntimeWorkersInitializeTask : public WorkerTask { private: const uint _nworkers; uint _started; @@ -38,7 +38,7 @@ private: public: ZRuntimeWorkersInitializeTask(uint nworkers) : - AbstractGangTask("ZRuntimeWorkersInitializeTask"), + WorkerTask("ZRuntimeWorkersInitializeTask"), _nworkers(nworkers), _started(0), _lock() {} @@ -61,22 +61,22 @@ ZRuntimeWorkers::ZRuntimeWorkers() : _workers("RuntimeWorker", ParallelGCThreads) { - log_info_p(gc, init)("Runtime Workers: %u", _workers.total_workers()); + log_info_p(gc, init)("Runtime Workers: %u", _workers.max_workers()); // Initialize worker threads _workers.initialize_workers(); - _workers.update_active_workers(_workers.total_workers()); - if (_workers.active_workers() != _workers.total_workers()) { + _workers.set_active_workers(_workers.max_workers()); + if (_workers.active_workers() != _workers.max_workers()) { vm_exit_during_initialization("Failed to create ZRuntimeWorkers"); } // Execute task to reduce latency in early safepoints, // which otherwise would have to take on any warmup costs. - ZRuntimeWorkersInitializeTask task(_workers.total_workers()); + ZRuntimeWorkersInitializeTask task(_workers.max_workers()); _workers.run_task(&task); } -WorkGang* ZRuntimeWorkers::workers() { +WorkerThreads* ZRuntimeWorkers::workers() { return &_workers; } diff --git a/src/hotspot/share/gc/z/zRuntimeWorkers.hpp b/src/hotspot/share/gc/z/zRuntimeWorkers.hpp index 8ff19c7b699..dede5b0b2d9 100644 --- a/src/hotspot/share/gc/z/zRuntimeWorkers.hpp +++ b/src/hotspot/share/gc/z/zRuntimeWorkers.hpp @@ -24,18 +24,18 @@ #ifndef SHARE_GC_Z_ZRUNTIMEWORKERS_HPP #define SHARE_GC_Z_ZRUNTIMEWORKERS_HPP -#include "gc/shared/workgroup.hpp" +#include "gc/shared/workerThread.hpp" class ThreadClosure; class ZRuntimeWorkers { private: - WorkGang _workers; + WorkerThreads _workers; public: ZRuntimeWorkers(); - WorkGang* workers(); + WorkerThreads* workers(); void threads_do(ThreadClosure* tc) const; }; diff --git a/src/hotspot/share/gc/z/zTask.cpp b/src/hotspot/share/gc/z/zTask.cpp index 37905ebc6df..7a0503a4fb8 100644 --- a/src/hotspot/share/gc/z/zTask.cpp +++ b/src/hotspot/share/gc/z/zTask.cpp @@ -25,23 +25,23 @@ #include "gc/z/zTask.hpp" #include "gc/z/zThread.hpp" -ZTask::GangTask::GangTask(ZTask* ztask, const char* name) : - AbstractGangTask(name), - _ztask(ztask) {} +ZTask::Task::Task(ZTask* task, const char* name) : + WorkerTask(name), + _task(task) {} -void ZTask::GangTask::work(uint worker_id) { +void ZTask::Task::work(uint worker_id) { ZThread::set_worker_id(worker_id); - _ztask->work(); + _task->work(); ZThread::clear_worker_id(); } ZTask::ZTask(const char* name) : - _gang_task(this, name) {} + _worker_task(this, name) {} const char* ZTask::name() const { - return _gang_task.name(); + return _worker_task.name(); } -AbstractGangTask* ZTask::gang_task() { - return &_gang_task; +WorkerTask* ZTask::worker_task() { + return &_worker_task; } diff --git a/src/hotspot/share/gc/z/zTask.hpp b/src/hotspot/share/gc/z/zTask.hpp index a4a116b7c22..80836aedcac 100644 --- a/src/hotspot/share/gc/z/zTask.hpp +++ b/src/hotspot/share/gc/z/zTask.hpp @@ -24,28 +24,28 @@ #ifndef SHARE_GC_Z_ZTASK_HPP #define SHARE_GC_Z_ZTASK_HPP -#include "gc/shared/workgroup.hpp" +#include "gc/shared/workerThread.hpp" #include "memory/allocation.hpp" class ZTask : public StackObj { private: - class GangTask : public AbstractGangTask { + class Task : public WorkerTask { private: - ZTask* const _ztask; + ZTask* const _task; public: - GangTask(ZTask* ztask, const char* name); + Task(ZTask* task, const char* name); virtual void work(uint worker_id); }; - GangTask _gang_task; + Task _worker_task; public: ZTask(const char* name); const char* name() const; - AbstractGangTask* gang_task(); + WorkerTask* worker_task(); virtual void work() = 0; }; diff --git a/src/hotspot/share/gc/z/zWorkers.cpp b/src/hotspot/share/gc/z/zWorkers.cpp index 782d91fd703..84f17f299fb 100644 --- a/src/hotspot/share/gc/z/zWorkers.cpp +++ b/src/hotspot/share/gc/z/zWorkers.cpp @@ -31,7 +31,7 @@ #include "gc/z/zWorkers.hpp" #include "runtime/java.hpp" -class ZWorkersInitializeTask : public AbstractGangTask { +class ZWorkersInitializeTask : public WorkerTask { private: const uint _nworkers; uint _started; @@ -39,7 +39,7 @@ private: public: ZWorkersInitializeTask(uint nworkers) : - AbstractGangTask("ZWorkersInitializeTask"), + WorkerTask("ZWorkersInitializeTask"), _nworkers(nworkers), _started(0), _lock() {} @@ -66,20 +66,20 @@ ZWorkers::ZWorkers() : UseDynamicNumberOfGCThreads ? ConcGCThreads : MAX2(ConcGCThreads, ParallelGCThreads)) { if (UseDynamicNumberOfGCThreads) { - log_info_p(gc, init)("GC Workers: %u (dynamic)", _workers.total_workers()); + log_info_p(gc, init)("GC Workers: %u (dynamic)", _workers.max_workers()); } else { - log_info_p(gc, init)("GC Workers: %u/%u (static)", ConcGCThreads, _workers.total_workers()); + log_info_p(gc, init)("GC Workers: %u/%u (static)", ConcGCThreads, _workers.max_workers()); } // Initialize worker threads _workers.initialize_workers(); - _workers.update_active_workers(_workers.total_workers()); - if (_workers.active_workers() != _workers.total_workers()) { + _workers.set_active_workers(_workers.max_workers()); + if (_workers.active_workers() != _workers.max_workers()) { vm_exit_during_initialization("Failed to create ZWorkers"); } // Execute task to register threads as workers - ZWorkersInitializeTask task(_workers.total_workers()); + ZWorkersInitializeTask task(_workers.max_workers()); _workers.run_task(&task); } @@ -89,13 +89,13 @@ uint ZWorkers::active_workers() const { void ZWorkers::set_active_workers(uint nworkers) { log_info(gc, task)("Using %u workers", nworkers); - _workers.update_active_workers(nworkers); + _workers.set_active_workers(nworkers); } void ZWorkers::run(ZTask* task) { log_debug(gc, task)("Executing Task: %s, Active Workers: %u", task->name(), active_workers()); ZStatWorkers::at_start(); - _workers.run_task(task->gang_task()); + _workers.run_task(task->worker_task()); ZStatWorkers::at_end(); } @@ -104,12 +104,12 @@ void ZWorkers::run_all(ZTask* task) { const uint prev_active_workers = _workers.active_workers(); // Execute task using all workers - _workers.update_active_workers(_workers.total_workers()); + _workers.set_active_workers(_workers.max_workers()); log_debug(gc, task)("Executing Task: %s, Active Workers: %u", task->name(), active_workers()); - _workers.run_task(task->gang_task()); + _workers.run_task(task->worker_task()); // Restore number of active workers - _workers.update_active_workers(prev_active_workers); + _workers.set_active_workers(prev_active_workers); } void ZWorkers::threads_do(ThreadClosure* tc) const { diff --git a/src/hotspot/share/gc/z/zWorkers.hpp b/src/hotspot/share/gc/z/zWorkers.hpp index 9618f00b087..3ee14ece6be 100644 --- a/src/hotspot/share/gc/z/zWorkers.hpp +++ b/src/hotspot/share/gc/z/zWorkers.hpp @@ -24,14 +24,14 @@ #ifndef SHARE_GC_Z_ZWORKERS_HPP #define SHARE_GC_Z_ZWORKERS_HPP -#include "gc/shared/workgroup.hpp" +#include "gc/shared/workerThread.hpp" class ThreadClosure; class ZTask; class ZWorkers { private: - WorkGang _workers; + WorkerThreads _workers; public: ZWorkers(); diff --git a/src/hotspot/share/logging/logPrefix.hpp b/src/hotspot/share/logging/logPrefix.hpp index 2027bf6bc29..3411bfb7c79 100644 --- a/src/hotspot/share/logging/logPrefix.hpp +++ b/src/hotspot/share/logging/logPrefix.hpp @@ -94,8 +94,7 @@ DEBUG_ONLY(size_t Test_log_prefix_prefixer(char* buf, size_t len);) DEBUG_ONLY(LOG_PREFIX(Test_log_prefix_prefixer, LOG_TAGS(logging, test))) \ LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, tlab)) \ LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, verify)) \ - LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, verify, start)) \ - LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, workgang)) + LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, verify, start)) // The empty prefix, used when there's no prefix defined. diff --git a/src/hotspot/share/logging/logTag.hpp b/src/hotspot/share/logging/logTag.hpp index cf86eaccc4d..efa03312bd6 100644 --- a/src/hotspot/share/logging/logTag.hpp +++ b/src/hotspot/share/logging/logTag.hpp @@ -196,8 +196,7 @@ LOG_TAG(vmoperation) \ LOG_TAG(vmthread) \ LOG_TAG(vtables) \ - LOG_TAG(vtablestubs) \ - LOG_TAG(workgang) + LOG_TAG(vtablestubs) #define PREFIX_LOG_TAG(T) (LogTag::_##T) diff --git a/src/hotspot/share/memory/heapInspection.cpp b/src/hotspot/share/memory/heapInspection.cpp index a656bb3cb5d..b024de61589 100644 --- a/src/hotspot/share/memory/heapInspection.cpp +++ b/src/hotspot/share/memory/heapInspection.cpp @@ -577,20 +577,21 @@ uintx HeapInspection::populate_table(KlassInfoTable* cit, BoolObjectClosure *fil if (parallel_thread_num > 1) { ResourceMark rm; - WorkGang* gang = Universe::heap()->safepoint_workers(); - if (gang != NULL) { - // The GC provided a WorkGang to be used during a safepoint. + WorkerThreads* workers = Universe::heap()->safepoint_workers(); + if (workers != NULL) { + // The GC provided a WorkerThreads to be used during a safepoint. - // Can't run with more threads than provided by the WorkGang. - WithUpdatedActiveWorkers update_and_restore(gang, parallel_thread_num); + // Can't run with more threads than provided by the WorkerThreads. + const uint capped_parallel_thread_num = MIN2(parallel_thread_num, workers->max_workers()); + WithActiveWorkers with_active_workers(workers, capped_parallel_thread_num); - ParallelObjectIterator* poi = Universe::heap()->parallel_object_iterator(gang->active_workers()); + ParallelObjectIterator* poi = Universe::heap()->parallel_object_iterator(workers->active_workers()); if (poi != NULL) { // The GC supports parallel object iteration. ParHeapInspectTask task(poi, cit, filter); // Run task with the active workers. - gang->run_task(&task); + workers->run_task(&task); delete poi; if (task.success()) { diff --git a/src/hotspot/share/memory/heapInspection.hpp b/src/hotspot/share/memory/heapInspection.hpp index d05af988803..f8d16225681 100644 --- a/src/hotspot/share/memory/heapInspection.hpp +++ b/src/hotspot/share/memory/heapInspection.hpp @@ -25,12 +25,12 @@ #ifndef SHARE_MEMORY_HEAPINSPECTION_HPP #define SHARE_MEMORY_HEAPINSPECTION_HPP +#include "gc/shared/workerThread.hpp" #include "memory/allocation.hpp" #include "oops/objArrayOop.hpp" #include "oops/oop.hpp" #include "oops/annotations.hpp" #include "utilities/macros.hpp" -#include "gc/shared/workgroup.hpp" class ParallelObjectIterator; @@ -226,7 +226,7 @@ class HeapInspection : public StackObj { // Parallel heap inspection task. Parallel inspection can fail due to // a native OOM when allocating memory for TL-KlassInfoTable. // _success will be set false on an OOM, and serial inspection tried. -class ParHeapInspectTask : public AbstractGangTask { +class ParHeapInspectTask : public WorkerTask { private: ParallelObjectIterator* _poi; KlassInfoTable* _shared_cit; @@ -239,7 +239,7 @@ class ParHeapInspectTask : public AbstractGangTask { ParHeapInspectTask(ParallelObjectIterator* poi, KlassInfoTable* shared_cit, BoolObjectClosure* filter) : - AbstractGangTask("Iterating heap"), + WorkerTask("Iterating heap"), _poi(poi), _shared_cit(shared_cit), _filter(filter), diff --git a/src/hotspot/share/runtime/nonJavaThread.hpp b/src/hotspot/share/runtime/nonJavaThread.hpp index 0556fa95044..5eb26e42924 100644 --- a/src/hotspot/share/runtime/nonJavaThread.hpp +++ b/src/hotspot/share/runtime/nonJavaThread.hpp @@ -101,31 +101,6 @@ class NamedThread: public NonJavaThread { uint gc_id() { return _gc_id; } }; -// Worker threads are named and have an id of an assigned work. -class WorkerThread: public NamedThread { - private: - uint _id; - public: - static WorkerThread* current() { - return WorkerThread::cast(Thread::current()); - } - - static WorkerThread* cast(Thread* t) { - assert(t->is_Worker_thread(), "incorrect cast to WorkerThread"); - return static_cast(t); - } - - WorkerThread() : _id(0) { } - virtual bool is_Worker_thread() const { return true; } - - void set_id(uint work_id) { _id = work_id; } - uint id() const { return _id; } - - // Printing - virtual const char* type_name() const { return "WorkerThread"; } - -}; - // A single WatcherThread is used for simulating timer interrupts. class WatcherThread: public NonJavaThread { friend class VMStructs; diff --git a/src/hotspot/share/runtime/safepoint.cpp b/src/hotspot/share/runtime/safepoint.cpp index 49046a710ee..be371446242 100644 --- a/src/hotspot/share/runtime/safepoint.cpp +++ b/src/hotspot/share/runtime/safepoint.cpp @@ -37,7 +37,8 @@ #include "gc/shared/gcLocker.hpp" #include "gc/shared/oopStorage.hpp" #include "gc/shared/strongRootsScope.hpp" -#include "gc/shared/workgroup.hpp" +#include "gc/shared/workerThread.hpp" +#include "gc/shared/workerUtils.hpp" #include "interpreter/interpreter.hpp" #include "jfr/jfrEvents.hpp" #include "logging/log.hpp" @@ -515,7 +516,7 @@ public: } }; -class ParallelSPCleanupTask : public AbstractGangTask { +class ParallelSPCleanupTask : public WorkerTask { private: SubTasksDone _subtasks; uint _num_workers; @@ -539,7 +540,7 @@ private: public: ParallelSPCleanupTask(uint num_workers) : - AbstractGangTask("Parallel Safepoint Cleanup"), + WorkerTask("Parallel Safepoint Cleanup"), _subtasks(SafepointSynchronize::SAFEPOINT_CLEANUP_NUM_TASKS), _num_workers(num_workers), _do_lazy_roots(!VMThread::vm_operation()->skip_thread_oop_barriers() && @@ -602,7 +603,7 @@ void SafepointSynchronize::do_cleanup_tasks() { CollectedHeap* heap = Universe::heap(); assert(heap != NULL, "heap not initialized yet?"); - WorkGang* cleanup_workers = heap->safepoint_workers(); + WorkerThreads* cleanup_workers = heap->safepoint_workers(); if (cleanup_workers != NULL) { // Parallel cleanup using GC provided thread pool. uint num_cleanup_workers = cleanup_workers->active_workers(); diff --git a/src/hotspot/share/runtime/sweeper.cpp b/src/hotspot/share/runtime/sweeper.cpp index 0d270eb0b0d..31c9220ea78 100644 --- a/src/hotspot/share/runtime/sweeper.cpp +++ b/src/hotspot/share/runtime/sweeper.cpp @@ -29,7 +29,7 @@ #include "code/nmethod.hpp" #include "compiler/compileBroker.hpp" #include "gc/shared/collectedHeap.hpp" -#include "gc/shared/workgroup.hpp" +#include "gc/shared/workerThread.hpp" #include "jfr/jfrEvents.hpp" #include "logging/log.hpp" #include "logging/logStream.hpp" diff --git a/src/hotspot/share/runtime/thread.hpp b/src/hotspot/share/runtime/thread.hpp index d0c9cd65072..9540b7855bb 100644 --- a/src/hotspot/share/runtime/thread.hpp +++ b/src/hotspot/share/runtime/thread.hpp @@ -99,7 +99,6 @@ class JavaThread; // - VMThread // - ConcurrentGCThread // - WorkerThread -// - GangWorker // - WatcherThread // - JfrThreadSampler // - LogAsyncWriter diff --git a/src/hotspot/share/services/heapDumper.cpp b/src/hotspot/share/services/heapDumper.cpp index 8c21c80f772..348ed2c3746 100644 --- a/src/hotspot/share/services/heapDumper.cpp +++ b/src/hotspot/share/services/heapDumper.cpp @@ -32,7 +32,7 @@ #include "classfile/vmSymbols.hpp" #include "gc/shared/gcLocker.hpp" #include "gc/shared/gcVMOperations.hpp" -#include "gc/shared/workgroup.hpp" +#include "gc/shared/workerThread.hpp" #include "jfr/jfrEvents.hpp" #include "memory/allocation.inline.hpp" #include "memory/resourceArea.hpp" @@ -1853,7 +1853,7 @@ class DumperController : public CHeapObj { }; // The VM operation that performs the heap dump -class VM_HeapDumper : public VM_GC_Operation, public AbstractGangTask { +class VM_HeapDumper : public VM_GC_Operation, public WorkerTask { private: static VM_HeapDumper* _global_dumper; static DumpWriter* _global_writer; @@ -1973,7 +1973,7 @@ class VM_HeapDumper : public VM_GC_Operation, public AbstractGangTask { GCCause::_heap_dump /* GC Cause */, 0 /* total full collections, dummy, ignored */, gc_before_heap_dump), - AbstractGangTask("dump heap") { + WorkerTask("dump heap") { _local_writer = writer; _gc_before_heap_dump = gc_before_heap_dump; _klass_map = new (ResourceObj::C_HEAP, mtServiceability) GrowableArray(INITIAL_CLASS_COUNT, mtServiceability); @@ -2248,16 +2248,16 @@ void VM_HeapDumper::doit() { set_global_dumper(); set_global_writer(); - WorkGang* gang = ch->safepoint_workers(); + WorkerThreads* workers = ch->safepoint_workers(); - if (gang == NULL) { + if (workers == NULL) { // Use serial dump, set dumper threads and writer threads number to 1. _num_dumper_threads=1; _num_writer_threads=1; work(0); } else { - prepare_parallel_dump(gang->active_workers()); - gang->run_task(this); + prepare_parallel_dump(workers->active_workers()); + workers->run_task(this); finish_parallel_dump(); } diff --git a/test/hotspot/gtest/gc/g1/test_g1BatchedGangTask.cpp b/test/hotspot/gtest/gc/g1/test_g1BatchedGangTask.cpp index 9facc4a61f3..d166fdce71e 100644 --- a/test/hotspot/gtest/gc/g1/test_g1BatchedGangTask.cpp +++ b/test/hotspot/gtest/gc/g1/test_g1BatchedGangTask.cpp @@ -24,30 +24,30 @@ #include "precompiled.hpp" -#include "gc/g1/g1BatchedGangTask.hpp" -#include "gc/shared/workgroup.hpp" +#include "gc/g1/g1BatchedTask.hpp" +#include "gc/shared/workerThread.hpp" #include "runtime/atomic.hpp" #include "unittest.hpp" -class G1BatchedGangTaskWorkers : AllStatic { - static WorkGang* _work_gang; - static WorkGang* work_gang() { - if (_work_gang == nullptr) { - _work_gang = new WorkGang("G1 Small Workers", MaxWorkers); - _work_gang->initialize_workers(); - _work_gang->update_active_workers(MaxWorkers); +class G1BatchedTaskWorkers : AllStatic { + static WorkerThreads* _workers; + static WorkerThreads* workers() { + if (_workers == nullptr) { + _workers = new WorkerThreads("G1 Small Workers", MaxWorkers); + _workers->initialize_workers(); + _workers->set_active_workers(MaxWorkers); } - return _work_gang; + return _workers; } public: static const uint MaxWorkers = 4; - static void run_task(AbstractGangTask* task) { - work_gang()->run_task(task); + static void run_task(WorkerTask* task) { + workers()->run_task(task); } }; -WorkGang* G1BatchedGangTaskWorkers::_work_gang = nullptr; +WorkerThreads* G1BatchedTaskWorkers::_workers = nullptr; class G1TestSubTask : public G1AbstractSubTask { mutable uint _phase; @@ -96,7 +96,7 @@ public: return 1.0; } - // Called by G1BatchedGangTask to provide information about the the maximum + // Called by G1BatchedTask to provide information about the the maximum // number of workers for all subtasks after it has been determined. void set_max_workers(uint max_workers) override { assert(max_workers >= 1, "must be"); @@ -140,18 +140,18 @@ public: } }; -class G1TestBatchedGangTask : public G1BatchedGangTask { +class G1TestBatchedTask : public G1BatchedTask { public: - G1TestBatchedGangTask() : G1BatchedGangTask("Batched Gang Test Task", nullptr) { + G1TestBatchedTask() : G1BatchedTask("Batched Test Task", nullptr) { add_serial_task(new G1SerialTestSubTask()); add_parallel_task(new G1ParallelTestSubTask()); } }; -TEST_VM(G1BatchedGangTask, check) { - G1TestBatchedGangTask task; +TEST_VM(G1BatchedTask, check) { + G1TestBatchedTask task; uint tasks = task.num_workers_estimate(); ASSERT_EQ(tasks, 3u); - task.set_max_workers(G1BatchedGangTaskWorkers::MaxWorkers); - G1BatchedGangTaskWorkers::run_task(&task); + task.set_max_workers(G1BatchedTaskWorkers::MaxWorkers); + G1BatchedTaskWorkers::run_task(&task); } diff --git a/test/hotspot/gtest/gc/g1/test_g1CardSet.cpp b/test/hotspot/gtest/gc/g1/test_g1CardSet.cpp index dfb8a4d142e..cbfb5d58aed 100644 --- a/test/hotspot/gtest/gc/g1/test_g1CardSet.cpp +++ b/test/hotspot/gtest/gc/g1/test_g1CardSet.cpp @@ -27,7 +27,7 @@ #include "gc/g1/g1CardSetMemory.hpp" #include "gc/g1/heapRegionRemSet.hpp" #include "gc/shared/gcTraceTime.inline.hpp" -#include "gc/shared/workgroup.hpp" +#include "gc/shared/workerThread.hpp" #include "logging/log.hpp" #include "unittest.hpp" #include "utilities/powerOfTwo.hpp" @@ -44,15 +44,15 @@ class G1CardSetTest : public ::testing::Test { } }; - static WorkGang* _workers; + static WorkerThreads* _workers; static uint _max_workers; - static WorkGang* workers() { + static WorkerThreads* workers() { if (_workers == NULL) { _max_workers = os::processor_count(); - _workers = new WorkGang("G1CardSetTest Work Gang", _max_workers); + _workers = new WorkerThreads("G1CardSetTest Workers", _max_workers); _workers->initialize_workers(); - _workers->update_active_workers(_max_workers); + _workers->set_active_workers(_max_workers); } return _workers; } @@ -85,7 +85,7 @@ public: static void iterate_cards(G1CardSet* card_set, G1CardSet::G1CardSetCardIterator* cl); }; -WorkGang* G1CardSetTest::_workers = NULL; +WorkerThreads* G1CardSetTest::_workers = NULL; uint G1CardSetTest::_max_workers = 0; void G1CardSetTest::add_cards(G1CardSet* card_set, uint cards_per_region, uint* cards, uint num_cards, G1AddCardResult* results) { @@ -376,7 +376,7 @@ void G1CardSetTest::cardset_basic_test() { } } -class G1CardSetMtTestTask : public AbstractGangTask { +class G1CardSetMtTestTask : public WorkerTask { G1CardSet* _card_set; size_t _added; @@ -384,7 +384,7 @@ class G1CardSetMtTestTask : public AbstractGangTask { public: G1CardSetMtTestTask(G1CardSet* card_set) : - AbstractGangTask(""), + WorkerTask(""), _card_set(card_set), _added(0), _found(0) { } diff --git a/test/hotspot/gtest/gc/g1/test_stressCommitUncommit.cpp b/test/hotspot/gtest/gc/g1/test_stressCommitUncommit.cpp index f18d2dc3d3f..668c63acf51 100644 --- a/test/hotspot/gtest/gc/g1/test_stressCommitUncommit.cpp +++ b/test/hotspot/gtest/gc/g1/test_stressCommitUncommit.cpp @@ -26,36 +26,36 @@ #include "gc/g1/g1BlockOffsetTable.hpp" #include "gc/g1/g1RegionToSpaceMapper.hpp" #include "memory/virtualspace.hpp" -#include "gc/shared/workgroup.hpp" +#include "gc/shared/workerThread.hpp" #include "runtime/atomic.hpp" #include "runtime/os.hpp" #include "unittest.hpp" class G1MapperWorkers : AllStatic { - static WorkGang* _work_gang; - static WorkGang* work_gang() { - if (_work_gang == NULL) { - _work_gang = new WorkGang("G1 Small Workers", MaxWorkers); - _work_gang->initialize_workers(); - _work_gang->update_active_workers(MaxWorkers); + static WorkerThreads* _workers; + static WorkerThreads* workers() { + if (_workers == NULL) { + _workers = new WorkerThreads("G1 Small Workers", MaxWorkers); + _workers->initialize_workers(); + _workers->set_active_workers(MaxWorkers); } - return _work_gang; + return _workers; } public: static const uint MaxWorkers = 4; - static void run_task(AbstractGangTask* task) { - work_gang()->run_task(task); + static void run_task(WorkerTask* task) { + workers()->run_task(task); } }; -WorkGang* G1MapperWorkers::_work_gang = NULL; +WorkerThreads* G1MapperWorkers::_workers = NULL; -class G1TestCommitUncommit : public AbstractGangTask { +class G1TestCommitUncommit : public WorkerTask { G1RegionToSpaceMapper* _mapper; uint _claim_id; public: G1TestCommitUncommit(G1RegionToSpaceMapper* mapper) : - AbstractGangTask("Stress mapper"), + WorkerTask("Stress mapper"), _mapper(mapper), _claim_id(0) { } diff --git a/test/hotspot/gtest/gc/shared/test_oopStorage.cpp b/test/hotspot/gtest/gc/shared/test_oopStorage.cpp index 59da835cb06..85a1c098aa9 100644 --- a/test/hotspot/gtest/gc/shared/test_oopStorage.cpp +++ b/test/hotspot/gtest/gc/shared/test_oopStorage.cpp @@ -24,7 +24,7 @@ #include "precompiled.hpp" #include "gc/shared/oopStorage.inline.hpp" #include "gc/shared/oopStorageParState.inline.hpp" -#include "gc/shared/workgroup.hpp" +#include "gc/shared/workerThread.hpp" #include "memory/allocation.inline.hpp" #include "memory/resourceArea.hpp" #include "metaprogramming/conditional.hpp" @@ -863,7 +863,7 @@ TEST_VM_F(OopStorageTestIteration, oops_do) { class OopStorageTestParIteration : public OopStorageTestIteration { public: - WorkGang* workers(); + WorkerThreads* workers(); class VM_ParStateVerify; @@ -871,22 +871,22 @@ public: template class TaskUsingOopsDo; private: - static WorkGang* _workers; + static WorkerThreads* _workers; }; -WorkGang* OopStorageTestParIteration::_workers = NULL; +WorkerThreads* OopStorageTestParIteration::_workers = NULL; -WorkGang* OopStorageTestParIteration::workers() { +WorkerThreads* OopStorageTestParIteration::workers() { if (_workers == NULL) { - _workers = new WorkGang("OopStorageTestParIteration workers", _max_workers); + _workers = new WorkerThreads("OopStorageTestParIteration workers", _max_workers); _workers->initialize_workers(); - _workers->update_active_workers(_max_workers); + _workers->set_active_workers(_max_workers); } return _workers; } template -class OopStorageTestParIteration::Task : public AbstractGangTask { +class OopStorageTestParIteration::Task : public WorkerTask { typedef OopStorage::ParState StateType; typedef typename Conditional -class OopStorageTestParIteration::TaskUsingOopsDo : public AbstractGangTask { +class OopStorageTestParIteration::TaskUsingOopsDo : public WorkerTask { public: TaskUsingOopsDo(const char* name, OopStorage* storage, VerifyState* vstate) : - AbstractGangTask(name), + WorkerTask(name), _state(storage), _vstate(vstate) {} @@ -931,7 +931,7 @@ private: class OopStorageTestParIteration::VM_ParStateVerify : public VM_GTestExecuteAtSafepoint { public: - VM_ParStateVerify(WorkGang* workers, AbstractGangTask* task) : + VM_ParStateVerify(WorkerThreads* workers, WorkerTask* task) : _workers(workers), _task(task) {} @@ -940,8 +940,8 @@ public: } private: - WorkGang* _workers; - AbstractGangTask* _task; + WorkerThreads* _workers; + WorkerTask* _task; }; TEST_VM_F(OopStorageTestParIteration, par_state_safepoint_iterate) { diff --git a/test/hotspot/gtest/gc/shared/test_oopStorage_parperf.cpp b/test/hotspot/gtest/gc/shared/test_oopStorage_parperf.cpp index 00b3a9e6f38..9e8716291b3 100644 --- a/test/hotspot/gtest/gc/shared/test_oopStorage_parperf.cpp +++ b/test/hotspot/gtest/gc/shared/test_oopStorage_parperf.cpp @@ -24,7 +24,7 @@ #include "precompiled.hpp" #include "gc/shared/oopStorage.inline.hpp" #include "gc/shared/oopStorageParState.inline.hpp" -#include "gc/shared/workgroup.hpp" +#include "gc/shared/workerThread.hpp" #include "logging/log.hpp" #include "logging/logConfiguration.hpp" #include "memory/allocation.inline.hpp" @@ -56,7 +56,7 @@ public: OopStorageParIterPerf(); ~OopStorageParIterPerf(); - WorkGang* workers() const; + WorkerThreads* workers() const; class VM_ParStateTime; class Task; @@ -66,19 +66,19 @@ public: void show_task(const Task* task, Tickspan duration, uint nthreads); void run_test(uint nthreads); - static WorkGang* _workers; + static WorkerThreads* _workers; OopStorage _storage; oop* _entries[_storage_entries]; }; -WorkGang* OopStorageParIterPerf::_workers = NULL; +WorkerThreads* OopStorageParIterPerf::_workers = NULL; -WorkGang* OopStorageParIterPerf::workers() const { +WorkerThreads* OopStorageParIterPerf::workers() const { if (_workers == NULL) { - WorkGang* wg = new WorkGang("OopStorageParIterPerf workers", _num_workers); + WorkerThreads* wg = new WorkerThreads("OopStorageParIterPerf workers", _num_workers); wg->initialize_workers(); - wg->update_active_workers(_num_workers); + wg->set_active_workers(_num_workers); _workers = wg; } return _workers; @@ -99,7 +99,7 @@ OopStorageParIterPerf::~OopStorageParIterPerf() { class OopStorageParIterPerf::VM_ParStateTime : public VM_GTestExecuteAtSafepoint { public: - VM_ParStateTime(WorkGang* workers, AbstractGangTask* task, uint nthreads) : + VM_ParStateTime(WorkerThreads* workers, WorkerTask* task, uint nthreads) : _workers(workers), _task(task), _nthreads(nthreads) {} @@ -108,12 +108,12 @@ public: } private: - WorkGang* _workers; - AbstractGangTask* _task; + WorkerThreads* _workers; + WorkerTask* _task; uint _nthreads; }; -class OopStorageParIterPerf::Task : public AbstractGangTask { +class OopStorageParIterPerf::Task : public WorkerTask { typedef OopStorage::ParState StateType; Tickspan* _worker_times; @@ -122,7 +122,7 @@ class OopStorageParIterPerf::Task : public AbstractGangTask { public: Task(OopStorage* storage, OopClosure* closure, uint nthreads) : - AbstractGangTask("OopStorageParIterPerf::Task"), + WorkerTask("OopStorageParIterPerf::Task"), _worker_times(NULL), _state(storage, nthreads), _closure(closure) -- GitLab From 40d69f0c41c8550605c3a1e6e572aecd3a8cf138 Mon Sep 17 00:00:00 2001 From: Jaikiran Pai Date: Thu, 14 Oct 2021 14:38:16 +0000 Subject: [PATCH 210/385] 8254267: javax/xml/crypto/dsig/LogParameters.java failed with "RuntimeException: Unexpected log output:" Reviewed-by: weijun, dfuchs --- .../javax/xml/crypto/dsig/LogParameters.java | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/test/jdk/javax/xml/crypto/dsig/LogParameters.java b/test/jdk/javax/xml/crypto/dsig/LogParameters.java index cd829761f6e..fee2f2b1aa2 100644 --- a/test/jdk/javax/xml/crypto/dsig/LogParameters.java +++ b/test/jdk/javax/xml/crypto/dsig/LogParameters.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. * 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,21 +28,31 @@ import java.util.logging.*; /** * @test - * @bug 8247907 + * @bug 8247907 8254267 + * @summary Tests that parameterized log messages (the ones that use "{}") generated + * through the use of com.sun.org.slf4j.internal.Logger work as expected and the parameter + * values are properly replaced in the logged message. * @library /test/lib * @modules java.xml.crypto/com.sun.org.slf4j.internal + * @run main/othervm LogParameters */ public class LogParameters { + + private static final Logger julLogger = Logger.getLogger(LogParameters.class.getName()); + public static void main(String[] args) { ByteArrayOutputStream bout = new ByteArrayOutputStream(); - Logger.getLogger(String.class.getName()).setLevel(Level.ALL); + julLogger.setLevel(Level.ALL); Handler h = new StreamHandler(bout, new SimpleFormatter()); h.setLevel(Level.ALL); - Logger.getLogger(String.class.getName()).addHandler(h); + julLogger.addHandler(h); + // now create a com.sun.org.slf4j.internal.Logger for the same class + // for which we just configured the java.util.logging.Logger instance com.sun.org.slf4j.internal.Logger log = - com.sun.org.slf4j.internal.LoggerFactory.getLogger(String.class); + com.sun.org.slf4j.internal.LoggerFactory.getLogger(LogParameters.class); + // issue a parameterized log message log.debug("I have {} {}s.", 10, "apple"); h.flush(); -- GitLab From ede3f4e94c752a8457b7c24e001bd122845d2f6a Mon Sep 17 00:00:00 2001 From: Bernhard Urban-Forster Date: Thu, 14 Oct 2021 16:58:14 +0000 Subject: [PATCH 211/385] 8274795: AArch64: avoid spilling and restoring r18 in macro assembler Reviewed-by: aph --- .../cpu/aarch64/macroAssembler_aarch64.cpp | 20 +++++++++---------- .../cpu/aarch64/macroAssembler_aarch64.hpp | 4 ---- .../templateInterpreterGenerator_aarch64.cpp | 5 +++-- 3 files changed, 12 insertions(+), 17 deletions(-) diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp index de228bfeb6f..5c9b1fc327d 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp @@ -1855,15 +1855,6 @@ void MacroAssembler::increment(Address dst, int value) str(rscratch1, dst); } - -void MacroAssembler::pusha() { - push(0x7fffffff, sp); -} - -void MacroAssembler::popa() { - pop(0x7fffffff, sp); -} - // Push lots of registers in the bit set supplied. Don't push sp. // Return the number of words pushed int MacroAssembler::push(unsigned int bitset, Register stack) { @@ -2505,7 +2496,7 @@ void MacroAssembler::pop_call_clobbered_registers_except(RegSet exclude) { void MacroAssembler::push_CPU_state(bool save_vectors, bool use_sve, int sve_vector_size_in_bytes) { - push(0x3fffffff, sp); // integer registers except lr & sp + push(RegSet::range(r0, r29), sp); // integer registers except lr & sp if (save_vectors && use_sve && sve_vector_size_in_bytes > 16) { sub(sp, sp, sve_vector_size_in_bytes * FloatRegisterImpl::number_of_registers); for (int i = 0; i < FloatRegisterImpl::number_of_registers; i++) { @@ -2543,7 +2534,14 @@ void MacroAssembler::pop_CPU_state(bool restore_vectors, bool use_sve, reinitialize_ptrue(); } - pop(0x3fffffff, sp); // integer registers except lr & sp + // integer registers except lr & sp + pop(RegSet::range(r0, r17), sp); +#ifdef R18_RESERVED + ldp(zr, r19, Address(post(sp, 2 * wordSize))); + pop(RegSet::range(r20, r29), sp); +#else + pop(RegSet::range(r18_tls, r29), sp); +#endif } /** diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp index dae0a206656..3287f153ab8 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp @@ -1106,10 +1106,6 @@ public: void push(Register src); void pop(Register dst); - // push all registers onto the stack - void pusha(); - void popa(); - void repne_scan(Register addr, Register value, Register count, Register scratch); void repne_scanw(Register addr, Register value, Register count, diff --git a/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp index db253fe5c2c..e20cffd5767 100644 --- a/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp @@ -1397,11 +1397,12 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { __ cmp(rscratch1, (u1)StackOverflow::stack_guard_yellow_reserved_disabled); __ br(Assembler::NE, no_reguard); - __ pusha(); // XXX only save smashed registers + __ push_call_clobbered_registers(); __ mov(c_rarg0, rthread); __ mov(rscratch2, CAST_FROM_FN_PTR(address, SharedRuntime::reguard_yellow_pages)); __ blr(rscratch2); - __ popa(); // XXX only restore smashed registers + __ pop_call_clobbered_registers(); + __ bind(no_reguard); } -- GitLab From a16f2d0a3c326dd8b3b2133a9c170d998b7aa631 Mon Sep 17 00:00:00 2001 From: Fernando Guallini Date: Thu, 14 Oct 2021 18:26:27 +0000 Subject: [PATCH 212/385] 8272908: Missing coverage for certain classes in com.sun.org.apache.xml.internal.security Reviewed-by: rhalade --- .../internal/security/SignatureKeyInfo.java | 216 ++++++++++++++++++ .../xml/internal/security/TruncateHMAC.java | 19 +- ...signature-enveloping-hmac-sha1-keyinfo.xml | 25 ++ 3 files changed, 253 insertions(+), 7 deletions(-) create mode 100644 test/jdk/com/sun/org/apache/xml/internal/security/SignatureKeyInfo.java create mode 100644 test/jdk/com/sun/org/apache/xml/internal/security/signature-enveloping-hmac-sha1-keyinfo.xml diff --git a/test/jdk/com/sun/org/apache/xml/internal/security/SignatureKeyInfo.java b/test/jdk/com/sun/org/apache/xml/internal/security/SignatureKeyInfo.java new file mode 100644 index 00000000000..d1de2030c24 --- /dev/null +++ b/test/jdk/com/sun/org/apache/xml/internal/security/SignatureKeyInfo.java @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 8272908 + * @summary Verify signature KeyInfo + * @library /test/lib + * @modules java.xml.crypto/com.sun.org.apache.xml.internal.security + * java.xml.crypto/com.sun.org.apache.xml.internal.security.c14n + * java.xml.crypto/com.sun.org.apache.xml.internal.security.signature + * java.xml.crypto/com.sun.org.apache.xml.internal.security.utils + * java.xml.crypto/com.sun.org.apache.xml.internal.security.keys + * java.xml.crypto/com.sun.org.apache.xml.internal.security.keys.content.keyvalues + * java.xml.crypto/com.sun.org.apache.xml.internal.security.keys.content + * java.xml.crypto/com.sun.org.apache.xml.internal.security.exceptions + * @run main/othervm SignatureKeyInfo + */ + +import com.sun.org.apache.xml.internal.security.Init; +import com.sun.org.apache.xml.internal.security.exceptions.XMLSecurityException; +import com.sun.org.apache.xml.internal.security.keys.KeyInfo; +import com.sun.org.apache.xml.internal.security.keys.content.PGPData; +import com.sun.org.apache.xml.internal.security.keys.content.RetrievalMethod; +import com.sun.org.apache.xml.internal.security.keys.content.SPKIData; +import com.sun.org.apache.xml.internal.security.signature.XMLSignature; +import com.sun.org.apache.xml.internal.security.utils.Constants; +import com.sun.org.apache.xml.internal.security.utils.XMLUtils; +import com.sun.org.apache.xml.internal.security.utils.ElementProxy; +import com.sun.org.apache.xml.internal.security.keys.content.keyvalues.RSAKeyValue; +import com.sun.org.apache.xml.internal.security.keys.content.keyvalues.DSAKeyValue; + +import jdk.test.lib.Asserts; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + + +import javax.xml.crypto.dsig.CanonicalizationMethod; +import javax.xml.crypto.dsig.SignatureMethod; +import javax.xml.parsers.DocumentBuilderFactory; +import java.io.File; +import java.math.BigInteger; +import java.security.*; + +import static jdk.test.lib.Asserts.assertEquals; + +public class SignatureKeyInfo { + + private final static String DIR = System.getProperty("test.src", "."); + private static DocumentBuilderFactory dbf = null; + private static Document doc; + + private static final String NAME = "testName"; + private static final String TEXT = "testText"; + private static final String NS = Constants.SignatureSpecNS; + private static final String RSA = "RSA"; + private static final String DSA = "DSA"; + private static final String FILE_TO_SIGN = "signature-enveloping-hmac-sha1.xml"; + private static final String FILE_TO_VERIFY = "signature-enveloping-hmac-sha1-keyinfo.xml"; + private static final int FIRST_EL = 0; + + public static void main(String[] args) throws Exception { + + Init.init(); + dbf = DocumentBuilderFactory.newInstance(); + dbf.setNamespaceAware(true); + dbf.setValidating(false); + verifyXmlKeyInfo(); + sign(RSA); + sign(DSA); + } + + private static void sign(String algorithm) throws Exception { + File file = new File(DIR, FILE_TO_SIGN); + + doc = dbf.newDocumentBuilder().parse(file); + + KeyPair kp = getKeyPair(algorithm); + + String signMethod = RSA.equals(algorithm) ? SignatureMethod.RSA_SHA256 + : SignatureMethod.DSA_SHA256; + + XMLSignature signature = new XMLSignature(doc, null, + signMethod, CanonicalizationMethod.INCLUSIVE); + + signature.addKeyInfo(kp.getPublic()); + KeyInfo keyInfo = signature.getKeyInfo(); + addKeyInfoData(keyInfo, algorithm); + signature.sign(kp.getPrivate()); + } + + private static Element getSignElement() { + NodeList nl = + doc.getElementsByTagNameNS(NS, "Signature"); + if (nl.getLength() == 0) { + throw new RuntimeException("Could not find signature Element"); + } + + return (Element) nl.item(FIRST_EL); + } + + private static void addKeyInfoData(KeyInfo keyInfo, String algorithm) throws Exception { + KeyPair keyPair = getKeyPair(algorithm); + + if (algorithm.equals(RSA)) { + RSAKeyValue rsaKeyValue = new RSAKeyValue(doc, keyPair.getPublic()); + keyInfo.add(rsaKeyValue); + } else { + DSAKeyValue dsaKeyValue = new DSAKeyValue(doc, keyPair.getPublic()); + keyInfo.add(dsaKeyValue); + } + + Element elpgp= doc.createElementNS(NS, Constants._TAG_PGPDATA); + Element elrm= doc.createElementNS(NS, Constants._TAG_RETRIEVALMETHOD); + Element elspki= doc.createElementNS(NS, Constants._TAG_SPKIDATA); + keyInfo.add(new PGPData(elpgp, NS)); + keyInfo.add(new RetrievalMethod(elrm, NS)); + keyInfo.add(new SPKIData(elspki, NS)); + + keyInfo.setId(TEXT); + keyInfo.addKeyName(TEXT); + keyInfo.add(keyPair.getPublic()); + keyInfo.addKeyValue(keyPair.getPublic()); + keyInfo.addDEREncodedKeyValue(keyPair.getPublic()); + keyInfo.addKeyInfoReference(NS); + keyInfo.addMgmtData(TEXT); + + Element e = XMLUtils.createElementInSignatureSpace(doc, NAME); + keyInfo.addKeyValue(e); + keyInfo.addUnknownElement(e); + keyInfo.addText(TEXT); + keyInfo.addTextElement(TEXT, NAME); + keyInfo.addBigIntegerElement(BigInteger.valueOf(12345), NAME); + keyInfo.addBase64Text(TEXT.getBytes()); + keyInfo.addBase64Element(TEXT.getBytes(), NAME); + + verifyKeyInfoData(keyInfo, algorithm); + } + + private static KeyPair getKeyPair(String algorithm) throws NoSuchAlgorithmException { + KeyPairGenerator keyGen = KeyPairGenerator.getInstance(algorithm); + keyGen.initialize(2048); + + return keyGen.genKeyPair(); + } + + private static void verifyKeyInfoData(KeyInfo keyInfo, String algorithm) + throws XMLSecurityException { + Asserts.assertTrue(keyInfo.containsKeyName()); + verifyElementText(keyInfo.itemKeyName(FIRST_EL)); + Asserts.assertTrue(keyInfo.containsKeyValue()); + verifyElementNS(keyInfo.itemKeyValue(FIRST_EL).getBaseNamespace()); + + Asserts.assertTrue(keyInfo.containsKeyInfoReference()); + verifyElementNS(keyInfo.itemKeyInfoReference(FIRST_EL).getURI()); + Asserts.assertTrue(keyInfo.containsDEREncodedKeyValue()); + Asserts.assertTrue(keyInfo.containsMgmtData()); + verifyElementText(keyInfo.itemMgmtData(FIRST_EL)); + Asserts.assertEquals(TEXT, keyInfo.getId()); + + Asserts.assertTrue(keyInfo.containsPGPData()); + verifyElementNS(keyInfo.itemPGPData(FIRST_EL).getBaseNamespace()); + + Asserts.assertTrue(keyInfo.containsRetrievalMethod()); + verifyElementNS(keyInfo.itemRetrievalMethod(FIRST_EL).getBaseNamespace()); + Asserts.assertTrue(keyInfo.containsSPKIData()); + verifyElementNS(keyInfo.itemSPKIData(FIRST_EL).getBaseNamespace()); + + Asserts.assertTrue(keyInfo.containsUnknownElement()); + Asserts.assertEquals(NAME, keyInfo.itemUnknownElement(13).getLocalName()); + + Asserts.assertFalse(keyInfo.isEmpty()); + Asserts.assertEquals(algorithm, keyInfo.getPublicKey().getAlgorithm()); + } + + private static void verifyXmlKeyInfo() throws Exception { + File file = new File(DIR, FILE_TO_VERIFY); + + doc = dbf.newDocumentBuilder().parse(file); + Element sigElement = getSignElement(); + XMLSignature signature = new XMLSignature + (sigElement, file.toURI().toString()); + + KeyInfo keyInfo = signature.getKeyInfo(); + assertEquals(TEXT, keyInfo.itemMgmtData(FIRST_EL).getMgmtData()); + } + + private static void verifyElementText(ElementProxy elementProxy) { + Asserts.assertEquals(TEXT, elementProxy.getTextFromTextChild()); + } + + private static void verifyElementNS(String actualNs) { + Asserts.assertEquals(NS, actualNs); + } +} \ No newline at end of file diff --git a/test/jdk/com/sun/org/apache/xml/internal/security/TruncateHMAC.java b/test/jdk/com/sun/org/apache/xml/internal/security/TruncateHMAC.java index 2316d707658..b080df28ef4 100644 --- a/test/jdk/com/sun/org/apache/xml/internal/security/TruncateHMAC.java +++ b/test/jdk/com/sun/org/apache/xml/internal/security/TruncateHMAC.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,6 +47,7 @@ import com.sun.org.apache.xml.internal.security.signature.XMLSignature; import com.sun.org.apache.xml.internal.security.signature.XMLSignatureException; import com.sun.org.apache.xml.internal.security.utils.Constants; +import static java.nio.charset.StandardCharsets.US_ASCII; public class TruncateHMAC { @@ -64,7 +65,11 @@ public class TruncateHMAC { validate("signature-enveloping-hmac-sha1-trunclen-8-attack.xml", false); // this one should pass validate("signature-enveloping-hmac-sha1.xml", true); - generate_hmac_sha1_40(); + + // There are multiple validations regarding hmac min output length, therefore + // checking different values will exercise multiple code blocks + generate_hmac_sha1(40); + generate_hmac_sha1(128); if (atLeastOneFailed) { throw new Exception @@ -86,7 +91,7 @@ public class TruncateHMAC { try { XMLSignature signature = new XMLSignature (sigElement, file.toURI().toString()); - SecretKey sk = signature.createSecretKey("secret".getBytes("ASCII")); + SecretKey sk = signature.createSecretKey("secret".getBytes(US_ASCII)); System.out.println ("Validation status: " + signature.checkSignatureValue(sk)); if (!pass) { @@ -106,15 +111,15 @@ public class TruncateHMAC { } } - private static void generate_hmac_sha1_40() throws Exception { - System.out.println("Generating "); + private static void generate_hmac_sha1(int hmacOutputLength) throws Exception { + System.out.println("Generating " + hmacOutputLength); Document doc = dbf.newDocumentBuilder().newDocument(); try { XMLSignature sig = new XMLSignature - (doc, null, XMLSignature.ALGO_ID_MAC_HMAC_SHA1, 40, + (doc, null, XMLSignature.ALGO_ID_MAC_HMAC_SHA1, hmacOutputLength, Canonicalizer.ALGO_ID_C14N_OMIT_COMMENTS); - sig.sign(getSecretKey("secret".getBytes("ASCII"))); + sig.sign(getSecretKey("secret".getBytes(US_ASCII))); System.out.println("FAILED"); atLeastOneFailed = true; } catch (XMLSignatureException xse) { diff --git a/test/jdk/com/sun/org/apache/xml/internal/security/signature-enveloping-hmac-sha1-keyinfo.xml b/test/jdk/com/sun/org/apache/xml/internal/security/signature-enveloping-hmac-sha1-keyinfo.xml new file mode 100644 index 00000000000..5cd9d74dd5c --- /dev/null +++ b/test/jdk/com/sun/org/apache/xml/internal/security/signature-enveloping-hmac-sha1-keyinfo.xml @@ -0,0 +1,25 @@ + + + + + + + + 7/XTsHaBSOnJ/jXD5v0zL6VKYsk= + + + + JElPttIT4Am7Q+MNoMyv+WDfAZw= + + + testText + + + + BAds672US3sCYunM2k2bEQLbuRxdQlNTvq+5fitOpDMe0mBdZV4J3yZaG0taziYIuAT9GJGfds+q + xtXOCNWe/60= + + + + some text + \ No newline at end of file -- GitLab From 21df412bd9a02f0c3f351467951415141d920e03 Mon Sep 17 00:00:00 2001 From: Andrey Turbanov Date: Thu, 14 Oct 2021 23:12:05 +0000 Subject: [PATCH 213/385] 8275240: Change nested classes in jdk.attach to static nested classes Reviewed-by: cjplummer, dholmes, sspitsyn --- .../aix/classes/sun/tools/attach/VirtualMachineImpl.java | 2 +- .../linux/classes/sun/tools/attach/VirtualMachineImpl.java | 2 +- .../macosx/classes/sun/tools/attach/VirtualMachineImpl.java | 2 +- .../classes/sun/tools/attach/VirtualMachineImpl.java | 6 ++---- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/jdk.attach/aix/classes/sun/tools/attach/VirtualMachineImpl.java b/src/jdk.attach/aix/classes/sun/tools/attach/VirtualMachineImpl.java index 75cc0fbb476..78450b8053e 100644 --- a/src/jdk.attach/aix/classes/sun/tools/attach/VirtualMachineImpl.java +++ b/src/jdk.attach/aix/classes/sun/tools/attach/VirtualMachineImpl.java @@ -233,7 +233,7 @@ public class VirtualMachineImpl extends HotSpotVirtualMachine { /* * InputStream for the socket connection to get target VM */ - private class SocketInputStream extends InputStream { + private static class SocketInputStream extends InputStream { int s; public SocketInputStream(int s) { diff --git a/src/jdk.attach/linux/classes/sun/tools/attach/VirtualMachineImpl.java b/src/jdk.attach/linux/classes/sun/tools/attach/VirtualMachineImpl.java index e2fad3c06e2..402cc10b67b 100644 --- a/src/jdk.attach/linux/classes/sun/tools/attach/VirtualMachineImpl.java +++ b/src/jdk.attach/linux/classes/sun/tools/attach/VirtualMachineImpl.java @@ -237,7 +237,7 @@ public class VirtualMachineImpl extends HotSpotVirtualMachine { /* * InputStream for the socket connection to get target VM */ - private class SocketInputStream extends InputStream { + private static class SocketInputStream extends InputStream { int s = -1; public SocketInputStream(int s) { diff --git a/src/jdk.attach/macosx/classes/sun/tools/attach/VirtualMachineImpl.java b/src/jdk.attach/macosx/classes/sun/tools/attach/VirtualMachineImpl.java index 9c9e0b7494e..e484ddd1bc0 100644 --- a/src/jdk.attach/macosx/classes/sun/tools/attach/VirtualMachineImpl.java +++ b/src/jdk.attach/macosx/classes/sun/tools/attach/VirtualMachineImpl.java @@ -233,7 +233,7 @@ public class VirtualMachineImpl extends HotSpotVirtualMachine { /* * InputStream for the socket connection to get target VM */ - private class SocketInputStream extends InputStream { + private static class SocketInputStream extends InputStream { int s; public SocketInputStream(int s) { diff --git a/src/jdk.attach/windows/classes/sun/tools/attach/VirtualMachineImpl.java b/src/jdk.attach/windows/classes/sun/tools/attach/VirtualMachineImpl.java index 27b3f5c8eb6..1277e1fd123 100644 --- a/src/jdk.attach/windows/classes/sun/tools/attach/VirtualMachineImpl.java +++ b/src/jdk.attach/windows/classes/sun/tools/attach/VirtualMachineImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,8 +29,6 @@ import com.sun.tools.attach.AgentLoadException; import com.sun.tools.attach.AttachNotSupportedException; import com.sun.tools.attach.spi.AttachProvider; -import sun.tools.attach.HotSpotVirtualMachine; - import java.io.IOException; import java.io.InputStream; import java.util.Random; @@ -141,7 +139,7 @@ public class VirtualMachineImpl extends HotSpotVirtualMachine { } // An InputStream based on a pipe to the target VM - private class PipedInputStream extends InputStream { + private static class PipedInputStream extends InputStream { private long hPipe; -- GitLab From 9623d5bb46d14018a2b777fb7ffed6c66d912c84 Mon Sep 17 00:00:00 2001 From: Jie Fu Date: Thu, 14 Oct 2021 23:12:56 +0000 Subject: [PATCH 214/385] 8275265: java/nio/channels tests needing large heap sizes fail on x86_32 Reviewed-by: alanb, bpb --- test/jdk/java/nio/channels/Channels/ReadXBytes.java | 1 + test/jdk/java/nio/channels/FileChannel/LargeGatheringWrite.java | 1 + 2 files changed, 2 insertions(+) diff --git a/test/jdk/java/nio/channels/Channels/ReadXBytes.java b/test/jdk/java/nio/channels/Channels/ReadXBytes.java index 19214b9d4fc..1f36d4031fd 100644 --- a/test/jdk/java/nio/channels/Channels/ReadXBytes.java +++ b/test/jdk/java/nio/channels/Channels/ReadXBytes.java @@ -25,6 +25,7 @@ * @test * @bug 8268435 8274780 * @summary Verify ChannelInputStream methods readAllBytes and readNBytes + * @requires vm.bits == 64 * @library .. * @library /test/lib * @build jdk.test.lib.RandomFactory diff --git a/test/jdk/java/nio/channels/FileChannel/LargeGatheringWrite.java b/test/jdk/java/nio/channels/FileChannel/LargeGatheringWrite.java index bbfe0f57d79..69927150962 100644 --- a/test/jdk/java/nio/channels/FileChannel/LargeGatheringWrite.java +++ b/test/jdk/java/nio/channels/FileChannel/LargeGatheringWrite.java @@ -25,6 +25,7 @@ * @test * @bug 8274548 * @summary Test gathering write of more than INT_MAX bytes + * @requires vm.bits == 64 * @library .. * @library /test/lib * @build jdk.test.lib.RandomFactory -- GitLab From c355704a4b3d376b5429daba1576442b575f41ea Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Fri, 15 Oct 2021 02:21:26 +0000 Subject: [PATCH 215/385] 8041125: ColorConvertOp filter much slower in JDK 8 compared to JDK7 Reviewed-by: prr --- .../classes/sun/java2d/cmm/lcms/LCMS.java | 13 +- .../sun/java2d/cmm/lcms/LCMSImageLayout.java | 2 +- .../sun/java2d/cmm/lcms/LCMSTransform.java | 6 +- src/java.desktop/share/native/liblcms/LCMS.c | 143 +++--------------- 4 files changed, 36 insertions(+), 128 deletions(-) diff --git a/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMS.java b/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMS.java index edf13447a40..ee9ced827b7 100644 --- a/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMS.java +++ b/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMS.java @@ -148,11 +148,12 @@ final class LCMS implements PCMM { } /* methods invoked from LCMSTransform */ - public static native void colorConvert(long trans, - LCMSImageLayout src, - LCMSImageLayout dest); - - public static native void initLCMS(Class Trans, Class IL, Class Pf); + static native void colorConvert(long trans, int width, int height, + int srcOffset, int srcNextRowOffset, + int dstOffset, int dstNextRowOffset, + boolean srcAtOnce, boolean dstAtOnce, + Object srcData, Object dstData, + int srcType, int dstType); private LCMS() {}; @@ -176,8 +177,6 @@ final class LCMS implements PCMM { } }); - initLCMS(LCMSTransform.class, LCMSImageLayout.class, ICC_Profile.class); - theLcms = new LCMS(); return theLcms; diff --git a/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMSImageLayout.java b/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMSImageLayout.java index 8285e0a3192..fff7f674490 100644 --- a/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMSImageLayout.java +++ b/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMSImageLayout.java @@ -83,7 +83,7 @@ final class LCMSImageLayout { * at once by doTransfrom() native call. Otherwise, the * image is processed scan by scan. */ - private boolean imageAtOnce = false; + boolean imageAtOnce = false; Object dataArray; private int dataArrayLength; /* in bytes */ diff --git a/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java b/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java index 9c27476a8c9..8198932bacd 100644 --- a/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java +++ b/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java @@ -156,7 +156,11 @@ final class LCMSTransform implements ColorTransform { } } } - LCMS.colorConvert(tfm.ID, in, out); + LCMS.colorConvert(tfm.ID, in.width, in.height, in.offset, + in.nextRowOffset, out.offset, out.nextRowOffset, + in.imageAtOnce, out.imageAtOnce, + in.dataArray, out.dataArray, + in.dataType, out.dataType); Reference.reachabilityFence(tfm); // prevent deallocation of "tfm.ID" } diff --git a/src/java.desktop/share/native/liblcms/LCMS.c b/src/java.desktop/share/native/liblcms/LCMS.c index a0a8fe78239..e4aaeb72891 100644 --- a/src/java.desktop/share/native/liblcms/LCMS.c +++ b/src/java.desktop/share/native/liblcms/LCMS.c @@ -70,17 +70,6 @@ typedef union { jint j; } TagSignature_t, *TagSignature_p; -static jfieldID Trans_renderType_fID; -static jfieldID IL_isIntPacked_fID; -static jfieldID IL_dataType_fID; -static jfieldID IL_pixelType_fID; -static jfieldID IL_dataArray_fID; -static jfieldID IL_offset_fID; -static jfieldID IL_nextRowOffset_fID; -static jfieldID IL_width_fID; -static jfieldID IL_height_fID; -static jfieldID IL_imageAtOnce_fID; - JavaVM *javaVM; void errorHandler(cmsContext ContextID, cmsUInt32Number errorCode, @@ -461,44 +450,34 @@ JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_setTagDataNative } } -void* getILData (JNIEnv *env, jobject img, jint* pDataType, - jobject* pDataObject) { - void* result = NULL; - *pDataType = (*env)->GetIntField (env, img, IL_dataType_fID); - *pDataObject = (*env)->GetObjectField(env, img, IL_dataArray_fID); - switch (*pDataType) { +static void *getILData(JNIEnv *env, jobject data, jint type) { + switch (type) { case DT_BYTE: - result = (*env)->GetByteArrayElements (env, *pDataObject, 0); - break; + return (*env)->GetByteArrayElements(env, data, 0); case DT_SHORT: - result = (*env)->GetShortArrayElements (env, *pDataObject, 0); - break; + return (*env)->GetShortArrayElements(env, data, 0); case DT_INT: - result = (*env)->GetIntArrayElements (env, *pDataObject, 0); - break; + return (*env)->GetIntArrayElements(env, data, 0); case DT_DOUBLE: - result = (*env)->GetDoubleArrayElements (env, *pDataObject, 0); - break; + return (*env)->GetDoubleArrayElements(env, data, 0); + default: + return NULL; } - - return result; } -void releaseILData (JNIEnv *env, void* pData, jint dataType, - jobject dataObject) { - switch (dataType) { +static void releaseILData(JNIEnv *env, void *pData, jint type, jobject data) { + switch (type) { case DT_BYTE: - (*env)->ReleaseByteArrayElements(env,dataObject,(jbyte*)pData,0); + (*env)->ReleaseByteArrayElements(env, data, (jbyte *) pData, 0); break; case DT_SHORT: - (*env)->ReleaseShortArrayElements(env,dataObject,(jshort*)pData, 0); + (*env)->ReleaseShortArrayElements(env, data, (jshort *) pData, 0); break; case DT_INT: - (*env)->ReleaseIntArrayElements(env,dataObject,(jint*)pData,0); + (*env)->ReleaseIntArrayElements(env, data, (jint *) pData, 0); break; case DT_DOUBLE: - (*env)->ReleaseDoubleArrayElements(env,dataObject,(jdouble*)pData, - 0); + (*env)->ReleaseDoubleArrayElements(env, data, (jdouble *) pData, 0); break; } } @@ -506,31 +485,15 @@ void releaseILData (JNIEnv *env, void* pData, jint dataType, /* * Class: sun_java2d_cmm_lcms_LCMS * Method: colorConvert - * Signature: (Lsun/java2d/cmm/lcms/LCMSTransform;Lsun/java2d/cmm/lcms/LCMSImageLayout;Lsun/java2d/cmm/lcms/LCMSImageLayout;)V + * Signature: (JIIIIIIZZLjava/lang/Object;Ljava/lang/Object;)V */ JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_colorConvert - (JNIEnv *env, jclass cls, jlong ID, jobject src, jobject dst) + (JNIEnv *env, jclass cls, jlong ID, jint width, jint height, jint srcOffset, + jint srcNextRowOffset, jint dstOffset, jint dstNextRowOffset, + jboolean srcAtOnce, jboolean dstAtOnce, + jobject srcData, jobject dstData, jint srcDType, jint dstDType) { cmsHTRANSFORM sTrans = jlong_to_ptr(ID); - int srcDType, dstDType; - int srcOffset, srcNextRowOffset, dstOffset, dstNextRowOffset; - int width, height, i; - void* inputBuffer; - void* outputBuffer; - char* inputRow; - char* outputRow; - jobject srcData, dstData; - jboolean srcAtOnce = JNI_FALSE, dstAtOnce = JNI_FALSE; - - srcOffset = (*env)->GetIntField (env, src, IL_offset_fID); - srcNextRowOffset = (*env)->GetIntField (env, src, IL_nextRowOffset_fID); - dstOffset = (*env)->GetIntField (env, dst, IL_offset_fID); - dstNextRowOffset = (*env)->GetIntField (env, dst, IL_nextRowOffset_fID); - width = (*env)->GetIntField (env, src, IL_width_fID); - height = (*env)->GetIntField (env, src, IL_height_fID); - - srcAtOnce = (*env)->GetBooleanField(env, src, IL_imageAtOnce_fID); - dstAtOnce = (*env)->GetBooleanField(env, dst, IL_imageAtOnce_fID); if (sTrans == NULL) { J2dRlsTraceLn(J2D_TRACE_ERROR, "LCMS_colorConvert: transform == NULL"); @@ -539,30 +502,27 @@ JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_colorConvert return; } - - inputBuffer = getILData (env, src, &srcDType, &srcData); - + void *inputBuffer = getILData(env, srcData, srcDType); if (inputBuffer == NULL) { J2dRlsTraceLn(J2D_TRACE_ERROR, ""); // An exception should have already been thrown. return; } - outputBuffer = getILData (env, dst, &dstDType, &dstData); - + void *outputBuffer = getILData(env, dstData, dstDType); if (outputBuffer == NULL) { releaseILData(env, inputBuffer, srcDType, srcData); // An exception should have already been thrown. return; } - inputRow = (char*)inputBuffer + srcOffset; - outputRow = (char*)outputBuffer + dstOffset; + char *inputRow = (char *) inputBuffer + srcOffset; + char *outputRow = (char *) outputBuffer + dstOffset; if (srcAtOnce && dstAtOnce) { cmsDoTransform(sTrans, inputRow, outputRow, width * height); } else { - for (i = 0; i < height; i++) { + for (int i = 0; i < height; i++) { cmsDoTransform(sTrans, inputRow, outputRow, width); inputRow += srcNextRowOffset; outputRow += dstNextRowOffset; @@ -607,61 +567,6 @@ JNIEXPORT jobject JNICALL Java_sun_java2d_cmm_lcms_LCMS_getProfileID return NULL; } -/* - * Class: sun_java2d_cmm_lcms_LCMS - * Method: initLCMS - * Signature: (Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Class;)V - */ -JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_initLCMS - (JNIEnv *env, jclass cls, jclass Trans, jclass IL, jclass Pf) -{ - /* TODO: move initialization of the IDs to the static blocks of - * corresponding classes to avoid problems with invalidating ids by class - * unloading - */ - Trans_renderType_fID = (*env)->GetFieldID (env, Trans, "renderType", "I"); - if (Trans_renderType_fID == NULL) { - return; - } - IL_isIntPacked_fID = (*env)->GetFieldID (env, IL, "isIntPacked", "Z"); - if (IL_isIntPacked_fID == NULL) { - return; - } - IL_dataType_fID = (*env)->GetFieldID (env, IL, "dataType", "I"); - if (IL_dataType_fID == NULL) { - return; - } - IL_pixelType_fID = (*env)->GetFieldID (env, IL, "pixelType", "I"); - if (IL_pixelType_fID == NULL) { - return; - } - IL_dataArray_fID = (*env)->GetFieldID(env, IL, "dataArray", - "Ljava/lang/Object;"); - if (IL_dataArray_fID == NULL) { - return; - } - IL_width_fID = (*env)->GetFieldID (env, IL, "width", "I"); - if (IL_width_fID == NULL) { - return; - } - IL_height_fID = (*env)->GetFieldID (env, IL, "height", "I"); - if (IL_height_fID == NULL) { - return; - } - IL_offset_fID = (*env)->GetFieldID (env, IL, "offset", "I"); - if (IL_offset_fID == NULL) { - return; - } - IL_imageAtOnce_fID = (*env)->GetFieldID (env, IL, "imageAtOnce", "Z"); - if (IL_imageAtOnce_fID == NULL) { - return; - } - IL_nextRowOffset_fID = (*env)->GetFieldID (env, IL, "nextRowOffset", "I"); - if (IL_nextRowOffset_fID == NULL) { - return; - } -} - static cmsBool _getHeaderInfo(cmsHPROFILE pf, jbyte* pBuffer, jint bufferSize) { cmsUInt32Number pfSize = 0; -- GitLab From 322b1301061ba113dc5f7f3710dde2d80a18a14e Mon Sep 17 00:00:00 2001 From: Andrey Turbanov Date: Fri, 15 Oct 2021 07:09:11 +0000 Subject: [PATCH 216/385] 8275106: Cleanup Iterator usages in java.desktop Reviewed-by: serb, pbansal --- .../macosx/classes/sun/font/CStrike.java | 8 ++------ .../sun/beans/introspect/EventSetInfo.java | 9 ++------- .../sun/beans/introspect/PropertyInfo.java | 10 ++-------- .../java/awt/DefaultKeyboardFocusManager.java | 10 +++++----- .../BeanContextServicesSupport.java | 20 +++++++++---------- .../javax/imageio/plugins/tiff/TIFFTag.java | 8 +++----- .../standard/PrinterStateReasons.java | 4 +--- .../classes/javax/swing/JDesktopPane.java | 8 +------- .../sun/awt/datatransfer/DataTransferer.java | 4 ++-- .../classes/sun/awt/im/InputContext.java | 8 ++++---- .../sun/java2d/loops/GraphicsPrimitive.java | 6 +----- .../unix/classes/sun/awt/X11/ListHelper.java | 6 ++---- .../unix/classes/sun/awt/X11/XAtomList.java | 11 ++++------ .../sun/awt/X11/XCreateWindowParams.java | 6 +----- .../sun/awt/X11/XDropTargetRegistry.java | 14 ++++--------- .../sun/awt/X11/XEmbeddedFramePeer.java | 8 +++----- .../unix/classes/sun/awt/X11/XMSelection.java | 15 ++++---------- .../unix/classes/sun/awt/X11/XToolkit.java | 8 ++------ 18 files changed, 53 insertions(+), 110 deletions(-) diff --git a/src/java.desktop/macosx/classes/sun/font/CStrike.java b/src/java.desktop/macosx/classes/sun/font/CStrike.java index 31047d2f5f5..088fb01591e 100644 --- a/src/java.desktop/macosx/classes/sun/font/CStrike.java +++ b/src/java.desktop/macosx/classes/sun/font/CStrike.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,8 +29,6 @@ import java.awt.Rectangle; import java.awt.geom.*; import java.util.*; -import sun.awt.SunHints; - public final class CStrike extends PhysicalStrike { // Creates the native strike @@ -444,9 +442,7 @@ public final class CStrike extends PhysicalStrike { // clean up everyone else if (generalCache != null) { - final Iterator i = generalCache.values().iterator(); - while (i.hasNext()) { - final long longValue = i.next().longValue(); + for (long longValue : generalCache.values()) { if (longValue != -1 && longValue != 0) { removeGlyphInfoFromCache(longValue); StrikeCache.freeLongPointer(longValue); diff --git a/src/java.desktop/share/classes/com/sun/beans/introspect/EventSetInfo.java b/src/java.desktop/share/classes/com/sun/beans/introspect/EventSetInfo.java index 23b4f1c3f24..188fcbdef3c 100644 --- a/src/java.desktop/share/classes/com/sun/beans/introspect/EventSetInfo.java +++ b/src/java.desktop/share/classes/com/sun/beans/introspect/EventSetInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -132,12 +132,7 @@ public final class EventSetInfo { } } } - Iterator iterator = map.values().iterator(); - while (iterator.hasNext()) { - if (!iterator.next().initialize()) { - iterator.remove(); - } - } + map.values().removeIf(eventSetInfo -> !eventSetInfo.initialize()); return !map.isEmpty() ? Collections.unmodifiableMap(map) : Collections.emptyMap(); diff --git a/src/java.desktop/share/classes/com/sun/beans/introspect/PropertyInfo.java b/src/java.desktop/share/classes/com/sun/beans/introspect/PropertyInfo.java index 934398ae7bd..833aeb7265c 100644 --- a/src/java.desktop/share/classes/com/sun/beans/introspect/PropertyInfo.java +++ b/src/java.desktop/share/classes/com/sun/beans/introspect/PropertyInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,7 +33,6 @@ import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Collections; import java.util.EnumMap; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.TreeMap; @@ -303,12 +302,7 @@ public final class PropertyInfo { } } } - Iterator iterator = map.values().iterator(); - while (iterator.hasNext()) { - if (!iterator.next().initialize()) { - iterator.remove(); - } - } + map.values().removeIf(propertyInfo -> !propertyInfo.initialize()); return !map.isEmpty() ? Collections.unmodifiableMap(map) : Collections.emptyMap(); diff --git a/src/java.desktop/share/classes/java/awt/DefaultKeyboardFocusManager.java b/src/java.desktop/share/classes/java/awt/DefaultKeyboardFocusManager.java index c95443429e2..00e6a9a4a68 100644 --- a/src/java.desktop/share/classes/java/awt/DefaultKeyboardFocusManager.java +++ b/src/java.desktop/share/classes/java/awt/DefaultKeyboardFocusManager.java @@ -887,11 +887,11 @@ public class DefaultKeyboardFocusManager extends KeyboardFocusManager { boolean stopPostProcessing = false; java.util.List processors = getKeyEventPostProcessors(); if (processors != null) { - for (java.util.Iterator iter = processors.iterator(); - !stopPostProcessing && iter.hasNext(); ) - { - stopPostProcessing = iter.next(). - postProcessKeyEvent(e); + for (KeyEventPostProcessor processor : processors) { + stopPostProcessing = processor.postProcessKeyEvent(e); + if (stopPostProcessing) { + break; + } } } if (!stopPostProcessing) { diff --git a/src/java.desktop/share/classes/java/beans/beancontext/BeanContextServicesSupport.java b/src/java.desktop/share/classes/java/beans/beancontext/BeanContextServicesSupport.java index f5c027b912f..878c489e0f6 100644 --- a/src/java.desktop/share/classes/java/beans/beancontext/BeanContextServicesSupport.java +++ b/src/java.desktop/share/classes/java/beans/beancontext/BeanContextServicesSupport.java @@ -1163,23 +1163,23 @@ public class BeanContextServicesSupport extends BeanContextSupport int count = 0; - Iterator> i = services.entrySet().iterator(); + for (Map.Entry entry : services.entrySet()) { + BCSSServiceProvider bcsp; - while (i.hasNext() && count < serializable) { - Map.Entry entry = i.next(); - BCSSServiceProvider bcsp = null; - - try { + try { bcsp = entry.getValue(); - } catch (ClassCastException cce) { + } catch (ClassCastException cce) { continue; - } + } - if (bcsp.getServiceProvider() instanceof Serializable) { + if (bcsp.getServiceProvider() instanceof Serializable) { oos.writeObject(entry.getKey()); oos.writeObject(bcsp); count++; - } + } + if (count >= serializable) { + break; + } } if (count != serializable) diff --git a/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFTag.java b/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFTag.java index 33f88f9e34c..ced327455c1 100644 --- a/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFTag.java +++ b/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFTag.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,6 @@ */ package javax.imageio.plugins.tiff; -import java.util.Iterator; import java.util.Set; import java.util.SortedMap; import java.util.TreeMap; @@ -401,11 +400,10 @@ public class TIFFTag { int[] intValues = null; if (valueNames != null) { Set values = valueNames.keySet(); - Iterator iter = values.iterator(); intValues = new int[values.size()]; int i = 0; - while (iter.hasNext()) { - intValues[i++] = iter.next(); + for (int value : values) { + intValues[i++] = value; } } return intValues; diff --git a/src/java.desktop/share/classes/javax/print/attribute/standard/PrinterStateReasons.java b/src/java.desktop/share/classes/javax/print/attribute/standard/PrinterStateReasons.java index bd2d0f66fac..ecc4d3c44d7 100644 --- a/src/java.desktop/share/classes/javax/print/attribute/standard/PrinterStateReasons.java +++ b/src/java.desktop/share/classes/javax/print/attribute/standard/PrinterStateReasons.java @@ -242,9 +242,7 @@ public final class PrinterStateReasons public int size() { int result = 0; - Iterator iter = iterator(); - while (iter.hasNext()) { - iter.next(); + for (PrinterStateReason ignored : this) { ++ result; } return result; diff --git a/src/java.desktop/share/classes/javax/swing/JDesktopPane.java b/src/java.desktop/share/classes/javax/swing/JDesktopPane.java index 069a24eaad5..c5ad9399caa 100644 --- a/src/java.desktop/share/classes/javax/swing/JDesktopPane.java +++ b/src/java.desktop/share/classes/javax/swing/JDesktopPane.java @@ -35,7 +35,6 @@ import java.io.ObjectOutputStream; import java.io.Serial; import java.util.ArrayList; import java.util.Collection; -import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; @@ -328,12 +327,7 @@ public class JDesktopPane extends JLayeredPane implements Accessible */ public JInternalFrame[] getAllFramesInLayer(int layer) { Collection allFrames = getAllFrames(this); - Iterator iterator = allFrames.iterator(); - while (iterator.hasNext()) { - if (iterator.next().getLayer() != layer) { - iterator.remove(); - } - } + allFrames.removeIf(frame -> frame.getLayer() != layer); return allFrames.toArray(new JInternalFrame[0]); } diff --git a/src/java.desktop/share/classes/sun/awt/datatransfer/DataTransferer.java b/src/java.desktop/share/classes/sun/awt/datatransfer/DataTransferer.java index b6fbd9e96a5..8ca34787e19 100644 --- a/src/java.desktop/share/classes/sun/awt/datatransfer/DataTransferer.java +++ b/src/java.desktop/share/classes/sun/awt/datatransfer/DataTransferer.java @@ -1957,8 +1957,8 @@ search: Set keySet = map.keySet(); long[] retval = new long[keySet.size()]; int i = 0; - for (Iterator iter = keySet.iterator(); iter.hasNext(); i++) { - retval[i] = iter.next(); + for (long key : keySet) { + retval[i++] = key; } return retval; } diff --git a/src/java.desktop/share/classes/sun/awt/im/InputContext.java b/src/java.desktop/share/classes/sun/awt/im/InputContext.java index bb955dc5089..3ca1f6cedb9 100644 --- a/src/java.desktop/share/classes/sun/awt/im/InputContext.java +++ b/src/java.desktop/share/classes/sun/awt/im/InputContext.java @@ -47,8 +47,8 @@ import java.lang.Character.Subset; import java.security.AccessController; import java.security.PrivilegedAction; import java.text.MessageFormat; +import java.util.Collection; import java.util.HashMap; -import java.util.Iterator; import java.util.Locale; import java.util.prefs.BackingStoreException; import java.util.prefs.Preferences; @@ -695,10 +695,10 @@ public class InputContext extends java.awt.im.InputContext } inputMethodLocator = null; if (usedInputMethods != null && !usedInputMethods.isEmpty()) { - Iterator iterator = usedInputMethods.values().iterator(); + Collection methods = usedInputMethods.values(); usedInputMethods = null; - while (iterator.hasNext()) { - iterator.next().dispose(); + for (InputMethod method : methods) { + method.dispose(); } } diff --git a/src/java.desktop/share/classes/sun/java2d/loops/GraphicsPrimitive.java b/src/java.desktop/share/classes/sun/java2d/loops/GraphicsPrimitive.java index b6e6300070e..fa1f406fb29 100644 --- a/src/java.desktop/share/classes/sun/java2d/loops/GraphicsPrimitive.java +++ b/src/java.desktop/share/classes/sun/java2d/loops/GraphicsPrimitive.java @@ -39,7 +39,6 @@ import java.lang.reflect.Field; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.HashMap; -import java.util.Iterator; import java.util.Map; import java.util.StringTokenizer; @@ -441,12 +440,9 @@ public abstract class GraphicsPrimitive { public void run() { PrintStream ps = getTraceOutputFile(); - Iterator> iterator = - traceMap.entrySet().iterator(); long total = 0; int numprims = 0; - while (iterator.hasNext()) { - Map.Entry me = iterator.next(); + for (Map.Entry me : traceMap.entrySet()) { Object prim = me.getKey(); int[] count = me.getValue(); if (count[0] == 1) { diff --git a/src/java.desktop/unix/classes/sun/awt/X11/ListHelper.java b/src/java.desktop/unix/classes/sun/awt/X11/ListHelper.java index 32d3ae46771..6053fac3ede 100644 --- a/src/java.desktop/unix/classes/sun/awt/X11/ListHelper.java +++ b/src/java.desktop/unix/classes/sun/awt/X11/ListHelper.java @@ -566,10 +566,8 @@ final class ListHelper implements XScrollbarClient { } private boolean isItemSelected(int index) { - Iterator itr = selected.iterator(); - while (itr.hasNext()) { - Integer val = itr.next(); - if (val.intValue() == index) { + for (int val : selected) { + if (val == index) { return true; } } diff --git a/src/java.desktop/unix/classes/sun/awt/X11/XAtomList.java b/src/java.desktop/unix/classes/sun/awt/X11/XAtomList.java index 10253f3946a..20e839702d9 100644 --- a/src/java.desktop/unix/classes/sun/awt/X11/XAtomList.java +++ b/src/java.desktop/unix/classes/sun/awt/X11/XAtomList.java @@ -71,10 +71,9 @@ class XAtomList { */ public XAtom[] getAtoms() { XAtom[] res = new XAtom[size()]; - Iterator iter = atoms.iterator(); int i = 0; - while (iter.hasNext()) { - res[i++] = iter.next(); + for (XAtom atom : atoms) { + res[i++] = atom; } return res; } @@ -124,10 +123,8 @@ class XAtomList { */ public XAtomList subset(int mask, Map mapping) { XAtomList res = new XAtomList(); - Iterator iter = mapping.keySet().iterator(); - while (iter.hasNext()) { - Integer bits = iter.next(); - if ( (mask & bits.intValue()) == bits.intValue() ) { + for (int bits : mapping.keySet()) { + if ((mask & bits) == bits) { XAtom atom = mapping.get(bits); if (contains(atom)) { res.add(atom); diff --git a/src/java.desktop/unix/classes/sun/awt/X11/XCreateWindowParams.java b/src/java.desktop/unix/classes/sun/awt/X11/XCreateWindowParams.java index 5f1ad4fba30..349f86794e3 100644 --- a/src/java.desktop/unix/classes/sun/awt/X11/XCreateWindowParams.java +++ b/src/java.desktop/unix/classes/sun/awt/X11/XCreateWindowParams.java @@ -26,8 +26,6 @@ package sun.awt.X11; import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; @SuppressWarnings("serial") // JDK-implementation class public class XCreateWindowParams extends HashMap { @@ -82,9 +80,7 @@ public class XCreateWindowParams extends HashMap { } public String toString() { StringBuilder buf = new StringBuilder(); - Iterator> eIter = entrySet().iterator(); - while (eIter.hasNext()) { - Map.Entry entry = eIter.next(); + for (Entry entry : entrySet()) { buf.append(entry.getKey()) .append(": ") .append(entry.getValue()) diff --git a/src/java.desktop/unix/classes/sun/awt/X11/XDropTargetRegistry.java b/src/java.desktop/unix/classes/sun/awt/X11/XDropTargetRegistry.java index 1870aace4fb..169014c4ef7 100644 --- a/src/java.desktop/unix/classes/sun/awt/X11/XDropTargetRegistry.java +++ b/src/java.desktop/unix/classes/sun/awt/X11/XDropTargetRegistry.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -141,22 +141,16 @@ final class XDropTargetRegistry { } public long[] getSites() { long[] ret = new long[sites.size()]; - Iterator iter = sites.iterator(); int index = 0; - while (iter.hasNext()) { - Long l = iter.next(); - ret[index++] = l.longValue(); + for (long window : sites) { + ret[index++] = window; } return ret; } public long getSite(int x, int y) { assert XToolkit.isAWTLockHeldByCurrentThread(); - Iterator iter = sites.iterator(); - while (iter.hasNext()) { - Long l = iter.next(); - long window = l.longValue(); - + for (long window : sites) { Point p = XBaseWindow.toOtherWindow(getRoot(), window, x, y); if (p == null) { diff --git a/src/java.desktop/unix/classes/sun/awt/X11/XEmbeddedFramePeer.java b/src/java.desktop/unix/classes/sun/awt/X11/XEmbeddedFramePeer.java index 937c3a36cfc..9da2d408525 100644 --- a/src/java.desktop/unix/classes/sun/awt/X11/XEmbeddedFramePeer.java +++ b/src/java.desktop/unix/classes/sun/awt/X11/XEmbeddedFramePeer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,6 @@ package sun.awt.X11; import java.awt.*; import java.util.LinkedList; -import java.util.Iterator; import sun.util.logging.PlatformLogger; @@ -246,9 +245,8 @@ public class XEmbeddedFramePeer extends XFramePeer { // Register accelerators if (embedder != null && embedder.isActive()) { int i = 0; - Iterator iter = strokes.iterator(); - while (iter.hasNext()) { - embedder.registerAccelerator(iter.next(), i++); + for (AWTKeyStroke stroke : strokes) { + embedder.registerAccelerator(stroke, i++); } } // Now we know that the embedder is an XEmbed server, so we diff --git a/src/java.desktop/unix/classes/sun/awt/X11/XMSelection.java b/src/java.desktop/unix/classes/sun/awt/X11/XMSelection.java index 43a981dd2a4..f63437c76ff 100644 --- a/src/java.desktop/unix/classes/sun/awt/X11/XMSelection.java +++ b/src/java.desktop/unix/classes/sun/awt/X11/XMSelection.java @@ -318,9 +318,7 @@ public class XMSelection { log.fine("Selection Changed : Screen = " + screen + "Event =" + ev); } if (listeners != null) { - Iterator iter = listeners.iterator(); - while (iter.hasNext()) { - XMSelectionListener disp = iter.next(); + for (XMSelectionListener disp : listeners) { disp.selectionChanged(screen, this, ev.get_window(), ev); } } @@ -331,11 +329,8 @@ public class XMSelection { log.fine("Owner dead : Screen = " + screen + "Event =" + de); } if (listeners != null) { - Iterator iter = listeners.iterator(); - while (iter.hasNext()) { - XMSelectionListener disp = iter.next(); + for (XMSelectionListener disp : listeners) { disp.ownerDeath(screen, this, de.get_window()); - } } } @@ -357,10 +352,8 @@ public class XMSelection { synchronized void dispatchOwnerChangedEvent(XEvent ev, int screen, long owner, long data, long timestamp) { if (listeners != null) { - Iterator iter = listeners.iterator(); - while (iter.hasNext()) { - XMSelectionListener disp = iter.next(); - disp.ownerChanged(screen,this, owner, data, timestamp); + for (XMSelectionListener disp : listeners) { + disp.ownerChanged(screen, this, owner, data, timestamp); } } } diff --git a/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java b/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java index c5c7a964e81..196338517a4 100644 --- a/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java +++ b/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java @@ -624,9 +624,7 @@ public final class XToolkit extends UNIXToolkit implements Runnable { } } if (dispatchers != null) { - Iterator iter = dispatchers.iterator(); - while (iter.hasNext()) { - XEventDispatcher disp = iter.next(); + for (XEventDispatcher disp : dispatchers) { disp.dispatchEvent(ev); } } @@ -1661,9 +1659,7 @@ public final class XToolkit extends UNIXToolkit implements Runnable { return; } - Iterator> i = updatedSettings.entrySet().iterator(); - while (i.hasNext()) { - Map.Entry e = i.next(); + for (Map.Entry e : updatedSettings.entrySet()) { String name = e.getKey(); name = "gnome." + name; -- GitLab From 4cb7124c1e9c5fd1d3a82fd8933cc63fefde9531 Mon Sep 17 00:00:00 2001 From: Christian Hagedorn Date: Fri, 15 Oct 2021 07:38:38 +0000 Subject: [PATCH 217/385] 8262912: ciReplay: replay does not simulate unresolved classes Reviewed-by: kvn, dlong --- src/hotspot/share/ci/ciEnv.cpp | 9 +- src/hotspot/share/ci/ciEnv.hpp | 10 ++ src/hotspot/share/ci/ciInstanceKlass.hpp | 1 + src/hotspot/share/ci/ciObjectFactory.cpp | 1 + src/hotspot/share/ci/ciReplay.cpp | 71 +++++++-- src/hotspot/share/ci/ciReplay.hpp | 3 + .../jtreg/compiler/ciReplay/CiReplayBase.java | 14 +- .../ciReplay/TestUnresolvedClasses.java | 147 ++++++++++++++++++ 8 files changed, 241 insertions(+), 15 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/ciReplay/TestUnresolvedClasses.java diff --git a/src/hotspot/share/ci/ciEnv.cpp b/src/hotspot/share/ci/ciEnv.cpp index 443f5a0d1b0..1d58cdb9525 100644 --- a/src/hotspot/share/ci/ciEnv.cpp +++ b/src/hotspot/share/ci/ciEnv.cpp @@ -636,8 +636,15 @@ ciKlass* ciEnv::get_klass_by_index_impl(const constantPoolHandle& cpool, } // It is known to be accessible, since it was found in the constant pool. + ciKlass* ciKlass = get_klass(klass); is_accessible = true; - return get_klass(klass); +#ifndef PRODUCT + if (ReplayCompiles && ciKlass == _unloaded_ciinstance_klass) { + // Klass was unresolved at replay dump time and therefore not accessible. + is_accessible = false; + } +#endif + return ciKlass; } // ------------------------------------------------------------------ diff --git a/src/hotspot/share/ci/ciEnv.hpp b/src/hotspot/share/ci/ciEnv.hpp index c027f15e776..32dc5f51eaf 100644 --- a/src/hotspot/share/ci/ciEnv.hpp +++ b/src/hotspot/share/ci/ciEnv.hpp @@ -27,6 +27,7 @@ #include "ci/ciClassList.hpp" #include "ci/ciObjectFactory.hpp" +#include "ci/ciReplay.hpp" #include "classfile/vmClassMacros.hpp" #include "code/debugInfoRec.hpp" #include "code/dependencies.hpp" @@ -187,6 +188,15 @@ private: if (o == NULL) { return NULL; } else { +#ifndef PRODUCT + if (ReplayCompiles && o->is_klass()) { + Klass* k = (Klass*)o; + if (k->is_instance_klass() && ciReplay::is_klass_unresolved((InstanceKlass*)k)) { + // Klass was unresolved at replay dump time. Simulate this case. + return ciEnv::_unloaded_ciinstance_klass; + } + } +#endif return _factory->get_metadata(o); } } diff --git a/src/hotspot/share/ci/ciInstanceKlass.hpp b/src/hotspot/share/ci/ciInstanceKlass.hpp index 6ea4b4f1a48..d77d9c4c277 100644 --- a/src/hotspot/share/ci/ciInstanceKlass.hpp +++ b/src/hotspot/share/ci/ciInstanceKlass.hpp @@ -43,6 +43,7 @@ class ciInstanceKlass : public ciKlass { friend class ciExceptionHandler; friend class ciMethod; friend class ciField; + friend class ciReplay; private: enum SubklassValue { subklass_unknown, subklass_false, subklass_true }; diff --git a/src/hotspot/share/ci/ciObjectFactory.cpp b/src/hotspot/share/ci/ciObjectFactory.cpp index 979136316e9..0f53c9957ce 100644 --- a/src/hotspot/share/ci/ciObjectFactory.cpp +++ b/src/hotspot/share/ci/ciObjectFactory.cpp @@ -378,6 +378,7 @@ ciMetadata* ciObjectFactory::create_new_metadata(Metadata* o) { if (o->is_klass()) { Klass* k = (Klass*)o; if (k->is_instance_klass()) { + assert(!ReplayCompiles || ciReplay::no_replay_state() || !ciReplay::is_klass_unresolved((InstanceKlass*)k), "must be whitelisted for replay compilation"); return new (arena()) ciInstanceKlass(k); } else if (k->is_objArray_klass()) { return new (arena()) ciObjArrayKlass(k); diff --git a/src/hotspot/share/ci/ciReplay.cpp b/src/hotspot/share/ci/ciReplay.cpp index 96475184b68..a5f69bec4ea 100644 --- a/src/hotspot/share/ci/ciReplay.cpp +++ b/src/hotspot/share/ci/ciReplay.cpp @@ -49,6 +49,7 @@ #include "runtime/fieldDescriptor.inline.hpp" #include "runtime/globals_extension.hpp" #include "runtime/handles.inline.hpp" +#include "runtime/jniHandles.inline.hpp" #include "runtime/java.hpp" #include "utilities/copy.hpp" #include "utilities/macros.hpp" @@ -90,6 +91,11 @@ typedef struct _ciMethodRecord { int _backedge_counter; } ciMethodRecord; +typedef struct _ciInstanceKlassRecord { + const InstanceKlass* _klass; + jobject _java_mirror; // Global handle to java mirror to prevent unloading +} ciInstanceKlassRecord; + typedef struct _ciInlineRecord { const char* _klass_name; const char* _method_name; @@ -111,6 +117,7 @@ class CompileReplay : public StackObj { GrowableArray _ci_method_records; GrowableArray _ci_method_data_records; + GrowableArray _ci_instance_klass_records; // Use pointer because we may need to return inline records // without destroying them. @@ -882,7 +889,7 @@ class CompileReplay : public StackObj { // constant pool is the same length as 'length' and make sure the // constant pool tags are in the same state. void process_ciInstanceKlass(TRAPS) { - InstanceKlass* k = (InstanceKlass *)parse_klass(CHECK); + InstanceKlass* k = (InstanceKlass*)parse_klass(CHECK); if (k == NULL) { return; } @@ -905,6 +912,7 @@ class CompileReplay : public StackObj { } else if (is_linked) { k->link_class(CHECK); } + new_ciInstanceKlass(k); ConstantPool* cp = k->constants(); if (length != cp->length()) { report_error("constant pool length mismatch: wrong class files?"); @@ -951,10 +959,10 @@ class CompileReplay : public StackObj { break; case JVM_CONSTANT_Class: - if (tag == JVM_CONSTANT_Class) { - } else if (tag == JVM_CONSTANT_UnresolvedClass) { - tty->print_cr("Warning: entry was unresolved in the replay data"); - } else { + if (tag == JVM_CONSTANT_UnresolvedClass) { + Klass* k = cp->klass_at(i, CHECK); + tty->print_cr("Warning: entry was unresolved in the replay data: %s", k->name()->as_utf8()); + } else if (tag != JVM_CONSTANT_Class) { report_error("Unexpected tag"); return; } @@ -1132,6 +1140,28 @@ class CompileReplay : public StackObj { return NULL; } + // Create and initialize a record for a ciInstanceKlass which was present at replay dump time. + void new_ciInstanceKlass(const InstanceKlass* klass) { + ciInstanceKlassRecord* rec = NEW_RESOURCE_OBJ(ciInstanceKlassRecord); + rec->_klass = klass; + oop java_mirror = klass->java_mirror(); + Handle h_java_mirror(_thread, java_mirror); + rec->_java_mirror = JNIHandles::make_global(h_java_mirror); + _ci_instance_klass_records.append(rec); + } + + // Check if a ciInstanceKlass was present at replay dump time for a klass. + ciInstanceKlassRecord* find_ciInstanceKlass(const InstanceKlass* klass) { + for (int i = 0; i < _ci_instance_klass_records.length(); i++) { + ciInstanceKlassRecord* rec = _ci_instance_klass_records.at(i); + if (klass == rec->_klass) { + // ciInstanceKlass for this klass was resolved. + return rec; + } + } + return NULL; + } + // Create and initialize a record for a ciMethodData ciMethodDataRecord* new_ciMethodData(Method* method) { ciMethodDataRecord* rec = NEW_RESOURCE_OBJ(ciMethodDataRecord); @@ -1265,6 +1295,10 @@ void ciReplay::replay(TRAPS) { vm_exit(exit_code); } +bool ciReplay::no_replay_state() { + return replay_state == NULL; +} + void* ciReplay::load_inline_data(ciMethod* method, int entry_bci, int comp_level) { if (FLAG_IS_DEFAULT(InlineDataFile)) { tty->print_cr("ERROR: no inline replay data file specified (use -XX:InlineDataFile=inline_pid12345.txt)."); @@ -1336,7 +1370,7 @@ int ciReplay::replay_impl(TRAPS) { } void ciReplay::initialize(ciMethodData* m) { - if (replay_state == NULL) { + if (no_replay_state()) { return; } @@ -1390,7 +1424,7 @@ void ciReplay::initialize(ciMethodData* m) { bool ciReplay::should_not_inline(ciMethod* method) { - if (replay_state == NULL) { + if (no_replay_state()) { return false; } VM_ENTRY_MARK; @@ -1427,7 +1461,7 @@ bool ciReplay::should_not_inline(void* data, ciMethod* method, int bci, int inli } void ciReplay::initialize(ciMethod* m) { - if (replay_state == NULL) { + if (no_replay_state()) { return; } @@ -1456,8 +1490,17 @@ void ciReplay::initialize(ciMethod* m) { } } +void ciReplay::initialize(ciInstanceKlass* ci_ik, InstanceKlass* ik) { + assert(!no_replay_state(), "must have replay state"); + + ASSERT_IN_VM; + ciInstanceKlassRecord* rec = replay_state->find_ciInstanceKlass(ik); + assert(rec != NULL, "ciInstanceKlass must be whitelisted"); + ci_ik->_java_mirror = CURRENT_ENV->get_instance(JNIHandles::resolve(rec->_java_mirror)); +} + bool ciReplay::is_loaded(Method* method) { - if (replay_state == NULL) { + if (no_replay_state()) { return true; } @@ -1467,6 +1510,16 @@ bool ciReplay::is_loaded(Method* method) { ciMethodRecord* rec = replay_state->find_ciMethodRecord(method); return rec != NULL; } + +bool ciReplay::is_klass_unresolved(const InstanceKlass* klass) { + if (no_replay_state()) { + return false; + } + + // Check if klass is found on whitelist. + ciInstanceKlassRecord* rec = replay_state->find_ciInstanceKlass(klass); + return rec == NULL; +} #endif // PRODUCT oop ciReplay::obj_field(oop obj, Symbol* name) { diff --git a/src/hotspot/share/ci/ciReplay.hpp b/src/hotspot/share/ci/ciReplay.hpp index b63a62109f9..e7bd626fea5 100644 --- a/src/hotspot/share/ci/ciReplay.hpp +++ b/src/hotspot/share/ci/ciReplay.hpp @@ -106,6 +106,7 @@ class ciReplay { public: // Replay specified compilation and exit VM. static void replay(TRAPS); + static bool no_replay_state(); // Load inlining decisions from file and use them // during compilation of specified method. static void* load_inline_data(ciMethod* method, int entry_bci, int comp_level); @@ -114,7 +115,9 @@ class ciReplay { // replay file when replaying compiles. static void initialize(ciMethodData* method); static void initialize(ciMethod* method); + static void initialize(ciInstanceKlass* ciKlass, InstanceKlass* ik); + static bool is_klass_unresolved(const InstanceKlass* klass); static bool is_loaded(Method* method); static bool should_not_inline(ciMethod* method); diff --git a/test/hotspot/jtreg/compiler/ciReplay/CiReplayBase.java b/test/hotspot/jtreg/compiler/ciReplay/CiReplayBase.java index ff8aeb39fa1..e401cbdd49c 100644 --- a/test/hotspot/jtreg/compiler/ciReplay/CiReplayBase.java +++ b/test/hotspot/jtreg/compiler/ciReplay/CiReplayBase.java @@ -132,7 +132,7 @@ public abstract class CiReplayBase { public abstract void testAction(); - private static void remove(String item) { + public static void remove(String item) { File toDelete = new File(item); toDelete.delete(); if (Platform.isWindows()) { @@ -164,14 +164,14 @@ public abstract class CiReplayBase { options.add(needCoreDump ? ENABLE_COREDUMP_ON_CRASH : DISABLE_COREDUMP_ON_CRASH); if (needCoreDump) { // CiReplayBase$TestMain needs to be quoted because of shell eval - options.add("-XX:CompileOnly='" + TestMain.class.getName() + "::test'"); - options.add("'" + TestMain.class.getName() + "'"); + options.add("-XX:CompileOnly='" + getTestClass() + "::test'"); + options.add("'" + getTestClass() + "'"); crashOut = ProcessTools.executeProcess( CoreUtils.addCoreUlimitCommand( ProcessTools.createTestJvm(options.toArray(new String[0])))); } else { - options.add("-XX:CompileOnly=" + TestMain.class.getName() + "::test"); - options.add(TestMain.class.getName()); + options.add("-XX:CompileOnly=" + getTestClass() + "::test"); + options.add(getTestClass()); crashOut = ProcessTools.executeProcess(ProcessTools.createTestJvm(options)); } crashOutputString = crashOut.getOutput(); @@ -194,6 +194,10 @@ public abstract class CiReplayBase { return true; } + public String getTestClass() { + return TestMain.class.getName(); + } + public void commonTests() { positiveTest(); if (Platform.isTieredSupported()) { diff --git a/test/hotspot/jtreg/compiler/ciReplay/TestUnresolvedClasses.java b/test/hotspot/jtreg/compiler/ciReplay/TestUnresolvedClasses.java new file mode 100644 index 00000000000..7667f12ecf4 --- /dev/null +++ b/test/hotspot/jtreg/compiler/ciReplay/TestUnresolvedClasses.java @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 8262912 + * @library / /test/lib + * @summary Test class resolution based on whitelist created by ciInstanceKlass entries in replay file. + * @requires vm.flightRecorder != true & vm.compMode != "Xint" & vm.debug == true & vm.compiler2.enabled + * @modules java.base/jdk.internal.misc + * @build sun.hotspot.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * compiler.ciReplay.TestUnresolvedClasses + */ + +package compiler.ciReplay; + +import jdk.test.lib.Asserts; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.util.ArrayList; +import java.util.List; + +public class TestUnresolvedClasses extends CiReplayBase { + private static final String LOG_FILE = "hotspot.log"; + private static final String[] COMMAND_LINE = new String[] {"-XX:LogFile='" + LOG_FILE + "'", "-XX:+LogCompilation", "-XX:+PrintIdeal", + "-XX:CompileCommand=dontinline,compiler.ciReplay.Test::dontInline"}; + public static void main(String[] args) { + new TestUnresolvedClasses().runTest(false, TIERED_DISABLED_VM_OPTION); + } + + @Override + public String getTestClass() { + return Test.class.getName(); + } + + @Override + public void testAction() { + positiveTest(COMMAND_LINE); + // Should find CallStaticJava node for dontInline() as f.bar() is resolved and parsing completes. + checkLogFile(true); + + // Remove ciInstanceKlass entry for Foo in replay file. + try { + Path replayFilePath = Paths.get(REPLAY_FILE_NAME); + List replayContent = Files.readAllLines(replayFilePath); + List newReplayContent = new ArrayList<>(); + boolean foundFoo = false; + for (String line : replayContent) { + if (!line.startsWith("ciInstanceKlass compiler/ciReplay/Foo")) { + newReplayContent.add(line); + } else { + foundFoo = true; + } + } + Asserts.assertTrue(foundFoo, "Did not find ciInstanceKlass compiler/ciReplay/Foo entry"); + Files.write(replayFilePath, newReplayContent, StandardOpenOption.TRUNCATE_EXISTING); + } catch (IOException ioe) { + throw new Error("Failed to read/write replay data: " + ioe, ioe); + } + + positiveTest(COMMAND_LINE); + // No ciInstanceKlass entry for Foo is found in the replay. Replay compilation simulates that Foo is unresolved. + // Therefore, C2 cannot resolve f.bar() at parsing time. It emits an UCT to resolve Foo and stops parsing. + // The call to dontInline() will not be parsed and thus we should not find a CallStaticJava node for it. + checkLogFile(false); + remove(LOG_FILE); + } + + // Parse entry in hotspot.log file and try to find the call for dontInline(). + private void checkLogFile(boolean shouldMatch) { + String toMatch = "Test::dontInline"; + try (var br = Files.newBufferedReader(Paths.get(LOG_FILE))) { + String line; + boolean printIdealLine = false; + while ((line = br.readLine()) != null) { + if (printIdealLine) { + if (line.startsWith(" Date: Fri, 15 Oct 2021 09:51:28 +0000 Subject: [PATCH 218/385] 8271071: accessibility of a table on macOS lacks cell navigation Reviewed-by: ant, kizune, pbansal --- .../classes/sun/lwawt/macosx/CAccessible.java | 14 ++++ .../libawt_lwawt/awt/a11y/CellAccessibility.m | 5 ++ .../awt/a11y/CommonComponentAccessibility.h | 1 + .../awt/a11y/CommonComponentAccessibility.m | 22 ++++++ .../awt/a11y/TableAccessibility.m | 76 +++++++++---------- .../awt/a11y/TableRowAccessibility.m | 5 ++ 6 files changed, 85 insertions(+), 38 deletions(-) diff --git a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessible.java b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessible.java index 3a66e456956..097f662b87c 100644 --- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessible.java +++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessible.java @@ -73,6 +73,7 @@ class CAccessible extends CFRetainedResource implements Accessible { private static native void menuItemSelected(long ptr); private static native void treeNodeExpanded(long ptr); private static native void treeNodeCollapsed(long ptr); + private static native void selectedCellsChanged(long ptr); private Accessible accessible; @@ -126,6 +127,19 @@ class CAccessible extends CFRetainedResource implements Accessible { } else if (name.equals(ACCESSIBLE_ACTIVE_DESCENDANT_PROPERTY)) { if (newValue instanceof AccessibleContext) { activeDescendant = (AccessibleContext)newValue; + if (newValue instanceof Accessible) { + Accessible a = (Accessible)newValue; + AccessibleContext ac = a.getAccessibleContext(); + if (ac != null) { + Accessible p = ac.getAccessibleParent(); + if (p != null) { + AccessibleContext pac = p.getAccessibleContext(); + if ((pac != null) && (pac.getAccessibleRole() == AccessibleRole.TABLE)) { + selectedCellsChanged(ptr); + } + } + } + } } } else if (name.equals(ACCESSIBLE_STATE_PROPERTY)) { AccessibleContext thisAC = accessible.getAccessibleContext(); diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/CellAccessibility.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/CellAccessibility.m index 688d8eb3176..05ac73bc4f2 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/CellAccessibility.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/CellAccessibility.m @@ -53,6 +53,11 @@ } } +- (NSInteger)accessibilityIndex +{ + return self->fIndex; +} + - (NSRect)accessibilityFrame { return [super accessibilityFrame]; diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/CommonComponentAccessibility.h b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/CommonComponentAccessibility.h index 0e946b4a67f..fc81a1e8e09 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/CommonComponentAccessibility.h +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/CommonComponentAccessibility.h @@ -57,6 +57,7 @@ - (void)postTitleChanged; - (void)postTreeNodeExpanded; - (void)postTreeNodeCollapsed; +- (void)postSelectedCellsChanged; - (BOOL)isEqual:(nonnull id)anObject; - (BOOL)isAccessibleWithEnv:(JNIEnv _Nonnull * _Nonnull)env forAccessible:(nonnull jobject)accessible; diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/CommonComponentAccessibility.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/CommonComponentAccessibility.m index c18ef863be7..d5680e3d05a 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/CommonComponentAccessibility.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/CommonComponentAccessibility.m @@ -378,6 +378,12 @@ static jobject sAccessibilityClass = NULL; NSAccessibilityPostNotification([[self accessibilitySelectedRows] firstObject], NSAccessibilityRowCollapsedNotification); } +- (void)postSelectedCellsChanged +{ + AWT_ASSERT_APPKIT_THREAD; + NSAccessibilityPostNotification(self, NSAccessibilitySelectedCellsChangedNotification); +} + - (BOOL)isEqual:(id)anObject { if (![anObject isKindOfClass:[self class]]) return NO; @@ -1231,3 +1237,19 @@ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_treeNodeCollapsed waitUntilDone:NO]; JNI_COCOA_EXIT(env); } + +/* + * Class: sun_lwawt_macosx_CAccessible + * Method: selectedCellsChanged + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_selectedCellsChanged + (JNIEnv *env, jclass jklass, jlong element) +{ + JNI_COCOA_ENTER(env); + [ThreadUtilities performOnMainThread:@selector(postSelectedCellsChanged) + on:(CommonComponentAccessibility *)jlong_to_ptr(element) + withObject:nil + waitUntilDone:NO]; + JNI_COCOA_EXIT(env); +} diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TableAccessibility.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TableAccessibility.m index cd534c1ad3c..b3c73a38c95 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TableAccessibility.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TableAccessibility.m @@ -122,6 +122,26 @@ static jmethodID sjm_getAccessibleName = NULL; return isAccessibleChildSelected; } +- (TableRowAccessibility *)createRowWithIndex:(NSUInteger)index +{ + return [[TableRowAccessibility alloc] initWithParent:self + withEnv:[ThreadUtilities getJNIEnv] + withAccessible:NULL + withIndex:index + withView:[self view] + withJavaRole:JavaAccessibilityIgnore]; +} + +- (ColumnAccessibility *)createColumnWithIndex:(NSUInteger)index +{ + return [[ColumnAccessibility alloc] initWithParent:self + withEnv:[ThreadUtilities getJNIEnv] + withAccessible:NULL + withIndex:index + withView:self->fView + withJavaRole:JavaAccessibilityIgnore]; +} + // NSAccessibilityElement protocol methods - (NSArray *)accessibilityChildren @@ -139,12 +159,7 @@ static jmethodID sjm_getAccessibleName = NULL; int rowCount = [self accessibilityRowCount]; NSMutableArray *children = [NSMutableArray arrayWithCapacity:rowCount]; for (int i = 0; i < rowCount; i++) { - [children addObject:[[TableRowAccessibility alloc] initWithParent:self - withEnv:[ThreadUtilities getJNIEnv] - withAccessible:NULL - withIndex:i - withView:[self view] - withJavaRole:JavaAccessibilityIgnore]]; + [children addObject:[self createRowWithIndex:i]]; } return [NSArray arrayWithArray:children]; } @@ -154,12 +169,7 @@ static jmethodID sjm_getAccessibleName = NULL; NSArray *selectedRowIndexses = [self getTableSelectedInfo:sun_lwawt_macosx_CAccessibility_JAVA_AX_ROWS]; NSMutableArray *children = [NSMutableArray arrayWithCapacity:[selectedRowIndexses count]]; for (NSNumber *index in selectedRowIndexses) { - [children addObject:[[TableRowAccessibility alloc] initWithParent:self - withEnv:[ThreadUtilities getJNIEnv] - withAccessible:NULL - withIndex:index.unsignedIntValue - withView:[self view] - withJavaRole:JavaAccessibilityIgnore]]; + [children addObject:[self createRowWithIndex:index.unsignedIntValue]]; } return [NSArray arrayWithArray:children]; } @@ -184,12 +194,7 @@ static jmethodID sjm_getAccessibleName = NULL; int colCount = [self accessibilityColumnCount]; NSMutableArray *columns = [NSMutableArray arrayWithCapacity:colCount]; for (int i = 0; i < colCount; i++) { - [columns addObject:[[ColumnAccessibility alloc] initWithParent:self - withEnv:[ThreadUtilities getJNIEnv] - withAccessible:NULL - withIndex:i - withView:self->fView - withJavaRole:JavaAccessibilityIgnore]]; + [columns addObject:[self createColumnWithIndex:i]]; } return [NSArray arrayWithArray:columns]; } @@ -199,12 +204,7 @@ static jmethodID sjm_getAccessibleName = NULL; NSArray *indexes = [self getTableSelectedInfo:sun_lwawt_macosx_CAccessibility_JAVA_AX_COLS]; NSMutableArray *columns = [NSMutableArray arrayWithCapacity:[indexes count]]; for (NSNumber *i in indexes) { - [columns addObject:[[ColumnAccessibility alloc] initWithParent:self - withEnv:[ThreadUtilities getJNIEnv] - withAccessible:NULL - withIndex:i.unsignedIntValue - withView:self->fView - withJavaRole:JavaAccessibilityIgnore]]; + [columns addObject:[self createColumnWithIndex:i.unsignedIntValue]]; } return [NSArray arrayWithArray:columns]; } @@ -219,23 +219,23 @@ static jmethodID sjm_getAccessibleName = NULL; return [[self getTableInfo:sun_lwawt_macosx_CAccessibility_JAVA_AX_COLS] integerValue]; } -- (nullable NSArray *)accessibilitySelectedCells +- (id)accessibilityCellForColumn:(NSInteger)column row:(NSInteger)row { - NSArray *children = [super accessibilitySelectedChildren]; - NSMutableArray *cells = [NSMutableArray arrayWithCapacity:[children count]]; - for (CommonComponentAccessibility *child in children) { - [cells addObject:[[CellAccessibility alloc] initWithParent:self - withEnv:[ThreadUtilities getJNIEnv] - withAccessible:child->fAccessible - withIndex:child->fIndex - withView:fView - withJavaRole:child->fJavaRole]]; - } - return [NSArray arrayWithArray:cells]; + return [[[self createRowWithIndex:row] accessibilityChildren] objectAtIndex:column]; } -- (id)accessibilityCellForColumn:(NSInteger)column row:(NSInteger)row { - return [[(TableRowAccessibility *)[[self accessibilityRows] objectAtIndex:row] accessibilityChildren] objectAtIndex:column]; +- (NSArray *)accessibilitySelectedCells +{ + NSArray *selectedRows = [self getTableSelectedInfo:sun_lwawt_macosx_CAccessibility_JAVA_AX_ROWS]; + NSArray *selectedColumns = [self getTableSelectedInfo:sun_lwawt_macosx_CAccessibility_JAVA_AX_COLS]; + NSMutableArray *selectedCells = [NSMutableArray arrayWithCapacity:[selectedRows count] * [selectedColumns count]]; + for (NSNumber *row in selectedRows) { + for (NSNumber *col in selectedColumns) { + CellAccessibility *cell = [self accessibilityCellForColumn:[col integerValue] row:[row integerValue]]; + [selectedCells addObject:cell]; + } + } + return [NSArray arrayWithArray:selectedCells]; } @end diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TableRowAccessibility.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TableRowAccessibility.m index 60985e203f9..4327d05ffad 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TableRowAccessibility.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TableRowAccessibility.m @@ -142,4 +142,9 @@ static jmethodID jm_getChildrenAndRoles = NULL; return NSMakeRect(point.x, point.y, width, height); } +- (BOOL)isAccessibilityOrderedByRow +{ + return YES; +} + @end -- GitLab From ced79091f6ce1791f33c3e5e153eb0535c4d53db Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Fri, 15 Oct 2021 11:15:49 +0000 Subject: [PATCH 219/385] 8275286: Check current thread when calling JRT methods that expect it Reviewed-by: zgu, coleenp, dholmes --- src/hotspot/share/runtime/interfaceSupport.inline.hpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/hotspot/share/runtime/interfaceSupport.inline.hpp b/src/hotspot/share/runtime/interfaceSupport.inline.hpp index 8ba799a4baf..82cd2c180a1 100644 --- a/src/hotspot/share/runtime/interfaceSupport.inline.hpp +++ b/src/hotspot/share/runtime/interfaceSupport.inline.hpp @@ -300,6 +300,7 @@ class VMNativeEntryWrapper { #define JRT_ENTRY(result_type, header) \ result_type header { \ + assert(current == JavaThread::current(), "Must be"); \ MACOS_AARCH64_ONLY(ThreadWXEnable __wx(WXWrite, current)); \ ThreadInVMfromJava __tiv(current); \ VM_ENTRY_BASE(result_type, header, current) \ @@ -327,6 +328,7 @@ class VMNativeEntryWrapper { #define JRT_ENTRY_NO_ASYNC(result_type, header) \ result_type header { \ + assert(current == JavaThread::current(), "Must be"); \ MACOS_AARCH64_ONLY(ThreadWXEnable __wx(WXWrite, current)); \ ThreadInVMfromJava __tiv(current, false /* check asyncs */); \ VM_ENTRY_BASE(result_type, header, current) \ @@ -336,17 +338,20 @@ class VMNativeEntryWrapper { // to get back into Java from the VM #define JRT_BLOCK_ENTRY(result_type, header) \ result_type header { \ + assert(current == JavaThread::current(), "Must be"); \ MACOS_AARCH64_ONLY(ThreadWXEnable __wx(WXWrite, current)); \ HandleMarkCleaner __hm(current); #define JRT_BLOCK \ { \ + assert(current == JavaThread::current(), "Must be"); \ ThreadInVMfromJava __tiv(current); \ JavaThread* THREAD = current; /* For exception macros. */ \ debug_only(VMEntryWrapper __vew;) #define JRT_BLOCK_NO_ASYNC \ { \ + assert(current == JavaThread::current(), "Must be"); \ ThreadInVMfromJava __tiv(current, false /* check asyncs */); \ JavaThread* THREAD = current; /* For exception macros. */ \ debug_only(VMEntryWrapper __vew;) -- GitLab From 172aed1a2d75756b140cb723133ac5fb67f7745e Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Fri, 15 Oct 2021 12:10:27 +0000 Subject: [PATCH 220/385] 8274338: com/sun/jdi/RedefineCrossEvent.java failed "assert(m != __null) failed: NULL mirror" Reviewed-by: dholmes, iklam --- src/hotspot/share/classfile/classLoaderData.cpp | 3 +++ src/hotspot/share/oops/instanceKlass.cpp | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/hotspot/share/classfile/classLoaderData.cpp b/src/hotspot/share/classfile/classLoaderData.cpp index fe702db9192..0f1840cc9a6 100644 --- a/src/hotspot/share/classfile/classLoaderData.cpp +++ b/src/hotspot/share/classfile/classLoaderData.cpp @@ -353,6 +353,9 @@ void ClassLoaderData::methods_do(void f(Method*)) { } void ClassLoaderData::loaded_classes_do(KlassClosure* klass_closure) { + // To call this, one must have the MultiArray_lock held, but the _klasses list still has lock free reads. + assert_locked_or_safepoint(MultiArray_lock); + // Lock-free access requires load_acquire for (Klass* k = Atomic::load_acquire(&_klasses); k != NULL; k = k->next_link()) { // Do not filter ArrayKlass oops here... diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp index dd7fee01a28..31a91588059 100644 --- a/src/hotspot/share/oops/instanceKlass.cpp +++ b/src/hotspot/share/oops/instanceKlass.cpp @@ -2584,6 +2584,9 @@ void InstanceKlass::restore_unshareable_info(ClassLoaderData* loader_data, Handl constants()->restore_unshareable_info(CHECK); if (array_klasses() != NULL) { + // To get a consistent list of classes we need MultiArray_lock to ensure + // array classes aren't observed while they are being restored. + MutexLocker ml(MultiArray_lock); // Array classes have null protection domain. // --> see ArrayKlass::complete_create_array_klass() array_klasses()->restore_unshareable_info(ClassLoaderData::the_null_class_loader_data(), Handle(), CHECK); -- GitLab From 8e02064288a5954ab71b306fc31978a47012ef50 Mon Sep 17 00:00:00 2001 From: Weijun Wang Date: Fri, 15 Oct 2021 13:51:52 +0000 Subject: [PATCH 221/385] 8049520: FileCredentialsCache loads cache once and is never refreshed Reviewed-by: mullan --- .../sun/security/krb5/Credentials.java | 10 +-- .../jdk/sun/security/krb5/ccache/Refresh.java | 65 +++++++++++++++++++ 2 files changed, 67 insertions(+), 8 deletions(-) create mode 100644 test/jdk/sun/security/krb5/ccache/Refresh.java diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/Credentials.java b/src/java.security.jgss/share/classes/sun/security/krb5/Credentials.java index 2ec1952f489..d84ccd2b631 100644 --- a/src/java.security.jgss/share/classes/sun/security/krb5/Credentials.java +++ b/src/java.security.jgss/share/classes/sun/security/krb5/Credentials.java @@ -61,7 +61,6 @@ public class Credentials { HostAddresses cAddr; AuthorizationData authzData; private static boolean DEBUG = Krb5.DEBUG; - private static CredentialsCache cache; static boolean alreadyLoaded = false; private static boolean alreadyTried = false; @@ -416,9 +415,8 @@ public class Credentials { public static synchronized Credentials acquireDefaultCreds() { Credentials result = null; - if (cache == null) { - cache = CredentialsCache.getInstance(); - } + CredentialsCache cache = CredentialsCache.getInstance(); + if (cache != null) { Credentials temp = cache.getInitialCreds(); if (temp != null) { @@ -505,10 +503,6 @@ public class Credentials { service, second, client, ccreds); } - public CredentialsCache getCache() { - return cache; - } - /* * Prints out debug info. */ diff --git a/test/jdk/sun/security/krb5/ccache/Refresh.java b/test/jdk/sun/security/krb5/ccache/Refresh.java new file mode 100644 index 00000000000..c07eaf35222 --- /dev/null +++ b/test/jdk/sun/security/krb5/ccache/Refresh.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 8049520 + * @summary FileCredentialsCache loads cache once and is never refreshed + * @modules java.security.jgss/sun.security.krb5 + * java.security.jgss/sun.security.krb5.internal.ccache:+open + * @library /test/lib + */ +import java.nio.file.Files; +import java.nio.file.Path; + +import jdk.test.lib.Asserts; +import jdk.test.lib.process.Proc; +import sun.security.krb5.Credentials; + +public class Refresh { + public static void main(String[] args) throws Exception { + if (args.length == 0) { + Proc.create("Refresh") + .args("test") + .env("KRB5CCNAME", "tmpcc") + .inheritIO() + .start() + .waitFor(0); + } else { + Path cache = Path.of(System.getenv("KRB5CCNAME")); + byte[] data = TimeInCCache.ccache.clone(); + Files.write(cache, data); + check("dummy@MAXI.LOCAL"); + data[0x2A] = data[0x49] = 'f'; + Files.write(cache, data); + check("fummy@MAXI.LOCAL"); + } + } + + static void check(String expected) throws Exception { + var cred = Credentials.acquireTGTFromCache(null, null); + var pn = cred == null ? null : cred.getClient(); + var name = pn == null ? null : pn.toString(); + Asserts.assertEQ(expected, name); + } +} -- GitLab From da8da3a16148a750ce502f7b7281fe289acaef40 Mon Sep 17 00:00:00 2001 From: Alexander Zvegintsev Date: Fri, 15 Oct 2021 14:03:55 +0000 Subject: [PATCH 222/385] 8269698: Specification for methods of java.awt.im.InputContext should mention that they do nothing Reviewed-by: serb --- .../share/classes/java/awt/im/InputContext.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/java.desktop/share/classes/java/awt/im/InputContext.java b/src/java.desktop/share/classes/java/awt/im/InputContext.java index 27ddd28655b..2a73793df2b 100644 --- a/src/java.desktop/share/classes/java/awt/im/InputContext.java +++ b/src/java.desktop/share/classes/java/awt/im/InputContext.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,7 @@ import java.util.Locale; import java.awt.AWTEvent; import java.beans.Transient; import java.lang.Character.Subset; -import sun.awt.im.InputMethodContext; +import java.util.Objects; /** * Provides methods to control text input facilities such as input @@ -144,6 +144,7 @@ public class InputContext { */ public boolean selectInputMethod(Locale locale) { // real implementation is in sun.awt.im.InputContext + Objects.requireNonNull(locale); return false; } @@ -215,6 +216,7 @@ public class InputContext { */ public void setCompositionEnabled(boolean enable) { // real implementation is in sun.awt.im.InputContext + throw new UnsupportedOperationException(); } /** @@ -234,7 +236,7 @@ public class InputContext { @Transient public boolean isCompositionEnabled() { // real implementation is in sun.awt.im.InputContext - return false; + throw new UnsupportedOperationException(); } /** @@ -258,6 +260,7 @@ public class InputContext { */ public void reconvert() { // real implementation is in sun.awt.im.InputContext + throw new UnsupportedOperationException(); } /** @@ -269,6 +272,7 @@ public class InputContext { */ public void dispatchEvent(AWTEvent event) { // real implementation is in sun.awt.im.InputContext + Objects.requireNonNull(event); } /** @@ -286,6 +290,7 @@ public class InputContext { */ public void removeNotify(Component client) { // real implementation is in sun.awt.im.InputContext + Objects.requireNonNull(client); } /** -- GitLab From 8c4da9c15fec7bd27e243e9a6c9ebcad63109506 Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Fri, 15 Oct 2021 16:17:29 +0000 Subject: [PATCH 223/385] 8275013: Improve discussion of serialization method declarations in java.io.Object{Input, Output}Stream Reviewed-by: smarks, rriggs --- .../share/classes/java/io/ObjectInputStream.java | 10 ++++++++-- .../share/classes/java/io/ObjectOutputStream.java | 13 ++++++++++--- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/java.base/share/classes/java/io/ObjectInputStream.java b/src/java.base/share/classes/java/io/ObjectInputStream.java index 315df036949..d58bf1d91c9 100644 --- a/src/java.base/share/classes/java/io/ObjectInputStream.java +++ b/src/java.base/share/classes/java/io/ObjectInputStream.java @@ -145,8 +145,8 @@ import sun.security.action.GetIntegerAction; * entire graphs. * *

      Serializable classes that require special handling during the - * serialization and deserialization process should implement the following - * methods: + * serialization and deserialization process should implement methods + * with the following signatures: * *

        * private void writeObject(java.io.ObjectOutputStream stream)
      @@ -157,6 +157,12 @@ import sun.security.action.GetIntegerAction;
        *     throws ObjectStreamException;
        * 
      * + *

      The method name, modifiers, return type, and number and type of + * parameters must match exactly for the method to be used by + * serialization or deserialization. The methods should only be + * declared to throw checked exceptions consistent with these + * signatures. + * *

      The readObject method is responsible for reading and restoring the state * of the object for its particular class using data written to the stream by * the corresponding writeObject method. The method does not need to concern diff --git a/src/java.base/share/classes/java/io/ObjectOutputStream.java b/src/java.base/share/classes/java/io/ObjectOutputStream.java index a64186c7ed7..8d34fcec483 100644 --- a/src/java.base/share/classes/java/io/ObjectOutputStream.java +++ b/src/java.base/share/classes/java/io/ObjectOutputStream.java @@ -83,9 +83,10 @@ import sun.reflect.misc.ReflectUtil; * oos.close(); *

      * - *

      Classes that require special handling during the serialization and - * deserialization process must implement special methods with these exact - * signatures: + *

      Serializable classes that require special handling during the + * serialization and deserialization process should implement methods + * with the following signatures: + * *
      *

        * private void readObject(java.io.ObjectInputStream stream)
      @@ -96,6 +97,12 @@ import sun.reflect.misc.ReflectUtil;
        *     throws ObjectStreamException;
        * 
      * + *

      The method name, modifiers, return type, and number and type of + * parameters must match exactly for the method to be used by + * serialization or deserialization. The methods should only be + * declared to throw checked exceptions consistent with these + * signatures. + * *

      The writeObject method is responsible for writing the state of the object * for its particular class so that the corresponding readObject method can * restore it. The method does not need to concern itself with the state -- GitLab From ee64ce9f14c36c38fc4fadf8e5f350daa46e3a78 Mon Sep 17 00:00:00 2001 From: Calvin Cheung Date: Fri, 15 Oct 2021 16:53:00 +0000 Subject: [PATCH 224/385] 8274937: Revert the timeout setting for DynamicLoaderConstraintsTest Reviewed-by: dcubed, minqi --- .../loaderConstraints/DynamicLoaderConstraintsTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/hotspot/jtreg/runtime/cds/appcds/loaderConstraints/DynamicLoaderConstraintsTest.java b/test/hotspot/jtreg/runtime/cds/appcds/loaderConstraints/DynamicLoaderConstraintsTest.java index e7e7197c43e..9d194c288a3 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/loaderConstraints/DynamicLoaderConstraintsTest.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/loaderConstraints/DynamicLoaderConstraintsTest.java @@ -33,7 +33,7 @@ * jdk.httpserver * @build sun.hotspot.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox - * @run main/othervm/timeout=180 -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. DynamicLoaderConstraintsTest + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. DynamicLoaderConstraintsTest */ /** @@ -49,7 +49,7 @@ * jdk.httpserver * @build sun.hotspot.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox - * @run main/othervm/timeout=180 -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. DynamicLoaderConstraintsTest custom + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. DynamicLoaderConstraintsTest custom */ /** @@ -66,7 +66,7 @@ * jdk.httpserver * @build sun.hotspot.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox - * @run main/othervm/timeout=180 -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. DynamicLoaderConstraintsTest custom-zgc + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. DynamicLoaderConstraintsTest custom-zgc */ import com.sun.net.httpserver.HttpExchange; -- GitLab From f17818516cf80e6e208309200c98b23919c3cddb Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Fri, 15 Oct 2021 17:24:30 +0000 Subject: [PATCH 225/385] 8275249: Suppress warnings on non-serializable array component types in jdk.jlink Reviewed-by: iris --- .../share/classes/jdk/tools/jlink/internal/TaskHelper.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java index e3d53273cba..55c5e9d5dad 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -81,6 +81,7 @@ public final class TaskHelper { return this; } public final String key; + @SuppressWarnings("serial") // Array component type is not Serializable public final Object[] args; public boolean showUsage; } -- GitLab From ad9e234f5ed61635f926618a40f453fe7b6b491f Mon Sep 17 00:00:00 2001 From: Naoto Sato Date: Fri, 15 Oct 2021 20:36:30 +0000 Subject: [PATCH 226/385] 8275145: file.encoding system property has an incorrect value on Windows Reviewed-by: mchung, iris, rriggs, alanb --- src/java.base/share/native/libjava/System.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/java.base/share/native/libjava/System.c b/src/java.base/share/native/libjava/System.c index d2c20ff17fc..b4a6e325feb 100644 --- a/src/java.base/share/native/libjava/System.c +++ b/src/java.base/share/native/libjava/System.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -146,7 +146,15 @@ Java_jdk_internal_util_SystemProps_00024Raw_platformProperties(JNIEnv *env, jcla PUTPROP(propArray, _path_separator_NDX, sprops->path_separator); PUTPROP(propArray, _line_separator_NDX, sprops->line_separator); +#ifdef MACOSX + /* + * Since sun_jnu_encoding is now hard-coded to UTF-8 on Mac, we don't + * want to use it to overwrite file.encoding + */ PUTPROP(propArray, _file_encoding_NDX, sprops->encoding); +#else + PUTPROP(propArray, _file_encoding_NDX, sprops->sun_jnu_encoding); +#endif PUTPROP(propArray, _sun_jnu_encoding_NDX, sprops->sun_jnu_encoding); /* -- GitLab From 831802ddb103f8f9747a9fb139af8365924da801 Mon Sep 17 00:00:00 2001 From: Lance Andersen Date: Fri, 15 Oct 2021 20:38:43 +0000 Subject: [PATCH 227/385] 8275163: Deflater::deflate methods omit javadoc for ReadOnlyBufferException Reviewed-by: bpb, iris, naoto --- src/java.base/share/classes/java/util/zip/Deflater.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/java.base/share/classes/java/util/zip/Deflater.java b/src/java.base/share/classes/java/util/zip/Deflater.java index 7bbb0539d5e..d41b8a7e126 100644 --- a/src/java.base/share/classes/java/util/zip/Deflater.java +++ b/src/java.base/share/classes/java/util/zip/Deflater.java @@ -495,6 +495,7 @@ public class Deflater { * @param output the buffer for the compressed data * @return the actual number of bytes of compressed data written to the * output buffer + * @throws ReadOnlyBufferException if the given output buffer is read-only * @since 11 */ public int deflate(ByteBuffer output) { @@ -674,6 +675,7 @@ public class Deflater { * the output buffer * * @throws IllegalArgumentException if the flush mode is invalid + * @throws ReadOnlyBufferException if the given output buffer is read-only * @since 11 */ public int deflate(ByteBuffer output, int flush) { -- GitLab From 7fc3a8d052bfb8d31fedec56f72b10a40ba7bf83 Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Fri, 15 Oct 2021 22:58:21 +0000 Subject: [PATCH 228/385] 8275149: (ch) ReadableByteChannel returned by Channels.newChannel(InputStream) throws ReadOnlyBufferException Reviewed-by: alanb --- .../share/classes/java/nio/channels/Channels.java | 3 +++ test/jdk/java/nio/channels/Channels/Basic.java | 11 +++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) 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 900b4336e25..2d1637c5369 100644 --- a/src/java.base/share/classes/java/nio/channels/Channels.java +++ b/src/java.base/share/classes/java/nio/channels/Channels.java @@ -295,6 +295,9 @@ public final class Channels { if (!isOpen()) { throw new ClosedChannelException(); } + if (dst.isReadOnly()) { + throw new IllegalArgumentException(); + } int len = dst.remaining(); int totalRead = 0; diff --git a/test/jdk/java/nio/channels/Channels/Basic.java b/test/jdk/java/nio/channels/Channels/Basic.java index bfbbbe73723..b0d83565d48 100644 --- a/test/jdk/java/nio/channels/Channels/Basic.java +++ b/test/jdk/java/nio/channels/Channels/Basic.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. * 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,7 +22,7 @@ */ /* @test - * @bug 4417152 4481572 6248930 6725399 6884800 8220477 + * @bug 4417152 4481572 6248930 6725399 6884800 8220477 8275149 * @summary Test Channels basic functionality */ @@ -296,6 +296,13 @@ public class Basic { byte data[] = new byte[messageSize+1]; ByteBuffer bb = ByteBuffer.wrap(data); + try { + rbc.read(bb.asReadOnlyBuffer()); + throw new RuntimeException("IllegalArgumentException not thrown"); + } catch (IllegalArgumentException expected) { + // ignore it + } + int bytesRead = 0; int totalRead = 0; while (bytesRead != -1) { -- GitLab From 96fef40b8206c7027c6688bc0cb0bd979bea4b4b Mon Sep 17 00:00:00 2001 From: Jonathan Gibbons Date: Sat, 16 Oct 2021 03:04:11 +0000 Subject: [PATCH 229/385] 8189591: No way to locally suppress doclint warnings Reviewed-by: hannesw, prappo --- .../jdk/javadoc/internal/doclint/Env.java | 109 +++++++++++++- .../javadoc/internal/doclint/Messages.java | 16 +- .../javadoc/doclet/testJavaFX/TestJavaFX.java | 2 +- .../tools/doclint/SuppressWarningsTest.java | 140 ++++++++++++++++++ 4 files changed, 257 insertions(+), 10 deletions(-) create mode 100644 test/langtools/tools/doclint/SuppressWarningsTest.java diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Env.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Env.java index a822f4f157e..01a0a867673 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Env.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Env.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. * 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,21 +26,31 @@ package jdk.javadoc.internal.doclint; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; +import java.util.EnumSet; +import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; +import java.util.Map; import java.util.Set; +import java.util.function.Function; import java.util.regex.Pattern; +import java.util.stream.Collectors; +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.AnnotationValue; import javax.lang.model.element.Element; import javax.lang.model.element.ElementKind; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.Modifier; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; import javax.lang.model.util.Elements; import javax.lang.model.util.Types; -import javax.tools.Diagnostic.Kind; import com.sun.source.doctree.DocCommentTree; import com.sun.source.tree.CompilationUnitTree; @@ -106,6 +116,7 @@ public class Env { // Types used when analysing doc comments. TypeMirror java_lang_Error; TypeMirror java_lang_RuntimeException; + TypeMirror java_lang_SuppressWarnings; TypeMirror java_lang_Throwable; TypeMirror java_lang_Void; @@ -125,6 +136,9 @@ public class Env { /** The set of methods, if any, that the current declaration overrides. */ Set currOverriddenMethods; + /** A map containing the info derived from {@code @SuppressWarnings} for an element. */ + Map> suppressWarnings = new HashMap<>(); + Env() { messages = new Messages(this); } @@ -145,6 +159,7 @@ public class Env { java_lang_Error = elements.getTypeElement("java.lang.Error").asType(); java_lang_RuntimeException = elements.getTypeElement("java.lang.RuntimeException").asType(); + java_lang_SuppressWarnings = elements.getTypeElement("java.lang.SuppressWarnings").asType(); java_lang_Throwable = elements.getTypeElement("java.lang.Throwable").asType(); java_lang_Void = elements.getTypeElement("java.lang.Void").asType(); } @@ -247,6 +262,96 @@ public class Env { return true; } + /** + * {@return whether or not warnings in a group are suppressed for the current element} + * @param g the group + */ + boolean suppressWarnings(Messages.Group g) { + return suppressWarnings(currElement, g); + } + + /** + * {@return whether or not warnings in a group are suppressed for a given element} + * @param e the element + * @param g the group + */ + boolean suppressWarnings(Element e, Messages.Group g) { + // check if warnings are suppressed in any enclosing classes + Element encl = e.getEnclosingElement(); + if (encl != null && encl.asType().getKind() == TypeKind.DECLARED) { + if (suppressWarnings(encl, g)) { + return true; + } + } + + // check the local @SuppressWarnings annotation, caching the results + return suppressWarnings.computeIfAbsent(e, this::getSuppressedGroups).contains(g); + } + + /** + * Returns the set of groups for an element for which messages should be suppressed. + * The set is determined by examining the arguments for any {@code @SuppressWarnings} + * annotation that may be present on the element. + * The supported strings are: "doclint" and "doclint:GROUP,..." for each GROUP + * + * @param e the element + * @return the set + */ + private Set getSuppressedGroups(Element e) { + var gMap = Arrays.stream(Messages.Group.values()) + .collect(Collectors.toMap(Messages.Group::optName, Function.identity())); + var set = EnumSet.noneOf(Messages.Group.class); + for (String arg : getSuppressWarningsValue(e)) { + if (arg.equals("doclint")) { + set = EnumSet.allOf(Messages.Group.class); + break; + } else if (arg.startsWith("doclint:")) { + final int len = "doclint:".length(); + for (String a : arg.substring(len).split(",")) { + Messages.Group argGroup = gMap.get(a); + if (argGroup != null) { + set.add(argGroup); + } + } + } + } + return set; + } + + /** + * Returns the list of values given to an instance of {@code @SuppressWarnings} for an element, + * or an empty list if there is no annotation. + * + * @param e the element + * @return the list + */ + private List getSuppressWarningsValue(Element e) { + for (AnnotationMirror am : e.getAnnotationMirrors()) { + DeclaredType dt = am.getAnnotationType(); + if (types.isSameType(dt, java_lang_SuppressWarnings)) { + var values = am.getElementValues(); + for (var entry : values.entrySet()) { + if (entry.getKey().getSimpleName().contentEquals("value")) { + AnnotationValue av = entry.getValue(); + if (av.getValue() instanceof List list) { + List result = new ArrayList<>(); + for (var item : list) { + if (item instanceof AnnotationValue avItem + && avItem.getValue() instanceof String s) { + result.add(s); + } + } + return result; + } + } + } + + } + } + return Collections.emptyList(); + } + + private > T min(T item1, T item2) { return (item1 == null) ? item2 : (item2 == null) ? item1 diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Messages.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Messages.java index a588233df28..c77d09c9512 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Messages.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Messages.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -115,6 +115,9 @@ public class Messages { protected void report(Group group, Diagnostic.Kind dkind, DocTree tree, String code, Object... args) { if (options.isEnabled(group, env.currAccess)) { + if (dkind == Diagnostic.Kind.WARNING && env.suppressWarnings(group)) { + return; + } String msg = (code == null) ? (String) args[0] : localize(code, args); env.trees.printMessage(dkind, msg, tree, env.currDocComment, env.currPath.getCompilationUnit()); @@ -125,6 +128,9 @@ public class Messages { protected void report(Group group, Diagnostic.Kind dkind, Tree tree, String code, Object... args) { if (options.isEnabled(group, env.currAccess)) { + if (dkind == Diagnostic.Kind.WARNING && env.suppressWarnings(group)) { + return; + } String msg = localize(code, args); env.trees.printMessage(dkind, msg, tree, env.currPath.getCompilationUnit()); @@ -315,18 +321,14 @@ public class Messages { */ private static class Table { - private static final Comparator DECREASING = (o1, o2) -> o2.compareTo(o1); + private static final Comparator DECREASING = Comparator.reverseOrder(); private final TreeMap> map = new TreeMap<>(DECREASING); void put(String label, int n) { if (n == 0) { return; } - Set labels = map.get(n); - if (labels == null) { - map.put(n, labels = new TreeSet<>()); - } - labels.add(label); + map.computeIfAbsent(n, k -> new TreeSet<>()).add(label); } void print(PrintWriter out) { diff --git a/test/langtools/jdk/javadoc/doclet/testJavaFX/TestJavaFX.java b/test/langtools/jdk/javadoc/doclet/testJavaFX/TestJavaFX.java index c2ffaef2663..443f4749333 100644 --- a/test/langtools/jdk/javadoc/doclet/testJavaFX/TestJavaFX.java +++ b/test/langtools/jdk/javadoc/doclet/testJavaFX/TestJavaFX.java @@ -456,7 +456,7 @@ public class TestJavaFX extends JavadocTester { checkExit(Exit.OK); checkOutput(Output.OUT, false, - "warning", + ": warning:", "no comment"); } } diff --git a/test/langtools/tools/doclint/SuppressWarningsTest.java b/test/langtools/tools/doclint/SuppressWarningsTest.java new file mode 100644 index 00000000000..519a769e4f3 --- /dev/null +++ b/test/langtools/tools/doclint/SuppressWarningsTest.java @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 8189591 + * @summary No way to locally suppress doclint warnings + * @library /tools/lib + * @modules jdk.javadoc/jdk.javadoc.internal.doclint + * @build toolbox.ToolBox SuppressWarningsTest + * @run main SuppressWarningsTest + */ + +import java.io.PrintStream; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; + +import jdk.javadoc.internal.doclint.DocLint; +import toolbox.ToolBox; + +public class SuppressWarningsTest { + public static void main(String... args) throws Exception { + new SuppressWarningsTest().run(); + } + + enum Kind { + NONE("// no annotation"), + MISSING("@SuppressWarnings(\"doclint:missing\")"), + OTHER("@SuppressWarnings(\"doclint:html\")"), + ALL("@SuppressWarnings(\"doclint\")"); + final String anno; + Kind(String anno) { + this.anno = anno; + } + } + + ToolBox tb = new ToolBox(); + PrintStream log = System.err; + + void run() throws Exception { + for (Kind ok : Kind.values()) { + for (Kind ik : Kind.values()) { + for (Kind mk : Kind.values()) { + test(ok, ik, mk); + } + } + } + + if (errorCount == 0) { + log.println("No errors"); + } else { + log.println(errorCount + " errors"); + throw new Exception(errorCount + " errors"); + } + } + + void test(Kind outerKind, Kind innerKind, Kind memberKind) throws Exception { + log.println("Test: outer:" + outerKind + " inner: " + innerKind + " member:" + memberKind); + Path base = Path.of(outerKind + "-" + innerKind + "-" + memberKind); + Files.createDirectories(base); + Path src = base.resolve("src"); + tb.writeJavaFiles(src, """ + /** . */ + ##OUTER## + public class Outer { + /** . */ + private Outer() { } + /** . */ + ##INNER## + public class Inner { + /** . */ + private Inner() { } + ##MEMBER## + public void m() { } + } + } + """ + .replace("##OUTER##", outerKind.anno) + .replace("##INNER##", innerKind.anno) + .replace("##MEMBER##", memberKind.anno)); + + DocLint dl = new DocLint(); + StringWriter sw = new StringWriter(); + try (PrintWriter pw = new PrintWriter(sw)) { + dl.run(pw, src.resolve("Outer.java").toString()); + } + String out = sw.toString(); + out.lines().forEach(System.err::println); + + boolean expectSuppressed = false; + for (Kind k : List.of(outerKind, innerKind, memberKind)) { + expectSuppressed |= k == Kind.ALL || k == Kind.MISSING; + } + boolean foundWarning = out.contains("warning: no comment"); + if (expectSuppressed) { + if (foundWarning) { + error("found unexpected warning"); + } else { + log.println("Passed: no warning, as expected"); + } + } else { + if (foundWarning) { + log.println("Passed: found warning, as expected"); + } else { + error("no warning"); + } + } + log.println(); + } + + int errorCount; + + void error(String message) { + log.println("Error: " + message); + errorCount++; + } +} -- GitLab From bfcf6a29a16bc12d77a897fbec304868957c3188 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Sat, 16 Oct 2021 11:05:48 +0000 Subject: [PATCH 230/385] 8275277: assert(dest_attr.is_in_cset() == (obj->forwardee() == obj)) failed: Only evac-failed objects must be in the collection set here but is not Reviewed-by: ayang, rkennke --- src/hotspot/share/gc/g1/g1ParScanThreadState.inline.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/gc/g1/g1ParScanThreadState.inline.hpp b/src/hotspot/share/gc/g1/g1ParScanThreadState.inline.hpp index a3634737103..b2c1efa3c1f 100644 --- a/src/hotspot/share/gc/g1/g1ParScanThreadState.inline.hpp +++ b/src/hotspot/share/gc/g1/g1ParScanThreadState.inline.hpp @@ -111,7 +111,7 @@ template void G1ParScanThreadState::write_ref_field_post(T* p, oop obj // References to the current collection set are references to objects that failed // evacuation. Currently these regions are always relabelled as old without // remembered sets, so skip them. - assert(dest_attr.is_in_cset() == (obj->forwardee() == obj), + assert(dest_attr.is_in_cset() == (obj->is_forwarded() && obj->forwardee() == obj), "Only evac-failed objects must be in the collection set here but " PTR_FORMAT " is not", p2i(obj)); if (dest_attr.is_in_cset()) { return; -- GitLab From 31500692d1503cb73249e0425e6930aaaa49258a Mon Sep 17 00:00:00 2001 From: Yasumasa Suenaga Date: Sun, 17 Oct 2021 08:59:13 +0000 Subject: [PATCH 231/385] 8271949: dumppath in -XX:FlightRecorderOptions does not affect Reviewed-by: ddong, mgronlun --- src/hotspot/share/jfr/jni/jfrJniMethod.cpp | 13 ++++- src/hotspot/share/jfr/jni/jfrJniMethod.hpp | 6 +- .../jfr/jni/jfrJniMethodRegistration.cpp | 2 + .../recorder/repository/jfrEmergencyDump.cpp | 45 ++++++++++++--- .../recorder/repository/jfrEmergencyDump.hpp | 9 ++- .../jfr/recorder/service/jfrOptionSet.cpp | 21 +++++++ .../share/classes/jdk/jfr/internal/JVM.java | 17 +++++- .../classes/jdk/jfr/internal/Options.java | 28 +++++++-- .../jdk/jfr/internal/SecuritySupport.java | 1 - test/jdk/jdk/jfr/jvm/TestDumpOnCrash.java | 57 ++++++++++++++----- 10 files changed, 167 insertions(+), 32 deletions(-) diff --git a/src/hotspot/share/jfr/jni/jfrJniMethod.cpp b/src/hotspot/share/jfr/jni/jfrJniMethod.cpp index 54a4680ced8..f02469ab2c0 100644 --- a/src/hotspot/share/jfr/jni/jfrJniMethod.cpp +++ b/src/hotspot/share/jfr/jni/jfrJniMethod.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,6 +35,7 @@ #include "jfr/recorder/repository/jfrRepository.hpp" #include "jfr/recorder/repository/jfrChunkRotation.hpp" #include "jfr/recorder/repository/jfrChunkWriter.hpp" +#include "jfr/recorder/repository/jfrEmergencyDump.hpp" #include "jfr/recorder/service/jfrEventThrottler.hpp" #include "jfr/recorder/service/jfrOptionSet.hpp" #include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp" @@ -315,6 +316,16 @@ JVM_ENTRY_NO_ENV(void, jfr_set_repository_location(JNIEnv* env, jobject repo, js return JfrRepository::set_path(location, thread); JVM_END +NO_TRANSITION(void, jfr_set_dump_path(JNIEnv* env, jobject jvm, jstring dumppath)) + const char* dump_path = env->GetStringUTFChars(dumppath, NULL); + JfrEmergencyDump::set_dump_path(dump_path); + env->ReleaseStringUTFChars(dumppath, dump_path); +NO_TRANSITION_END + +NO_TRANSITION(jstring, jfr_get_dump_path(JNIEnv* env, jobject jvm)) + return env->NewStringUTF(JfrEmergencyDump::get_dump_path()); +NO_TRANSITION_END + JVM_ENTRY_NO_ENV(void, jfr_uncaught_exception(JNIEnv* env, jobject jvm, jobject t, jthrowable throwable)) JfrJavaSupport::uncaught_exception(throwable, thread); JVM_END diff --git a/src/hotspot/share/jfr/jni/jfrJniMethod.hpp b/src/hotspot/share/jfr/jni/jfrJniMethod.hpp index 19a676c4a22..946ef04470d 100644 --- a/src/hotspot/share/jfr/jni/jfrJniMethod.hpp +++ b/src/hotspot/share/jfr/jni/jfrJniMethod.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. * 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,10 @@ jlong JNICALL jfr_type_id(JNIEnv* env, jobject jvm, jclass jc); void JNICALL jfr_set_repository_location(JNIEnv* env, jobject repo, jstring location); +void JNICALL jfr_set_dump_path(JNIEnv* env, jobject jvm, jstring dumppath); + +jstring JNICALL jfr_get_dump_path(JNIEnv* env, jobject jvm); + jobject JNICALL jfr_get_event_writer(JNIEnv* env, jclass cls); jobject JNICALL jfr_new_event_writer(JNIEnv* env, jclass cls); diff --git a/src/hotspot/share/jfr/jni/jfrJniMethodRegistration.cpp b/src/hotspot/share/jfr/jni/jfrJniMethodRegistration.cpp index db137776f65..5bc8a95a826 100644 --- a/src/hotspot/share/jfr/jni/jfrJniMethodRegistration.cpp +++ b/src/hotspot/share/jfr/jni/jfrJniMethodRegistration.cpp @@ -75,6 +75,8 @@ JfrJniMethodRegistration::JfrJniMethodRegistration(JNIEnv* env) { (char*)"flush", (char*)"(Ljdk/jfr/internal/EventWriter;II)Z", (void*)jfr_event_writer_flush, (char*)"flush", (char*)"()V", (void*)jfr_flush, (char*)"setRepositoryLocation", (char*)"(Ljava/lang/String;)V", (void*)jfr_set_repository_location, + (char*)"setDumpPath", (char*)"(Ljava/lang/String;)V", (void*)jfr_set_dump_path, + (char*)"getDumpPath", (char*)"()Ljava/lang/String;", (void*)jfr_get_dump_path, (char*)"abort", (char*)"(Ljava/lang/String;)V", (void*)jfr_abort, (char*)"addStringConstant", (char*)"(JLjava/lang/String;)Z", (void*)jfr_add_string_constant, (char*)"uncaughtException", (char*)"(Ljava/lang/Thread;Ljava/lang/Throwable;)V", (void*)jfr_uncaught_exception, diff --git a/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp b/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp index 0bcfc8568f5..c00bed02b52 100644 --- a/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp +++ b/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp @@ -41,6 +41,8 @@ #include "utilities/growableArray.hpp" #include "utilities/ostream.hpp" +char JfrEmergencyDump::_dump_path[JVM_MAXPATHLEN] = { 0 }; + static const char vm_error_filename_fmt[] = "hs_err_pid%p.jfr"; static const char vm_oom_filename_fmt[] = "hs_oom_pid%p.jfr"; static const char vm_soe_filename_fmt[] = "hs_soe_pid%p.jfr"; @@ -66,12 +68,17 @@ static bool is_path_empty() { } // returns with an appended file separator (if successful) -static size_t get_current_directory() { - if (os::get_current_directory(_path_buffer, sizeof(_path_buffer)) == NULL) { - return 0; +static size_t get_dump_directory() { + const char* dump_path = JfrEmergencyDump::get_dump_path(); + if (*dump_path == '\0') { + if (os::get_current_directory(_path_buffer, sizeof(_path_buffer)) == NULL) { + return 0; + } + } else { + strcpy(_path_buffer, dump_path); } - const size_t cwd_len = strlen(_path_buffer); - const int result = jio_snprintf(_path_buffer + cwd_len, + const size_t path_len = strlen(_path_buffer); + const int result = jio_snprintf(_path_buffer + path_len, sizeof(_path_buffer), "%s", os::file_separator()); @@ -105,7 +112,7 @@ static void close_emergency_dump_file() { static const char* create_emergency_dump_path() { assert(is_path_empty(), "invariant"); - const size_t path_len = get_current_directory(); + const size_t path_len = get_dump_directory(); if (path_len == 0) { return NULL; } @@ -125,12 +132,21 @@ static const char* create_emergency_dump_path() { return result ? _path_buffer : NULL; } -static bool open_emergency_dump_file() { +bool JfrEmergencyDump::open_emergency_dump_file() { if (is_emergency_dump_file_open()) { // opened already return true; } - return open_emergency_dump_fd(create_emergency_dump_path()); + + bool result = open_emergency_dump_fd(create_emergency_dump_path()); + if (!result && *_dump_path != '\0') { + log_warning(jfr)("Unable to create an emergency dump file at the location set by dumppath=%s", _dump_path); + // Fallback. Try to create it in the current directory. + *_dump_path = '\0'; + *_path_buffer = '\0'; + result = open_emergency_dump_fd(create_emergency_dump_path()); + } + return result; } static void report(outputStream* st, bool emergency_file_opened, const char* repository_path) { @@ -150,6 +166,19 @@ static void report(outputStream* st, bool emergency_file_opened, const char* rep } } +void JfrEmergencyDump::set_dump_path(const char* dump_path) { + if (dump_path != NULL) { + if (strlen(dump_path) < JVM_MAXPATHLEN) { + strncpy(_dump_path, dump_path, JVM_MAXPATHLEN); + _dump_path[JVM_MAXPATHLEN - 1] = '\0'; + } + } +} + +const char* JfrEmergencyDump::get_dump_path() { + return _dump_path; +} + void JfrEmergencyDump::on_vm_error_report(outputStream* st, const char* repository_path) { assert(st != NULL, "invariant"); Thread* thread = Thread::current_or_null_safe(); diff --git a/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.hpp b/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.hpp index 909f73bf892..c96a7d802dc 100644 --- a/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.hpp +++ b/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,7 +32,14 @@ // Responsible for creating an hs_err.jfr file in exceptional shutdown situations (crash, OOM) // class JfrEmergencyDump : AllStatic { + private: + static char _dump_path[JVM_MAXPATHLEN]; + + static bool open_emergency_dump_file(); + public: + static void set_dump_path(const char* dump_path); + static const char* get_dump_path(); static const char* chunk_path(const char* repository_path); static void on_vm_error(const char* repository_path); static void on_vm_error_report(outputStream* st, const char* repository_path); diff --git a/src/hotspot/share/jfr/recorder/service/jfrOptionSet.cpp b/src/hotspot/share/jfr/recorder/service/jfrOptionSet.cpp index 166603d4397..ce8fc5e4efa 100644 --- a/src/hotspot/share/jfr/recorder/service/jfrOptionSet.cpp +++ b/src/hotspot/share/jfr/recorder/service/jfrOptionSet.cpp @@ -163,6 +163,7 @@ bool JfrOptionSet::allow_event_retransforms() { // default options for the dcmd parser const char* const default_repository = NULL; +const char* const default_dumppath = NULL; const char* const default_global_buffer_size = "512k"; const char* const default_num_global_buffers = "20"; const char* const default_memory_size = "10m"; @@ -182,6 +183,13 @@ static DCmdArgument _dcmd_repository( false, default_repository); +static DCmdArgument _dcmd_dumppath( + "dumppath", + "Path to emergency dump", + "STRING", + false, + default_dumppath); + static DCmdArgument _dcmd_threadbuffersize( "threadbuffersize", "Thread buffer size", @@ -258,6 +266,7 @@ static DCmdParser _parser; static void register_parser_options() { _parser.add_dcmd_option(&_dcmd_repository); + _parser.add_dcmd_option(&_dcmd_dumppath); _parser.add_dcmd_option(&_dcmd_threadbuffersize); _parser.add_dcmd_option(&_dcmd_memorysize); _parser.add_dcmd_option(&_dcmd_globalbuffersize); @@ -346,6 +355,18 @@ bool JfrOptionSet::configure(TRAPS) { configure._repository_path.set_value(repo_copy); } + configure._dump_path.set_is_set(_dcmd_dumppath.is_set()); + char* dumppath = _dcmd_dumppath.value(); + if (dumppath != NULL) { + const size_t len = strlen(dumppath); + char* dumppath_copy = JfrCHeapObj::new_array(len + 1); + if (NULL == dumppath_copy) { + return false; + } + strncpy(dumppath_copy, dumppath, len + 1); + configure._dump_path.set_value(dumppath_copy); + } + configure._stack_depth.set_is_set(_dcmd_stackdepth.is_set()); configure._stack_depth.set_value(_dcmd_stackdepth.value()); diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/JVM.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/JVM.java index a88b428dac3..2b2dd27ff4b 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/JVM.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/JVM.java @@ -473,13 +473,26 @@ public final class JVM { public native void flush(); /** - * Sets the location of the disk repository, to be used at an emergency - * dump. + * Sets the location of the disk repository. * * @param dirText */ public native void setRepositoryLocation(String dirText); + /** + * Sets the path to emergency dump. + * + * @param dumpPathText + */ + public native void setDumpPath(String dumpPathText); + + /** + * Gets the path to emergency dump. + * + * @return The path to emergency dump. + */ + public native String getDumpPath(); + /** * Access to VM termination support. * diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/Options.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/Options.java index 4d430bebba2..5398b599422 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/Options.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/Options.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,9 +25,16 @@ package jdk.jfr.internal; +import java.io.IOException; + +import jdk.jfr.internal.LogLevel; +import jdk.jfr.internal.LogTag; +import jdk.jfr.internal.Logger; import jdk.jfr.internal.SecuritySupport.SafePath; import jdk.internal.misc.Unsafe; +import static java.nio.file.LinkOption.*; + /** * Options that control Flight Recorder. * @@ -48,7 +55,7 @@ public final class Options { private static final int DEFAULT_STACK_DEPTH = 64; private static final boolean DEFAULT_SAMPLE_THREADS = true; private static final long DEFAULT_MAX_CHUNK_SIZE = 12 * 1024 * 1024; - private static final SafePath DEFAULT_DUMP_PATH = SecuritySupport.USER_HOME; + private static final SafePath DEFAULT_DUMP_PATH = new SafePath("."); private static long memorySize; private static long globalBufferSize; @@ -57,7 +64,6 @@ public final class Options { private static int stackDepth; private static boolean sampleThreads; private static long maxChunkSize; - private static SafePath dumpPath; static { final long pageSize = Unsafe.getUnsafe().pageSize(); @@ -114,11 +120,23 @@ public final class Options { } public static synchronized void setDumpPath(SafePath path) { - dumpPath = path; + if (path.toFile().canWrite()) { + try { + jvm.setDumpPath(path.toPath().toRealPath(NOFOLLOW_LINKS).toString()); + } catch (IOException e) { + if (Logger.shouldLog(LogTag.JFR_SYSTEM_SETTING, LogLevel.WARN)) { + Logger.log(LogTag.JFR_SYSTEM_SETTING, LogLevel.WARN, "Error occurred in path resolution: " + e.toString()); + } + } + } else { + if (Logger.shouldLog(LogTag.JFR_SYSTEM_SETTING, LogLevel.WARN)) { + Logger.log(LogTag.JFR_SYSTEM_SETTING, LogLevel.WARN, "Cannot write JFR emergency dump to " + path.toString()); + } + } } public static synchronized SafePath getDumpPath() { - return dumpPath; + return new SafePath(jvm.getDumpPath()); } public static synchronized void setStackDepth(Integer stackTraceDepth) { diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/SecuritySupport.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/SecuritySupport.java index d761eb98c58..81ae6d4f097 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/SecuritySupport.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/SecuritySupport.java @@ -77,7 +77,6 @@ public final class SecuritySupport { private static final Module JFR_MODULE = Event.class.getModule(); public static final SafePath JFC_DIRECTORY = getPathInProperty("java.home", "lib/jfr"); public static final FileAccess PRIVILEGED = new Privileged(); - static final SafePath USER_HOME = getPathInProperty("user.home", null); static final SafePath JAVA_IO_TMPDIR = getPathInProperty("java.io.tmpdir", null); static { diff --git a/test/jdk/jdk/jfr/jvm/TestDumpOnCrash.java b/test/jdk/jdk/jfr/jvm/TestDumpOnCrash.java index 3869509b242..870ccbee5f7 100644 --- a/test/jdk/jdk/jfr/jvm/TestDumpOnCrash.java +++ b/test/jdk/jdk/jfr/jvm/TestDumpOnCrash.java @@ -26,6 +26,7 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.ArrayList; import java.util.List; import jdk.internal.misc.Unsafe; @@ -74,22 +75,49 @@ public class TestDumpOnCrash { } public static void main(String[] args) throws Exception { + // Test without dumppath test(CrasherIllegalAccess.class, "", true); test(CrasherIllegalAccess.class, "", false); test(CrasherHalt.class, "", true); test(CrasherHalt.class, "", false); + // Test with dumppath + Path dumppath = Files.createTempDirectory(null); + try { + test(CrasherIllegalAccess.class, "", true, dumppath.toString()); + test(CrasherIllegalAccess.class, "", false, dumppath.toString()); + test(CrasherHalt.class, "", true, dumppath.toString()); + test(CrasherHalt.class, "", false, dumppath.toString()); + } finally { + dumppath.toFile().delete(); + } + + // Test with illegal dumppath + Path illegalpath = Path.of("silverbullet"); + test(CrasherIllegalAccess.class, "", true, illegalpath.toString(), null); + test(CrasherIllegalAccess.class, "", false, illegalpath.toString(), null); + test(CrasherHalt.class, "", true, illegalpath.toString(), null); + test(CrasherHalt.class, "", false, illegalpath.toString(), null); + // Test is excluded until 8219680 is fixed // @ignore 8219680 // test(CrasherSig.class, "FPE", true); } private static void test(Class crasher, String signal, boolean disk) throws Exception { + test(crasher, signal, disk, null); + } + + private static void test(Class crasher, String signal, boolean disk, String dumppath) throws Exception { + test(crasher, signal, disk, dumppath, dumppath); + } + + private static void test(Class crasher, String signal, boolean disk, String dumppath, String expectedPath) throws Exception { // The JVM may be in a state it can't recover from, so try three times // before concluding functionality is not working. for (int attempt = 0; attempt < ATTEMPTS; attempt++) { try { - verify(runProcess(crasher, signal, disk)); + verify(runProcess(crasher, signal, disk, dumppath), expectedPath); return; } catch (Exception e) { System.out.println("Attempt " + attempt + ". Verification failed:"); @@ -105,17 +133,19 @@ public class TestDumpOnCrash { throw new Exception(ATTEMPTS + " attempts with failure!"); } - private static long runProcess(Class crasher, String signal, boolean disk) throws Exception { + private static long runProcess(Class crasher, String signal, boolean disk, String dumppath) throws Exception { System.out.println("Test case for crasher " + crasher.getName()); - final String flightRecordingOptions = "dumponexit=true,disk=" + Boolean.toString(disk); - Process p = ProcessTools.createTestJvm( - "-Xmx64m", - "-XX:-CreateCoredumpOnCrash", - "--add-exports=java.base/jdk.internal.misc=ALL-UNNAMED", - "-XX:StartFlightRecording:" + flightRecordingOptions, - crasher.getName(), - signal) - .start(); + List options = new ArrayList<>(); + options.add("-Xmx64m"); + options.add("-XX:-CreateCoredumpOnCrash"); + options.add("--add-exports=java.base/jdk.internal.misc=ALL-UNNAMED"); + options.add("-XX:StartFlightRecording:dumponexit=true,disk=" + Boolean.toString(disk)); + if (dumppath != null) { + options.add("-XX:FlightRecorderOptions=dumppath=" + dumppath); + } + options.add(crasher.getName()); + options.add(signal); + Process p = ProcessTools.createTestJvm(options).start(); OutputAnalyzer output = new OutputAnalyzer(p); System.out.println("========== Crasher process output:"); @@ -125,9 +155,10 @@ public class TestDumpOnCrash { return p.pid(); } - private static void verify(long pid) throws IOException { + private static void verify(long pid, String dumppath) throws IOException { String fileName = "hs_err_pid" + pid + ".jfr"; - Path file = Paths.get(fileName).toAbsolutePath().normalize(); + Path file = (dumppath == null) ? Paths.get(fileName) : Paths.get(dumppath, fileName); + file = file.toAbsolutePath().normalize(); Asserts.assertTrue(Files.exists(file), "No emergency jfr recording file " + file + " exists"); Asserts.assertNotEquals(Files.size(file), 0L, "File length 0. Should at least be some bytes"); -- GitLab From bb7dacdc78ad50797900e7e9610a1ed8e7ab1b00 Mon Sep 17 00:00:00 2001 From: Stefan Karlsson Date: Mon, 18 Oct 2021 07:03:17 +0000 Subject: [PATCH 232/385] 8275334: Move class loading Events to a separate section in hs_err files Reviewed-by: stuefe, coleenp --- src/hotspot/share/classfile/classLoader.cpp | 2 +- src/hotspot/share/utilities/events.cpp | 2 ++ src/hotspot/share/utilities/events.hpp | 17 +++++++++++++++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/classfile/classLoader.cpp b/src/hotspot/share/classfile/classLoader.cpp index c5e7da83a76..cf5ede2415f 100644 --- a/src/hotspot/share/classfile/classLoader.cpp +++ b/src/hotspot/share/classfile/classLoader.cpp @@ -1138,7 +1138,7 @@ InstanceKlass* ClassLoader::load_class(Symbol* name, bool search_append_only, TR const char* const class_name = name->as_C_string(); - EventMark m("loading class %s", class_name); + EventMarkClassLoading m("Loading class %s", class_name); const char* const file_name = file_name_for_class_name(class_name, name->utf8_length()); diff --git a/src/hotspot/share/utilities/events.cpp b/src/hotspot/share/utilities/events.cpp index 77cc16e174e..09e4ea89781 100644 --- a/src/hotspot/share/utilities/events.cpp +++ b/src/hotspot/share/utilities/events.cpp @@ -39,6 +39,7 @@ StringEventLog* Events::_vm_operations = NULL; ExceptionsEventLog* Events::_exceptions = NULL; StringEventLog* Events::_redefinitions = NULL; UnloadingEventLog* Events::_class_unloading = NULL; +StringEventLog* Events::_class_loading = NULL; StringEventLog* Events::_deopt_messages = NULL; EventLog::EventLog() { @@ -96,6 +97,7 @@ void Events::init() { _exceptions = new ExceptionsEventLog("Internal exceptions", "exc"); _redefinitions = new StringEventLog("Classes redefined", "redef"); _class_unloading = new UnloadingEventLog("Classes unloaded", "unload"); + _class_loading = new StringEventLog("Classes loaded", "load"); _deopt_messages = new StringEventLog("Deoptimization events", "deopt"); } } diff --git a/src/hotspot/share/utilities/events.hpp b/src/hotspot/share/utilities/events.hpp index 851526ae568..a98ee5b7969 100644 --- a/src/hotspot/share/utilities/events.hpp +++ b/src/hotspot/share/utilities/events.hpp @@ -235,6 +235,9 @@ class Events : AllStatic { // Class unloading events static UnloadingEventLog* _class_unloading; + + // Class loading events + static StringEventLog* _class_loading; public: // Print all event logs; limit number of events per event log to be printed with max @@ -260,6 +263,8 @@ class Events : AllStatic { static void log_class_unloading(Thread* thread, InstanceKlass* ik); + static void log_class_loading(Thread* thread, const char* format, ...) ATTRIBUTE_PRINTF(2, 3); + static void log_deopt_message(Thread* thread, const char* format, ...) ATTRIBUTE_PRINTF(2, 3); // Register default loggers @@ -314,6 +319,15 @@ inline void Events::log_class_unloading(Thread* thread, InstanceKlass* ik) { } } +inline void Events::log_class_loading(Thread* thread, const char* format, ...) { + if (LogEvents && _class_loading != NULL) { + va_list ap; + va_start(ap, format); + _class_loading->logv(thread, format, ap); + va_end(ap); + } +} + inline void Events::log_deopt_message(Thread* thread, const char* format, ...) { if (LogEvents && _deopt_messages != NULL) { va_list ap; @@ -473,4 +487,7 @@ typedef EventMarkWithLogFunction EventMark; // These end up in the vm_operation log. typedef EventMarkWithLogFunction EventMarkVMOperation; +// These end up in the class loading log. +typedef EventMarkWithLogFunction EventMarkClassLoading; + #endif // SHARE_UTILITIES_EVENTS_HPP -- GitLab From ebb1363e5d6b47daf1badad93490580fedcb0572 Mon Sep 17 00:00:00 2001 From: Tobias Holenstein Date: Mon, 18 Oct 2021 07:32:17 +0000 Subject: [PATCH 233/385] 8251513: Code around Parse::do_lookupswitch/do_tableswitch should be cleaned up Reviewed-by: roland, thartmann --- src/hotspot/share/ci/ciStreams.hpp | 8 +++-- src/hotspot/share/opto/parse2.cpp | 53 ++++++++++++------------------ 2 files changed, 26 insertions(+), 35 deletions(-) diff --git a/src/hotspot/share/ci/ciStreams.hpp b/src/hotspot/share/ci/ciStreams.hpp index 84f12952da5..8f46510a0d2 100644 --- a/src/hotspot/share/ci/ciStreams.hpp +++ b/src/hotspot/share/ci/ciStreams.hpp @@ -203,11 +203,13 @@ public: } // For a lookup or switch table, return target destination - int get_int_table( int index ) const { - return Bytes::get_Java_u4((address)&_table_base[index]); } + jint get_int_table( int index ) const { + return (jint)Bytes::get_Java_u4((address)&_table_base[index]); + } int get_dest_table( int index ) const { - return cur_bci() + get_int_table(index); } + return cur_bci() + get_int_table(index); + } // --- Constant pool access --- int get_constant_raw_index() const; diff --git a/src/hotspot/share/opto/parse2.cpp b/src/hotspot/share/opto/parse2.cpp index becd187a5ed..ee9c67fa944 100644 --- a/src/hotspot/share/opto/parse2.cpp +++ b/src/hotspot/share/opto/parse2.cpp @@ -410,8 +410,8 @@ static void merge_ranges(SwitchRange* ranges, int& rp) { void Parse::do_tableswitch() { // Get information about tableswitch int default_dest = iter().get_dest_table(0); - int lo_index = iter().get_int_table(1); - int hi_index = iter().get_int_table(2); + jint lo_index = iter().get_int_table(1); + jint hi_index = iter().get_int_table(2); int len = hi_index - lo_index + 1; if (len < 1) { @@ -438,9 +438,9 @@ void Parse::do_tableswitch() { SwitchRange* ranges = NEW_RESOURCE_ARRAY(SwitchRange, rnum); int rp = -1; if (lo_index != min_jint) { - uint cnt = 1; + float cnt = 1.0F; if (profile != NULL) { - cnt = profile->default_count() / (hi_index != max_jint ? 2 : 1); + cnt = (float)profile->default_count() / (hi_index != max_jint ? 2.0F : 1.0F); } ranges[++rp].setRange(min_jint, lo_index-1, default_dest, cnt); } @@ -448,9 +448,9 @@ void Parse::do_tableswitch() { jint match_int = lo_index+j; int dest = iter().get_dest_table(j+3); makes_backward_branch |= (dest <= bci()); - uint cnt = 1; + float cnt = 1.0F; if (profile != NULL) { - cnt = profile->count_at(j); + cnt = (float)profile->count_at(j); } if (rp < 0 || !ranges[rp].adjoin(match_int, dest, cnt, trim_ranges)) { ranges[++rp].set(match_int, dest, cnt); @@ -459,9 +459,9 @@ void Parse::do_tableswitch() { jint highest = lo_index+(len-1); assert(ranges[rp].hi() == highest, ""); if (highest != max_jint) { - uint cnt = 1; + float cnt = 1.0F; if (profile != NULL) { - cnt = profile->default_count() / (lo_index != min_jint ? 2 : 1); + cnt = (float)profile->default_count() / (lo_index != min_jint ? 2.0F : 1.0F); } if (!ranges[rp].adjoinRange(highest+1, max_jint, default_dest, cnt, trim_ranges)) { ranges[++rp].setRange(highest+1, max_jint, default_dest, cnt); @@ -487,7 +487,7 @@ void Parse::do_tableswitch() { void Parse::do_lookupswitch() { // Get information about lookupswitch int default_dest = iter().get_dest_table(0); - int len = iter().get_int_table(1); + jint len = iter().get_int_table(1); if (len < 1) { // If this is a backward branch, add safepoint maybe_add_safepoint(default_dest); @@ -513,26 +513,15 @@ void Parse::do_lookupswitch() { table[3*j+0] = iter().get_int_table(2+2*j); table[3*j+1] = iter().get_dest_table(2+2*j+1); // Handle overflow when converting from uint to jint - table[3*j+2] = (profile == NULL) ? 1 : MIN2(max_jint, profile->count_at(j)); + table[3*j+2] = (profile == NULL) ? 1 : (jint)MIN2((uint)max_jint, profile->count_at(j)); } qsort(table, len, 3*sizeof(table[0]), jint_cmp); } - float defaults = 0; - jint prev = min_jint; - for (int j = 0; j < len; j++) { - jint match_int = table[3*j+0]; - if (match_int != prev) { - defaults += (float)match_int - prev; - } - prev = match_int+1; - } - if (prev != min_jint) { - defaults += (float)max_jint - prev + 1; - } - float default_cnt = 1; + float default_cnt = 1.0F; if (profile != NULL) { - default_cnt = profile->default_count()/defaults; + juint defaults = max_juint - len; + default_cnt = (float)profile->default_count()/(float)defaults; } int rnum = len*2+1; @@ -541,25 +530,25 @@ void Parse::do_lookupswitch() { int rp = -1; for (int j = 0; j < len; j++) { jint match_int = table[3*j+0]; - int dest = table[3*j+1]; - int cnt = table[3*j+2]; - int next_lo = rp < 0 ? min_jint : ranges[rp].hi()+1; + jint dest = table[3*j+1]; + jint cnt = table[3*j+2]; + jint next_lo = rp < 0 ? min_jint : ranges[rp].hi()+1; makes_backward_branch |= (dest <= bci()); - float c = default_cnt * ((float)match_int - next_lo); + float c = default_cnt * ((float)match_int - (float)next_lo); if (match_int != next_lo && (rp < 0 || !ranges[rp].adjoinRange(next_lo, match_int-1, default_dest, c, trim_ranges))) { assert(default_dest != never_reached, "sentinel value for dead destinations"); ranges[++rp].setRange(next_lo, match_int-1, default_dest, c); } - if (rp < 0 || !ranges[rp].adjoin(match_int, dest, cnt, trim_ranges)) { + if (rp < 0 || !ranges[rp].adjoin(match_int, dest, (float)cnt, trim_ranges)) { assert(dest != never_reached, "sentinel value for dead destinations"); - ranges[++rp].set(match_int, dest, cnt); + ranges[++rp].set(match_int, dest, (float)cnt); } } jint highest = table[3*(len-1)]; assert(ranges[rp].hi() == highest, ""); if (highest != max_jint && - !ranges[rp].adjoinRange(highest+1, max_jint, default_dest, default_cnt * ((float)max_jint - highest), trim_ranges)) { - ranges[++rp].setRange(highest+1, max_jint, default_dest, default_cnt * ((float)max_jint - highest)); + !ranges[rp].adjoinRange(highest+1, max_jint, default_dest, default_cnt * ((float)max_jint - (float)highest), trim_ranges)) { + ranges[++rp].setRange(highest+1, max_jint, default_dest, default_cnt * ((float)max_jint - (float)highest)); } assert(rp < rnum, "not too many ranges"); -- GitLab From 45ebf85ca9a1e071955ba2e3cb32449bfbd85d14 Mon Sep 17 00:00:00 2001 From: Stefan Karlsson Date: Mon, 18 Oct 2021 11:20:51 +0000 Subject: [PATCH 234/385] 8275333: Print count in "Too many recored phases?" assert Reviewed-by: eosterlund, tschatzl --- src/hotspot/share/gc/shared/gcTimer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/gc/shared/gcTimer.cpp b/src/hotspot/share/gc/shared/gcTimer.cpp index ca835e30ed3..d7669604d82 100644 --- a/src/hotspot/share/gc/shared/gcTimer.cpp +++ b/src/hotspot/share/gc/shared/gcTimer.cpp @@ -130,7 +130,7 @@ void TimePartitions::clear() { } void TimePartitions::report_gc_phase_start(const char* name, const Ticks& time, GCPhase::PhaseType type) { - assert(_phases->length() <= 1000, "Too many recored phases?"); + assert(_phases->length() <= 1000, "Too many recorded phases? (count: %d)", _phases->length()); int level = _active_phases.count(); -- GitLab From 1afddb2560504c533d30b2f79d735f59f519e7c5 Mon Sep 17 00:00:00 2001 From: Andrey Turbanov Date: Mon, 18 Oct 2021 12:02:00 +0000 Subject: [PATCH 235/385] 8275322: Change nested classes in java.management to static nested classes Reviewed-by: alanb, dfuchs, mchung, sspitsyn --- .../com/sun/jmx/mbeanserver/DefaultMXBeanMappingFactory.java | 2 +- .../share/classes/sun/management/MemoryPoolImpl.java | 5 ++--- .../classes/sun/management/NotificationEmitterSupport.java | 4 ++-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/java.management/share/classes/com/sun/jmx/mbeanserver/DefaultMXBeanMappingFactory.java b/src/java.management/share/classes/com/sun/jmx/mbeanserver/DefaultMXBeanMappingFactory.java index 7cad0dbed96..6f35c44953f 100644 --- a/src/java.management/share/classes/com/sun/jmx/mbeanserver/DefaultMXBeanMappingFactory.java +++ b/src/java.management/share/classes/com/sun/jmx/mbeanserver/DefaultMXBeanMappingFactory.java @@ -806,7 +806,7 @@ public class DefaultMXBeanMappingFactory extends MXBeanMappingFactory { private final MXBeanMapping valueMapping; } - private final class CompositeMapping extends NonNullMXBeanMapping { + private static final class CompositeMapping extends NonNullMXBeanMapping { CompositeMapping(Class targetClass, CompositeType compositeType, String[] itemNames, diff --git a/src/java.management/share/classes/sun/management/MemoryPoolImpl.java b/src/java.management/share/classes/sun/management/MemoryPoolImpl.java index 227d19947db..3b8197bb8f1 100644 --- a/src/java.management/share/classes/sun/management/MemoryPoolImpl.java +++ b/src/java.management/share/classes/sun/management/MemoryPoolImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,6 @@ import java.lang.management.MemoryPoolMXBean; import java.lang.management.MemoryUsage; import java.lang.management.MemoryType; import java.lang.management.MemoryManagerMXBean; -import javax.management.openmbean.CompositeData; import javax.management.ObjectName; import static java.lang.management.MemoryNotificationInfo.*; @@ -287,7 +286,7 @@ class MemoryPoolImpl implements MemoryPoolMXBean { * The VM will not trigger this sensor in subsequent crossing * unless the memory usage has returned below the threshold. */ - class PoolSensor extends Sensor { + static class PoolSensor extends Sensor { final MemoryPoolImpl pool; PoolSensor(MemoryPoolImpl pool, String name) { diff --git a/src/java.management/share/classes/sun/management/NotificationEmitterSupport.java b/src/java.management/share/classes/sun/management/NotificationEmitterSupport.java index a78b3453b0d..da6898c84af 100644 --- a/src/java.management/share/classes/sun/management/NotificationEmitterSupport.java +++ b/src/java.management/share/classes/sun/management/NotificationEmitterSupport.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -167,7 +167,7 @@ public abstract class NotificationEmitterSupport implements NotificationEmitter } } - private class ListenerInfo { + private static class ListenerInfo { public NotificationListener listener; NotificationFilter filter; Object handback; -- GitLab From a619f8909bb074712db22746e785f7485795a8f5 Mon Sep 17 00:00:00 2001 From: Weijun Wang Date: Mon, 18 Oct 2021 13:24:39 +0000 Subject: [PATCH 236/385] 8274721: UnixSystem fails to provide uid, gid or groups if no username is available Reviewed-by: mullan --- .../unix/native/libjaas/Unix.c | 73 +++++++++++-------- 1 file changed, 41 insertions(+), 32 deletions(-) diff --git a/src/jdk.security.auth/unix/native/libjaas/Unix.c b/src/jdk.security.auth/unix/native/libjaas/Unix.c index 37acef3a636..3a93df9ffc9 100644 --- a/src/jdk.security.auth/unix/native/libjaas/Unix.c +++ b/src/jdk.security.auth/unix/native/libjaas/Unix.c @@ -66,54 +66,63 @@ Java_com_sun_security_auth_module_UnixSystem_getUnixInfo groups = (gid_t *)calloc(numSuppGroups, sizeof(gid_t)); if (groups == NULL) { jclass cls = (*env)->FindClass(env,"java/lang/OutOfMemoryError"); - if (cls != NULL) + if (cls != NULL) { (*env)->ThrowNew(env, cls, NULL); + } return; } cls = (*env)->GetObjectClass(env, obj); - memset(pwd_buf, 0, sizeof(pwd_buf)); - - if (getpwuid_r(getuid(), &resbuf, pwd_buf, sizeof(pwd_buf), &pwd) == 0 && - pwd != NULL && - getgroups(numSuppGroups, groups) != -1) { + supplementaryGroupID = (*env)->GetFieldID(env, cls, "groups", "[J"); + if (supplementaryGroupID == 0) { + goto cleanUpAndReturn; + } - userNameID = (*env)->GetFieldID(env, cls, "username", "Ljava/lang/String;"); - if (userNameID == 0) + if (getgroups(numSuppGroups, groups) != -1) { + jgroups = (*env)->NewLongArray(env, numSuppGroups); + if (jgroups == NULL) { goto cleanUpAndReturn; - - userID = (*env)->GetFieldID(env, cls, "uid", "J"); - if (userID == 0) + } + jgroupsAsArray = (*env)->GetLongArrayElements(env, jgroups, 0); + if (jgroupsAsArray == NULL) { goto cleanUpAndReturn; + } + for (i = 0; i < numSuppGroups; i++) { + jgroupsAsArray[i] = groups[i]; + } + (*env)->ReleaseLongArrayElements(env, jgroups, jgroupsAsArray, 0); + (*env)->SetObjectField(env, obj, supplementaryGroupID, jgroups); + } - groupID = (*env)->GetFieldID(env, cls, "gid", "J"); - if (groupID == 0) - goto cleanUpAndReturn; + userNameID = (*env)->GetFieldID(env, cls, "username", "Ljava/lang/String;"); + if (userNameID == 0) { + goto cleanUpAndReturn; + } - supplementaryGroupID = (*env)->GetFieldID(env, cls, "groups", "[J"); - if (supplementaryGroupID == 0) - goto cleanUpAndReturn; + userID = (*env)->GetFieldID(env, cls, "uid", "J"); + if (userID == 0) { + goto cleanUpAndReturn; + } - jstr = (*env)->NewStringUTF(env, pwd->pw_name); - if (jstr == NULL) - goto cleanUpAndReturn; - (*env)->SetObjectField(env, obj, userNameID, jstr); + groupID = (*env)->GetFieldID(env, cls, "gid", "J"); + if (groupID == 0) { + goto cleanUpAndReturn; + } + memset(pwd_buf, 0, sizeof(pwd_buf)); + if (getpwuid_r(getuid(), &resbuf, pwd_buf, sizeof(pwd_buf), &pwd) == 0 && + pwd != NULL) { (*env)->SetLongField(env, obj, userID, pwd->pw_uid); - (*env)->SetLongField(env, obj, groupID, pwd->pw_gid); - - jgroups = (*env)->NewLongArray(env, numSuppGroups); - if (jgroups == NULL) - goto cleanUpAndReturn; - jgroupsAsArray = (*env)->GetLongArrayElements(env, jgroups, 0); - if (jgroupsAsArray == NULL) + jstr = (*env)->NewStringUTF(env, pwd->pw_name); + if (jstr == NULL) { goto cleanUpAndReturn; - for (i = 0; i < numSuppGroups; i++) - jgroupsAsArray[i] = groups[i]; - (*env)->ReleaseLongArrayElements(env, jgroups, jgroupsAsArray, 0); - (*env)->SetObjectField(env, obj, supplementaryGroupID, jgroups); + } + (*env)->SetObjectField(env, obj, userNameID, jstr); + } else { + (*env)->SetLongField(env, obj, userID, getuid()); + (*env)->SetLongField(env, obj, groupID, getgid()); } cleanUpAndReturn: free(groups); -- GitLab From d548f2fc0dbc9e7864dd1701873bbf3d12a75ecb Mon Sep 17 00:00:00 2001 From: Andy Herrick Date: Mon, 18 Oct 2021 13:28:41 +0000 Subject: [PATCH 237/385] 8274346: Support for additional content in an app-image. Reviewed-by: asemenyuk, almatvee --- .../internal/AbstractAppImageBuilder.java | 9 +- .../jpackage/internal/ApplicationLayout.java | 28 ++++- .../jdk/jpackage/internal/Arguments.java | 7 +- .../jdk/jpackage/internal/DeployParams.java | 5 +- .../internal/StandardBundlerParam.java | 10 ++ .../jdk/jpackage/internal/ValidOptions.java | 1 + .../resources/HelpResources.properties | 4 + .../resources/HelpResources_ja.properties | 4 + .../resources/HelpResources_zh_CN.properties | 4 + .../tools/jpackage/share/AppContentTest.java | 105 ++++++++++++++++++ 10 files changed, 167 insertions(+), 10 deletions(-) create mode 100644 test/jdk/tools/jpackage/share/AppContentTest.java diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractAppImageBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractAppImageBuilder.java index da73b9a6419..72d85affb72 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractAppImageBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractAppImageBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. * 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,10 +29,12 @@ import java.io.IOException; import java.io.InputStream; import java.nio.file.Path; import java.util.Map; +import java.util.List; import static jdk.jpackage.internal.OverridableResource.createResource; import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; import static jdk.jpackage.internal.StandardBundlerParam.ICON; import static jdk.jpackage.internal.StandardBundlerParam.SOURCE_DIR; +import static jdk.jpackage.internal.StandardBundlerParam.APP_CONTENT; import jdk.jpackage.internal.resources.ResourceLocator; /* @@ -75,6 +77,11 @@ public abstract class AbstractAppImageBuilder { appLayout.appDirectory()); } AppImageFile.save(root, params); + List items = APP_CONTENT.fetchFrom(params); + for (String item : items) { + IOUtils.copyRecursive(Path.of(item), + appLayout.contentDirectory().resolve(Path.of(item).getFileName())); + } } public static OverridableResource createIconResource(String defaultIconName, diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationLayout.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationLayout.java index ceb0e3f7e72..110fe79fb5a 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationLayout.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationLayout.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -66,7 +66,12 @@ public final class ApplicationLayout implements PathGroup.Facade paths) { @@ -129,6 +134,13 @@ public final class ApplicationLayout implements PathGroup.Facade setOptionValue("java-options", a)); }), + APP_CONTENT ("app-content", OptionCategories.PROPERTY, () -> { + getArgumentList(popArg()).forEach( + a -> setOptionValue("app-content", a)); + }), + FILE_ASSOCIATIONS ("file-associations", OptionCategories.PROPERTY, () -> { Map args = new HashMap<>(); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/DeployParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/DeployParams.java index da237fd7d8b..68685af5c32 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/DeployParams.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/DeployParams.java @@ -294,6 +294,7 @@ public class DeployParams { StandardBundlerParam.ADD_MODULES.getID(), StandardBundlerParam.LIMIT_MODULES.getID(), StandardBundlerParam.FILE_ASSOCIATIONS.getID(), + StandardBundlerParam.APP_CONTENT.getID(), StandardBundlerParam.JLINK_OPTIONS.getID() )); @@ -306,8 +307,8 @@ public class DeployParams { String delim = "\n\n"; if (key.equals(StandardBundlerParam.MODULE_PATH.getID())) { delim = File.pathSeparator; - } else if (key.equals( - StandardBundlerParam.ADD_MODULES.getID())) { + } else if (key.equals(StandardBundlerParam.ADD_MODULES.getID()) || + key.equals(StandardBundlerParam.APP_CONTENT.getID())) { delim = ","; } bundlerArguments.put(key, existingValue + delim + value); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java index a097d5f01f8..ee0a92e710c 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java @@ -404,6 +404,16 @@ class StandardBundlerParam extends BundlerParamInfo { (s, p) -> Path.of(s) ); + @SuppressWarnings("unchecked") + static final StandardBundlerParam> APP_CONTENT = + new StandardBundlerParam<>( + Arguments.CLIOptions.APP_CONTENT.getId(), + (Class>) (Object)List.class, + p->Collections.emptyList(), + (s, p) -> Arrays.asList(s.split(",")) + + ); + @SuppressWarnings("unchecked") static final BundlerParamInfo> MODULE_PATH = new StandardBundlerParam<>( 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 deec3bb7d10..d9198588841 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ValidOptions.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ValidOptions.java @@ -82,6 +82,7 @@ class ValidOptions { options.put(CLIOptions.JAVA_OPTIONS.getId(), USE.LAUNCHER); options.put(CLIOptions.ADD_LAUNCHER.getId(), USE.LAUNCHER); options.put(CLIOptions.JLINK_OPTIONS.getId(), USE.LAUNCHER); + options.put(CLIOptions.APP_CONTENT.getId(), USE.LAUNCHER); options.put(CLIOptions.LICENSE_FILE.getId(), USE.INSTALL); options.put(CLIOptions.INSTALL_DIR.getId(), USE.INSTALL); 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 f2b0ecc6134..e4784751566 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 @@ -128,6 +128,10 @@ Generic Options:\n\ \ (absolute path or relative to the current directory)\n\ \ All files in the input directory will be packaged into the\n\ \ application image.\n\ +\ --app-content [,...]\n\ +\ A comma separated list of paths to files and/or directories\n\ +\ to add to the application payload.\n\ +\ This option can be used more than once.\n\ \n\ \Options for creating the application launcher(s):\n\ \ --add-launcher =\n\ diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources_ja.properties b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources_ja.properties index efb249404fb..8e88994cb1f 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources_ja.properties +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources_ja.properties @@ -128,6 +128,10 @@ Generic Options:\n\ \ (absolute path or relative to the current directory)\n\ \ All files in the input directory will be packaged into the\n\ \ application image.\n\ +\ --app-content [,...]\n\ +\ A comma separated list of paths to files and/or directories\n\ +\ to add to the application payload.\n\ +\ This option can be used more than once.\n\ \n\ \Options for creating the application launcher(s):\n\ \ --add-launcher =\n\ diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources_zh_CN.properties b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources_zh_CN.properties index 2964d5ffb98..6a18294edbc 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources_zh_CN.properties +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources_zh_CN.properties @@ -128,6 +128,10 @@ Generic Options:\n\ \ (absolute path or relative to the current directory)\n\ \ All files in the input directory will be packaged into the\n\ \ application image.\n\ +\ --app-content [,...]\n\ +\ A comma separated list of paths to files and/or directories\n\ +\ to add to the application payload.\n\ +\ This option can be used more than once.\n\ \n\ \Options for creating the application launcher(s):\n\ \ --add-launcher =\n\ diff --git a/test/jdk/tools/jpackage/share/AppContentTest.java b/test/jdk/tools/jpackage/share/AppContentTest.java new file mode 100644 index 00000000000..4b2100e0d56 --- /dev/null +++ b/test/jdk/tools/jpackage/share/AppContentTest.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 java.nio.file.Files; +import jdk.jpackage.internal.ApplicationLayout; +import jdk.jpackage.test.PackageTest; +import jdk.jpackage.test.PackageType; +import jdk.jpackage.test.TKit; +import jdk.jpackage.test.Annotations.Test; +import jdk.jpackage.test.Annotations.Parameter; +import jdk.jpackage.test.Annotations.Parameters; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + + +/** + * Tests generation of packages with input folder containing empty folders. + */ + +/* + * @test + * @summary jpackage with --app-content option + * @library ../helpers + * @library /test/lib + * @key jpackagePlatformPackage + * @build jdk.jpackage.test.* + * @build AppContentTest + * @modules jdk.jpackage/jdk.jpackage.internal + * @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main + * --jpt-run=AppContentTest + */ +public class AppContentTest { + + private static final String TEST_JAVA = TKit.TEST_SRC_ROOT.resolve( + "apps/PrintEnv.java").toString(); + private static final String TEST_DUKE = TKit.TEST_SRC_ROOT.resolve( + "apps/dukeplug.png").toString(); + private static final String TEST_DIR = TKit.TEST_SRC_ROOT.resolve( + "apps").toString(); + private static final String TEST_BAD = TKit.TEST_SRC_ROOT.resolve( + "non-existant").toString(); + + private final List testPathArgs; + + @Parameters + public static Collection data() { + return List.of(new String[][]{ + {TEST_JAVA, TEST_DUKE}, // include two files in two options + {TEST_JAVA, TEST_BAD}, // try to include non-existant content + {TEST_JAVA + "," + TEST_DUKE, TEST_DIR}, // two files in one option, + // and a dir tree in another option. + }); + } + + public AppContentTest(String... testPathArgs) { + this.testPathArgs = List.of(testPathArgs); + } + + @Test + public void test() throws Exception { + + new PackageTest().configureHelloApp() + .addInitializer(cmd -> { + for (String arg : testPathArgs) { + cmd.addArguments("--app-content", arg); + } + }) + .addInstallVerifier(cmd -> { + ApplicationLayout appLayout = cmd.appLayout(); + Path contentDir = appLayout.contentDirectory(); + for (String arg : testPathArgs) { + List paths = Arrays.asList(arg.split(",")); + for (String p : paths) { + Path name = Path.of(p).getFileName(); + TKit.assertPathExists(contentDir.resolve(name), true); + } + } + + }) + .setExpectedExitCode(testPathArgs.contains(TEST_BAD) ? 1 : 0) + .run(); + } +} -- GitLab From fb8e5cf4ecee1b737bdcc806d219709854185764 Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Mon, 18 Oct 2021 15:48:59 +0000 Subject: [PATCH 238/385] 8275368: Correct statement of kinds of elements Processor.process operates over Reviewed-by: jlahoda --- .../annotation/processing/Processor.java | 21 ++++++++++--------- .../processing/RoundEnvironment.java | 16 +++++++++----- 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/src/java.compiler/share/classes/javax/annotation/processing/Processor.java b/src/java.compiler/share/classes/javax/annotation/processing/Processor.java index 0b2160da263..d70910c9d49 100644 --- a/src/java.compiler/share/classes/javax/annotation/processing/Processor.java +++ b/src/java.compiler/share/classes/javax/annotation/processing/Processor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -322,15 +322,16 @@ public interface Processor { void init(ProcessingEnvironment processingEnv); /** - * Processes a set of annotation interfaces on type elements - * originating from the prior round and returns whether or not - * these annotation interfaces are claimed by this processor. If {@code - * true} is returned, the annotation interfaces are claimed and subsequent - * processors will not be asked to process them; if {@code false} - * is returned, the annotation interfaces are unclaimed and subsequent - * processors may be asked to process them. A processor may - * always return the same boolean value or may vary the result - * based on its own chosen criteria. + * Processes a set of annotation interfaces on {@linkplain + * RoundEnvironment#getRootElements() root elements} originating + * from the prior round and returns whether or not these + * annotation interfaces are claimed by this processor. If {@code + * true} is returned, the annotation interfaces are claimed and + * subsequent processors will not be asked to process them; if + * {@code false} is returned, the annotation interfaces are + * unclaimed and subsequent processors may be asked to process + * them. A processor may always return the same boolean value or + * may vary the result based on its own chosen criteria. * *

      The input set will be empty if the processor supports {@code * "*"} and the root elements have no annotations. A {@code diff --git a/src/java.compiler/share/classes/javax/annotation/processing/RoundEnvironment.java b/src/java.compiler/share/classes/javax/annotation/processing/RoundEnvironment.java index c50c6b787a6..6323bda1339 100644 --- a/src/java.compiler/share/classes/javax/annotation/processing/RoundEnvironment.java +++ b/src/java.compiler/share/classes/javax/annotation/processing/RoundEnvironment.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,8 +25,7 @@ package javax.annotation.processing; -import javax.lang.model.element.Element; -import javax.lang.model.element.TypeElement; +import javax.lang.model.element.*; import java.util.LinkedHashSet; import java.util.Collections; import java.util.Set; @@ -58,8 +57,15 @@ public interface RoundEnvironment { boolean errorRaised(); /** - * Returns the {@linkplain Processor root elements} for annotation processing generated - * by the prior round. + * Returns the {@linkplain Processor root elements} for annotation + * processing {@linkplain Filer generated} by the prior round. + * + * @apiNote + * Root elements correspond to the top-level declarations in + * compilation units (JLS section {@jls 7.3}). Root elements are + * most commonly {@linkplain TypeElement types}, but can also be + * {@linkplain PackageElement packages} or {@linkplain + * ModuleElement modules}. * * @return the root elements for annotation processing generated * by the prior round, or an empty set if there were none -- GitLab From 4d383b9fcd2e1cb3afde17a37bc2dc5a37247d04 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Mon, 18 Oct 2021 16:02:22 +0000 Subject: [PATCH 239/385] 8275298: Remove unnecessary weak_oops_do call in adjust weak roots phase Reviewed-by: tschatzl, sjohanss --- src/hotspot/share/gc/g1/g1ConcurrentMark.cpp | 3 --- src/hotspot/share/gc/g1/g1FullGCAdjustTask.cpp | 11 ++++------- src/hotspot/share/gc/g1/g1FullGCAdjustTask.hpp | 1 - src/hotspot/share/gc/g1/g1YoungCollector.cpp | 2 -- .../share/gc/parallel/psParallelCompact.cpp | 14 -------------- src/hotspot/share/gc/parallel/psScavenge.cpp | 2 -- src/hotspot/share/gc/shared/genCollectedHeap.cpp | 2 -- src/hotspot/share/gc/shared/referenceProcessor.cpp | 3 +++ src/hotspot/share/gc/shared/referenceProcessor.hpp | 2 -- 9 files changed, 7 insertions(+), 33 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp index 33bd3352f2d..0acfd809ff2 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp @@ -1645,9 +1645,6 @@ void G1ConcurrentMark::weak_refs_work() { "Mark stack should be empty (unless it has overflown)"); assert(rp->num_queues() == active_workers, "why not"); - - rp->verify_no_references_recorded(); - assert(!rp->discovery_enabled(), "Post condition"); } if (has_overflown()) { diff --git a/src/hotspot/share/gc/g1/g1FullGCAdjustTask.cpp b/src/hotspot/share/gc/g1/g1FullGCAdjustTask.cpp index 273db274a56..b3a4ee11d53 100644 --- a/src/hotspot/share/gc/g1/g1FullGCAdjustTask.cpp +++ b/src/hotspot/share/gc/g1/g1FullGCAdjustTask.cpp @@ -81,7 +81,6 @@ class G1AdjustRegionClosure : public HeapRegionClosure { G1FullGCAdjustTask::G1FullGCAdjustTask(G1FullCollector* collector) : G1FullGCTask("G1 Adjust", collector), _root_processor(G1CollectedHeap::heap(), collector->workers()), - _references_done(false), _weak_proc_task(collector->workers()), _hrclaimer(collector->workers()), _adjust(collector) { @@ -97,14 +96,12 @@ void G1FullGCAdjustTask::work(uint worker_id) { G1FullGCMarker* marker = collector()->marker(worker_id); marker->preserved_stack()->adjust_during_full_gc(); - // Adjust the weak roots. - if (!Atomic::cmpxchg(&_references_done, false, true)) { - G1CollectedHeap::heap()->ref_processor_stw()->weak_oops_do(&_adjust); + { + // Adjust the weak roots. + AlwaysTrueClosure always_alive; + _weak_proc_task.work(worker_id, &always_alive, &_adjust); } - AlwaysTrueClosure always_alive; - _weak_proc_task.work(worker_id, &always_alive, &_adjust); - CLDToOopClosure adjust_cld(&_adjust, ClassLoaderData::_claim_strong); CodeBlobToOopClosure adjust_code(&_adjust, CodeBlobToOopClosure::FixRelocations); _root_processor.process_all_roots(&_adjust, &adjust_cld, &adjust_code); diff --git a/src/hotspot/share/gc/g1/g1FullGCAdjustTask.hpp b/src/hotspot/share/gc/g1/g1FullGCAdjustTask.hpp index 56c5957cd26..c9b190acd06 100644 --- a/src/hotspot/share/gc/g1/g1FullGCAdjustTask.hpp +++ b/src/hotspot/share/gc/g1/g1FullGCAdjustTask.hpp @@ -36,7 +36,6 @@ class G1CollectedHeap; class G1FullGCAdjustTask : public G1FullGCTask { G1RootProcessor _root_processor; - volatile bool _references_done; WeakProcessor::Task _weak_proc_task; HeapRegionClaimer _hrclaimer; G1AdjustClosure _adjust; diff --git a/src/hotspot/share/gc/g1/g1YoungCollector.cpp b/src/hotspot/share/gc/g1/g1YoungCollector.cpp index 2adee5b4d13..dafa9b1a587 100644 --- a/src/hotspot/share/gc/g1/g1YoungCollector.cpp +++ b/src/hotspot/share/gc/g1/g1YoungCollector.cpp @@ -984,8 +984,6 @@ void G1YoungCollector::process_discovered_references(G1ParScanThreadStateSet* pe _g1h->make_pending_list_reachable(); - rp->verify_no_references_recorded(); - phase_times()->record_ref_proc_time((Ticks::now() - start).seconds() * MILLIUNITS); } diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.cpp b/src/hotspot/share/gc/parallel/psParallelCompact.cpp index 4de272e8829..212bd424e63 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.cpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.cpp @@ -1923,8 +1923,6 @@ bool PSParallelCompact::invoke_no_policy(bool maximum_heap_compaction) { old_gen->object_space()->check_mangled_unused_area_complete(); } - NOT_PRODUCT(ref_processor()->verify_no_references_recorded()); - collection_exit.update(); heap->print_heap_after_gc(); @@ -2161,8 +2159,6 @@ class PSAdjustTask final : public WorkerTask { enum PSAdjustSubTask { PSAdjustSubTask_code_cache, - PSAdjustSubTask_old_ref_process, - PSAdjustSubTask_young_ref_process, PSAdjustSubTask_num_elements }; @@ -2204,16 +2200,6 @@ public: CodeBlobToOopClosure adjust_code(&adjust, CodeBlobToOopClosure::FixRelocations); CodeCache::blobs_do(&adjust_code); } - if (_sub_tasks.try_claim_task(PSAdjustSubTask_old_ref_process)) { - PSParallelCompact::ref_processor()->weak_oops_do(&adjust); - } - if (_sub_tasks.try_claim_task(PSAdjustSubTask_young_ref_process)) { - // Roots were visited so references into the young gen in roots - // may have been scanned. Process them also. - // Should the reference processor have a span that excludes - // young gen objects? - PSScavenge::reference_processor()->weak_oops_do(&adjust); - } _sub_tasks.all_tasks_claimed(); } }; diff --git a/src/hotspot/share/gc/parallel/psScavenge.cpp b/src/hotspot/share/gc/parallel/psScavenge.cpp index 293ca5b3810..f4a2fce76ec 100644 --- a/src/hotspot/share/gc/parallel/psScavenge.cpp +++ b/src/hotspot/share/gc/parallel/psScavenge.cpp @@ -654,8 +654,6 @@ bool PSScavenge::invoke_no_policy() { DerivedPointerTable::update_pointers(); #endif - NOT_PRODUCT(reference_processor()->verify_no_references_recorded()); - // Re-verify object start arrays if (VerifyObjectStartArray && VerifyAfterGC) { diff --git a/src/hotspot/share/gc/shared/genCollectedHeap.cpp b/src/hotspot/share/gc/shared/genCollectedHeap.cpp index 18658dd9edf..662dbdd9c5f 100644 --- a/src/hotspot/share/gc/shared/genCollectedHeap.cpp +++ b/src/hotspot/share/gc/shared/genCollectedHeap.cpp @@ -798,8 +798,6 @@ void GenCollectedHeap::full_process_roots(bool is_adjust_phase, void GenCollectedHeap::gen_process_weak_roots(OopClosure* root_closure) { WeakProcessor::oops_do(root_closure); - _young_gen->ref_processor()->weak_oops_do(root_closure); - _old_gen->ref_processor()->weak_oops_do(root_closure); } bool GenCollectedHeap::no_allocs_since_save_marks() { diff --git a/src/hotspot/share/gc/shared/referenceProcessor.cpp b/src/hotspot/share/gc/shared/referenceProcessor.cpp index 48d5280b664..c8f7b8a68fc 100644 --- a/src/hotspot/share/gc/shared/referenceProcessor.cpp +++ b/src/hotspot/share/gc/shared/referenceProcessor.cpp @@ -216,6 +216,9 @@ ReferenceProcessorStats ReferenceProcessor::process_discovered_references(RefPro phase_times.set_total_time_ms((os::elapsedTime() - start_time) * 1000); + // Elements on discovered lists were pushed to the pending list. + verify_no_references_recorded(); + return stats; } diff --git a/src/hotspot/share/gc/shared/referenceProcessor.hpp b/src/hotspot/share/gc/shared/referenceProcessor.hpp index f95ec84e06b..4591352cee0 100644 --- a/src/hotspot/share/gc/shared/referenceProcessor.hpp +++ b/src/hotspot/share/gc/shared/referenceProcessor.hpp @@ -420,8 +420,6 @@ public: // iterate over oops void weak_oops_do(OopClosure* f); // weak roots - void verify_list(DiscoveredList& ref_list); - // Discover a Reference object, using appropriate discovery criteria virtual bool discover_reference(oop obj, ReferenceType rt); -- GitLab From 426bcee9274bb3ec7dce551f85adb2ab61c22481 Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Mon, 18 Oct 2021 16:11:16 +0000 Subject: [PATCH 240/385] 8275360: Use @Override in javax.annotation.processing Reviewed-by: iris --- .../javax/annotation/processing/AbstractProcessor.java | 5 +++++ .../classes/javax/annotation/processing/Completions.java | 1 - 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/java.compiler/share/classes/javax/annotation/processing/AbstractProcessor.java b/src/java.compiler/share/classes/javax/annotation/processing/AbstractProcessor.java index 469ec4a4b8e..7754105a8d4 100644 --- a/src/java.compiler/share/classes/javax/annotation/processing/AbstractProcessor.java +++ b/src/java.compiler/share/classes/javax/annotation/processing/AbstractProcessor.java @@ -79,6 +79,7 @@ public abstract class AbstractProcessor implements Processor { * @return the options recognized by this processor, or an empty * set if none */ + @Override public Set getSupportedOptions() { SupportedOptions so = this.getClass().getAnnotation(SupportedOptions.class); return (so == null) ? @@ -101,6 +102,7 @@ public abstract class AbstractProcessor implements Processor { * @return the names of the annotation interfaces supported by * this processor, or an empty set if none */ + @Override public Set getSupportedAnnotationTypes() { SupportedAnnotationTypes sat = this.getClass().getAnnotation(SupportedAnnotationTypes.class); boolean initialized = isInitialized(); @@ -128,6 +130,7 @@ public abstract class AbstractProcessor implements Processor { * * @return the latest source version supported by this processor */ + @Override public SourceVersion getSupportedSourceVersion() { SupportedSourceVersion ssv = this.getClass().getAnnotation(SupportedSourceVersion.class); SourceVersion sv = null; @@ -167,6 +170,7 @@ public abstract class AbstractProcessor implements Processor { /** * {@inheritDoc} */ + @Override public abstract boolean process(Set annotations, RoundEnvironment roundEnv); @@ -178,6 +182,7 @@ public abstract class AbstractProcessor implements Processor { * @param member {@inheritDoc} * @param userText {@inheritDoc} */ + @Override public Iterable getCompletions(Element element, AnnotationMirror annotation, ExecutableElement member, diff --git a/src/java.compiler/share/classes/javax/annotation/processing/Completions.java b/src/java.compiler/share/classes/javax/annotation/processing/Completions.java index 8b7aa291645..5b476afec65 100644 --- a/src/java.compiler/share/classes/javax/annotation/processing/Completions.java +++ b/src/java.compiler/share/classes/javax/annotation/processing/Completions.java @@ -52,7 +52,6 @@ public class Completions { return value; } - public String getMessage() { return message; } -- GitLab From bcbe3845d92e38ad0086cc337dc5957842eef056 Mon Sep 17 00:00:00 2001 From: Gerard Ziemski Date: Mon, 18 Oct 2021 16:24:02 +0000 Subject: [PATCH 241/385] 8269175: [macosx-aarch64] wrong CPU speed in hs_err file Reviewed-by: dholmes, dcubed, stuefe --- src/hotspot/os/bsd/os_bsd.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/hotspot/os/bsd/os_bsd.cpp b/src/hotspot/os/bsd/os_bsd.cpp index c0cbbe94a57..d1adfeb1ddd 100644 --- a/src/hotspot/os/bsd/os_bsd.cpp +++ b/src/hotspot/os/bsd/os_bsd.cpp @@ -1311,13 +1311,17 @@ void os::get_summary_cpu_info(char* buf, size_t buflen) { strncpy(machine, "", sizeof(machine)); } - const char* emulated = ""; #if defined(__APPLE__) && !defined(ZERO) if (VM_Version::is_cpu_emulated()) { - emulated = " (EMULATED)"; + snprintf(buf, buflen, "\"%s\" %s (EMULATED) %d MHz", model, machine, mhz); + } else { + NOT_AARCH64(snprintf(buf, buflen, "\"%s\" %s %d MHz", model, machine, mhz)); + // aarch64 CPU doesn't report its speed + AARCH64_ONLY(snprintf(buf, buflen, "\"%s\" %s", model, machine)); } +#else + snprintf(buf, buflen, "\"%s\" %s %d MHz", model, machine, mhz); #endif - snprintf(buf, buflen, "\"%s\" %s%s %d MHz", model, machine, emulated, mhz); } void os::print_memory_info(outputStream* st) { -- GitLab From 72a976ef05fc2c62657920a560a0abc60b27c852 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20Gr=C3=B6nlund?= Date: Mon, 18 Oct 2021 16:52:36 +0000 Subject: [PATCH 242/385] 8266936: Add a finalization JFR event Reviewed-by: coleenp, mchung, egahlin --- make/data/hotspot-symbols/symbols-unix | 1 + .../share/classfile/systemDictionary.cpp | 3 +- src/hotspot/share/include/jvm.h | 6 + src/hotspot/share/jfr/jni/jfrJavaSupport.cpp | 51 +-- src/hotspot/share/jfr/jni/jfrJavaSupport.hpp | 5 +- src/hotspot/share/jfr/metadata/metadata.xml | 7 + .../periodic/jfrFinalizerStatisticsEvent.cpp | 131 ++++++++ .../periodic/jfrFinalizerStatisticsEvent.hpp | 38 +++ .../share/jfr/periodic/jfrPeriodic.cpp | 14 +- .../recorder/checkpoint/types/jfrTypeSet.cpp | 91 +++-- .../checkpoint/types/jfrTypeSetUtils.cpp | 258 ++------------ .../checkpoint/types/jfrTypeSetUtils.hpp | 112 +------ .../share/jfr/recorder/service/jfrPostBox.cpp | 8 +- .../service/jfrRecorderThreadLoop.cpp | 21 +- .../share/jfr/support/jfrKlassUnloading.cpp | 16 + .../share/jfr/support/jfrSymbolTable.cpp | 316 ++++++++++++++++++ .../share/jfr/support/jfrSymbolTable.hpp | 148 ++++++++ src/hotspot/share/logging/logTag.hpp | 1 + src/hotspot/share/oops/instanceKlass.cpp | 5 +- src/hotspot/share/prims/jvm.cpp | 10 + src/hotspot/share/runtime/mutexLocker.cpp | 5 +- src/hotspot/share/runtime/serviceThread.cpp | 7 + .../share/services/classLoadingService.cpp | 124 ++++--- .../share/services/classLoadingService.hpp | 67 +--- .../share/services/finalizerService.cpp | 313 +++++++++++++++++ .../share/services/finalizerService.hpp | 68 ++++ src/hotspot/share/services/management.cpp | 19 ++ src/hotspot/share/services/management.hpp | 16 +- src/hotspot/share/utilities/macros.hpp | 2 + .../classes/java/lang/ref/Finalizer.java | 3 + .../share/native/libjava/Finalizer.c | 35 ++ src/jdk.jfr/share/conf/jfr/default.jfc | 5 + src/jdk.jfr/share/conf/jfr/profile.jfc | 5 + .../runtime/TestFinalizerStatisticsEvent.java | 129 +++++++ test/lib/jdk/test/lib/jfr/EventNames.java | 1 + .../lib/jdk/test/lib/jfr/TestClassLoader.java | 9 +- 36 files changed, 1508 insertions(+), 542 deletions(-) create mode 100644 src/hotspot/share/jfr/periodic/jfrFinalizerStatisticsEvent.cpp create mode 100644 src/hotspot/share/jfr/periodic/jfrFinalizerStatisticsEvent.hpp create mode 100644 src/hotspot/share/jfr/support/jfrSymbolTable.cpp create mode 100644 src/hotspot/share/jfr/support/jfrSymbolTable.hpp create mode 100644 src/hotspot/share/services/finalizerService.cpp create mode 100644 src/hotspot/share/services/finalizerService.hpp create mode 100644 src/java.base/share/native/libjava/Finalizer.c create mode 100644 test/jdk/jdk/jfr/event/runtime/TestFinalizerStatisticsEvent.java diff --git a/make/data/hotspot-symbols/symbols-unix b/make/data/hotspot-symbols/symbols-unix index a34732739d3..d735f61b3a4 100644 --- a/make/data/hotspot-symbols/symbols-unix +++ b/make/data/hotspot-symbols/symbols-unix @@ -183,6 +183,7 @@ JVM_ReferenceRefersTo JVM_RegisterLambdaProxyClassForArchiving JVM_RegisterSignal JVM_ReleaseUTF +JVM_ReportFinalizationComplete JVM_ResumeThread JVM_SetArrayElement JVM_SetClassSigners diff --git a/src/hotspot/share/classfile/systemDictionary.cpp b/src/hotspot/share/classfile/systemDictionary.cpp index f7484e7d60d..af49f29dcd1 100644 --- a/src/hotspot/share/classfile/systemDictionary.cpp +++ b/src/hotspot/share/classfile/systemDictionary.cpp @@ -76,6 +76,7 @@ #include "runtime/signature.hpp" #include "services/classLoadingService.hpp" #include "services/diagnosticCommand.hpp" +#include "services/finalizerService.hpp" #include "services/threadService.hpp" #include "utilities/macros.hpp" #include "utilities/utf8.hpp" @@ -1600,7 +1601,7 @@ bool SystemDictionary::do_unloading(GCTimer* gc_timer) { if (unloading_occurred) { MutexLocker ml2(is_concurrent ? Module_lock : NULL); JFR_ONLY(Jfr::on_unloading_classes();) - + MANAGEMENT_ONLY(FinalizerService::purge_unloaded();) MutexLocker ml1(is_concurrent ? SystemDictionary_lock : NULL); ClassLoaderDataGraph::clean_module_and_package_info(); constraints()->purge_loader_constraints(); diff --git a/src/hotspot/share/include/jvm.h b/src/hotspot/share/include/jvm.h index 7b80d72b562..00035a68072 100644 --- a/src/hotspot/share/include/jvm.h +++ b/src/hotspot/share/include/jvm.h @@ -753,6 +753,12 @@ JVM_AssertionStatusDirectives(JNIEnv *env, jclass unused); JNIEXPORT jboolean JNICALL JVM_SupportsCX8(void); +/* + * java.lang.ref.Finalizer + */ +JNIEXPORT void JNICALL +JVM_ReportFinalizationComplete(JNIEnv *env, jobject finalizee); + /************************************************************************* PART 2: Support for the Verifier and Class File Format Checker ************************************************************************/ diff --git a/src/hotspot/share/jfr/jni/jfrJavaSupport.cpp b/src/hotspot/share/jfr/jni/jfrJavaSupport.cpp index a02f30d9b52..e24cc620938 100644 --- a/src/hotspot/share/jfr/jni/jfrJavaSupport.cpp +++ b/src/hotspot/share/jfr/jni/jfrJavaSupport.cpp @@ -383,7 +383,7 @@ static void read_specialized_field(JavaValue* result, const Handle& h_oop, field } } -static bool find_field(InstanceKlass* ik, +static bool find_field(const InstanceKlass* ik, Symbol* name_symbol, Symbol* signature_symbol, fieldDescriptor* fd, @@ -395,29 +395,32 @@ static bool find_field(InstanceKlass* ik, return ik->find_local_field(name_symbol, signature_symbol, fd); } -static void lookup_field(JfrJavaArguments* args, InstanceKlass* klass, fieldDescriptor* fd, bool static_field) { +static void lookup_field(JfrJavaArguments* args, const InstanceKlass* ik, fieldDescriptor* fd, bool static_field) { assert(args != NULL, "invariant"); - assert(klass != NULL, "invariant"); - assert(klass->is_initialized(), "invariant"); + assert(ik != NULL, "invariant"); + assert(ik->is_initialized(), "invariant"); assert(fd != NULL, "invariant"); - find_field(klass, args->name(), args->signature(), fd, static_field, true); + find_field(ik, args->name(), args->signature(), fd, static_field, true); +} + +static void read_field(JfrJavaArguments* args, JavaValue* result, Thread* thread) { + const bool static_field = !args->has_receiver(); + fieldDescriptor fd; + const InstanceKlass* const ik = static_cast(args->klass()); + lookup_field(args, ik, &fd, static_field); + assert(fd.offset() > 0, "invariant"); + HandleMark hm(thread); + Handle h_oop(static_field ? Handle(thread, ik->java_mirror()) : Handle(thread, args->receiver())); + read_specialized_field(result, h_oop, &fd); } static void read_field(JfrJavaArguments* args, JavaValue* result, TRAPS) { assert(args != NULL, "invariant"); assert(result != NULL, "invariant"); DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD)); - InstanceKlass* const klass = static_cast(args->klass()); klass->initialize(CHECK); - const bool static_field = !args->has_receiver(); - fieldDescriptor fd; - lookup_field(args, klass, &fd, static_field); - assert(fd.offset() > 0, "invariant"); - - HandleMark hm(THREAD); - Handle h_oop(static_field ? Handle(THREAD, klass->java_mirror()) : Handle(THREAD, args->receiver())); - read_specialized_field(result, h_oop, &fd); + read_field(args, result, static_cast(THREAD)); } static void write_field(JfrJavaArguments* args, JavaValue* result, TRAPS) { @@ -448,6 +451,11 @@ void JfrJavaSupport::get_field(JfrJavaArguments* args, TRAPS) { read_field(args, args->result(), THREAD); } +void JfrJavaSupport::get_field(JfrJavaArguments* args, Thread* thread) { + assert(args != NULL, "invariant"); + read_field(args, args->result(), thread); +} + void JfrJavaSupport::get_field_local_ref(JfrJavaArguments* args, TRAPS) { assert(args != NULL, "invariant"); DEBUG_ONLY(check_java_thread_in_vm(THREAD)); @@ -487,20 +495,18 @@ Klass* JfrJavaSupport::klass(const jobject handle) { return obj->klass(); } -static char* allocate_string(bool c_heap, int length, JavaThread* jt) { +static char* allocate_string(bool c_heap, int length, Thread* thread) { return c_heap ? NEW_C_HEAP_ARRAY(char, length, mtTracing) : - NEW_RESOURCE_ARRAY_IN_THREAD(jt, char, length); + NEW_RESOURCE_ARRAY_IN_THREAD(thread, char, length); } -const char* JfrJavaSupport::c_str(oop string, JavaThread* t, bool c_heap /* false */) { - DEBUG_ONLY(check_java_thread_in_vm(t)); +const char* JfrJavaSupport::c_str(oop string, Thread* thread, bool c_heap /* false */) { char* str = NULL; const typeArrayOop value = java_lang_String::value(string); if (value != NULL) { const int length = java_lang_String::utf8_length(string, value); - str = allocate_string(c_heap, length + 1, t); + str = allocate_string(c_heap, length + 1, thread); if (str == NULL) { - JfrJavaSupport::throw_out_of_memory_error("Unable to allocate native memory", t); return NULL; } java_lang_String::as_utf8_string(string, value, str, length + 1); @@ -508,9 +514,8 @@ const char* JfrJavaSupport::c_str(oop string, JavaThread* t, bool c_heap /* fals return str; } -const char* JfrJavaSupport::c_str(jstring string, JavaThread* t, bool c_heap /* false */) { - DEBUG_ONLY(check_java_thread_in_vm(t)); - return string != NULL ? c_str(resolve_non_null(string), t, c_heap) : NULL; +const char* JfrJavaSupport::c_str(jstring string, Thread* thread, bool c_heap /* false */) { + return string != NULL ? c_str(resolve_non_null(string), thread, c_heap) : NULL; } /* diff --git a/src/hotspot/share/jfr/jni/jfrJavaSupport.hpp b/src/hotspot/share/jfr/jni/jfrJavaSupport.hpp index 6a2f200322c..ca97d90dd78 100644 --- a/src/hotspot/share/jfr/jni/jfrJavaSupport.hpp +++ b/src/hotspot/share/jfr/jni/jfrJavaSupport.hpp @@ -56,6 +56,7 @@ class JfrJavaSupport : public AllStatic { static void set_field(JfrJavaArguments* args, TRAPS); static void get_field(JfrJavaArguments* args, TRAPS); + static void get_field(JfrJavaArguments* args, Thread* thread); static void new_object(JfrJavaArguments* args, TRAPS); // global jni handle result @@ -75,8 +76,8 @@ class JfrJavaSupport : public AllStatic { // misc static Klass* klass(const jobject handle); - static const char* c_str(jstring string, JavaThread* jt, bool c_heap = false); - static const char* c_str(oop string, JavaThread* jt, bool c_heap = false); + static const char* c_str(jstring string, Thread* thread, bool c_heap = false); + static const char* c_str(oop string, Thread* thread, bool c_heap = false); // exceptions static void throw_illegal_state_exception(const char* message, TRAPS); diff --git a/src/hotspot/share/jfr/metadata/metadata.xml b/src/hotspot/share/jfr/metadata/metadata.xml index 1a19b763314..6a1f426785c 100644 --- a/src/hotspot/share/jfr/metadata/metadata.xml +++ b/src/hotspot/share/jfr/metadata/metadata.xml @@ -1081,6 +1081,13 @@ + + + + + + + diff --git a/src/hotspot/share/jfr/periodic/jfrFinalizerStatisticsEvent.cpp b/src/hotspot/share/jfr/periodic/jfrFinalizerStatisticsEvent.cpp new file mode 100644 index 00000000000..7404b8aa56c --- /dev/null +++ b/src/hotspot/share/jfr/periodic/jfrFinalizerStatisticsEvent.cpp @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 "utilities/macros.hpp" +#if INCLUDE_MANAGEMENT +#include "classfile/classLoaderDataGraph.hpp" +#include "classfile/javaClasses.inline.hpp" +#include "jfr/jfrEvents.hpp" +#include "jfr/jni/jfrJavaSupport.hpp" +#include "jfr/periodic/jfrFinalizerStatisticsEvent.hpp" +#include "jfr/support/jfrSymbolTable.hpp" +#include "jfr/utilities/jfrTime.hpp" +#include "jfr/utilities/jfrTypes.hpp" +#include "oops/instanceKlass.inline.hpp" +#include "runtime/mutexLocker.hpp" +#include "runtime/thread.inline.hpp" +#include "services/finalizerService.hpp" + +static oop get_codesource(oop pd, Thread* thread) { + assert(pd != NULL, "invariant"); + assert(thread != NULL, "invariant"); + JavaValue result(T_OBJECT); + JfrJavaArguments args(&result); + args.set_klass(pd->klass()); + args.set_name("codesource"); + args.set_signature("Ljava/security/CodeSource;"); + args.set_receiver(pd); + JfrJavaSupport::get_field(&args, thread); + return result.get_oop(); +} + +// Caller needs ResourceMark +static const char* get_locationNoFragString(oop codesource, Thread* thread) { + assert(codesource != NULL, "invariant"); + assert(thread != NULL, "invariant"); + JavaValue result(T_OBJECT); + JfrJavaArguments args(&result); + args.set_klass(codesource->klass()); + args.set_name("locationNoFragString"); + args.set_signature("Ljava/lang/String;"); + args.set_receiver(codesource); + JfrJavaSupport::get_field(&args, thread); + const oop string_oop = result.get_oop(); + return string_oop != NULL ? JfrJavaSupport::c_str(string_oop, thread) : NULL; +} + +// Caller needs ResourceMark +static const char* codesource(const InstanceKlass* ik, Thread* thread) { + assert(ik != NULL, "invariant"); + assert(thread != NULL, "invariant"); + oop pd = java_lang_Class::protection_domain(ik->java_mirror()); + if (pd == NULL) { + return NULL; + } + oop codesource = get_codesource(pd, thread); + return codesource != NULL ? get_locationNoFragString(codesource, thread) : NULL; +} + +static void send_event(const FinalizerEntry* fe, const InstanceKlass* ik, const JfrTicks& timestamp, Thread* thread) { + assert(ik != NULL, "invariant"); + assert(ik->has_finalizer(), "invariant"); + assert(thread != NULL, "invariant"); + const char* const url = codesource(ik, thread); + const traceid url_symbol_id = url != NULL ? JfrSymbolTable::add(url) : 0; + EventFinalizerStatistics event(UNTIMED); + event.set_endtime(timestamp); + event.set_finalizableClass(ik); + event.set_codeSource(url_symbol_id); + if (fe == NULL) { + event.set_objects(0); + event.set_totalFinalizersRun(0); + } else { + assert(fe->klass() == ik, "invariant"); + event.set_objects(fe->objects_on_heap()); + event.set_totalFinalizersRun(fe->total_finalizers_run()); + } + event.commit(); +} + +void JfrFinalizerStatisticsEvent::send_unload_event(const InstanceKlass* ik) { + Thread* const thread = Thread::current(); + ResourceMark rm(thread); + send_event(FinalizerService::lookup(ik, thread), ik, JfrTicks::now(), thread); +} + +// Finalizer events generated by the periodic task will all have the same timestamp. + +class FinalizerStatisticsEventClosure : public FinalizerEntryClosure { + private: + Thread* _thread; + const JfrTicks _timestamp; + public: + FinalizerStatisticsEventClosure(Thread* thread) : _thread(thread), _timestamp(JfrTicks::now()) {} + virtual bool do_entry(const FinalizerEntry* fe) { + assert(fe != NULL, "invariant"); + send_event(fe, fe->klass(), _timestamp, _thread); + return true; + } +}; + +void JfrFinalizerStatisticsEvent::generate_events() { + Thread* const thread = Thread::current(); + ResourceMark rm(thread); + FinalizerStatisticsEventClosure fsec(thread); + MutexLocker lock(ClassLoaderDataGraph_lock); // To prevent entries from being removed by class unloading. + FinalizerService::do_entries(&fsec, thread); +} + +#endif // INCLUDE_MANAGEMENT diff --git a/src/hotspot/share/jfr/periodic/jfrFinalizerStatisticsEvent.hpp b/src/hotspot/share/jfr/periodic/jfrFinalizerStatisticsEvent.hpp new file mode 100644 index 00000000000..fe739495718 --- /dev/null +++ b/src/hotspot/share/jfr/periodic/jfrFinalizerStatisticsEvent.hpp @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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_JFR_PERIODIC_JFRFINALIZERSTATISTICSEVENT_HPP +#define SHARE_JFR_PERIODIC_JFRFINALIZERSTATISTICSEVENT_HPP + +#include "memory/allocation.hpp" + +class InstanceKlass; + +class JfrFinalizerStatisticsEvent : AllStatic { + public: + static void send_unload_event(const InstanceKlass* ik) NOT_MANAGEMENT_RETURN; + static void generate_events() NOT_MANAGEMENT_RETURN; +}; + +#endif // SHARE_JFR_PERIODIC_JFRFINALIZERSTATISTICSEVENT_HPP diff --git a/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp index 905f1e53ac0..5b0ce8e2328 100644 --- a/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp +++ b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp @@ -37,6 +37,7 @@ #include "gc/shared/gcVMOperations.hpp" #include "gc/shared/objectCountEventSender.hpp" #include "jfr/jfrEvents.hpp" +#include "jfr/periodic/jfrFinalizerStatisticsEvent.hpp" #include "jfr/periodic/jfrModuleEvent.hpp" #include "jfr/periodic/jfrOSInterface.hpp" #include "jfr/periodic/jfrThreadCPULoadEvent.hpp" @@ -472,10 +473,14 @@ TRACE_REQUEST_FUNC(JavaThreadStatistics) { } TRACE_REQUEST_FUNC(ClassLoadingStatistics) { +#if INCLUDE_MANAGEMENT EventClassLoadingStatistics event; event.set_loadedClassCount(ClassLoadingService::loaded_class_count()); event.set_unloadedClassCount(ClassLoadingService::unloaded_class_count()); event.commit(); +#else + log_debug(jfr, system)("Unable to generate requestable event ClassLoadingStatistics. The required jvm feature 'management' is missing."); +#endif } class JfrClassLoaderStatsClosure : public ClassLoaderStatsClosure { @@ -635,7 +640,6 @@ TRACE_REQUEST_FUNC(CodeSweeperConfiguration) { event.commit(); } - TRACE_REQUEST_FUNC(ShenandoahHeapRegionInformation) { #if INCLUDE_SHENANDOAHGC if (UseShenandoahGC) { @@ -644,3 +648,11 @@ TRACE_REQUEST_FUNC(ShenandoahHeapRegionInformation) { } #endif } + +TRACE_REQUEST_FUNC(FinalizerStatistics) { +#if INCLUDE_MANAGEMENT + JfrFinalizerStatisticsEvent::generate_events(); +#else + log_debug(jfr, system)("Unable to generate requestable event FinalizerStatistics. The required jvm feature 'management' is missing."); +#endif +} diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp index 0d338187775..fb593adb8a8 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp @@ -55,8 +55,8 @@ typedef const ModuleEntry* ModPtr; typedef const ClassLoaderData* CldPtr; typedef const Method* MethodPtr; typedef const Symbol* SymbolPtr; -typedef const JfrSymbolId::SymbolEntry* SymbolEntryPtr; -typedef const JfrSymbolId::CStringEntry* CStringEntryPtr; +typedef const JfrSymbolTable::SymbolEntry* SymbolEntryPtr; +typedef const JfrSymbolTable::StringEntry* StringEntryPtr; static JfrCheckpointWriter* _writer = NULL; static JfrCheckpointWriter* _leakp_writer = NULL; @@ -64,18 +64,7 @@ static JfrArtifactSet* _artifacts = NULL; static JfrArtifactClosure* _subsystem_callback = NULL; static bool _class_unload = false; static bool _flushpoint = false; -static bool _clear_artifacts = false; - -// incremented on each rotation -static u8 checkpoint_id = 1; - -// creates a unique id by combining a checkpoint relative symbol id (2^24) -// with the current checkpoint id (2^40) -#define CREATE_SYMBOL_ID(sym_id) (((u8)((checkpoint_id << 24) | sym_id))) - -static traceid create_symbol_id(traceid artifact_id) { - return artifact_id != 0 ? CREATE_SYMBOL_ID(artifact_id) : 0; -} +static bool _initial_type_set = true; static bool current_epoch() { return _class_unload || _flushpoint; @@ -86,7 +75,7 @@ static bool previous_epoch() { } static bool is_initial_typeset_for_chunk() { - return _clear_artifacts && !_class_unload; + return _initial_type_set && !_class_unload; } static bool is_complete() { @@ -94,15 +83,15 @@ static bool is_complete() { } static traceid mark_symbol(KlassPtr klass, bool leakp) { - return klass != NULL ? create_symbol_id(_artifacts->mark(klass, leakp)) : 0; + return klass != NULL ? _artifacts->mark(klass, leakp) : 0; } static traceid mark_symbol(Symbol* symbol, bool leakp) { - return symbol != NULL ? create_symbol_id(_artifacts->mark(symbol, leakp)) : 0; + return symbol != NULL ? _artifacts->mark(symbol, leakp) : 0; } static traceid get_bootstrap_name(bool leakp) { - return create_symbol_id(_artifacts->bootstrap_name(leakp)); + return _artifacts->bootstrap_name(leakp); } static const char* primitive_name(KlassPtr type_array_klass) { @@ -924,14 +913,14 @@ static void write_methods() { } template <> -void set_serialized(SymbolEntryPtr ptr) { +void set_serialized(SymbolEntryPtr ptr) { assert(ptr != NULL, "invariant"); ptr->set_serialized(); assert(ptr->is_serialized(), "invariant"); } template <> -void set_serialized(CStringEntryPtr ptr) { +void set_serialized(StringEntryPtr ptr) { assert(ptr != NULL, "invariant"); ptr->set_serialized(); assert(ptr->is_serialized(), "invariant"); @@ -941,7 +930,7 @@ static int write_symbol(JfrCheckpointWriter* writer, SymbolEntryPtr entry, bool assert(writer != NULL, "invariant"); assert(entry != NULL, "invariant"); ResourceMark rm; - writer->write(create_symbol_id(entry->id())); + writer->write(entry->id()); writer->write(entry->value()->as_C_string()); return 1; } @@ -959,42 +948,42 @@ int write__symbol__leakp(JfrCheckpointWriter* writer, const void* e) { return write_symbol(writer, entry, true); } -static int write_cstring(JfrCheckpointWriter* writer, CStringEntryPtr entry, bool leakp) { +static int write_string(JfrCheckpointWriter* writer, StringEntryPtr entry, bool leakp) { assert(writer != NULL, "invariant"); assert(entry != NULL, "invariant"); - writer->write(create_symbol_id(entry->id())); + writer->write(entry->id()); writer->write(entry->value()); return 1; } -int write__cstring(JfrCheckpointWriter* writer, const void* e) { +int write__string(JfrCheckpointWriter* writer, const void* e) { assert(e != NULL, "invariant"); - CStringEntryPtr entry = (CStringEntryPtr)e; + StringEntryPtr entry = (StringEntryPtr)e; set_serialized(entry); - return write_cstring(writer, entry, false); + return write_string(writer, entry, false); } -int write__cstring__leakp(JfrCheckpointWriter* writer, const void* e) { +int write__string__leakp(JfrCheckpointWriter* writer, const void* e) { assert(e != NULL, "invariant"); - CStringEntryPtr entry = (CStringEntryPtr)e; - return write_cstring(writer, entry, true); + StringEntryPtr entry = (StringEntryPtr)e; + return write_string(writer, entry, true); } typedef SymbolPredicate SymPredicate; typedef JfrPredicatedTypeWriterImplHost SymbolEntryWriterImpl; typedef JfrTypeWriterHost SymbolEntryWriter; -typedef SymbolPredicate CStringPredicate; -typedef JfrPredicatedTypeWriterImplHost CStringEntryWriterImpl; -typedef JfrTypeWriterHost CStringEntryWriter; +typedef SymbolPredicate StringPredicate; +typedef JfrPredicatedTypeWriterImplHost StringEntryWriterImpl; +typedef JfrTypeWriterHost StringEntryWriter; typedef SymbolPredicate LeakSymPredicate; typedef JfrPredicatedTypeWriterImplHost LeakSymbolEntryWriterImpl; typedef JfrTypeWriterHost LeakSymbolEntryWriter; typedef CompositeFunctor CompositeSymbolWriter; -typedef SymbolPredicate LeakCStringPredicate; -typedef JfrPredicatedTypeWriterImplHost LeakCStringEntryWriterImpl; -typedef JfrTypeWriterHost LeakCStringEntryWriter; -typedef CompositeFunctor CompositeCStringWriter; +typedef SymbolPredicate LeakStringPredicate; +typedef JfrPredicatedTypeWriterImplHost LeakStringEntryWriterImpl; +typedef JfrTypeWriterHost LeakStringEntryWriter; +typedef CompositeFunctor CompositeStringWriter; static void write_symbols_with_leakp() { assert(_leakp_writer != NULL, "invariant"); @@ -1002,12 +991,12 @@ static void write_symbols_with_leakp() { LeakSymbolEntryWriter lsw(_leakp_writer, _class_unload); CompositeSymbolWriter csw(&lsw, &sw); _artifacts->iterate_symbols(csw); - CStringEntryWriter ccsw(_writer, _class_unload, true); // skip header - LeakCStringEntryWriter lccsw(_leakp_writer, _class_unload, true); // skip header - CompositeCStringWriter cccsw(&lccsw, &ccsw); - _artifacts->iterate_cstrings(cccsw); - sw.add(ccsw.count()); - lsw.add(lccsw.count()); + StringEntryWriter sew(_writer, _class_unload, true); // skip header + LeakStringEntryWriter lsew(_leakp_writer, _class_unload, true); // skip header + CompositeStringWriter csew(&lsew, &sew); + _artifacts->iterate_strings(csew); + sw.add(sew.count()); + lsw.add(lsew.count()); _artifacts->tally(sw); } @@ -1019,9 +1008,9 @@ static void write_symbols() { } SymbolEntryWriter sw(_writer, _class_unload); _artifacts->iterate_symbols(sw); - CStringEntryWriter csw(_writer, _class_unload, true); // skip header - _artifacts->iterate_cstrings(csw); - sw.add(csw.count()); + StringEntryWriter sew(_writer, _class_unload, true); // skip header + _artifacts->iterate_strings(sew); + sw.add(sew.count()); _artifacts->tally(sw); } @@ -1040,10 +1029,10 @@ static size_t teardown() { if (previous_epoch()) { clear_klasses_and_methods(); JfrKlassUnloading::clear(); - _clear_artifacts = true; - ++checkpoint_id; + _artifacts->increment_checkpoint_id(); + _initial_type_set = true; } else { - _clear_artifacts = false; + _initial_type_set = false; } return total_count; } @@ -1056,7 +1045,7 @@ static void setup(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer if (_artifacts == NULL) { _artifacts = new JfrArtifactSet(class_unload); } else { - _artifacts->initialize(class_unload, _clear_artifacts); + _artifacts->initialize(class_unload); } if (!_class_unload) { JfrKlassUnloading::sort(previous_epoch()); @@ -1091,7 +1080,9 @@ size_t JfrTypeSet::serialize(JfrCheckpointWriter* writer, JfrCheckpointWriter* l void JfrTypeSet::clear() { ResourceMark rm; JfrKlassUnloading::clear(); - _clear_artifacts = true; + if (_artifacts != NULL) { + _artifacts->clear(); + } setup(NULL, NULL, false, false); register_klasses(); clear_packages(); diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.cpp b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.cpp index 5eb70fb23d2..19a9fa7516b 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.cpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.cpp @@ -30,225 +30,7 @@ #include "oops/oop.inline.hpp" #include "oops/symbol.hpp" -static JfrSymbolId::CStringEntry* bootstrap = NULL; - -JfrSymbolId::JfrSymbolId() : - _sym_table(new SymbolTable(this)), - _cstring_table(new CStringTable(this)), - _sym_list(NULL), - _cstring_list(NULL), - _sym_query(NULL), - _cstring_query(NULL), - _symbol_id_counter(1), - _class_unload(false) { - assert(_sym_table != NULL, "invariant"); - assert(_cstring_table != NULL, "invariant"); - bootstrap = new CStringEntry(0, (const char*)&BOOTSTRAP_LOADER_NAME); - assert(bootstrap != NULL, "invariant"); - bootstrap->set_id(1); - _cstring_list = bootstrap; -} - -JfrSymbolId::~JfrSymbolId() { - clear(); - delete _sym_table; - delete _cstring_table; - delete bootstrap; -} - -void JfrSymbolId::clear() { - assert(_sym_table != NULL, "invariant"); - if (_sym_table->has_entries()) { - _sym_table->clear_entries(); - } - assert(!_sym_table->has_entries(), "invariant"); - - assert(_cstring_table != NULL, "invariant"); - if (_cstring_table->has_entries()) { - _cstring_table->clear_entries(); - } - assert(!_cstring_table->has_entries(), "invariant"); - - _sym_list = NULL; - _symbol_id_counter = 1; - - _sym_query = NULL; - _cstring_query = NULL; - - assert(bootstrap != NULL, "invariant"); - bootstrap->reset(); - _cstring_list = bootstrap; -} - -void JfrSymbolId::set_class_unload(bool class_unload) { - _class_unload = class_unload; -} - -void JfrSymbolId::on_link(const SymbolEntry* entry) { - assert(entry != NULL, "invariant"); - const_cast(entry->literal())->increment_refcount(); - assert(entry->id() == 0, "invariant"); - entry->set_id(++_symbol_id_counter); - entry->set_list_next(_sym_list); - _sym_list = entry; -} - -bool JfrSymbolId::on_equals(uintptr_t hash, const SymbolEntry* entry) { - assert(entry != NULL, "invariant"); - assert(entry->hash() == hash, "invariant"); - assert(_sym_query != NULL, "invariant"); - return _sym_query == entry->literal(); -} - -void JfrSymbolId::on_unlink(const SymbolEntry* entry) { - assert(entry != NULL, "invariant"); - const_cast(entry->literal())->decrement_refcount(); -} - -static const char* resource_to_cstring(const char* resource_str) { - assert(resource_str != NULL, "invariant"); - const size_t length = strlen(resource_str); - char* const c_string = JfrCHeapObj::new_array(length + 1); - assert(c_string != NULL, "invariant"); - strncpy(c_string, resource_str, length + 1); - return c_string; -} - -void JfrSymbolId::on_link(const CStringEntry* entry) { - assert(entry != NULL, "invariant"); - assert(entry->id() == 0, "invariant"); - entry->set_id(++_symbol_id_counter); - const_cast(entry)->set_literal(resource_to_cstring(entry->literal())); - entry->set_list_next(_cstring_list); - _cstring_list = entry; -} - -static bool string_compare(const char* query, const char* candidate) { - assert(query != NULL, "invariant"); - assert(candidate != NULL, "invariant"); - const size_t length = strlen(query); - return strncmp(query, candidate, length) == 0; -} - -bool JfrSymbolId::on_equals(uintptr_t hash, const CStringEntry* entry) { - assert(entry != NULL, "invariant"); - assert(entry->hash() == hash, "invariant"); - assert(_cstring_query != NULL, "invariant"); - return string_compare(_cstring_query, entry->literal()); -} - -void JfrSymbolId::on_unlink(const CStringEntry* entry) { - assert(entry != NULL, "invariant"); - JfrCHeapObj::free(const_cast(entry->literal()), strlen(entry->literal() + 1)); -} - -traceid JfrSymbolId::bootstrap_name(bool leakp) { - assert(bootstrap != NULL, "invariant"); - if (leakp) { - bootstrap->set_leakp(); - } - return 1; -} - -traceid JfrSymbolId::mark(const Symbol* symbol, bool leakp) { - assert(symbol != NULL, "invariant"); - return mark((uintptr_t)symbol->identity_hash(), symbol, leakp); -} - -traceid JfrSymbolId::mark(uintptr_t hash, const Symbol* data, bool leakp) { - assert(data != NULL, "invariant"); - assert(_sym_table != NULL, "invariant"); - _sym_query = data; - const SymbolEntry& entry = _sym_table->lookup_put(hash, data); - if (_class_unload) { - entry.set_unloading(); - } - if (leakp) { - entry.set_leakp(); - } - return entry.id(); -} - -traceid JfrSymbolId::mark(uintptr_t hash, const char* str, bool leakp) { - assert(str != NULL, "invariant"); - assert(_cstring_table != NULL, "invariant"); - _cstring_query = str; - const CStringEntry& entry = _cstring_table->lookup_put(hash, str); - if (_class_unload) { - entry.set_unloading(); - } - if (leakp) { - entry.set_leakp(); - } - return entry.id(); -} - -/* -* hidden classes symbol is the external name + -* the address of its InstanceKlass slash appended: -* java.lang.invoke.LambdaForm$BMH/22626602 -* -* caller needs ResourceMark -*/ - -uintptr_t JfrSymbolId::hidden_klass_name_hash(const InstanceKlass* ik) { - assert(ik != NULL, "invariant"); - assert(ik->is_hidden(), "invariant"); - const oop mirror = ik->java_mirror_no_keepalive(); - assert(mirror != NULL, "invariant"); - return (uintptr_t)mirror->identity_hash(); -} - -static const char* create_hidden_klass_symbol(const InstanceKlass* ik, uintptr_t hash) { - assert(ik != NULL, "invariant"); - assert(ik->is_hidden(), "invariant"); - assert(hash != 0, "invariant"); - char* hidden_symbol = NULL; - const oop mirror = ik->java_mirror_no_keepalive(); - assert(mirror != NULL, "invariant"); - char hash_buf[40]; - sprintf(hash_buf, "/" UINTX_FORMAT, hash); - const size_t hash_len = strlen(hash_buf); - const size_t result_len = ik->name()->utf8_length(); - hidden_symbol = NEW_RESOURCE_ARRAY(char, result_len + hash_len + 1); - ik->name()->as_klass_external_name(hidden_symbol, (int)result_len + 1); - assert(strlen(hidden_symbol) == result_len, "invariant"); - strcpy(hidden_symbol + result_len, hash_buf); - assert(strlen(hidden_symbol) == result_len + hash_len, "invariant"); - return hidden_symbol; -} - -bool JfrSymbolId::is_hidden_klass(const Klass* k) { - assert(k != NULL, "invariant"); - return k->is_instance_klass() && ((const InstanceKlass*)k)->is_hidden(); -} - -traceid JfrSymbolId::mark_hidden_klass_name(const InstanceKlass* ik, bool leakp) { - assert(ik != NULL, "invariant"); - assert(ik->is_hidden(), "invariant"); - const uintptr_t hash = hidden_klass_name_hash(ik); - const char* const hidden_symbol = create_hidden_klass_symbol(ik, hash); - return mark(hash, hidden_symbol, leakp); -} - -traceid JfrSymbolId::mark(const Klass* k, bool leakp) { - assert(k != NULL, "invariant"); - traceid symbol_id = 0; - if (is_hidden_klass(k)) { - assert(k->is_instance_klass(), "invariant"); - symbol_id = mark_hidden_klass_name((const InstanceKlass*)k, leakp); - } - if (0 == symbol_id) { - Symbol* const sym = k->name(); - if (sym != NULL) { - symbol_id = mark(sym, leakp); - } - } - assert(symbol_id > 0, "a symbol handler must mark the symbol for writing"); - return symbol_id; -} - -JfrArtifactSet::JfrArtifactSet(bool class_unload) : _symbol_id(new JfrSymbolId()), +JfrArtifactSet::JfrArtifactSet(bool class_unload) : _symbol_table(NULL), _klass_list(NULL), _total_count(0) { initialize(class_unload); @@ -258,47 +40,53 @@ JfrArtifactSet::JfrArtifactSet(bool class_unload) : _symbol_id(new JfrSymbolId() static const size_t initial_klass_list_size = 256; const int initial_klass_loader_set_size = 64; -void JfrArtifactSet::initialize(bool class_unload, bool clear /* false */) { - assert(_symbol_id != NULL, "invariant"); - if (clear) { - _symbol_id->clear(); +void JfrArtifactSet::initialize(bool class_unload) { + if (_symbol_table == NULL) { + _symbol_table = JfrSymbolTable::create(); + assert(_symbol_table != NULL, "invariant"); } - _symbol_id->set_class_unload(class_unload); + assert(_symbol_table != NULL, "invariant"); + _symbol_table->set_class_unload(class_unload); _total_count = 0; // resource allocation _klass_list = new GrowableArray(initial_klass_list_size); _klass_loader_set = new GrowableArray(initial_klass_loader_set_size); } +void JfrArtifactSet::clear() { + if (_symbol_table != NULL) { + _symbol_table->clear(); + } +} + JfrArtifactSet::~JfrArtifactSet() { - _symbol_id->clear(); - delete _symbol_id; + delete _symbol_table; // _klass_list and _klass_loader_list will be cleared by a ResourceMark } traceid JfrArtifactSet::bootstrap_name(bool leakp) { - return _symbol_id->bootstrap_name(leakp); + return _symbol_table->bootstrap_name(leakp); } traceid JfrArtifactSet::mark_hidden_klass_name(const Klass* klass, bool leakp) { assert(klass->is_instance_klass(), "invariant"); - return _symbol_id->mark_hidden_klass_name((const InstanceKlass*)klass, leakp); + return _symbol_table->mark_hidden_klass_name((const InstanceKlass*)klass, leakp); } traceid JfrArtifactSet::mark(uintptr_t hash, const Symbol* sym, bool leakp) { - return _symbol_id->mark(hash, sym, leakp); + return _symbol_table->mark(hash, sym, leakp); } traceid JfrArtifactSet::mark(const Klass* klass, bool leakp) { - return _symbol_id->mark(klass, leakp); + return _symbol_table->mark(klass, leakp); } traceid JfrArtifactSet::mark(const Symbol* symbol, bool leakp) { - return _symbol_id->mark(symbol, leakp); + return _symbol_table->mark(symbol, leakp); } traceid JfrArtifactSet::mark(uintptr_t hash, const char* const str, bool leakp) { - return _symbol_id->mark(hash, str, leakp); + return _symbol_table->mark(hash, str, leakp); } bool JfrArtifactSet::has_klass_entries() const { @@ -324,3 +112,9 @@ void JfrArtifactSet::register_klass(const Klass* k) { size_t JfrArtifactSet::total_count() const { return _total_count; } + +void JfrArtifactSet::increment_checkpoint_id() { + assert(_symbol_table != NULL, "invariant"); + _symbol_table->increment_checkpoint_id(); +} + diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp index b93d1673b72..5b33bfd3266 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp @@ -26,8 +26,8 @@ #define SHARE_JFR_RECORDER_CHECKPOINT_TYPES_JFRTYPESETUTILS_HPP #include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp" +#include "jfr/support/jfrSymbolTable.hpp" #include "jfr/utilities/jfrAllocation.hpp" -#include "jfr/utilities/jfrHashtable.hpp" #include "oops/klass.hpp" #include "oops/method.hpp" @@ -191,98 +191,6 @@ class LeakPredicate { } }; -template -class ListEntry : public JfrHashtableEntry { - public: - ListEntry(uintptr_t hash, const T& data) : JfrHashtableEntry(hash, data), - _list_next(NULL), _serialized(false), _unloading(false), _leakp(false) {} - const ListEntry* list_next() const { return _list_next; } - void reset() const { - _list_next = NULL; _serialized = false; _unloading = false; _leakp = false; - } - void set_list_next(const ListEntry* next) const { _list_next = next; } - bool is_serialized() const { return _serialized; } - void set_serialized() const { _serialized = true; } - bool is_unloading() const { return _unloading; } - void set_unloading() const { _unloading = true; } - bool is_leakp() const { return _leakp; } - void set_leakp() const { _leakp = true; } - private: - mutable const ListEntry* _list_next; - mutable bool _serialized; - mutable bool _unloading; - mutable bool _leakp; -}; - -class JfrSymbolId : public JfrCHeapObj { - template class, typename, size_t> - friend class HashTableHost; - typedef HashTableHost SymbolTable; - typedef HashTableHost CStringTable; - friend class JfrArtifactSet; - public: - typedef SymbolTable::HashEntry SymbolEntry; - typedef CStringTable::HashEntry CStringEntry; - private: - SymbolTable* _sym_table; - CStringTable* _cstring_table; - const SymbolEntry* _sym_list; - const CStringEntry* _cstring_list; - const Symbol* _sym_query; - const char* _cstring_query; - traceid _symbol_id_counter; - bool _class_unload; - - // hashtable(s) callbacks - void on_link(const SymbolEntry* entry); - bool on_equals(uintptr_t hash, const SymbolEntry* entry); - void on_unlink(const SymbolEntry* entry); - void on_link(const CStringEntry* entry); - bool on_equals(uintptr_t hash, const CStringEntry* entry); - void on_unlink(const CStringEntry* entry); - - template - void iterate(Functor& functor, const T* list) { - const T* symbol = list; - while (symbol != NULL) { - const T* next = symbol->list_next(); - functor(symbol); - symbol = next; - } - } - - traceid mark_hidden_klass_name(const InstanceKlass* k, bool leakp); - bool is_hidden_klass(const Klass* k); - uintptr_t hidden_klass_name_hash(const InstanceKlass* ik); - - public: - JfrSymbolId(); - ~JfrSymbolId(); - - void clear(); - void set_class_unload(bool class_unload); - - traceid mark(uintptr_t hash, const Symbol* sym, bool leakp); - traceid mark(const Klass* k, bool leakp); - traceid mark(const Symbol* symbol, bool leakp); - traceid mark(uintptr_t hash, const char* str, bool leakp); - traceid bootstrap_name(bool leakp); - - template - void iterate_symbols(Functor& functor) { - iterate(functor, _sym_list); - } - - template - void iterate_cstrings(Functor& functor) { - iterate(functor, _cstring_list); - } - - bool has_entries() const { return has_symbol_entries() || has_cstring_entries(); } - bool has_symbol_entries() const { return _sym_list != NULL; } - bool has_cstring_entries() const { return _cstring_list != NULL; } -}; - /** * When processing a set of artifacts, there will be a need * to track transitive dependencies originating with each artifact. @@ -299,7 +207,7 @@ class JfrSymbolId : public JfrCHeapObj { */ class JfrArtifactSet : public JfrCHeapObj { private: - JfrSymbolId* _symbol_id; + JfrSymbolTable* _symbol_table; GrowableArray* _klass_list; GrowableArray* _klass_loader_set; size_t _total_count; @@ -309,7 +217,8 @@ class JfrArtifactSet : public JfrCHeapObj { ~JfrArtifactSet(); // caller needs ResourceMark - void initialize(bool class_unload, bool clear = false); + void initialize(bool class_unload); + void clear(); traceid mark(uintptr_t hash, const Symbol* sym, bool leakp); traceid mark(const Klass* klass, bool leakp); @@ -318,15 +227,16 @@ class JfrArtifactSet : public JfrCHeapObj { traceid mark_hidden_klass_name(const Klass* klass, bool leakp); traceid bootstrap_name(bool leakp); - const JfrSymbolId::SymbolEntry* map_symbol(const Symbol* symbol) const; - const JfrSymbolId::SymbolEntry* map_symbol(uintptr_t hash) const; - const JfrSymbolId::CStringEntry* map_cstring(uintptr_t hash) const; + const JfrSymbolTable::SymbolEntry* map_symbol(const Symbol* symbol) const; + const JfrSymbolTable::SymbolEntry* map_symbol(uintptr_t hash) const; + const JfrSymbolTable::StringEntry* map_string(uintptr_t hash) const; bool has_klass_entries() const; int entries() const; size_t total_count() const; void register_klass(const Klass* k); bool should_do_loader_klass(const Klass* k); + void increment_checkpoint_id(); template void iterate_klasses(Functor& functor) const { @@ -339,12 +249,12 @@ class JfrArtifactSet : public JfrCHeapObj { template void iterate_symbols(T& functor) { - _symbol_id->iterate_symbols(functor); + _symbol_table->iterate_symbols(functor); } template - void iterate_cstrings(T& functor) { - _symbol_id->iterate_cstrings(functor); + void iterate_strings(T& functor) { + _symbol_table->iterate_strings(functor); } template diff --git a/src/hotspot/share/jfr/recorder/service/jfrPostBox.cpp b/src/hotspot/share/jfr/recorder/service/jfrPostBox.cpp index 43838e815ee..4001e51f5b0 100644 --- a/src/hotspot/share/jfr/recorder/service/jfrPostBox.cpp +++ b/src/hotspot/share/jfr/recorder/service/jfrPostBox.cpp @@ -26,6 +26,8 @@ #include "jfr/recorder/service/jfrPostBox.hpp" #include "jfr/utilities/jfrTryLock.hpp" #include "runtime/atomic.hpp" +#include "runtime/handles.hpp" +#include "runtime/interfaceSupport.inline.hpp" #include "runtime/thread.inline.hpp" #define MSG_IS_SYNCHRONOUS ( (MSGBIT(MSG_ROTATE)) | \ @@ -110,7 +112,9 @@ void JfrPostBox::asynchronous_post(int msg) { void JfrPostBox::synchronous_post(int msg) { assert(is_synchronous(msg), "invariant"); assert(!JfrMsg_lock->owned_by_self(), "should not hold JfrMsg_lock here!"); - MonitorLocker msg_lock(JfrMsg_lock); + NoHandleMark nhm; + ThreadBlockInVM transition(JavaThread::current()); + MonitorLocker msg_lock(JfrMsg_lock, Mutex::_no_safepoint_check_flag); deposit(msg); // serial_id is used to check when what we send in has been processed. // _msg_read_serial is read under JfrMsg_lock protection. @@ -168,6 +172,6 @@ void JfrPostBox::notify_waiters() { // safeguard to ensure no threads are left waiting void JfrPostBox::notify_collection_stop() { - MutexLocker msg_lock(JfrMsg_lock); + assert(JfrMsg_lock->owned_by_self(), "invariant"); JfrMsg_lock->notify_all(); } diff --git a/src/hotspot/share/jfr/recorder/service/jfrRecorderThreadLoop.cpp b/src/hotspot/share/jfr/recorder/service/jfrRecorderThreadLoop.cpp index 6cbd487d514..1145b3c21b8 100644 --- a/src/hotspot/share/jfr/recorder/service/jfrRecorderThreadLoop.cpp +++ b/src/hotspot/share/jfr/recorder/service/jfrRecorderThreadLoop.cpp @@ -51,23 +51,24 @@ void recorderthread_entry(JavaThread* thread, JavaThread* unused) { log_debug(jfr, system)("Recorder thread STARTED"); { + // Run as _thread_in_native to minimize impact on safepoint synchronization. + NoHandleMark nhm; + ThreadToNativeFromVM transition(thread); + bool done = false; int msgs = 0; JfrRecorderService service; - MutexLocker msg_lock(JfrMsg_lock); + + MonitorLocker msg_lock(JfrMsg_lock, Mutex::_no_safepoint_check_flag); // JFR MESSAGE LOOP PROCESSING - BEGIN while (!done) { if (post_box.is_empty()) { - JfrMsg_lock->wait(); + msg_lock.wait(); } msgs = post_box.collect(); - JfrMsg_lock->unlock(); { - // Run as _thread_in_native as much a possible - // to minimize impact on safepoint synchronizations. - NoHandleMark nhm; - ThreadToNativeFromVM transition(thread); + MutexUnlocker mul(JfrMsg_lock, Mutex::_no_safepoint_check_flag); if (PROCESS_FULL_BUFFERS) { service.process_full_buffers(); } @@ -82,18 +83,16 @@ void recorderthread_entry(JavaThread* thread, JavaThread* unused) { service.flushpoint(); } } - JfrMsg_lock->lock(); post_box.notify_waiters(); if (SHUTDOWN) { log_debug(jfr, system)("Request to STOP recorder"); done = true; } } // JFR MESSAGE LOOP PROCESSING - END - - } // JfrMsg_lock scope + post_box.notify_collection_stop(); + } // JfrMsg_lock scope and the thread returns to _thread_in_vm assert(!JfrMsg_lock->owned_by_self(), "invariant"); - post_box.notify_collection_stop(); JfrRecorder::on_recorder_thread_exit(); #undef START diff --git a/src/hotspot/share/jfr/support/jfrKlassUnloading.cpp b/src/hotspot/share/jfr/support/jfrKlassUnloading.cpp index 7d7b5ca9161..b1794a7a1e1 100644 --- a/src/hotspot/share/jfr/support/jfrKlassUnloading.cpp +++ b/src/hotspot/share/jfr/support/jfrKlassUnloading.cpp @@ -23,11 +23,14 @@ */ #include "precompiled.hpp" +#include "jfr/jfrEvents.hpp" +#include "jfr/periodic/jfrFinalizerStatisticsEvent.hpp" #include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp" #include "jfr/support/jfrKlassUnloading.hpp" #include "jfr/utilities/jfrPredicate.hpp" #include "jfr/utilities/jfrRelation.hpp" #include "runtime/mutexLocker.hpp" +#include "utilities/macros.hpp" static const int initial_array_size = 64; @@ -107,9 +110,22 @@ static bool add_to_unloaded_klass_set(traceid klass_id, bool current_epoch) { return true; } +#if INCLUDE_MANAGEMENT +static void send_finalizer_event(const Klass* k) { + if (!k->is_instance_klass()) { + return; + } + const InstanceKlass* const ik = InstanceKlass::cast(k); + if (ik->has_finalizer()) { + JfrFinalizerStatisticsEvent::send_unload_event(ik); + } +} +#endif + bool JfrKlassUnloading::on_unload(const Klass* k) { assert(k != NULL, "invariant"); assert_locked_or_safepoint(ClassLoaderDataGraph_lock); + MANAGEMENT_ONLY(send_finalizer_event(k);) if (IS_JDK_JFR_EVENT_SUBKLASS(k)) { ++event_klass_unloaded_count; } diff --git a/src/hotspot/share/jfr/support/jfrSymbolTable.cpp b/src/hotspot/share/jfr/support/jfrSymbolTable.cpp new file mode 100644 index 00000000000..786fff37efd --- /dev/null +++ b/src/hotspot/share/jfr/support/jfrSymbolTable.cpp @@ -0,0 +1,316 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 "classfile/javaClasses.inline.hpp" +#include "classfile/classLoaderData.hpp" +#include "jfr/support/jfrSymbolTable.hpp" +#include "oops/instanceKlass.hpp" +#include "oops/oop.inline.hpp" +#include "oops/symbol.hpp" +#include "runtime/mutexLocker.hpp" + +// incremented on each rotation +static u8 checkpoint_id = 1; + +// creates a unique id by combining a checkpoint relative symbol id (2^24) +// with the current checkpoint id (2^40) +#define CREATE_SYMBOL_ID(sym_id) (((u8)((checkpoint_id << 24) | sym_id))) + +static traceid create_symbol_id(traceid artifact_id) { + return artifact_id != 0 ? CREATE_SYMBOL_ID(artifact_id) : 0; +} + +static uintptr_t string_hash(const char* str) { + return java_lang_String::hash_code(reinterpret_cast(str), static_cast(strlen(str))); +} + +static JfrSymbolTable::StringEntry* bootstrap = NULL; + +static JfrSymbolTable* _instance = NULL; + +static JfrSymbolTable& instance() { + assert(_instance != NULL, "invariant"); + return *_instance; +} + +JfrSymbolTable* JfrSymbolTable::create() { + assert(_instance == NULL, "invariant"); + assert_lock_strong(ClassLoaderDataGraph_lock); + _instance = new JfrSymbolTable(); + return _instance; +} + +void JfrSymbolTable::destroy() { + assert_lock_strong(ClassLoaderDataGraph_lock); + if (_instance != NULL) { + delete _instance; + _instance = NULL; + } + assert(_instance == NULL, "invariant"); +} + +JfrSymbolTable::JfrSymbolTable() : + _symbols(new Symbols(this)), + _strings(new Strings(this)), + _symbol_list(NULL), + _string_list(NULL), + _symbol_query(NULL), + _string_query(NULL), + _id_counter(1), + _class_unload(false) { + assert(_symbols != NULL, "invariant"); + assert(_strings != NULL, "invariant"); + bootstrap = new StringEntry(0, (const char*)&BOOTSTRAP_LOADER_NAME); + assert(bootstrap != NULL, "invariant"); + bootstrap->set_id(create_symbol_id(1)); + _string_list = bootstrap; +} + +JfrSymbolTable::~JfrSymbolTable() { + clear(); + delete _symbols; + delete _strings; + delete bootstrap; +} + +void JfrSymbolTable::clear() { + assert(_symbols != NULL, "invariant"); + if (_symbols->has_entries()) { + _symbols->clear_entries(); + } + assert(!_symbols->has_entries(), "invariant"); + + assert(_strings != NULL, "invariant"); + if (_strings->has_entries()) { + _strings->clear_entries(); + } + assert(!_strings->has_entries(), "invariant"); + + _symbol_list = NULL; + _id_counter = 1; + + _symbol_query = NULL; + _string_query = NULL; + + assert(bootstrap != NULL, "invariant"); + bootstrap->reset(); + _string_list = bootstrap; +} + +void JfrSymbolTable::set_class_unload(bool class_unload) { + _class_unload = class_unload; +} + +void JfrSymbolTable::increment_checkpoint_id() { + assert_lock_strong(ClassLoaderDataGraph_lock); + clear(); + ++checkpoint_id; +} + +template +inline void JfrSymbolTable::assign_id(T* entry) { + assert(entry != NULL, "invariant"); + assert(entry->id() == 0, "invariant"); + entry->set_id(create_symbol_id(++_id_counter)); +} + +void JfrSymbolTable::on_link(const SymbolEntry* entry) { + assign_id(entry); + const_cast(entry->literal())->increment_refcount(); + entry->set_list_next(_symbol_list); + _symbol_list = entry; +} + +bool JfrSymbolTable::on_equals(uintptr_t hash, const SymbolEntry* entry) { + assert(entry != NULL, "invariant"); + assert(entry->hash() == hash, "invariant"); + assert(_symbol_query != NULL, "invariant"); + return _symbol_query == entry->literal(); +} + +void JfrSymbolTable::on_unlink(const SymbolEntry* entry) { + assert(entry != NULL, "invariant"); + const_cast(entry->literal())->decrement_refcount(); +} + +static const char* resource_to_c_heap_string(const char* resource_str) { + assert(resource_str != NULL, "invariant"); + const size_t length = strlen(resource_str); + char* const c_string = JfrCHeapObj::new_array(length + 1); + assert(c_string != NULL, "invariant"); + strncpy(c_string, resource_str, length + 1); + return c_string; +} + +void JfrSymbolTable::on_link(const StringEntry* entry) { + assign_id(entry); + const_cast(entry)->set_literal(resource_to_c_heap_string(entry->literal())); + entry->set_list_next(_string_list); + _string_list = entry; +} + +static bool string_compare(const char* query, const char* candidate) { + assert(query != NULL, "invariant"); + assert(candidate != NULL, "invariant"); + const size_t length = strlen(query); + return strncmp(query, candidate, length) == 0; +} + +bool JfrSymbolTable::on_equals(uintptr_t hash, const StringEntry* entry) { + assert(entry != NULL, "invariant"); + assert(entry->hash() == hash, "invariant"); + assert(_string_query != NULL, "invariant"); + return string_compare(_string_query, entry->literal()); +} + +void JfrSymbolTable::on_unlink(const StringEntry* entry) { + assert(entry != NULL, "invariant"); + JfrCHeapObj::free(const_cast(entry->literal()), strlen(entry->literal() + 1)); +} + +traceid JfrSymbolTable::bootstrap_name(bool leakp) { + assert(bootstrap != NULL, "invariant"); + if (leakp) { + bootstrap->set_leakp(); + } + return bootstrap->id(); +} + +traceid JfrSymbolTable::mark(const Symbol* sym, bool leakp /* false */) { + assert(sym != NULL, "invariant"); + return mark((uintptr_t)sym->identity_hash(), sym, leakp); +} + +traceid JfrSymbolTable::mark(uintptr_t hash, const Symbol* sym, bool leakp) { + assert(sym != NULL, "invariant"); + assert(_symbols != NULL, "invariant"); + _symbol_query = sym; + const SymbolEntry& entry = _symbols->lookup_put(hash, sym); + if (_class_unload) { + entry.set_unloading(); + } + if (leakp) { + entry.set_leakp(); + } + return entry.id(); +} + +traceid JfrSymbolTable::mark(const char* str, bool leakp /* false*/) { + return mark(string_hash(str), str, leakp); +} + +traceid JfrSymbolTable::mark(uintptr_t hash, const char* str, bool leakp) { + assert(str != NULL, "invariant"); + assert(_strings != NULL, "invariant"); + _string_query = str; + const StringEntry& entry = _strings->lookup_put(hash, str); + if (_class_unload) { + entry.set_unloading(); + } + if (leakp) { + entry.set_leakp(); + } + return entry.id(); +} + +/* +* hidden classes symbol is the external name + +* the address of its InstanceKlass slash appended: +* java.lang.invoke.LambdaForm$BMH/22626602 +* +* caller needs ResourceMark +*/ + +uintptr_t JfrSymbolTable::hidden_klass_name_hash(const InstanceKlass* ik) { + assert(ik != NULL, "invariant"); + assert(ik->is_hidden(), "invariant"); + const oop mirror = ik->java_mirror_no_keepalive(); + assert(mirror != NULL, "invariant"); + return (uintptr_t)mirror->identity_hash(); +} + +static const char* create_hidden_klass_symbol(const InstanceKlass* ik, uintptr_t hash) { + assert(ik != NULL, "invariant"); + assert(ik->is_hidden(), "invariant"); + assert(hash != 0, "invariant"); + char* hidden_symbol = NULL; + const oop mirror = ik->java_mirror_no_keepalive(); + assert(mirror != NULL, "invariant"); + char hash_buf[40]; + sprintf(hash_buf, "/" UINTX_FORMAT, hash); + const size_t hash_len = strlen(hash_buf); + const size_t result_len = ik->name()->utf8_length(); + hidden_symbol = NEW_RESOURCE_ARRAY(char, result_len + hash_len + 1); + ik->name()->as_klass_external_name(hidden_symbol, (int)result_len + 1); + assert(strlen(hidden_symbol) == result_len, "invariant"); + strcpy(hidden_symbol + result_len, hash_buf); + assert(strlen(hidden_symbol) == result_len + hash_len, "invariant"); + return hidden_symbol; +} + +bool JfrSymbolTable::is_hidden_klass(const Klass* k) { + assert(k != NULL, "invariant"); + return k->is_instance_klass() && ((const InstanceKlass*)k)->is_hidden(); +} + +traceid JfrSymbolTable::mark_hidden_klass_name(const InstanceKlass* ik, bool leakp) { + assert(ik != NULL, "invariant"); + assert(ik->is_hidden(), "invariant"); + const uintptr_t hash = hidden_klass_name_hash(ik); + const char* const hidden_symbol = create_hidden_klass_symbol(ik, hash); + return mark(hash, hidden_symbol, leakp); +} + +traceid JfrSymbolTable::mark(const Klass* k, bool leakp) { + assert(k != NULL, "invariant"); + traceid symbol_id = 0; + if (is_hidden_klass(k)) { + assert(k->is_instance_klass(), "invariant"); + symbol_id = mark_hidden_klass_name((const InstanceKlass*)k, leakp); + } else { + Symbol* const sym = k->name(); + if (sym != NULL) { + symbol_id = mark(sym, leakp); + } + } + assert(symbol_id > 0, "a symbol handler must mark the symbol for writing"); + return symbol_id; +} + +template +traceid JfrSymbolTable::add_impl(const T* sym) { + assert(sym != NULL, "invariant"); + assert(_instance != NULL, "invariant"); + assert_locked_or_safepoint(ClassLoaderDataGraph_lock); + return instance().mark(sym); +} + +traceid JfrSymbolTable::add(const Symbol* sym) { + return add_impl(sym); +} + +traceid JfrSymbolTable::add(const char* str) { + return add_impl(str); +} diff --git a/src/hotspot/share/jfr/support/jfrSymbolTable.hpp b/src/hotspot/share/jfr/support/jfrSymbolTable.hpp new file mode 100644 index 00000000000..5a6d9beaa17 --- /dev/null +++ b/src/hotspot/share/jfr/support/jfrSymbolTable.hpp @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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_JFR_SUPPORT_JFRSYMBOLTABLE_HPP +#define SHARE_JFR_SUPPORT_JFRSYMBOLTABLE_HPP + +#include "jfr/utilities/jfrHashtable.hpp" +#include "jfr/utilities/jfrTypes.hpp" + +template +class ListEntry : public JfrHashtableEntry { + public: + ListEntry(uintptr_t hash, const T& data) : JfrHashtableEntry(hash, data), + _list_next(NULL), _serialized(false), _unloading(false), _leakp(false) {} + const ListEntry* list_next() const { return _list_next; } + void reset() const { + _list_next = NULL; _serialized = false; _unloading = false; _leakp = false; + } + void set_list_next(const ListEntry* next) const { _list_next = next; } + bool is_serialized() const { return _serialized; } + void set_serialized() const { _serialized = true; } + bool is_unloading() const { return _unloading; } + void set_unloading() const { _unloading = true; } + bool is_leakp() const { return _leakp; } + void set_leakp() const { _leakp = true; } + private: + mutable const ListEntry* _list_next; + mutable bool _serialized; + mutable bool _unloading; + mutable bool _leakp; +}; + +/* + * This table maps an oop/Symbol* or a char* to the Jfr type 'Symbol'. + * + * It provides an interface over the corresponding constant pool (TYPE_SYMBOL), + * which is represented in the binary format as a sequence of checkpoint events. + * The returned id can be used as a foreign key, but please note that the id is + * epoch-relative, and is therefore only valid in the current epoch / chunk. + * The table is cleared as part of rotation. + * + * Caller must ensure mutual exclusion by means of the ClassLoaderDataGraph_lock or by safepointing. + */ +class JfrSymbolTable : public JfrCHeapObj { + template class, typename, size_t> + friend class HashTableHost; + typedef HashTableHost Symbols; + typedef HashTableHost Strings; + friend class JfrArtifactSet; + + public: + typedef Symbols::HashEntry SymbolEntry; + typedef Strings::HashEntry StringEntry; + + static traceid add(const Symbol* sym); + static traceid add(const char* str); + + private: + Symbols* _symbols; + Strings* _strings; + const SymbolEntry* _symbol_list; + const StringEntry* _string_list; + const Symbol* _symbol_query; + const char* _string_query; + traceid _id_counter; + bool _class_unload; + + JfrSymbolTable(); + ~JfrSymbolTable(); + static JfrSymbolTable* create(); + static void destroy(); + + void clear(); + void increment_checkpoint_id(); + void set_class_unload(bool class_unload); + + traceid mark(uintptr_t hash, const Symbol* sym, bool leakp); + traceid mark(const Klass* k, bool leakp); + traceid mark(const Symbol* sym, bool leakp = false); + traceid mark(const char* str, bool leakp = false); + traceid mark(uintptr_t hash, const char* str, bool leakp); + traceid bootstrap_name(bool leakp); + + bool has_entries() const { return has_symbol_entries() || has_string_entries(); } + bool has_symbol_entries() const { return _symbol_list != NULL; } + bool has_string_entries() const { return _string_list != NULL; } + + traceid mark_hidden_klass_name(const InstanceKlass* k, bool leakp); + bool is_hidden_klass(const Klass* k); + uintptr_t hidden_klass_name_hash(const InstanceKlass* ik); + + // hashtable(s) callbacks + void on_link(const SymbolEntry* entry); + bool on_equals(uintptr_t hash, const SymbolEntry* entry); + void on_unlink(const SymbolEntry* entry); + void on_link(const StringEntry* entry); + bool on_equals(uintptr_t hash, const StringEntry* entry); + void on_unlink(const StringEntry* entry); + + template + static traceid add_impl(const T* sym); + + template + void assign_id(T* entry); + + template + void iterate_symbols(Functor& functor) { + iterate(functor, _symbol_list); + } + + template + void iterate_strings(Functor& functor) { + iterate(functor, _string_list); + } + + template + void iterate(Functor& functor, const T* list) { + const T* symbol = list; + while (symbol != NULL) { + const T* next = symbol->list_next(); + functor(symbol); + symbol = next; + } + } +}; + +#endif // SHARE_JFR_SUPPORT_JFRSYMBOLTABLE_HPP diff --git a/src/hotspot/share/logging/logTag.hpp b/src/hotspot/share/logging/logTag.hpp index efa03312bd6..2042cf2b4d7 100644 --- a/src/hotspot/share/logging/logTag.hpp +++ b/src/hotspot/share/logging/logTag.hpp @@ -71,6 +71,7 @@ LOG_TAG(event) \ LOG_TAG(exceptions) \ LOG_TAG(exit) \ + LOG_TAG(finalizer) \ LOG_TAG(fingerprint) \ DEBUG_ONLY(LOG_TAG(foreign)) \ LOG_TAG(free) \ diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp index 31a91588059..fb6c653ddc9 100644 --- a/src/hotspot/share/oops/instanceKlass.cpp +++ b/src/hotspot/share/oops/instanceKlass.cpp @@ -83,6 +83,7 @@ #include "runtime/reflectionUtils.hpp" #include "runtime/thread.inline.hpp" #include "services/classLoadingService.hpp" +#include "services/finalizerService.hpp" #include "services/threadService.hpp" #include "utilities/dtrace.hpp" #include "utilities/events.hpp" @@ -96,7 +97,6 @@ #include "jfr/jfrEvents.hpp" #endif - #ifdef DTRACE_ENABLED @@ -1405,8 +1405,9 @@ instanceOop InstanceKlass::register_finalizer(instanceOop i, TRAPS) { // Pass the handle as argument, JavaCalls::call expects oop as jobjects JavaValue result(T_VOID); JavaCallArguments args(h_i); - methodHandle mh (THREAD, Universe::finalizer_register_method()); + methodHandle mh(THREAD, Universe::finalizer_register_method()); JavaCalls::call(&result, mh, &args, CHECK_NULL); + MANAGEMENT_ONLY(FinalizerService::on_register(h_i(), THREAD);) return h_i(); } diff --git a/src/hotspot/share/prims/jvm.cpp b/src/hotspot/share/prims/jvm.cpp index acc64da5281..b7139423e4c 100644 --- a/src/hotspot/share/prims/jvm.cpp +++ b/src/hotspot/share/prims/jvm.cpp @@ -104,6 +104,9 @@ #if INCLUDE_JFR #include "jfr/jfr.hpp" #endif +#if INCLUDE_MANAGEMENT +#include "services/finalizerService.hpp" +#endif #include @@ -681,6 +684,12 @@ JVM_ENTRY(jobject, JVM_Clone(JNIEnv* env, jobject handle)) return JNIHandles::make_local(THREAD, new_obj()); JVM_END +// java.lang.ref.Finalizer //////////////////////////////////////////////////// + +JVM_ENTRY(void, JVM_ReportFinalizationComplete(JNIEnv * env, jobject finalizee)) + MANAGEMENT_ONLY(FinalizerService::on_complete(JNIHandles::resolve_non_null(finalizee), THREAD);) +JVM_END + // java.io.File /////////////////////////////////////////////////////////////// JVM_LEAF(char*, JVM_NativePath(char* path)) @@ -3851,3 +3860,4 @@ JVM_END JVM_ENTRY_NO_ENV(jint, JVM_FindSignal(const char *name)) return os::get_signal_number(name); JVM_END + diff --git a/src/hotspot/share/runtime/mutexLocker.cpp b/src/hotspot/share/runtime/mutexLocker.cpp index acd2a067047..35900865d37 100644 --- a/src/hotspot/share/runtime/mutexLocker.cpp +++ b/src/hotspot/share/runtime/mutexLocker.cpp @@ -305,6 +305,7 @@ void mutex_init() { #if INCLUDE_JFR def(JfrBuffer_lock , PaddedMutex , nosafepoint, true); + def(JfrMsg_lock , PaddedMonitor, nosafepoint-3, true); def(JfrStacktrace_lock , PaddedMutex , stackwatermark-1, true); def(JfrThreadSampler_lock , PaddedMonitor, nosafepoint, true); #endif @@ -365,10 +366,6 @@ void mutex_init() { defl(Module_lock , PaddedMutex , ClassLoaderDataGraph_lock, false); defl(SystemDictionary_lock , PaddedMonitor, Module_lock, true); defl(JNICritical_lock , PaddedMonitor, MultiArray_lock, true); // used for JNI critical regions - -#if INCLUDE_JFR - defl(JfrMsg_lock , PaddedMonitor, Module_lock, true); -#endif } GCMutexLocker::GCMutexLocker(Mutex* mutex) { diff --git a/src/hotspot/share/runtime/serviceThread.cpp b/src/hotspot/share/runtime/serviceThread.cpp index bba0f0f3325..6b23755f7c3 100644 --- a/src/hotspot/share/runtime/serviceThread.cpp +++ b/src/hotspot/share/runtime/serviceThread.cpp @@ -47,6 +47,7 @@ #include "prims/resolvedMethodTable.hpp" #include "services/diagnosticArgument.hpp" #include "services/diagnosticFramework.hpp" +#include "services/finalizerService.hpp" #include "services/gcNotifier.hpp" #include "services/lowMemoryDetector.hpp" #include "services/threadIdTable.hpp" @@ -115,6 +116,7 @@ void ServiceThread::service_thread_entry(JavaThread* jt, TRAPS) { bool has_dcmd_notification_event = false; bool stringtable_work = false; bool symboltable_work = false; + bool finalizerservice_work = false; bool resolved_method_table_work = false; bool thread_id_table_work = false; bool protection_domain_table_work = false; @@ -145,6 +147,7 @@ void ServiceThread::service_thread_entry(JavaThread* jt, TRAPS) { (has_dcmd_notification_event = (!UseNotificationThread && DCmdFactory::has_pending_jmx_notification())) | (stringtable_work = StringTable::has_work()) | (symboltable_work = SymbolTable::has_work()) | + (finalizerservice_work = FinalizerService::has_work()) | (resolved_method_table_work = ResolvedMethodTable::has_work()) | (thread_id_table_work = ThreadIdTable::has_work()) | (protection_domain_table_work = SystemDictionary::pd_cache_table()->has_work()) | @@ -172,6 +175,10 @@ void ServiceThread::service_thread_entry(JavaThread* jt, TRAPS) { SymbolTable::do_concurrent_work(jt); } + if (finalizerservice_work) { + FinalizerService::do_concurrent_work(jt); + } + if (has_jvmti_events) { _jvmti_event->post(); _jvmti_event = NULL; // reset diff --git a/src/hotspot/share/services/classLoadingService.cpp b/src/hotspot/share/services/classLoadingService.cpp index 9da4496971c..16a6fd005a4 100644 --- a/src/hotspot/share/services/classLoadingService.cpp +++ b/src/hotspot/share/services/classLoadingService.cpp @@ -119,49 +119,62 @@ void ClassLoadingService::init() { } } -void ClassLoadingService::notify_class_unloaded(InstanceKlass* k) { - DTRACE_CLASSLOAD_PROBE(unloaded, k, false); - // Classes that can be unloaded must be non-shared - _classes_unloaded_count->inc(); +bool ClassLoadingService::set_verbose(bool verbose) { + MutexLocker m(Management_lock); + // verbose will be set to the previous value + LogLevelType level = verbose ? LogLevel::Info : LogLevel::Off; + LogConfiguration::configure_stdout(level, false, LOG_TAGS(class, load)); + reset_trace_class_unloading(); + return verbose; +} - if (UsePerfData) { - // add the class size - size_t size = compute_class_size(k); - _classbytes_unloaded->inc(size); +// Caller to this function must own Management_lock +void ClassLoadingService::reset_trace_class_unloading() { + assert(Management_lock->owned_by_self(), "Must own the Management_lock"); + bool value = MemoryService::get_verbose() || ClassLoadingService::get_verbose(); + LogLevelType level = value ? LogLevel::Info : LogLevel::Off; + LogConfiguration::configure_stdout(level, false, LOG_TAGS(class, unload)); +} - // Compute method size & subtract from running total. - // We are called during phase 1 of mark sweep, so it's - // still ok to iterate through Method*s here. - Array* methods = k->methods(); - for (int i = 0; i < methods->length(); i++) { - _class_methods_size->inc(-methods->at(i)->size()); - } - } +jlong ClassLoadingService::loaded_class_count() { + return _classes_loaded_count->get_value() + _shared_classes_loaded_count->get_value(); } -void ClassLoadingService::notify_class_loaded(InstanceKlass* k, bool shared_class) { - DTRACE_CLASSLOAD_PROBE(loaded, k, shared_class); - PerfCounter* classes_counter = (shared_class ? _shared_classes_loaded_count - : _classes_loaded_count); - // increment the count - classes_counter->inc(); +jlong ClassLoadingService::unloaded_class_count() { + return _classes_unloaded_count->get_value() + _shared_classes_unloaded_count->get_value(); +} - if (UsePerfData) { - PerfCounter* classbytes_counter = (shared_class ? _shared_classbytes_loaded - : _classbytes_loaded); - // add the class size - size_t size = compute_class_size(k); - classbytes_counter->inc(size); - } +jlong ClassLoadingService::loaded_class_bytes() { + return UsePerfData ? _classbytes_loaded->get_value() + _shared_classbytes_loaded->get_value() : -1; } -size_t ClassLoadingService::compute_class_size(InstanceKlass* k) { - // lifted from ClassStatistics.do_class(Klass* k) +jlong ClassLoadingService::unloaded_class_bytes() { + return UsePerfData ? _classbytes_unloaded->get_value() + _shared_classbytes_unloaded->get_value() : -1; +} + +jlong ClassLoadingService::loaded_shared_class_count() { + return _shared_classes_loaded_count->get_value(); +} - size_t class_size = 0; +jlong ClassLoadingService::unloaded_shared_class_count() { + return _shared_classes_unloaded_count->get_value(); +} - class_size += k->size(); +jlong ClassLoadingService::loaded_shared_class_bytes() { + return UsePerfData ? _shared_classbytes_loaded->get_value() : -1; +} +jlong ClassLoadingService::unloaded_shared_class_bytes() { + return UsePerfData ? _shared_classbytes_unloaded->get_value() : -1; +} + +jlong ClassLoadingService::class_method_data_size() { + return UsePerfData ? _class_methods_size->get_value() : -1; +} + +static size_t compute_class_size(InstanceKlass* k) { + // lifted from ClassStatistics.do_class(Klass* k) + size_t class_size = k->size(); if (k->is_instance_klass()) { class_size += k->methods()->size(); // FIXME: Need to count the contents of methods @@ -177,21 +190,40 @@ size_t ClassLoadingService::compute_class_size(InstanceKlass* k) { return class_size * oopSize; } -bool ClassLoadingService::set_verbose(bool verbose) { - MutexLocker m(Management_lock); - // verbose will be set to the previous value - LogLevelType level = verbose ? LogLevel::Info : LogLevel::Off; - LogConfiguration::configure_stdout(level, false, LOG_TAGS(class, load)); - reset_trace_class_unloading(); - return verbose; +void ClassLoadingService::notify_class_loaded(InstanceKlass* k, bool shared_class) { + DTRACE_CLASSLOAD_PROBE(loaded, k, shared_class); + PerfCounter* classes_counter = (shared_class ? _shared_classes_loaded_count + : _classes_loaded_count); + // increment the count + classes_counter->inc(); + + if (UsePerfData) { + PerfCounter* classbytes_counter = (shared_class ? _shared_classbytes_loaded + : _classbytes_loaded); + // add the class size + size_t size = compute_class_size(k); + classbytes_counter->inc(size); + } } -// Caller to this function must own Management_lock -void ClassLoadingService::reset_trace_class_unloading() { - assert(Management_lock->owned_by_self(), "Must own the Management_lock"); - bool value = MemoryService::get_verbose() || ClassLoadingService::get_verbose(); - LogLevelType level = value ? LogLevel::Info : LogLevel::Off; - LogConfiguration::configure_stdout(level, false, LOG_TAGS(class, unload)); +void ClassLoadingService::notify_class_unloaded(InstanceKlass* k) { + DTRACE_CLASSLOAD_PROBE(unloaded, k, false); + // Classes that can be unloaded must be non-shared + _classes_unloaded_count->inc(); + + if (UsePerfData) { + // add the class size + size_t size = compute_class_size(k); + _classbytes_unloaded->inc(size); + + // Compute method size & subtract from running total. + // We are called during phase 1 of mark sweep, so it's + // still ok to iterate through Method*s here. + Array* methods = k->methods(); + for (int i = 0; i < methods->length(); i++) { + _class_methods_size->inc(-methods->at(i)->size()); + } + } } #endif // INCLUDE_MANAGEMENT diff --git a/src/hotspot/share/services/classLoadingService.hpp b/src/hotspot/share/services/classLoadingService.hpp index db422cbf11f..f9db3da5091 100644 --- a/src/hotspot/share/services/classLoadingService.hpp +++ b/src/hotspot/share/services/classLoadingService.hpp @@ -35,7 +35,7 @@ class InstanceKlass; // VM monitoring and management support for the Class Loading subsystem class ClassLoadingService : public AllStatic { -private: + private: // Counters for classes loaded from class files static PerfCounter* _classes_loaded_count; static PerfCounter* _classes_unloaded_count; @@ -50,59 +50,20 @@ private: static PerfVariable* _class_methods_size; - static size_t compute_class_size(InstanceKlass* k); - -public: - static void init(); - - static bool get_verbose() { return log_is_enabled(Info, class, load); } - static bool set_verbose(bool verbose); + public: + static void init() NOT_MANAGEMENT_RETURN; + static bool set_verbose(bool verbose) NOT_MANAGEMENT_RETURN_(false); static void reset_trace_class_unloading() NOT_MANAGEMENT_RETURN; - - static jlong loaded_class_count() { - return _classes_loaded_count->get_value() + _shared_classes_loaded_count->get_value(); - } - static jlong unloaded_class_count() { - return _classes_unloaded_count->get_value() + _shared_classes_unloaded_count->get_value(); - } - static jlong loaded_class_bytes() { - if (UsePerfData) { - return _classbytes_loaded->get_value() + _shared_classbytes_loaded->get_value(); - } else { - return -1; - } - } - static jlong unloaded_class_bytes() { - if (UsePerfData) { - return _classbytes_unloaded->get_value() + _shared_classbytes_unloaded->get_value(); - } else { - return -1; - } - } - - static jlong loaded_shared_class_count() { - return _shared_classes_loaded_count->get_value(); - } - static jlong unloaded_shared_class_count() { - return _shared_classes_unloaded_count->get_value(); - } - static jlong loaded_shared_class_bytes() { - if (UsePerfData) { - return _shared_classbytes_loaded->get_value(); - } else { - return -1; - } - } - static jlong unloaded_shared_class_bytes() { - if (UsePerfData) { - return _shared_classbytes_unloaded->get_value(); - } else { - return -1; - } - } - static jlong class_method_data_size() { - return (UsePerfData ? _class_methods_size->get_value() : -1); - } + static jlong loaded_class_count() NOT_MANAGEMENT_RETURN_(0L); + static jlong unloaded_class_count() NOT_MANAGEMENT_RETURN_(0L); + static jlong loaded_class_bytes() NOT_MANAGEMENT_RETURN_(0L); + static jlong unloaded_class_bytes() NOT_MANAGEMENT_RETURN_(0L); + static jlong loaded_shared_class_count() NOT_MANAGEMENT_RETURN_(0L); + static jlong unloaded_shared_class_count() NOT_MANAGEMENT_RETURN_(0L); + static jlong loaded_shared_class_bytes() NOT_MANAGEMENT_RETURN_(0L); + static jlong unloaded_shared_class_bytes() NOT_MANAGEMENT_RETURN_(0L); + static jlong class_method_data_size() NOT_MANAGEMENT_RETURN_(0L); + static bool get_verbose() { return log_is_enabled(Info, class, load); } static void notify_class_loaded(InstanceKlass* k, bool shared_class) NOT_MANAGEMENT_RETURN; diff --git a/src/hotspot/share/services/finalizerService.cpp b/src/hotspot/share/services/finalizerService.cpp new file mode 100644 index 00000000000..557d4511280 --- /dev/null +++ b/src/hotspot/share/services/finalizerService.cpp @@ -0,0 +1,313 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 "utilities/macros.hpp" +#if INCLUDE_MANAGEMENT +#include "classfile/classLoaderDataGraph.inline.hpp" +#include "memory/resourceArea.hpp" +#include "logging/log.hpp" +#include "runtime/atomic.hpp" +#include "runtime/interfaceSupport.inline.hpp" +#include "runtime/mutexLocker.hpp" +#include "runtime/synchronizer.hpp" +#include "runtime/thread.inline.hpp" +#include "services/finalizerService.hpp" +#include "utilities/concurrentHashTableTasks.inline.hpp" +#include "utilities/debug.hpp" + +FinalizerEntry::FinalizerEntry(const InstanceKlass* ik) : + _ik(ik), + _objects_on_heap(0), + _total_finalizers_run(0) {} + +const InstanceKlass* FinalizerEntry::klass() const { + return _ik; +} + +uintptr_t FinalizerEntry::objects_on_heap() const { + return Atomic::load(&_objects_on_heap); +} + +uintptr_t FinalizerEntry::total_finalizers_run() const { + return Atomic::load(&_total_finalizers_run); +} + +void FinalizerEntry::on_register() { + Atomic::inc(&_objects_on_heap, memory_order_relaxed); +} + +void FinalizerEntry::on_complete() { + Atomic::inc(&_total_finalizers_run, memory_order_relaxed); + Atomic::dec(&_objects_on_heap, memory_order_relaxed); +} + +static inline uintx hash_function(const InstanceKlass* ik) { + assert(ik != nullptr, "invariant"); + return primitive_hash(ik); +} + +static inline uintx hash_function(const FinalizerEntry* fe) { + return hash_function(fe->klass()); +} + +class FinalizerEntryLookup : StackObj { + private: + const InstanceKlass* const _ik; + public: + FinalizerEntryLookup(const InstanceKlass* ik) : _ik(ik) {} + uintx get_hash() const { return hash_function(_ik); } + bool equals(FinalizerEntry** value, bool* is_dead) { + assert(value != nullptr, "invariant"); + assert(*value != nullptr, "invariant"); + return (*value)->klass() == _ik; + } +}; + +class FinalizerTableConfig : public AllStatic { + public: + typedef FinalizerEntry* Value; // value of the Node in the hashtable + + static uintx get_hash(Value const& value, bool* is_dead) { + return hash_function(value); + } + static void* allocate_node(void* context, size_t size, Value const& value) { + return AllocateHeap(size, mtServiceability); + } + static void free_node(void* context, void* memory, Value const& value) { + FreeHeap(memory); + } +}; + +typedef ConcurrentHashTable FinalizerHashtable; +static FinalizerHashtable* _table = nullptr; +static const size_t DEFAULT_TABLE_SIZE = 2048; +// 2^24 is max size, like StringTable. +static const size_t MAX_SIZE = 24; +static volatile bool _has_work = false; + +static size_t ceil_log2(size_t value) { + size_t ret; + for (ret = 1; ((size_t)1 << ret) < value; ++ret); + return ret; +} + +class FinalizerEntryLookupResult { + private: + FinalizerEntry* _result; + public: + FinalizerEntryLookupResult() : _result(nullptr) {} + void operator()(FinalizerEntry* node) { + assert(node != nullptr, "invariant"); + _result = node; + } + FinalizerEntry* result() const { return _result; } +}; + +class FinalizerEntryLookupGet { + private: + FinalizerEntry* _result; + public: + FinalizerEntryLookupGet() : _result(nullptr) {} + void operator()(FinalizerEntry** node) { + assert(node != nullptr, "invariant"); + _result = *node; + } + FinalizerEntry* result() const { return _result; } +}; + +static inline void set_has_work(bool value) { + Atomic::store(&_has_work, value); +} + +static inline bool has_work() { + return Atomic::load(&_has_work); +} + +static void request_resize() { + if (!has_work()) { + MutexLocker ml(Service_lock, Mutex::_no_safepoint_check_flag); + if (!has_work()) { + set_has_work(true); + Service_lock->notify_all(); + } + } +} + +static FinalizerEntry* add_to_table_if_needed(const InstanceKlass* ik, Thread* thread) { + FinalizerEntryLookup lookup(ik); + FinalizerEntry* entry = nullptr; + bool grow_hint = false; + do { + // We have looked up the entry once, proceed with insertion. + entry = new FinalizerEntry(ik); + if (_table->insert(thread, lookup, entry, &grow_hint)) { + break; + } + // In case another thread did a concurrent add, return value already in the table. + // This could fail if the entry got deleted concurrently, so loop back until success. + FinalizerEntryLookupGet felg; + if (_table->get(thread, lookup, felg, &grow_hint)) { + entry = felg.result(); + break; + } + } while (true); + if (grow_hint) { + request_resize(); + } + assert(entry != nullptr, "invariant"); + return entry; +} + +static void do_table_concurrent_work(JavaThread* jt) { + if (!_table->is_max_size_reached()) { + FinalizerHashtable::GrowTask gt(_table); + if (!gt.prepare(jt)) { + return; + } + while (gt.do_task(jt)) { + gt.pause(jt); + { + ThreadBlockInVM tbivm(jt); + } + gt.cont(jt); + } + gt.done(jt); + } + set_has_work(false); +} + +bool FinalizerService::has_work() { + return ::has_work(); +} + +void FinalizerService::do_concurrent_work(JavaThread* service_thread) { + assert(service_thread != nullptr, "invariant"); + assert(has_work(), "invariant"); + do_table_concurrent_work(service_thread); +} + +void FinalizerService::init() { + assert(_table == nullptr, "invariant"); + const size_t start_size_log_2 = ceil_log2(DEFAULT_TABLE_SIZE); + _table = new FinalizerHashtable(start_size_log_2, MAX_SIZE); +} + +static FinalizerEntry* lookup_entry(const InstanceKlass* ik, Thread* thread) { + FinalizerEntryLookup lookup(ik); + FinalizerEntryLookupGet felg; + _table->get(thread, lookup, felg); + return felg.result(); +} + +const FinalizerEntry* FinalizerService::lookup(const InstanceKlass* ik, Thread* thread) { + assert(ik != nullptr, "invariant"); + assert(thread != nullptr, "invariant"); + assert(ik->has_finalizer(), "invariant"); + return lookup_entry(ik, thread); +} + +// Add if not exist. +static FinalizerEntry* get_entry(const InstanceKlass* ik, Thread* thread) { + assert(ik != nullptr, "invariant"); + assert(ik->has_finalizer(), "invariant"); + FinalizerEntry* const entry = lookup_entry(ik, thread); + return entry != nullptr ? entry : add_to_table_if_needed(ik, thread); +} + +static FinalizerEntry* get_entry(oop finalizee, Thread* thread) { + assert(finalizee != nullptr, "invariant"); + assert(finalizee->is_instance(), "invariant"); + return get_entry(InstanceKlass::cast(finalizee->klass()), thread); +} + +static void log_registered(oop finalizee, Thread* thread) { + ResourceMark rm(thread); + const intptr_t identity_hash = ObjectSynchronizer::FastHashCode(thread, finalizee); + log_info(finalizer)("Registered object (" INTPTR_FORMAT ") of class %s as finalizable", identity_hash, finalizee->klass()->external_name()); +} + +void FinalizerService::on_register(oop finalizee, Thread* thread) { + FinalizerEntry* const fe = get_entry(finalizee, thread); + assert(fe != nullptr, "invariant"); + fe->on_register(); + if (log_is_enabled(Info, finalizer)) { + log_registered(finalizee, thread); + } +} + +static void log_completed(oop finalizee, Thread* thread) { + ResourceMark rm(thread); + const intptr_t identity_hash = ObjectSynchronizer::FastHashCode(thread, finalizee); + log_info(finalizer)("Finalizer was run for object (" INTPTR_FORMAT ") of class %s", identity_hash, finalizee->klass()->external_name()); +} + +void FinalizerService::on_complete(oop finalizee, JavaThread* finalizer_thread) { + FinalizerEntry* const fe = get_entry(finalizee, finalizer_thread); + assert(fe != nullptr, "invariant"); + fe->on_complete(); + if (log_is_enabled(Info, finalizer)) { + log_completed(finalizee, finalizer_thread); + } +} + +class FinalizerScan : public StackObj { + private: + FinalizerEntryClosure* _closure; + public: + FinalizerScan(FinalizerEntryClosure* closure) : _closure(closure) {} + bool operator()(FinalizerEntry** fe) { + return _closure->do_entry(*fe); + } +}; + +void FinalizerService::do_entries(FinalizerEntryClosure* closure, Thread* thread) { + assert(closure != nullptr, "invariant"); + FinalizerScan scan(closure); + _table->do_scan(thread, scan); +} + +static bool remove_entry(const InstanceKlass* ik) { + assert(ik != nullptr, "invariant"); + FinalizerEntryLookup lookup(ik); + return _table->remove(Thread::current(), lookup); +} + +static void on_unloading(Klass* klass) { + assert(klass != nullptr, "invariant"); + if (!klass->is_instance_klass()) { + return; + } + const InstanceKlass* const ik = InstanceKlass::cast(klass); + if (ik->has_finalizer()) { + remove_entry(ik); + } +} + +void FinalizerService::purge_unloaded() { + assert_locked_or_safepoint(ClassLoaderDataGraph_lock); + ClassLoaderDataGraph::classes_unloading_do(&on_unloading); +} + +#endif // INCLUDE_MANAGEMENT diff --git a/src/hotspot/share/services/finalizerService.hpp b/src/hotspot/share/services/finalizerService.hpp new file mode 100644 index 00000000000..74c4452e08a --- /dev/null +++ b/src/hotspot/share/services/finalizerService.hpp @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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_SERVICES_FINALIZERSERVICE_HPP +#define SHARE_SERVICES_FINALIZERSERVICE_HPP + +#include "memory/allocation.hpp" +#include "oops/oopsHierarchy.hpp" + +class InstanceKlass; +class JavaThread; +class Thread; + +class FinalizerEntry : public CHeapObj { + private: + const InstanceKlass* const _ik; + uintptr_t _objects_on_heap; + uintptr_t _total_finalizers_run; + public: + FinalizerEntry(const InstanceKlass* ik); + const InstanceKlass* klass() const NOT_MANAGEMENT_RETURN_(nullptr); + uintptr_t objects_on_heap() const NOT_MANAGEMENT_RETURN_(0L); + uintptr_t total_finalizers_run() const NOT_MANAGEMENT_RETURN_(0L); + void on_register() NOT_MANAGEMENT_RETURN; + void on_complete() NOT_MANAGEMENT_RETURN; +}; + +class FinalizerEntryClosure : public StackObj { + public: + virtual bool do_entry(const FinalizerEntry* fe) = 0; +}; + +class FinalizerService : AllStatic { + friend class ServiceThread; + private: + static bool has_work() NOT_MANAGEMENT_RETURN_(false); + static void do_concurrent_work(JavaThread* service_thread) NOT_MANAGEMENT_RETURN; + public: + static void init() NOT_MANAGEMENT_RETURN; + static void purge_unloaded() NOT_MANAGEMENT_RETURN; + static void on_register(oop finalizee, Thread* thread) NOT_MANAGEMENT_RETURN; + static void on_complete(oop finalizee, JavaThread* finalizer_thread) NOT_MANAGEMENT_RETURN; + static void do_entries(FinalizerEntryClosure* closure, Thread* thread) NOT_MANAGEMENT_RETURN; + static const FinalizerEntry* lookup(const InstanceKlass* ik, Thread* thread) NOT_MANAGEMENT_RETURN_(nullptr); +}; + +#endif // SHARE_SERVICES_FINALIZERSERVICE_HPP diff --git a/src/hotspot/share/services/management.cpp b/src/hotspot/share/services/management.cpp index df4c20cebf1..7f103ea7849 100644 --- a/src/hotspot/share/services/management.cpp +++ b/src/hotspot/share/services/management.cpp @@ -55,6 +55,7 @@ #include "services/classLoadingService.hpp" #include "services/diagnosticCommand.hpp" #include "services/diagnosticFramework.hpp" +#include "services/finalizerService.hpp" #include "services/writeableFlags.hpp" #include "services/heapDumper.hpp" #include "services/lowMemoryDetector.hpp" @@ -94,6 +95,7 @@ void management_init() { ThreadService::init(); RuntimeService::init(); ClassLoadingService::init(); + FinalizerService::init(); #else ThreadService::init(); #endif // INCLUDE_MANAGEMENT @@ -206,6 +208,15 @@ InstanceKlass* Management::initialize_klass(Klass* k, TRAPS) { return ik; } + +void Management::record_vm_init_completed() { + // Initialize the timestamp to get the current time + _vm_init_done_time->set_value(os::javaTimeMillis()); + + // Update the timestamp to the vm init done time + _stamp.update(); +} + void Management::record_vm_startup_time(jlong begin, jlong duration) { // if the performance counter is not initialized, // then vm initialization failed; simply return. @@ -216,6 +227,14 @@ void Management::record_vm_startup_time(jlong begin, jlong duration) { PerfMemory::set_accessible(true); } +jlong Management::begin_vm_creation_time() { + return _begin_vm_creation_time->get_value(); +} + +jlong Management::vm_init_done_time() { + return _vm_init_done_time->get_value(); +} + jlong Management::timestamp() { TimeStamp t; t.update(); diff --git a/src/hotspot/share/services/management.hpp b/src/hotspot/share/services/management.hpp index 96b50eb3e61..8c5be096b3c 100644 --- a/src/hotspot/share/services/management.hpp +++ b/src/hotspot/share/services/management.hpp @@ -70,20 +70,10 @@ public: static void record_vm_startup_time(jlong begin, jlong duration) NOT_MANAGEMENT_RETURN; - static void record_vm_init_completed() { - // Initialize the timestamp to get the current time - _vm_init_done_time->set_value(os::javaTimeMillis()); + static void record_vm_init_completed() NOT_MANAGEMENT_RETURN; - // Update the timestamp to the vm init done time - _stamp.update(); - } - - static jlong begin_vm_creation_time() { - return _begin_vm_creation_time->get_value(); - } - static jlong vm_init_done_time() { - return _vm_init_done_time->get_value(); - } + static jlong begin_vm_creation_time() NOT_MANAGEMENT_RETURN_(0L); + static jlong vm_init_done_time() NOT_MANAGEMENT_RETURN_(0L); // methods to return a Klass*. static InstanceKlass* java_lang_management_ThreadInfo_klass(TRAPS); diff --git a/src/hotspot/share/utilities/macros.hpp b/src/hotspot/share/utilities/macros.hpp index 501ba0dbabc..9b362b88c11 100644 --- a/src/hotspot/share/utilities/macros.hpp +++ b/src/hotspot/share/utilities/macros.hpp @@ -126,9 +126,11 @@ #if INCLUDE_MANAGEMENT #define NOT_MANAGEMENT_RETURN /* next token must be ; */ #define NOT_MANAGEMENT_RETURN_(code) /* next token must be ; */ +#define MANAGEMENT_ONLY(x) x #else #define NOT_MANAGEMENT_RETURN {} #define NOT_MANAGEMENT_RETURN_(code) { return code; } +#define MANAGEMENT_ONLY(x) #endif // INCLUDE_MANAGEMENT #ifndef INCLUDE_EPSILONGC diff --git a/src/java.base/share/classes/java/lang/ref/Finalizer.java b/src/java.base/share/classes/java/lang/ref/Finalizer.java index 9b402caca44..d5838b7a6b1 100644 --- a/src/java.base/share/classes/java/lang/ref/Finalizer.java +++ b/src/java.base/share/classes/java/lang/ref/Finalizer.java @@ -86,6 +86,7 @@ final class Finalizer extends FinalReference { /* Package-private; must assert finalizee != null; if (!(finalizee instanceof java.lang.Enum)) { jla.invokeFinalize(finalizee); + reportComplete(finalizee); // Clear stack slot containing this variable, to decrease // the chances of false retention with a conservative GC @@ -95,6 +96,8 @@ final class Finalizer extends FinalReference { /* Package-private; must super.clear(); } + private static native void reportComplete(Object finalizee); + /* Create a privileged secondary finalizer thread in the system thread * group for the given Runnable, and wait for it to complete. * diff --git a/src/java.base/share/native/libjava/Finalizer.c b/src/java.base/share/native/libjava/Finalizer.c new file mode 100644 index 00000000000..d0b81f63d6e --- /dev/null +++ b/src/java.base/share/native/libjava/Finalizer.c @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "jvm.h" + +#include "java_lang_ref_Finalizer.h" + +JNIEXPORT void JNICALL +Java_java_lang_ref_Finalizer_reportComplete(JNIEnv* env, jclass cls, jobject finalizee) { + JVM_ReportFinalizationComplete(env, finalizee); +} + + diff --git a/src/jdk.jfr/share/conf/jfr/default.jfc b/src/jdk.jfr/share/conf/jfr/default.jfc index 6c83215981b..b168791f479 100644 --- a/src/jdk.jfr/share/conf/jfr/default.jfc +++ b/src/jdk.jfr/share/conf/jfr/default.jfc @@ -807,6 +807,11 @@ true + + true + endChunk + + diff --git a/src/jdk.jfr/share/conf/jfr/profile.jfc b/src/jdk.jfr/share/conf/jfr/profile.jfc index ae3df6a9314..8d1bada4638 100644 --- a/src/jdk.jfr/share/conf/jfr/profile.jfc +++ b/src/jdk.jfr/share/conf/jfr/profile.jfc @@ -807,6 +807,11 @@ true + + true + endChunk + + diff --git a/test/jdk/jdk/jfr/event/runtime/TestFinalizerStatisticsEvent.java b/test/jdk/jdk/jfr/event/runtime/TestFinalizerStatisticsEvent.java new file mode 100644 index 00000000000..1024855a7f1 --- /dev/null +++ b/test/jdk/jdk/jfr/event/runtime/TestFinalizerStatisticsEvent.java @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 jdk.jfr.event.runtime; + +import java.util.List; +import jdk.jfr.Recording; +import jdk.jfr.consumer.RecordedClass; +import jdk.jfr.consumer.RecordedEvent; +import jdk.test.lib.Asserts; +import jdk.test.lib.jfr.EventNames; +import jdk.test.lib.jfr.Events; +import jdk.test.lib.jfr.TestClassLoader; + +/** + * @test + * @summary The test verifies that classes overriding finalize() are represented as events. + * @key jfr + * @requires vm.hasJFR + * @library /test/lib /test/jdk + * @run main/othervm -Xlog:class+unload,finalizer -Xmx16m jdk.jfr.event.runtime.TestFinalizerStatisticsEvent + */ + +public final class TestFinalizerStatisticsEvent { + private final static String TEST_CLASS_NAME = "jdk.jfr.event.runtime.TestFinalizerStatisticsEvent$TestClassOverridingFinalize"; + private final static String TEST_CLASS_UNLOAD_NAME = "jdk.jfr.event.runtime.TestFinalizerStatisticsEvent$TestClassUnloadOverridingFinalize"; + private final static String EVENT_PATH = EventNames.FinalizerStatistics; + + // Declare as public static to prevent the compiler from optimizing away all unread writes + public static TestClassLoader unloadableClassLoader; + public static Class unloadOverrideClass; + public static Object overridingInstance; + + public static void main(String[] args) throws Throwable { + Recording recording1 = new Recording(); + recording1.enable(EVENT_PATH); + Recording recording2 = new Recording(); + recording2.enable(EVENT_PATH); + recording1.start(); + allocateAndGC(); + recording2.start(); // rotation writes an event for TEST_CLASS_NAME into recording1 + unloadableClassLoader = new TestClassLoader(); + unloadOverrideClass = unloadableClassLoader.loadClass(TEST_CLASS_UNLOAD_NAME); + unloadOverrideClass = null; + unloadableClassLoader = null; + allocateAndGC(); // the unloading of class TEST_CLASS_UNLOAD_NAME is intercepted and an event is written into both recording1 and recording2 + recording2.stop(); // rotation writes an event for TEST_CLASS_NAME into both recording1 and recording2 + allocateAndGC(); + recording1.stop(); // rotation writes an event for TEST_CLASS_NAME into recording1 which now has 4 events reflecting this test case (3 chunks + 1 unload) + + try { + verify(recording2); + verify(recording1); + } + finally { + recording2.close(); + recording1.close(); + } + } + + private static void allocateAndGC() { + overridingInstance = new TestClassOverridingFinalize(); + overridingInstance = null; + System.gc(); + } + + private static void verify(Recording recording) throws Throwable { + boolean foundTestClassName = false; + boolean foundTestClassUnloadName = false; + List events = Events.fromRecording(recording); + Events.hasEvents(events); + for (RecordedEvent event : events) { + System.out.println("Event:" + event); + RecordedClass overridingClass = event.getValue("finalizableClass"); + switch (overridingClass.getName()) { + case TEST_CLASS_NAME: { + Asserts.assertTrue(event.getString("codeSource").startsWith("file://")); + foundTestClassName = true; + break; + } + case TEST_CLASS_UNLOAD_NAME: { + Asserts.assertTrue(event.getString("codeSource").startsWith("file://")); + foundTestClassUnloadName = true; + break; + } + } + } + Asserts.assertTrue(foundTestClassName, "The class: " + TEST_CLASS_NAME + " overriding finalize() is not found"); + Asserts.assertTrue(foundTestClassUnloadName, "The class: " + TEST_CLASS_UNLOAD_NAME + " overriding finalize() is not found"); + } + + static public class TestClassOverridingFinalize { + public boolean finalized = false; + + @Override + protected void finalize() { + finalized = true; + } + } + + static public class TestClassUnloadOverridingFinalize { + public boolean finalized = false; + + @Override + protected void finalize() { + finalized = true; + } + } +} diff --git a/test/lib/jdk/test/lib/jfr/EventNames.java b/test/lib/jdk/test/lib/jfr/EventNames.java index 34df9600ec6..c17b503463f 100644 --- a/test/lib/jdk/test/lib/jfr/EventNames.java +++ b/test/lib/jdk/test/lib/jfr/EventNames.java @@ -88,6 +88,7 @@ public class EventNames { public static final String RedefineClasses = PREFIX + "RedefineClasses"; public static final String RetransformClasses = PREFIX + "RetransformClasses"; public static final String ClassRedefinition = PREFIX + "ClassRedefinition"; + public static final String FinalizerStatistics = PREFIX + "FinalizerStatistics"; // This event is hard to test public final static String ReservedStackActivation = PREFIX + "ReservedStackActivation"; diff --git a/test/lib/jdk/test/lib/jfr/TestClassLoader.java b/test/lib/jdk/test/lib/jfr/TestClassLoader.java index fe9e25d26a9..4e463828c66 100644 --- a/test/lib/jdk/test/lib/jfr/TestClassLoader.java +++ b/test/lib/jdk/test/lib/jfr/TestClassLoader.java @@ -28,6 +28,10 @@ package jdk.test.lib.jfr; import java.io.DataInputStream; import java.io.IOException; import java.io.InputStream; +import java.net.URL; +import java.security.cert.Certificate; +import java.security.CodeSource; +import java.security.ProtectionDomain; /** * Custom class loader which will try to load the class via getResourceAsStream(). @@ -53,7 +57,10 @@ public class TestClassLoader extends ClassLoader { dis = new DataInputStream(is); dis.readFully(buf); dis.close(); - return defineClass(name, buf, 0, buf.length); + URL url = getResource(resourceName); + CodeSource cs = new CodeSource(url, (Certificate[])null); + ProtectionDomain pd = new ProtectionDomain(cs, null); + return defineClass(name, buf, 0, buf.length, pd); } } catch (SecurityException e) { // This error will happen quite often (for example when loading -- GitLab From bad75e6796aa7940a9418e317021242ba11d8d50 Mon Sep 17 00:00:00 2001 From: Calvin Cheung Date: Mon, 18 Oct 2021 18:05:39 +0000 Subject: [PATCH 243/385] 8275150: URLClassLoaderTable should store OopHandle instead of Handle Reviewed-by: stefank, minqi --- src/hotspot/share/cds/unregisteredClasses.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/hotspot/share/cds/unregisteredClasses.cpp b/src/hotspot/share/cds/unregisteredClasses.cpp index c17c3543109..c0b20e9a966 100644 --- a/src/hotspot/share/cds/unregisteredClasses.cpp +++ b/src/hotspot/share/cds/unregisteredClasses.cpp @@ -34,7 +34,8 @@ #include "memory/oopFactory.hpp" #include "memory/resourceArea.hpp" #include "oops/instanceKlass.hpp" -#include "runtime/handles.hpp" +#include "oops/oopHandle.inline.hpp" +#include "runtime/handles.inline.hpp" #include "runtime/javaCalls.hpp" #include "services/threadService.hpp" @@ -72,7 +73,7 @@ InstanceKlass* UnregisteredClasses::load_class(Symbol* name, const char* path, T } class URLClassLoaderTable : public ResourceHashtable< - Symbol*, Handle, + Symbol*, OopHandle, 137, // prime number ResourceObj::C_HEAP> {}; @@ -103,12 +104,12 @@ Handle UnregisteredClasses::get_url_classloader(Symbol* path, TRAPS) { if (_url_classloader_table == NULL) { _url_classloader_table = new (ResourceObj::C_HEAP, mtClass)URLClassLoaderTable(); } - Handle* url_classloader_ptr = _url_classloader_table->get(path); + OopHandle* url_classloader_ptr = _url_classloader_table->get(path); if (url_classloader_ptr != NULL) { - return *url_classloader_ptr; + return Handle(THREAD, (*url_classloader_ptr).resolve()); } else { Handle url_classloader = create_url_classloader(path, CHECK_NH); - _url_classloader_table->put(path, url_classloader); + _url_classloader_table->put(path, OopHandle(Universe::vm_global(), url_classloader())); path->increment_refcount(); return url_classloader; } -- GitLab From a03119ce1a34642565c669bd2471f52eec088b96 Mon Sep 17 00:00:00 2001 From: "Daniel D. Daugherty" Date: Mon, 18 Oct 2021 18:25:53 +0000 Subject: [PATCH 244/385] 8275436: [BACKOUT] JDK-8271949 dumppath in -XX:FlightRecorderOptions does not affect Reviewed-by: mgronlun --- src/hotspot/share/jfr/jni/jfrJniMethod.cpp | 13 +---- src/hotspot/share/jfr/jni/jfrJniMethod.hpp | 6 +- .../jfr/jni/jfrJniMethodRegistration.cpp | 2 - .../recorder/repository/jfrEmergencyDump.cpp | 45 +++------------ .../recorder/repository/jfrEmergencyDump.hpp | 9 +-- .../jfr/recorder/service/jfrOptionSet.cpp | 21 ------- .../share/classes/jdk/jfr/internal/JVM.java | 17 +----- .../classes/jdk/jfr/internal/Options.java | 28 ++------- .../jdk/jfr/internal/SecuritySupport.java | 1 + test/jdk/jdk/jfr/jvm/TestDumpOnCrash.java | 57 +++++-------------- 10 files changed, 32 insertions(+), 167 deletions(-) diff --git a/src/hotspot/share/jfr/jni/jfrJniMethod.cpp b/src/hotspot/share/jfr/jni/jfrJniMethod.cpp index f02469ab2c0..54a4680ced8 100644 --- a/src/hotspot/share/jfr/jni/jfrJniMethod.cpp +++ b/src/hotspot/share/jfr/jni/jfrJniMethod.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,7 +35,6 @@ #include "jfr/recorder/repository/jfrRepository.hpp" #include "jfr/recorder/repository/jfrChunkRotation.hpp" #include "jfr/recorder/repository/jfrChunkWriter.hpp" -#include "jfr/recorder/repository/jfrEmergencyDump.hpp" #include "jfr/recorder/service/jfrEventThrottler.hpp" #include "jfr/recorder/service/jfrOptionSet.hpp" #include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp" @@ -316,16 +315,6 @@ JVM_ENTRY_NO_ENV(void, jfr_set_repository_location(JNIEnv* env, jobject repo, js return JfrRepository::set_path(location, thread); JVM_END -NO_TRANSITION(void, jfr_set_dump_path(JNIEnv* env, jobject jvm, jstring dumppath)) - const char* dump_path = env->GetStringUTFChars(dumppath, NULL); - JfrEmergencyDump::set_dump_path(dump_path); - env->ReleaseStringUTFChars(dumppath, dump_path); -NO_TRANSITION_END - -NO_TRANSITION(jstring, jfr_get_dump_path(JNIEnv* env, jobject jvm)) - return env->NewStringUTF(JfrEmergencyDump::get_dump_path()); -NO_TRANSITION_END - JVM_ENTRY_NO_ENV(void, jfr_uncaught_exception(JNIEnv* env, jobject jvm, jobject t, jthrowable throwable)) JfrJavaSupport::uncaught_exception(throwable, thread); JVM_END diff --git a/src/hotspot/share/jfr/jni/jfrJniMethod.hpp b/src/hotspot/share/jfr/jni/jfrJniMethod.hpp index 946ef04470d..19a676c4a22 100644 --- a/src/hotspot/share/jfr/jni/jfrJniMethod.hpp +++ b/src/hotspot/share/jfr/jni/jfrJniMethod.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -113,10 +113,6 @@ jlong JNICALL jfr_type_id(JNIEnv* env, jobject jvm, jclass jc); void JNICALL jfr_set_repository_location(JNIEnv* env, jobject repo, jstring location); -void JNICALL jfr_set_dump_path(JNIEnv* env, jobject jvm, jstring dumppath); - -jstring JNICALL jfr_get_dump_path(JNIEnv* env, jobject jvm); - jobject JNICALL jfr_get_event_writer(JNIEnv* env, jclass cls); jobject JNICALL jfr_new_event_writer(JNIEnv* env, jclass cls); diff --git a/src/hotspot/share/jfr/jni/jfrJniMethodRegistration.cpp b/src/hotspot/share/jfr/jni/jfrJniMethodRegistration.cpp index 5bc8a95a826..db137776f65 100644 --- a/src/hotspot/share/jfr/jni/jfrJniMethodRegistration.cpp +++ b/src/hotspot/share/jfr/jni/jfrJniMethodRegistration.cpp @@ -75,8 +75,6 @@ JfrJniMethodRegistration::JfrJniMethodRegistration(JNIEnv* env) { (char*)"flush", (char*)"(Ljdk/jfr/internal/EventWriter;II)Z", (void*)jfr_event_writer_flush, (char*)"flush", (char*)"()V", (void*)jfr_flush, (char*)"setRepositoryLocation", (char*)"(Ljava/lang/String;)V", (void*)jfr_set_repository_location, - (char*)"setDumpPath", (char*)"(Ljava/lang/String;)V", (void*)jfr_set_dump_path, - (char*)"getDumpPath", (char*)"()Ljava/lang/String;", (void*)jfr_get_dump_path, (char*)"abort", (char*)"(Ljava/lang/String;)V", (void*)jfr_abort, (char*)"addStringConstant", (char*)"(JLjava/lang/String;)Z", (void*)jfr_add_string_constant, (char*)"uncaughtException", (char*)"(Ljava/lang/Thread;Ljava/lang/Throwable;)V", (void*)jfr_uncaught_exception, diff --git a/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp b/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp index c00bed02b52..0bcfc8568f5 100644 --- a/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp +++ b/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp @@ -41,8 +41,6 @@ #include "utilities/growableArray.hpp" #include "utilities/ostream.hpp" -char JfrEmergencyDump::_dump_path[JVM_MAXPATHLEN] = { 0 }; - static const char vm_error_filename_fmt[] = "hs_err_pid%p.jfr"; static const char vm_oom_filename_fmt[] = "hs_oom_pid%p.jfr"; static const char vm_soe_filename_fmt[] = "hs_soe_pid%p.jfr"; @@ -68,17 +66,12 @@ static bool is_path_empty() { } // returns with an appended file separator (if successful) -static size_t get_dump_directory() { - const char* dump_path = JfrEmergencyDump::get_dump_path(); - if (*dump_path == '\0') { - if (os::get_current_directory(_path_buffer, sizeof(_path_buffer)) == NULL) { - return 0; - } - } else { - strcpy(_path_buffer, dump_path); +static size_t get_current_directory() { + if (os::get_current_directory(_path_buffer, sizeof(_path_buffer)) == NULL) { + return 0; } - const size_t path_len = strlen(_path_buffer); - const int result = jio_snprintf(_path_buffer + path_len, + const size_t cwd_len = strlen(_path_buffer); + const int result = jio_snprintf(_path_buffer + cwd_len, sizeof(_path_buffer), "%s", os::file_separator()); @@ -112,7 +105,7 @@ static void close_emergency_dump_file() { static const char* create_emergency_dump_path() { assert(is_path_empty(), "invariant"); - const size_t path_len = get_dump_directory(); + const size_t path_len = get_current_directory(); if (path_len == 0) { return NULL; } @@ -132,21 +125,12 @@ static const char* create_emergency_dump_path() { return result ? _path_buffer : NULL; } -bool JfrEmergencyDump::open_emergency_dump_file() { +static bool open_emergency_dump_file() { if (is_emergency_dump_file_open()) { // opened already return true; } - - bool result = open_emergency_dump_fd(create_emergency_dump_path()); - if (!result && *_dump_path != '\0') { - log_warning(jfr)("Unable to create an emergency dump file at the location set by dumppath=%s", _dump_path); - // Fallback. Try to create it in the current directory. - *_dump_path = '\0'; - *_path_buffer = '\0'; - result = open_emergency_dump_fd(create_emergency_dump_path()); - } - return result; + return open_emergency_dump_fd(create_emergency_dump_path()); } static void report(outputStream* st, bool emergency_file_opened, const char* repository_path) { @@ -166,19 +150,6 @@ static void report(outputStream* st, bool emergency_file_opened, const char* rep } } -void JfrEmergencyDump::set_dump_path(const char* dump_path) { - if (dump_path != NULL) { - if (strlen(dump_path) < JVM_MAXPATHLEN) { - strncpy(_dump_path, dump_path, JVM_MAXPATHLEN); - _dump_path[JVM_MAXPATHLEN - 1] = '\0'; - } - } -} - -const char* JfrEmergencyDump::get_dump_path() { - return _dump_path; -} - void JfrEmergencyDump::on_vm_error_report(outputStream* st, const char* repository_path) { assert(st != NULL, "invariant"); Thread* thread = Thread::current_or_null_safe(); diff --git a/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.hpp b/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.hpp index c96a7d802dc..909f73bf892 100644 --- a/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.hpp +++ b/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,14 +32,7 @@ // Responsible for creating an hs_err.jfr file in exceptional shutdown situations (crash, OOM) // class JfrEmergencyDump : AllStatic { - private: - static char _dump_path[JVM_MAXPATHLEN]; - - static bool open_emergency_dump_file(); - public: - static void set_dump_path(const char* dump_path); - static const char* get_dump_path(); static const char* chunk_path(const char* repository_path); static void on_vm_error(const char* repository_path); static void on_vm_error_report(outputStream* st, const char* repository_path); diff --git a/src/hotspot/share/jfr/recorder/service/jfrOptionSet.cpp b/src/hotspot/share/jfr/recorder/service/jfrOptionSet.cpp index ce8fc5e4efa..166603d4397 100644 --- a/src/hotspot/share/jfr/recorder/service/jfrOptionSet.cpp +++ b/src/hotspot/share/jfr/recorder/service/jfrOptionSet.cpp @@ -163,7 +163,6 @@ bool JfrOptionSet::allow_event_retransforms() { // default options for the dcmd parser const char* const default_repository = NULL; -const char* const default_dumppath = NULL; const char* const default_global_buffer_size = "512k"; const char* const default_num_global_buffers = "20"; const char* const default_memory_size = "10m"; @@ -183,13 +182,6 @@ static DCmdArgument _dcmd_repository( false, default_repository); -static DCmdArgument _dcmd_dumppath( - "dumppath", - "Path to emergency dump", - "STRING", - false, - default_dumppath); - static DCmdArgument _dcmd_threadbuffersize( "threadbuffersize", "Thread buffer size", @@ -266,7 +258,6 @@ static DCmdParser _parser; static void register_parser_options() { _parser.add_dcmd_option(&_dcmd_repository); - _parser.add_dcmd_option(&_dcmd_dumppath); _parser.add_dcmd_option(&_dcmd_threadbuffersize); _parser.add_dcmd_option(&_dcmd_memorysize); _parser.add_dcmd_option(&_dcmd_globalbuffersize); @@ -355,18 +346,6 @@ bool JfrOptionSet::configure(TRAPS) { configure._repository_path.set_value(repo_copy); } - configure._dump_path.set_is_set(_dcmd_dumppath.is_set()); - char* dumppath = _dcmd_dumppath.value(); - if (dumppath != NULL) { - const size_t len = strlen(dumppath); - char* dumppath_copy = JfrCHeapObj::new_array(len + 1); - if (NULL == dumppath_copy) { - return false; - } - strncpy(dumppath_copy, dumppath, len + 1); - configure._dump_path.set_value(dumppath_copy); - } - configure._stack_depth.set_is_set(_dcmd_stackdepth.is_set()); configure._stack_depth.set_value(_dcmd_stackdepth.value()); diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/JVM.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/JVM.java index 2b2dd27ff4b..a88b428dac3 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/JVM.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/JVM.java @@ -473,26 +473,13 @@ public final class JVM { public native void flush(); /** - * Sets the location of the disk repository. + * Sets the location of the disk repository, to be used at an emergency + * dump. * * @param dirText */ public native void setRepositoryLocation(String dirText); - /** - * Sets the path to emergency dump. - * - * @param dumpPathText - */ - public native void setDumpPath(String dumpPathText); - - /** - * Gets the path to emergency dump. - * - * @return The path to emergency dump. - */ - public native String getDumpPath(); - /** * Access to VM termination support. * diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/Options.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/Options.java index 5398b599422..4d430bebba2 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/Options.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/Options.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,16 +25,9 @@ package jdk.jfr.internal; -import java.io.IOException; - -import jdk.jfr.internal.LogLevel; -import jdk.jfr.internal.LogTag; -import jdk.jfr.internal.Logger; import jdk.jfr.internal.SecuritySupport.SafePath; import jdk.internal.misc.Unsafe; -import static java.nio.file.LinkOption.*; - /** * Options that control Flight Recorder. * @@ -55,7 +48,7 @@ public final class Options { private static final int DEFAULT_STACK_DEPTH = 64; private static final boolean DEFAULT_SAMPLE_THREADS = true; private static final long DEFAULT_MAX_CHUNK_SIZE = 12 * 1024 * 1024; - private static final SafePath DEFAULT_DUMP_PATH = new SafePath("."); + private static final SafePath DEFAULT_DUMP_PATH = SecuritySupport.USER_HOME; private static long memorySize; private static long globalBufferSize; @@ -64,6 +57,7 @@ public final class Options { private static int stackDepth; private static boolean sampleThreads; private static long maxChunkSize; + private static SafePath dumpPath; static { final long pageSize = Unsafe.getUnsafe().pageSize(); @@ -120,23 +114,11 @@ public final class Options { } public static synchronized void setDumpPath(SafePath path) { - if (path.toFile().canWrite()) { - try { - jvm.setDumpPath(path.toPath().toRealPath(NOFOLLOW_LINKS).toString()); - } catch (IOException e) { - if (Logger.shouldLog(LogTag.JFR_SYSTEM_SETTING, LogLevel.WARN)) { - Logger.log(LogTag.JFR_SYSTEM_SETTING, LogLevel.WARN, "Error occurred in path resolution: " + e.toString()); - } - } - } else { - if (Logger.shouldLog(LogTag.JFR_SYSTEM_SETTING, LogLevel.WARN)) { - Logger.log(LogTag.JFR_SYSTEM_SETTING, LogLevel.WARN, "Cannot write JFR emergency dump to " + path.toString()); - } - } + dumpPath = path; } public static synchronized SafePath getDumpPath() { - return new SafePath(jvm.getDumpPath()); + return dumpPath; } public static synchronized void setStackDepth(Integer stackTraceDepth) { diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/SecuritySupport.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/SecuritySupport.java index 81ae6d4f097..d761eb98c58 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/SecuritySupport.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/SecuritySupport.java @@ -77,6 +77,7 @@ public final class SecuritySupport { private static final Module JFR_MODULE = Event.class.getModule(); public static final SafePath JFC_DIRECTORY = getPathInProperty("java.home", "lib/jfr"); public static final FileAccess PRIVILEGED = new Privileged(); + static final SafePath USER_HOME = getPathInProperty("user.home", null); static final SafePath JAVA_IO_TMPDIR = getPathInProperty("java.io.tmpdir", null); static { diff --git a/test/jdk/jdk/jfr/jvm/TestDumpOnCrash.java b/test/jdk/jdk/jfr/jvm/TestDumpOnCrash.java index 870ccbee5f7..3869509b242 100644 --- a/test/jdk/jdk/jfr/jvm/TestDumpOnCrash.java +++ b/test/jdk/jdk/jfr/jvm/TestDumpOnCrash.java @@ -26,7 +26,6 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.ArrayList; import java.util.List; import jdk.internal.misc.Unsafe; @@ -75,49 +74,22 @@ public class TestDumpOnCrash { } public static void main(String[] args) throws Exception { - // Test without dumppath test(CrasherIllegalAccess.class, "", true); test(CrasherIllegalAccess.class, "", false); test(CrasherHalt.class, "", true); test(CrasherHalt.class, "", false); - // Test with dumppath - Path dumppath = Files.createTempDirectory(null); - try { - test(CrasherIllegalAccess.class, "", true, dumppath.toString()); - test(CrasherIllegalAccess.class, "", false, dumppath.toString()); - test(CrasherHalt.class, "", true, dumppath.toString()); - test(CrasherHalt.class, "", false, dumppath.toString()); - } finally { - dumppath.toFile().delete(); - } - - // Test with illegal dumppath - Path illegalpath = Path.of("silverbullet"); - test(CrasherIllegalAccess.class, "", true, illegalpath.toString(), null); - test(CrasherIllegalAccess.class, "", false, illegalpath.toString(), null); - test(CrasherHalt.class, "", true, illegalpath.toString(), null); - test(CrasherHalt.class, "", false, illegalpath.toString(), null); - // Test is excluded until 8219680 is fixed // @ignore 8219680 // test(CrasherSig.class, "FPE", true); } private static void test(Class crasher, String signal, boolean disk) throws Exception { - test(crasher, signal, disk, null); - } - - private static void test(Class crasher, String signal, boolean disk, String dumppath) throws Exception { - test(crasher, signal, disk, dumppath, dumppath); - } - - private static void test(Class crasher, String signal, boolean disk, String dumppath, String expectedPath) throws Exception { // The JVM may be in a state it can't recover from, so try three times // before concluding functionality is not working. for (int attempt = 0; attempt < ATTEMPTS; attempt++) { try { - verify(runProcess(crasher, signal, disk, dumppath), expectedPath); + verify(runProcess(crasher, signal, disk)); return; } catch (Exception e) { System.out.println("Attempt " + attempt + ". Verification failed:"); @@ -133,19 +105,17 @@ public class TestDumpOnCrash { throw new Exception(ATTEMPTS + " attempts with failure!"); } - private static long runProcess(Class crasher, String signal, boolean disk, String dumppath) throws Exception { + private static long runProcess(Class crasher, String signal, boolean disk) throws Exception { System.out.println("Test case for crasher " + crasher.getName()); - List options = new ArrayList<>(); - options.add("-Xmx64m"); - options.add("-XX:-CreateCoredumpOnCrash"); - options.add("--add-exports=java.base/jdk.internal.misc=ALL-UNNAMED"); - options.add("-XX:StartFlightRecording:dumponexit=true,disk=" + Boolean.toString(disk)); - if (dumppath != null) { - options.add("-XX:FlightRecorderOptions=dumppath=" + dumppath); - } - options.add(crasher.getName()); - options.add(signal); - Process p = ProcessTools.createTestJvm(options).start(); + final String flightRecordingOptions = "dumponexit=true,disk=" + Boolean.toString(disk); + Process p = ProcessTools.createTestJvm( + "-Xmx64m", + "-XX:-CreateCoredumpOnCrash", + "--add-exports=java.base/jdk.internal.misc=ALL-UNNAMED", + "-XX:StartFlightRecording:" + flightRecordingOptions, + crasher.getName(), + signal) + .start(); OutputAnalyzer output = new OutputAnalyzer(p); System.out.println("========== Crasher process output:"); @@ -155,10 +125,9 @@ public class TestDumpOnCrash { return p.pid(); } - private static void verify(long pid, String dumppath) throws IOException { + private static void verify(long pid) throws IOException { String fileName = "hs_err_pid" + pid + ".jfr"; - Path file = (dumppath == null) ? Paths.get(fileName) : Paths.get(dumppath, fileName); - file = file.toAbsolutePath().normalize(); + Path file = Paths.get(fileName).toAbsolutePath().normalize(); Asserts.assertTrue(Files.exists(file), "No emergency jfr recording file " + file + " exists"); Asserts.assertNotEquals(Files.size(file), 0L, "File length 0. Should at least be some bytes"); -- GitLab From 947d52c4c3deec1bdea43959c200201c614ae114 Mon Sep 17 00:00:00 2001 From: Jayathirth D V Date: Tue, 19 Oct 2021 04:04:25 +0000 Subject: [PATCH 245/385] 8255898: Test java/awt/FileDialog/FilenameFilterTest/FilenameFilterTest.java fails on Mac OS Reviewed-by: prr, serb --- test/jdk/ProblemList.txt | 2 +- .../awt/FileDialog/FilenameFilterTest/FilenameFilterTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 781147ad09b..aaa505deae5 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -481,7 +481,7 @@ java/awt/Robot/RobotWheelTest/RobotWheelTest.java 8129827 generic-all java/awt/Focus/WindowUpdateFocusabilityTest/WindowUpdateFocusabilityTest.java 8202926 linux-all java/awt/datatransfer/ConstructFlavoredObjectTest/ConstructFlavoredObjectTest.java 8202860 linux-all java/awt/dnd/DisposeFrameOnDragCrash/DisposeFrameOnDragTest.java 8202790 macosx-all,linux-all -java/awt/FileDialog/FilenameFilterTest/FilenameFilterTest.java 8202882,8255898 linux-all,macosx-all +java/awt/FileDialog/FilenameFilterTest/FilenameFilterTest.java 8202882 linux-all java/awt/dnd/MissingDragExitEventTest/MissingDragExitEventTest.java 8030121 macosx-all,linux-all java/awt/Choice/ChoicePopupLocation/ChoicePopupLocation.java 8202931 macosx-all,linux-all java/awt/Focus/NonFocusableBlockedOwnerTest/NonFocusableBlockedOwnerTest.java 7124275 macosx-all diff --git a/test/jdk/java/awt/FileDialog/FilenameFilterTest/FilenameFilterTest.java b/test/jdk/java/awt/FileDialog/FilenameFilterTest/FilenameFilterTest.java index 959c90b6997..13a3db5bbf4 100644 --- a/test/jdk/java/awt/FileDialog/FilenameFilterTest/FilenameFilterTest.java +++ b/test/jdk/java/awt/FileDialog/FilenameFilterTest/FilenameFilterTest.java @@ -28,7 +28,7 @@ @summary namefilter is not called for file dialog on windows @library ../../regtesthelpers @build Util - @run main FilenameFilterTest + @run main/othervm FilenameFilterTest */ import java.awt.*; -- GitLab From 9d191fce55fa70d6a2affc724fad57b0e20e4bde Mon Sep 17 00:00:00 2001 From: Julia Boes Date: Tue, 19 Oct 2021 10:19:15 +0000 Subject: [PATCH 246/385] 8245095: Implementation of JEP 408: Simple Web Server MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Julia Boes Co-authored-by: Chris Hegarty Co-authored-by: Michael McMahon Co-authored-by: Daniel Fuchs Co-authored-by: Jan Lahoda Co-authored-by: Ivan Šipka Reviewed-by: ihse, jlaskey, michaelm, chegar, dfuchs --- make/CreateJmods.gmk | 7 +- .../tools/symbolgenerator/CreateSymbols.java | 24 + make/modules/jdk.httpserver/Gensrc.gmk | 41 + .../com/sun/net/httpserver/Filter.java | 64 +- .../com/sun/net/httpserver/Headers.java | 81 ++ .../com/sun/net/httpserver/HttpExchange.java | 27 +- .../com/sun/net/httpserver/HttpHandlers.java | 169 +++ .../com/sun/net/httpserver/HttpServer.java | 56 +- .../com/sun/net/httpserver/HttpsServer.java | 60 +- .../com/sun/net/httpserver/Request.java | 120 +++ .../sun/net/httpserver/SimpleFileServer.java | 265 +++++ .../com/sun/net/httpserver/package-info.java | 8 +- .../share/classes/module-info.java | 36 +- .../httpserver/DelegatingHttpExchange.java | 108 ++ .../sun/net/httpserver/ExchangeImpl.java | 2 +- .../simpleserver/FileServerHandler.java | 385 +++++++ .../sun/net/httpserver/simpleserver/Main.java | 65 ++ .../httpserver/simpleserver/OutputFilter.java | 133 +++ .../simpleserver/ResourceBundleHelper.java | 49 + .../simpleserver/SimpleFileServerImpl.java | 216 ++++ .../resources/simpleserver.properties | 70 ++ test/jdk/TEST.ROOT | 5 +- .../com/sun/net/httpserver/FilterTest.java | 104 +- .../com/sun/net/httpserver/HeadersTest.java | 130 +++ .../httpserver/UnmodifiableHeadersTest.java | 21 +- .../simpleserver/CommandLineNegativeTest.java | 245 +++++ .../simpleserver/CommandLinePositiveTest.java | 240 +++++ .../simpleserver/CustomFileSystemTest.java | 970 ++++++++++++++++++ .../simpleserver/FileServerHandlerTest.java | 231 +++++ .../simpleserver/HttpHandlersTest.java | 362 +++++++ .../simpleserver/HttpsServerTest.java | 173 ++++ .../IdempotencyAndCommutativityTest.java | 146 +++ .../simpleserver/MapToPathTest.java | 359 +++++++ .../simpleserver/OutputFilterTest.java | 342 ++++++ .../httpserver/simpleserver/RequestTest.java | 167 +++ .../simpleserver/SecurityManagerTest.java | 201 ++++ .../SecurityManagerTestNoRead.policy | 39 + .../SecurityManagerTestRead.policy | 43 + .../ServerMimeTypesResolutionTest.java | 211 ++++ .../simpleserver/SimpleFileServerTest.java | 703 +++++++++++++ .../simpleserver/StressDirListings.java | 110 ++ .../simpleserver/ZipFileSystemTest.java | 413 ++++++++ 42 files changed, 7166 insertions(+), 35 deletions(-) create mode 100644 make/modules/jdk.httpserver/Gensrc.gmk create mode 100644 src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpHandlers.java create mode 100644 src/jdk.httpserver/share/classes/com/sun/net/httpserver/Request.java create mode 100644 src/jdk.httpserver/share/classes/com/sun/net/httpserver/SimpleFileServer.java create mode 100644 src/jdk.httpserver/share/classes/sun/net/httpserver/DelegatingHttpExchange.java create mode 100644 src/jdk.httpserver/share/classes/sun/net/httpserver/simpleserver/FileServerHandler.java create mode 100644 src/jdk.httpserver/share/classes/sun/net/httpserver/simpleserver/Main.java create mode 100644 src/jdk.httpserver/share/classes/sun/net/httpserver/simpleserver/OutputFilter.java create mode 100644 src/jdk.httpserver/share/classes/sun/net/httpserver/simpleserver/ResourceBundleHelper.java create mode 100644 src/jdk.httpserver/share/classes/sun/net/httpserver/simpleserver/SimpleFileServerImpl.java create mode 100644 src/jdk.httpserver/share/classes/sun/net/httpserver/simpleserver/resources/simpleserver.properties create mode 100644 test/jdk/com/sun/net/httpserver/simpleserver/CommandLineNegativeTest.java create mode 100644 test/jdk/com/sun/net/httpserver/simpleserver/CommandLinePositiveTest.java create mode 100644 test/jdk/com/sun/net/httpserver/simpleserver/CustomFileSystemTest.java create mode 100644 test/jdk/com/sun/net/httpserver/simpleserver/FileServerHandlerTest.java create mode 100644 test/jdk/com/sun/net/httpserver/simpleserver/HttpHandlersTest.java create mode 100644 test/jdk/com/sun/net/httpserver/simpleserver/HttpsServerTest.java create mode 100644 test/jdk/com/sun/net/httpserver/simpleserver/IdempotencyAndCommutativityTest.java create mode 100644 test/jdk/com/sun/net/httpserver/simpleserver/MapToPathTest.java create mode 100644 test/jdk/com/sun/net/httpserver/simpleserver/OutputFilterTest.java create mode 100644 test/jdk/com/sun/net/httpserver/simpleserver/RequestTest.java create mode 100644 test/jdk/com/sun/net/httpserver/simpleserver/SecurityManagerTest.java create mode 100644 test/jdk/com/sun/net/httpserver/simpleserver/SecurityManagerTestNoRead.policy create mode 100644 test/jdk/com/sun/net/httpserver/simpleserver/SecurityManagerTestRead.policy create mode 100644 test/jdk/com/sun/net/httpserver/simpleserver/ServerMimeTypesResolutionTest.java create mode 100644 test/jdk/com/sun/net/httpserver/simpleserver/SimpleFileServerTest.java create mode 100644 test/jdk/com/sun/net/httpserver/simpleserver/StressDirListings.java create mode 100644 test/jdk/com/sun/net/httpserver/simpleserver/ZipFileSystemTest.java diff --git a/make/CreateJmods.gmk b/make/CreateJmods.gmk index 6edc69397a5..d9e5f415fe7 100644 --- a/make/CreateJmods.gmk +++ b/make/CreateJmods.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -196,6 +196,11 @@ else # not java.base endif endif +# Set main class of jdk.httpserver module +ifeq ($(MODULE), jdk.httpserver) + JMOD_FLAGS += --main-class sun.net.httpserver.simpleserver.Main +endif + # Changes to the jmod tool itself should also trigger a rebuild of all jmods. # The variable JMOD_CMD could contain an environment variable assignment before # the actual command. Filter that out using wildcard before adding to DEPS. diff --git a/make/langtools/src/classes/build/tools/symbolgenerator/CreateSymbols.java b/make/langtools/src/classes/build/tools/symbolgenerator/CreateSymbols.java index 71ff01f94dd..1f439e1c29e 100644 --- a/make/langtools/src/classes/build/tools/symbolgenerator/CreateSymbols.java +++ b/make/langtools/src/classes/build/tools/symbolgenerator/CreateSymbols.java @@ -123,6 +123,7 @@ import com.sun.tools.classfile.InnerClasses_attribute; import com.sun.tools.classfile.InnerClasses_attribute.Info; import com.sun.tools.classfile.Method; import com.sun.tools.classfile.MethodParameters_attribute; +import com.sun.tools.classfile.ModuleMainClass_attribute; import com.sun.tools.classfile.ModuleResolution_attribute; import com.sun.tools.classfile.ModuleTarget_attribute; import com.sun.tools.classfile.Module_attribute; @@ -928,6 +929,12 @@ public class CreateSymbols { attributes.put(Attribute.ModuleTarget, new ModuleTarget_attribute(attrIdx, targetIdx)); } + if (header.moduleMainClass != null) { + int attrIdx = addString(cp, Attribute.ModuleMainClass); + int targetIdx = addString(cp, header.moduleMainClass); + attributes.put(Attribute.ModuleMainClass, + new ModuleMainClass_attribute(attrIdx, targetIdx)); + } int attrIdx = addString(cp, Attribute.Module); attributes.put(Attribute.Module, new Module_attribute(attrIdx, @@ -2294,6 +2301,13 @@ public class CreateSymbols { chd.isSealed = true; break; } + case Attribute.ModuleMainClass: { + ModuleMainClass_attribute moduleMainClass = (ModuleMainClass_attribute) attr; + assert feature instanceof ModuleHeaderDescription; + ModuleHeaderDescription mhd = (ModuleHeaderDescription) feature; + mhd.moduleMainClass = moduleMainClass.getMainClassName(cf.constant_pool); + break; + } default: throw new IllegalStateException("Unhandled attribute: " + attrName); @@ -2731,6 +2745,7 @@ public class CreateSymbols { List provides = new ArrayList<>(); Integer moduleResolution; String moduleTarget; + String moduleMainClass; @Override public int hashCode() { @@ -2743,6 +2758,7 @@ public class CreateSymbols { hash = 83 * hash + Objects.hashCode(this.provides); hash = 83 * hash + Objects.hashCode(this.moduleResolution); hash = 83 * hash + Objects.hashCode(this.moduleTarget); + hash = 83 * hash + Objects.hashCode(this.moduleMainClass); return hash; } @@ -2781,6 +2797,10 @@ public class CreateSymbols { other.moduleResolution)) { return false; } + if (!Objects.equals(this.moduleMainClass, + other.moduleMainClass)) { + return false; + } return true; } @@ -2818,6 +2838,8 @@ public class CreateSymbols { output.append(" resolution " + quote(Integer.toHexString(moduleResolution), true)); + if (moduleMainClass != null) + output.append(" moduleMainClass " + quote(moduleMainClass, true)); writeAttributes(output); output.append("\n"); writeInnerClasses(output, baselineVersion, version); @@ -2862,6 +2884,8 @@ public class CreateSymbols { moduleResolution = Integer.parseInt(resolutionFlags, 16); } + moduleMainClass = reader.attributes.get("moduleMainClass"); + readAttributes(reader); reader.moveNext(); readInnerClasses(reader); diff --git a/make/modules/jdk.httpserver/Gensrc.gmk b/make/modules/jdk.httpserver/Gensrc.gmk new file mode 100644 index 00000000000..6e90917db33 --- /dev/null +++ b/make/modules/jdk.httpserver/Gensrc.gmk @@ -0,0 +1,41 @@ +# +# Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +include GensrcCommonJdk.gmk +include GensrcProperties.gmk +include Modules.gmk + +################################################################################ + +# Use wildcard so as to avoid getting non-existing directories back +SIMPLESERVER_RESOURCES_DIRS := $(wildcard $(addsuffix /sun/net/httpserver/simpleserver/resources, \ + $(call FindModuleSrcDirs, jdk.httpserver))) + +$(eval $(call SetupCompileProperties, SIMPLESERVER_PROPERTIES, \ + SRC_DIRS := $(SIMPLESERVER_RESOURCES_DIRS), \ + CLASS := ListResourceBundle, \ +)) + +TARGETS += $(SIMPLESERVER_PROPERTIES) diff --git a/src/jdk.httpserver/share/classes/com/sun/net/httpserver/Filter.java b/src/jdk.httpserver/share/classes/com/sun/net/httpserver/Filter.java index 2149357b97c..7dacefcb59b 100644 --- a/src/jdk.httpserver/share/classes/com/sun/net/httpserver/Filter.java +++ b/src/jdk.httpserver/share/classes/com/sun/net/httpserver/Filter.java @@ -28,10 +28,13 @@ package com.sun.net.httpserver; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.net.URI; import java.util.List; import java.util.ListIterator; import java.util.Objects; import java.util.function.Consumer; +import java.util.function.UnaryOperator; +import sun.net.httpserver.DelegatingHttpExchange; /** * A filter used to pre- and post-process incoming requests. Pre-processing occurs @@ -134,7 +137,6 @@ public abstract class Filter { */ public abstract void doFilter (HttpExchange exchange, Chain chain) throws IOException; - /** * Returns a short description of this {@code Filter}. * @@ -252,4 +254,64 @@ public abstract class Filter { } }; } + + /** + * Returns a + * {@linkplain Filter#beforeHandler(String, Consumer) pre-processing Filter} + * that inspects and possibly adapts the request state. + * + * The {@code Request} returned by the {@link UnaryOperator requestOperator} + * will be the effective request state of the exchange. It is executed for + * each {@code HttpExchange} before invoking either the next filter in the + * chain or the exchange handler (if this is the final filter in the chain). + * Exceptions thrown by the {@code requestOperator} are not handled by the + * filter. + * + * @apiNote + * When the returned filter is invoked, it first invokes the + * {@code requestOperator} with the given exchange, {@code ex}, in order to + * retrieve the adapted request state. It then invokes the next + * filter in the chain or the exchange handler, passing an exchange + * equivalent to {@code ex} with the adapted request state set as the + * effective request state. + * + *

      Example of adding the {@code "Foo"} request header to all requests: + *

      {@code
      +     *     var filter = Filter.adaptRequest("Add Foo header", r -> r.with("Foo", List.of("Bar")));
      +     *     httpContext.getFilters().add(filter);
      +     * }
      + * + * @param description the string to be returned from {@link #description()} + * @param requestOperator the request operator + * @return a filter that adapts the request state before the exchange is handled + * @throws NullPointerException if any argument is null + * @since 18 + */ + public static Filter adaptRequest(String description, + UnaryOperator requestOperator) { + Objects.requireNonNull(description); + Objects.requireNonNull(requestOperator); + + return new Filter() { + @Override + public void doFilter(HttpExchange exchange, Chain chain) throws IOException { + var request = requestOperator.apply(exchange); + var newExchange = new DelegatingHttpExchange(exchange) { + @Override + public URI getRequestURI() { return request.getRequestURI(); } + + @Override + public String getRequestMethod() { return request.getRequestMethod(); } + + @Override + public Headers getRequestHeaders() { return request.getRequestHeaders(); } + }; + chain.doFilter(newExchange); + } + @Override + public String description() { + return description; + } + }; + } } diff --git a/src/jdk.httpserver/share/classes/com/sun/net/httpserver/Headers.java b/src/jdk.httpserver/share/classes/com/sun/net/httpserver/Headers.java index 2ba160f7216..84535027eb4 100644 --- a/src/jdk.httpserver/share/classes/com/sun/net/httpserver/Headers.java +++ b/src/jdk.httpserver/share/classes/com/sun/net/httpserver/Headers.java @@ -25,6 +25,7 @@ package com.sun.net.httpserver; +import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.LinkedList; @@ -33,6 +34,8 @@ import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.function.BiFunction; +import java.util.stream.Collectors; +import sun.net.httpserver.UnmodifiableHeaders; /** * HTTP request and response headers are represented by this class which @@ -65,6 +68,14 @@ import java.util.function.BiFunction; * value given overwriting any existing values in the value list. * * + *

      An instance of {@code Headers} is either mutable or immutable. + * A mutable headers allows to add, remove, or modify header names and + * values, e.g. the instance returned by {@link HttpExchange#getResponseHeaders()}. + * An immutable headers disallows any modification to header names or + * values, e.g. the instance returned by {@link HttpExchange#getRequestHeaders()}. + * The mutator methods for an immutable headers instance unconditionally throw + * {@code UnsupportedOperationException}. + * *

      All methods in this class reject {@code null} values for keys and values. * {@code null} keys will never be present in HTTP request or response headers. * @since 1.6 @@ -78,6 +89,25 @@ public class Headers implements Map> { */ public Headers() {map = new HashMap<>(32);} + /** + * Creates a mutable {@code Headers} from the given {@code headers} with + * the same header names and values. + * + * @param headers a map of header names and values + * @throws NullPointerException if {@code headers} or any of its names or + * values are null, or if any value contains + * null. + * @since 18 + */ + public Headers(Map> headers) { + Objects.requireNonNull(headers); + var h = headers.entrySet().stream() + .collect(Collectors.toUnmodifiableMap( + Entry::getKey, e -> new LinkedList<>(e.getValue()))); + map = new HashMap<>(32); + this.putAll(h); + } + /** * Normalize the key by converting to following form. * First {@code char} upper case, rest lower case. @@ -254,4 +284,55 @@ public class Headers implements Map> { sb.append(" }"); return sb.toString(); } + + /** + * Returns an immutable {@code Headers} with the given name value pairs as + * its set of headers. + * + *

      The supplied {@code String} instances must alternate as header names + * and header values. To add several values to the same name, the same name + * must be supplied with each new value. If the supplied {@code headers} is + * empty, then an empty {@code Headers} is returned. + * + * @param headers the list of name value pairs + * @return an immutable headers with the given name value pairs + * @throws NullPointerException if {@code headers} or any of its + * elements are null. + * @throws IllegalArgumentException if the number of supplied strings is odd. + * @since 18 + */ + public static Headers of(String... headers) { + Objects.requireNonNull(headers); + if (headers.length == 0) { + return new UnmodifiableHeaders(new Headers()); + } + if (headers.length % 2 != 0) { + throw new IllegalArgumentException("wrong number, %d, of elements" + .formatted(headers.length)); + } + Arrays.stream(headers).forEach(Objects::requireNonNull); + + var h = new Headers(); + for (int i = 0; i < headers.length; i += 2) { + String name = headers[i]; + String value = headers[i + 1]; + h.add(name, value); + } + return new UnmodifiableHeaders(h); + } + + /** + * Returns an immutable {@code Headers} from the given {@code headers} with + * the same header names and values. + * + * @param headers a map of header names and values + * @return an immutable headers + * @throws NullPointerException if {@code headers} or any of its names or + * values are null, or if any value contains + * null. + * @since 18 + */ + public static Headers of(Map> headers) { + return new UnmodifiableHeaders(new Headers(headers)); + } } diff --git a/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpExchange.java b/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpExchange.java index 5ad7cf5330b..ea2845f56f5 100644 --- a/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpExchange.java +++ b/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpExchange.java @@ -69,7 +69,7 @@ import java.net.URI; * @since 1.6 */ -public abstract class HttpExchange implements AutoCloseable { +public abstract class HttpExchange implements AutoCloseable, Request { /** * Constructor for subclasses to call. @@ -78,19 +78,8 @@ public abstract class HttpExchange implements AutoCloseable { } /** - * Returns an immutable {@link Headers} containing the HTTP headers that - * were included with this request. - * - *

      The keys in this {@code Headers} are the header names, while the - * values are a {@link java.util.List} of - * {@linkplain java.lang.String Strings} containing each value that was - * included in the request, in the order they were included. Header fields - * appearing multiple times are represented as multiple string values. - * - *

      The keys in {@code Headers} are case-insensitive. - * - * @return a read-only {@code Headers} which can be used to access request - * headers. + * {@inheritDoc} + * @return {@inheritDoc} */ public abstract Headers getRequestHeaders(); @@ -111,16 +100,14 @@ public abstract class HttpExchange implements AutoCloseable { public abstract Headers getResponseHeaders(); /** - * Returns the request {@link URI}. - * - * @return the request {@code URI} + * {@inheritDoc} + * @return {@inheritDoc} */ public abstract URI getRequestURI(); /** - * Returns the request method. - * - * @return the request method + * {@inheritDoc} + * @return {@inheritDoc} */ public abstract String getRequestMethod(); diff --git a/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpHandlers.java b/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpHandlers.java new file mode 100644 index 00000000000..03642033914 --- /dev/null +++ b/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpHandlers.java @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.net.httpserver; + +import java.nio.charset.StandardCharsets; +import java.util.Objects; +import java.util.function.Predicate; + +/** + * Implementations of {@link com.sun.net.httpserver.HttpHandler HttpHandler} + * that implement various useful handlers, such as a static response handler, + * or a conditional handler that complements one handler with another. + * + *

      The factory method {@link #of(int, Headers, String)} provides a + * means to create handlers with pre-set static response state. For example, a + * {@code jsonHandler} that always returns 200 with the same json: + *

      {@code
      + *    HttpHandlers.of(200,
      + *                    Headers.of("Content-Type", "application/json"),
      + *                    Files.readString(Path.of("some.json")));
      + * }
      + * or a {@code notAllowedHandler} that always replies with 405 - + * Method Not Allowed, and indicates the set of methods that are allowed: + *
      {@code
      + *    HttpHandlers.of(405, Headers.of("Allow", "GET"), "");
      + * }
      + * + *

      The functionality of a handler can be extended or enhanced through the + * use of {@link #handleOrElse(Predicate, HttpHandler, HttpHandler) handleOrElse}, + * which allows to complement a given handler. For example, complementing a + * {@code jsonHandler} with notAllowedHandler: + * + *

      {@code
      + *    Predicate IS_GET = r -> r.getRequestMethod().equals("GET");
      + *    var handler = HttpHandlers.handleOrElse(IS_GET, jsonHandler, notAllowedHandler);
      + * }
      + * + * The above handleOrElse {@code handler} offers an if-else like construct; + * if the request method is "GET" then handling of the exchange is delegated to + * the {@code jsonHandler}, otherwise handling of the exchange is delegated to + * the {@code notAllowedHandler}. + * + * @since 18 + */ +public final class HttpHandlers { + + private HttpHandlers() { } + + /** + * Complements a conditional {@code HttpHandler} with another handler. + * + *

      This method creates a handleOrElse handler; an if-else like + * construct. Exchanges who's request matches the {@code handlerTest} + * predicate are handled by the {@code handler}. All remaining exchanges + * are handled by the {@code fallbackHandler}. + * + *

      Example of a nested handleOrElse handler: + *

      {@code
      +     *    Predicate IS_GET = r -> r.getRequestMethod().equals("GET");
      +     *    Predicate WANTS_DIGEST =  r -> r.getRequestHeaders().containsKey("Want-Digest");
      +     *
      +     *    var h1 = new SomeHandler();
      +     *    var h2 = HttpHandlers.handleOrElse(IS_GET, new SomeGetHandler(), h1);
      +     *    var h3 = HttpHandlers.handleOrElse(WANTS_DIGEST.and(IS_GET), new SomeDigestHandler(), h2);
      +     * }
      + * The {@code h3} handleOrElse handler delegates handling of the exchange to + * {@code SomeDigestHandler} if the "Want-Digest" request header is present + * and the request method is {@code GET}, otherwise it delegates handling of + * the exchange to the {@code h2} handler. The {@code h2} handleOrElse + * handler, in turn, delegates handling of the exchange to {@code + * SomeGetHandler} if the request method is {@code GET}, otherwise it + * delegates handling of the exchange to the {@code h1} handler. The {@code + * h1} handler handles all exchanges that are not previously delegated to + * either {@code SomeGetHandler} or {@code SomeDigestHandler}. + * + * @param handlerTest a request predicate + * @param handler a conditional handler + * @param fallbackHandler a fallback handler + * @return a handler + * @throws NullPointerException if any argument is null + */ + public static HttpHandler handleOrElse(Predicate handlerTest, + HttpHandler handler, + HttpHandler fallbackHandler) { + Objects.requireNonNull(handlerTest); + Objects.requireNonNull(handler); + Objects.requireNonNull(fallbackHandler); + return exchange -> { + if (handlerTest.test(exchange)) + handler.handle(exchange); + else + fallbackHandler.handle(exchange); + }; + } + + /** + * Returns an {@code HttpHandler} that sends a response comprising the given + * {@code statusCode}, {@code headers}, and {@code body}. + * + *

      This method creates a handler that reads and discards the request + * body before it sets the response state and sends the response. + * + *

      {@code headers} are the effective headers of the response. The + * response body bytes are a {@code UTF-8} encoded byte sequence of + * {@code body}. The response headers + * {@linkplain HttpExchange#sendResponseHeaders(int, long) are sent} with + * the given {@code statusCode} and the body bytes' length (or {@code -1} + * if the body is empty). The body bytes are then sent as response body, + * unless the body is empty, in which case no response body is sent. + * + * @param statusCode a response status code + * @param headers a headers + * @param body a response body string + * @return a handler + * @throws IllegalArgumentException if statusCode is not a positive 3-digit + * integer, as per rfc2616, section 6.1.1 + * @throws NullPointerException if headers or body are null + */ + public static HttpHandler of(int statusCode, Headers headers, String body) { + if (statusCode < 100 || statusCode > 999) + throw new IllegalArgumentException("statusCode must be 3-digit: " + + statusCode); + Objects.requireNonNull(headers); + Objects.requireNonNull(body); + + final var headersCopy = Headers.of(headers); + final var bytes = body.getBytes(StandardCharsets.UTF_8); + + return exchange -> { + try (exchange) { + exchange.getRequestBody().readAllBytes(); + exchange.getResponseHeaders().putAll(headersCopy); + if (exchange.getRequestMethod().equals("HEAD")) { + exchange.getResponseHeaders().set("Content-Length", Integer.toString(bytes.length)); + exchange.sendResponseHeaders(statusCode, -1); + } + else if (bytes.length == 0) { + exchange.sendResponseHeaders(statusCode, -1); + } else { + exchange.sendResponseHeaders(statusCode, bytes.length); + exchange.getResponseBody().write(bytes); + } + } + }; + } +} diff --git a/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpServer.java b/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpServer.java index 0067334f417..8ed0172690f 100644 --- a/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpServer.java +++ b/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpServer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,6 +30,8 @@ import com.sun.net.httpserver.spi.HttpServerProvider; import java.io.IOException; import java.net.BindException; import java.net.InetSocketAddress; +import java.util.Arrays; +import java.util.Objects; import java.util.concurrent.Executor; /** @@ -150,6 +152,58 @@ public abstract class HttpServer { return provider.createHttpServer (addr, backlog); } + /** + * Creates an {@code HttpServer} instance with an initial context. + * + *

      The server is created with an initial context that maps the + * URI {@code path} to the exchange {@code handler}. The initial context is + * created as if by an invocation of + * {@link HttpServer#createContext(String) createContext(path)}. The + * {@code filters}, if any, are added to the initial context, in the order + * they are given. The returned server is not started so can be configured + * further if required. + * + *

      The server instance will bind to the given + * {@link java.net.InetSocketAddress}. + * + *

      A maximum backlog can also be specified. This is the maximum number + * of queued incoming connections to allow on the listening socket. + * Queued TCP connections exceeding this limit may be rejected by + * the TCP implementation. The HttpServer is acquired from the currently + * installed {@link HttpServerProvider}. + * + * @param addr the address to listen on, if {@code null} then + * {@link #bind bind} must be called to set the address + * @param backlog the socket backlog. If this value is less than or + * equal to zero, then a system default value is used + * @param path the root URI path of the context, must be absolute + * @param handler the HttpHandler for the context + * @param filters the Filters for the context, optional + * @return the HttpServer + * @throws BindException if the server cannot bind to the address + * @throws IOException if an I/O error occurs + * @throws IllegalArgumentException if path is invalid + * @throws NullPointerException if any of: {@code path}, {@code handler}, + * {@code filters}, or any element of {@code filters}, are {@code null} + * @since 18 + */ + public static HttpServer create(InetSocketAddress addr, + int backlog, + String path, + HttpHandler handler, + Filter... filters) throws IOException { + Objects.requireNonNull(path); + Objects.requireNonNull(handler); + Objects.requireNonNull(filters); + Arrays.stream(filters).forEach(Objects::requireNonNull); + + HttpServer server = HttpServer.create(addr, backlog); + HttpContext context = server.createContext(path); + context.setHandler(handler); + Arrays.stream(filters).forEach(f -> context.getFilters().add(f)); + return server; + } + /** * Binds a currently unbound {@code HttpServer} to the given address and * port number. A maximum backlog can also be specified. This is the maximum diff --git a/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpsServer.java b/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpsServer.java index aef47ed3bc4..7b3dafd5582 100644 --- a/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpsServer.java +++ b/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpsServer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,9 @@ package com.sun.net.httpserver; import java.io.IOException; import java.net.BindException; import java.net.InetSocketAddress; +import java.util.Arrays; +import java.util.Objects; + import com.sun.net.httpserver.spi.HttpServerProvider; /** @@ -92,6 +95,61 @@ public abstract class HttpsServer extends HttpServer { return provider.createHttpsServer(addr, backlog); } + /** + * Creates an {@code HttpsServer} instance with an initial context. + * + *

      The server is created with an initial context that maps the + * URI {@code path} to the exchange {@code handler}. The initial context is + * created as if by an invocation of + * {@link HttpsServer#createContext(String) createContext(path)}. The + * {@code filters}, if any, are added to the initial context, in the order + * they are given. The returned server is not started so can be configured + * further if required. + * + *

      The server instance will bind to the given + * {@link java.net.InetSocketAddress}. + * + *

      A maximum backlog can also be specified. This is the maximum number + * of queued incoming connections to allow on the listening socket. + * Queued TCP connections exceeding this limit may be rejected by + * the TCP implementation. The HttpsServer is acquired from the currently + * installed {@link HttpServerProvider}. + * + *

      The server must have an HttpsConfigurator established with + * {@link #setHttpsConfigurator(HttpsConfigurator)}. + * + * @param addr the address to listen on, if {@code null} then + * {@link #bind bind} must be called to set the address + * @param backlog the socket backlog. If this value is less than or + * equal to zero, then a system default value is used + * @param path the root URI path of the context, must be absolute + * @param handler the HttpHandler for the context + * @param filters the Filters for the context, optional + * @return the HttpsServer + * @throws BindException if the server cannot bind to the address + * @throws IOException if an I/O error occurs + * @throws IllegalArgumentException if path is invalid + * @throws NullPointerException if any of: {@code path}, {@code handler}, + * {@code filters}, or any element of {@code filters}, are {@code null} + * @since 18 + */ + public static HttpsServer create(InetSocketAddress addr, + int backlog, + String path, + HttpHandler handler, + Filter... filters) throws IOException { + Objects.requireNonNull(path); + Objects.requireNonNull(handler); + Objects.requireNonNull(filters); + Arrays.stream(filters).forEach(Objects::requireNonNull); + + HttpsServer server = HttpsServer.create(addr, backlog); + HttpContext context = server.createContext(path); + context.setHandler(handler); + Arrays.stream(filters).forEach(f -> context.getFilters().add(f)); + return server; + } + /** * Sets this server's {@link HttpsConfigurator} object. * diff --git a/src/jdk.httpserver/share/classes/com/sun/net/httpserver/Request.java b/src/jdk.httpserver/share/classes/com/sun/net/httpserver/Request.java new file mode 100644 index 00000000000..8d9d8748e6c --- /dev/null +++ b/src/jdk.httpserver/share/classes/com/sun/net/httpserver/Request.java @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.net.httpserver; + +import java.net.URI; +import java.util.List; +import java.util.Objects; + +/** + * A view of the immutable request state of an HTTP exchange. + * + * @since 18 + */ +public interface Request { + + /** + * Returns the request {@link URI}. + * + * @return the request {@code URI} + */ + URI getRequestURI(); + + /** + * Returns the request method. + * + * @return the request method string + */ + String getRequestMethod(); + + /** + * Returns an immutable {@link Headers} containing the HTTP headers that + * were included with this request. + * + *

      The keys in this {@code Headers} are the header names, while the + * values are a {@link java.util.List} of + * {@linkplain java.lang.String Strings} containing each value that was + * included in the request, in the order they were included. Header fields + * appearing multiple times are represented as multiple string values. + * + *

      The keys in {@code Headers} are case-insensitive. + * + * @return a read-only {@code Headers} which can be used to access request + * headers. + */ + Headers getRequestHeaders(); + + /** + * Returns an identical {@code Request} with an additional header. + * + *

      The returned {@code Request} has the same set of + * {@link #getRequestHeaders() headers} as {@code this} request, but with + * the addition of the given header. All other request state remains + * unchanged. + * + *

      If {@code this} request already contains a header with the same name + * as the given {@code headerName}, then its value is not replaced. + * + * @implSpec + * The default implementation first creates a new {@code Headers}, {@code h}, + * then adds all the request headers from {@code this} request to {@code h}, + * then adds the given name-values mapping if {@code headerName} is + * not present in {@code h}. Then an unmodifiable view, {@code h'}, of + * {@code h} and a new {@code Request}, {@code r}, are created. + * The {@code getRequestMethod} and {@code getRequestURI} methods of + * {@code r} simply invoke the equivalently named method of {@code this} + * request. The {@code getRequestHeaders} method returns {@code h'}. Lastly, + * {@code r} is returned. + * + * @param headerName the header name + * @param headerValues the list of header values + * @return a request + * @throws NullPointerException if any argument is null, or if any element + * of headerValues is null. + */ + default Request with(String headerName, List headerValues) { + Objects.requireNonNull(headerName); + Objects.requireNonNull(headerValues); + final Request r = this; + + var h = new Headers(); + h.putAll(r.getRequestHeaders()); + if (!h.containsKey(headerName)) { + h.put(headerName, headerValues); + } + var unmodifiableHeaders = Headers.of(h); + return new Request() { + @Override + public URI getRequestURI() { return r.getRequestURI(); } + + @Override + public String getRequestMethod() { return r.getRequestMethod(); } + + @Override + public Headers getRequestHeaders() { return unmodifiableHeaders; } + }; + } +} diff --git a/src/jdk.httpserver/share/classes/com/sun/net/httpserver/SimpleFileServer.java b/src/jdk.httpserver/share/classes/com/sun/net/httpserver/SimpleFileServer.java new file mode 100644 index 00000000000..bd81e8e5eac --- /dev/null +++ b/src/jdk.httpserver/share/classes/com/sun/net/httpserver/SimpleFileServer.java @@ -0,0 +1,265 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.net.httpserver; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.UncheckedIOException; +import java.net.InetSocketAddress; +import java.net.URLConnection; +import java.nio.file.Path; +import java.util.Objects; +import java.util.function.Consumer; +import java.util.function.Predicate; +import java.util.function.UnaryOperator; +import sun.net.httpserver.simpleserver.FileServerHandler; +import sun.net.httpserver.simpleserver.OutputFilter; + +/** + * A simple HTTP file server and its components (intended for testing, + * development and debugging purposes only). + * + *

      A simple file server is composed of three + * components: + *

        + *
      • an {@link HttpServer HttpServer} that is bound to a given address,
      • + *
      • an {@link HttpHandler HttpHandler} that serves files from a given + * directory path, and
      • + *
      • an optional {@link Filter Filter} that prints log messages relating to + * the exchanges handled by the server.
      • + *
      + * The individual server components can be retrieved for reuse and extension via + * the static methods provided. + * + *

      Simple file server

      + * + *

      The {@link #createFileServer(InetSocketAddress,Path,OutputLevel) createFileServer} + * static factory method returns an {@link HttpServer HttpServer} that is a + * simple out-of-the-box file server. The server comes with an initial handler + * that serves files from a given directory path (and its subdirectories). + * The output level determines what log messages are printed to + * {@code System.out}, if any. + * + *

      Example of a simple file server: + *

      {@code
      + *    var addr = new InetSocketAddress(8080);
      + *    var server = SimpleFileServer.createFileServer(addr, Path.of("/some/path"), OutputLevel.INFO);
      + *    server.start();
      + * }
      + * + *

      File handler

      + * + *

      The {@link #createFileHandler(Path) createFileHandler} static factory + * method returns an {@code HttpHandler} that serves files and directory + * listings. The handler supports only the HEAD and GET request + * methods; to handle other request methods, one can either add additional + * handlers to the server, or complement the file handler by composing a single + * handler via + * {@link HttpHandlers#handleOrElse(Predicate, HttpHandler, HttpHandler)}. + * + *

      Example of composing a single handler: + *

      {@code
      + *    var handler = HttpHandlers.handleOrElse(
      + *        (req) -> req.getRequestMethod().equals("PUT"),
      + *        (exchange) -> {
      + *            // validate and handle PUT request
      + *        },
      + *        SimpleFileServer.createFileHandler(Path.of("/some/path")))
      + *    );
      + * }
      + * + *

      Output filter

      + * + *

      The {@link #createOutputFilter(OutputStream, OutputLevel) createOutputFilter} + * static factory method returns a + * {@link Filter#afterHandler(String, Consumer) post-processing filter} that + * prints log messages relating to the exchanges handled by the server. The + * output format is specified by the {@link OutputLevel outputLevel}. + * + *

      Example of an output filter: + *

      {@code
      + *    var filter = SimpleFileServer.createOutputFilter(System.out, OutputLevel.VERBOSE);
      + *    var server = HttpServer.create(new InetSocketAddress(8080), 10, "/some/path/", new SomeHandler(), filter);
      + *    server.start();
      + * }
      + * + *

      Main entry point

      + * + *

      A simple HTTP file server implementation is + * provided via the + * main entry point + * of the {@code jdk.httpserver} module. + * + * @since 18 + */ +public final class SimpleFileServer { + + private static final UnaryOperator MIME_TABLE = + URLConnection.getFileNameMap()::getContentTypeFor; + + private SimpleFileServer() { } + + /** + * Describes the log message output level produced by the server when + * processing exchanges. + * + * @since 18 + */ + public enum OutputLevel { + /** + * Used to specify no log message output level. + */ + NONE, + + /** + * Used to specify the informative log message output level. + * + *

      The log message format is based on the + * Common Logfile Format, + * that includes the following information about an {@code HttpExchange}: + * + *

      {@code remotehost rfc931 authuser [date] "request" status bytes} + * + *

      Example: + *

      {@code
      +         *    127.0.0.1 - - [22/Jun/2000:13:55:36 -0700] "GET /example.txt HTTP/1.1" 200 -
      +         * }
      + * + * @implNote The fields {@code rfc931}, {@code authuser} and {@code bytes} + * are not captured in the implementation, so are always represented as + * {@code '-'}. + */ + INFO, + + /** + * Used to specify the verbose log message output level. + * + *

      Additional to the information provided by the + * {@linkplain OutputLevel#INFO info} level, the verbose level + * includes the request and response headers of the {@code HttpExchange} + * and the absolute path of the resource served up. + */ + VERBOSE + } + + /** + * Creates a file server the serves files from a given path. + * + *

      The server is configured with an initial context that maps the + * URI {@code path} to a file handler. The file handler is + * created as if by an invocation of + * {@link #createFileHandler(Path) createFileHandler(rootDirectory)}, and is + * associated to a context created as if by an invocation of + * {@link HttpServer#createContext(String) createContext("/")}. + * + *

      An output level can be given to print log messages relating to the + * exchanges handled by the server. The log messages, if any, are printed to + * {@code System.out}. If {@link OutputLevel#NONE OutputLevel.NONE} is + * given, no log messages are printed. + * + * @param addr the address to listen on + * @param rootDirectory the root directory to be served, must be an absolute path + * @param outputLevel the log message output level + * @return an HttpServer + * @throws IllegalArgumentException if root does not exist, is not absolute, + * is not a directory, or is not readable + * @throws UncheckedIOException if an I/O error occurs + * @throws NullPointerException if any argument is null + * @throws SecurityException if a security manager is installed and a + * recursive {@link java.io.FilePermission} "{@code read}" of the + * rootDirectory is denied + */ + public static HttpServer createFileServer(InetSocketAddress addr, + Path rootDirectory, + OutputLevel outputLevel) { + Objects.requireNonNull(addr); + Objects.requireNonNull(rootDirectory); + Objects.requireNonNull(outputLevel); + try { + var handler = FileServerHandler.create(rootDirectory, MIME_TABLE); + if (outputLevel.equals(OutputLevel.NONE)) + return HttpServer.create(addr, 0, "/", handler); + else + return HttpServer.create(addr, 0, "/", handler, OutputFilter.create(System.out, outputLevel)); + } catch (IOException ioe) { + throw new UncheckedIOException(ioe); + } + } + + /** + * Creates a file handler that serves files from a given directory + * path (and its subdirectories). + * + *

      The file handler resolves the request URI against the given + * {@code rootDirectory} path to determine the path {@code p} on the + * associated file system to serve the response. If the path {@code p} is + * a directory, then the response contains a directory listing, formatted in + * HTML, as the response body. If the path {@code p} is a file, then the + * response contains a "Content-Type" header based on the best-guess + * content type, as determined by an invocation of + * {@linkplain java.net.FileNameMap#getContentTypeFor(String) getContentTypeFor}, + * on the system-wide {@link URLConnection#getFileNameMap() mimeTable}, as + * well as the contents of the file as the response body. + * + *

      The handler supports only requests with the HEAD or GET + * method, and will reply with a {@code 405} response code for requests with + * any other method. + * + * @param rootDirectory the root directory to be served, must be an absolute path + * @return a file handler + * @throws IllegalArgumentException if rootDirectory does not exist, + * is not absolute, is not a directory, or is not readable + * @throws NullPointerException if the argument is null + * @throws SecurityException if a security manager is installed and a + * recursive {@link java.io.FilePermission} "{@code read}" of the + * rootDirectory is denied + */ + public static HttpHandler createFileHandler(Path rootDirectory) { + Objects.requireNonNull(rootDirectory); + return FileServerHandler.create(rootDirectory, MIME_TABLE); + } + + /** + * Creates a {@linkplain Filter#afterHandler(String, Consumer) + * post-processing Filter} that prints log messages about + * {@linkplain HttpExchange exchanges}. The log messages are printed to + * the given {@code OutputStream} in {@code UTF-8} encoding. + * + * @apiNote + * To not output any log messages it is recommended to not use a filter. + * + * @param out the stream to print to + * @param outputLevel the output level + * @return a post-processing filter + * @throws IllegalArgumentException if {@link OutputLevel#NONE OutputLevel.NONE} + * is given + * @throws NullPointerException if any argument is null + */ + public static Filter createOutputFilter(OutputStream out, + OutputLevel outputLevel) { + Objects.requireNonNull(out); + Objects.requireNonNull(outputLevel); + return OutputFilter.create(out, outputLevel); + } +} diff --git a/src/jdk.httpserver/share/classes/com/sun/net/httpserver/package-info.java b/src/jdk.httpserver/share/classes/com/sun/net/httpserver/package-info.java index 0f5382444ec..ed3978e0eae 100644 --- a/src/jdk.httpserver/share/classes/com/sun/net/httpserver/package-info.java +++ b/src/jdk.httpserver/share/classes/com/sun/net/httpserver/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -120,6 +120,12 @@ } }); +

      + The {@link com.sun.net.httpserver.SimpleFileServer} class offers a simple + HTTP file server (intended for testing, development and debugging purposes + only). A default implementation is provided via the + main entry point + of the {@code jdk.httpserver} module. @since 1.6 */ diff --git a/src/jdk.httpserver/share/classes/module-info.java b/src/jdk.httpserver/share/classes/module-info.java index 015b9355d00..417854d2ee8 100644 --- a/src/jdk.httpserver/share/classes/module-info.java +++ b/src/jdk.httpserver/share/classes/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,40 @@ /** * Defines the JDK-specific HTTP server API. + *

      + * A basic high-level API for building embedded servers. Both HTTP and + * HTTPS are supported. + *

      + * The main components are: + *

        + *
      • the {@link com.sun.net.httpserver.HttpExchange} class that describes a + * request and response pair,
      • + *
      • the {@link com.sun.net.httpserver.HttpHandler} interface to handle + * incoming requests, plus the {@link com.sun.net.httpserver.HttpHandlers} class + * that provides useful handler implementations,
      • + *
      • the {@link com.sun.net.httpserver.HttpContext} class that maps a URI path + * to a {@code HttpHandler},
      • + *
      • the {@link com.sun.net.httpserver.HttpServer} class to listen for + * connections and dispatch requests to handlers,
      • + *
      • the {@link com.sun.net.httpserver.Filter} class that allows pre- and post- + * processing of requests.
      + *

      + * The {@link com.sun.net.httpserver.SimpleFileServer} class offers a simple + * HTTP file server (intended for testing, development and debugging purposes + * only). A default implementation is provided via the + * main entry point of the {@code jdk.httpserver} module, which can be used on + * the command line as such: + *

      {@code
      + *    Usage: java -m jdk.httpserver [-b bind address] [-p port] [-d directory]
      + *                                  [-o none|info|verbose] [-h to show options]
      + *    Options:
      + *    -b, --bind-address    - Address to bind to. Default: 127.0.0.1 or ::1 (loopback).
      + *                            For all interfaces use "-b 0.0.0.0" or "-b ::".
      + *    -d, --directory       - Directory to serve. Default: current directory.
      + *    -o, --output          - Output format. none|info|verbose. Default: info.
      + *    -p, --port            - Port to listen on. Default: 8000.
      + *    -h, -?, --help        - Print this help message.
      + * }
      * * @uses com.sun.net.httpserver.spi.HttpServerProvider * diff --git a/src/jdk.httpserver/share/classes/sun/net/httpserver/DelegatingHttpExchange.java b/src/jdk.httpserver/share/classes/sun/net/httpserver/DelegatingHttpExchange.java new file mode 100644 index 00000000000..88399471a7f --- /dev/null +++ b/src/jdk.httpserver/share/classes/sun/net/httpserver/DelegatingHttpExchange.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.net.httpserver; + +import com.sun.net.httpserver.Headers; +import com.sun.net.httpserver.HttpContext; +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpPrincipal; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetSocketAddress; +import java.net.URI; + +public abstract class DelegatingHttpExchange extends HttpExchange { + + private final HttpExchange exchange; + + public DelegatingHttpExchange(HttpExchange ex) { + this.exchange = ex; + } + + public abstract Headers getRequestHeaders(); + + public abstract String getRequestMethod(); + + public abstract URI getRequestURI(); + + public Headers getResponseHeaders() { + return exchange.getResponseHeaders(); + } + + public HttpContext getHttpContext() { + return exchange.getHttpContext(); + } + + public void close() { + exchange.close(); + } + + public InputStream getRequestBody() { + return exchange.getRequestBody(); + } + + public int getResponseCode() { + return exchange.getResponseCode(); + } + + public OutputStream getResponseBody() { + return exchange.getResponseBody(); + } + + public void sendResponseHeaders(int rCode, long contentLen) throws IOException { + exchange.sendResponseHeaders(rCode, contentLen); + } + + public InetSocketAddress getRemoteAddress() { + return exchange.getRemoteAddress(); + } + + public InetSocketAddress getLocalAddress() { + return exchange.getLocalAddress(); + } + + public String getProtocol() { + return exchange.getProtocol(); + } + + public Object getAttribute(String name) { + return exchange.getAttribute(name); + } + + public void setAttribute(String name, Object value) { + exchange.setAttribute(name, value); + } + + public void setStreams(InputStream i, OutputStream o) { + exchange.setStreams(i, o); + } + + public HttpPrincipal getPrincipal() { + return exchange.getPrincipal(); + } +} diff --git a/src/jdk.httpserver/share/classes/sun/net/httpserver/ExchangeImpl.java b/src/jdk.httpserver/share/classes/sun/net/httpserver/ExchangeImpl.java index 454b6cd435c..6a7398611ac 100644 --- a/src/jdk.httpserver/share/classes/sun/net/httpserver/ExchangeImpl.java +++ b/src/jdk.httpserver/share/classes/sun/net/httpserver/ExchangeImpl.java @@ -85,7 +85,7 @@ class ExchangeImpl { String m, URI u, Request req, long len, HttpConnection connection ) throws IOException { this.req = req; - this.reqHdrs = new UnmodifiableHeaders(req.headers()); + this.reqHdrs = Headers.of(req.headers()); this.rspHdrs = new Headers(); this.method = m; this.uri = u; diff --git a/src/jdk.httpserver/share/classes/sun/net/httpserver/simpleserver/FileServerHandler.java b/src/jdk.httpserver/share/classes/sun/net/httpserver/simpleserver/FileServerHandler.java new file mode 100644 index 00000000000..b1b28446b4d --- /dev/null +++ b/src/jdk.httpserver/share/classes/sun/net/httpserver/simpleserver/FileServerHandler.java @@ -0,0 +1,385 @@ +/* + * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 sun.net.httpserver.simpleserver; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.UncheckedIOException; +import java.lang.System.Logger; +import java.net.URI; +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.List; +import java.util.Map; +import java.util.function.UnaryOperator; +import com.sun.net.httpserver.Headers; +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import com.sun.net.httpserver.HttpHandlers; +import static java.nio.charset.StandardCharsets.UTF_8; + +/** + * A basic HTTP file server handler for static content. + * + *

      Must be given an absolute pathname to the directory to be served. + * Supports only HEAD and GET requests. Directory listings and files can be + * served, content types are supported on a best-guess basis. + */ +public final class FileServerHandler implements HttpHandler { + + private static final List SUPPORTED_METHODS = List.of("HEAD", "GET"); + private static final List UNSUPPORTED_METHODS = + List.of("CONNECT", "DELETE", "OPTIONS", "PATCH", "POST", "PUT", "TRACE"); + + private final Path root; + private final UnaryOperator mimeTable; + private final Logger logger; + + private FileServerHandler(Path root, UnaryOperator mimeTable) { + root = root.normalize(); + + @SuppressWarnings("removal") + var securityManager = System.getSecurityManager(); + if (securityManager != null) + securityManager.checkRead(pathForSecurityCheck(root.toString())); + + if (!Files.exists(root)) + throw new IllegalArgumentException("Path does not exist: " + root); + if (!root.isAbsolute()) + throw new IllegalArgumentException("Path is not absolute: " + root); + if (!Files.isDirectory(root)) + throw new IllegalArgumentException("Path is not a directory: " + root); + if (!Files.isReadable(root)) + throw new IllegalArgumentException("Path is not readable: " + root); + this.root = root; + this.mimeTable = mimeTable; + this.logger = System.getLogger("com.sun.net.httpserver"); + } + + private static String pathForSecurityCheck(String path) { + var separator = String.valueOf(File.separatorChar); + return path.endsWith(separator) ? (path + "-") : (path + separator + "-"); + } + + private static final HttpHandler NOT_IMPLEMENTED_HANDLER = + HttpHandlers.of(501, Headers.of(), ""); + + private static final HttpHandler METHOD_NOT_ALLOWED_HANDLER = + HttpHandlers.of(405, Headers.of("Allow", "HEAD, GET"), ""); + + public static HttpHandler create(Path root, UnaryOperator mimeTable) { + var fallbackHandler = HttpHandlers.handleOrElse( + r -> UNSUPPORTED_METHODS.contains(r.getRequestMethod()), + METHOD_NOT_ALLOWED_HANDLER, + NOT_IMPLEMENTED_HANDLER); + return HttpHandlers.handleOrElse( + r -> SUPPORTED_METHODS.contains(r.getRequestMethod()), + new FileServerHandler(root, mimeTable), fallbackHandler); + } + + private void handleHEAD(HttpExchange exchange, Path path) throws IOException { + handleSupportedMethod(exchange, path, false); + } + + private void handleGET(HttpExchange exchange, Path path) throws IOException { + handleSupportedMethod(exchange, path, true); + } + + private void handleSupportedMethod(HttpExchange exchange, Path path, boolean writeBody) + throws IOException { + if (Files.isDirectory(path)) { + if (missingSlash(exchange)) { + handleMovedPermanently(exchange); + return; + } + if (indexFile(path) != null) { + serveFile(exchange, indexFile(path), writeBody); + } else { + listFiles(exchange, path, writeBody); + } + } else { + serveFile(exchange, path, writeBody); + } + } + + private void handleMovedPermanently(HttpExchange exchange) throws IOException { + exchange.getResponseHeaders().set("Location", getRedirectURI(exchange.getRequestURI())); + exchange.sendResponseHeaders(301, -1); + } + + private void handleForbidden(HttpExchange exchange) throws IOException { + exchange.sendResponseHeaders(403, -1); + } + + private void handleNotFound(HttpExchange exchange) throws IOException { + String fileNotFound = ResourceBundleHelper.getMessage("html.not.found"); + var bytes = (openHTML + + "

      " + fileNotFound + "

      \n" + + "

      " + sanitize.apply(exchange.getRequestURI().getPath()) + "

      \n" + + closeHTML).getBytes(UTF_8); + exchange.getResponseHeaders().set("Content-Type", "text/html; charset=UTF-8"); + + if (exchange.getRequestMethod().equals("HEAD")) { + exchange.getResponseHeaders().set("Content-Length", Integer.toString(bytes.length)); + exchange.sendResponseHeaders(404, -1); + } else { + exchange.sendResponseHeaders(404, bytes.length); + try (OutputStream os = exchange.getResponseBody()) { + os.write(bytes); + } + } + } + + private static void discardRequestBody(HttpExchange exchange) throws IOException { + try (InputStream is = exchange.getRequestBody()) { + is.readAllBytes(); + } + } + + private String getRedirectURI(URI uri) { + String query = uri.getRawQuery(); + String redirectPath = uri.getRawPath() + "/"; + return query == null ? redirectPath : redirectPath + "?" + query; + } + + private static boolean missingSlash(HttpExchange exchange) { + return !exchange.getRequestURI().getPath().endsWith("/"); + } + + private static String contextPath(HttpExchange exchange) { + String context = exchange.getHttpContext().getPath(); + if (!context.startsWith("/")) { + throw new IllegalArgumentException("Context path invalid: " + context); + } + return context; + } + + private static String requestPath(HttpExchange exchange) { + String request = exchange.getRequestURI().getPath(); + if (!request.startsWith("/")) { + throw new IllegalArgumentException("Request path invalid: " + request); + } + return request; + } + + // Checks that the request does not escape context. + private static void checkRequestWithinContext(String requestPath, + String contextPath) { + if (requestPath.equals(contextPath)) { + return; // context path requested, e.g. context /foo, request /foo + } + String contextPathWithTrailingSlash = contextPath.endsWith("/") + ? contextPath : contextPath + "/"; + if (!requestPath.startsWith(contextPathWithTrailingSlash)) { + throw new IllegalArgumentException("Request not in context: " + contextPath); + } + } + + // Checks that path is, or is within, the root. + private static Path checkPathWithinRoot(Path path, Path root) { + if (!path.startsWith(root)) { + throw new IllegalArgumentException("Request not in root"); + } + return path; + } + + // Returns the request URI path relative to the context. + private static String relativeRequestPath(HttpExchange exchange) { + String context = contextPath(exchange); + String request = requestPath(exchange); + checkRequestWithinContext(request, context); + return request.substring(context.length()); + } + + private Path mapToPath(HttpExchange exchange, Path root) { + try { + assert root.isAbsolute() && Files.isDirectory(root); // checked during creation + String uriPath = relativeRequestPath(exchange); + String[] pathSegment = uriPath.split("/"); + + // resolve each path segment against the root + Path path = root; + for (var segment : pathSegment) { + path = path.resolve(segment); + if (!Files.isReadable(path) || isHiddenOrSymLink(path)) { + return null; // stop resolution, null results in 404 response + } + } + path = path.normalize(); + return checkPathWithinRoot(path, root); + } catch (Exception e) { + logger.log(System.Logger.Level.TRACE, + "FileServerHandler: request URI path resolution failed", e); + return null; // could not resolve request URI path + } + } + + private static Path indexFile(Path path) { + Path html = path.resolve("index.html"); + Path htm = path.resolve("index.htm"); + return Files.exists(html) ? html : Files.exists(htm) ? htm : null; + } + + private void serveFile(HttpExchange exchange, Path path, boolean writeBody) + throws IOException + { + var respHdrs = exchange.getResponseHeaders(); + respHdrs.set("Content-Type", mediaType(path.toString())); + respHdrs.set("Last-Modified", getLastModified(path)); + if (writeBody) { + exchange.sendResponseHeaders(200, Files.size(path)); + try (InputStream fis = Files.newInputStream(path); + OutputStream os = exchange.getResponseBody()) { + fis.transferTo(os); + } + } else { + respHdrs.set("Content-Length", Long.toString(Files.size(path))); + exchange.sendResponseHeaders(200, -1); + } + } + + private void listFiles(HttpExchange exchange, Path path, boolean writeBody) + throws IOException + { + var respHdrs = exchange.getResponseHeaders(); + respHdrs.set("Content-Type", "text/html; charset=UTF-8"); + respHdrs.set("Last-Modified", getLastModified(path)); + var bodyBytes = dirListing(exchange, path).getBytes(UTF_8); + if (writeBody) { + exchange.sendResponseHeaders(200, bodyBytes.length); + try (OutputStream os = exchange.getResponseBody()) { + os.write(bodyBytes); + } + } else { + respHdrs.set("Content-Length", Integer.toString(bodyBytes.length)); + exchange.sendResponseHeaders(200, -1); + } + } + + private static final String openHTML = """ + + + + + + + """; + + private static final String closeHTML = """ + + + """; + + private static final String hrefListItemTemplate = """ +
    • %s
    • + """; + + private static String hrefListItemFor(URI uri) { + return hrefListItemTemplate.formatted(uri.toASCIIString(), sanitize.apply(uri.getPath())); + } + + private static String dirListing(HttpExchange exchange, Path path) throws IOException { + String dirListing = ResourceBundleHelper.getMessage("html.dir.list"); + var sb = new StringBuilder(openHTML + + "

      " + dirListing + " " + + sanitize.apply(exchange.getRequestURI().getPath()) + + "

      \n" + + "
        \n"); + try (var paths = Files.list(path)) { + paths.filter(p -> Files.isReadable(p) && !isHiddenOrSymLink(p)) + .map(p -> path.toUri().relativize(p.toUri())) + .forEach(uri -> sb.append(hrefListItemFor(uri))); + } + sb.append("
      \n"); + sb.append(closeHTML); + + return sb.toString(); + } + + private static String getLastModified(Path path) throws IOException { + var fileTime = Files.getLastModifiedTime(path); + return fileTime.toInstant().atZone(ZoneId.of("GMT")) + .format(DateTimeFormatter.RFC_1123_DATE_TIME); + } + + private static boolean isHiddenOrSymLink(Path path) { + try { + return Files.isHidden(path) || Files.isSymbolicLink(path); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + // Default for unknown content types, as per RFC 2046 + private static final String DEFAULT_CONTENT_TYPE = "application/octet-stream"; + + private String mediaType(String file) { + String type = mimeTable.apply(file); + return type != null ? type : DEFAULT_CONTENT_TYPE; + } + + // A non-exhaustive map of reserved-HTML and special characters to their + // equivalent entity. + private static final Map RESERVED_CHARS = Map.of( + (int) '&' , "&" , + (int) '<' , "<" , + (int) '>' , ">" , + (int) '"' , """ , + (int) '\'' , "'" , + (int) '/' , "/" ); + + // A function that takes a string and returns a sanitized version of that + // string with the reserved-HTML and special characters replaced with their + // equivalent entity. + private static final UnaryOperator sanitize = + file -> file.chars().collect(StringBuilder::new, + (sb, c) -> sb.append(RESERVED_CHARS.getOrDefault(c, Character.toString(c))), + StringBuilder::append).toString(); + + @Override + public void handle(HttpExchange exchange) throws IOException { + assert List.of("GET", "HEAD").contains(exchange.getRequestMethod()); + try (exchange) { + discardRequestBody(exchange); + Path path = mapToPath(exchange, root); + if (path != null) { + exchange.setAttribute("request-path", path.toString()); // store for OutputFilter + if (!Files.exists(path) || !Files.isReadable(path) || isHiddenOrSymLink(path)) { + handleNotFound(exchange); + } else if (exchange.getRequestMethod().equals("HEAD")) { + handleHEAD(exchange, path); + } else { + handleGET(exchange, path); + } + } else { + exchange.setAttribute("request-path", "could not resolve request URI path"); + handleNotFound(exchange); + } + } + } +} diff --git a/src/jdk.httpserver/share/classes/sun/net/httpserver/simpleserver/Main.java b/src/jdk.httpserver/share/classes/sun/net/httpserver/simpleserver/Main.java new file mode 100644 index 00000000000..c51140bf5e9 --- /dev/null +++ b/src/jdk.httpserver/share/classes/sun/net/httpserver/simpleserver/Main.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 sun.net.httpserver.simpleserver; + +import java.io.PrintWriter; +import static java.nio.charset.StandardCharsets.UTF_8; + +/** + * Programmatic entry point to start the simpleserver tool. + * + *

      This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interface are subject to change or deletion + * without notice. + */ +public class Main { + + /** + * This constructor should never be called. + */ + private Main() { throw new AssertionError(); } + + /** + * The main entry point. + * + *

      The command line arguments are parsed and the server is started. If + * started successfully, the server will run on a new non-daemon thread, + * and this method will return. Otherwise, if the server is not started + * successfully, e.g. an error is encountered while parsing the arguments + * or an I/O error occurs, the server is not started and this method invokes + * System::exit with an appropriate exit code. + * + * @param args the command-line options + * @throws NullPointerException if {@code args} is {@code null}, or if there + * are any {@code null} values in the {@code args} array + */ + public static void main(String... args) { + int ec = SimpleFileServerImpl.start(new PrintWriter(System.out, true, UTF_8), args); + if (ec != 0) + System.exit(ec); + // otherwise the server has been started successfully and runs in + // another non-daemon thread. + } +} diff --git a/src/jdk.httpserver/share/classes/sun/net/httpserver/simpleserver/OutputFilter.java b/src/jdk.httpserver/share/classes/sun/net/httpserver/simpleserver/OutputFilter.java new file mode 100644 index 00000000000..bdbcf2361ee --- /dev/null +++ b/src/jdk.httpserver/share/classes/sun/net/httpserver/simpleserver/OutputFilter.java @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 sun.net.httpserver.simpleserver; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintStream; +import java.time.OffsetDateTime; +import java.time.format.DateTimeFormatter; +import java.util.function.Consumer; +import com.sun.net.httpserver.Filter; +import com.sun.net.httpserver.Headers; +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.SimpleFileServer.OutputLevel; +import static java.nio.charset.StandardCharsets.UTF_8; + +/** + * A Filter that outputs log messages about an HttpExchange. The implementation + * uses a {@link Filter#afterHandler(String, Consumer) post-processing filter}. + * + *

      If the outputLevel is INFO, the format is based on the + * Common Logfile Format. + * In this case the output includes the following information about an exchange: + * + *

      remotehost rfc931 authuser [date] "request line" status bytes + * + *

      Example: + * 127.0.0.1 - - [22/Jun/2000:13:55:36 -0700] "GET /example.txt HTTP/1.1" 200 - + * + *

      The fields rfc931, authuser and bytes are not captured in the implementation + * and are always represented as '-'. + * + *

      If the outputLevel is VERBOSE, the output additionally includes the + * absolute path of the resource requested, if it has been + * {@linkplain HttpExchange#setAttribute(String, Object) provided} via the + * attribute {@code "request-path"}, as well as the request and response headers + * of the exchange. + */ +public final class OutputFilter extends Filter { + private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("dd/MMM/yyyy:HH:mm:ss Z"); + private final PrintStream printStream; + private final OutputLevel outputLevel; + private final Filter filter; + + private OutputFilter(OutputStream os, OutputLevel outputLevel) { + printStream = new PrintStream(os, true, UTF_8); + this.outputLevel = outputLevel; + var description = "HttpExchange OutputFilter (outputLevel: " + outputLevel + ")"; + this.filter = Filter.afterHandler(description, operation()); + } + + public static OutputFilter create(OutputStream os, OutputLevel outputLevel) { + if (outputLevel.equals(OutputLevel.NONE)) { + throw new IllegalArgumentException("Not a valid outputLevel: " + outputLevel); + } + return new OutputFilter(os, outputLevel); + } + + private Consumer operation() { + return e -> { + String s = e.getRemoteAddress().getHostString() + " " + + "- - " // rfc931 and authuser + + "[" + OffsetDateTime.now().format(FORMATTER) + "] " + + "\"" + e.getRequestMethod() + " " + e.getRequestURI() + " " + e.getProtocol() + "\" " + + e.getResponseCode() + " -"; // bytes + printStream.println(s); + + if (outputLevel.equals(OutputLevel.VERBOSE)) { + if (e.getAttribute("request-path") instanceof String requestPath) { + printStream.println("Resource requested: " + requestPath); + } + logHeaders(">", e.getRequestHeaders()); + logHeaders("<", e.getResponseHeaders()); + } + }; + } + + private void logHeaders(String sign, Headers headers) { + headers.forEach((name, values) -> { + var sb = new StringBuilder(); + var it = values.iterator(); + while (it.hasNext()) { + sb.append(it.next()); + if (it.hasNext()) { + sb.append(", "); + } + } + printStream.println(sign + " " + name + ": " + sb); + }); + printStream.println(sign); + } + + @Override + public void doFilter(HttpExchange exchange, Chain chain) throws IOException { + try { + filter.doFilter(exchange, chain); + } catch (Throwable t) { + if (!outputLevel.equals(OutputLevel.NONE)) { + reportError(ResourceBundleHelper.getMessage("err.server.handle.failed", + t.getMessage())); + } + throw t; + } + } + + @Override + public String description() { return filter.description(); } + + private void reportError(String message) { + printStream.println(ResourceBundleHelper.getMessage("error.prefix") + " " + message); + } +} diff --git a/src/jdk.httpserver/share/classes/sun/net/httpserver/simpleserver/ResourceBundleHelper.java b/src/jdk.httpserver/share/classes/sun/net/httpserver/simpleserver/ResourceBundleHelper.java new file mode 100644 index 00000000000..99349fe3474 --- /dev/null +++ b/src/jdk.httpserver/share/classes/sun/net/httpserver/simpleserver/ResourceBundleHelper.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 sun.net.httpserver.simpleserver; + +import java.text.MessageFormat; +import java.util.Locale; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +class ResourceBundleHelper { + static final ResourceBundle bundle; + + static { + try { + bundle = ResourceBundle.getBundle("sun.net.httpserver.simpleserver.resources.simpleserver"); + } catch (MissingResourceException e) { + throw new InternalError("Cannot find simpleserver resource bundle for locale " + Locale.getDefault()); + } + } + + static String getMessage(String key, Object... args) { + try { + return MessageFormat.format(bundle.getString(key), args); + } catch (MissingResourceException e) { + throw new InternalError("Missing message: " + key); + } + } +} diff --git a/src/jdk.httpserver/share/classes/sun/net/httpserver/simpleserver/SimpleFileServerImpl.java b/src/jdk.httpserver/share/classes/sun/net/httpserver/simpleserver/SimpleFileServerImpl.java new file mode 100644 index 00000000000..d236879c6b5 --- /dev/null +++ b/src/jdk.httpserver/share/classes/sun/net/httpserver/simpleserver/SimpleFileServerImpl.java @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 sun.net.httpserver.simpleserver; + +import com.sun.net.httpserver.HttpServer; +import com.sun.net.httpserver.SimpleFileServer; +import com.sun.net.httpserver.SimpleFileServer.OutputLevel; + +import java.io.PrintWriter; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.UnknownHostException; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.Iterator; +import java.util.Locale; +import java.util.NoSuchElementException; +import java.util.Objects; + +/** + * A class that provides a simple HTTP file server to serve the content of + * a given directory. + * + *

      The server is an HttpServer bound to a given address. It comes with an + * HttpHandler that serves files from a given directory path + * (and its subdirectories) on the default file system, and an optional Filter + * that prints log messages related to the exchanges handled by the server to + * a given output stream. + * + *

      Unless specified as arguments, the default values are:

        + *
      • bind address: 127.0.0.1 or ::1 (loopback)
      • + *
      • directory: current working directory
      • + *
      • outputLevel: info
      + *
    • port: 8000
    • + *

      + * The implementation is provided via the main entry point of the jdk.httpserver + * module. + */ +final class SimpleFileServerImpl { + private static final InetAddress LOOPBACK_ADDR = InetAddress.getLoopbackAddress(); + private static final int DEFAULT_PORT = 8000; + private static final Path DEFAULT_ROOT = Path.of("").toAbsolutePath(); + private static final OutputLevel DEFAULT_OUTPUT_LEVEL = OutputLevel.INFO; + private static boolean addrSpecified = false; + + private SimpleFileServerImpl() { throw new AssertionError(); } + + /** + * Starts a simple HTTP file server created on a directory. + * + * @param writer the writer to which output should be written + * @param args the command line options + * @throws NullPointerException if any of the arguments are {@code null}, + * or if there are any {@code null} values in the {@code args} array + * @return startup status code + */ + static int start(PrintWriter writer, String[] args) { + Objects.requireNonNull(args); + for (var arg : args) { + Objects.requireNonNull(arg); + } + Out out = new Out(writer); + + InetAddress addr = LOOPBACK_ADDR; + int port = DEFAULT_PORT; + Path root = DEFAULT_ROOT; + OutputLevel outputLevel = DEFAULT_OUTPUT_LEVEL; + + // parse options + Iterator options = Arrays.asList(args).iterator(); + String option = null; + String optionArg = null; + try { + while (options.hasNext()) { + option = options.next(); + switch (option) { + case "-h", "-?", "--help" -> { + out.showHelp(); + return Startup.OK.statusCode; + } + case "-b", "--bind-address" -> { + addr = InetAddress.getByName(optionArg = options.next()); + addrSpecified = true; + } + case "-d", "--directory" -> + root = Path.of(optionArg = options.next()); + case "-o", "--output" -> + outputLevel = Enum.valueOf(OutputLevel.class, + (optionArg = options.next()).toUpperCase(Locale.ROOT)); + case "-p", "--port" -> + port = Integer.parseInt(optionArg = options.next()); + default -> throw new AssertionError(); + } + } + } catch (AssertionError ae) { + out.reportError(ResourceBundleHelper.getMessage("err.unknown.option", option)); + out.showUsage(); + return Startup.CMDERR.statusCode; + } catch (NoSuchElementException nsee) { + out.reportError(ResourceBundleHelper.getMessage("err.missing.arg", option)); + out.showOption(option); + return Startup.CMDERR.statusCode; + } catch (Exception e) { + out.reportError(ResourceBundleHelper.getMessage("err.invalid.arg", option, optionArg)); + e.printStackTrace(out.writer); + return Startup.CMDERR.statusCode; + } finally { + out.flush(); + } + + // configure and start server + try { + var socketAddr = new InetSocketAddress(addr, port); + var server = SimpleFileServer.createFileServer(socketAddr, root, outputLevel); + server.start(); + out.printStartMessage(root, server); + } catch (Throwable t) { + out.reportError(ResourceBundleHelper.getMessage("err.server.config.failed", t.getMessage())); + return Startup.SYSERR.statusCode; + } finally { + out.flush(); + } + return Startup.OK.statusCode; + } + + private final static class Out { + private final PrintWriter writer; + private Out() { throw new AssertionError(); } + + Out(PrintWriter writer) { + this.writer = Objects.requireNonNull(writer); + } + + void printStartMessage(Path root, HttpServer server) + throws UnknownHostException + { + String port = Integer.toString(server.getAddress().getPort()); + var inetAddr = server.getAddress().getAddress(); + var isAnyLocal = inetAddr.isAnyLocalAddress(); + var addr = isAnyLocal ? InetAddress.getLocalHost().getHostAddress() : inetAddr.getHostAddress(); + if (!addrSpecified) { + writer.println(ResourceBundleHelper.getMessage("loopback.info")); + } + if (isAnyLocal) { + writer.println(ResourceBundleHelper.getMessage("msg.start.anylocal", root, addr, port)); + } else { + writer.println(ResourceBundleHelper.getMessage("msg.start.other", root, addr, port)); + } + } + + void showUsage() { + writer.println(ResourceBundleHelper.getMessage("usage")); + } + + void showHelp() { + writer.println(ResourceBundleHelper.getMessage("usage")); + writer.println(ResourceBundleHelper.getMessage("options", LOOPBACK_ADDR.getHostAddress())); + } + + void showOption(String option) { + switch (option) { + case "-b", "--bind-address" -> + writer.println(ResourceBundleHelper.getMessage("opt.bindaddress", LOOPBACK_ADDR.getHostAddress())); + case "-d", "--directory" -> + writer.println(ResourceBundleHelper.getMessage("opt.directory")); + case "-o", "--output" -> + writer.println(ResourceBundleHelper.getMessage("opt.output")); + case "-p", "--port" -> + writer.println(ResourceBundleHelper.getMessage("opt.port")); + } + } + + void reportError(String message) { + writer.println(ResourceBundleHelper.getMessage("error.prefix") + " " + message); + } + + void flush() { + writer.flush(); + } + } + + private enum Startup { + /** Started with no errors */ + OK(0), + /** Not started, bad command-line arguments */ + CMDERR(1), + /** Not started, system error or resource exhaustion */ + SYSERR(2); + + Startup(int statusCode) { + this.statusCode = statusCode; + } + public final int statusCode; + } +} diff --git a/src/jdk.httpserver/share/classes/sun/net/httpserver/simpleserver/resources/simpleserver.properties b/src/jdk.httpserver/share/classes/sun/net/httpserver/simpleserver/resources/simpleserver.properties new file mode 100644 index 00000000000..bf7572b02d6 --- /dev/null +++ b/src/jdk.httpserver/share/classes/sun/net/httpserver/simpleserver/resources/simpleserver.properties @@ -0,0 +1,70 @@ +# +# Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. +# 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. +# + +usage=\ +Usage: java -m jdk.httpserver [-b bind address] [-p port] [-d directory]\n\ +\ [-o none|info|verbose] [-h to show options] + +options=\ +Options:\n\ +-b, --bind-address - Address to bind to. Default: {0} (loopback).\n\ +\ For all interfaces use "-b 0.0.0.0" or "-b ::".\n\ +-d, --directory - Directory to serve. Default: current directory.\n\ +-o, --output - Output format. none|info|verbose. Default: info.\n\ +-p, --port - Port to listen on. Default: 8000.\n\ +-h, -?, --help - Print this help message.\n\ +To stop the server, press Ctrl + C. + +opt.bindaddress=\ +-b, --bind-address - Address to bind to. Default: {0} (loopback).\n\ +\ For all interfaces use "-b 0.0.0.0" or "-b ::". +opt.directory=\ +-d, --directory - Directory to serve. Default: current directory. +opt.output=\ +-o, --output - Output format. none|info|verbose. Default: info. +opt.port=\ +-p, --port - Port to listen on. Default: 8000. + +loopback.info=\ +Binding to loopback by default. For all interfaces use "-b 0.0.0.0" or "-b ::". + +msg.start.anylocal=\ +Serving {0} and subdirectories on 0.0.0.0 (all interfaces) port {2}\n\ +URL http://{1}:{2}/ + +msg.start.other=\ +Serving {0} and subdirectories on {1} port {2}\n\ +URL http://{1}:{2}/ + +error.prefix=Error: + +err.unknown.option=unknown option: {0} +err.missing.arg=no value given for {0} +err.invalid.arg=invalid value given for {0}: {1} +err.server.config.failed=server config failed: {0} +err.server.handle.failed=server exchange handling failed: {0} + +html.dir.list=Directory listing for +html.not.found=File not found diff --git a/test/jdk/TEST.ROOT b/test/jdk/TEST.ROOT index 9f8bcca9b91..0a6afd8e66a 100644 --- a/test/jdk/TEST.ROOT +++ b/test/jdk/TEST.ROOT @@ -27,8 +27,9 @@ exclusiveAccess.dirs=java/math/BigInteger/largeMemory \ java/rmi/Naming java/util/prefs sun/management/jmxremote \ sun/tools/jstatd sun/tools/jcmd \ sun/tools/jinfo sun/tools/jmap sun/tools/jps sun/tools/jstack sun/tools/jstat \ -com/sun/tools/attach sun/security/mscapi java/util/Arrays/largeMemory \ -java/util/BitSet/stream javax/rmi java/net/httpclient/websocket +com/sun/tools/attach sun/security/mscapi java/util/stream java/util/Arrays/largeMemory \ +java/util/BitSet/stream javax/rmi java/net/httpclient/websocket \ +com/sun/net/httpserver/simpleserver # Group definitions groups=TEST.groups diff --git a/test/jdk/com/sun/net/httpserver/FilterTest.java b/test/jdk/com/sun/net/httpserver/FilterTest.java index 8c4f734d96c..45c7ef21e8d 100644 --- a/test/jdk/com/sun/net/httpserver/FilterTest.java +++ b/test/jdk/com/sun/net/httpserver/FilterTest.java @@ -40,6 +40,8 @@ import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.nio.charset.StandardCharsets; import java.util.concurrent.CompletableFuture; +import java.util.List; +import java.util.concurrent.atomic.AtomicReference; import java.util.logging.ConsoleHandler; import java.util.logging.Level; import java.util.logging.Logger; @@ -47,10 +49,10 @@ import com.sun.net.httpserver.Filter; import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpHandler; import com.sun.net.httpserver.HttpServer; -import static java.net.http.HttpClient.Builder.NO_PROXY; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import org.testng.annotations.BeforeTest; +import static java.net.http.HttpClient.Builder.NO_PROXY; import static org.testng.Assert.*; public class FilterTest { @@ -79,6 +81,9 @@ public class FilterTest { expectThrows(NPE, () -> Filter.afterHandler("Some description", null)); expectThrows(NPE, () -> Filter.afterHandler(null, HttpExchange::getResponseCode)); + + expectThrows(NPE, () -> Filter.adaptRequest("Some description", null)); + expectThrows(NPE, () -> Filter.adaptRequest(null, r -> r.with("Foo", List.of("Bar")))); } @Test @@ -90,6 +95,9 @@ public class FilterTest { var afterFilter = Filter.afterHandler(desc, HttpExchange::getResponseCode); assertEquals(desc, afterFilter.description()); + + var adaptFilter = Filter.adaptRequest(desc, r -> r.with("Foo", List.of("Bar"))); + assertEquals(desc, adaptFilter.description()); } @DataProvider @@ -305,6 +313,64 @@ public class FilterTest { } } + @Test + public void testInspectRequest() throws Exception { + var handler = new EchoHandler(); + var inspectedURI = new AtomicReference(); + var filter = Filter.adaptRequest("Inspect request URI", + r -> {inspectedURI.set(r.getRequestURI()); return r;}); + var server = HttpServer.create(new InetSocketAddress(LOOPBACK_ADDR,0), 10); + server.createContext("/", handler).getFilters().add(filter); + server.start(); + try { + var client = HttpClient.newBuilder().proxy(NO_PROXY).build(); + var request = HttpRequest.newBuilder(uri(server, "foo/bar")).build(); + var response = client.send(request, HttpResponse.BodyHandlers.ofString()); + assertEquals(response.statusCode(), 200); + assertEquals(inspectedURI.get(), URI.create("/foo/bar")); + } finally { + server.stop(0); + } + } + + private static HttpExchange originalExchange; + + /** + * Confirms that adaptRequest changes only the expected request state and + * all other exchange state remains unchanged. + */ + @Test + public void testAdaptRequest() throws Exception { + var handler = new CompareStateAndEchoHandler(); + var captureFilter = Filter.beforeHandler("capture exchange", e -> { + e.setAttribute("foo", "bar"); + originalExchange = e; + }); + var adaptFilter = Filter.adaptRequest("Add x-foo request header", r -> { + // Confirm request state is unchanged + assertEquals(r.getRequestHeaders(), originalExchange.getRequestHeaders()); + assertEquals(r.getRequestURI(), originalExchange.getRequestURI()); + assertEquals(r.getRequestMethod(), originalExchange.getRequestMethod()); + return r.with("x-foo", List.of("bar")); + }); + var server = HttpServer.create(new InetSocketAddress(LOOPBACK_ADDR,0), 10); + var context = server.createContext("/", handler); + context.getFilters().add(captureFilter); + context.getFilters().add(adaptFilter); + server.start(); + try { + var client = HttpClient.newBuilder().proxy(NO_PROXY).build(); + var request = HttpRequest.newBuilder(uri(server, "")).build(); + var response = client.send(request, HttpResponse.BodyHandlers.ofString()); + assertEquals(response.statusCode(), 200); + assertEquals(response.body(), "bar"); + } finally { + server.stop(0); + } + } + + // --- infra --- + static URI uri(HttpServer server, String path) { return URI.create("http://localhost:%s/%s".formatted(server.getAddress().getPort(), path)); } @@ -325,6 +391,42 @@ public class FilterTest { } } + /** + * A handler that compares the adapted exchange with the original exchange, + * before discarding the request and returning the test request header value. + */ + static class CompareStateAndEchoHandler implements HttpHandler { + @Override + public void handle(HttpExchange exchange) throws IOException { + assertEquals(exchange.getLocalAddress(), originalExchange.getLocalAddress()); + assertEquals(exchange.getRemoteAddress(), originalExchange.getRemoteAddress()); + assertEquals(exchange.getProtocol(), originalExchange.getProtocol()); + assertEquals(exchange.getPrincipal(), originalExchange.getPrincipal()); + assertEquals(exchange.getHttpContext(), originalExchange.getHttpContext()); + assertEquals(exchange.getRequestMethod(), originalExchange.getRequestMethod()); + assertEquals(exchange.getRequestURI(), originalExchange.getRequestURI()); + assertEquals(exchange.getRequestBody(), originalExchange.getRequestBody()); + assertEquals(exchange.getResponseHeaders(), originalExchange.getResponseHeaders()); + assertEquals(exchange.getResponseCode(), originalExchange.getResponseCode()); + assertEquals(exchange.getResponseBody(), originalExchange.getResponseBody()); + assertEquals(exchange.getAttribute("foo"), originalExchange.getAttribute("foo")); + assertFalse(exchange.getRequestHeaders().equals(originalExchange.getRequestHeaders())); + + exchange.setAttribute("foo", "barbar"); + assertEquals(exchange.getAttribute("foo"), originalExchange.getAttribute("foo")); + + try (InputStream is = exchange.getRequestBody(); + OutputStream os = exchange.getResponseBody()) { + is.readAllBytes(); + var resp = exchange.getRequestHeaders().get("x-foo") + .get(0) + .getBytes(StandardCharsets.UTF_8); + exchange.sendResponseHeaders(200, resp.length); + os.write(resp); + } + } + } + /** * A test handler that does nothing */ diff --git a/test/jdk/com/sun/net/httpserver/HeadersTest.java b/test/jdk/com/sun/net/httpserver/HeadersTest.java index b62d2a6d79a..dffa4143c0f 100644 --- a/test/jdk/com/sun/net/httpserver/HeadersTest.java +++ b/test/jdk/com/sun/net/httpserver/HeadersTest.java @@ -26,6 +26,7 @@ * @bug 8251496 8268960 * @summary Tests for methods in Headers class * @modules jdk.httpserver/com.sun.net.httpserver:+open + * jdk.httpserver/sun.net.httpserver:+open * @library /test/lib * @build jdk.test.lib.net.URIBuilder * @run testng/othervm HeadersTest @@ -55,10 +56,12 @@ import com.sun.net.httpserver.HttpServer; import jdk.test.lib.net.URIBuilder; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; +import sun.net.httpserver.UnmodifiableHeaders; import static java.net.http.HttpClient.Builder.NO_PROXY; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertNotEquals; import static org.testng.Assert.assertThrows; import static org.testng.Assert.assertTrue; @@ -314,4 +317,131 @@ public class HeadersTest { h2.put("b", List.of("22")); assertTrue(h1.equals(h2)); } + + @Test + public static void test1ArgConstructorNull() { + assertThrows(NPE, () -> new Headers(null)); + { + final var m = new HashMap>(); + m.put(null, List.of("Bar")); + assertThrows(NPE, () -> new Headers(m)); + } + { + final var m = new HashMap>(); + m.put("Foo", null); + assertThrows(NPE, () -> new Headers(m)); + } + { + final var m = new HashMap>(); + final var list = new LinkedList(); + list.add(null); + m.put("Foo", list); + assertThrows(NPE, () -> new Headers(m)); + } + } + + @Test + public static void test1ArgConstructor() { + { + var h = new Headers(new Headers()); + assertTrue(h.isEmpty()); + } + { + var h = new Headers(Map.of("Foo", List.of("Bar"))); + assertEquals(h.get("Foo"), List.of("Bar")); + assertEquals(h.size(), 1); + } + { + var h1 = new Headers(new UnmodifiableHeaders(new Headers())); + assertTrue(h1.isEmpty()); + h1.put("Foo", List.of("Bar")); // modifiable + assertEquals(h1.get("Foo"), List.of("Bar")); + assertEquals(h1.size(), 1); + + var h2 = new Headers(h1); + assertEquals(h2.get("Foo"), List.of("Bar")); + assertEquals(h2.size(), 1); + + assertEquals(h1, h2); + h1.set("Foo", "Barbar"); + assertNotEquals(h1, h2); + } + } + + @Test + public static void testMutableHeaders() { + { + var h = new Headers(); + h.add("Foo", "Bar"); + h.add("Foo", "Bazz"); + h.get("Foo").remove(0); + h.remove("Foo"); + h.clear(); + } + { + var h = new Headers(Map.of("Foo", List.of("Bar"))); + h.get("Foo").add("Bazz"); + h.get("Foo").remove(0); + h.remove("Foo"); + h.clear(); + } + } + + @Test + public static void testOfNull() { + assertThrows(NPE, () -> Headers.of((String[])null)); + assertThrows(NPE, () -> Headers.of(null, "Bar")); + assertThrows(NPE, () -> Headers.of("Foo", null)); + + assertThrows(NPE, () -> Headers.of((Map>) null)); + { + final var m = new HashMap>(); + m.put(null, List.of("Bar")); + assertThrows(NPE, () -> Headers.of(m)); + } + { + final var m = new HashMap>(); + m.put("Foo", null); + assertThrows(NPE, () -> Headers.of(m)); + } + { + final var m = new HashMap>(); + final var list = new LinkedList(); + list.add(null); + m.put("Foo", list); + assertThrows(NPE, () -> Headers.of(m)); + } + } + + @Test + public static void testOf() { + final var h = Headers.of("a", "1", "b", "2"); + assertEquals(h.size(), 2); + List.of("a", "b").forEach(n -> assertTrue(h.containsKey(n))); + List.of("1", "2").forEach(v -> assertTrue(h.containsValue(List.of(v)))); + } + + @Test + public static void testOfEmpty() { + for (var h : List.of(Headers.of(), Headers.of(new String[] { }))) { + assertEquals(h.size(), 0); + assertTrue(h.isEmpty()); + } + } + + @Test + public static void testOfNumberOfElements() { + assertThrows(IAE, () -> Headers.of("a")); + assertThrows(IAE, () -> Headers.of("a", "1", "b")); + } + + @Test + public static void testOfMultipleValues() { + final var h = Headers.of("a", "1", "b", "1", "b", "2", "b", "3"); + assertEquals(h.size(), 2); + List.of("a", "b").forEach(n -> assertTrue(h.containsKey(n))); + List.of(List.of("1"), List.of("1", "2", "3")).forEach(v -> assertTrue(h.containsValue(v))); + } + + // Immutability tests in UnmodifiableHeadersTest.java } diff --git a/test/jdk/com/sun/net/httpserver/UnmodifiableHeadersTest.java b/test/jdk/com/sun/net/httpserver/UnmodifiableHeadersTest.java index bdcaa4a4683..8c70d65c966 100644 --- a/test/jdk/com/sun/net/httpserver/UnmodifiableHeadersTest.java +++ b/test/jdk/com/sun/net/httpserver/UnmodifiableHeadersTest.java @@ -40,6 +40,7 @@ import com.sun.net.httpserver.Headers; import com.sun.net.httpserver.HttpContext; import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpPrincipal; +import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import sun.net.httpserver.UnmodifiableHeaders; import static org.testng.Assert.assertEquals; @@ -62,14 +63,24 @@ public class UnmodifiableHeadersTest { assertEquals(unmodifiableHeaders2.get("Foo"), headers.get("Foo")); } - @Test - public static void testUnmodifiableHeaders() { + @DataProvider + public Object[][] headers() { var headers = new Headers(); headers.add("Foo", "Bar"); - HttpExchange exchange = new TestHttpExchange(headers); + var exchange = new TestHttpExchange(headers); + + return new Object[][] { + { exchange.getRequestHeaders() }, + { Headers.of("Foo", "Bar") }, + { Headers.of(Map.of("Foo", List.of("Bar"))) }, + }; + } - assertUnsupportedOperation(exchange.getRequestHeaders()); - assertUnmodifiableCollection(exchange.getRequestHeaders()); + @Test(dataProvider = "headers") + public static void testUnmodifiableHeaders(Headers headers) { + assertUnsupportedOperation(headers); + assertUnmodifiableCollection(headers); + assertUnmodifiableList(headers); } static final Class UOP = UnsupportedOperationException.class; diff --git a/test/jdk/com/sun/net/httpserver/simpleserver/CommandLineNegativeTest.java b/test/jdk/com/sun/net/httpserver/simpleserver/CommandLineNegativeTest.java new file mode 100644 index 00000000000..a494d5961a3 --- /dev/null +++ b/test/jdk/com/sun/net/httpserver/simpleserver/CommandLineNegativeTest.java @@ -0,0 +1,245 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 Negative tests for simpleserver command-line tool + * @library /test/lib + * @modules jdk.httpserver + * @run testng/othervm CommandLineNegativeTest + */ + +import java.io.IOException; +import java.net.InetAddress; +import java.nio.file.Files; +import java.nio.file.Path; +import jdk.test.lib.Platform; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.util.FileUtils; +import org.testng.SkipException; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import static java.lang.System.out; +import static org.testng.Assert.assertFalse; + +public class CommandLineNegativeTest { + + static final Path JAVA_HOME = Path.of(System.getProperty("java.home")); + static final String JAVA = getJava(JAVA_HOME); + static final Path CWD = Path.of(".").toAbsolutePath().normalize(); + static final Path TEST_DIR = CWD.resolve("CommandLineNegativeTest"); + static final Path TEST_FILE = TEST_DIR.resolve("file.txt"); + static final String LOOPBACK_ADDR = InetAddress.getLoopbackAddress().getHostAddress(); + + @BeforeTest + public void setup() throws IOException { + if (Files.exists(TEST_DIR)) { + FileUtils.deleteFileTreeWithRetry(TEST_DIR); + } + Files.createDirectories(TEST_DIR); + Files.createFile(TEST_FILE); + } + + @DataProvider + public Object[][] unknownOption() { + return new Object[][] { + {"--unknownOption"}, + {"null"} + }; + } + + @Test(dataProvider = "unknownOption") + public void testBadOption(String opt) throws Throwable { + out.println("\n--- testUnknownOption, opt=\"%s\" ".formatted(opt)); + simpleserver(JAVA, "-m", "jdk.httpserver", opt) + .shouldNotHaveExitValue(0) + .shouldContain("Error: unknown option: " + opt); + } + + @DataProvider + public Object[][] tooManyOptionArgs() { + return new Object[][] { + {"-b", "localhost"}, + {"-d", "/some/path"}, + {"-o", "none"}, + {"-p", "0"}, + {"--bind-address", "localhost"}, + {"--directory", "/some/path"}, + {"--output", "none"}, + {"--port", "0"} + // doesn't fail for -h option + }; + } + + @Test(dataProvider = "tooManyOptionArgs") + public void testTooManyOptionArgs(String opt, String arg) throws Throwable { + out.println("\n--- testTooManyOptionArgs, opt=\"%s\" ".formatted(opt)); + simpleserver(JAVA, "-m", "jdk.httpserver", opt, arg, arg) + .shouldNotHaveExitValue(0) + .shouldContain("Error: unknown option: " + arg); + } + + @DataProvider + public Object[][] noArg() { + return new Object[][] { + {"-b", """ + -b, --bind-address - Address to bind to. Default: %s (loopback). + For all interfaces use "-b 0.0.0.0" or "-b ::".""".formatted(LOOPBACK_ADDR)}, + {"-d", "-d, --directory - Directory to serve. Default: current directory."}, + {"-o", "-o, --output - Output format. none|info|verbose. Default: info."}, + {"-p", "-p, --port - Port to listen on. Default: 8000."}, + {"--bind-address", """ + -b, --bind-address - Address to bind to. Default: %s (loopback). + For all interfaces use "-b 0.0.0.0" or "-b ::".""".formatted(LOOPBACK_ADDR)}, + {"--directory", "-d, --directory - Directory to serve. Default: current directory."}, + {"--output", "-o, --output - Output format. none|info|verbose. Default: info."}, + {"--port", "-p, --port - Port to listen on. Default: 8000."} + // doesn't fail for -h option + }; + } + + @Test(dataProvider = "noArg") + public void testNoArg(String opt, String msg) throws Throwable { + out.println("\n--- testNoArg, opt=\"%s\" ".formatted(opt)); + simpleserver(JAVA, "-m", "jdk.httpserver", opt) + .shouldNotHaveExitValue(0) + .shouldContain("Error: no value given for " + opt) + .shouldContain(msg); + } + + @DataProvider + public Object[][] invalidValue() { + return new Object[][] { + {"-b", "[127.0.0.1]"}, + {"-b", "badhost"}, + {"--bind-address", "192.168.1.220..."}, + + {"-o", "bad-output-level"}, + {"--output", "bad-output-level"}, + + {"-p", "+-"}, + {"--port", "+-"} + }; + } + + @Test(dataProvider = "invalidValue") + public void testInvalidValue(String opt, String val) throws Throwable { + out.println("\n--- testInvalidValue, opt=\"%s\" ".formatted(opt)); + simpleserver(JAVA, "-m", "jdk.httpserver", opt, val) + .shouldNotHaveExitValue(0) + .shouldContain("Error: invalid value given for " + opt + ": " + val); + } + + @DataProvider + public Object[][] portOptions() { return new Object[][] {{"-p"}, {"--port"}}; } + + @Test(dataProvider = "portOptions") + public void testPortOutOfRange(String opt) throws Throwable { + out.println("\n--- testPortOutOfRange, opt=\"%s\" ".formatted(opt)); + simpleserver(JAVA, "-m", "jdk.httpserver", opt, "65536") // range 0 to 65535 + .shouldNotHaveExitValue(0) + .shouldContain("Error: server config failed: " + "port out of range:65536"); + } + + @DataProvider + public Object[][] directoryOptions() { return new Object[][] {{"-d"}, {"--directory"}}; } + + @Test(dataProvider = "directoryOptions") + public void testRootNotAbsolute(String opt) throws Throwable { + out.println("\n--- testRootNotAbsolute, opt=\"%s\" ".formatted(opt)); + var root = Path.of("."); + assertFalse(root.isAbsolute()); + simpleserver(JAVA, "-m", "jdk.httpserver", opt, root.toString()) + .shouldNotHaveExitValue(0) + .shouldContain("Error: server config failed: " + "Path is not absolute:"); + } + + @Test(dataProvider = "directoryOptions") + public void testRootNotADirectory(String opt) throws Throwable { + out.println("\n--- testRootNotADirectory, opt=\"%s\" ".formatted(opt)); + var file = TEST_FILE.toString(); + assertFalse(Files.isDirectory(TEST_FILE)); + simpleserver(JAVA, "-m", "jdk.httpserver", opt, file) + .shouldNotHaveExitValue(0) + .shouldContain("Error: server config failed: " + "Path is not a directory: " + file); + } + + @Test(dataProvider = "directoryOptions") + public void testRootDoesNotExist(String opt) throws Throwable { + out.println("\n--- testRootDoesNotExist, opt=\"%s\" ".formatted(opt)); + Path root = TEST_DIR.resolve("not/existent/dir"); + assertFalse(Files.exists(root)); + simpleserver(JAVA, "-m", "jdk.httpserver", opt, root.toString()) + .shouldNotHaveExitValue(0) + .shouldContain("Error: server config failed: " + "Path does not exist: " + root.toString()); + } + + @Test(dataProvider = "directoryOptions") + public void testRootNotReadable(String opt) throws Throwable { + out.println("\n--- testRootNotReadable, opt=\"%s\" ".formatted(opt)); + if (Platform.isWindows()) { + // Not applicable to Windows. Reason: cannot revoke an owner's read + // access to a directory that was created by that owner + throw new SkipException("cannot run on Windows"); + } + Path root = Files.createDirectories(TEST_DIR.resolve("not/readable/dir")); + try { + root.toFile().setReadable(false, false); + assertFalse(Files.isReadable(root)); + simpleserver(JAVA, "-m", "jdk.httpserver", opt, root.toString()) + .shouldNotHaveExitValue(0) + .shouldContain("Error: server config failed: " + "Path is not readable: " + root.toString()); + } finally { + root.toFile().setReadable(true, false); + } + } + + @AfterTest + public void teardown() throws IOException { + if (Files.exists(TEST_DIR)) { + FileUtils.deleteFileTreeWithRetry(TEST_DIR); + } + } + + // --- infra --- + + static String getJava(Path image) { + boolean isWindows = System.getProperty("os.name").startsWith("Windows"); + Path java = image.resolve("bin").resolve(isWindows ? "java.exe" : "java"); + if (Files.notExists(java)) + throw new RuntimeException(java + " not found"); + return java.toAbsolutePath().toString(); + } + + static OutputAnalyzer simpleserver(String... args) throws Throwable { + var pb = new ProcessBuilder(args) + .directory(TEST_DIR.toFile()); + var outputAnalyser = ProcessTools.executeCommand(pb) + .outputTo(System.out) + .errorTo(System.out); + return outputAnalyser; + } +} diff --git a/test/jdk/com/sun/net/httpserver/simpleserver/CommandLinePositiveTest.java b/test/jdk/com/sun/net/httpserver/simpleserver/CommandLinePositiveTest.java new file mode 100644 index 00000000000..a5e636c354d --- /dev/null +++ b/test/jdk/com/sun/net/httpserver/simpleserver/CommandLinePositiveTest.java @@ -0,0 +1,240 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 Positive tests for simpleserver command-line tool + * @library /test/lib + * @modules jdk.httpserver + * @run testng/othervm CommandLinePositiveTest + */ + +import java.io.IOException; +import java.net.InetAddress; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.concurrent.TimeUnit; +import jdk.test.lib.Platform; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.util.FileUtils; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import static java.lang.System.out; + +public class CommandLinePositiveTest { + + static final Path JAVA_HOME = Path.of(System.getProperty("java.home")); + static final String JAVA = getJava(JAVA_HOME); + static final Path CWD = Path.of(".").toAbsolutePath().normalize(); + static final Path TEST_DIR = CWD.resolve("CommandLinePositiveTest"); + static final Path TEST_FILE = TEST_DIR.resolve("file.txt"); + static final String TEST_DIR_STR = TEST_DIR.toString(); + static final String LOOPBACK_ADDR = InetAddress.getLoopbackAddress().getHostAddress(); + + @BeforeTest + public void setup() throws IOException { + if (Files.exists(TEST_DIR)) { + FileUtils.deleteFileTreeWithRetry(TEST_DIR); + } + Files.createDirectories(TEST_DIR); + Files.createFile(TEST_FILE); + } + + static final int SIGTERM = 15; + static final int NORMAL_EXIT_CODE = normalExitCode(); + + static int normalExitCode() { + if (Platform.isWindows()) { + return 1; // expected process destroy exit code + } else { + // signal terminated exit code on Unix is 128 + signal value + return 128 + SIGTERM; + } + } + + @DataProvider + public Object[][] directoryOptions() { return new Object[][] {{"-d"}, {"--directory"}}; } + + @Test(dataProvider = "directoryOptions") + public void testDirectory(String opt) throws Throwable { + out.println("\n--- testDirectory, opt=\"%s\" ".formatted(opt)); + simpleserver(JAVA, "-m", "jdk.httpserver", "-p", "0", opt, TEST_DIR_STR) + .shouldHaveExitValue(NORMAL_EXIT_CODE) + .shouldContain("Binding to loopback by default. For all interfaces use \"-b 0.0.0.0\" or \"-b ::\".") + .shouldContain("Serving " + TEST_DIR_STR + " and subdirectories on " + LOOPBACK_ADDR + " port") + .shouldContain("URL http://" + LOOPBACK_ADDR); + } + + @DataProvider + public Object[][] portOptions() { return new Object[][] {{"-p"}, {"--port"}}; } + + @Test(dataProvider = "portOptions") + public void testPort(String opt) throws Throwable { + out.println("\n--- testPort, opt=\"%s\" ".formatted(opt)); + simpleserver(JAVA, "-m", "jdk.httpserver", opt, "0") + .shouldHaveExitValue(NORMAL_EXIT_CODE) + .shouldContain("Binding to loopback by default. For all interfaces use \"-b 0.0.0.0\" or \"-b ::\".") + .shouldContain("Serving " + TEST_DIR_STR + " and subdirectories on " + LOOPBACK_ADDR + " port") + .shouldContain("URL http://" + LOOPBACK_ADDR); + } + + @DataProvider + public Object[][] helpOptions() { return new Object[][] {{"-h"}, {"-?"}, {"--help"}}; } + + static final String USAGE_TEXT = """ + Usage: java -m jdk.httpserver [-b bind address] [-p port] [-d directory] + [-o none|info|verbose] [-h to show options]"""; + + static final String OPTIONS_TEXT = """ + Options: + -b, --bind-address - Address to bind to. Default: %s (loopback). + For all interfaces use "-b 0.0.0.0" or "-b ::". + -d, --directory - Directory to serve. Default: current directory. + -o, --output - Output format. none|info|verbose. Default: info. + -p, --port - Port to listen on. Default: 8000. + -h, -?, --help - Print this help message. + To stop the server, press Ctrl + C.""".formatted(LOOPBACK_ADDR); + + @Test(dataProvider = "helpOptions") + public void testHelp(String opt) throws Throwable { + out.println("\n--- testHelp, opt=\"%s\" ".formatted(opt)); + simpleserver(WaitForLine.HELP_STARTUP_LINE, + false, // do not explicitly destroy the process + JAVA, "-m", "jdk.httpserver", opt) + .shouldHaveExitValue(0) + .shouldContain(USAGE_TEXT) + .shouldContain(OPTIONS_TEXT); + } + + @DataProvider + public Object[][] bindOptions() { return new Object[][] {{"-b"}, {"--bind-address"}}; } + + @Test(dataProvider = "bindOptions") + public void testBindAllInterfaces(String opt) throws Throwable { + out.println("\n--- testPort, opt=\"%s\" ".formatted(opt)); + simpleserver(JAVA, "-m", "jdk.httpserver", opt, "0.0.0.0") + .shouldHaveExitValue(NORMAL_EXIT_CODE) + .shouldContain("Serving " + TEST_DIR_STR + " and subdirectories on 0.0.0.0 (all interfaces) port") + .shouldContain("URL http://" + InetAddress.getLocalHost().getHostAddress()); + simpleserver(JAVA, "-m", "jdk.httpserver", opt, "::0") + .shouldHaveExitValue(NORMAL_EXIT_CODE) + .shouldContain("Serving " + TEST_DIR_STR + " and subdirectories on 0.0.0.0 (all interfaces) port") + .shouldContain("URL http://" + InetAddress.getLocalHost().getHostAddress()); + } + + @Test(dataProvider = "bindOptions") + public void testLastOneWinsBindAddress(String opt) throws Throwable { + out.println("\n--- testLastOneWinsBindAddress, opt=\"%s\" ".formatted(opt)); + simpleserver(JAVA, "-m", "jdk.httpserver", "-p", "0", opt, "123.4.5.6", opt, LOOPBACK_ADDR) + .shouldHaveExitValue(NORMAL_EXIT_CODE) + .shouldContain("Serving " + TEST_DIR_STR + " and subdirectories on " + LOOPBACK_ADDR + " port") + .shouldContain("URL http://" + LOOPBACK_ADDR); + + } + + @Test(dataProvider = "directoryOptions") + public void testLastOneWinsDirectory(String opt) throws Throwable { + out.println("\n--- testLastOneWinsDirectory, opt=\"%s\" ".formatted(opt)); + simpleserver(JAVA, "-m", "jdk.httpserver", "-p", "0", opt, TEST_DIR_STR, opt, TEST_DIR_STR) + .shouldHaveExitValue(NORMAL_EXIT_CODE) + .shouldContain("Binding to loopback by default. For all interfaces use \"-b 0.0.0.0\" or \"-b ::\".") + .shouldContain("Serving " + TEST_DIR_STR + " and subdirectories on " + LOOPBACK_ADDR + " port") + .shouldContain("URL http://" + LOOPBACK_ADDR); + } + + @DataProvider + public Object[][] outputOptions() { return new Object[][] {{"-o"}, {"--output"}}; } + + @Test(dataProvider = "outputOptions") + public void testLastOneWinsOutput(String opt) throws Throwable { + out.println("\n--- testLastOneWinsOutput, opt=\"%s\" ".formatted(opt)); + simpleserver(JAVA, "-m", "jdk.httpserver", "-p", "0", opt, "none", opt, "verbose") + .shouldHaveExitValue(NORMAL_EXIT_CODE) + .shouldContain("Binding to loopback by default. For all interfaces use \"-b 0.0.0.0\" or \"-b ::\".") + .shouldContain("Serving " + TEST_DIR_STR + " and subdirectories on " + LOOPBACK_ADDR + " port") + .shouldContain("URL http://" + LOOPBACK_ADDR); + } + + @Test(dataProvider = "portOptions") + public void testLastOneWinsPort(String opt) throws Throwable { + out.println("\n--- testLastOneWinsPort, opt=\"%s\" ".formatted(opt)); + simpleserver(JAVA, "-m", "jdk.httpserver", opt, "-999", opt, "0") + .shouldHaveExitValue(NORMAL_EXIT_CODE) + .shouldContain("Binding to loopback by default. For all interfaces use \"-b 0.0.0.0\" or \"-b ::\".") + .shouldContain("Serving " + TEST_DIR_STR + " and subdirectories on " + LOOPBACK_ADDR + " port") + .shouldContain("URL http://" + LOOPBACK_ADDR); + } + + @AfterTest + public void teardown() throws IOException { + if (Files.exists(TEST_DIR)) { + FileUtils.deleteFileTreeWithRetry(TEST_DIR); + } + } + + // --- infra --- + + static String getJava(Path image) { + boolean isWindows = System.getProperty("os.name").startsWith("Windows"); + Path java = image.resolve("bin").resolve(isWindows ? "java.exe" : "java"); + if (Files.notExists(java)) + throw new RuntimeException(java + " not found"); + return java.toAbsolutePath().toString(); + } + + static final String REGULAR_STARTUP_LINE1_STRING = "Serving"; + static final String REGULAR_STARTUP_LINE2_STRING = "URL http://"; + + // The stdout/stderr output line to wait for when starting the simpleserver + enum WaitForLine { + REGULAR_STARTUP_LINE (REGULAR_STARTUP_LINE2_STRING) , + HELP_STARTUP_LINE (OPTIONS_TEXT.lines().reduce((first, second) -> second).orElseThrow()); + + final String value; + WaitForLine(String value) { this.value = value; } + } + + static OutputAnalyzer simpleserver(String... args) throws Throwable { + return simpleserver(WaitForLine.REGULAR_STARTUP_LINE, true, args); + } + + static OutputAnalyzer simpleserver(WaitForLine waitForLine, boolean destroy, String... args) throws Throwable { + StringBuffer sb = new StringBuffer(); // stdout & stderr + // start the process and await the waitForLine before returning + var p = ProcessTools.startProcess("simpleserver", + new ProcessBuilder(args).directory(TEST_DIR.toFile()), + line -> sb.append(line + "\n"), + line -> line.startsWith(waitForLine.value), + 30, // suitably high default timeout, not expected to timeout + TimeUnit.SECONDS); + if (destroy) { + p.destroy(); // SIGTERM on Unix + } + int ec = p.waitFor(); + var outputAnalyser = new OutputAnalyzer(sb.toString(), "", ec); + return outputAnalyser; + } +} diff --git a/test/jdk/com/sun/net/httpserver/simpleserver/CustomFileSystemTest.java b/test/jdk/com/sun/net/httpserver/simpleserver/CustomFileSystemTest.java new file mode 100644 index 00000000000..0826ca259ae --- /dev/null +++ b/test/jdk/com/sun/net/httpserver/simpleserver/CustomFileSystemTest.java @@ -0,0 +1,970 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 Tests for SimpleFileServer with a root that is not of the default + * file system + * @library /test/lib + * @build jdk.test.lib.Platform jdk.test.lib.net.URIBuilder + * @run testng/othervm CustomFileSystemTest + */ + +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse.BodyHandlers; +import java.nio.channels.SeekableByteChannel; +import java.nio.file.AccessMode; +import java.nio.file.CopyOption; +import java.nio.file.DirectoryStream; +import java.nio.file.FileStore; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.LinkOption; +import java.nio.file.OpenOption; +import java.nio.file.Path; +import java.nio.file.PathMatcher; +import java.nio.file.ProviderMismatchException; +import java.nio.file.WatchEvent; +import java.nio.file.WatchKey; +import java.nio.file.WatchService; +import java.nio.file.attribute.BasicFileAttributes; +import java.nio.file.attribute.FileAttribute; +import java.nio.file.attribute.FileAttributeView; +import java.nio.file.attribute.UserPrincipalLookupService; +import java.nio.file.spi.FileSystemProvider; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.logging.ConsoleHandler; +import java.util.logging.Level; +import java.util.logging.Logger; +import com.sun.net.httpserver.HttpServer; +import com.sun.net.httpserver.SimpleFileServer; +import com.sun.net.httpserver.SimpleFileServer.OutputLevel; +import jdk.test.lib.Platform; +import jdk.test.lib.net.URIBuilder; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import static java.net.http.HttpClient.Builder.NO_PROXY; +import static java.nio.charset.StandardCharsets.UTF_8; +import static java.nio.file.StandardOpenOption.CREATE; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertTrue; + +public class CustomFileSystemTest { + static final InetSocketAddress LOOPBACK_ADDR = new InetSocketAddress(InetAddress.getLoopbackAddress(), 0); + + static final boolean ENABLE_LOGGING = true; + static final Logger LOGGER = Logger.getLogger("com.sun.net.httpserver"); + + @BeforeTest + public void setup() throws Exception { + if (ENABLE_LOGGING) { + ConsoleHandler ch = new ConsoleHandler(); + LOGGER.setLevel(Level.ALL); + ch.setLevel(Level.ALL); + LOGGER.addHandler(ch); + } + } + + @Test + public void testFileGET() throws Exception { + var root = createDirectoryInCustomFs("testFileGET"); + var file = Files.writeString(root.resolve("aFile.txt"), "some text", CREATE); + var lastModified = getLastModified(file); + var expectedLength = Long.toString(Files.size(file)); + + var server = SimpleFileServer.createFileServer(LOOPBACK_ADDR, root, OutputLevel.VERBOSE); + server.start(); + try { + var client = HttpClient.newBuilder().proxy(NO_PROXY).build(); + var request = HttpRequest.newBuilder(uri(server, "aFile.txt")).build(); + var response = client.send(request, BodyHandlers.ofString()); + assertEquals(response.statusCode(), 200); + assertEquals(response.body(), "some text"); + assertEquals(response.headers().firstValue("content-type").get(), "text/plain"); + assertEquals(response.headers().firstValue("content-length").get(), expectedLength); + assertEquals(response.headers().firstValue("last-modified").get(), lastModified); + } finally { + server.stop(0); + } + } + + @Test + public void testDirectoryGET() throws Exception { + var expectedBody = openHTML + """ +

      Directory listing for /

      + + """ + closeHTML; + var expectedLength = Integer.toString(expectedBody.getBytes(UTF_8).length); + var root = createDirectoryInCustomFs("testDirectoryGET"); + var file = Files.writeString(root.resolve("aFile.txt"), "some text", CREATE); + var lastModified = getLastModified(root); + + var server = SimpleFileServer.createFileServer(LOOPBACK_ADDR, root, OutputLevel.VERBOSE); + server.start(); + try { + var client = HttpClient.newBuilder().proxy(NO_PROXY).build(); + var request = HttpRequest.newBuilder(uri(server, "")).build(); + var response = client.send(request, BodyHandlers.ofString()); + assertEquals(response.statusCode(), 200); + assertEquals(response.headers().firstValue("content-type").get(), "text/html; charset=UTF-8"); + assertEquals(response.headers().firstValue("content-length").get(), expectedLength); + assertEquals(response.headers().firstValue("last-modified").get(), lastModified); + assertEquals(response.body(), expectedBody); + } finally { + server.stop(0); + } + } + + @Test + public void testFileHEAD() throws Exception { + var root = createDirectoryInCustomFs("testFileHEAD"); + var file = Files.writeString(root.resolve("aFile.txt"), "some text", CREATE); + var lastModified = getLastModified(file); + var expectedLength = Long.toString(Files.size(file)); + + var server = SimpleFileServer.createFileServer(LOOPBACK_ADDR, root, OutputLevel.VERBOSE); + server.start(); + try { + var client = HttpClient.newBuilder().proxy(NO_PROXY).build(); + var request = HttpRequest.newBuilder(uri(server, "aFile.txt")) + .method("HEAD", HttpRequest.BodyPublishers.noBody()).build(); + var response = client.send(request, BodyHandlers.ofString()); + assertEquals(response.statusCode(), 200); + assertEquals(response.headers().firstValue("content-type").get(), "text/plain"); + assertEquals(response.headers().firstValue("content-length").get(), expectedLength); + assertEquals(response.headers().firstValue("last-modified").get(), lastModified); + assertEquals(response.body(), ""); + } finally { + server.stop(0); + } + } + + @Test + public void testDirectoryHEAD() throws Exception { + var expectedLength = Integer.toString( + (openHTML + """ +

      Directory listing for /

      + + """ + closeHTML).getBytes(UTF_8).length); + var root = createDirectoryInCustomFs("testDirectoryHEAD"); + var file = Files.writeString(root.resolve("aFile.txt"), "some text", CREATE); + var lastModified = getLastModified(root); + + var server = SimpleFileServer.createFileServer(LOOPBACK_ADDR, root, OutputLevel.VERBOSE); + server.start(); + try { + var client = HttpClient.newBuilder().proxy(NO_PROXY).build(); + var request = HttpRequest.newBuilder(uri(server, "")) + .method("HEAD", HttpRequest.BodyPublishers.noBody()).build(); + var response = client.send(request, BodyHandlers.ofString()); + assertEquals(response.statusCode(), 200); + assertEquals(response.headers().firstValue("content-type").get(), "text/html; charset=UTF-8"); + assertEquals(response.headers().firstValue("content-length").get(), expectedLength); + assertEquals(response.headers().firstValue("last-modified").get(), lastModified); + assertEquals(response.body(), ""); + } finally { + server.stop(0); + } + } + + @DataProvider + public Object[][] indexFiles() { + var fileContent = openHTML + """ +

      This is an index file

      + """ + closeHTML; + var dirListing = openHTML + """ +

      Directory listing for /

      +
        +
      + """ + closeHTML; + return new Object[][] { + {"1", "index.html", "text/html", "116", fileContent, true}, + {"2", "index.htm", "text/html", "116", fileContent, true}, + {"3", "index.txt", "text/html; charset=UTF-8", "134", dirListing, false} + }; + } + + @Test(dataProvider = "indexFiles") + public void testDirectoryWithIndexGET(String id, + String filename, + String contentType, + String contentLength, + String expectedBody, + boolean serveIndexFile) throws Exception { + var root = createDirectoryInCustomFs("testDirectoryWithIndexGET"+id); + var lastModified = getLastModified(root); + if (serveIndexFile) { + var file = Files.writeString(root.resolve(filename), expectedBody, CREATE); + lastModified = getLastModified(file); + } + + var server = SimpleFileServer.createFileServer(LOOPBACK_ADDR, root, OutputLevel.VERBOSE); + server.start(); + try { + var client = HttpClient.newBuilder().proxy(NO_PROXY).build(); + var request = HttpRequest.newBuilder(uri(server, "")).build(); + var response = client.send(request, BodyHandlers.ofString()); + assertEquals(response.statusCode(), 200); + assertEquals(response.headers().firstValue("content-type").get(), contentType); + assertEquals(response.headers().firstValue("content-length").get(), contentLength); + assertEquals(response.headers().firstValue("last-modified").get(), lastModified); + assertEquals(response.body(), expectedBody); + } finally { + server.stop(0); + if (serveIndexFile) { + Files.delete(root.resolve(filename)); + } + } + } + + @Test + public void testNotReadableFileGET() throws Exception { + if (!Platform.isWindows()) { // not applicable on Windows + var expectedBody = openHTML + """ +

      File not found

      +

      /aFile.txt

      + """ + closeHTML; + var expectedLength = Integer.toString(expectedBody.getBytes(UTF_8).length); + var root = createDirectoryInCustomFs("testNotReadableFileGET"); + var file = Files.writeString(root.resolve("aFile.txt"), "some text", CREATE); + + file.toFile().setReadable(false, false); + assert !Files.isReadable(file); + + var server = SimpleFileServer.createFileServer(LOOPBACK_ADDR, root, OutputLevel.VERBOSE); + server.start(); + try { + var client = HttpClient.newBuilder().proxy(NO_PROXY).build(); + var request = HttpRequest.newBuilder(uri(server, "aFile.txt")).build(); + var response = client.send(request, BodyHandlers.ofString()); + assertEquals(response.statusCode(), 404); + assertEquals(response.headers().firstValue("content-length").get(), expectedLength); + assertEquals(response.body(), expectedBody); + } finally { + server.stop(0); + file.toFile().setReadable(true, false); + } + } + } + + @Test + public void testNotReadableSegmentGET() throws Exception { + if (!Platform.isWindows()) { // not applicable on Windows + var expectedBody = openHTML + """ +

      File not found

      +

      /dir/aFile.txt

      + """ + closeHTML; + var expectedLength = Integer.toString(expectedBody.getBytes(UTF_8).length); + var root = createDirectoryInCustomFs("testNotReadableSegmentGET"); + var dir = Files.createDirectory(root.resolve("dir")); + var file = Files.writeString(dir.resolve("aFile.txt"), "some text", CREATE); + + dir.toFile().setReadable(false, false); + assert !Files.isReadable(dir); + assert Files.isReadable(file); + + var server = SimpleFileServer.createFileServer(LOOPBACK_ADDR, root, OutputLevel.VERBOSE); + server.start(); + try { + var client = HttpClient.newBuilder().proxy(NO_PROXY).build(); + var request = HttpRequest.newBuilder(uri(server, "dir/aFile.txt")).build(); + var response = client.send(request, BodyHandlers.ofString()); + assertEquals(response.statusCode(), 404); + assertEquals(response.headers().firstValue("content-length").get(), expectedLength); + assertEquals(response.body(), expectedBody); + } finally { + server.stop(0); + dir.toFile().setReadable(true, false); + } + } + } + + @Test + public void testInvalidRequestURIGET() throws Exception { + var expectedBody = openHTML + """ +

      File not found

      +

      /aFile?#.txt

      + """ + closeHTML; + var expectedLength = Integer.toString(expectedBody.getBytes(UTF_8).length); + var root = createDirectoryInCustomFs("testInvalidRequestURIGET"); + + var server = SimpleFileServer.createFileServer(LOOPBACK_ADDR, root, OutputLevel.VERBOSE); + server.start(); + try { + var client = HttpClient.newBuilder().proxy(NO_PROXY).build(); + var request = HttpRequest.newBuilder(uri(server, "aFile?#.txt")).build(); + var response = client.send(request, BodyHandlers.ofString()); + assertEquals(response.statusCode(), 404); + assertEquals(response.headers().firstValue("content-length").get(), expectedLength); + assertEquals(response.body(), expectedBody); + } finally { + server.stop(0); + } + } + + @Test + public void testNotFoundGET() throws Exception { + var expectedBody = openHTML + """ +

      File not found

      +

      /doesNotExist.txt

      + """ + closeHTML; + var expectedLength = Integer.toString(expectedBody.getBytes(UTF_8).length); + var root = createDirectoryInCustomFs("testNotFoundGET"); + + var server = SimpleFileServer.createFileServer(LOOPBACK_ADDR, root, OutputLevel.VERBOSE); + server.start(); + try { + var client = HttpClient.newBuilder().proxy(NO_PROXY).build(); + var request = HttpRequest.newBuilder(uri(server, "doesNotExist.txt")).build(); + var response = client.send(request, BodyHandlers.ofString()); + assertEquals(response.statusCode(), 404); + assertEquals(response.headers().firstValue("content-length").get(), expectedLength); + assertEquals(response.body(), expectedBody); + } finally { + server.stop(0); + } + } + + @Test + public void testNotFoundHEAD() throws Exception { + var expectedBody = openHTML + """ +

      File not found

      +

      /doesNotExist.txt

      + """ + closeHTML; + var expectedLength = Integer.toString(expectedBody.getBytes(UTF_8).length); + var root = createDirectoryInCustomFs("testNotFoundHEAD"); + + var server = SimpleFileServer.createFileServer(LOOPBACK_ADDR, root, OutputLevel.VERBOSE); + server.start(); + try { + var client = HttpClient.newBuilder().proxy(NO_PROXY).build(); + var request = HttpRequest.newBuilder(uri(server, "doesNotExist.txt")) + .method("HEAD", HttpRequest.BodyPublishers.noBody()).build(); + var response = client.send(request, BodyHandlers.ofString()); + assertEquals(response.statusCode(), 404); + assertEquals(response.headers().firstValue("content-length").get(), expectedLength); + assertEquals(response.body(), ""); + } finally { + server.stop(0); + } + } + + @Test + public void testSymlinkGET() throws Exception { + var expectedBody = openHTML + """ +

      File not found

      +

      /symlink

      + """ + closeHTML; + var expectedLength = Integer.toString(expectedBody.getBytes(UTF_8).length); + var root = createDirectoryInCustomFs("testSymlinkGET"); + var symlink = root.resolve("symlink"); + var target = Files.writeString(root.resolve("target.txt"), "some text", CREATE); + Files.createSymbolicLink(symlink, target); + + var server = SimpleFileServer.createFileServer(LOOPBACK_ADDR, root, OutputLevel.VERBOSE); + server.start(); + try { + var client = HttpClient.newBuilder().proxy(NO_PROXY).build(); + var request = HttpRequest.newBuilder(uri(server, "symlink")).build(); + var response = client.send(request, BodyHandlers.ofString()); + assertEquals(response.statusCode(), 404); + assertEquals(response.headers().firstValue("content-length").get(), expectedLength); + assertEquals(response.body(), expectedBody); + } finally { + server.stop(0); + } + } + + @Test + public void testSymlinkSegmentGET() throws Exception { + var expectedBody = openHTML + """ +

      File not found

      +

      /symlink/aFile.txt

      + """ + closeHTML; + var expectedLength = Integer.toString(expectedBody.getBytes(UTF_8).length); + var root = createDirectoryInCustomFs("testSymlinkSegmentGET"); + var symlink = root.resolve("symlink"); + var target = Files.createDirectory(root.resolve("target")); + Files.writeString(target.resolve("aFile.txt"), "some text", CREATE); + Files.createSymbolicLink(symlink, target); + + var server = SimpleFileServer.createFileServer(LOOPBACK_ADDR, root, OutputLevel.VERBOSE); + server.start(); + try { + var client = HttpClient.newBuilder().proxy(NO_PROXY).build(); + var request = HttpRequest.newBuilder(uri(server, "symlink/aFile.txt")).build(); + var response = client.send(request, BodyHandlers.ofString()); + assertEquals(response.statusCode(), 404); + assertEquals(response.headers().firstValue("content-length").get(), expectedLength); + assertEquals(response.body(), expectedBody); + } finally { + server.stop(0); + } + } + + @Test + public void testHiddenFileGET() throws Exception { + var root = createDirectoryInCustomFs("testHiddenFileGET"); + var file = createHiddenFile(root); + var fileName = file.getFileName().toString(); + var expectedBody = openHTML + """ +

      File not found

      +

      /""" + fileName + + """ +

      + """ + closeHTML; + var expectedLength = Integer.toString(expectedBody.getBytes(UTF_8).length); + + var server = SimpleFileServer.createFileServer(LOOPBACK_ADDR, root, OutputLevel.VERBOSE); + server.start(); + try { + var client = HttpClient.newBuilder().proxy(NO_PROXY).build(); + var request = HttpRequest.newBuilder(uri(server, fileName)).build(); + var response = client.send(request, BodyHandlers.ofString()); + assertEquals(response.statusCode(), 404); + assertEquals(response.headers().firstValue("content-length").get(), expectedLength); + assertEquals(response.body(), expectedBody); + } finally { + server.stop(0); + } + } + + @Test + public void testHiddenSegmentGET() throws Exception { + var root = createDirectoryInCustomFs("testHiddenSegmentGET"); + var file = createFileInHiddenDirectory(root); + var expectedBody = openHTML + """ +

      File not found

      +

      /.hiddenDirectory/aFile.txt

      + """ + closeHTML; + var expectedLength = Integer.toString(expectedBody.getBytes(UTF_8).length); + + var server = SimpleFileServer.createFileServer(LOOPBACK_ADDR, root, OutputLevel.VERBOSE); + server.start(); + try { + var client = HttpClient.newBuilder().proxy(NO_PROXY).build(); + var request = HttpRequest.newBuilder(uri(server, ".hiddenDirectory/aFile.txt")).build(); + var response = client.send(request, BodyHandlers.ofString()); + assertEquals(response.statusCode(), 404); + assertEquals(response.headers().firstValue("content-length").get(), expectedLength); + assertEquals(response.body(), expectedBody); + } finally { + server.stop(0); + } + } + + private Path createHiddenFile(Path root) throws IOException { + Path file; + if (Platform.isWindows()) { + file = Files.createFile(root.resolve("aFile.txt")); + Files.setAttribute(file, "dos:hidden", true, LinkOption.NOFOLLOW_LINKS); + } else { + file = Files.writeString(root.resolve(".aFile.txt"), "some text", CREATE); + } + assertTrue(Files.isHidden(file)); + return file; + } + + private Path createFileInHiddenDirectory(Path root) throws IOException { + Path dir; + Path file; + if (Platform.isWindows()) { + dir = Files.createDirectory(root.resolve("hiddenDirectory")); + Files.setAttribute(dir, "dos:hidden", true, LinkOption.NOFOLLOW_LINKS); + } else { + dir = Files.createDirectory(root.resolve(".hiddenDirectory")); + } + file = Files.writeString(dir.resolve("aFile.txt"), "some text", CREATE); + assertTrue(Files.isHidden(dir)); + assertFalse(Files.isHidden(file)); + return file; + } + + @Test + public void testMovedPermanently() throws Exception { + var root = createDirectoryInCustomFs("testMovedPermanently"); + Files.createDirectory(root.resolve("aDirectory")); + var expectedBody = openHTML + """ +

      Directory listing for /aDirectory/

      +
        +
      + """ + closeHTML; + var expectedLength = Integer.toString(expectedBody.getBytes(UTF_8).length); + + var server = SimpleFileServer.createFileServer(LOOPBACK_ADDR, root, OutputLevel.VERBOSE); + server.start(); + try { + { + var client = HttpClient.newBuilder().proxy(NO_PROXY) + .followRedirects(HttpClient.Redirect.NEVER).build(); + var uri = uri(server, "aDirectory"); + var request = HttpRequest.newBuilder(uri).build(); + var response = client.send(request, BodyHandlers.ofString()); + assertEquals(response.statusCode(), 301); + assertEquals(response.headers().firstValue("content-length").get(), "0"); + assertEquals(response.headers().firstValue("location").get(), "/aDirectory/"); + + // tests that query component is preserved during redirect + var uri2 = uri(server, "aDirectory", "query"); + var req2 = HttpRequest.newBuilder(uri2).build(); + var res2 = client.send(req2, BodyHandlers.ofString()); + assertEquals(res2.statusCode(), 301); + assertEquals(res2.headers().firstValue("content-length").get(), "0"); + assertEquals(res2.headers().firstValue("location").get(), "/aDirectory/?query"); + } + + { // tests that redirect to returned relative URI works + var client = HttpClient.newBuilder().proxy(NO_PROXY) + .followRedirects(HttpClient.Redirect.ALWAYS).build(); + var uri = uri(server, "aDirectory"); + var request = HttpRequest.newBuilder(uri).build(); + var response = client.send(request, BodyHandlers.ofString()); + assertEquals(response.statusCode(), 200); + assertEquals(response.body(), expectedBody); + assertEquals(response.headers().firstValue("content-type").get(), "text/html; charset=UTF-8"); + assertEquals(response.headers().firstValue("content-length").get(), expectedLength); + } + } finally { + server.stop(0); + } + } + + @Test + public void testXss() throws Exception { + var root = createDirectoryInCustomFs("testXss"); + + var server = SimpleFileServer.createFileServer(LOOPBACK_ADDR, root, OutputLevel.VERBOSE); + server.start(); + try { + var client = HttpClient.newBuilder().proxy(NO_PROXY).build(); + var request = HttpRequest.newBuilder(uri(server, "beginDelim%3C%3EEndDelim")).build(); + var response = client.send(request, BodyHandlers.ofString()); + assertEquals(response.statusCode(), 404); + assertTrue(response.body().contains("beginDelim%3C%3EEndDelim")); + assertTrue(response.body().contains("File not found")); + } finally { + server.stop(0); + } + } + + static Path createDirectoryInCustomFs(String name) throws Exception { + var defaultFs = FileSystems.getDefault(); + var fs = new CustomProvider(defaultFs.provider()).newFileSystem(defaultFs); + var dir = fs.getPath(name); + if (Files.notExists(dir)) { + Files.createDirectory(dir); + } + return dir.toAbsolutePath(); + } + + static final String openHTML = """ + + + + + + + """; + + static final String closeHTML = """ + + + """; + + static URI uri(HttpServer server, String path) { + return URIBuilder.newBuilder() + .host("localhost") + .port(server.getAddress().getPort()) + .scheme("http") + .path("/" + path) + .buildUnchecked(); + } + + static URI uri(HttpServer server, String path, String query) { + return URIBuilder.newBuilder() + .host("localhost") + .port(server.getAddress().getPort()) + .scheme("http") + .path("/" + path) + .query(query) + .buildUnchecked(); + } + + static String getLastModified(Path path) throws IOException { + return Files.getLastModifiedTime(path).toInstant().atZone(ZoneId.of("GMT")) + .format(DateTimeFormatter.RFC_1123_DATE_TIME); + } + + // --- Custom File System --- + + static class CustomProvider extends FileSystemProvider { + private final ConcurrentHashMap map = + new ConcurrentHashMap<>(); + private final FileSystemProvider defaultProvider; + + public CustomProvider(FileSystemProvider provider) { + defaultProvider = provider; + } + + @Override + public String getScheme() { + return defaultProvider.getScheme(); + } + + public FileSystem newFileSystem(FileSystem fs) { + return map.computeIfAbsent(fs, (sfs) -> + new CustomFileSystem(this, fs)); + } + + @Override + public FileSystem newFileSystem(URI uri, Map env) throws IOException { + FileSystem fs = defaultProvider.newFileSystem(uri, env); + return map.computeIfAbsent(fs, (sfs) -> + new CustomFileSystem(this, fs) + ); + } + + @Override + public FileSystem getFileSystem(URI uri) { + return map.get(defaultProvider.getFileSystem(uri)); + } + + @Override + public Path getPath(URI uri) { + Path p = defaultProvider.getPath(uri); + return map.get(defaultProvider.getFileSystem(uri)).wrap(p); + } + + @Override + public SeekableByteChannel newByteChannel(Path path, Set options, FileAttribute... attrs) throws IOException { + Path p = toCustomPath(path).unwrap(); + return defaultProvider.newByteChannel(p, options, attrs); + } + + @Override + public DirectoryStream newDirectoryStream(Path dir, DirectoryStream.Filter filter) throws IOException { + throw new RuntimeException("not implemented"); + } + + @Override + public void createDirectory(Path dir, FileAttribute... attrs) throws IOException { + Path p = toCustomPath(dir).unwrap(); + defaultProvider.createDirectory(p, attrs); + } + + @Override + public void delete(Path path) throws IOException { + Path p = toCustomPath(path).unwrap(); + defaultProvider.delete(p); + } + + @Override + public void copy(Path source, Path target, CopyOption... options) throws IOException { + Path sp = toCustomPath(source).unwrap(); + Path tp = toCustomPath(target).unwrap(); + defaultProvider.copy(sp, tp, options); + } + + @Override + public void move(Path source, Path target, CopyOption... options) + throws IOException { + Path sp = toCustomPath(source).unwrap(); + Path tp = toCustomPath(target).unwrap(); + defaultProvider.move(sp, tp, options); + } + + @Override + public boolean isSameFile(Path path, Path path2) + throws IOException { + Path p = toCustomPath(path).unwrap(); + Path p2 = toCustomPath(path2).unwrap(); + return defaultProvider.isSameFile(p, p2); + } + + @Override + public boolean isHidden(Path path) throws IOException { + Path p = toCustomPath(path).unwrap(); + return defaultProvider.isHidden(p); + } + + @Override + public FileStore getFileStore(Path path) throws IOException { + Path p = toCustomPath(path).unwrap(); + return defaultProvider.getFileStore(p); + } + + @Override + public void checkAccess(Path path, AccessMode... modes) throws IOException { + Path p = toCustomPath(path).unwrap(); + defaultProvider.checkAccess(p, modes); + } + + @Override + public V getFileAttributeView(Path path, + Class type, + LinkOption... options) { + Path p = toCustomPath(path).unwrap(); + return defaultProvider.getFileAttributeView(p, type, options); + } + + @Override + public A readAttributes(Path path, + Class type, + LinkOption... options) + throws IOException { + Path p = toCustomPath(path).unwrap(); + return defaultProvider.readAttributes(p, type, options); + } + + @Override + public Map readAttributes(Path path, + String attributes, + LinkOption... options) + throws IOException { + Path p = toCustomPath(path).unwrap(); + return defaultProvider.readAttributes(p, attributes, options); + } + + @Override + public void setAttribute(Path path, String attribute, + Object value, LinkOption... options) + throws IOException { + Path p = toCustomPath(path).unwrap(); + defaultProvider.setAttribute(p, attribute, options); + } + + // Checks that the given file is a CustomPath + static CustomPath toCustomPath(Path obj) { + if (obj == null) + throw new NullPointerException(); + if (!(obj instanceof CustomPath cp)) + throw new ProviderMismatchException(); + return cp; + } + } + + static class CustomFileSystem extends FileSystem { + + private final CustomProvider provider; + private final FileSystem delegate; + + public CustomFileSystem(CustomProvider provider, FileSystem delegate) { + this.provider = provider; + this.delegate = delegate; + } + + @Override + public FileSystemProvider provider() { + return provider; + } + + @Override + public void close() throws IOException { delegate.close(); } + + @Override + public boolean isOpen() { + return true; + } + + @Override + public boolean isReadOnly() { + return false; + } + + @Override + public String getSeparator() { return delegate.getSeparator(); } + + @Override + public Iterable getRootDirectories() { + return null; + } + + @Override + public Iterable getFileStores() { + return null; + } + + @Override + public Set supportedFileAttributeViews() { + return null; + } + + @Override + public Path getPath(String first, String... more) { + return delegate.getPath(first, more); + } + + @Override + public PathMatcher getPathMatcher(String syntaxAndPattern) { + return null; + } + + @Override + public UserPrincipalLookupService getUserPrincipalLookupService() { + return null; + } + + @Override + public WatchService newWatchService() throws IOException { + return null; + } + + @Override + public String toString() { + return delegate.toString(); + } + + Path wrap(Path path) { + return (path != null) ? new CustomPath(this, path) : null; + } + + Path unwrap(Path wrapper) { + if (wrapper == null) + throw new NullPointerException(); + if (!(wrapper instanceof CustomPath cp)) + throw new ProviderMismatchException(); + return cp.unwrap(); + } + } + + static class CustomPath implements Path { + + private final CustomFileSystem fs; + private final Path delegate; + + CustomPath(CustomFileSystem fs, Path delegate) { + this.fs = fs; + this.delegate = delegate; + } + + @Override + public FileSystem getFileSystem() { + return fs; + } + + @Override + public boolean isAbsolute() { + return delegate.isAbsolute(); + } + + @Override + public Path getRoot() { + return fs.wrap(delegate.getRoot()); + } + + @Override + public Path getFileName() { + return null; + } + + @Override + public Path getParent() { + return null; + } + + @Override + public int getNameCount() { + return 0; + } + + @Override + public Path getName(int index) { + return null; + } + + @Override + public Path subpath(int beginIndex, int endIndex) { + return null; + } + + @Override + public boolean startsWith(Path other) { + return delegate.startsWith(other); + } + + @Override + public boolean endsWith(Path other) { + return false; + } + + @Override + public Path normalize() { + return fs.wrap(delegate.normalize()); + } + + @Override + public Path resolve(Path other) { + return fs.wrap(delegate.resolve(fs.unwrap(other))); + } + + @Override + public Path relativize(Path other) { + return null; + } + + @Override + public URI toUri() { + return delegate.toUri(); + } + + @Override + public Path toAbsolutePath() { + return fs.wrap(delegate.toAbsolutePath()); + } + + @Override + public Path toRealPath(LinkOption... options) throws IOException { + return null; + } + + @Override + public WatchKey register(WatchService watcher, WatchEvent.Kind[] events, WatchEvent.Modifier... modifiers) throws IOException { + return null; + } + + @Override + public int compareTo(Path other) { + return 0; + } + + Path unwrap() { + return delegate; + } + } +} diff --git a/test/jdk/com/sun/net/httpserver/simpleserver/FileServerHandlerTest.java b/test/jdk/com/sun/net/httpserver/simpleserver/FileServerHandlerTest.java new file mode 100644 index 00000000000..a5179b03f16 --- /dev/null +++ b/test/jdk/com/sun/net/httpserver/simpleserver/FileServerHandlerTest.java @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 Tests for FileServerHandler + * @run testng FileServerHandlerTest + */ + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetSocketAddress; +import java.net.URI; +import java.nio.file.Path; +import java.util.List; +import java.util.Map; +import com.sun.net.httpserver.Authenticator; +import com.sun.net.httpserver.Filter; +import com.sun.net.httpserver.Headers; +import com.sun.net.httpserver.HttpContext; +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import com.sun.net.httpserver.HttpPrincipal; +import com.sun.net.httpserver.HttpServer; +import com.sun.net.httpserver.SimpleFileServer; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import static org.testng.Assert.*; + +public class FileServerHandlerTest { + + static final Path CWD = Path.of(".").toAbsolutePath(); + static final Class RE = RuntimeException.class; + + @DataProvider + public Object[][] notAllowedMethods() { + var l = List.of("POST", "PUT", "DELETE", "TRACE", "OPTIONS"); + return l.stream().map(s -> new Object[] { s }).toArray(Object[][]::new); + } + + @Test(dataProvider = "notAllowedMethods") + public void testNotAllowedRequestMethod(String requestMethod) throws Exception { + var handler = SimpleFileServer.createFileHandler(CWD); + var exchange = new MethodHttpExchange(requestMethod); + handler.handle(exchange); + assertEquals(exchange.rCode, 405); + assertEquals(exchange.getResponseHeaders().getFirst("allow"), "HEAD, GET"); + } + + @DataProvider + public Object[][] notImplementedMethods() { + var l = List.of("GARBAGE", "RUBBISH", "TRASH", "FOO", "BAR"); + return l.stream().map(s -> new Object[] { s }).toArray(Object[][]::new); + } + + @Test(dataProvider = "notImplementedMethods") + public void testNotImplementedRequestMethod(String requestMethod) throws Exception { + var handler = SimpleFileServer.createFileHandler(CWD); + var exchange = new MethodHttpExchange(requestMethod); + handler.handle(exchange); + assertEquals(exchange.rCode, 501); + } + + // 301 and 404 response codes tested in SimpleFileServerTest + + @Test + public void testThrowingExchange() { + var h = SimpleFileServer.createFileHandler(CWD); + { + var exchange = new ThrowingHttpExchange("GET") { + public InputStream getRequestBody() { + throw new RuntimeException("getRequestBody"); + } + }; + var t = expectThrows(RE, () -> h.handle(exchange)); + assertEquals(t.getMessage(), "getRequestBody"); + } + { + var exchange = new ThrowingHttpExchange("GET") { + public Headers getResponseHeaders() { + throw new RuntimeException("getResponseHeaders"); + } + }; + var t = expectThrows(RE, () -> h.handle(exchange)); + assertEquals(t.getMessage(), "getResponseHeaders"); + } + { + var exchange = new ThrowingHttpExchange("GET") { + public void sendResponseHeaders(int rCode, long responseLength) { + throw new RuntimeException("sendResponseHeaders"); + } + }; + var t = expectThrows(RE, () -> h.handle(exchange)); + assertEquals(t.getMessage(), "sendResponseHeaders"); + } + { + var exchange = new ThrowingHttpExchange("GET") { + public OutputStream getResponseBody() { + throw new RuntimeException("getResponseBody"); + } + }; + var t = expectThrows(RE, () -> h.handle(exchange)); + assertEquals(t.getMessage(), "getResponseBody"); + } + { + var exchange = new ThrowingHttpExchange("GET") { + public void close() { + throw new RuntimeException("close"); + } + }; + var t = expectThrows(RE, () -> h.handle(exchange)); + assertEquals(t.getMessage(), "close"); + } + } + + static class ThrowingHttpExchange extends StubHttpExchange { + private final String method; + volatile int rCode; + volatile long responseLength; + volatile Headers responseHeaders; + volatile Headers requestHeaders; + volatile InputStream requestBody; + + ThrowingHttpExchange(String method) { + this.method = method; + responseHeaders = new Headers(); + requestHeaders = new Headers(); + requestBody = new ByteArrayInputStream(new byte[]{}); + } + + @Override public String getRequestMethod() { return method; } + @Override public Headers getResponseHeaders() { return responseHeaders; } + @Override public Headers getRequestHeaders() { return requestHeaders; } + @Override public InputStream getRequestBody() { return requestBody; } + @Override public URI getRequestURI() { return URI.create("/"); } + @Override public OutputStream getResponseBody() { + return OutputStream.nullOutputStream(); + } + @Override public void sendResponseHeaders(int rCode, long responseLength) { + this.rCode = rCode; + this.responseLength = responseLength; + } + @Override public HttpContext getHttpContext() { + return new HttpContext() { + @Override public HttpHandler getHandler() { return null; } + @Override public void setHandler(HttpHandler handler) { } + @Override public String getPath() { + return "/"; + } + @Override public HttpServer getServer() { + return null; + } + @Override public Map getAttributes() { + return null; + } + @Override public List getFilters() { + return null; + } + @Override public Authenticator setAuthenticator(Authenticator auth) { + return null; + } + @Override public Authenticator getAuthenticator() { + return null; + } + }; + } + } + + static class MethodHttpExchange extends StubHttpExchange { + private final String method; + volatile int rCode; + volatile long responseLength; + volatile Headers responseHeaders; + volatile InputStream requestBody; + + MethodHttpExchange(String method) { + this.method = method; + responseHeaders = new Headers(); + requestBody = InputStream.nullInputStream(); + } + + @Override public String getRequestMethod() { return method; } + @Override public Headers getResponseHeaders() { return responseHeaders; } + @Override public InputStream getRequestBody() { return requestBody; } + @Override public void sendResponseHeaders(int rCode, long responseLength) { + this.rCode = rCode; + this.responseLength = responseLength; + } + } + + static class StubHttpExchange extends HttpExchange { + @Override public Headers getRequestHeaders() { return null; } + @Override public Headers getResponseHeaders() { return null; } + @Override public URI getRequestURI() { return null; } + @Override public String getRequestMethod() { return null; } + @Override public void close() { } + @Override public InputStream getRequestBody() { return null; } + @Override public OutputStream getResponseBody() { return null; } + @Override public HttpContext getHttpContext() { return null; } + @Override public void sendResponseHeaders(int rCode, long responseLength) { } + @Override public InetSocketAddress getRemoteAddress() { return null; } + @Override public int getResponseCode() { return 0; } + @Override public InetSocketAddress getLocalAddress() { return null; } + @Override public String getProtocol() { return null; } + @Override public Object getAttribute(String name) { return null; } + @Override public void setAttribute(String name, Object value) { } + @Override public void setStreams(InputStream i, OutputStream o) { } + @Override public HttpPrincipal getPrincipal() { return null; } + } +} diff --git a/test/jdk/com/sun/net/httpserver/simpleserver/HttpHandlersTest.java b/test/jdk/com/sun/net/httpserver/simpleserver/HttpHandlersTest.java new file mode 100644 index 00000000000..85d271e44fa --- /dev/null +++ b/test/jdk/com/sun/net/httpserver/simpleserver/HttpHandlersTest.java @@ -0,0 +1,362 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 Tests for HttpHandlers + * @library /test/lib + * @build jdk.test.lib.net.URIBuilder + * @run testng/othervm HttpHandlersTest + */ + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpRequest.BodyPublishers; +import java.net.http.HttpResponse.BodyHandlers; +import java.util.logging.ConsoleHandler; +import java.util.logging.Level; +import java.util.logging.Logger; +import jdk.test.lib.net.URIBuilder; +import com.sun.net.httpserver.*; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import static java.net.http.HttpClient.Builder.NO_PROXY; +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.testng.Assert.*; + +public class HttpHandlersTest { + + static final Class NPE = NullPointerException.class; + static final Class IAE = IllegalArgumentException.class; + static final Class RE = RuntimeException.class; + static final InetSocketAddress LOOPBACK_ADDR = new InetSocketAddress(InetAddress.getLoopbackAddress(), 0); + + static final boolean ENABLE_LOGGING = true; + static final Logger LOGGER = Logger.getLogger("com.sun.net.httpserver"); + + @BeforeTest + public void setup() { + if (ENABLE_LOGGING) { + ConsoleHandler ch = new ConsoleHandler(); + LOGGER.setLevel(Level.ALL); + ch.setLevel(Level.ALL); + LOGGER.addHandler(ch); + } + } + + @Test + public void testNull() { + final var handler = new TestHandler(); + assertThrows(NPE, () -> HttpHandlers.handleOrElse(null, handler, new TestHandler())); + assertThrows(NPE, () -> HttpHandlers.handleOrElse(p -> true, null, handler)); + assertThrows(NPE, () -> HttpHandlers.handleOrElse(p -> true, handler, null)); + + final var headers = new Headers(); + final var body = ""; + assertThrows(NPE, () -> HttpHandlers.of(200, null, body)); + assertThrows(NPE, () -> HttpHandlers.of(200, headers, null)); + } + + @Test + public void testOfStatusCode() { + final var headers = new Headers(); + final var body = ""; + assertThrows(IAE, () -> HttpHandlers.of(99, headers, body)); + assertThrows(IAE, () -> HttpHandlers.of(1000, headers, body)); + } + + @Test + public void testOfNoBody() throws Exception { + var handler = HttpHandlers.of(200, Headers.of("foo", "bar"), ""); + var server = HttpServer.create(LOOPBACK_ADDR, 0); + server.createContext("/", handler); + server.start(); + try { + var client = HttpClient.newBuilder().proxy(NO_PROXY).build(); + var request = HttpRequest.newBuilder(uri(server, "")).build(); + var response = client.send(request, BodyHandlers.ofString()); + assertTrue(response.headers().map().containsKey("date")); + assertEquals(response.headers().firstValue("foo").get(), "bar"); + assertEquals(response.headers().firstValue("content-length").get(), "0"); + assertEquals(response.headers().map().size(), 3); + assertEquals(response.statusCode(), 200); + assertEquals(response.body(), ""); + } finally { + server.stop(0); + } + } + + @Test + public void testOfWithBody() throws Exception { + var handler = HttpHandlers.of(200, Headers.of("foo", "bar"), "hello world"); + var expectedLength = Integer.toString("hello world".getBytes(UTF_8).length); + var server = HttpServer.create(LOOPBACK_ADDR, 0); + server.createContext("/", handler); + server.start(); + try { + var client = HttpClient.newBuilder().proxy(NO_PROXY).build(); + var request = HttpRequest.newBuilder(uri(server, "")).build(); + var response = client.send(request, BodyHandlers.ofString()); + assertTrue(response.headers().map().containsKey("date")); + assertEquals(response.headers().firstValue("foo").get(), "bar"); + assertEquals(response.headers().firstValue("content-length").get(), expectedLength); + assertEquals(response.headers().map().size(), 3); + assertEquals(response.statusCode(), 200); + assertEquals(response.body(), "hello world"); + } finally { + server.stop(0); + } + } + + @Test + public void testOfHeadRequest() throws Exception { + var handler = HttpHandlers.of(200, Headers.of("content-length", "999"), "hello world"); + var expectedLength = Integer.toString("hello world".getBytes(UTF_8).length); + var server = HttpServer.create(LOOPBACK_ADDR, 0); + server.createContext("/", handler); + server.start(); + try { + var client = HttpClient.newBuilder().proxy(NO_PROXY).build(); + var request = HttpRequest.newBuilder(uri(server, "")) + .method("HEAD", BodyPublishers.noBody()).build(); + var response = client.send(request, BodyHandlers.ofString()); + assertTrue(response.headers().map().containsKey("date")); + assertEquals(response.headers().firstValue("content-length").get(), expectedLength); + assertEquals(response.headers().map().size(), 2); + assertEquals(response.statusCode(), 200); + } finally { + server.stop(0); + } + } + + @Test + public void testOfOverwriteHeaders() throws Exception { + var headers = Headers.of("content-length", "1000", "date", "12345"); + var handler = HttpHandlers.of(200, headers, "hello world"); + var expectedLength = Integer.toString("hello world".getBytes(UTF_8).length); + var server = HttpServer.create(LOOPBACK_ADDR, 0); + server.createContext("/", handler); + server.start(); + try { + var client = HttpClient.newBuilder().proxy(NO_PROXY).build(); + var request = HttpRequest.newBuilder(uri(server, "")).build(); + var response = client.send(request, BodyHandlers.ofString()); + assertNotEquals(response.headers().firstValue("date").get(), "12345"); + assertEquals(response.headers().firstValue("content-length").get(), expectedLength); + assertEquals(response.headers().map().size(), 2); + assertEquals(response.statusCode(), 200); + assertEquals(response.body(), "hello world"); + } finally { + server.stop(0); + } + } + + @DataProvider + public Object[][] responseBodies() { + return new Object[][] { {"hello world"}, {""} }; + } + + @Test(dataProvider = "responseBodies") + public void testOfThrowingExchange(String body) { + var h = HttpHandlers.of(200, Headers.of(), body); + { + var exchange = new ThrowingHttpExchange() { + public InputStream getRequestBody() { + throw new RuntimeException("getRequestBody"); + } + }; + var t = expectThrows(RE, () -> h.handle(exchange)); + assertEquals(t.getMessage(), "getRequestBody"); + } + { + var exchange = new ThrowingHttpExchange() { + public Headers getResponseHeaders() { + throw new RuntimeException("getResponseHeaders"); + } + }; + var t = expectThrows(RE, () -> h.handle(exchange)); + assertEquals(t.getMessage(), "getResponseHeaders"); + } + { + var exchange = new ThrowingHttpExchange() { + public void sendResponseHeaders(int rCode, long responseLength) { + throw new RuntimeException("sendResponseHeaders"); + } + }; + var t = expectThrows(RE, () -> h.handle(exchange)); + assertEquals(t.getMessage(), "sendResponseHeaders"); + } + { + var exchange = new ThrowingHttpExchange() { + public OutputStream getResponseBody() { + throw new RuntimeException("getResponseBody"); + } + }; + if (!body.isEmpty()) { // getResponseBody not called if no responseBody + var t = expectThrows(RE, () -> h.handle(exchange)); + assertEquals(t.getMessage(), "getResponseBody"); + } + } + { + var exchange = new ThrowingHttpExchange() { + public void close() { + throw new RuntimeException("close"); + } + }; + var t = expectThrows(RE, () -> h.handle(exchange)); + assertEquals(t.getMessage(), "close"); + } + } + + @Test + public void testHandleOrElseTrue() throws Exception { + var h1 = new TestHandler("TestHandler-1"); + var h2 = new TestHandler("TestHandler-2"); + var handler = HttpHandlers.handleOrElse(p -> true, h1, h2); + var server = HttpServer.create(LOOPBACK_ADDR, 0); + server.createContext("/", handler); + server.start(); + try { + var client = HttpClient.newBuilder().proxy(NO_PROXY).build(); + var request = HttpRequest.newBuilder(uri(server, "")).build(); + var response = client.send(request, BodyHandlers.ofString()); + assertEquals(response.statusCode(), 200); + assertEquals(response.body(), "TestHandler-1"); + } finally { + server.stop(0); + } + } + + @Test + public void testHandleOrElseFalse() throws Exception { + var h1 = new TestHandler("TestHandler-1"); + var h2 = new TestHandler("TestHandler-2"); + var handler = HttpHandlers.handleOrElse(p -> false, h1, h2); + var server = HttpServer.create(LOOPBACK_ADDR, 0); + server.createContext("/", handler); + server.start(); + try { + var client = HttpClient.newBuilder().proxy(NO_PROXY).build(); + var request = HttpRequest.newBuilder(uri(server, "")).build(); + var response = client.send(request, BodyHandlers.ofString()); + assertEquals(response.statusCode(), 200); + assertEquals(response.body(), "TestHandler-2"); + } finally { + server.stop(0); + } + } + + @Test + public void testHandleOrElseNested() throws Exception { + var h1 = new TestHandler("TestHandler-1"); + var h2 = new TestHandler("TestHandler-2"); + var h3 = new TestHandler("TestHandler-3"); + var h4 = HttpHandlers.handleOrElse(p -> false, h1, h2); + var handler = HttpHandlers.handleOrElse(p -> false, h3, h4); + var server = HttpServer.create(LOOPBACK_ADDR, 0); + server.createContext("/", handler); + server.start(); + try { + var client = HttpClient.newBuilder().proxy(NO_PROXY).build(); + var request = HttpRequest.newBuilder(uri(server, "")).build(); + var response = client.send(request, BodyHandlers.ofString()); + assertEquals(response.statusCode(), 200); + assertEquals(response.body(), "TestHandler-2"); + } finally { + server.stop(0); + } + } + + /** + * A test handler that discards the request and returns its name + */ + static class TestHandler implements HttpHandler { + final String name; + TestHandler(String name) { this.name = name; } + TestHandler() { this("no name"); } + + @Override + public void handle(HttpExchange exchange) throws IOException { + try (InputStream is = exchange.getRequestBody(); + OutputStream os = exchange.getResponseBody()) { + is.readAllBytes(); + var resp = name.getBytes(UTF_8); + exchange.sendResponseHeaders(200, resp.length); + os.write(resp); + } + } + } + + static URI uri(HttpServer server, String path) { + return URIBuilder.newBuilder() + .host("localhost") + .port(server.getAddress().getPort()) + .scheme("http") + .path("/" + path) + .buildUnchecked(); + } + + static class ThrowingHttpExchange extends HttpExchange { + static final String requestMethod = "GET"; + volatile int responseCode; + volatile long responseLength; + volatile Headers responseHeaders; + volatile InputStream requestBody; + + ThrowingHttpExchange() { + responseHeaders = new Headers(); + this.requestBody = InputStream.nullInputStream(); + } + + @Override public Headers getResponseHeaders() { return responseHeaders; } + @Override public InputStream getRequestBody() { return requestBody; } + @Override public void sendResponseHeaders(int rCode, long responseLength) { + this.responseCode = rCode; + this.responseLength = responseLength; + } + @Override public OutputStream getResponseBody() { + return OutputStream.nullOutputStream(); + } + @Override public String getRequestMethod() { return requestMethod; } + + @Override public Headers getRequestHeaders() { return null; } + @Override public URI getRequestURI() { return null; } + @Override public HttpContext getHttpContext() { return null; } + @Override public void close() { } + @Override public InetSocketAddress getRemoteAddress() { return null; } + @Override public int getResponseCode() { return 0; } + @Override public InetSocketAddress getLocalAddress() { return null; } + @Override public String getProtocol() { return null; } + @Override public Object getAttribute(String name) { return null; } + @Override public void setAttribute(String name, Object value) { } + @Override public void setStreams(InputStream i, OutputStream o) { } + @Override public HttpPrincipal getPrincipal() { return null; } + } +} diff --git a/test/jdk/com/sun/net/httpserver/simpleserver/HttpsServerTest.java b/test/jdk/com/sun/net/httpserver/simpleserver/HttpsServerTest.java new file mode 100644 index 00000000000..2227c4cd437 --- /dev/null +++ b/test/jdk/com/sun/net/httpserver/simpleserver/HttpsServerTest.java @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Test for HttpsServer::create + * @library /test/lib + * @build jdk.test.lib.Platform jdk.test.lib.net.URIBuilder + * @run testng/othervm HttpsServerTest + */ + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse.BodyHandlers; +import java.nio.charset.StandardCharsets; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.logging.ConsoleHandler; +import java.util.logging.Level; +import java.util.logging.Logger; +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import com.sun.net.httpserver.HttpServer; +import com.sun.net.httpserver.HttpsConfigurator; +import com.sun.net.httpserver.HttpsServer; +import javax.net.ssl.SSLContext; +import jdk.test.lib.net.SimpleSSLContext; +import jdk.test.lib.net.URIBuilder; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; +import static java.net.http.HttpClient.Builder.NO_PROXY; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertThrows; + +public class HttpsServerTest { + + static final Class NPE = NullPointerException.class; + static final InetSocketAddress LOOPBACK_ADDR = new InetSocketAddress(InetAddress.getLoopbackAddress(), 0); + + static final boolean ENABLE_LOGGING = true; + static final Logger LOGGER = Logger.getLogger("com.sun.net.httpserver"); + + SSLContext sslContext; + + @BeforeTest + public void setup() throws IOException { + if (ENABLE_LOGGING) { + ConsoleHandler ch = new ConsoleHandler(); + LOGGER.setLevel(Level.ALL); + ch.setLevel(Level.ALL); + LOGGER.addHandler(ch); + } + sslContext = new SimpleSSLContext().get(); + SSLContext.setDefault(sslContext); + } + + @Test + public void testNull() { + assertThrows(NPE, () -> HttpsServer.create(null, 0, null, new Handler())); + assertThrows(NPE, () -> HttpsServer.create(null, 0, "/", null)); + assertThrows(NPE, () -> HttpsServer.create(null, 0, "/", new Handler(), (Filter)null)); + assertThrows(NPE, () -> HttpsServer.create(null, 0, "/", new Handler(), new Filter[]{null})); + } + + @Test + public void testCreate() throws IOException { + assertNull(HttpsServer.create().getAddress()); + + final var s1 = HttpsServer.create(null, 0); + assertNull(s1.getAddress()); + s1.bind((LOOPBACK_ADDR), 0); + assertEquals(s1.getAddress().getAddress(), LOOPBACK_ADDR.getAddress()); + + final var s2 = HttpsServer.create(null, 0, "/foo/", new Handler()); + assertNull(s2.getAddress()); + s2.bind(LOOPBACK_ADDR, 0); + assertEquals(s2.getAddress().getAddress(), LOOPBACK_ADDR.getAddress()); + s2.removeContext("/foo/"); // throws if context doesn't exist + } + + @Test + public void testExchange() throws Exception { + var filter = new Filter(); + var server = HttpsServer.create(LOOPBACK_ADDR, 0, "/test", new Handler(), filter); + server.setHttpsConfigurator(new HttpsConfigurator(sslContext)); + server.start(); + try { + var client = HttpClient.newBuilder() + .proxy(NO_PROXY) + .sslContext(sslContext) + .build(); + var request = HttpRequest.newBuilder(uri(server, "/test")).build(); + var response = client.send(request, BodyHandlers.ofString()); + assertEquals(response.statusCode(), 200); + assertEquals(response.body(), "hello world"); + assertEquals(response.headers().firstValue("content-length").get(), + Integer.toString("hello world".length())); + assertEquals(response.statusCode(), filter.responseCode.get().intValue()); + } finally { + server.stop(0); + } + } + + static URI uri(HttpServer server, String path) { + return URIBuilder.newBuilder() + .scheme("https") + .host("localhost") + .port(server.getAddress().getPort()) + .path(path) + .buildUnchecked(); + } + + /** + * A test handler that discards the request and sends a response + */ + static class Handler implements HttpHandler { + @Override + public void handle(HttpExchange exchange) throws IOException { + try (InputStream is = exchange.getRequestBody(); + OutputStream os = exchange.getResponseBody()) { + is.readAllBytes(); + var resp = "hello world".getBytes(StandardCharsets.UTF_8); + exchange.sendResponseHeaders(200, resp.length); + os.write(resp); + } + } + } + + /** + * A test post-processing filter that captures the response code + */ + static class Filter extends com.sun.net.httpserver.Filter { + final CompletableFuture responseCode = new CompletableFuture<>(); + + @Override + public void doFilter(HttpExchange exchange, Chain chain) throws IOException { + chain.doFilter(exchange); + responseCode.complete(exchange.getResponseCode()); + } + + @Override + public String description() { + return "HttpsServerTest Filter"; + } + } +} diff --git a/test/jdk/com/sun/net/httpserver/simpleserver/IdempotencyAndCommutativityTest.java b/test/jdk/com/sun/net/httpserver/simpleserver/IdempotencyAndCommutativityTest.java new file mode 100644 index 00000000000..d98944077dc --- /dev/null +++ b/test/jdk/com/sun/net/httpserver/simpleserver/IdempotencyAndCommutativityTest.java @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.*; +import java.util.logging.ConsoleHandler; +import java.util.logging.Level; +import java.util.logging.Logger; +import jdk.test.lib.net.URIBuilder; +import com.sun.net.httpserver.HttpServer; +import com.sun.net.httpserver.SimpleFileServer; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import static java.net.http.HttpClient.Builder.NO_PROXY; +import static java.nio.file.StandardOpenOption.CREATE; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + +/* + * @test + * @summary Test idempotency and commutativity of responses with an exhaustive + * set of binary request sequences + * @library /test/lib + * @build jdk.test.lib.net.URIBuilder + * @run testng/othervm IdempotencyAndCommutativityTest + */ +public class IdempotencyAndCommutativityTest { + + static final Path CWD = Path.of(".").toAbsolutePath().normalize(); + static final InetSocketAddress LOOPBACK_ADDR = new InetSocketAddress(InetAddress.getLoopbackAddress(), 0); + + static final String FILE_NAME = "file.txt"; + static final String DIR_NAME = ""; + static final String MISSING_FILE_NAME = "doesNotExist"; + + static HttpServer server; + static HttpClient client; + + static final boolean ENABLE_LOGGING = true; + static final Logger LOGGER = Logger.getLogger("com.sun.net.httpserver"); + + @BeforeTest + public void setup() throws IOException { + if (ENABLE_LOGGING) { + ConsoleHandler ch = new ConsoleHandler(); + LOGGER.setLevel(Level.ALL); + ch.setLevel(Level.ALL); + LOGGER.addHandler(ch); + } + Path root = Files.createDirectories(CWD.resolve("testDirectory")); + Files.writeString(root.resolve(FILE_NAME), "some text", CREATE); + + client = HttpClient.newBuilder().proxy(NO_PROXY).build(); + server = SimpleFileServer.createFileServer(LOOPBACK_ADDR, root, SimpleFileServer.OutputLevel.VERBOSE); + server.start(); + } + + // Container of expected response state for a given request + record ExchangeValues(String method, String resource, int respCode, String contentType) {} + + // Creates an exhaustive set of binary exchange sequences + @DataProvider + public Object[][] allBinarySequences() { + final List sequences = List.of( + new ExchangeValues("GET", FILE_NAME, 200, "text/plain"), + new ExchangeValues("GET", DIR_NAME, 200, "text/html; charset=UTF-8"), + new ExchangeValues("GET", MISSING_FILE_NAME, 404, "text/html; charset=UTF-8"), + new ExchangeValues("HEAD", FILE_NAME, 200, "text/plain"), + new ExchangeValues("HEAD", DIR_NAME, 200, "text/html; charset=UTF-8"), + new ExchangeValues("HEAD", MISSING_FILE_NAME, 404, "text/html; charset=UTF-8"), + new ExchangeValues("UNKNOWN", FILE_NAME, 501, null), + new ExchangeValues("UNKNOWN", DIR_NAME, 501, null), + new ExchangeValues("UNKNOWN", MISSING_FILE_NAME, 501, null) + ); + + return sequences.stream() // cartesian product + .flatMap(s1 -> sequences.stream().map(s2 -> new ExchangeValues[] { s1, s2 })) + .toArray(Object[][]::new); + } + + @Test(dataProvider = "allBinarySequences") + public void testBinarySequences(ExchangeValues e1, ExchangeValues e2) throws Exception { + System.out.println("---"); + System.out.println(e1); + executeExchange(e1); + System.out.println(e2); + executeExchange(e2); + } + + private static void executeExchange(ExchangeValues e) throws Exception { + var request = HttpRequest.newBuilder(uri(server, e.resource())) + .method(e.method(), HttpRequest.BodyPublishers.noBody()) + .build(); + var response = client.send(request, HttpResponse.BodyHandlers.ofString()); + assertEquals(response.statusCode(), e.respCode()); + if (e.contentType != null) { + assertEquals(response.headers().firstValue("content-type").get(), e.contentType()); + } else { + assertTrue(response.headers().firstValue("content-type").isEmpty()); + } + } + + @AfterTest + public static void teardown() { + server.stop(0); + } + + static URI uri(HttpServer server, String path) { + return URIBuilder.newBuilder() + .host("localhost") + .port(server.getAddress().getPort()) + .scheme("http") + .path("/" + path) + .buildUnchecked(); + } +} diff --git a/test/jdk/com/sun/net/httpserver/simpleserver/MapToPathTest.java b/test/jdk/com/sun/net/httpserver/simpleserver/MapToPathTest.java new file mode 100644 index 00000000000..d6e61da4073 --- /dev/null +++ b/test/jdk/com/sun/net/httpserver/simpleserver/MapToPathTest.java @@ -0,0 +1,359 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 Tests the FileServerHandler's mapping of request URI path to file + * system path + * @library /test/lib + * @build jdk.test.lib.Platform jdk.test.lib.net.URIBuilder + * @run testng/othervm MapToPathTest + */ + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse.BodyHandlers; +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.List; +import java.util.logging.ConsoleHandler; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.stream.Stream; +import com.sun.net.httpserver.Filter; +import com.sun.net.httpserver.Headers; +import com.sun.net.httpserver.HttpHandlers; +import com.sun.net.httpserver.HttpServer; +import com.sun.net.httpserver.SimpleFileServer; +import com.sun.net.httpserver.SimpleFileServer.OutputLevel; +import jdk.test.lib.net.URIBuilder; +import jdk.test.lib.util.FileUtils; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; +import static java.lang.System.out; +import static java.net.http.HttpClient.Builder.NO_PROXY; +import static java.nio.file.StandardOpenOption.CREATE; +import static org.testng.Assert.assertEquals; + +public class MapToPathTest { + + static final Path CWD = Path.of(".").toAbsolutePath(); + static final Path TEST_DIR = CWD.resolve("MapToPathTest").normalize(); + + static final InetSocketAddress LOOPBACK_ADDR = new InetSocketAddress(InetAddress.getLoopbackAddress(), 0); + static final Filter OUTPUT_FILTER = SimpleFileServer.createOutputFilter(out, OutputLevel.VERBOSE); + + static final boolean ENABLE_LOGGING = true; + static final Logger LOGGER = Logger.getLogger("com.sun.net.httpserver"); + + @BeforeTest + public void setup() throws IOException { + if (ENABLE_LOGGING) { + ConsoleHandler ch = new ConsoleHandler(); + LOGGER.setLevel(Level.ALL); + ch.setLevel(Level.ALL); + LOGGER.addHandler(ch); + } + if (Files.exists(TEST_DIR)) { + FileUtils.deleteFileTreeWithRetry(TEST_DIR); + } + createDirectories(TEST_DIR); + } + + private void createDirectories(Path testDir) throws IOException { + // Create directory tree: + // + // |-- TEST_DIR + // |-- foo + // |-- bar + // |-- baz + // |-- file.txt + // |-- file.txt + // |-- foobar + // |-- file.txt + // |-- file.txt + + Files.createDirectories(TEST_DIR); + Stream.of("foo", "foobar", "foo/bar/baz").forEach(s -> { + try { + Path p = testDir.resolve(s); + Files.createDirectories(p); + Files.writeString(p.resolve("file.txt"), s, CREATE); + } catch (IOException ioe) { + throw new UncheckedIOException(ioe); + } + }); + Files.writeString(testDir.resolve("file.txt"), "testdir", CREATE); + } + + @Test + public void test() throws Exception { + var client = HttpClient.newBuilder().proxy(NO_PROXY).build(); + { + var handler = SimpleFileServer.createFileHandler(TEST_DIR); + var server = HttpServer.create(LOOPBACK_ADDR, 10, "/", handler, OUTPUT_FILTER); + server.start(); + try { + var req1 = HttpRequest.newBuilder(uri(server, "/")).build(); + var res1 = client.send(req1, BodyHandlers.ofString()); + assertEquals(res1.statusCode(), 200); + assertEquals(res1.headers().firstValue("content-type").get(), "text/html; charset=UTF-8"); + assertEquals(res1.headers().firstValue("content-length").get(), Long.toString(257L)); + assertEquals(res1.headers().firstValue("last-modified").get(), getLastModified(TEST_DIR)); + + var req2 = HttpRequest.newBuilder(uri(server, "/../")).build(); + var res2 = client.send(req2, BodyHandlers.ofString()); + assertEquals(res2.statusCode(), 404); // cannot escape root + + var req3 = HttpRequest.newBuilder(uri(server, "/foo/bar/baz/c://")).build(); + var res3 = client.send(req3, BodyHandlers.ofString()); + assertEquals(res3.statusCode(), 404); // not found + + var req4 = HttpRequest.newBuilder(uri(server, "/foo/file:" + TEST_DIR.getParent())).build(); + var res4 = client.send(req4, BodyHandlers.ofString()); + assertEquals(res4.statusCode(), 404); // not found + + var req5 = HttpRequest.newBuilder(uri(server, "/foo/bar/\\..\\../")).build(); + var res5 = client.send(req5, BodyHandlers.ofString()); + assertEquals(res5.statusCode(), 404); // not found + + var req6 = HttpRequest.newBuilder(uri(server, "/foo")).build(); + var res6 = client.send(req6, BodyHandlers.ofString()); + assertEquals(res6.statusCode(), 301); // redirect + assertEquals(res6.headers().firstValue("content-length").get(), "0"); + assertEquals(res6.headers().firstValue("location").get(), "/foo/"); + } finally { + server.stop(0); + } + } + { + var handler = SimpleFileServer.createFileHandler(TEST_DIR); + var server = HttpServer.create(LOOPBACK_ADDR, 10, "/browse/", handler, OUTPUT_FILTER); + server.start(); + try { + var req1 = HttpRequest.newBuilder(uri(server, "/browse/file.txt")).build(); + var res1 = client.send(req1, BodyHandlers.ofString()); + assertEquals(res1.statusCode(), 200); + assertEquals(res1.body(), "testdir"); + assertEquals(res1.headers().firstValue("content-type").get(), "text/plain"); + assertEquals(res1.headers().firstValue("content-length").get(), Long.toString(7L)); + assertEquals(res1.headers().firstValue("last-modified").get(), getLastModified(TEST_DIR.resolve("file.txt"))); + + var req2 = HttpRequest.newBuilder(uri(server, "/store/file.txt")).build(); + var res2 = client.send(req2, BodyHandlers.ofString()); + assertEquals(res2.statusCode(), 404); // no context found + } finally { + server.stop(0); + } + } + { + // Test "/foo/" context (with trailing slash) + var handler = SimpleFileServer.createFileHandler(TEST_DIR.resolve("foo")); + var server = HttpServer.create(LOOPBACK_ADDR, 10, "/foo/", handler, OUTPUT_FILTER); + server.start(); + try { + var req1 = HttpRequest.newBuilder(uri(server, "/foo/file.txt")).build(); + var res1 = client.send(req1, BodyHandlers.ofString()); + assertEquals(res1.statusCode(), 200); + assertEquals(res1.body(), "foo"); + assertEquals(res1.headers().firstValue("content-type").get(), "text/plain"); + assertEquals(res1.headers().firstValue("content-length").get(), Long.toString(3L)); + assertEquals(res1.headers().firstValue("last-modified").get(), getLastModified(TEST_DIR.resolve("foo").resolve("file.txt"))); + + var req2 = HttpRequest.newBuilder(uri(server, "/foobar/file.txt")).build(); + var res2 = client.send(req2, BodyHandlers.ofString()); + assertEquals(res2.statusCode(), 404); // no context found + + var req3 = HttpRequest.newBuilder(uri(server, "/foo/../foobar/file.txt")).build(); + var res3 = client.send(req3, BodyHandlers.ofString()); + assertEquals(res3.statusCode(), 404); // cannot escape context + + var req4 = HttpRequest.newBuilder(uri(server, "/foo/../..")).build(); + var res4 = client.send(req4, BodyHandlers.ofString()); + assertEquals(res4.statusCode(), 404); // cannot escape root + + var req5 = HttpRequest.newBuilder(uri(server, "/foo/bar")).build(); + var res5 = client.send(req5, BodyHandlers.ofString()); + assertEquals(res5.statusCode(), 301); // redirect + assertEquals(res5.headers().firstValue("content-length").get(), "0"); + assertEquals(res5.headers().firstValue("location").get(), "/foo/bar/"); + } finally { + server.stop(0); + } + } + { + // Test "/foo" context (without trailing slash) + var handler = SimpleFileServer.createFileHandler(TEST_DIR.resolve("foo")); + var server = HttpServer.create(LOOPBACK_ADDR, 10, "/foo", handler, OUTPUT_FILTER); + server.start(); + try { + var req1 = HttpRequest.newBuilder(uri(server, "/foo/file.txt")).build(); + var res1 = client.send(req1, BodyHandlers.ofString()); + assertEquals(res1.statusCode(), 200); + assertEquals(res1.body(), "foo"); + assertEquals(res1.headers().firstValue("content-type").get(), "text/plain"); + assertEquals(res1.headers().firstValue("content-length").get(), Long.toString(3L)); + assertEquals(res1.headers().firstValue("last-modified").get(), getLastModified(TEST_DIR.resolve("foo").resolve("file.txt"))); + + var req2 = HttpRequest.newBuilder(uri(server, "/foobar/")).build(); + var res2 = client.send(req2, BodyHandlers.ofString()); + assertEquals(res2.statusCode(), 404); // handler prevents mapping to /foo/bar + + var req3 = HttpRequest.newBuilder(uri(server, "/foobar/file.txt")).build(); + var res3 = client.send(req3, BodyHandlers.ofString()); + assertEquals(res3.statusCode(), 404); // handler prevents mapping to /foo/bar/file.txt + + var req4 = HttpRequest.newBuilder(uri(server, "/file.txt")).build(); + var res4 = client.send(req4, BodyHandlers.ofString()); + assertEquals(res4.statusCode(), 404); + + var req5 = HttpRequest.newBuilder(uri(server, "/foo/bar")).build(); + var res5 = client.send(req5, BodyHandlers.ofString()); + assertEquals(res5.statusCode(), 301); // redirect + assertEquals(res5.headers().firstValue("content-length").get(), "0"); + assertEquals(res5.headers().firstValue("location").get(), "/foo/bar/"); + + var req6 = HttpRequest.newBuilder(uri(server, "/foo")).build(); + var res6 = client.send(req6, BodyHandlers.ofString()); + assertEquals(res6.statusCode(), 301); // redirect + assertEquals(res6.headers().firstValue("content-length").get(), "0"); + assertEquals(res6.headers().firstValue("location").get(), "/foo/"); + } finally { + server.stop(0); + } + } + } + + // Tests with a mixture of in-memory and file handlers. + @Test + public void multipleContexts() throws Exception { + var rootHandler = HttpHandlers.of(200, Headers.of(), "root response body"); + var fooHandler = SimpleFileServer.createFileHandler(TEST_DIR.resolve("foo")); + var foobarHandler = SimpleFileServer.createFileHandler(TEST_DIR.resolve("foobar")); + var barHandler = HttpHandlers.of(200, Headers.of(), "bar response body"); + + var server = HttpServer.create(LOOPBACK_ADDR, 0); + server.createContext("/", rootHandler); + server.createContext("/foo/", fooHandler); + server.createContext("/bar/", barHandler); + server.createContext("/foobar/", foobarHandler); + server.start(); + var client = HttpClient.newBuilder().proxy(NO_PROXY).build(); + try { + for (String uriPath : List.of("/", "/blah", "/xyz/t/z", "/txt") ) { + out.println("uri.Path=" + uriPath); + var req1 = HttpRequest.newBuilder(uri(server, uriPath)).build(); + var res1 = client.send(req1, BodyHandlers.ofString()); + assertEquals(res1.statusCode(), 200); + assertEquals(res1.body(), "root response body"); + } + { + var req1 = HttpRequest.newBuilder(uri(server, "/foo/file.txt")).build(); + var res1 = client.send(req1, BodyHandlers.ofString()); + assertEquals(res1.statusCode(), 200); + assertEquals(res1.body(), "foo"); + + var req2 = HttpRequest.newBuilder(uri(server, "/foo/bar/baz/file.txt")).build(); + var res2 = client.send(req2, BodyHandlers.ofString()); + assertEquals(res2.statusCode(), 200); + assertEquals(res2.body(), "foo/bar/baz"); + } + { + var req1 = HttpRequest.newBuilder(uri(server, "/foobar/file.txt")).build(); + var res1 = client.send(req1, BodyHandlers.ofString()); + assertEquals(res1.statusCode(), 200); + assertEquals(res1.body(), "foobar"); + } + for (String uriPath : List.of("/bar/", "/bar/t", "/bar/t/z", "/bar/index.html") ) { + out.println("uri.Path=" + uriPath); + var req1 = HttpRequest.newBuilder(uri(server, uriPath)).build(); + var res1 = client.send(req1, BodyHandlers.ofString()); + assertEquals(res1.statusCode(), 200); + assertEquals(res1.body(), "bar response body"); + } + } finally { + server.stop(0); + } + } + + // Tests requests with queries, which are simply ignored by the handler + @Test + public void requestWithQuery() throws Exception { + var client = HttpClient.newBuilder().proxy(NO_PROXY).build(); + var handler = SimpleFileServer.createFileHandler(TEST_DIR); + var server = HttpServer.create(LOOPBACK_ADDR, 10, "/", handler, OUTPUT_FILTER); + server.start(); + try { + for (String query : List.of("x=y", "x=", "xxx", "#:?") ) { + out.println("uri.Query=" + query); + var req = HttpRequest.newBuilder(uri(server, "", query)).build(); + var res = client.send(req, BodyHandlers.ofString()); + assertEquals(res.statusCode(), 200); + assertEquals(res.headers().firstValue("content-type").get(), "text/html; charset=UTF-8"); + assertEquals(res.headers().firstValue("content-length").get(), Long.toString(257L)); + assertEquals(res.headers().firstValue("last-modified").get(), getLastModified(TEST_DIR)); + } + } finally { + server.stop(0); + } + } + + @AfterTest + public void teardown() throws IOException { + if (Files.exists(TEST_DIR)) { + FileUtils.deleteFileTreeWithRetry(TEST_DIR); + } + } + + static URI uri(HttpServer server, String path) { + return URIBuilder.newBuilder() + .host("localhost") + .port(server.getAddress().getPort()) + .scheme("http") + .path(path) + .buildUnchecked(); + } + + static URI uri(HttpServer server, String path, String query) { + return URIBuilder.newBuilder() + .host("localhost") + .port(server.getAddress().getPort()) + .scheme("http") + .path(path) + .query(query) + .buildUnchecked(); + } + + static String getLastModified(Path path) throws IOException { + return Files.getLastModifiedTime(path).toInstant().atZone(ZoneId.of("GMT")) + .format(DateTimeFormatter.RFC_1123_DATE_TIME); + } +} diff --git a/test/jdk/com/sun/net/httpserver/simpleserver/OutputFilterTest.java b/test/jdk/com/sun/net/httpserver/simpleserver/OutputFilterTest.java new file mode 100644 index 00000000000..b7583ea901b --- /dev/null +++ b/test/jdk/com/sun/net/httpserver/simpleserver/OutputFilterTest.java @@ -0,0 +1,342 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 Tests for OutputFilter + * @modules java.base/sun.net.www:+open + * @library /test/lib + * @build jdk.test.lib.net.URIBuilder + * @run testng/othervm -Djdk.httpclient.redirects.retrylimit=1 OutputFilterTest + */ + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.nio.charset.StandardCharsets; +import java.nio.file.Path; +import java.util.List; +import java.util.logging.ConsoleHandler; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.regex.Pattern; +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import com.sun.net.httpserver.HttpServer; +import com.sun.net.httpserver.SimpleFileServer; +import com.sun.net.httpserver.SimpleFileServer.OutputLevel; +import jdk.test.lib.net.URIBuilder; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import static java.net.http.HttpClient.Builder.NO_PROXY; +import static java.nio.charset.StandardCharsets.*; +import static com.sun.net.httpserver.SimpleFileServer.OutputLevel.*; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertThrows; +import static org.testng.Assert.assertTrue; + +public class OutputFilterTest { + static final Class NPE = NullPointerException.class; + static final Class IAE = IllegalArgumentException.class; + static final Class IOE = IOException.class; + + static final OutputStream OUT = new ByteArrayOutputStream(); + static final InetSocketAddress LOOPBACK_ADDR = new InetSocketAddress(InetAddress.getLoopbackAddress(), 0); + + static final boolean ENABLE_LOGGING = true; + static final Logger logger = Logger.getLogger("com.sun.net.httpserver"); + + @BeforeTest + public void setup() { + if (ENABLE_LOGGING) { + ConsoleHandler ch = new ConsoleHandler(); + logger.setLevel(Level.ALL); + ch.setLevel(Level.ALL); + logger.addHandler(ch); + } + } + + @Test + public void testNull() { + assertThrows(NPE, () -> SimpleFileServer.createOutputFilter(null, null)); + assertThrows(NPE, () -> SimpleFileServer.createOutputFilter(null, VERBOSE)); + assertThrows(NPE, () -> SimpleFileServer.createOutputFilter(OUT, null)); + } + + @Test + public void testDescription() { + var filter = SimpleFileServer.createOutputFilter(OUT, VERBOSE); + assertEquals(filter.description(), "HttpExchange OutputFilter (outputLevel: VERBOSE)"); + + filter = SimpleFileServer.createOutputFilter(OUT, INFO); + assertEquals(filter.description(), "HttpExchange OutputFilter (outputLevel: INFO)"); + } + + @Test + public void testNONE() { + assertThrows(IAE, () -> SimpleFileServer.createOutputFilter(OUT, NONE)); + } + + /** + * Confirms that the output filter produces the expected output for a + * successful exchange (with the request-path attribute set.) + */ + @Test + public void testExchange() throws Exception { + var baos = new ByteArrayOutputStream(); + var handler = new RequestPathHandler(); + var filter = SimpleFileServer.createOutputFilter(baos, VERBOSE); + var server = HttpServer.create(LOOPBACK_ADDR, 10, "/", handler, filter); + server.start(); + try (baos) { + var client = HttpClient.newBuilder().proxy(NO_PROXY).build(); + var request = HttpRequest.newBuilder(uri(server, "")).build(); + var response = client.send(request, HttpResponse.BodyHandlers.ofString()); + assertEquals(response.statusCode(), 200); + assertEquals(response.headers().map().size(), 3); + assertEquals(response.body(), "hello world"); + } finally { + server.stop(0); + baos.flush(); + var filterOutput = baos.toString(UTF_8); + var pattern = Pattern.compile(""" + 127\\.0\\.0\\.1 - - \\[[\\s\\S]+] "GET / HTTP/1\\.1" 200 - + Resource requested: /foo/bar + (>[\\s\\S]+:[\\s\\S]+)+ + > + (<[\\s\\S]+:[\\s\\S]+)+ + < + """.replaceAll("\n", System.lineSeparator())); + assertTrue(pattern.matcher(filterOutput).matches()); + + /* + * Expected output format: + * """ + * 127.0.0.1 - - [06/Jul/2021:12:56:47 +0100] "GET / HTTP/1.1" 200 - + * Resource requested: /foo/bar + * > Connection: Upgrade, HTTP2-Settings + * > Http2-settings: AAEAAEAAAAIAAAABAAMAAABkAAQBAAAAAAUAAEAA + * > Host: localhost:59146 + * > Upgrade: h2c + * > User-agent: Java-http-client/18-internal + * > Content-length: 0 + * > + * < Date: Tue, 06 Jul 2021 11:56:47 GMT + * < Content-length: 11 + * < + * """; + */ + } + } + + /** + * Confirms that the output filter produces the expected output for + * a successful exchange (without the request-path attribute set.) + */ + @Test + public void testExchangeWithoutRequestPath() throws Exception { + var baos = new ByteArrayOutputStream(); + var handler = new NoRequestPathHandler(); + var filter = SimpleFileServer.createOutputFilter(baos, VERBOSE); + var server = HttpServer.create(LOOPBACK_ADDR, 10, "/", handler, filter); + server.start(); + try (baos) { + var client = HttpClient.newBuilder().proxy(NO_PROXY).build(); + var request = HttpRequest.newBuilder(uri(server, "")).build(); + var response = client.send(request, HttpResponse.BodyHandlers.ofString()); + assertEquals(response.statusCode(), 200); + assertEquals(response.headers().map().size(), 2); + assertEquals(response.body(), "hello world"); + } finally { + server.stop(0); + baos.flush(); + var filterOutput = baos.toString(UTF_8); + var pattern = Pattern.compile(""" + 127\\.0\\.0\\.1 - - \\[[\\s\\S]+] "GET / HTTP/1\\.1" 200 - + (>[\\s\\S]+:[\\s\\S]+)+ + > + (<[\\s\\S]+:[\\s\\S]+)+ + < + """.replaceAll("\n", System.lineSeparator())); + assertTrue(pattern.matcher(filterOutput).matches()); + + /* + * Expected output: + * """ + * 127.0.0.1 - - [12/Jul/2021:10:05:10 +0000] "GET / HTTP/1.1" 200 - + * > Connection: Upgrade, HTTP2-Settings + * > Http2-settings: AAEAAEAAAAIAAAABAAMAAABkAAQBAAAAAAUAAEAA + * > Host: localhost:57931 + * > Upgrade: h2c + * > User-agent: Java-http-client/18-internal + * > Content-length: 0 + * > + * < Date: Mon, 12 Jul 2021 10:05:10 GMT + * < Content-length: 11 + * < + * """; + */ + } + } + + @DataProvider + public Object[][] throwingHandler() { + return new Object[][] { + {VERBOSE, "Error: server exchange handling failed: IOE ThrowingHandler" + System.lineSeparator()}, + {INFO, "Error: server exchange handling failed: IOE ThrowingHandler" + System.lineSeparator()}, + {NONE, ""} + }; + } + + /** + * Confirms that the output filter captures a throwable that is thrown + * during the exchange handling and prints the expected error message. + * The "httpclient.redirects.retrylimit" system property is set to 1 to + * prevent retries on the client side, which would result in more than one + * error message. + */ + @Test(dataProvider = "throwingHandler") + public void testExchangeThrowingHandler(OutputLevel level, + String expectedOutput) throws Exception { + var baos = new ByteArrayOutputStream(); + var handler = new ThrowingHandler(); + HttpServer server; + if (level.equals(NONE)) { + server = HttpServer.create(LOOPBACK_ADDR, 10, "/", handler); + } else { + var filter = SimpleFileServer.createOutputFilter(baos, level); + server = HttpServer.create(LOOPBACK_ADDR, 10, "/", handler, filter); + } + server.start(); + try (baos) { + var client = HttpClient.newBuilder().proxy(NO_PROXY).build(); + var request = HttpRequest.newBuilder(uri(server, "")).build(); + assertThrows(IOE, () -> client.send(request, HttpResponse.BodyHandlers.ofString())); + } finally { + server.stop(0); + baos.flush(); + assertEquals(baos.toString(UTF_8), expectedOutput); + } + } + + /** + * Confirms that the output filter prints the expected message if the request + * URI cannot be resolved. This only applies if the filter is used in + * combination with the SimpleFileServer file-handler, which sets the + * necessary request-path attribute. + */ + @Test + public void testCannotResolveRequestURI() throws Exception { + var baos = new ByteArrayOutputStream(); + var handler = SimpleFileServer.createFileHandler(Path.of(".").toAbsolutePath()); + var filter = SimpleFileServer.createOutputFilter(baos, VERBOSE); + var server = HttpServer.create(LOOPBACK_ADDR, 0, "/", handler, filter); + server.start(); + try (baos) { + var client = HttpClient.newBuilder().proxy(NO_PROXY).build(); + var request = HttpRequest.newBuilder(uri(server, "aFile\u0000.txt")).build(); + var response = client.send(request, HttpResponse.BodyHandlers.ofString()); + assertEquals(response.statusCode(), 404); + assertEquals(response.headers().map().size(), 3); + } finally { + server.stop(0); + baos.flush(); + var filterOutput = baos.toString(UTF_8); + var pattern = Pattern.compile(""" + 127\\.0\\.0\\.1 - - \\[[\\s\\S]+] "GET /aFile%00\\.txt HTTP/1\\.1" 404 - + Resource requested: could not resolve request URI path + (>[\\s\\S]+:[\\s\\S]+)+ + > + (<[\\s\\S]+:[\\s\\S]+)+ + < + """.replaceAll("\n", System.lineSeparator())); + assertTrue(pattern.matcher(filterOutput).matches()); + } + } + + // --- infra --- + + static URI uri(HttpServer server, String path) { + return URIBuilder.newBuilder() + .host("localhost") + .port(server.getAddress().getPort()) + .scheme("http") + .path("/" + path) + .buildUnchecked(); + } + + /** + * A handler that sets the request-path attribute and a custom header + * and sends a response. + */ + static class RequestPathHandler implements HttpHandler { + @Override + public void handle(HttpExchange exchange) throws IOException { + try (InputStream is = exchange.getRequestBody(); + OutputStream os = exchange.getResponseBody()) { + is.readAllBytes(); + exchange.setAttribute("request-path", "/foo/bar"); + exchange.getResponseHeaders().put("Foo", List.of("bar", "bar")); + var resp = "hello world".getBytes(StandardCharsets.UTF_8); + exchange.sendResponseHeaders(200, resp.length); + os.write(resp); + } + } + } + + /** + * A handler that sets no request-path attribute and sends a response. + */ + static class NoRequestPathHandler implements HttpHandler { + @Override + public void handle(HttpExchange exchange) throws IOException { + try (InputStream is = exchange.getRequestBody(); + OutputStream os = exchange.getResponseBody()) { + is.readAllBytes(); + var resp = "hello world".getBytes(StandardCharsets.UTF_8); + exchange.sendResponseHeaders(200, resp.length); + os.write(resp); + } + } + } + + /** + * A handler that throws an IOException. + */ + static class ThrowingHandler implements HttpHandler { + @Override + public void handle(HttpExchange exchange) throws IOException { + try (exchange) { + throw new IOException("IOE ThrowingHandler"); + } + } + } +} diff --git a/test/jdk/com/sun/net/httpserver/simpleserver/RequestTest.java b/test/jdk/com/sun/net/httpserver/simpleserver/RequestTest.java new file mode 100644 index 00000000000..cb740f4dd2a --- /dev/null +++ b/test/jdk/com/sun/net/httpserver/simpleserver/RequestTest.java @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 Tests for Request + * @run testng RequestTest + */ + +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetSocketAddress; +import java.net.URI; +import java.util.AbstractMap; +import java.util.List; +import java.util.Map; +import com.sun.net.httpserver.*; +import org.testng.annotations.Test; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertThrows; + +public class RequestTest { + + @Test + public void testAddToEmpty() { + var headers = new Headers(); + Request request = new TestHttpExchange(headers); + request = request.with("Foo", List.of("Bar")); + assertEquals(request.getRequestHeaders().size(), 1); + assertEquals(request.getRequestHeaders().get("Foo"), List.of("Bar")); + assertReadOnly(request.getRequestHeaders()); + } + + @Test + public void testAddition() { + var headers = new Headers(); + headers.add("Foo", "Bar"); + Request request = new TestHttpExchange(headers); + request = request.with("X-Foo", List.of("Bar")); + assertEquals(request.getRequestHeaders().size(), 2); + assertEquals(request.getRequestHeaders().get("Foo"), List.of("Bar")); + assertEquals(request.getRequestHeaders().get("X-Foo"), List.of("Bar")); + assertReadOnly(request.getRequestHeaders()); + } + + @Test + public void testAddWithExisting() { + final String headerName = "Foo"; + var headers = new Headers(); + headers.add(headerName, "Bar"); + Request request = new TestHttpExchange(headers); + request = request.with(headerName, List.of("blahblahblah")); + assertEquals(request.getRequestHeaders().size(), 1); + assertEquals(request.getRequestHeaders().get(headerName), List.of("Bar")); + assertReadOnly(request.getRequestHeaders()); + } + + @Test + public void testAddSeveral() { + var headers = new Headers(); + headers.add("Foo", "Bar"); + Request request = new TestHttpExchange(headers); + request = request.with("Larry", List.of("a")) + .with("Curly", List.of("b")) + .with("Moe", List.of("c")); + assertEquals(request.getRequestHeaders().size(), 4); + assertEquals(request.getRequestHeaders().getFirst("Foo"), "Bar"); + assertEquals(request.getRequestHeaders().getFirst("Larry"), "a"); + assertEquals(request.getRequestHeaders().getFirst("Curly"), "b"); + assertEquals(request.getRequestHeaders().getFirst("Moe" ), "c"); + assertReadOnly(request.getRequestHeaders()); + } + + static final Class UOP = UnsupportedOperationException.class; + + static void assertReadOnly(Headers headers) { + assertUnsupportedOperation(headers); + assertUnmodifiableCollection(headers); + assertUnmodifiableList(headers); + } + + static void assertUnsupportedOperation(Headers headers) { + assertThrows(UOP, () -> headers.add("a", "b")); + assertThrows(UOP, () -> headers.compute("c", (k, v) -> List.of("c"))); + assertThrows(UOP, () -> headers.computeIfAbsent("d", k -> List.of("d"))); + assertThrows(UOP, () -> headers.computeIfPresent("Foo", (k, v) -> null)); + assertThrows(UOP, () -> headers.merge("e", List.of("e"), (k, v) -> List.of("e"))); + assertThrows(UOP, () -> headers.put("f", List.of("f"))); + assertThrows(UOP, () -> headers.putAll(Map.of())); + assertThrows(UOP, () -> headers.putIfAbsent("g", List.of("g"))); + assertThrows(UOP, () -> headers.remove("h")); + assertThrows(UOP, () -> headers.replace("i", List.of("i"))); + assertThrows(UOP, () -> headers.replace("j", List.of("j"), List.of("j"))); + assertThrows(UOP, () -> headers.replaceAll((k, v) -> List.of("k"))); + assertThrows(UOP, () -> headers.set("l", "m")); + assertThrows(UOP, () -> headers.clear()); + } + + static void assertUnmodifiableCollection(Headers headers) { + var entry = new AbstractMap.SimpleEntry<>("n", List.of("n")); + + assertThrows(UOP, () -> headers.values().remove(List.of("Bar"))); + assertThrows(UOP, () -> headers.values().removeAll(List.of("Bar"))); + assertThrows(UOP, () -> headers.keySet().remove("Foo")); + assertThrows(UOP, () -> headers.keySet().removeAll(List.of("Foo"))); + assertThrows(UOP, () -> headers.entrySet().remove(entry)); + assertThrows(UOP, () -> headers.entrySet().removeAll(List.of(entry))); + } + + static void assertUnmodifiableList(Headers headers) { + assertThrows(UOP, () -> headers.get("Foo").remove(0)); + assertThrows(UOP, () -> headers.get("foo").remove(0)); + assertThrows(UOP, () -> headers.values().stream().findFirst().orElseThrow().remove(0)); + assertThrows(UOP, () -> headers.entrySet().stream().findFirst().orElseThrow().getValue().remove(0)); + } + + static class TestHttpExchange extends StubHttpExchange { + final Headers headers; + TestHttpExchange(Headers headers) { + this.headers = headers; + } + @Override + public Headers getRequestHeaders() { + return headers; + } + } + + static class StubHttpExchange extends HttpExchange { + @Override public Headers getRequestHeaders() { return null; } + @Override public Headers getResponseHeaders() { return null; } + @Override public URI getRequestURI() { return null; } + @Override public String getRequestMethod() { return null; } + @Override public HttpContext getHttpContext() { return null; } + @Override public void close() { } + @Override public InputStream getRequestBody() { return null; } + @Override public OutputStream getResponseBody() { return null; } + @Override public void sendResponseHeaders(int rCode, long responseLength) { } + @Override public InetSocketAddress getRemoteAddress() { return null; } + @Override public int getResponseCode() { return 0; } + @Override public InetSocketAddress getLocalAddress() { return null; } + @Override public String getProtocol() { return null; } + @Override public Object getAttribute(String name) { return null; } + @Override public void setAttribute(String name, Object value) { } + @Override public void setStreams(InputStream i, OutputStream o) { } + @Override public HttpPrincipal getPrincipal() { return null; } + } +} diff --git a/test/jdk/com/sun/net/httpserver/simpleserver/SecurityManagerTest.java b/test/jdk/com/sun/net/httpserver/simpleserver/SecurityManagerTest.java new file mode 100644 index 00000000000..72d0050b2af --- /dev/null +++ b/test/jdk/com/sun/net/httpserver/simpleserver/SecurityManagerTest.java @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 Tests for FileServerHandler with SecurityManager + * @library /test/lib + * @build jdk.test.lib.net.URIBuilder + * @run main/othervm/java.security.policy=SecurityManagerTestRead.policy -ea SecurityManagerTest true + * @run main/othervm/java.security.policy=SecurityManagerTestNoRead.policy -ea SecurityManagerTest false + * @run main/othervm -ea SecurityManagerTest true + */ + +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse.BodyHandlers; +import java.nio.file.Files; +import java.nio.file.Path; +import java.security.AccessControlException; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.logging.ConsoleHandler; +import java.util.logging.Level; +import java.util.logging.Logger; +import com.sun.net.httpserver.HttpServer; +import com.sun.net.httpserver.SimpleFileServer; +import com.sun.net.httpserver.SimpleFileServer.OutputLevel; +import jdk.test.lib.net.URIBuilder; +import jdk.test.lib.util.FileUtils; +import static java.net.http.HttpClient.Builder.NO_PROXY; +import static java.nio.charset.StandardCharsets.UTF_8; +import static java.nio.file.StandardOpenOption.CREATE; + +/** + * Tests the permission checks during the creation of a FileServerHandler. + * + * A FileServerHandler can only be created if a "read" FilePermission is + * granted for the root directory passed. The test consists of 3 runs: + * 1) security manager enabled and "read" FilePermission granted + * 2) security manager enabled and "read" FilePermission NOT granted + * 3) security manager NOT enabled + * 2) misses the required permissions to call many of the java.nio.file methods, + * the test works around this by reusing the test directory created in the + * previous run. +* */ +public class SecurityManagerTest { + + static final Path CWD = Path.of(".").toAbsolutePath().normalize(); + static final Path TEST_DIR = CWD.resolve("SecurityManagerTest"); + static final InetSocketAddress LOOPBACK_ADDR = + new InetSocketAddress(InetAddress.getLoopbackAddress(), 0); + + static final boolean ENABLE_LOGGING = true; + static final Logger LOGGER = Logger.getLogger("com.sun.net.httpserver"); + + static boolean readPermitted; + static String lastModifiedDir; + static String lastModifiedFile; + + public static void main(String[] args) throws Exception { + setupLogging(); + readPermitted = Boolean.parseBoolean(args[0]); + if (readPermitted) { + createTestDir(); + testDirectoryGET(); + testFileGET(); + } else { // no FilePermission "read" for TEST_DIR granted, + // assert handler cannot be created + testCreateHandler(); + } + } + + private static void setupLogging() { + if (ENABLE_LOGGING) { + ConsoleHandler ch = new ConsoleHandler(); + LOGGER.setLevel(Level.ALL); + ch.setLevel(Level.ALL); + LOGGER.addHandler(ch); + } + } + + private static void createTestDir() throws IOException { + if (Files.exists(TEST_DIR)) { + FileUtils.deleteFileTreeWithRetry(TEST_DIR); + } + Files.createDirectories(TEST_DIR); + var file = Files.writeString(TEST_DIR.resolve("aFile.txt"), "some text", CREATE); + lastModifiedDir = getLastModified(TEST_DIR); + lastModifiedFile = getLastModified(file); + } + + private static void testDirectoryGET() throws Exception { + var expectedBody = openHTML + """ +

      Directory listing for /

      +
      + """ + closeHTML; + var expectedLength = Integer.toString(expectedBody.getBytes(UTF_8).length); + var server = SimpleFileServer.createFileServer(LOOPBACK_ADDR, TEST_DIR, OutputLevel.VERBOSE); + + server.start(); + try { + var client = HttpClient.newBuilder().proxy(NO_PROXY).build(); + var request = HttpRequest.newBuilder(uri(server, "")).build(); + var response = client.send(request, BodyHandlers.ofString()); + assert response.statusCode() == 200; + assert response.body().equals(expectedBody); + assert response.headers().firstValue("content-type").get().equals("text/html; charset=UTF-8"); + assert response.headers().firstValue("content-length").get().equals(expectedLength); + assert response.headers().firstValue("last-modified").get().equals(lastModifiedDir); + } finally { + server.stop(0); + } + } + + private static void testFileGET() throws Exception { + var expectedBody = "some text"; + var expectedLength = Integer.toString(expectedBody.getBytes(UTF_8).length); + var server = SimpleFileServer.createFileServer(LOOPBACK_ADDR, TEST_DIR, OutputLevel.VERBOSE); + + server.start(); + try { + var client = HttpClient.newBuilder().proxy(NO_PROXY).build(); + var request = HttpRequest.newBuilder(uri(server, "aFile.txt")).build(); + var response = client.send(request, BodyHandlers.ofString()); + assert response.statusCode() == 200; + assert response.body().equals("some text"); + assert response.headers().firstValue("content-type").get().equals("text/plain"); + assert response.headers().firstValue("content-length").get().equals(expectedLength); + assert response.headers().firstValue("last-modified").get().equals(lastModifiedFile); + } finally { + server.stop(0); + } + } + + @SuppressWarnings("removal") + private static void testCreateHandler(){ + try { + SimpleFileServer.createFileServer(LOOPBACK_ADDR, TEST_DIR, OutputLevel.NONE); + throw new RuntimeException("Handler creation expected to fail"); + } catch (AccessControlException expected) { } + + try { + SimpleFileServer.createFileHandler(TEST_DIR); + throw new RuntimeException("Handler creation expected to fail"); + } catch (AccessControlException expected) { } + } + + static final String openHTML = """ + + + + + + + """; + + static final String closeHTML = """ + + + """; + + static URI uri(HttpServer server, String path) { + return URIBuilder.newBuilder() + .host("localhost") + .port(server.getAddress().getPort()) + .scheme("http") + .path("/" + path) + .buildUnchecked(); + } + + static String getLastModified(Path path) throws IOException { + return Files.getLastModifiedTime(path).toInstant().atZone(ZoneId.of("GMT")) + .format(DateTimeFormatter.RFC_1123_DATE_TIME); + } +} diff --git a/test/jdk/com/sun/net/httpserver/simpleserver/SecurityManagerTestNoRead.policy b/test/jdk/com/sun/net/httpserver/simpleserver/SecurityManagerTestNoRead.policy new file mode 100644 index 00000000000..b91171b4145 --- /dev/null +++ b/test/jdk/com/sun/net/httpserver/simpleserver/SecurityManagerTestNoRead.policy @@ -0,0 +1,39 @@ +// +// Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. +// 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. +// + +// for JTwork/classes/test/lib/jdk/test/lib/util/FileUtils.class +grant codeBase "file:${test.classes}/../../../../../../test/lib/-" { + permission java.util.PropertyPermission "*", "read"; +}; + +grant codeBase "file:${test.classes}/*" { + permission java.net.URLPermission "http://localhost:*/*", "GET"; + + // for HTTP server + permission java.net.SocketPermission "localhost:*", "accept,resolve"; + + // for HTTP/1.1 server logging + permission java.util.logging.LoggingPermission "control"; + + permission java.util.PropertyPermission "*", "read"; +}; diff --git a/test/jdk/com/sun/net/httpserver/simpleserver/SecurityManagerTestRead.policy b/test/jdk/com/sun/net/httpserver/simpleserver/SecurityManagerTestRead.policy new file mode 100644 index 00000000000..b8b6b3a5f37 --- /dev/null +++ b/test/jdk/com/sun/net/httpserver/simpleserver/SecurityManagerTestRead.policy @@ -0,0 +1,43 @@ +// +// Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. +// 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. +// + +// for JTwork/classes/test/lib/jdk/test/lib/util/FileUtils.class +grant codeBase "file:${test.classes}/../../../../../../test/lib/-" { + permission java.util.PropertyPermission "*", "read"; +}; + +grant codeBase "file:${test.classes}/*" { + permission java.net.URLPermission "http://localhost:*/*", "GET"; + + // for test directory tree + permission java.io.FilePermission "${user.dir}${/}SecurityManagerTest", "read,write,delete"; + permission java.io.FilePermission "${user.dir}${/}SecurityManagerTest/-", "read,write,delete"; + + // for HTTP server + permission java.net.SocketPermission "localhost:*", "accept,resolve"; + + // for HTTP/1.1 server logging + permission java.util.logging.LoggingPermission "control"; + + permission java.util.PropertyPermission "*", "read"; +}; diff --git a/test/jdk/com/sun/net/httpserver/simpleserver/ServerMimeTypesResolutionTest.java b/test/jdk/com/sun/net/httpserver/simpleserver/ServerMimeTypesResolutionTest.java new file mode 100644 index 00000000000..baa7d17b505 --- /dev/null +++ b/test/jdk/com/sun/net/httpserver/simpleserver/ServerMimeTypesResolutionTest.java @@ -0,0 +1,211 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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.StringReader; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.*; +import java.util.logging.ConsoleHandler; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.stream.Collectors; +import jdk.test.lib.net.URIBuilder; +import com.sun.net.httpserver.HttpServer; +import com.sun.net.httpserver.SimpleFileServer; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import sun.net.www.MimeTable; + +import static java.net.http.HttpClient.Builder.NO_PROXY; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + +/* + * @test + * @summary Tests for MIME types in response headers + * @modules java.base/sun.net.www:+open + * @library /test/lib + * @build jdk.test.lib.net.URIBuilder + * @run testng/othervm ServerMimeTypesResolutionTest + */ +public class ServerMimeTypesResolutionTest { + + static final Path CWD = Path.of(".").toAbsolutePath(); + static final InetSocketAddress LOOPBACK_ADDR = new InetSocketAddress(InetAddress.getLoopbackAddress(), 0); + static final String FILE_NAME = "empty-file-of-type"; + static final String UNKNOWN_FILE_EXTENSION = ".unknown-file-extension"; + static final Properties SUPPORTED_MIME_TYPES = new Properties(); + static final Set UNSUPPORTED_FILE_EXTENSIONS = new HashSet<>(); + static List supportedFileExtensions; + static Path root; + + static final boolean ENABLE_LOGGING = true; + static final Logger LOGGER = Logger.getLogger("com.sun.net.httpserver"); + + @BeforeTest + public void setup() throws Exception { + if (ENABLE_LOGGING) { + ConsoleHandler ch = new ConsoleHandler(); + LOGGER.setLevel(Level.ALL); + ch.setLevel(Level.ALL); + LOGGER.addHandler(ch); + } + getSupportedMimeTypes(SUPPORTED_MIME_TYPES); + supportedFileExtensions = getFileExtensions(SUPPORTED_MIME_TYPES); + root = createFileTreeFromMimeTypes(SUPPORTED_MIME_TYPES); + } + + public static Properties getSupportedMimeTypes(Properties properties) throws IOException { + properties.load(MimeTable.class.getResourceAsStream("content-types.properties")); + return properties; + } + + private static List getFileExtensions(Properties input) { + return new ArrayList<>(getMimeTypesPerFileExtension(input).keySet()); + } + + private static Map getMimeTypesPerFileExtension(Properties input) { + return input + .entrySet() + .stream() + .filter(entry -> ((String)entry.getValue()).contains("file_extensions")) + .flatMap(entry -> + Arrays.stream( + ((String)deserialize((String) entry.getValue(), ";") + .get("file_extensions")).split(",")) + .map(extension -> + Map.entry(extension, entry.getKey().toString()))) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + } + + private static Path createFileTreeFromMimeTypes(Properties properties) + throws IOException { + final Path root = Files.createDirectory(CWD.resolve(ServerMimeTypesResolutionTest.class.getSimpleName())); + for (String extension : supportedFileExtensions) { + Files.createFile(root.resolve(toFileName(extension))); + } + Files.createFile(root.resolve(toFileName(UNKNOWN_FILE_EXTENSION))); + return root; + } + + private static String toFileName(String extension) { + return "%s%s".formatted(FILE_NAME, extension); + } + + protected static Properties deserialize(String serialized, String delimiter) { + try { + Properties properties = new Properties(); + properties.load( + new StringReader( + Optional.ofNullable(delimiter) + .map(d -> serialized.replaceAll(delimiter, System.lineSeparator())) + .orElse(serialized) + ) + ); + return properties; + } catch (IOException exception) { + exception.printStackTrace(); + throw new RuntimeException(("error while deserializing string %s " + + "to properties").formatted(serialized), exception); + } + } + + @Test + public static void testMimeTypeHeaders() throws Exception { + final var server = SimpleFileServer.createFileServer(LOOPBACK_ADDR, root, SimpleFileServer.OutputLevel.VERBOSE); + server.start(); + try { + final var client = HttpClient.newBuilder().proxy(NO_PROXY).build(); + final Map mimeTypesPerFileExtension = getMimeTypesPerFileExtension(SUPPORTED_MIME_TYPES); + for (String extension : supportedFileExtensions) { + final String expectedMimeType = mimeTypesPerFileExtension.get(extension); + execute(server, client, extension, expectedMimeType); + } + execute(server, client, UNKNOWN_FILE_EXTENSION,"application/octet-stream"); + } finally { + server.stop(0); + } + } + + private static void execute(HttpServer server, + HttpClient client, + String extension, + String expectedMimeType) + throws IOException, InterruptedException { + final var uri = uri(server, toFileName(extension)); + final var request = HttpRequest.newBuilder(uri).build(); + final var response = client.send(request, HttpResponse.BodyHandlers.ofString()); + assertEquals(response.statusCode(), 200); + assertEquals(response.headers().firstValue("content-type").get(),expectedMimeType); + } + + static URI uri(HttpServer server, String path) { + return URIBuilder.newBuilder() + .host("localhost") + .port(server.getAddress().getPort()) + .scheme("http") + .path("/" + path) + .buildUnchecked(); + } + + @DataProvider + public static Object[][] commonExtensions() { + Set extensions = Set.of(".aac", ".abw", ".arc", ".avi", ".azw", ".bin", ".bmp", ".bz", + ".bz2", ".csh", ".css", ".csv", ".doc", ".docx",".eot", ".epub", ".gz", ".gif", ".htm", ".html", ".ico", + ".ics", ".jar", ".jpeg", ".jpg", ".js", ".json", ".jsonld", ".mid", ".midi", ".mjs", ".mp3", ".cda", + ".mp4", ".mpeg", ".mpkg", ".odp", ".ods", ".odt", ".oga", ".ogv", ".ogx", ".opus", ".otf", ".png", + ".pdf", ".php", ".ppt", ".pptx", ".rar", ".rtf", ".sh", ".svg", ".swf", ".tar", ".tif", ".tiff", ".ts", + ".ttf", ".txt", ".vsd", ".wav", ".weba", ".webm", ".webp", ".woff", ".woff2", ".xhtml", ".xls", ".xlsx", + ".xml", ".xul", ".zip", ".3gp", ".3g2", ".7z"); + return extensions.stream().map(e -> new Object[]{e}).toArray(Object[][]::new); + } + + /** + * This is a one-off test to check which common file extensions are + * currently supported by the system-wide mime table returned by + * {@linkplain java.net.FileNameMap#getContentTypeFor(String) getContentTypeFor}. + * + * Source common mime types: + * https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types + */ +// @Test(dataProvider = "commonExtensions") + public static void testCommonExtensions(String extension) { + var contains = supportedFileExtensions.contains(extension); + if (!contains) UNSUPPORTED_FILE_EXTENSIONS.add(extension); + assertTrue(contains, "expecting %s to be present".formatted(extension)); + } + +// @AfterTest + public static void printUnsupportedFileExtensions() { + System.out.println("Unsupported file extensions: " + UNSUPPORTED_FILE_EXTENSIONS.size()); + UNSUPPORTED_FILE_EXTENSIONS.forEach(System.out::println); + } +} diff --git a/test/jdk/com/sun/net/httpserver/simpleserver/SimpleFileServerTest.java b/test/jdk/com/sun/net/httpserver/simpleserver/SimpleFileServerTest.java new file mode 100644 index 00000000000..440e106c682 --- /dev/null +++ b/test/jdk/com/sun/net/httpserver/simpleserver/SimpleFileServerTest.java @@ -0,0 +1,703 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * 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 Tests for SimpleFileServer + * @library /test/lib + * @build jdk.test.lib.Platform jdk.test.lib.net.URIBuilder + * @run testng/othervm SimpleFileServerTest + */ + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpRequest.BodyPublishers; +import java.net.http.HttpResponse.BodyHandlers; +import java.nio.file.Files; +import java.nio.file.LinkOption; +import java.nio.file.Path; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.logging.ConsoleHandler; +import java.util.logging.Level; +import java.util.logging.Logger; +import com.sun.net.httpserver.HttpServer; +import com.sun.net.httpserver.SimpleFileServer; +import com.sun.net.httpserver.SimpleFileServer.OutputLevel; +import jdk.test.lib.Platform; +import jdk.test.lib.net.URIBuilder; +import jdk.test.lib.util.FileUtils; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import static java.net.http.HttpClient.Builder.NO_PROXY; +import static java.nio.charset.StandardCharsets.UTF_8; +import static java.nio.file.StandardOpenOption.CREATE; +import static org.testng.Assert.*; + +public class SimpleFileServerTest { + + static final Class NPE = NullPointerException.class; + static final Class IAE = IllegalArgumentException.class; + static final Class UIOE = UncheckedIOException.class; + + static final Path CWD = Path.of(".").toAbsolutePath(); + static final Path TEST_DIR = CWD.resolve("SimpleFileServerTest"); + + static final InetSocketAddress LOOPBACK_ADDR = new InetSocketAddress(InetAddress.getLoopbackAddress(), 0); + + static final boolean ENABLE_LOGGING = true; + static final Logger LOGGER = Logger.getLogger("com.sun.net.httpserver"); + + @BeforeTest + public void setup() throws IOException { + if (ENABLE_LOGGING) { + ConsoleHandler ch = new ConsoleHandler(); + LOGGER.setLevel(Level.ALL); + ch.setLevel(Level.ALL); + LOGGER.addHandler(ch); + } + if (Files.exists(TEST_DIR)) { + FileUtils.deleteFileTreeWithRetry(TEST_DIR); + } + Files.createDirectories(TEST_DIR); + } + + @Test + public void testFileGET() throws Exception { + var root = Files.createDirectory(TEST_DIR.resolve("testFileGET")); + var file = Files.writeString(root.resolve("aFile.txt"), "some text", CREATE); + var lastModified = getLastModified(file); + var expectedLength = Long.toString(Files.size(file)); + + var server = SimpleFileServer.createFileServer(LOOPBACK_ADDR, root, OutputLevel.VERBOSE); + server.start(); + try { + var client = HttpClient.newBuilder().proxy(NO_PROXY).build(); + var request = HttpRequest.newBuilder(uri(server, "aFile.txt")).build(); + var response = client.send(request, BodyHandlers.ofString()); + assertEquals(response.statusCode(), 200); + assertEquals(response.body(), "some text"); + assertEquals(response.headers().firstValue("content-type").get(), "text/plain"); + assertEquals(response.headers().firstValue("content-length").get(), expectedLength); + assertEquals(response.headers().firstValue("last-modified").get(), lastModified); + } finally { + server.stop(0); + } + } + + @Test + public void testDirectoryGET() throws Exception { + var expectedBody = openHTML + """ +

      Directory listing for /

      + + """ + closeHTML; + var expectedLength = Integer.toString(expectedBody.getBytes(UTF_8).length); + var root = Files.createDirectory(TEST_DIR.resolve("testDirectoryGET")); + var file = Files.writeString(root.resolve("aFile.txt"), "some text", CREATE); + var lastModified = getLastModified(root); + + var server = SimpleFileServer.createFileServer(LOOPBACK_ADDR, root, OutputLevel.VERBOSE); + server.start(); + try { + var client = HttpClient.newBuilder().proxy(NO_PROXY).build(); + var request = HttpRequest.newBuilder(uri(server, "")).build(); + var response = client.send(request, BodyHandlers.ofString()); + assertEquals(response.statusCode(), 200); + assertEquals(response.headers().firstValue("content-type").get(), "text/html; charset=UTF-8"); + assertEquals(response.headers().firstValue("content-length").get(), expectedLength); + assertEquals(response.headers().firstValue("last-modified").get(), lastModified); + assertEquals(response.body(), expectedBody); + } finally { + server.stop(0); + } + } + + @Test + public void testFileHEAD() throws Exception { + var root = Files.createDirectory(TEST_DIR.resolve("testFileHEAD")); + var file = Files.writeString(root.resolve("aFile.txt"), "some text", CREATE); + var lastModified = getLastModified(file); + var expectedLength = Long.toString(Files.size(file)); + + var server = SimpleFileServer.createFileServer(LOOPBACK_ADDR, root, OutputLevel.VERBOSE); + server.start(); + try { + var client = HttpClient.newBuilder().proxy(NO_PROXY).build(); + var request = HttpRequest.newBuilder(uri(server, "aFile.txt")) + .method("HEAD", BodyPublishers.noBody()).build(); + var response = client.send(request, BodyHandlers.ofString()); + assertEquals(response.statusCode(), 200); + assertEquals(response.headers().firstValue("content-type").get(), "text/plain"); + assertEquals(response.headers().firstValue("content-length").get(), expectedLength); + assertEquals(response.headers().firstValue("last-modified").get(), lastModified); + assertEquals(response.body(), ""); + } finally { + server.stop(0); + } + } + + @Test + public void testDirectoryHEAD() throws Exception { + var expectedLength = Integer.toString( + (openHTML + """ +

      Directory listing for /

      + + """ + closeHTML).getBytes(UTF_8).length); + var root = Files.createDirectory(TEST_DIR.resolve("testDirectoryHEAD")); + var file = Files.writeString(root.resolve("aFile.txt"), "some text", CREATE); + var lastModified = getLastModified(root); + + var server = SimpleFileServer.createFileServer(LOOPBACK_ADDR, root, OutputLevel.VERBOSE); + server.start(); + try { + var client = HttpClient.newBuilder().proxy(NO_PROXY).build(); + var request = HttpRequest.newBuilder(uri(server, "")) + .method("HEAD", BodyPublishers.noBody()).build(); + var response = client.send(request, BodyHandlers.ofString()); + assertEquals(response.statusCode(), 200); + assertEquals(response.headers().firstValue("content-type").get(), "text/html; charset=UTF-8"); + assertEquals(response.headers().firstValue("content-length").get(), expectedLength); + assertEquals(response.headers().firstValue("last-modified").get(), lastModified); + assertEquals(response.body(), ""); + } finally { + server.stop(0); + } + } + + @DataProvider + public Object[][] indexFiles() { + var fileContent = openHTML + """ +

      This is an index file

      + """ + closeHTML; + var dirListing = openHTML + """ +

      Directory listing for /

      +
        +
      + """ + closeHTML; + return new Object[][] { + {"1", "index.html", "text/html", "116", fileContent, true}, + {"2", "index.htm", "text/html", "116", fileContent, true}, + {"3", "index.txt", "text/html; charset=UTF-8", "134", dirListing, false} + }; + } + + @Test(dataProvider = "indexFiles") + public void testDirectoryWithIndexGET(String id, + String filename, + String contentType, + String contentLength, + String expectedBody, + boolean serveIndexFile) throws Exception { + var root = Files.createDirectories(TEST_DIR.resolve("testDirectoryWithIndexGET"+id)); + var lastModified = getLastModified(root); + if (serveIndexFile) { + var file = Files.writeString(root.resolve(filename), expectedBody, CREATE); + lastModified = getLastModified(file); + } + + var server = SimpleFileServer.createFileServer(LOOPBACK_ADDR, root, OutputLevel.VERBOSE); + server.start(); + try { + var client = HttpClient.newBuilder().proxy(NO_PROXY).build(); + var request = HttpRequest.newBuilder(uri(server, "")).build(); + var response = client.send(request, BodyHandlers.ofString()); + assertEquals(response.statusCode(), 200); + assertEquals(response.headers().firstValue("content-type").get(), contentType); + assertEquals(response.headers().firstValue("content-length").get(), contentLength); + assertEquals(response.headers().firstValue("last-modified").get(), lastModified); + assertEquals(response.body(), expectedBody); + } finally { + server.stop(0); + if (serveIndexFile) { + Files.delete(root.resolve(filename)); + } + } + } + + @Test + public void testNotReadableFileGET() throws Exception { + if (!Platform.isWindows()) { // not applicable on Windows + var expectedBody = openHTML + """ +

      File not found

      +

      /aFile.txt

      + """ + closeHTML; + var expectedLength = Integer.toString(expectedBody.getBytes(UTF_8).length); + var root = Files.createDirectory(TEST_DIR.resolve("testNotReadableFileGET")); + var file = Files.writeString(root.resolve("aFile.txt"), "some text", CREATE); + + file.toFile().setReadable(false, false); + assert !Files.isReadable(file); + + var server = SimpleFileServer.createFileServer(LOOPBACK_ADDR, root, OutputLevel.VERBOSE); + server.start(); + try { + var client = HttpClient.newBuilder().proxy(NO_PROXY).build(); + var request = HttpRequest.newBuilder(uri(server, "aFile.txt")).build(); + var response = client.send(request, BodyHandlers.ofString()); + assertEquals(response.statusCode(), 404); + assertEquals(response.headers().firstValue("content-length").get(), expectedLength); + assertEquals(response.body(), expectedBody); + } finally { + server.stop(0); + file.toFile().setReadable(true, false); + } + } + } + + @Test + public void testNotReadableSegmentGET() throws Exception { + if (!Platform.isWindows()) { // not applicable on Windows + var expectedBody = openHTML + """ +

      File not found

      +

      /dir/aFile.txt

      + """ + closeHTML; + var expectedLength = Integer.toString(expectedBody.getBytes(UTF_8).length); + var root = Files.createDirectory(TEST_DIR.resolve("testNotReadableSegmentGET")); + var dir = Files.createDirectory(root.resolve("dir")); + var file = Files.writeString(dir.resolve("aFile.txt"), "some text", CREATE); + + dir.toFile().setReadable(false, false); + assert !Files.isReadable(dir); + assert Files.isReadable(file); + + var server = SimpleFileServer.createFileServer(LOOPBACK_ADDR, root, OutputLevel.VERBOSE); + server.start(); + try { + var client = HttpClient.newBuilder().proxy(NO_PROXY).build(); + var request = HttpRequest.newBuilder(uri(server, "dir/aFile.txt")).build(); + var response = client.send(request, BodyHandlers.ofString()); + assertEquals(response.statusCode(), 404); + assertEquals(response.headers().firstValue("content-length").get(), expectedLength); + assertEquals(response.body(), expectedBody); + } finally { + server.stop(0); + dir.toFile().setReadable(true, false); + } + } + } + + @Test + public void testInvalidRequestURIGET() throws Exception { + var expectedBody = openHTML + """ +

      File not found

      +

      /aFile?#.txt

      + """ + closeHTML; + var expectedLength = Integer.toString(expectedBody.getBytes(UTF_8).length); + var root = Files.createDirectory(TEST_DIR.resolve("testInvalidRequestURIGET")); + + var server = SimpleFileServer.createFileServer(LOOPBACK_ADDR, root, OutputLevel.VERBOSE); + server.start(); + try { + var client = HttpClient.newBuilder().proxy(NO_PROXY).build(); + var request = HttpRequest.newBuilder(uri(server, "aFile?#.txt")).build(); + var response = client.send(request, BodyHandlers.ofString()); + assertEquals(response.statusCode(), 404); + assertEquals(response.headers().firstValue("content-length").get(), expectedLength); + assertEquals(response.body(), expectedBody); + } finally { + server.stop(0); + } + } + + @Test + public void testNotFoundGET() throws Exception { + var expectedBody = openHTML + """ +

      File not found

      +

      /doesNotExist.txt

      + """ + closeHTML; + var expectedLength = Integer.toString(expectedBody.getBytes(UTF_8).length); + var root = Files.createDirectory(TEST_DIR.resolve("testNotFoundGET")); + + var server = SimpleFileServer.createFileServer(LOOPBACK_ADDR, root, OutputLevel.VERBOSE); + server.start(); + try { + var client = HttpClient.newBuilder().proxy(NO_PROXY).build(); + var request = HttpRequest.newBuilder(uri(server, "doesNotExist.txt")).build(); + var response = client.send(request, BodyHandlers.ofString()); + assertEquals(response.statusCode(), 404); + assertEquals(response.headers().firstValue("content-length").get(), expectedLength); + assertEquals(response.body(), expectedBody); + } finally { + server.stop(0); + } + } + + @Test + public void testNotFoundHEAD() throws Exception { + var expectedBody = openHTML + """ +

      File not found

      +

      /doesNotExist.txt

      + """ + closeHTML; + var expectedLength = Integer.toString(expectedBody.getBytes(UTF_8).length); + var root = Files.createDirectory(TEST_DIR.resolve("testNotFoundHEAD")); + + var server = SimpleFileServer.createFileServer(LOOPBACK_ADDR, root, OutputLevel.VERBOSE); + server.start(); + try { + var client = HttpClient.newBuilder().proxy(NO_PROXY).build(); + var request = HttpRequest.newBuilder(uri(server, "doesNotExist.txt")) + .method("HEAD", BodyPublishers.noBody()).build(); + var response = client.send(request, BodyHandlers.ofString()); + assertEquals(response.statusCode(), 404); + assertEquals(response.headers().firstValue("content-length").get(), expectedLength); + assertEquals(response.body(), ""); + } finally { + server.stop(0); + } + } + + @Test + public void testSymlinkGET() throws Exception { + var expectedBody = openHTML + """ +

      File not found

      +

      /symlink

      + """ + closeHTML; + var expectedLength = Integer.toString(expectedBody.getBytes(UTF_8).length); + var root = Files.createDirectory(TEST_DIR.resolve("testSymlinkGET")); + var symlink = root.resolve("symlink"); + var target = Files.writeString(root.resolve("target.txt"), "some text", CREATE); + Files.createSymbolicLink(symlink, target); + + var server = SimpleFileServer.createFileServer(LOOPBACK_ADDR, root, OutputLevel.VERBOSE); + server.start(); + try { + var client = HttpClient.newBuilder().proxy(NO_PROXY).build(); + var request = HttpRequest.newBuilder(uri(server, "symlink")).build(); + var response = client.send(request, BodyHandlers.ofString()); + assertEquals(response.statusCode(), 404); + assertEquals(response.headers().firstValue("content-length").get(), expectedLength); + assertEquals(response.body(), expectedBody); + } finally { + server.stop(0); + } + } + + @Test + public void testSymlinkSegmentGET() throws Exception { + var expectedBody = openHTML + """ +

      File not found

      +

      /symlink/aFile.txt

      + """ + closeHTML; + var expectedLength = Integer.toString(expectedBody.getBytes(UTF_8).length); + var root = Files.createDirectory(TEST_DIR.resolve("testSymlinkSegmentGET")); + var symlink = root.resolve("symlink"); + var target = Files.createDirectory(root.resolve("target")); + Files.writeString(target.resolve("aFile.txt"), "some text", CREATE); + Files.createSymbolicLink(symlink, target); + + var server = SimpleFileServer.createFileServer(LOOPBACK_ADDR, root, OutputLevel.VERBOSE); + server.start(); + try { + var client = HttpClient.newBuilder().proxy(NO_PROXY).build(); + var request = HttpRequest.newBuilder(uri(server, "symlink/aFile.txt")).build(); + var response = client.send(request, BodyHandlers.ofString()); + assertEquals(response.statusCode(), 404); + assertEquals(response.headers().firstValue("content-length").get(), expectedLength); + assertEquals(response.body(), expectedBody); + } finally { + server.stop(0); + } + } + + @Test + public void testHiddenFileGET() throws Exception { + var root = Files.createDirectory(TEST_DIR.resolve("testHiddenFileGET")); + var file = createHiddenFile(root); + var fileName = file.getFileName().toString(); + var expectedBody = openHTML + """ +

      File not found

      +

      /""" + fileName + + """ +

      + """ + closeHTML; + var expectedLength = Integer.toString(expectedBody.getBytes(UTF_8).length); + + var server = SimpleFileServer.createFileServer(LOOPBACK_ADDR, root, OutputLevel.VERBOSE); + server.start(); + try { + var client = HttpClient.newBuilder().proxy(NO_PROXY).build(); + var request = HttpRequest.newBuilder(uri(server, fileName)).build(); + var response = client.send(request, BodyHandlers.ofString()); + assertEquals(response.statusCode(), 404); + assertEquals(response.headers().firstValue("content-length").get(), expectedLength); + assertEquals(response.body(), expectedBody); + } finally { + server.stop(0); + } + } + + @Test + public void testHiddenSegmentGET() throws Exception { + var root = Files.createDirectory(TEST_DIR.resolve("testHiddenSegmentGET")); + var file = createFileInHiddenDirectory(root); + var expectedBody = openHTML + """ +

      File not found

      +

      /.hiddenDirectory/aFile.txt

      + """ + closeHTML; + var expectedLength = Integer.toString(expectedBody.getBytes(UTF_8).length); + + var server = SimpleFileServer.createFileServer(LOOPBACK_ADDR, root, OutputLevel.VERBOSE); + server.start(); + try { + var client = HttpClient.newBuilder().proxy(NO_PROXY).build(); + var request = HttpRequest.newBuilder(uri(server, ".hiddenDirectory/aFile.txt")).build(); + var response = client.send(request, BodyHandlers.ofString()); + assertEquals(response.statusCode(), 404); + assertEquals(response.headers().firstValue("content-length").get(), expectedLength); + assertEquals(response.body(), expectedBody); + } finally { + server.stop(0); + } + } + + private Path createHiddenFile(Path root) throws IOException { + Path file; + if (Platform.isWindows()) { + file = Files.createFile(root.resolve("aFile.txt")); + Files.setAttribute(file, "dos:hidden", true, LinkOption.NOFOLLOW_LINKS); + } else { + file = Files.writeString(root.resolve(".aFile.txt"), "some text", CREATE); + } + assertTrue(Files.isHidden(file)); + return file; + } + + private Path createFileInHiddenDirectory(Path root) throws IOException { + Path dir; + Path file; + if (Platform.isWindows()) { + dir = Files.createDirectory(root.resolve("hiddenDirectory")); + Files.setAttribute(dir, "dos:hidden", true, LinkOption.NOFOLLOW_LINKS); + } else { + dir = Files.createDirectory(root.resolve(".hiddenDirectory")); + } + file = Files.writeString(dir.resolve("aFile.txt"), "some text", CREATE); + assertTrue(Files.isHidden(dir)); + assertFalse(Files.isHidden(file)); + return file; + } + + @Test + public void testMovedPermanently() throws Exception { + var root = Files.createDirectory(TEST_DIR.resolve("testMovedPermanently")); + Files.createDirectory(root.resolve("aDirectory")); + var expectedBody = openHTML + """ +

      Directory listing for /aDirectory/

      +
        +
      + """ + closeHTML; + var expectedLength = Integer.toString(expectedBody.getBytes(UTF_8).length); + + var server = SimpleFileServer.createFileServer(LOOPBACK_ADDR, root, OutputLevel.VERBOSE); + server.start(); + try { + { + var client = HttpClient.newBuilder().proxy(NO_PROXY) + .followRedirects(HttpClient.Redirect.NEVER).build(); + var uri = uri(server, "aDirectory"); + var request = HttpRequest.newBuilder(uri).build(); + var response = client.send(request, BodyHandlers.ofString()); + assertEquals(response.statusCode(), 301); + assertEquals(response.headers().firstValue("content-length").get(), "0"); + assertEquals(response.headers().firstValue("location").get(), "/aDirectory/"); + + // tests that query component is preserved during redirect + var uri2 = uri(server, "aDirectory", "query"); + var req2 = HttpRequest.newBuilder(uri2).build(); + var res2 = client.send(req2, BodyHandlers.ofString()); + assertEquals(res2.statusCode(), 301); + assertEquals(res2.headers().firstValue("content-length").get(), "0"); + assertEquals(res2.headers().firstValue("location").get(), "/aDirectory/?query"); + } + + { // tests that redirect to returned relative URI works + var client = HttpClient.newBuilder().proxy(NO_PROXY) + .followRedirects(HttpClient.Redirect.ALWAYS).build(); + var uri = uri(server, "aDirectory"); + var request = HttpRequest.newBuilder(uri).build(); + var response = client.send(request, BodyHandlers.ofString()); + assertEquals(response.statusCode(), 200); + assertEquals(response.body(), expectedBody); + assertEquals(response.headers().firstValue("content-type").get(), "text/html; charset=UTF-8"); + assertEquals(response.headers().firstValue("content-length").get(), expectedLength); + } + } finally { + server.stop(0); + } + } + + @Test + public void testNull() { + final var addr = InetSocketAddress.createUnresolved("foo", 8080); + final var path = Path.of("/tmp"); + final var levl = OutputLevel.INFO; + assertThrows(NPE, () -> SimpleFileServer.createFileServer(null, null, null)); + assertThrows(NPE, () -> SimpleFileServer.createFileServer(null, null, levl)); + assertThrows(NPE, () -> SimpleFileServer.createFileServer(null, path, null)); + assertThrows(NPE, () -> SimpleFileServer.createFileServer(null, path, levl)); + assertThrows(NPE, () -> SimpleFileServer.createFileServer(addr, null, null)); + assertThrows(NPE, () -> SimpleFileServer.createFileServer(addr, null, levl)); + assertThrows(NPE, () -> SimpleFileServer.createFileServer(addr, path, null)); + + assertThrows(NPE, () -> SimpleFileServer.createFileHandler(null)); + + assertThrows(NPE, () -> SimpleFileServer.createOutputFilter(null, null)); + assertThrows(NPE, () -> SimpleFileServer.createOutputFilter(null, levl)); + assertThrows(NPE, () -> SimpleFileServer.createOutputFilter(System.out, null)); + } + + @Test + public void testInitialSlashContext() { + var server = SimpleFileServer.createFileServer(LOOPBACK_ADDR, TEST_DIR, OutputLevel.INFO); + server.removeContext("/"); // throws if no context + server.stop(0); + } + + @Test + public void testBound() { + var server = SimpleFileServer.createFileServer(LOOPBACK_ADDR, TEST_DIR, OutputLevel.INFO); + var boundAddr = server.getAddress(); + server.stop(0); + assertTrue(boundAddr.getAddress() != null); + assertTrue(boundAddr.getPort() > 0); + } + + @Test + public void testIllegalPath() throws Exception { + var addr = LOOPBACK_ADDR; + { // not absolute + Path p = Path.of("."); + assert Files.isDirectory(p); + assert Files.exists(p); + assert !p.isAbsolute(); + var iae = expectThrows(IAE, () -> SimpleFileServer.createFileServer(addr, p, OutputLevel.INFO)); + assertTrue(iae.getMessage().contains("is not absolute")); + } + { // not a directory + Path p = Files.createFile(TEST_DIR.resolve("aFile")); + assert !Files.isDirectory(p); + var iae = expectThrows(IAE, () -> SimpleFileServer.createFileServer(addr, p, OutputLevel.INFO)); + assertTrue(iae.getMessage().contains("not a directory")); + } + { // does not exist + Path p = TEST_DIR.resolve("doesNotExist"); + assert !Files.exists(p); + var iae = expectThrows(IAE, () -> SimpleFileServer.createFileServer(addr, p, OutputLevel.INFO)); + assertTrue(iae.getMessage().contains("does not exist")); + } + { // not readable + if (!Platform.isWindows()) { // not applicable on Windows + Path p = Files.createDirectory(TEST_DIR.resolve("aDir")); + p.toFile().setReadable(false, false); + assert !Files.isReadable(p); + try { + var iae = expectThrows(IAE, () -> SimpleFileServer.createFileServer(addr, p, OutputLevel.INFO)); + assertTrue(iae.getMessage().contains("not readable")); + } finally { + p.toFile().setReadable(true, false); + } + } + } + } + + @Test + public void testUncheckedIOException() { + var addr = InetSocketAddress.createUnresolved("foo", 8080); + assertThrows(UIOE, () -> SimpleFileServer.createFileServer(addr, TEST_DIR, OutputLevel.INFO)); + assertThrows(UIOE, () -> SimpleFileServer.createFileServer(addr, TEST_DIR, OutputLevel.VERBOSE)); + } + + @Test + public void testXss() throws Exception { + var root = Files.createDirectory(TEST_DIR.resolve("testXss")); + + var server = SimpleFileServer.createFileServer(LOOPBACK_ADDR, root, OutputLevel.VERBOSE); + server.start(); + try { + var client = HttpClient.newBuilder().proxy(NO_PROXY).build(); + var request = HttpRequest.newBuilder(uri(server, "beginDelim%3C%3EEndDelim")).build(); + var response = client.send(request, BodyHandlers.ofString()); + assertEquals(response.statusCode(), 404); + assertTrue(response.body().contains("beginDelim%3C%3EEndDelim")); + assertTrue(response.body().contains("File not found")); + } finally { + server.stop(0); + } + } + + @AfterTest + public void teardown() throws IOException { + if (Files.exists(TEST_DIR)) { + FileUtils.deleteFileTreeWithRetry(TEST_DIR); + } + } + + static final String openHTML = """ + + + + + + + """; + + static final String closeHTML = """ + + + """; + + static URI uri(HttpServer server, String path) { + return URIBuilder.newBuilder() + .host("localhost") + .port(server.getAddress().getPort()) + .scheme("http") + .path("/" + path) + .buildUnchecked(); + } + + static URI uri(HttpServer server, String path, String query) { + return URIBuilder.newBuilder() + .host("localhost") + .port(server.getAddress().getPort()) + .scheme("http") + .path("/" + path) + .query(query) + .buildUnchecked(); + } + + static String getLastModified(Path path) throws IOException { + return Files.getLastModifiedTime(path).toInstant().atZone(ZoneId.of("GMT")) + .format(DateTimeFormatter.RFC_1123_DATE_TIME); + } +} diff --git a/test/jdk/com/sun/net/httpserver/simpleserver/StressDirListings.java b/test/jdk/com/sun/net/httpserver/simpleserver/StressDirListings.java new file mode 100644 index 00000000000..0ef6904e13d --- /dev/null +++ b/test/jdk/com/sun/net/httpserver/simpleserver/StressDirListings.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Test to stress directory listings + * @library /test/lib + * @run testng/othervm StressDirListings + */ + +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse.BodyHandlers; +import java.nio.file.Path; +import java.util.logging.ConsoleHandler; +import java.util.logging.Level; +import java.util.logging.Logger; +import com.sun.net.httpserver.HttpServer; +import com.sun.net.httpserver.SimpleFileServer; +import com.sun.net.httpserver.SimpleFileServer.OutputLevel; +import jdk.test.lib.net.URIBuilder; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; +import static java.lang.System.out; +import static java.net.http.HttpClient.Builder.NO_PROXY; +import static org.testng.Assert.assertEquals; + +public class StressDirListings { + + static final Path CWD = Path.of(".").toAbsolutePath(); + static final InetSocketAddress LOOPBACK_ADDR = new InetSocketAddress(InetAddress.getLoopbackAddress(), 0); + + static final boolean ENABLE_LOGGING = false; + static final Logger LOGGER = Logger.getLogger("com.sun.net.httpserver"); + + HttpServer simpleFileServer; + + @BeforeTest + public void setup() throws IOException { + if (ENABLE_LOGGING) { + ConsoleHandler ch = new ConsoleHandler(); + LOGGER.setLevel(Level.ALL); + ch.setLevel(Level.ALL); + LOGGER.addHandler(ch); + } + simpleFileServer = SimpleFileServer.createFileServer(LOOPBACK_ADDR, CWD, OutputLevel.VERBOSE); + simpleFileServer.start(); + } + + @AfterTest + public void teardown() { + simpleFileServer.stop(0); + } + + // Enough to trigger FileSystemException: Too many open files (machine dependent) + static final int TIMES = 11_000; + + /** + * Issues a large number of identical GET requests sequentially, each of + * which returns the root directory listing. An IOException will be thrown + * if the server does not issue a valid reply, e.g. the server logic that + * enumerates the directory files fails to close the stream from Files::list. + */ + @Test + public void testDirListings() throws Exception { + var client = HttpClient.newBuilder().proxy(NO_PROXY).build(); + var request = HttpRequest.newBuilder(uri(simpleFileServer)).build(); + for (int i=0; iDirectory listing for / +
        +
      + """ + closeHTML; + var expectedLength = Integer.toString(expectedBody.getBytes(UTF_8).length); + var root = createZipFs(TEST_DIR.resolve("testDirectoryGET.zip")); + var lastModified = getLastModified(root); + + var server = SimpleFileServer.createFileServer(LOOPBACK_ADDR, root, OutputLevel.VERBOSE); + server.start(); + try { + var client = HttpClient.newBuilder().proxy(NO_PROXY).build(); + var request = HttpRequest.newBuilder(uri(server, "")).build(); + var response = client.send(request, BodyHandlers.ofString()); + assertEquals(response.statusCode(), 200); + assertEquals(response.headers().firstValue("content-type").get(), "text/html; charset=UTF-8"); + assertEquals(response.headers().firstValue("content-length").get(), expectedLength); + assertEquals(response.headers().firstValue("last-modified").get(), lastModified); + assertEquals(response.body(), expectedBody); + } finally { + server.stop(0); + root.getFileSystem().close(); + Files.deleteIfExists(TEST_DIR.resolve("testDirectoryGET.zip")); + } + } + + @Test + public void testFileHEAD() throws Exception { + var root = createZipFs(TEST_DIR.resolve("testFileHEAD.zip")); + var file = Files.writeString(root.resolve("aFile.txt"), "some text", CREATE); + var lastModified = getLastModified(file); + var expectedLength = Long.toString(Files.size(file)); + + var server = SimpleFileServer.createFileServer(LOOPBACK_ADDR, root, OutputLevel.VERBOSE); + server.start(); + try { + var client = HttpClient.newBuilder().proxy(NO_PROXY).build(); + var request = HttpRequest.newBuilder(uri(server, "aFile.txt")) + .method("HEAD", BodyPublishers.noBody()).build(); + var response = client.send(request, BodyHandlers.ofString()); + assertEquals(response.statusCode(), 200); + assertEquals(response.headers().firstValue("content-type").get(), "text/plain"); + assertEquals(response.headers().firstValue("content-length").get(), expectedLength); + assertEquals(response.headers().firstValue("last-modified").get(), lastModified); + assertEquals(response.body(), ""); + } finally { + server.stop(0); + root.getFileSystem().close(); + Files.deleteIfExists(TEST_DIR.resolve("testFileHEAD.zip")); + } + } + + @Test + public void testDirectoryHEAD() throws Exception { + var expectedLength = Integer.toString( + (openHTML + """ +

      Directory listing for /

      +
        +
      + """ + closeHTML).getBytes(UTF_8).length); + var root = createZipFs(TEST_DIR.resolve("testDirectoryHEAD.zip")); + var lastModified = getLastModified(root); + + var server = SimpleFileServer.createFileServer(LOOPBACK_ADDR, root, OutputLevel.VERBOSE); + server.start(); + try { + var client = HttpClient.newBuilder().proxy(NO_PROXY).build(); + var request = HttpRequest.newBuilder(uri(server, "")) + .method("HEAD", BodyPublishers.noBody()).build(); + var response = client.send(request, BodyHandlers.ofString()); + assertEquals(response.statusCode(), 200); + assertEquals(response.headers().firstValue("content-type").get(), "text/html; charset=UTF-8"); + assertEquals(response.headers().firstValue("content-length").get(), expectedLength); + assertEquals(response.headers().firstValue("last-modified").get(), lastModified); + assertEquals(response.body(), ""); + } finally { + server.stop(0); + root.getFileSystem().close(); + Files.deleteIfExists(TEST_DIR.resolve("testDirectoryHEAD.zip")); + } + } + + @DataProvider + public Object[][] indexFiles() { + var fileContent = openHTML + """ +

      This is an index file

      + """ + closeHTML; + var dirListing = openHTML + """ +

      Directory listing for /

      +
        +
      + """ + closeHTML; + return new Object[][] { + {"1", "index.html", "text/html", "116", fileContent, true}, + {"2", "index.htm", "text/html", "116", fileContent, true}, + {"3", "index.txt", "text/html; charset=UTF-8", "134", dirListing, false} + }; + } + + @Test(dataProvider = "indexFiles") + public void testDirectoryWithIndexGET(String id, + String filename, + String contentType, + String contentLength, + String expectedBody, + boolean serveIndexFile) throws Exception { + var root = createZipFs(TEST_DIR.resolve("testDirectoryWithIndexGET"+id+".zip")); + var lastModified = getLastModified(root); + if (serveIndexFile) { + var file = Files.writeString(root.resolve(filename), expectedBody, CREATE); + lastModified = getLastModified(file); + } + + var server = SimpleFileServer.createFileServer(LOOPBACK_ADDR, root, OutputLevel.VERBOSE); + server.start(); + try { + var client = HttpClient.newBuilder().proxy(NO_PROXY).build(); + var request = HttpRequest.newBuilder(uri(server, "")).build(); + var response = client.send(request, BodyHandlers.ofString()); + assertEquals(response.statusCode(), 200); + assertEquals(response.headers().firstValue("content-type").get(), contentType); + assertEquals(response.headers().firstValue("content-length").get(), contentLength); + assertEquals(response.headers().firstValue("last-modified").get(), lastModified); + assertEquals(response.body(), expectedBody); + } finally { + server.stop(0); + if (serveIndexFile) { + Files.delete(root.resolve(filename)); + } + root.getFileSystem().close(); + Files.deleteIfExists(TEST_DIR.resolve("testDirectoryWithIndexGET"+id+".zip")); + } + } + + // no testNotReadableGET() - Zip file system does not enforce access permissions + // no testSymlinkGET() - Zip file system does not support symlink creation + // no testHiddenFileGET() - Zip file system does not support hidden files + + @Test + public void testInvalidRequestURIGET() throws Exception { + var expectedBody = openHTML + """ +

      File not found

      +

      /aFile?#.txt

      + """ + closeHTML; + var expectedLength = Integer.toString(expectedBody.getBytes(UTF_8).length); + var root = createZipFs(TEST_DIR.resolve("testInvalidRequestURIGET.zip")); + var server = SimpleFileServer.createFileServer(LOOPBACK_ADDR, root, OutputLevel.VERBOSE); + server.start(); + try { + var client = HttpClient.newBuilder().proxy(NO_PROXY).build(); + var request = HttpRequest.newBuilder(uri(server, "aFile?#.txt")).build(); + var response = client.send(request, BodyHandlers.ofString()); + assertEquals(response.statusCode(), 404); + assertEquals(response.headers().firstValue("content-length").get(), expectedLength); + assertEquals(response.body(), expectedBody); + } finally { + server.stop(0); + root.getFileSystem().close(); + Files.deleteIfExists(TEST_DIR.resolve("testInvalidRequestURIGET.zip")); + } + } + + @Test + public void testNotFoundGET() throws Exception { + var expectedBody = openHTML + """ +

      File not found

      +

      /doesNotExist.txt

      + """ + closeHTML; + var expectedLength = Integer.toString(expectedBody.getBytes(UTF_8).length); + var root = createZipFs(TEST_DIR.resolve("testNotFoundGET.zip")); + + var server = SimpleFileServer.createFileServer(LOOPBACK_ADDR, root, OutputLevel.VERBOSE); + server.start(); + try { + var client = HttpClient.newBuilder().proxy(NO_PROXY).build(); + var request = HttpRequest.newBuilder(uri(server, "doesNotExist.txt")).build(); + var response = client.send(request, BodyHandlers.ofString()); + assertEquals(response.statusCode(), 404); + assertEquals(response.headers().firstValue("content-length").get(), expectedLength); + assertEquals(response.body(), expectedBody); + } finally { + server.stop(0); + root.getFileSystem().close(); + Files.deleteIfExists(TEST_DIR.resolve("testNotFoundGET.zip")); + } + } + + @Test + public void testNotFoundHEAD() throws Exception { + var expectedBody = openHTML + """ +

      File not found

      +

      /doesNotExist.txt

      + """ + + closeHTML; + var expectedLength = Integer.toString(expectedBody.getBytes(UTF_8).length); + var root = createZipFs(TEST_DIR.resolve("testNotFoundHEAD.zip")); + + var server = SimpleFileServer.createFileServer(LOOPBACK_ADDR, root, OutputLevel.VERBOSE); + server.start(); + try { + var client = HttpClient.newBuilder().proxy(NO_PROXY).build(); + var request = HttpRequest.newBuilder(uri(server, "doesNotExist.txt")) + .method("HEAD", BodyPublishers.noBody()).build(); + var response = client.send(request, BodyHandlers.ofString()); + assertEquals(response.statusCode(), 404); + assertEquals(response.headers().firstValue("content-length").get(), expectedLength); + assertEquals(response.body(), ""); + } finally { + server.stop(0); + root.getFileSystem().close(); + Files.deleteIfExists(TEST_DIR.resolve("testNotFoundHEAD.zip")); + } + } + + @Test + public void testMovedPermanently() throws Exception { + var root = createZipFs(TEST_DIR.resolve("testMovedPermanently.zip")); + Files.createDirectory(root.resolve("aDirectory")); + + var server = SimpleFileServer.createFileServer(LOOPBACK_ADDR, root, OutputLevel.VERBOSE); + server.start(); + try { + var client = HttpClient.newBuilder().proxy(NO_PROXY).build(); + var uri = uri(server, "aDirectory"); + var request = HttpRequest.newBuilder(uri).build(); + var response = client.send(request, BodyHandlers.ofString()); + assertEquals(response.statusCode(), 301); + assertEquals(response.headers().firstValue("content-length").get(), "0"); + assertEquals(response.headers().firstValue("location").get(), "/aDirectory/"); + } finally { + server.stop(0); + root.getFileSystem().close(); + Files.deleteIfExists(TEST_DIR.resolve("testMovedPermanently.zip")); + } + } + + static Path createZipFs(Path zipFile) throws Exception { + var p = zipFile.toAbsolutePath().normalize(); + var fs = FileSystems.newFileSystem(p, Map.of("create", "true")); + assert fs != FileSystems.getDefault(); + return fs.getPath("/"); // root entry + } + + @Test + public void testXss() throws Exception { + var root = createZipFs(TEST_DIR.resolve("testXss.zip")); + + var server = SimpleFileServer.createFileServer(LOOPBACK_ADDR, root, OutputLevel.VERBOSE); + server.start(); + try { + var client = HttpClient.newBuilder().proxy(NO_PROXY).build(); + var request = HttpRequest.newBuilder(uri(server, "beginDelim%3C%3EEndDelim")).build(); + var response = client.send(request, BodyHandlers.ofString()); + assertEquals(response.statusCode(), 404); + assertTrue(response.body().contains("beginDelim%3C%3EEndDelim")); + assertTrue(response.body().contains("File not found")); + } finally { + server.stop(0); + root.getFileSystem().close(); + Files.deleteIfExists(TEST_DIR.resolve("testXss.zip")); + } + } + + @AfterTest + public void teardown() throws IOException { + if (Files.exists(TEST_DIR)) { + FileUtils.deleteFileTreeWithRetry(TEST_DIR); + } + } + + static final String openHTML = """ + + + + + + + """; + + static final String closeHTML = """ + + + """; + + static URI uri(HttpServer server, String path) { + return URIBuilder.newBuilder() + .host("localhost") + .port(server.getAddress().getPort()) + .scheme("http") + .path("/" + path) + .buildUnchecked(); + } + + static String getLastModified(Path path) throws IOException { + return Files.getLastModifiedTime(path).toInstant().atZone(ZoneId.of("GMT")) + .format(DateTimeFormatter.RFC_1123_DATE_TIME); + } +} -- GitLab From a4491f22533370f481de71b7ddc8f6105fa2d414 Mon Sep 17 00:00:00 2001 From: Zhengyu Gu Date: Tue, 19 Oct 2021 12:00:30 +0000 Subject: [PATCH 247/385] 8275413: Remove unused InstanceKlass::set_array_klasses() method Reviewed-by: coleenp --- src/hotspot/share/oops/instanceKlass.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/hotspot/share/oops/instanceKlass.hpp b/src/hotspot/share/oops/instanceKlass.hpp index 8f9d1dca070..61eae5cb5de 100644 --- a/src/hotspot/share/oops/instanceKlass.hpp +++ b/src/hotspot/share/oops/instanceKlass.hpp @@ -393,7 +393,6 @@ class InstanceKlass: public Klass { // array klasses ObjArrayKlass* array_klasses() const { return _array_klasses; } inline ObjArrayKlass* array_klasses_acquire() const; // load with acquire semantics - void set_array_klasses(ObjArrayKlass* k) { _array_klasses = k; } inline void release_set_array_klasses(ObjArrayKlass* k); // store with release semantics // methods -- GitLab From d17d81a8b2a6336f37e17f31413a62c7adf49936 Mon Sep 17 00:00:00 2001 From: Hamlin Li Date: Tue, 19 Oct 2021 12:24:21 +0000 Subject: [PATCH 248/385] 8273626: G1: Factor out concurrent segmented array from G1CardSetAllocator Reviewed-by: tschatzl, ayang --- src/hotspot/share/gc/g1/g1CardSet.cpp | 27 +- src/hotspot/share/gc/g1/g1CardSet.hpp | 12 +- .../share/gc/g1/g1CardSetFreeMemoryTask.hpp | 2 - src/hotspot/share/gc/g1/g1CardSetMemory.cpp | 142 ++--------- src/hotspot/share/gc/g1/g1CardSetMemory.hpp | 149 ++--------- .../share/gc/g1/g1CardSetMemory.inline.hpp | 60 +---- src/hotspot/share/gc/g1/g1SegmentedArray.hpp | 217 ++++++++++++++++ .../share/gc/g1/g1SegmentedArray.inline.hpp | 236 ++++++++++++++++++ 8 files changed, 520 insertions(+), 325 deletions(-) create mode 100644 src/hotspot/share/gc/g1/g1SegmentedArray.hpp create mode 100644 src/hotspot/share/gc/g1/g1SegmentedArray.inline.hpp diff --git a/src/hotspot/share/gc/g1/g1CardSet.cpp b/src/hotspot/share/gc/g1/g1CardSet.cpp index caa9124bd6f..8c40a361dab 100644 --- a/src/hotspot/share/gc/g1/g1CardSet.cpp +++ b/src/hotspot/share/gc/g1/g1CardSet.cpp @@ -65,6 +65,8 @@ G1CardSetConfiguration::G1CardSetConfiguration() : _cards_in_howl_bitmap_threshold = _num_cards_in_howl_bitmap * (double)G1RemSetCoarsenHowlBitmapToHowlFullPercent / 100; _bitmap_hash_mask = ~(~(0) << _log2_num_cards_in_howl_bitmap); + init_card_set_alloc_options(); + log_configuration(); } @@ -89,9 +91,23 @@ G1CardSetConfiguration::G1CardSetConfiguration(uint inline_ptr_bits_per_card, _log2_num_cards_in_howl_bitmap = log2i_exact(_num_cards_in_howl_bitmap); _bitmap_hash_mask = ~(~(0) << _log2_num_cards_in_howl_bitmap); + init_card_set_alloc_options(); + log_configuration(); } +G1CardSetConfiguration::~G1CardSetConfiguration() { + FREE_C_HEAP_ARRAY(size_t, _card_set_alloc_options); +} + +void G1CardSetConfiguration::init_card_set_alloc_options() { + _card_set_alloc_options = NEW_C_HEAP_ARRAY(G1CardSetAllocOptions, num_mem_object_types(), mtGC); + new (&_card_set_alloc_options[0]) G1CardSetAllocOptions((uint)CardSetHash::get_node_size()); + new (&_card_set_alloc_options[1]) G1CardSetAllocOptions((uint)G1CardSetArray::size_in_bytes(_num_cards_in_array), 2, 256); + new (&_card_set_alloc_options[2]) G1CardSetAllocOptions((uint)G1CardSetBitMap::size_in_bytes(_num_cards_in_howl_bitmap), 2, 256); + new (&_card_set_alloc_options[3]) G1CardSetAllocOptions((uint)G1CardSetHowl::size_in_bytes(_num_buckets_in_howl), 2, 256); +} + void G1CardSetConfiguration::log_configuration() { log_debug_p(gc, remset)("Card Set container configuration: " "InlinePtr #elems %u size %zu " @@ -112,15 +128,8 @@ uint G1CardSetConfiguration::num_cards_in_inline_ptr(uint bits_per_card) { return G1CardSetInlinePtr::max_cards_in_inline_ptr(bits_per_card); } -G1CardSetAllocOptions* G1CardSetConfiguration::mem_object_alloc_options() { - G1CardSetAllocOptions* result = NEW_C_HEAP_ARRAY(G1CardSetAllocOptions, num_mem_object_types(), mtGC); - - result[0] = { (uint)CardSetHash::get_node_size() }; - result[1] = { (uint)G1CardSetArray::size_in_bytes(num_cards_in_array()), 2, 256 }; - result[2] = { (uint)G1CardSetBitMap::size_in_bytes(num_cards_in_howl_bitmap()), 2, 256 }; - result[3] = { (uint)G1CardSetHowl::size_in_bytes(num_buckets_in_howl()), 2, 256 }; - - return result; +const G1CardSetAllocOptions* G1CardSetConfiguration::mem_object_alloc_options(uint idx) { + return &_card_set_alloc_options[idx]; } const char* G1CardSetConfiguration::mem_object_type_name_str(uint index) { diff --git a/src/hotspot/share/gc/g1/g1CardSet.hpp b/src/hotspot/share/gc/g1/g1CardSet.hpp index 5220c2ce272..c2a533d42a0 100644 --- a/src/hotspot/share/gc/g1/g1CardSet.hpp +++ b/src/hotspot/share/gc/g1/g1CardSet.hpp @@ -32,7 +32,6 @@ #include "utilities/lockFreeStack.hpp" class G1CardSetAllocOptions; -class G1CardSetBufferList; class G1CardSetHashTable; class G1CardSetHashTableValue; class G1CardSetMemoryManager; @@ -60,6 +59,10 @@ class G1CardSetConfiguration { uint _log2_num_cards_in_howl_bitmap; size_t _bitmap_hash_mask; + G1CardSetAllocOptions* _card_set_alloc_options; + + void init_card_set_alloc_options(); + void log_configuration(); public: @@ -73,6 +76,8 @@ public: double cards_in_howl_threshold, uint max_cards_in_cardset); + ~G1CardSetConfiguration(); + // Inline pointer configuration uint inline_ptr_bits_per_card() const { return _inline_ptr_bits_per_card; } uint num_cards_in_inline_ptr() const; @@ -108,9 +113,8 @@ public: // Number of distinctly sized memory objects on the card set heap. // Currently contains CHT-Nodes, ArrayOfCards, BitMaps, Howl static constexpr uint num_mem_object_types() { return 4; } - // Returns the memory allocation options for the memory objects on the card set heap. The returned - // array must be freed by the caller. - G1CardSetAllocOptions* mem_object_alloc_options(); + // Returns the memory allocation options for the memory objects on the card set heap. + const G1CardSetAllocOptions* mem_object_alloc_options(uint idx); // For a given memory object, get a descriptive name. static const char* mem_object_type_name_str(uint index); diff --git a/src/hotspot/share/gc/g1/g1CardSetFreeMemoryTask.hpp b/src/hotspot/share/gc/g1/g1CardSetFreeMemoryTask.hpp index b0c0864f9f5..3d617243aa4 100644 --- a/src/hotspot/share/gc/g1/g1CardSetFreeMemoryTask.hpp +++ b/src/hotspot/share/gc/g1/g1CardSetFreeMemoryTask.hpp @@ -31,8 +31,6 @@ #include "utilities/growableArray.hpp" #include "utilities/ticks.hpp" -class G1CardSetBuffer; - // Task handling deallocation of free card set memory. class G1CardSetFreeMemoryTask : public G1ServiceTask { diff --git a/src/hotspot/share/gc/g1/g1CardSetMemory.cpp b/src/hotspot/share/gc/g1/g1CardSetMemory.cpp index ae14e555774..72ab11c518a 100644 --- a/src/hotspot/share/gc/g1/g1CardSetMemory.cpp +++ b/src/hotspot/share/gc/g1/g1CardSetMemory.cpp @@ -30,99 +30,20 @@ #include "utilities/formatBuffer.hpp" #include "utilities/ostream.hpp" -G1CardSetBuffer::G1CardSetBuffer(uint elem_size, uint num_instances, G1CardSetBuffer* next) : - _elem_size(elem_size), _num_elems(num_instances), _next(next), _next_allocate(0) { - - _buffer = NEW_C_HEAP_ARRAY(char, (size_t)_num_elems * elem_size, mtGCCardSet); -} - -G1CardSetBuffer::~G1CardSetBuffer() { - FREE_C_HEAP_ARRAY(mtGCCardSet, _buffer); -} - -void* G1CardSetBuffer::get_new_buffer_elem() { - if (_next_allocate >= _num_elems) { - return nullptr; - } - uint result = Atomic::fetch_and_add(&_next_allocate, 1u, memory_order_relaxed); - if (result >= _num_elems) { - return nullptr; - } - void* r = _buffer + (uint)result * _elem_size; - return r; -} - -void G1CardSetBufferList::bulk_add(G1CardSetBuffer& first, G1CardSetBuffer& last, size_t num, size_t mem_size) { - _list.prepend(first, last); - Atomic::add(&_num_buffers, num, memory_order_relaxed); - Atomic::add(&_mem_size, mem_size, memory_order_relaxed); -} - -void G1CardSetBufferList::print_on(outputStream* out, const char* prefix) { - out->print_cr("%s: buffers %zu size %zu", prefix, Atomic::load(&_num_buffers), Atomic::load(&_mem_size)); -} - -G1CardSetBuffer* G1CardSetBufferList::get() { - GlobalCounter::CriticalSection cs(Thread::current()); - - G1CardSetBuffer* result = _list.pop(); - if (result != nullptr) { - Atomic::dec(&_num_buffers, memory_order_relaxed); - Atomic::sub(&_mem_size, result->mem_size(), memory_order_relaxed); - } - return result; -} - -G1CardSetBuffer* G1CardSetBufferList::get_all(size_t& num_buffers, size_t& mem_size) { - GlobalCounter::CriticalSection cs(Thread::current()); - - G1CardSetBuffer* result = _list.pop_all(); - num_buffers = Atomic::load(&_num_buffers); - mem_size = Atomic::load(&_mem_size); - - if (result != nullptr) { - Atomic::sub(&_num_buffers, num_buffers, memory_order_relaxed); - Atomic::sub(&_mem_size, mem_size, memory_order_relaxed); - } - return result; -} - -void G1CardSetBufferList::free_all() { - size_t num_freed = 0; - size_t mem_size_freed = 0; - G1CardSetBuffer* cur; - - while ((cur = _list.pop()) != nullptr) { - mem_size_freed += cur->mem_size(); - num_freed++; - delete cur; - } - - Atomic::sub(&_num_buffers, num_freed, memory_order_relaxed); - Atomic::sub(&_mem_size, mem_size_freed, memory_order_relaxed); -} template G1CardSetAllocator::G1CardSetAllocator(const char* name, - const G1CardSetAllocOptions& buffer_options, + const G1CardSetAllocOptions* buffer_options, G1CardSetBufferList* free_buffer_list) : - _alloc_options(buffer_options), - _first(nullptr), - _last(nullptr), - _num_buffers(0), - _mem_size(0), - _free_buffer_list(free_buffer_list), + _segmented_array(name, buffer_options, free_buffer_list), _transfer_lock(false), _free_nodes_list(), _pending_nodes_list(), _num_pending_nodes(0), - _num_free_nodes(0), - _num_allocated_nodes(0), - _num_available_nodes(0) + _num_free_nodes(0) { - assert(elem_size() >= sizeof(G1CardSetContainer), "Element instance size %u for allocator %s too small", - elem_size(), name); - assert(_free_buffer_list != nullptr, "precondition!"); + uint elem_size = _segmented_array.elem_size(); + assert(elem_size >= sizeof(G1CardSetContainer), "Element instance size %u for allocator %s too small", elem_size, name); } template @@ -164,7 +85,6 @@ bool G1CardSetAllocator::try_transfer_pending() { template void G1CardSetAllocator::free(Elem* elem) { assert(elem != nullptr, "precondition"); - assert(elem_size() >= sizeof(G1CardSetContainer), "size mismatch"); // Desired minimum transfer batch size. There is relatively little // importance to the specific number. It shouldn't be too big, else // we're wasting space when the release rate is low. If the release @@ -192,47 +112,27 @@ template void G1CardSetAllocator::drop_all() { _free_nodes_list.pop_all(); _pending_nodes_list.pop_all(); - G1CardSetBuffer* cur = Atomic::load_acquire(&_first); - - if (cur != nullptr) { - assert(_last != nullptr, "If there is at least one element, there must be a last one."); - - G1CardSetBuffer* first = cur; -#ifdef ASSERT - // Check list consistency. - G1CardSetBuffer* last = cur; - uint num_buffers = 0; - size_t mem_size = 0; - while (cur != nullptr) { - mem_size += cur->mem_size(); - num_buffers++; - - G1CardSetBuffer* next = cur->next(); - last = cur; - cur = next; - } -#endif - assert(num_buffers == _num_buffers, "Buffer count inconsistent %u %u", num_buffers, _num_buffers); - assert(mem_size == _mem_size, "Memory size inconsistent"); - assert(last == _last, "Inconsistent last element"); - - _free_buffer_list->bulk_add(*first, *_last, _num_buffers, _mem_size); - } - - _first = nullptr; - _last = nullptr; - _num_available_nodes = 0; - _num_allocated_nodes = 0; _num_pending_nodes = 0; - _num_buffers = 0; - _mem_size = 0; _num_free_nodes = 0; } template void G1CardSetAllocator::print(outputStream* os) { + uint num_allocated_nodes = _segmented_array.num_allocated_nodes(); + uint num_available_nodes = _segmented_array.num_available_nodes(); + uint highest = _segmented_array.first_array_buffer() != nullptr + ? _segmented_array.first_array_buffer()->num_elems() + : 0; + uint num_buffers = _segmented_array.num_buffers(); os->print("MA " PTR_FORMAT ": %u elems pending (allocated %u available %u) used %.3f highest %u buffers %u size %zu ", - p2i(this), _num_pending_nodes, _num_allocated_nodes, _num_available_nodes, percent_of(_num_allocated_nodes - _num_pending_nodes, _num_available_nodes), _first != nullptr ? _first->num_elems() : 0, _num_buffers, mem_size()); + p2i(this), + _num_pending_nodes, + num_allocated_nodes, + num_available_nodes, + percent_of(num_allocated_nodes - _num_pending_nodes, num_available_nodes), + highest, + num_buffers, + mem_size()); } G1CardSetMemoryStats::G1CardSetMemoryStats() { @@ -411,13 +311,11 @@ G1CardSetMemoryManager::G1CardSetMemoryManager(G1CardSetConfiguration* config, _allocators = NEW_C_HEAP_ARRAY(G1CardSetAllocator, _config->num_mem_object_types(), mtGC); - G1CardSetAllocOptions* alloc_options = _config->mem_object_alloc_options(); for (uint i = 0; i < num_mem_object_types(); i++) { new (&_allocators[i]) G1CardSetAllocator(_config->mem_object_type_name_str(i), - alloc_options[i], + _config->mem_object_alloc_options(i), free_list_pool->free_list(i)); } - FREE_C_HEAP_ARRAY(size_t, alloc_options); } uint G1CardSetMemoryManager::num_mem_object_types() const { diff --git a/src/hotspot/share/gc/g1/g1CardSetMemory.hpp b/src/hotspot/share/gc/g1/g1CardSetMemory.hpp index 4cc03c913b9..c9f29bb674c 100644 --- a/src/hotspot/share/gc/g1/g1CardSetMemory.hpp +++ b/src/hotspot/share/gc/g1/g1CardSetMemory.hpp @@ -27,6 +27,8 @@ #include "gc/g1/g1CardSet.hpp" #include "gc/g1/g1CardSetContainers.hpp" +#include "gc/g1/g1CardSetContainers.inline.hpp" +#include "gc/g1/g1SegmentedArray.hpp" #include "memory/allocation.hpp" #include "utilities/growableArray.hpp" #include "utilities/lockFreeStack.hpp" @@ -36,130 +38,29 @@ class outputStream; // Collects G1CardSetAllocator options/heuristics. Called by G1CardSetAllocator // to determine the next size of the allocated G1CardSetBuffer. -class G1CardSetAllocOptions { - uint _elem_size; - uint _initial_num_elems; - // Defines a limit to the number of elements in the buffer - uint _max_num_elems; - - uint exponential_expand(uint prev_num_elems) { +class G1CardSetAllocOptions : public G1SegmentedArrayAllocOptions { + uint exponential_expand(uint prev_num_elems) const { return clamp(prev_num_elems * 2, _initial_num_elems, _max_num_elems); } public: static const uint BufferAlignment = 8; - static const uint MinimumBufferSize = 8; - static const uint MaximumBufferSize = UINT_MAX / 2; G1CardSetAllocOptions(uint elem_size, uint initial_num_elems = MinimumBufferSize, uint max_num_elems = MaximumBufferSize) : - _elem_size(align_up(elem_size, BufferAlignment)), - _initial_num_elems(initial_num_elems), - _max_num_elems(max_num_elems) { + G1SegmentedArrayAllocOptions(align_up(elem_size, BufferAlignment), initial_num_elems, max_num_elems, BufferAlignment) { } - uint next_num_elems(uint prev_num_elems) { + virtual uint next_num_elems(uint prev_num_elems) const override { return exponential_expand(prev_num_elems); } - - uint elem_size () const {return _elem_size;} -}; - -// A single buffer/arena containing _num_elems blocks of memory of _elem_size. -// G1CardSetBuffers can be linked together using a singly linked list. -class G1CardSetBuffer : public CHeapObj { - uint _elem_size; - uint _num_elems; - - G1CardSetBuffer* volatile _next; - - char* _buffer; // Actual data. - - // Index into the next free block to allocate into. Full if equal (or larger) - // to _num_elems (can be larger because we atomically increment this value and - // check only afterwards if the allocation has been successful). - uint volatile _next_allocate; - -public: - G1CardSetBuffer(uint elem_size, uint num_elems, G1CardSetBuffer* next); - ~G1CardSetBuffer(); - - G1CardSetBuffer* volatile* next_addr() { return &_next; } - - void* get_new_buffer_elem(); - - uint num_elems() const { return _num_elems; } - - G1CardSetBuffer* next() const { return _next; } - - void set_next(G1CardSetBuffer* next) { - assert(next != this, " loop condition"); - _next = next; - } - - void reset(G1CardSetBuffer* next) { - _next_allocate = 0; - assert(next != this, " loop condition"); - set_next(next); - memset((void*)_buffer, 0, (size_t)_num_elems * _elem_size); - } - - uint elem_size() const { return _elem_size; } - - size_t mem_size() const { return sizeof(*this) + (size_t)_num_elems * _elem_size; } - - bool is_full() const { return _next_allocate >= _num_elems; } }; -// Set of (free) G1CardSetBuffers. The assumed usage is that allocation -// to it and removal of elements is strictly separate, but every action may be -// performed by multiple threads at the same time. -// Counts and memory usage are current on a best-effort basis if accessed concurrently. -class G1CardSetBufferList { - static G1CardSetBuffer* volatile* next_ptr(G1CardSetBuffer& node) { - return node.next_addr(); - } - typedef LockFreeStack NodeStack; - - NodeStack _list; +typedef G1SegmentedArrayBuffer G1CardSetBuffer; - volatile size_t _num_buffers; - volatile size_t _mem_size; - -public: - G1CardSetBufferList() : _list(), _num_buffers(0), _mem_size(0) { } - ~G1CardSetBufferList() { free_all(); } - - void bulk_add(G1CardSetBuffer& first, G1CardSetBuffer& last, size_t num, size_t mem_size); - void add(G1CardSetBuffer& elem) { _list.prepend(elem); } - - G1CardSetBuffer* get(); - G1CardSetBuffer* get_all(size_t& num_buffers, size_t& mem_size); - - // Give back all memory to the OS. - void free_all(); - - void print_on(outputStream* out, const char* prefix = ""); - - size_t num_buffers() const { return Atomic::load(&_num_buffers); } - size_t mem_size() const { return Atomic::load(&_mem_size); } -}; +typedef G1SegmentedArrayBufferList G1CardSetBufferList; // Arena-like allocator for (card set) heap memory objects (Elem elements). // -// Actual allocation from the C heap occurs on G1CardSetBuffer basis, i.e. sets -// of elements. The assumed allocation pattern for these G1CardSetBuffer elements -// is assumed to be strictly two-phased: -// -// - in the first phase, G1CardSetBuffers are allocated from the C heap (or a free -// list given at initialization time). This allocation may occur in parallel. This -// typically corresponds to a single mutator phase, but may extend over multiple. -// -// - in the second phase, G1CardSetBuffers are given back in bulk to the free list. -// This is typically done during a GC pause. -// -// Some third party is responsible for giving back memory from the free list to -// the operating system. -// // Allocation and deallocation in the first phase on G1CardSetContainer basis // may occur by multiple threads at once. // @@ -168,7 +69,7 @@ public: // none, this class allocates a new G1CardSetBuffer (allocated from the C heap, // asking the G1CardSetAllocOptions instance about sizes etc) and uses that one. // -// The G1CardSetContainerOnHeaps free list is a linked list of G1CardSetContainers +// The NodeStack free list is a linked list of G1CardSetContainers // within all G1CardSetBuffer instances allocated so far. It uses a separate // pending list and global synchronization to avoid the ABA problem when the // user frees a memory object. @@ -184,24 +85,13 @@ template class G1CardSetAllocator { // G1CardSetBuffer management. - // G1CardSetAllocOptions provides parameters for allocation buffer - // sizing and expansion. - G1CardSetAllocOptions _alloc_options; - - G1CardSetBuffer* volatile _first; // The (start of the) list of all buffers. - G1CardSetBuffer* _last; // The last element of the list of all buffers. - volatile uint _num_buffers; // Number of assigned buffers to this allocator. - volatile size_t _mem_size; // Memory used by all buffers. - - G1CardSetBufferList* _free_buffer_list; // The global free buffer list to - // preferentially get new buffers from. - + typedef G1SegmentedArray SegmentedArray; // G1CardSetContainer node management within the G1CardSetBuffers allocated // by this allocator. - static G1CardSetContainer* volatile* next_ptr(G1CardSetContainer& node); typedef LockFreeStack NodeStack; + SegmentedArray _segmented_array; volatile bool _transfer_lock; NodeStack _free_nodes_list; NodeStack _pending_nodes_list; @@ -209,9 +99,6 @@ class G1CardSetAllocator { volatile uint _num_pending_nodes; // Number of nodes in the pending list. volatile uint _num_free_nodes; // Number of nodes in the free list. - volatile uint _num_allocated_nodes; // Number of total nodes allocated and in use. - volatile uint _num_available_nodes; // Number of nodes available in all buffers (allocated + free + pending + not yet used). - // Try to transfer nodes from _pending_nodes_list to _free_nodes_list, with a // synchronization delay for any in-progress pops from the _free_nodes_list // to solve ABA here. @@ -219,13 +106,9 @@ class G1CardSetAllocator { uint num_free_elems() const; - G1CardSetBuffer* create_new_buffer(G1CardSetBuffer* const prev); - - uint elem_size() const { return _alloc_options.elem_size(); } - public: G1CardSetAllocator(const char* name, - const G1CardSetAllocOptions& buffer_options, + const G1CardSetAllocOptions* buffer_options, G1CardSetBufferList* free_buffer_list); ~G1CardSetAllocator() { drop_all(); @@ -238,17 +121,17 @@ public: // be called in a globally synchronized area. void drop_all(); - uint num_buffers() const; - size_t mem_size() const { return sizeof(*this) + - num_buffers() * sizeof(G1CardSetBuffer) + (size_t)_num_available_nodes * elem_size(); + _segmented_array.num_buffers() * sizeof(G1CardSetBuffer) + _segmented_array.num_available_nodes() * _segmented_array.elem_size(); } size_t wasted_mem_size() const { - return ((size_t)_num_available_nodes - (_num_allocated_nodes - _num_pending_nodes)) * elem_size(); + return (_segmented_array.num_available_nodes() - (_segmented_array.num_allocated_nodes() - _num_pending_nodes)) * _segmented_array.elem_size(); } + inline uint num_buffers() { return _segmented_array.num_buffers(); } + void print(outputStream* os); }; diff --git a/src/hotspot/share/gc/g1/g1CardSetMemory.inline.hpp b/src/hotspot/share/gc/g1/g1CardSetMemory.inline.hpp index 4fd68d5d55a..0eaac226b59 100644 --- a/src/hotspot/share/gc/g1/g1CardSetMemory.inline.hpp +++ b/src/hotspot/share/gc/g1/g1CardSetMemory.inline.hpp @@ -27,6 +27,7 @@ #include "gc/g1/g1CardSetMemory.hpp" #include "gc/g1/g1CardSetContainers.hpp" +#include "gc/g1/g1SegmentedArray.inline.hpp" #include "utilities/ostream.hpp" #include "gc/g1/g1CardSetContainers.inline.hpp" @@ -37,42 +38,9 @@ G1CardSetContainer* volatile* G1CardSetAllocator::next_ptr(G1CardSetContai return node.next_addr(); } -template -G1CardSetBuffer* G1CardSetAllocator::create_new_buffer(G1CardSetBuffer* const prev) { - - // Take an existing buffer if available. - G1CardSetBuffer* next = _free_buffer_list->get(); - if (next == nullptr) { - uint prev_num_elems = (prev != nullptr) ? prev->num_elems() : 0; - uint num_elems = _alloc_options.next_num_elems(prev_num_elems); - next = new G1CardSetBuffer(elem_size(), num_elems, prev); - } else { - assert(elem_size() == next->elem_size() , "Mismatch %d != %d Elem %zu", elem_size(), next->elem_size(), sizeof(Elem)); - next->reset(prev); - } - - // Install it as current allocation buffer. - G1CardSetBuffer* old = Atomic::cmpxchg(&_first, prev, next); - if (old != prev) { - // Somebody else installed the buffer, use that one. - delete next; - return old; - } else { - // Did we install the first element in the list? If so, this is also the last. - if (prev == nullptr) { - _last = next; - } - // Successfully installed the buffer into the list. - Atomic::inc(&_num_buffers, memory_order_relaxed); - Atomic::add(&_mem_size, next->mem_size(), memory_order_relaxed); - Atomic::add(&_num_available_nodes, next->num_elems(), memory_order_relaxed); - return next; - } -} - template Elem* G1CardSetAllocator::allocate() { - assert(elem_size() > 0, "instance size not set."); + assert(_segmented_array.elem_size() > 0, "instance size not set."); if (num_free_elems() > 0) { // Pop under critical section to deal with ABA problem @@ -88,22 +56,9 @@ Elem* G1CardSetAllocator::allocate() { } } - G1CardSetBuffer* cur = Atomic::load_acquire(&_first); - if (cur == nullptr) { - cur = create_new_buffer(cur); - } - - while (true) { - Elem* elem = (Elem*)cur->get_new_buffer_elem(); - if (elem != nullptr) { - Atomic::inc(&_num_allocated_nodes, memory_order_relaxed); - guarantee(is_aligned(elem, 8), "result " PTR_FORMAT " not aligned", p2i(elem)); - return elem; - } - // The buffer is full. Next round. - assert(cur->is_full(), "must be"); - cur = create_new_buffer(cur); - } + Elem* elem = _segmented_array.allocate(); + assert(elem != nullptr, "must be"); + return elem; } inline uint8_t* G1CardSetMemoryManager::allocate(uint type) { @@ -119,11 +74,6 @@ inline void G1CardSetMemoryManager::free_node(void* value) { free(0, value); } -template -inline uint G1CardSetAllocator::num_buffers() const { - return Atomic::load(&_num_buffers); -} - template inline uint G1CardSetAllocator::num_free_elems() const { return Atomic::load(&_num_free_nodes); diff --git a/src/hotspot/share/gc/g1/g1SegmentedArray.hpp b/src/hotspot/share/gc/g1/g1SegmentedArray.hpp new file mode 100644 index 00000000000..62bdd802a12 --- /dev/null +++ b/src/hotspot/share/gc/g1/g1SegmentedArray.hpp @@ -0,0 +1,217 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, Huawei Technologies Co. Ltd. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_GC_G1_G1SEGMENTEDARRAY_HPP +#define SHARE_GC_G1_G1SEGMENTEDARRAY_HPP + +#include "memory/allocation.hpp" +#include "utilities/lockFreeStack.hpp" + +// A single buffer/arena containing _num_elems blocks of memory of _elem_size. +// G1SegmentedArrayBuffers can be linked together using a singly linked list. +template +class G1SegmentedArrayBuffer : public CHeapObj { + const uint _elem_size; + const uint _num_elems; + + G1SegmentedArrayBuffer* volatile _next; + + char* _buffer; // Actual data. + + // Index into the next free block to allocate into. Full if equal (or larger) + // to _num_elems (can be larger because we atomically increment this value and + // check only afterwards if the allocation has been successful). + uint volatile _next_allocate; + +public: + G1SegmentedArrayBuffer(uint elem_size, uint num_elems, G1SegmentedArrayBuffer* next); + ~G1SegmentedArrayBuffer(); + + G1SegmentedArrayBuffer* volatile* next_addr() { return &_next; } + + void* get_new_buffer_elem(); + + uint num_elems() const { return _num_elems; } + + G1SegmentedArrayBuffer* next() const { return _next; } + + void set_next(G1SegmentedArrayBuffer* next) { + assert(next != this, " loop condition"); + _next = next; + } + + void reset(G1SegmentedArrayBuffer* next) { + _next_allocate = 0; + assert(next != this, " loop condition"); + set_next(next); + memset((void*)_buffer, 0, (size_t)_num_elems * _elem_size); + } + + uint elem_size() const { return _elem_size; } + + size_t mem_size() const { return sizeof(*this) + (size_t)_num_elems * _elem_size; } + + bool is_full() const { return _next_allocate >= _num_elems; } +}; + +// Set of (free) G1SegmentedArrayBuffers. The assumed usage is that allocation +// to it and removal of elements is strictly separate, but every action may be +// performed by multiple threads at the same time. +// Counts and memory usage are current on a best-effort basis if accessed concurrently. +template +class G1SegmentedArrayBufferList { + static G1SegmentedArrayBuffer* volatile* next_ptr(G1SegmentedArrayBuffer& node) { + return node.next_addr(); + } + typedef LockFreeStack, &G1SegmentedArrayBufferList::next_ptr> NodeStack; + + NodeStack _list; + + volatile size_t _num_buffers; + volatile size_t _mem_size; + +public: + G1SegmentedArrayBufferList() : _list(), _num_buffers(0), _mem_size(0) { } + ~G1SegmentedArrayBufferList() { free_all(); } + + void bulk_add(G1SegmentedArrayBuffer& first, G1SegmentedArrayBuffer& last, size_t num, size_t mem_size); + void add(G1SegmentedArrayBuffer& elem) { _list.prepend(elem); } + + G1SegmentedArrayBuffer* get(); + G1SegmentedArrayBuffer* get_all(size_t& num_buffers, size_t& mem_size); + + // Give back all memory to the OS. + void free_all(); + + void print_on(outputStream* out, const char* prefix = ""); + + size_t num_buffers() const { return Atomic::load(&_num_buffers); } + size_t mem_size() const { return Atomic::load(&_mem_size); } +}; + +// Configuration for G1SegmentedArray, e.g element size, element number of next G1SegmentedArrayBuffer. +class G1SegmentedArrayAllocOptions { + +protected: + uint _elem_size; + uint _initial_num_elems; + // Defines a limit to the number of elements in the buffer + uint _max_num_elems; + uint _alignment; + + static const uint BufferAlignment = 4; + static const uint MinimumBufferSize = 8; + static const uint MaximumBufferSize = UINT_MAX / 2; + +public: + G1SegmentedArrayAllocOptions(uint elem_size, uint initial_num_elems, uint max_num_elems, uint alignment) : + _elem_size(elem_size), + _initial_num_elems(initial_num_elems), + _max_num_elems(max_num_elems), + _alignment(alignment) { + } + + virtual uint next_num_elems(uint prev_num_elems) const { + return _initial_num_elems; + } + + uint elem_size() const { return _elem_size; } + + uint alignment() const { return _alignment; } +}; + +// A segmented array where G1SegmentedArrayBuffer is the segment, and +// G1SegmentedArrayBufferList is the free list to cache G1SegmentedArrayBuffer, +// and G1SegmentedArrayAllocOptions is the configuration for G1SegmentedArray +// attributes. +// +// Implementation details as below: +// +// Arena-like allocator for (card set, or ...) heap memory objects (Elem elements). +// +// Actual allocation from the C heap occurs on G1SegmentedArrayBuffer basis, i.e. segments +// of elements. The assumed allocation pattern for these G1SegmentedArrayBuffer elements +// is assumed to be strictly two-phased: +// +// - in the first phase, G1SegmentedArrayBuffers are allocated from the C heap (or a free +// list given at initialization time). This allocation may occur in parallel. This +// typically corresponds to a single mutator phase, but may extend over multiple. +// +// - in the second phase, G1SegmentedArrayBuffers are given back in bulk to the free list. +// This is typically done during a GC pause. +// +// Some third party is responsible for giving back memory from the free list to +// the operating system. +// +// Allocation and deallocation in the first phase basis may occur by multiple threads at once. +// +// The class also manages a few counters for statistics using atomic operations. +// Their values are only consistent within each other with extra global +// synchronization. +template +class G1SegmentedArray { + // G1SegmentedArrayAllocOptions provides parameters for allocation buffer + // sizing and expansion. + const G1SegmentedArrayAllocOptions* _alloc_options; + + G1SegmentedArrayBuffer* volatile _first; // The (start of the) list of all buffers. + G1SegmentedArrayBuffer* _last; // The last element of the list of all buffers. + volatile uint _num_buffers; // Number of assigned buffers to this allocator. + volatile size_t _mem_size; // Memory used by all buffers. + + G1SegmentedArrayBufferList* _free_buffer_list; // The global free buffer list to + // preferentially get new buffers from. + + volatile uint _num_available_nodes; // Number of nodes available in all buffers (allocated + free + pending + not yet used). + volatile uint _num_allocated_nodes; // Number of total nodes allocated and in use. + +private: + inline G1SegmentedArrayBuffer* create_new_buffer(G1SegmentedArrayBuffer* const prev); + +public: + const G1SegmentedArrayBuffer* first_array_buffer() const { return Atomic::load(&_first); } + + uint num_available_nodes() const { return Atomic::load(&_num_available_nodes); } + uint num_allocated_nodes() const { return Atomic::load(&_num_allocated_nodes); } + + inline uint elem_size() const; + + G1SegmentedArray(const char* name, + const G1SegmentedArrayAllocOptions* buffer_options, + G1SegmentedArrayBufferList* free_buffer_list); + ~G1SegmentedArray() { + drop_all(); + } + + // Deallocate all buffers to the free buffer list and reset this allocator. Must + // be called in a globally synchronized area. + void drop_all(); + + inline Elem* allocate(); + + inline uint num_buffers() const; +}; + +#endif //SHARE_GC_G1_G1SEGMENTEDARRAY_HPP diff --git a/src/hotspot/share/gc/g1/g1SegmentedArray.inline.hpp b/src/hotspot/share/gc/g1/g1SegmentedArray.inline.hpp new file mode 100644 index 00000000000..e5b96aeb146 --- /dev/null +++ b/src/hotspot/share/gc/g1/g1SegmentedArray.inline.hpp @@ -0,0 +1,236 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, Huawei Technologies Co. Ltd. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_GC_G1_G1SEGMENTEDARRAY_INLINE_HPP +#define SHARE_GC_G1_G1SEGMENTEDARRAY_INLINE_HPP + +#include "gc/g1/g1SegmentedArray.hpp" +#include "runtime/atomic.hpp" +#include "utilities/globalCounter.inline.hpp" + +template +G1SegmentedArrayBuffer::G1SegmentedArrayBuffer(uint elem_size, uint num_instances, G1SegmentedArrayBuffer* next) : + _elem_size(elem_size), _num_elems(num_instances), _next(next), _next_allocate(0) { + + _buffer = NEW_C_HEAP_ARRAY(char, (size_t)_num_elems * elem_size, mtGCCardSet); +} + +template +G1SegmentedArrayBuffer::~G1SegmentedArrayBuffer() { + FREE_C_HEAP_ARRAY(mtGCCardSet, _buffer); +} + +template +void* G1SegmentedArrayBuffer::get_new_buffer_elem() { + if (_next_allocate >= _num_elems) { + return nullptr; + } + uint result = Atomic::fetch_and_add(&_next_allocate, 1u, memory_order_relaxed); + if (result >= _num_elems) { + return nullptr; + } + void* r = _buffer + (uint)result * _elem_size; + return r; +} + +template +void G1SegmentedArrayBufferList::bulk_add(G1SegmentedArrayBuffer& first, + G1SegmentedArrayBuffer& last, + size_t num, + size_t mem_size) { + _list.prepend(first, last); + Atomic::add(&_num_buffers, num, memory_order_relaxed); + Atomic::add(&_mem_size, mem_size, memory_order_relaxed); +} + +template +void G1SegmentedArrayBufferList::print_on(outputStream* out, const char* prefix) { + out->print_cr("%s: buffers %zu size %zu", + prefix, Atomic::load(&_num_buffers), Atomic::load(&_mem_size)); +} + +template +G1SegmentedArrayBuffer* G1SegmentedArrayBufferList::get() { + GlobalCounter::CriticalSection cs(Thread::current()); + + G1SegmentedArrayBuffer* result = _list.pop(); + if (result != nullptr) { + Atomic::dec(&_num_buffers, memory_order_relaxed); + Atomic::sub(&_mem_size, result->mem_size(), memory_order_relaxed); + } + return result; +} + +template +G1SegmentedArrayBuffer* G1SegmentedArrayBufferList::get_all(size_t& num_buffers, + size_t& mem_size) { + GlobalCounter::CriticalSection cs(Thread::current()); + + G1SegmentedArrayBuffer* result = _list.pop_all(); + num_buffers = Atomic::load(&_num_buffers); + mem_size = Atomic::load(&_mem_size); + + if (result != nullptr) { + Atomic::sub(&_num_buffers, num_buffers, memory_order_relaxed); + Atomic::sub(&_mem_size, mem_size, memory_order_relaxed); + } + return result; +} + +template +void G1SegmentedArrayBufferList::free_all() { + size_t num_freed = 0; + size_t mem_size_freed = 0; + G1SegmentedArrayBuffer* cur; + + while ((cur = _list.pop()) != nullptr) { + mem_size_freed += cur->mem_size(); + num_freed++; + delete cur; + } + + Atomic::sub(&_num_buffers, num_freed, memory_order_relaxed); + Atomic::sub(&_mem_size, mem_size_freed, memory_order_relaxed); +} + +template +G1SegmentedArrayBuffer* G1SegmentedArray::create_new_buffer(G1SegmentedArrayBuffer* const prev) { + // Take an existing buffer if available. + G1SegmentedArrayBuffer* next = _free_buffer_list->get(); + if (next == nullptr) { + uint prev_num_elems = (prev != nullptr) ? prev->num_elems() : 0; + uint num_elems = _alloc_options->next_num_elems(prev_num_elems); + next = new G1SegmentedArrayBuffer(elem_size(), num_elems, prev); + } else { + assert(elem_size() == next->elem_size() , + "Mismatch %d != %d Elem %zu", elem_size(), next->elem_size(), sizeof(Elem)); + next->reset(prev); + } + + // Install it as current allocation buffer. + G1SegmentedArrayBuffer* old = Atomic::cmpxchg(&_first, prev, next); + if (old != prev) { + // Somebody else installed the buffer, use that one. + delete next; + return old; + } else { + // Did we install the first element in the list? If so, this is also the last. + if (prev == nullptr) { + _last = next; + } + // Successfully installed the buffer into the list. + Atomic::inc(&_num_buffers, memory_order_relaxed); + Atomic::add(&_mem_size, next->mem_size(), memory_order_relaxed); + Atomic::add(&_num_available_nodes, next->num_elems(), memory_order_relaxed); + return next; + } +} + +template +uint G1SegmentedArray::elem_size() const { + return _alloc_options->elem_size(); +} + +template +G1SegmentedArray::G1SegmentedArray(const char* name, + const G1SegmentedArrayAllocOptions* buffer_options, + G1SegmentedArrayBufferList* free_buffer_list) : + _alloc_options(buffer_options), + _first(nullptr), + _last(nullptr), + _num_buffers(0), + _mem_size(0), + _free_buffer_list(free_buffer_list), + _num_available_nodes(0), + _num_allocated_nodes(0) { + assert(_free_buffer_list != nullptr, "precondition!"); +} + +template +void G1SegmentedArray::drop_all() { + G1SegmentedArrayBuffer* cur = Atomic::load_acquire(&_first); + + if (cur != nullptr) { + assert(_last != nullptr, "If there is at least one element, there must be a last one."); + + G1SegmentedArrayBuffer* first = cur; +#ifdef ASSERT + // Check list consistency. + G1SegmentedArrayBuffer* last = cur; + uint num_buffers = 0; + size_t mem_size = 0; + while (cur != nullptr) { + mem_size += cur->mem_size(); + num_buffers++; + + G1SegmentedArrayBuffer* next = cur->next(); + last = cur; + cur = next; + } +#endif + assert(num_buffers == _num_buffers, "Buffer count inconsistent %u %u", num_buffers, _num_buffers); + assert(mem_size == _mem_size, "Memory size inconsistent"); + assert(last == _last, "Inconsistent last element"); + + _free_buffer_list->bulk_add(*first, *_last, _num_buffers, _mem_size); + } + + _first = nullptr; + _last = nullptr; + _num_buffers = 0; + _mem_size = 0; + _num_available_nodes = 0; + _num_allocated_nodes = 0; +} + +template +Elem* G1SegmentedArray::allocate() { + assert(elem_size() > 0, "instance size not set."); + + G1SegmentedArrayBuffer* cur = Atomic::load_acquire(&_first); + if (cur == nullptr) { + cur = create_new_buffer(cur); + } + + while (true) { + Elem* elem = (Elem*)cur->get_new_buffer_elem(); + if (elem != nullptr) { + Atomic::inc(&_num_allocated_nodes, memory_order_relaxed); + guarantee(is_aligned(elem, _alloc_options->alignment()), + "result " PTR_FORMAT " not aligned at %u", p2i(elem), _alloc_options->alignment()); + return elem; + } + // The buffer is full. Next round. + assert(cur->is_full(), "must be"); + cur = create_new_buffer(cur); + } +} + +template +inline uint G1SegmentedArray::num_buffers() const { + return Atomic::load(&_num_buffers); +} + +#endif //SHARE_GC_G1_G1SEGMENTEDARRAY_INLINE_HPP -- GitLab From dcd6e0da245338de68d9dede451e233f4bfaa934 Mon Sep 17 00:00:00 2001 From: Jayathirth D V Date: Tue, 19 Oct 2021 12:25:32 +0000 Subject: [PATCH 249/385] 8255724: [XRender] the BlitRotateClippedArea test fails on Linux in the XR pipeline Reviewed-by: psadhukhan --- test/jdk/ProblemList.txt | 1 - .../image/DrawImage/BlitRotateClippedArea.java | 17 +++++++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index aaa505deae5..b44ecd1f424 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -242,7 +242,6 @@ java/awt/font/TextLayout/TextLayoutBounds.java 8169188 generic-all java/awt/FontMetrics/FontCrash.java 8198336 windows-all java/awt/image/BufferedImage/ICMColorDataTest/ICMColorDataTest.java 8233028 generic-all java/awt/image/DrawImage/IncorrectAlphaSurface2SW.java 8056077 linux-all -java/awt/image/DrawImage/BlitRotateClippedArea.java 8255724 linux-all java/awt/image/multiresolution/MultiresolutionIconTest.java 8169187,8252812 macosx-all,windows-all,linux-x64 java/awt/print/Headless/HeadlessPrinterJob.java 8196088 windows-all sun/awt/datatransfer/SuplementaryCharactersTransferTest.java 8011371 generic-all diff --git a/test/jdk/java/awt/image/DrawImage/BlitRotateClippedArea.java b/test/jdk/java/awt/image/DrawImage/BlitRotateClippedArea.java index 5db3fca9b60..a622c01377b 100644 --- a/test/jdk/java/awt/image/DrawImage/BlitRotateClippedArea.java +++ b/test/jdk/java/awt/image/DrawImage/BlitRotateClippedArea.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,7 +36,7 @@ import static java.awt.Transparency.TRANSLUCENT; /** * @test - * @bug 8255722 + * @bug 8255722 8255724 * @key headful */ public class BlitRotateClippedArea { @@ -103,10 +103,15 @@ public class BlitRotateClippedArea { throws IOException { for (int x = 0; x < gold.getWidth(); ++x) { for (int y = 0; y < gold.getHeight(); ++y) { - if (gold.getRGB(x, y) != img.getRGB(x, y)) { - ImageIO.write(gold, "png", new File("gold.png")); - ImageIO.write(img, "png", new File("snapshot.png")); - throw new RuntimeException("Test failed."); + Color goldColor = new Color(gold.getRGB(x, y)); + Color actualColor = new Color(img.getRGB(x, y)); + if ((Math.abs(goldColor.getRed() - actualColor.getRed()) > 1) || + (Math.abs(goldColor.getGreen() - actualColor.getGreen()) > 1) || + (Math.abs(goldColor.getBlue() - actualColor.getBlue()) > 1)) { + ImageIO.write(gold, "png", new File("gold.png")); + ImageIO.write(img, "png", new File("snapshot.png")); + throw new RuntimeException("Test failed for pixel :" + + x + "/" + y); } } } -- GitLab From 98ab4b03b311dcd8374cbbb21a898298798750d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20Gr=C3=B6nlund?= Date: Tue, 19 Oct 2021 13:00:50 +0000 Subject: [PATCH 250/385] 8275445: RunThese30M.java failed "assert(ZAddress::is_marked(addr)) failed: Should be marked" Reviewed-by: egahlin, coleenp --- .../periodic/jfrFinalizerStatisticsEvent.cpp | 45 +------------- .../share/services/finalizerService.cpp | 61 +++++++++++++++++++ .../share/services/finalizerService.hpp | 3 + .../runtime/TestFinalizerStatisticsEvent.java | 1 - 4 files changed, 65 insertions(+), 45 deletions(-) diff --git a/src/hotspot/share/jfr/periodic/jfrFinalizerStatisticsEvent.cpp b/src/hotspot/share/jfr/periodic/jfrFinalizerStatisticsEvent.cpp index 7404b8aa56c..7f68d7b5de0 100644 --- a/src/hotspot/share/jfr/periodic/jfrFinalizerStatisticsEvent.cpp +++ b/src/hotspot/share/jfr/periodic/jfrFinalizerStatisticsEvent.cpp @@ -26,63 +26,20 @@ #include "utilities/macros.hpp" #if INCLUDE_MANAGEMENT #include "classfile/classLoaderDataGraph.hpp" -#include "classfile/javaClasses.inline.hpp" #include "jfr/jfrEvents.hpp" -#include "jfr/jni/jfrJavaSupport.hpp" #include "jfr/periodic/jfrFinalizerStatisticsEvent.hpp" #include "jfr/support/jfrSymbolTable.hpp" #include "jfr/utilities/jfrTime.hpp" #include "jfr/utilities/jfrTypes.hpp" -#include "oops/instanceKlass.inline.hpp" #include "runtime/mutexLocker.hpp" #include "runtime/thread.inline.hpp" #include "services/finalizerService.hpp" -static oop get_codesource(oop pd, Thread* thread) { - assert(pd != NULL, "invariant"); - assert(thread != NULL, "invariant"); - JavaValue result(T_OBJECT); - JfrJavaArguments args(&result); - args.set_klass(pd->klass()); - args.set_name("codesource"); - args.set_signature("Ljava/security/CodeSource;"); - args.set_receiver(pd); - JfrJavaSupport::get_field(&args, thread); - return result.get_oop(); -} - -// Caller needs ResourceMark -static const char* get_locationNoFragString(oop codesource, Thread* thread) { - assert(codesource != NULL, "invariant"); - assert(thread != NULL, "invariant"); - JavaValue result(T_OBJECT); - JfrJavaArguments args(&result); - args.set_klass(codesource->klass()); - args.set_name("locationNoFragString"); - args.set_signature("Ljava/lang/String;"); - args.set_receiver(codesource); - JfrJavaSupport::get_field(&args, thread); - const oop string_oop = result.get_oop(); - return string_oop != NULL ? JfrJavaSupport::c_str(string_oop, thread) : NULL; -} - -// Caller needs ResourceMark -static const char* codesource(const InstanceKlass* ik, Thread* thread) { - assert(ik != NULL, "invariant"); - assert(thread != NULL, "invariant"); - oop pd = java_lang_Class::protection_domain(ik->java_mirror()); - if (pd == NULL) { - return NULL; - } - oop codesource = get_codesource(pd, thread); - return codesource != NULL ? get_locationNoFragString(codesource, thread) : NULL; -} - static void send_event(const FinalizerEntry* fe, const InstanceKlass* ik, const JfrTicks& timestamp, Thread* thread) { assert(ik != NULL, "invariant"); assert(ik->has_finalizer(), "invariant"); assert(thread != NULL, "invariant"); - const char* const url = codesource(ik, thread); + const char* const url = fe != nullptr ? fe->codesource() : nullptr; const traceid url_symbol_id = url != NULL ? JfrSymbolTable::add(url) : 0; EventFinalizerStatistics event(UNTIMED); event.set_endtime(timestamp); diff --git a/src/hotspot/share/services/finalizerService.cpp b/src/hotspot/share/services/finalizerService.cpp index 557d4511280..88bfd23488e 100644 --- a/src/hotspot/share/services/finalizerService.cpp +++ b/src/hotspot/share/services/finalizerService.cpp @@ -26,9 +26,13 @@ #include "utilities/macros.hpp" #if INCLUDE_MANAGEMENT #include "classfile/classLoaderDataGraph.inline.hpp" +#include "classfile/javaClasses.inline.hpp" +#include "classfile/symbolTable.hpp" #include "memory/resourceArea.hpp" #include "logging/log.hpp" +#include "oops/instanceKlass.inline.hpp" #include "runtime/atomic.hpp" +#include "runtime/fieldDescriptor.inline.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/mutexLocker.hpp" #include "runtime/synchronizer.hpp" @@ -37,15 +41,72 @@ #include "utilities/concurrentHashTableTasks.inline.hpp" #include "utilities/debug.hpp" +static const char* allocate(oop string) { + char* str = nullptr; + const typeArrayOop value = java_lang_String::value(string); + if (value != nullptr) { + const int length = java_lang_String::utf8_length(string, value); + str = NEW_C_HEAP_ARRAY(char, length, mtServiceability); + java_lang_String::as_utf8_string(string, value, str, length + 1); + } + return str; +} + +static int compute_field_offset(const Klass* klass, const char* field_name, const char* field_signature) { + assert(klass != nullptr, "invariant"); + Symbol* const name = SymbolTable::new_symbol(field_name); + assert(name != nullptr, "invariant"); + Symbol* const signature = SymbolTable::new_symbol(field_signature); + assert(signature != nullptr, "invariant"); + assert(klass->is_instance_klass(), "invariant"); + fieldDescriptor fd; + InstanceKlass::cast(klass)->find_field(name, signature, false, &fd); + return fd.offset(); +} + +static const char* location_no_frag_string(oop codesource) { + assert(codesource != nullptr, "invariant"); + static int loc_no_frag_offset = compute_field_offset(codesource->klass(), "locationNoFragString", "Ljava/lang/String;"); + oop string = codesource->obj_field(loc_no_frag_offset); + return string != nullptr ? allocate(string) : nullptr; +} + +static oop codesource(oop pd) { + assert(pd != nullptr, "invariant"); + static int codesource_offset = compute_field_offset(pd->klass(), "codesource", "Ljava/security/CodeSource;"); + return pd->obj_field(codesource_offset); +} + +static const char* get_codesource(const InstanceKlass* ik) { + assert(ik != nullptr, "invariant"); + oop pd = java_lang_Class::protection_domain(ik->java_mirror()); + if (pd == nullptr) { + return nullptr; + } + oop cs = codesource(pd); + return cs != nullptr ? location_no_frag_string(cs) : nullptr; +} + FinalizerEntry::FinalizerEntry(const InstanceKlass* ik) : _ik(ik), + _codesource(get_codesource(ik)), _objects_on_heap(0), _total_finalizers_run(0) {} +FinalizerEntry::~FinalizerEntry() { + if (_codesource != nullptr) { + FREE_C_HEAP_ARRAY(char, _codesource); + } +} + const InstanceKlass* FinalizerEntry::klass() const { return _ik; } +const char* FinalizerEntry::codesource() const { + return _codesource; +} + uintptr_t FinalizerEntry::objects_on_heap() const { return Atomic::load(&_objects_on_heap); } diff --git a/src/hotspot/share/services/finalizerService.hpp b/src/hotspot/share/services/finalizerService.hpp index 74c4452e08a..fbf1d5311de 100644 --- a/src/hotspot/share/services/finalizerService.hpp +++ b/src/hotspot/share/services/finalizerService.hpp @@ -35,11 +35,14 @@ class Thread; class FinalizerEntry : public CHeapObj { private: const InstanceKlass* const _ik; + const char* _codesource; uintptr_t _objects_on_heap; uintptr_t _total_finalizers_run; public: FinalizerEntry(const InstanceKlass* ik); + ~FinalizerEntry(); const InstanceKlass* klass() const NOT_MANAGEMENT_RETURN_(nullptr); + const char* codesource() const NOT_MANAGEMENT_RETURN_(nullptr); uintptr_t objects_on_heap() const NOT_MANAGEMENT_RETURN_(0L); uintptr_t total_finalizers_run() const NOT_MANAGEMENT_RETURN_(0L); void on_register() NOT_MANAGEMENT_RETURN; diff --git a/test/jdk/jdk/jfr/event/runtime/TestFinalizerStatisticsEvent.java b/test/jdk/jdk/jfr/event/runtime/TestFinalizerStatisticsEvent.java index 1024855a7f1..ecec7c383fb 100644 --- a/test/jdk/jdk/jfr/event/runtime/TestFinalizerStatisticsEvent.java +++ b/test/jdk/jdk/jfr/event/runtime/TestFinalizerStatisticsEvent.java @@ -99,7 +99,6 @@ public final class TestFinalizerStatisticsEvent { break; } case TEST_CLASS_UNLOAD_NAME: { - Asserts.assertTrue(event.getString("codeSource").startsWith("file://")); foundTestClassUnloadName = true; break; } -- GitLab From 002c538bc03f55fa600f331a66242ee8575919dc Mon Sep 17 00:00:00 2001 From: Zhengyu Gu Date: Tue, 19 Oct 2021 14:14:23 +0000 Subject: [PATCH 251/385] 8275287: Relax memory ordering constraints on updating instance class and array class counters Reviewed-by: dholmes, rkennke --- .../classfile/classLoaderDataGraph.inline.hpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/hotspot/share/classfile/classLoaderDataGraph.inline.hpp b/src/hotspot/share/classfile/classLoaderDataGraph.inline.hpp index 9e93c4ef926..e5b51ac277c 100644 --- a/src/hotspot/share/classfile/classLoaderDataGraph.inline.hpp +++ b/src/hotspot/share/classfile/classLoaderDataGraph.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,6 +30,7 @@ #include "classfile/javaClasses.hpp" #include "oops/oop.inline.hpp" #include "runtime/atomic.hpp" +#include "runtime/orderAccess.hpp" inline ClassLoaderData *ClassLoaderDataGraph::find_or_create(Handle loader) { guarantee(loader() != NULL && oopDesc::is_oop(loader()), "Loader must be oop"); @@ -43,29 +44,29 @@ inline ClassLoaderData *ClassLoaderDataGraph::find_or_create(Handle loader) { } size_t ClassLoaderDataGraph::num_instance_classes() { - return _num_instance_classes; + return Atomic::load(&_num_instance_classes); } size_t ClassLoaderDataGraph::num_array_classes() { - return _num_array_classes; + return Atomic::load(&_num_array_classes); } void ClassLoaderDataGraph::inc_instance_classes(size_t count) { - Atomic::add(&_num_instance_classes, count); + Atomic::add(&_num_instance_classes, count, memory_order_relaxed); } void ClassLoaderDataGraph::dec_instance_classes(size_t count) { - assert(count <= _num_instance_classes, "Sanity"); - Atomic::sub(&_num_instance_classes, count); + size_t old_count = Atomic::fetch_and_add(&_num_instance_classes, -count, memory_order_relaxed); + assert(old_count >= count, "Sanity"); } void ClassLoaderDataGraph::inc_array_classes(size_t count) { - Atomic::add(&_num_array_classes, count); + Atomic::add(&_num_array_classes, count, memory_order_relaxed); } void ClassLoaderDataGraph::dec_array_classes(size_t count) { - assert(count <= _num_array_classes, "Sanity"); - Atomic::sub(&_num_array_classes, count); + size_t old_count = Atomic::fetch_and_add(&_num_array_classes, -count, memory_order_relaxed); + assert(old_count >= count, "Sanity"); } bool ClassLoaderDataGraph::should_clean_metaspaces_and_reset() { -- GitLab From a579483c88e94bdaa787d109e5ae204e7fb308c0 Mon Sep 17 00:00:00 2001 From: Andrey Turbanov Date: Tue, 19 Oct 2021 14:46:30 +0000 Subject: [PATCH 252/385] 8274899: Replace usages of Collections.sort with List.sort call in jdk.hotspot.agent Reviewed-by: sspitsyn, cjplummer, ayang --- .../debugger/cdbg/basic/BasicCDebugInfoDataBase.java | 4 ++-- .../debugger/cdbg/basic/BasicLineNumberMapping.java | 4 ++-- .../share/classes/sun/jvm/hotspot/oops/ObjectHeap.java | 4 ++-- .../classes/sun/jvm/hotspot/oops/ObjectHistogram.java | 6 +----- .../classes/sun/jvm/hotspot/tools/FinalizerInfo.java | 9 ++------- .../classes/sun/jvm/hotspot/ui/ProcessListPanel.java | 5 ++--- .../sun/jvm/hotspot/ui/table/SortableTableModel.java | 7 ++----- 7 files changed, 13 insertions(+), 26 deletions(-) diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicCDebugInfoDataBase.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicCDebugInfoDataBase.java index ccc6e3bdaf8..26f7a9d333c 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicCDebugInfoDataBase.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicCDebugInfoDataBase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -137,7 +137,7 @@ public class BasicCDebugInfoDataBase implements CDebugInfoDataBase { // Sort blocks in ascending order of starting address (but do not // change ordering among blocks with the same starting address) - Collections.sort(blocks, new Comparator<>() { + blocks.sort(new Comparator<>() { public int compare(BlockSym b1, BlockSym b2) { Address a1 = b1.getAddress(); Address a2 = b2.getAddress(); diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicLineNumberMapping.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicLineNumberMapping.java index b9d2ac73361..eb5ad1206d1 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicLineNumberMapping.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/cdbg/basic/BasicLineNumberMapping.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,7 +50,7 @@ public class BasicLineNumberMapping { counter. This must be done before any queries are made. */ public void sort() { if (infoList == null) return; - Collections.sort(infoList, new Comparator<>() { + infoList.sort(new Comparator<>() { public int compare(BasicLineNumberInfo l1, BasicLineNumberInfo l2) { Address a1 = l1.getStartPC(); Address a2 = l2.getStartPC(); diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ObjectHeap.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ObjectHeap.java index 29d6c6593ff..59109901502 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ObjectHeap.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ObjectHeap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -365,7 +365,7 @@ public class ObjectHeap { } private void sortLiveRegions(List
      liveRegions) { - Collections.sort(liveRegions, new Comparator
      () { + liveRegions.sort(new Comparator
      () { public int compare(Address a1, Address a2) { if (AddressOps.lt(a1, a2)) { return -1; diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ObjectHistogram.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ObjectHistogram.java index 4bec528de8b..4238bc05f25 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ObjectHistogram.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ObjectHistogram.java @@ -50,11 +50,7 @@ public class ObjectHistogram implements HeapVisitor { public List getElements() { List list = new ArrayList<>(); list.addAll(map.values()); - Collections.sort(list, new Comparator<>() { - public int compare(ObjectHistogramElement o1, ObjectHistogramElement o2) { - return o1.compare(o2); - } - }); + list.sort(ObjectHistogramElement::compare); return list; } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/FinalizerInfo.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/FinalizerInfo.java index 354cc4cf777..973d66ac26e 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/FinalizerInfo.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/FinalizerInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,6 @@ import sun.jvm.hotspot.oops.*; import sun.jvm.hotspot.utilities.SystemDictionaryHelper; import java.util.ArrayList; -import java.util.Collections; import java.util.Comparator; import java.util.HashMap; @@ -126,11 +125,7 @@ public class FinalizerInfo extends Tool { */ ArrayList list = new ArrayList<>(); list.addAll(map.values()); - Collections.sort(list, new Comparator<>() { - public int compare(ObjectHistogramElement o1, ObjectHistogramElement o2) { - return o1.compare(o2); - } - }); + list.sort(ObjectHistogramElement::compare); /* * Print summary of objects in queue diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/ProcessListPanel.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/ProcessListPanel.java index 183aa809a99..b1304becd54 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/ProcessListPanel.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/ProcessListPanel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,6 @@ import java.awt.*; import java.awt.event.*; import java.util.*; import javax.swing.*; -import javax.swing.event.*; import javax.swing.table.*; import sun.jvm.hotspot.debugger.*; @@ -202,7 +201,7 @@ public class ProcessListPanel extends JPanel { } }; } - Collections.sort(els, c); + els.sort(c); } private javax.swing.Timer getTimer() { diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/table/SortableTableModel.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/table/SortableTableModel.java index a2c9b1600b6..dce7c740513 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/table/SortableTableModel.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/table/SortableTableModel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2021, Oracle and/or its affiliates. All rights reserved. * 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,9 +24,6 @@ package sun.jvm.hotspot.ui.table; -import java.util.Collections; -import java.util.List; - import javax.swing.event.TableModelEvent; import javax.swing.table.AbstractTableModel; @@ -55,7 +52,7 @@ public abstract class SortableTableModel extends AbstractTableModel { comparator.addColumn(column); comparator.setAscending(ascending); - Collections.sort(elements, comparator); + elements.sort(comparator); fireTableChanged(new TableModelEvent(this)); } -- GitLab From 8a3e0a1fc1fef02edf9621b13e8be8b96a12bb0f Mon Sep 17 00:00:00 2001 From: Naoto Sato Date: Tue, 19 Oct 2021 15:54:14 +0000 Subject: [PATCH 253/385] 7008363: TEST_BUG: test/java/lang/StringCoding/CheckEncodings.sh does nothing and is very slow at that Reviewed-by: iris, lancea, bpb, whuang --- test/jdk/ProblemList.txt | 1 - .../java/lang/StringCoding/CheckEncodings.sh | 70 ------------------- test/jdk/java/lang/StringCoding/locales.txt | 25 ------- 3 files changed, 96 deletions(-) delete mode 100644 test/jdk/java/lang/StringCoding/CheckEncodings.sh delete mode 100644 test/jdk/java/lang/StringCoding/locales.txt diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index b44ecd1f424..22c41c937c4 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -551,7 +551,6 @@ java/foreign/TestMismatch.java 8249684 macosx-all # jdk_lang -java/lang/StringCoding/CheckEncodings.sh 7008363 generic-all java/lang/ProcessHandle/InfoTest.java 8211847 aix-ppc64 java/lang/invoke/LFCaching/LFMultiThreadCachingTest.java 8151492 generic-all java/lang/invoke/LFCaching/LFGarbageCollectedTest.java 8078602 generic-all diff --git a/test/jdk/java/lang/StringCoding/CheckEncodings.sh b/test/jdk/java/lang/StringCoding/CheckEncodings.sh deleted file mode 100644 index b6b2efec8e8..00000000000 --- a/test/jdk/java/lang/StringCoding/CheckEncodings.sh +++ /dev/null @@ -1,70 +0,0 @@ -# -# Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# 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 Verify that unsupported encodings are handled gracefully. -# @bug 4629543 4785473 -# -# @run shell/timeout=300 CheckEncodings.sh - -# set platform-dependent variables -OS=`uname -s` -case "$OS" in - Linux | Darwin | AIX ) ;; - Windows* | CYGWIN* ) - echo "Passed"; exit 0 ;; - * ) echo "Unrecognized system!" ; exit 1 ;; -esac - -expectPass() { - if [ $1 -eq 0 ] - then echo "--- passed as expected" - else - echo "--- failed" - exit $1 - fi -} - -runTest() { - echo "Testing:" ${1} - set LC_ALL="${1}"; export LC_ALL - locale - ${TESTJAVA}/bin/java ${TESTVMOPTS} -version 2>&1 - expectPass $? -} - - -locale -a > machine_locales.txt - -# ${TESTSRC}/locales.txt contains the list of "fully supported" locales -# as defined by the i18n doc for 1.4 -cat ${TESTSRC}/locales.txt machine_locales.txt | sort | uniq > locale_union.txt - -for i in `xargs < locale_union.txt` ; do - runTest ${i} -done - -# random strings -for i in FOO 1234 ZZ; do - runTest ${i} -done diff --git a/test/jdk/java/lang/StringCoding/locales.txt b/test/jdk/java/lang/StringCoding/locales.txt deleted file mode 100644 index 47803359730..00000000000 --- a/test/jdk/java/lang/StringCoding/locales.txt +++ /dev/null @@ -1,25 +0,0 @@ -ar_SA -zh_CN -zh_TW -nl_NL -nl_NL_EURO -en_AU -en_CA -en_GB -en_US -fr_CA -fr_FR -fr_FR_EURO -de_DE -de_DE_EURO -iw_IL -hi_IN -it_IT -it_IT_EURO -ja_JP -ko_KR -pt_BR -es_ES -es_ES_EURO -sv_SE -th_TH -- GitLab From 99bf7dd8ddac1b5870534af50c97bec554004248 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20Gr=C3=B6nlund?= Date: Tue, 19 Oct 2021 16:20:45 +0000 Subject: [PATCH 254/385] 8275517: Off-by-one error in allocation Reviewed-by: tschatzl --- src/hotspot/share/services/finalizerService.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/hotspot/share/services/finalizerService.cpp b/src/hotspot/share/services/finalizerService.cpp index 88bfd23488e..9efcda886d8 100644 --- a/src/hotspot/share/services/finalizerService.cpp +++ b/src/hotspot/share/services/finalizerService.cpp @@ -46,7 +46,7 @@ static const char* allocate(oop string) { const typeArrayOop value = java_lang_String::value(string); if (value != nullptr) { const int length = java_lang_String::utf8_length(string, value); - str = NEW_C_HEAP_ARRAY(char, length, mtServiceability); + str = NEW_C_HEAP_ARRAY(char, length + 1, mtServiceability); java_lang_String::as_utf8_string(string, value, str, length + 1); } return str; @@ -94,9 +94,7 @@ FinalizerEntry::FinalizerEntry(const InstanceKlass* ik) : _total_finalizers_run(0) {} FinalizerEntry::~FinalizerEntry() { - if (_codesource != nullptr) { - FREE_C_HEAP_ARRAY(char, _codesource); - } + FREE_C_HEAP_ARRAY(char, _codesource); } const InstanceKlass* FinalizerEntry::klass() const { -- GitLab From fd10f1996ef94529b5b12e547957cd904ade1956 Mon Sep 17 00:00:00 2001 From: Vicente Romero Date: Tue, 19 Oct 2021 16:46:14 +0000 Subject: [PATCH 255/385] 8275302: unexpected compiler error: cast, intersection types and sealed Reviewed-by: jlahoda --- .../classes/com/sun/tools/javac/code/Types.java | 2 +- .../tools/javac/sealed/SealedCompilationTests.java | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java index 9a21c57fe44..9d182a4c076 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java @@ -1664,7 +1664,7 @@ public class Types { && s.hasTag(CLASS) && s.tsym.kind.matches(Kinds.KindSelector.TYP) && (t.tsym.isSealed() || s.tsym.isSealed())) { return (t.isCompound() || s.isCompound()) ? - false : + true : !areDisjoint((ClassSymbol)t.tsym, (ClassSymbol)s.tsym); } return result; diff --git a/test/langtools/tools/javac/sealed/SealedCompilationTests.java b/test/langtools/tools/javac/sealed/SealedCompilationTests.java index 4d254546e6d..ccf12cb3d9e 100644 --- a/test/langtools/tools/javac/sealed/SealedCompilationTests.java +++ b/test/langtools/tools/javac/sealed/SealedCompilationTests.java @@ -1250,5 +1250,18 @@ public class SealedCompilationTests extends CompilationTestCase { class Foo {} """ ); + assertOK( + """ + class Outer { + abstract class Base {} + interface Marker {} + sealed class B extends Base {} + final class C extends B implements Marker {} + private void test(T obj) { + B b = (B) obj; + } + } + """ + ); } } -- GitLab From 895e2bd7c0bded5283eca8792fbfb287bb75016b Mon Sep 17 00:00:00 2001 From: Alexander Zvegintsev Date: Tue, 19 Oct 2021 17:24:20 +0000 Subject: [PATCH 256/385] 8274160: java/awt/Window/ShapedAndTranslucentWindows/Common.java delay is too high Reviewed-by: psadhukhan, pbansal --- .../java/awt/Window/ShapedAndTranslucentWindows/Common.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/jdk/java/awt/Window/ShapedAndTranslucentWindows/Common.java b/test/jdk/java/awt/Window/ShapedAndTranslucentWindows/Common.java index a97ef2e0538..d555a521adf 100644 --- a/test/jdk/java/awt/Window/ShapedAndTranslucentWindows/Common.java +++ b/test/jdk/java/awt/Window/ShapedAndTranslucentWindows/Common.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,7 +47,7 @@ public abstract class Common { static final int STATIC_BLOCKS = 30; static final Color BG_COLOR = Color.BLUE; static final Color FG_COLOR = Color.RED; - static final int delay = 55000; + static final int delay = 1000; static final SecureRandom random = new SecureRandom(); static final int dl = 100; static final Class[] WINDOWS_TO_TEST = { Window.class, Frame.class, Dialog.class }; -- GitLab From a26f9db704a0ded15e467676a72de8955eb0d9f6 Mon Sep 17 00:00:00 2001 From: Weijun Wang Date: Fri, 26 Mar 2021 14:52:55 +0000 Subject: [PATCH 257/385] 8263314: Enhance XML Dsig modes Reviewed-by: rhalade, mschoene, valeriep, mullan --- .../dsig/internal/dom/DOMURIDereferencer.java | 25 ++++++++++++++++--- .../xml/crypto/dsig/GenerationTests.java | 7 +++++- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/java.xml.crypto/share/classes/org/jcp/xml/dsig/internal/dom/DOMURIDereferencer.java b/src/java.xml.crypto/share/classes/org/jcp/xml/dsig/internal/dom/DOMURIDereferencer.java index e6b88e7d4d2..6b728e236cb 100644 --- a/src/java.xml.crypto/share/classes/org/jcp/xml/dsig/internal/dom/DOMURIDereferencer.java +++ b/src/java.xml.crypto/share/classes/org/jcp/xml/dsig/internal/dom/DOMURIDereferencer.java @@ -37,6 +37,7 @@ import com.sun.org.apache.xml.internal.security.signature.XMLSignatureInput; import javax.xml.crypto.*; import javax.xml.crypto.dom.*; +import java.net.URI; /** * DOM-based implementation of URIDereferencer. @@ -70,9 +71,27 @@ public final class DOMURIDereferencer implements URIDereferencer { boolean secVal = Utils.secureValidation(context); - if (secVal && Policy.restrictReferenceUriScheme(uri)) { - throw new URIReferenceException( - "Uri " + uri + " is forbidden when secure validation is enabled"); + if (secVal) { + try { + if (Policy.restrictReferenceUriScheme(uri)) { + throw new URIReferenceException( + "URI " + uri + " is forbidden when secure validation is enabled"); + } + + if (uri != null && !uri.isEmpty() && uri.charAt(0) != '#' && URI.create(uri).getScheme() == null) { + // beseURI will be used to dereference a relative uri + try { + if (Policy.restrictReferenceUriScheme(baseURI)) { + throw new URIReferenceException( + "Base URI " + baseURI + " is forbidden when secure validation is enabled"); + } + } catch (IllegalArgumentException e) { // thrown by Policy.restrictReferenceUriScheme + throw new URIReferenceException("Invalid base URI " + baseURI); + } + } + } catch (IllegalArgumentException e) { // thrown by Policy.restrictReferenceUriScheme or URI.create + throw new URIReferenceException("Invalid URI " + uri); + } } // Check if same-document URI and already registered on the context diff --git a/test/jdk/javax/xml/crypto/dsig/GenerationTests.java b/test/jdk/javax/xml/crypto/dsig/GenerationTests.java index 3120dcc4333..5f1e217ab8b 100644 --- a/test/jdk/javax/xml/crypto/dsig/GenerationTests.java +++ b/test/jdk/javax/xml/crypto/dsig/GenerationTests.java @@ -1454,7 +1454,6 @@ public class GenerationTests { DOMValidateContext dvc = new DOMValidateContext (ks, doc.getDocumentElement()); File f = new File(DATA_DIR); - dvc.setBaseURI(f.toURI().toString()); dvc.setURIDereferencer(httpUd); XMLSignature sig2 = fac.unmarshalXMLSignature(dvc); @@ -2195,6 +2194,12 @@ public class GenerationTests { (DATA_DIR, uri.substring(uri.lastIndexOf('/')))); return new OctetStreamData(fis,ref.getURI(),ref.getType()); } catch (Exception e) { throw new URIReferenceException(e); } + } else if (uri.startsWith("certs/")) { + try { + FileInputStream fis = new FileInputStream(new File + (DATA_DIR, uri)); + return new OctetStreamData(fis,ref.getURI(),ref.getType()); + } catch (Exception e) { throw new URIReferenceException(e); } } // fallback on builtin deref -- GitLab From 34628ff8ac4acf72070945d030d6cd7999afe617 Mon Sep 17 00:00:00 2001 From: Weijun Wang Date: Tue, 11 May 2021 20:00:26 +0000 Subject: [PATCH 258/385] 8266115: More Manifest Jar Loading Reviewed-by: mschoene, ahgross, mullan, rhalade --- .../share/classes/java/util/jar/JarFile.java | 2 +- .../jar/JarFile/LargeManifestOOMTest.java | 78 ------------------- 2 files changed, 1 insertion(+), 79 deletions(-) delete mode 100644 test/jdk/java/util/jar/JarFile/LargeManifestOOMTest.java diff --git a/src/java.base/share/classes/java/util/jar/JarFile.java b/src/java.base/share/classes/java/util/jar/JarFile.java index b5336c61cb8..f0cd0e5c382 100644 --- a/src/java.base/share/classes/java/util/jar/JarFile.java +++ b/src/java.base/share/classes/java/util/jar/JarFile.java @@ -801,7 +801,7 @@ public class JarFile extends ZipFile { try (InputStream is = super.getInputStream(ze)) { long uncompressedSize = ze.getSize(); if (uncompressedSize > MAX_ARRAY_SIZE) { - throw new OutOfMemoryError("Required array size too large"); + throw new IOException("Unsupported size: " + uncompressedSize); } int len = (int)uncompressedSize; int bytesRead; diff --git a/test/jdk/java/util/jar/JarFile/LargeManifestOOMTest.java b/test/jdk/java/util/jar/JarFile/LargeManifestOOMTest.java deleted file mode 100644 index 514a2d4d2d4..00000000000 --- a/test/jdk/java/util/jar/JarFile/LargeManifestOOMTest.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -import jdk.test.lib.util.JarUtils; -import org.testng.Assert; -import org.testng.annotations.Test; - -import java.io.IOException; -import java.io.RandomAccessFile; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.jar.JarFile; - -/** - * @test - * @bug 8242882 - * @summary Verify that opening a jar file with a large manifest throws an OutOfMemoryError - * and not a NegativeArraySizeException - * @library /test/lib - * @run testng LargeManifestOOMTest - */ -public class LargeManifestOOMTest { - // file will be created with size greater than Integer.MAX_VALUE - private static final long MANIFEST_FILE_SIZE = Integer.MAX_VALUE + 1024L; - - /** - * Creates a jar which has a large manifest file and then uses the {@link JarFile} to - * {@link JarFile#getManifest() load the manifest}. The call to the {@link JarFile#getManifest()} - * is then expected to throw a {@link OutOfMemoryError} - */ - @Test - public void testOutOfMemoryError() throws Exception { - final Path jarSourceRoot = Paths.get("jar-source"); - createLargeManifest(jarSourceRoot.resolve("META-INF")); - final Path jarFilePath = Paths.get("oom-test.jar"); - JarUtils.createJarFile(jarFilePath.toAbsolutePath(), jarSourceRoot); - final JarFile jar = new JarFile(jarFilePath.toFile()); - Assert.assertThrows(OutOfMemoryError.class, () -> jar.getManifest()); - } - - /** - * Creates a {@code MANIFEST.MF}, whose content is {@link #MANIFEST_FILE_SIZE} in size, - * in the {@code parentDir} - * - * @param parentDir The directory in which the MANIFEST.MF file will be created - */ - private static void createLargeManifest(final Path parentDir) throws IOException { - Files.createDirectories(parentDir.toAbsolutePath()); - final Path manifestFile = parentDir.resolve("MANIFEST.MF"); - try (final RandomAccessFile largeManifest = new RandomAccessFile(manifestFile.toFile(), "rw")) { - largeManifest.writeUTF("Manifest-Version: 1.0\n"); - largeManifest.writeUTF("OOM-Test: a\n"); - largeManifest.setLength(MANIFEST_FILE_SIZE); - } - System.out.println("Size of file " + manifestFile + " is " + manifestFile.toFile().length()); - } -} -- GitLab From 3a7b663b6f3712c51cd14634c28777bd68200156 Mon Sep 17 00:00:00 2001 From: Michael McMahon Date: Thu, 20 May 2021 11:37:13 +0000 Subject: [PATCH 259/385] 8265776: Improve Stream handling for SSL Reviewed-by: dfuchs, chegar, rhalade, ahgross --- .../share/classes/sun/net/httpserver/SSLStreams.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/jdk.httpserver/share/classes/sun/net/httpserver/SSLStreams.java b/src/jdk.httpserver/share/classes/sun/net/httpserver/SSLStreams.java index 6d4ebaf31b8..7433986f1e7 100644 --- a/src/jdk.httpserver/share/classes/sun/net/httpserver/SSLStreams.java +++ b/src/jdk.httpserver/share/classes/sun/net/httpserver/SSLStreams.java @@ -515,7 +515,7 @@ class SSLStreams { throw new IOException ("SSL stream is closed"); } if (eof) { - return 0; + return -1; } int available=0; if (!needData) { @@ -528,7 +528,7 @@ class SSLStreams { bbuf = r.buf== bbuf? bbuf: r.buf; if ((available=bbuf.remaining()) == 0) { eof = true; - return 0; + return -1; } else { needData = false; } @@ -579,7 +579,7 @@ class SSLStreams { /** * close the SSL connection. All data must have been consumed * before this is called. Otherwise an exception will be thrown. - * [Note. May need to revisit this. not quite the normal close() symantics + * [Note. May need to revisit this. not quite the normal close() semantics */ public void close () throws IOException { eof = true; @@ -593,8 +593,11 @@ class SSLStreams { byte single[] = new byte [1]; public int read () throws IOException { + if (eof) { + return -1; + } int n = read (single, 0, 1); - if (n == 0) { + if (n <= 0) { return -1; } else { return single[0] & 0xFF; -- GitLab From dd199ee0631f7da10c91e2e99621e683e889ef87 Mon Sep 17 00:00:00 2001 From: Julia Boes Date: Tue, 25 May 2021 10:19:55 +0000 Subject: [PATCH 260/385] 8266097: Better hashing support Reviewed-by: chegar, dfuchs, ahgross, smarks, rhalade --- .../share/classes/java/util/HashMap.java | 46 +++++++++++++------ .../share/classes/java/util/HashSet.java | 11 +++-- 2 files changed, 38 insertions(+), 19 deletions(-) diff --git a/src/java.base/share/classes/java/util/HashMap.java b/src/java.base/share/classes/java/util/HashMap.java index 9715b6ea9b1..24fcd9516ca 100644 --- a/src/java.base/share/classes/java/util/HashMap.java +++ b/src/java.base/share/classes/java/util/HashMap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,7 @@ package java.util; import java.io.IOException; import java.io.InvalidObjectException; +import java.io.ObjectInputStream; import java.io.Serializable; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; @@ -1504,23 +1505,28 @@ public class HashMap extends AbstractMap * @throws IOException if an I/O error occurs */ @java.io.Serial - private void readObject(java.io.ObjectInputStream s) + private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { - // Read in the threshold (ignored), loadfactor, and any hidden stuff - s.defaultReadObject(); + + ObjectInputStream.GetField fields = s.readFields(); + + // Read loadFactor (ignore threshold) + float lf = fields.get("loadFactor", 0.75f); + if (lf <= 0 || Float.isNaN(lf)) + throw new InvalidObjectException("Illegal load factor: " + lf); + + lf = Math.min(Math.max(0.25f, lf), 4.0f); + HashMap.UnsafeHolder.putLoadFactor(this, lf); + reinitialize(); - if (loadFactor <= 0 || Float.isNaN(loadFactor)) - throw new InvalidObjectException("Illegal load factor: " + - loadFactor); + s.readInt(); // Read and ignore number of buckets int mappings = s.readInt(); // Read number of mappings (size) - if (mappings < 0) - throw new InvalidObjectException("Illegal mappings count: " + - mappings); - else if (mappings > 0) { // (if zero, use defaults) - // Size the table using given load factor only if within - // range of 0.25...4.0 - float lf = Math.min(Math.max(0.25f, loadFactor), 4.0f); + if (mappings < 0) { + throw new InvalidObjectException("Illegal mappings count: " + mappings); + } else if (mappings == 0) { + // use defaults + } else if (mappings > 0) { float fc = (float)mappings / lf + 1.0f; int cap = ((fc < DEFAULT_INITIAL_CAPACITY) ? DEFAULT_INITIAL_CAPACITY : @@ -1549,6 +1555,18 @@ public class HashMap extends AbstractMap } } + // Support for resetting final field during deserializing + private static final class UnsafeHolder { + private UnsafeHolder() { throw new InternalError(); } + private static final jdk.internal.misc.Unsafe unsafe + = jdk.internal.misc.Unsafe.getUnsafe(); + private static final long LF_OFFSET + = unsafe.objectFieldOffset(HashMap.class, "loadFactor"); + static void putLoadFactor(HashMap map, float lf) { + unsafe.putFloat(map, LF_OFFSET, lf); + } + } + /* ------------------------------------------------------------ */ // iterators diff --git a/src/java.base/share/classes/java/util/HashSet.java b/src/java.base/share/classes/java/util/HashSet.java index d370e5d6710..e28fc6d5c21 100644 --- a/src/java.base/share/classes/java/util/HashSet.java +++ b/src/java.base/share/classes/java/util/HashSet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -297,8 +297,8 @@ public class HashSet @java.io.Serial private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { - // Read in any hidden serialization magic - s.defaultReadObject(); + // Consume and ignore stream fields (currently zero). + s.readFields(); // Read capacity and verify non-negative. int capacity = s.readInt(); @@ -313,12 +313,13 @@ public class HashSet throw new InvalidObjectException("Illegal load factor: " + loadFactor); } + // Clamp load factor to range of 0.25...4.0. + loadFactor = Math.min(Math.max(0.25f, loadFactor), 4.0f); // Read size and verify non-negative. int size = s.readInt(); if (size < 0) { - throw new InvalidObjectException("Illegal size: " + - size); + throw new InvalidObjectException("Illegal size: " + size); } // Set the capacity according to the size and load factor ensuring that -- GitLab From 470e8a0fda5248f22e1cd90ed8064cdf04513c28 Mon Sep 17 00:00:00 2001 From: Valerie Peng Date: Thu, 3 Jun 2021 22:42:55 +0000 Subject: [PATCH 261/385] 8266103: Better specified spec values Reviewed-by: mullan, rhalade, mschoene --- .../classes/javax/crypto/spec/IvParameterSpec.java | 11 +++++++---- .../classes/javax/crypto/spec/RC5ParameterSpec.java | 9 +++++++-- .../classes/javax/crypto/spec/SecretKeySpec.java | 9 ++++++--- 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/src/java.base/share/classes/javax/crypto/spec/IvParameterSpec.java b/src/java.base/share/classes/javax/crypto/spec/IvParameterSpec.java index 243c848ff41..6a3d311eb14 100644 --- a/src/java.base/share/classes/javax/crypto/spec/IvParameterSpec.java +++ b/src/java.base/share/classes/javax/crypto/spec/IvParameterSpec.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -76,13 +76,16 @@ public class IvParameterSpec implements AlgorithmParameterSpec { if (iv == null) { throw new IllegalArgumentException("IV missing"); } - if (iv.length - offset < len) { - throw new IllegalArgumentException - ("IV buffer too short for given offset/length combination"); + if (offset < 0) { + throw new ArrayIndexOutOfBoundsException("offset is negative"); } if (len < 0) { throw new ArrayIndexOutOfBoundsException("len is negative"); } + if (iv.length - offset < len) { + throw new IllegalArgumentException + ("IV buffer too short for given offset/length combination"); + } this.iv = new byte[len]; System.arraycopy(iv, offset, this.iv, 0, len); } diff --git a/src/java.base/share/classes/javax/crypto/spec/RC5ParameterSpec.java b/src/java.base/share/classes/javax/crypto/spec/RC5ParameterSpec.java index 22d1c6a7c58..ced87331bce 100644 --- a/src/java.base/share/classes/javax/crypto/spec/RC5ParameterSpec.java +++ b/src/java.base/share/classes/javax/crypto/spec/RC5ParameterSpec.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -114,7 +114,12 @@ public class RC5ParameterSpec implements AlgorithmParameterSpec { this.version = version; this.rounds = rounds; this.wordSize = wordSize; - if (iv == null) throw new IllegalArgumentException("IV missing"); + if (iv == null) { + throw new IllegalArgumentException("IV missing"); + } + if (offset < 0) { + throw new ArrayIndexOutOfBoundsException("offset is negative"); + } int blockSize = (wordSize / 8) * 2; if (iv.length - offset < blockSize) { throw new IllegalArgumentException("IV too short"); diff --git a/src/java.base/share/classes/javax/crypto/spec/SecretKeySpec.java b/src/java.base/share/classes/javax/crypto/spec/SecretKeySpec.java index de8245074d4..41d4acab748 100644 --- a/src/java.base/share/classes/javax/crypto/spec/SecretKeySpec.java +++ b/src/java.base/share/classes/javax/crypto/spec/SecretKeySpec.java @@ -157,13 +157,16 @@ public class SecretKeySpec implements KeySpec, SecretKey { if (key.length == 0) { throw new IllegalArgumentException("Empty key"); } - if (key.length-offset < len) { - throw new IllegalArgumentException - ("Invalid offset/length combination"); + if (offset < 0) { + throw new ArrayIndexOutOfBoundsException("offset is negative"); } if (len < 0) { throw new ArrayIndexOutOfBoundsException("len is negative"); } + if (key.length - offset < len) { + throw new IllegalArgumentException + ("Invalid offset/length combination"); + } this.key = new byte[len]; System.arraycopy(key, offset, this.key, 0, len); this.algorithm = algorithm; -- GitLab From bddcc8ea9d567f05a5944d9a9794dd1743a36593 Mon Sep 17 00:00:00 2001 From: Aleksei Efimov Date: Tue, 8 Jun 2021 10:18:09 +0000 Subject: [PATCH 262/385] 8267712: Better LDAP reference processing Reviewed-by: dfuchs, ahgross, rhalade --- src/java.naming/share/classes/com/sun/jndi/ldap/Obj.java | 6 ++++++ .../share/classes/com/sun/jndi/ldap/VersionHelper.java | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/java.naming/share/classes/com/sun/jndi/ldap/Obj.java b/src/java.naming/share/classes/com/sun/jndi/ldap/Obj.java index da9e1926a5a..a842d42d25b 100644 --- a/src/java.naming/share/classes/com/sun/jndi/ldap/Obj.java +++ b/src/java.naming/share/classes/com/sun/jndi/ldap/Obj.java @@ -465,6 +465,12 @@ final class Obj { // Empty content refAddrList[posn] = new StringRefAddr(type, null); } else if (val.charAt(start) == separator) { + // Check if deserialization of binary RefAddr is allowed from + // 'javaReferenceAddress' LDAP attribute. + if (!VersionHelper.isSerialDataAllowed()) { + throw new NamingException("Object deserialization is not allowed"); + } + // Double separators indicate a non-StringRefAddr // Content is a Base64-encoded serialized RefAddr diff --git a/src/java.naming/share/classes/com/sun/jndi/ldap/VersionHelper.java b/src/java.naming/share/classes/com/sun/jndi/ldap/VersionHelper.java index edb43f73e8b..4d7ce28a841 100644 --- a/src/java.naming/share/classes/com/sun/jndi/ldap/VersionHelper.java +++ b/src/java.naming/share/classes/com/sun/jndi/ldap/VersionHelper.java @@ -82,7 +82,7 @@ public final class VersionHelper { /** * Returns true if deserialization of objects from 'javaSerializedData' - * LDAP attribute is allowed. + * and 'javaReferenceAddress' LDAP attributes is allowed. * * @return true if deserialization is allowed; false - otherwise */ -- GitLab From a48251cb4ad86f7554ba6a97b54d512e6fd98237 Mon Sep 17 00:00:00 2001 From: Hai-May Chao Date: Tue, 8 Jun 2021 21:58:23 +0000 Subject: [PATCH 263/385] 8266137: Improve Keystore integrity Reviewed-by: mschoene, rhalade, weijun --- .../security/tools/keytool/CertAndKeyGen.java | 9 +++++++ .../sun/security/tools/keytool/Main.java | 25 +++++++++++++------ 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/src/java.base/share/classes/sun/security/tools/keytool/CertAndKeyGen.java b/src/java.base/share/classes/sun/security/tools/keytool/CertAndKeyGen.java index 0901edc5d97..d61d6e0d3e7 100644 --- a/src/java.base/share/classes/sun/security/tools/keytool/CertAndKeyGen.java +++ b/src/java.base/share/classes/sun/security/tools/keytool/CertAndKeyGen.java @@ -32,7 +32,10 @@ import java.security.cert.CertificateEncodingException; import java.security.*; import java.security.spec.ECGenParameterSpec; import java.security.spec.NamedParameterSpec; +import java.util.Calendar; import java.util.Date; +import java.util.GregorianCalendar; +import java.util.TimeZone; import sun.security.pkcs10.PKCS10; import sun.security.util.SignatureUtil; @@ -304,6 +307,12 @@ public final class CertAndKeyGen { try { lastDate = new Date (); lastDate.setTime (firstDate.getTime () + validity * 1000); + Calendar c = new GregorianCalendar(TimeZone.getTimeZone("UTC")); + c.setTime(lastDate); + if (c.get(Calendar.YEAR) > 9999) { + throw new CertificateException("Validity period ends at calendar year " + + c.get(Calendar.YEAR) + " which is greater than 9999"); + } CertificateValidity interval = new CertificateValidity(firstDate,lastDate); 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 737d907f4b4..57078637a94 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 @@ -1445,8 +1445,7 @@ public final class Main { X509CertInfo.DN_NAME); Date firstDate = getStartDate(startDate); - Date lastDate = new Date(); - lastDate.setTime(firstDate.getTime() + validity*1000L*24L*60L*60L); + Date lastDate = getLastDate(firstDate, validity); CertificateValidity interval = new CertificateValidity(firstDate, lastDate); @@ -1558,12 +1557,10 @@ public final class Main { X509CertInfo.DN_NAME); Date firstDate = getStartDate(startDate); - Date lastDate = (Date) firstDate.clone(); - lastDate.setTime(lastDate.getTime() + validity*1000*24*60*60); + Date lastDate = getLastDate(firstDate, validity); CertificateValidity interval = new CertificateValidity(firstDate, lastDate); - PrivateKey privateKey = (PrivateKey)recoverKey(alias, storePass, keyPass).fst; if (sigAlgName == null) { @@ -3031,8 +3028,7 @@ public final class Main { // Extend its validity Date firstDate = getStartDate(startDate); - Date lastDate = new Date(); - lastDate.setTime(firstDate.getTime() + validity*1000L*24L*60L*60L); + Date lastDate = getLastDate(firstDate, validity); CertificateValidity interval = new CertificateValidity(firstDate, lastDate); certInfo.set(X509CertInfo.VALIDITY, interval); @@ -4693,6 +4689,21 @@ public final class Main { return result; } + private Date getLastDate(Date firstDate, long validity) + throws Exception { + Date lastDate = new Date(); + lastDate.setTime(firstDate.getTime() + validity*1000L*24L*60L*60L); + + Calendar c = new GregorianCalendar(TimeZone.getTimeZone("UTC")); + c.setTime(lastDate); + if (c.get(Calendar.YEAR) > 9999) { + throw new Exception("Validity period ends at calendar year " + + c.get(Calendar.YEAR) + " which is greater than 9999"); + } + + return lastDate; + } + private boolean isTrustedCert(Certificate cert) throws KeyStoreException { if (caks != null && caks.getCertificateAlias(cert) != null) { return true; -- GitLab From fde3839c0c40f48b435e4fd5ebf5b137e96c7f90 Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Wed, 16 Jun 2021 04:10:50 +0000 Subject: [PATCH 264/385] 8265167: Richer Text Editors Reviewed-by: prr, rhalade, mschoene, azvegint --- .../javax/swing/text/rtf/RTFParser.java | 64 +++++++++++++------ 1 file changed, 46 insertions(+), 18 deletions(-) diff --git a/src/java.desktop/share/classes/javax/swing/text/rtf/RTFParser.java b/src/java.desktop/share/classes/javax/swing/text/rtf/RTFParser.java index 88e2990942c..9b38c5cff57 100644 --- a/src/java.desktop/share/classes/javax/swing/text/rtf/RTFParser.java +++ b/src/java.desktop/share/classes/javax/swing/text/rtf/RTFParser.java @@ -233,25 +233,52 @@ abstract class RTFParser extends AbstractFilter currentCharacters.append(ch); } else { /* TODO: Test correct behavior of \bin keyword */ + if (pendingKeyword.equals("bin")) { /* magic layer-breaking kwd */ - long parameter = Long.parseLong(currentCharacters.toString()); + long parameter = 0L; + try { + parameter = Long.parseLong(currentCharacters.toString()); + } catch (NumberFormatException e) { + warning("Illegal number format " + currentCharacters.toString() + + " in \bin tag"); + pendingKeyword = null; + currentCharacters = new StringBuffer(); + state = S_text; + // Delimiters here are interpreted as text too + if (!Character.isWhitespace(ch)) + write(ch); + break; + } pendingKeyword = null; state = S_inblob; + int maxBytes = 4 * 1024 * 1024; binaryBytesLeft = parameter; - if (binaryBytesLeft > Integer.MAX_VALUE) - binaryBuf = new ByteArrayOutputStream(Integer.MAX_VALUE); - else - binaryBuf = new ByteArrayOutputStream((int)binaryBytesLeft); + + if (binaryBytesLeft > maxBytes) { + binaryBuf = new ByteArrayOutputStream(maxBytes); + } else if (binaryBytesLeft < 0) { + binaryBytesLeft = 0; + binaryBuf = new ByteArrayOutputStream((int)binaryBytesLeft); + } else { + binaryBuf = new ByteArrayOutputStream((int) binaryBytesLeft); + } savedSpecials = specialsTable; specialsTable = allSpecialsTable; break; } - int parameter = Integer.parseInt(currentCharacters.toString()); - ok = handleKeyword(pendingKeyword, parameter); - if (!ok) - warning("Unknown keyword: " + pendingKeyword + - " (param " + currentCharacters + ")"); + int parameter = 0; + try { + parameter = Integer.parseInt(currentCharacters.toString()); + ok = handleKeyword(pendingKeyword, parameter); + if (!ok) { + warning("Unknown keyword: " + pendingKeyword + + " (param " + currentCharacters + ")"); + } + } catch (NumberFormatException e) { + warning("Illegal number format " + currentCharacters.toString() + + " in " + pendingKeyword + " tag"); + } pendingKeyword = null; currentCharacters = new StringBuffer(); state = S_text; @@ -280,14 +307,15 @@ abstract class RTFParser extends AbstractFilter } break; case S_inblob: - binaryBuf.write(ch); - binaryBytesLeft --; - if (binaryBytesLeft == 0) { - state = S_text; - specialsTable = savedSpecials; - savedSpecials = null; - handleBinaryBlob(binaryBuf.toByteArray()); - binaryBuf = null; + if (binaryBytesLeft > 0) { + binaryBuf.write(ch); + binaryBytesLeft--; + } else { + state = S_text; + specialsTable = savedSpecials; + savedSpecials = null; + handleBinaryBlob(binaryBuf.toByteArray()); + binaryBuf = null; } } } -- GitLab From a07a046c9254a426c1805485537e345f30a4377c Mon Sep 17 00:00:00 2001 From: Xue-Lei Andrew Fan Date: Fri, 18 Jun 2021 04:04:43 +0000 Subject: [PATCH 265/385] 8267729: Improve TLS client handshaking Reviewed-by: ahgross, jnimeh, rhalade --- .../security/ssl/ECDHClientKeyExchange.java | 40 ++++++--- .../security/ssl/ECDHServerKeyExchange.java | 19 ++++- .../sun/security/ssl/KeyShareExtension.java | 50 ++++++++--- .../classes/sun/security/ssl/NamedGroup.java | 84 ++++--------------- .../classes/sun/security/ssl/SSLLogger.java | 2 +- 5 files changed, 101 insertions(+), 94 deletions(-) diff --git a/src/java.base/share/classes/sun/security/ssl/ECDHClientKeyExchange.java b/src/java.base/share/classes/sun/security/ssl/ECDHClientKeyExchange.java index f2cc67a793f..6b2264e0f13 100644 --- a/src/java.base/share/classes/sun/security/ssl/ECDHClientKeyExchange.java +++ b/src/java.base/share/classes/sun/security/ssl/ECDHClientKeyExchange.java @@ -27,6 +27,7 @@ package sun.security.ssl; import java.io.IOException; import java.nio.ByteBuffer; +import java.security.CryptoPrimitive; import java.security.GeneralSecurityException; import java.security.PublicKey; import java.security.interfaces.ECPublicKey; @@ -35,6 +36,7 @@ import java.security.spec.AlgorithmParameterSpec; import java.security.spec.ECParameterSpec; import java.security.spec.NamedParameterSpec; import java.text.MessageFormat; +import java.util.EnumSet; import java.util.Locale; import javax.crypto.SecretKey; import sun.security.ssl.SSLHandshake.HandshakeMessage; @@ -317,12 +319,19 @@ final class ECDHClientKeyExchange { // create the credentials try { - NamedGroup ng = namedGroup; // "effectively final" the lambda - // AlgorithmConstraints are checked internally. - SSLCredentials sslCredentials = namedGroup.decodeCredentials( - cke.encodedPoint, shc.algorithmConstraints, - s -> shc.conContext.fatal(Alert.INSUFFICIENT_SECURITY, - "ClientKeyExchange " + ng + ": " + s)); + SSLCredentials sslCredentials = + namedGroup.decodeCredentials(cke.encodedPoint); + if (shc.algorithmConstraints != null && + sslCredentials instanceof + NamedGroupCredentials namedGroupCredentials) { + if (!shc.algorithmConstraints.permits( + EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), + namedGroupCredentials.getPublicKey())) { + shc.conContext.fatal(Alert.INSUFFICIENT_SECURITY, + "ClientKeyExchange for " + namedGroup + + " does not comply with algorithm constraints"); + } + } shc.handshakeCredentials.add(sslCredentials); } catch (GeneralSecurityException e) { @@ -497,12 +506,19 @@ final class ECDHClientKeyExchange { // create the credentials try { - NamedGroup ng = namedGroup; // "effectively final" the lambda - // AlgorithmConstraints are checked internally. - SSLCredentials sslCredentials = namedGroup.decodeCredentials( - cke.encodedPoint, shc.algorithmConstraints, - s -> shc.conContext.fatal(Alert.INSUFFICIENT_SECURITY, - "ClientKeyExchange " + ng + ": " + s)); + SSLCredentials sslCredentials = + namedGroup.decodeCredentials(cke.encodedPoint); + if (shc.algorithmConstraints != null && + sslCredentials instanceof + NamedGroupCredentials namedGroupCredentials) { + if (!shc.algorithmConstraints.permits( + EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), + namedGroupCredentials.getPublicKey())) { + shc.conContext.fatal(Alert.INSUFFICIENT_SECURITY, + "ClientKeyExchange for " + namedGroup + + " does not comply with algorithm constraints"); + } + } shc.handshakeCredentials.add(sslCredentials); } catch (GeneralSecurityException e) { diff --git a/src/java.base/share/classes/sun/security/ssl/ECDHServerKeyExchange.java b/src/java.base/share/classes/sun/security/ssl/ECDHServerKeyExchange.java index 11efab71c85..09b7a6bdca2 100644 --- a/src/java.base/share/classes/sun/security/ssl/ECDHServerKeyExchange.java +++ b/src/java.base/share/classes/sun/security/ssl/ECDHServerKeyExchange.java @@ -27,6 +27,7 @@ package sun.security.ssl; import java.io.IOException; import java.nio.ByteBuffer; +import java.security.CryptoPrimitive; import java.security.GeneralSecurityException; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; @@ -37,6 +38,7 @@ import java.security.PublicKey; import java.security.Signature; import java.security.SignatureException; import java.text.MessageFormat; +import java.util.EnumSet; import java.util.Locale; import java.util.Map; import sun.security.ssl.SSLHandshake.HandshakeMessage; @@ -214,10 +216,19 @@ final class ECDHServerKeyExchange { } try { - sslCredentials = namedGroup.decodeCredentials( - publicPoint, handshakeContext.algorithmConstraints, - s -> chc.conContext.fatal(Alert.INSUFFICIENT_SECURITY, - "ServerKeyExchange " + namedGroup + ": " + (s))); + sslCredentials = + namedGroup.decodeCredentials(publicPoint); + if (handshakeContext.algorithmConstraints != null && + sslCredentials instanceof + NamedGroupCredentials namedGroupCredentials) { + if (!handshakeContext.algorithmConstraints.permits( + EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), + namedGroupCredentials.getPublicKey())) { + chc.conContext.fatal(Alert.INSUFFICIENT_SECURITY, + "ServerKeyExchange for " + namedGroup + + " does not comply with algorithm constraints"); + } + } } catch (GeneralSecurityException ex) { throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, "Cannot decode named group: " + diff --git a/src/java.base/share/classes/sun/security/ssl/KeyShareExtension.java b/src/java.base/share/classes/sun/security/ssl/KeyShareExtension.java index a0d9b98a77a..df430c557c9 100644 --- a/src/java.base/share/classes/sun/security/ssl/KeyShareExtension.java +++ b/src/java.base/share/classes/sun/security/ssl/KeyShareExtension.java @@ -27,6 +27,7 @@ package sun.security.ssl; import java.io.IOException; import java.nio.ByteBuffer; +import java.security.CryptoPrimitive; import java.security.GeneralSecurityException; import java.text.MessageFormat; import java.util.Collections; @@ -349,7 +350,8 @@ final class KeyShareExtension { NamedGroup ng = NamedGroup.valueOf(entry.namedGroupId); if (ng == null || !SupportedGroups.isActivatable( shc.algorithmConstraints, ng)) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + if (SSLLogger.isOn && + SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Ignore unsupported named group: " + NamedGroup.nameOf(entry.namedGroupId)); @@ -359,16 +361,33 @@ final class KeyShareExtension { try { SSLCredentials kaCred = - ng.decodeCredentials(entry.keyExchange, - shc.algorithmConstraints, - s -> SSLLogger.warning(s)); + ng.decodeCredentials(entry.keyExchange); + if (shc.algorithmConstraints != null && + kaCred instanceof + NamedGroupCredentials namedGroupCredentials) { + if (!shc.algorithmConstraints.permits( + EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), + namedGroupCredentials.getPublicKey())) { + if (SSLLogger.isOn && + SSLLogger.isOn("ssl,handshake")) { + SSLLogger.warning( + "key share entry of " + ng + " does not " + + " comply with algorithm constraints"); + } + + kaCred = null; + } + } + if (kaCred != null) { credentials.add(kaCred); } } catch (GeneralSecurityException ex) { - SSLLogger.warning( - "Cannot decode named group: " + - NamedGroup.nameOf(entry.namedGroupId)); + if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + SSLLogger.warning( + "Cannot decode named group: " + + NamedGroup.nameOf(entry.namedGroupId)); + } } } @@ -646,9 +665,20 @@ final class KeyShareExtension { SSLCredentials credentials = null; try { - SSLCredentials kaCred = ng.decodeCredentials( - keyShare.keyExchange, chc.algorithmConstraints, - s -> chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, s)); + SSLCredentials kaCred = + ng.decodeCredentials(keyShare.keyExchange); + if (chc.algorithmConstraints != null && + kaCred instanceof + NamedGroupCredentials namedGroupCredentials) { + if (!chc.algorithmConstraints.permits( + EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), + namedGroupCredentials.getPublicKey())) { + chc.conContext.fatal(Alert.INSUFFICIENT_SECURITY, + "key share entry of " + ng + " does not " + + " comply with algorithm constraints"); + } + } + if (kaCred != null) { credentials = kaCred; } diff --git a/src/java.base/share/classes/sun/security/ssl/NamedGroup.java b/src/java.base/share/classes/sun/security/ssl/NamedGroup.java index 8febedbe989..7afa619ad5d 100644 --- a/src/java.base/share/classes/sun/security/ssl/NamedGroup.java +++ b/src/java.base/share/classes/sun/security/ssl/NamedGroup.java @@ -419,12 +419,9 @@ enum NamedGroup { return spec.encodePossessionPublicKey(namedGroupPossession); } - SSLCredentials decodeCredentials(byte[] encoded, - AlgorithmConstraints constraints, - ExceptionSupplier onConstraintFail) - throws IOException, GeneralSecurityException { - return spec.decodeCredentials( - this, encoded, constraints, onConstraintFail); + SSLCredentials decodeCredentials( + byte[] encoded) throws IOException, GeneralSecurityException { + return spec.decodeCredentials(this, encoded); } SSLPossession createPossession(SecureRandom random) { @@ -436,30 +433,13 @@ enum NamedGroup { return spec.createKeyDerivation(hc); } - interface ExceptionSupplier { - void apply(String s) throws SSLException; - } - // A list of operations related to named groups. private interface NamedGroupScheme { - default void checkConstraints(PublicKey publicKey, - AlgorithmConstraints constraints, - ExceptionSupplier onConstraintFail) throws SSLException { - if (!constraints.permits( - EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), publicKey)) { - onConstraintFail.apply("key share entry does not " - + "comply with algorithm constraints"); - } - } - byte[] encodePossessionPublicKey( NamedGroupPossession namedGroupPossession); - SSLCredentials decodeCredentials( - NamedGroup ng, byte[] encoded, - AlgorithmConstraints constraints, - ExceptionSupplier onConstraintFail - ) throws IOException, GeneralSecurityException; + SSLCredentials decodeCredentials(NamedGroup ng, + byte[] encoded) throws IOException, GeneralSecurityException; SSLPossession createPossession(NamedGroup ng, SecureRandom random); @@ -524,13 +504,10 @@ enum NamedGroup { } @Override - public SSLCredentials decodeCredentials(NamedGroup ng, byte[] encoded, - AlgorithmConstraints constraints, - ExceptionSupplier onConstraintFail - ) throws IOException, GeneralSecurityException { + public SSLCredentials decodeCredentials(NamedGroup ng, + byte[] encoded) throws IOException, GeneralSecurityException { if (scheme != null) { - return scheme.decodeCredentials( - ng, encoded, constraints, onConstraintFail); + return scheme.decodeCredentials(ng, encoded); } return null; @@ -567,18 +544,9 @@ enum NamedGroup { } @Override - public SSLCredentials decodeCredentials(NamedGroup ng, byte[] encoded, - AlgorithmConstraints constraints, - ExceptionSupplier onConstraintFail - ) throws IOException, GeneralSecurityException { - - DHKeyExchange.DHECredentials result - = DHKeyExchange.DHECredentials.valueOf(ng, encoded); - - checkConstraints(result.getPublicKey(), constraints, - onConstraintFail); - - return result; + public SSLCredentials decodeCredentials(NamedGroup ng, + byte[] encoded) throws IOException, GeneralSecurityException { + return DHKeyExchange.DHECredentials.valueOf(ng, encoded); } @Override @@ -605,18 +573,9 @@ enum NamedGroup { } @Override - public SSLCredentials decodeCredentials(NamedGroup ng, byte[] encoded, - AlgorithmConstraints constraints, - ExceptionSupplier onConstraintFail - ) throws IOException, GeneralSecurityException { - - ECDHKeyExchange.ECDHECredentials result - = ECDHKeyExchange.ECDHECredentials.valueOf(ng, encoded); - - checkConstraints(result.getPublicKey(), constraints, - onConstraintFail); - - return result; + public SSLCredentials decodeCredentials(NamedGroup ng, + byte[] encoded) throws IOException, GeneralSecurityException { + return ECDHKeyExchange.ECDHECredentials.valueOf(ng, encoded); } @Override @@ -641,18 +600,9 @@ enum NamedGroup { } @Override - public SSLCredentials decodeCredentials(NamedGroup ng, byte[] encoded, - AlgorithmConstraints constraints, - ExceptionSupplier onConstraintFail - ) throws IOException, GeneralSecurityException { - - XDHKeyExchange.XDHECredentials result - = XDHKeyExchange.XDHECredentials.valueOf(ng, encoded); - - checkConstraints(result.getPublicKey(), constraints, - onConstraintFail); - - return result; + public SSLCredentials decodeCredentials(NamedGroup ng, + byte[] encoded) throws IOException, GeneralSecurityException { + return XDHKeyExchange.XDHECredentials.valueOf(ng, encoded); } @Override diff --git a/src/java.base/share/classes/sun/security/ssl/SSLLogger.java b/src/java.base/share/classes/sun/security/ssl/SSLLogger.java index acc3a96de09..9f2cbaf4837 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLLogger.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLLogger.java @@ -184,7 +184,7 @@ public final class SSLLogger { } private static void log(Level level, String msg, Object... params) { - if (logger.isLoggable(level)) { + if (logger != null && logger.isLoggable(level)) { if (params == null || params.length == 0) { logger.log(level, msg); } else { -- GitLab From 3470e7b300b5301326369892a4291f4904106e05 Mon Sep 17 00:00:00 2001 From: Weijun Wang Date: Fri, 18 Jun 2021 20:26:49 +0000 Subject: [PATCH 266/385] 8266109: More Resilient Classloading Reviewed-by: lancea, rhalade, mschoene, bchristi --- .../share/classes/java/net/URLClassLoader.java | 5 +++++ .../classes/jdk/internal/loader/Resource.java | 8 ++++++++ .../classes/jdk/internal/loader/URLClassPath.java | 14 ++++++++++++++ 3 files changed, 27 insertions(+) diff --git a/src/java.base/share/classes/java/net/URLClassLoader.java b/src/java.base/share/classes/java/net/URLClassLoader.java index 30f0040195a..97c95bc9f59 100644 --- a/src/java.base/share/classes/java/net/URLClassLoader.java +++ b/src/java.base/share/classes/java/net/URLClassLoader.java @@ -427,6 +427,11 @@ public class URLClassLoader extends SecureClassLoader implements Closeable { return defineClass(name, res); } catch (IOException e) { throw new ClassNotFoundException(name, e); + } catch (ClassFormatError e2) { + if (res.getDataError() != null) { + e2.addSuppressed(res.getDataError()); + } + throw e2; } } else { return null; diff --git a/src/java.base/share/classes/jdk/internal/loader/Resource.java b/src/java.base/share/classes/jdk/internal/loader/Resource.java index 55002f4c8c1..d119c4b5eae 100644 --- a/src/java.base/share/classes/jdk/internal/loader/Resource.java +++ b/src/java.base/share/classes/jdk/internal/loader/Resource.java @@ -187,4 +187,12 @@ public abstract class Resource { public CodeSigner[] getCodeSigners() { return null; } + + /** + * Returns non-fatal reading error during data retrieval if there's any. + * For example, CRC error when reading a JAR entry. + */ + public Exception getDataError() { + return null; + } } diff --git a/src/java.base/share/classes/jdk/internal/loader/URLClassPath.java b/src/java.base/share/classes/jdk/internal/loader/URLClassPath.java index 5ee7fdcdd55..dad2f25917b 100644 --- a/src/java.base/share/classes/jdk/internal/loader/URLClassPath.java +++ b/src/java.base/share/classes/jdk/internal/loader/URLClassPath.java @@ -60,6 +60,7 @@ import java.util.Properties; import java.util.Set; import java.util.StringTokenizer; import java.util.jar.JarFile; +import java.util.zip.CRC32; import java.util.zip.ZipEntry; import java.util.jar.JarEntry; import java.util.jar.Manifest; @@ -875,6 +876,7 @@ public class URLClassPath { } return new Resource() { + private Exception dataError = null; public String getName() { return name; } public URL getURL() { return url; } public URL getCodeSourceURL() { return csu; } @@ -890,6 +892,18 @@ public class URLClassPath { { return entry.getCertificates(); }; public CodeSigner[] getCodeSigners() { return entry.getCodeSigners(); }; + public Exception getDataError() + { return dataError; } + public byte[] getBytes() throws IOException { + byte[] bytes = super.getBytes(); + CRC32 crc32 = new CRC32(); + crc32.update(bytes); + if (crc32.getValue() != entry.getCrc()) { + dataError = new IOException( + "CRC error while extracting entry from JAR file"); + } + return bytes; + } }; } -- GitLab From c70f7cad47c9be0a203079de52ffab0ce53ba965 Mon Sep 17 00:00:00 2001 From: Jayathirth D V Date: Tue, 22 Jun 2021 12:42:51 +0000 Subject: [PATCH 267/385] 8267735: Better BMP support Reviewed-by: prr, rhalade, azvegint, ahgross, mschoene --- .../com/sun/imageio/plugins/bmp/BMPImageReader.java | 7 +++++++ .../com/sun/imageio/plugins/common/iio-plugin.properties | 1 + 2 files changed, 8 insertions(+) diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPImageReader.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPImageReader.java index 37d9a9b0384..df283e8102c 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPImageReader.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPImageReader.java @@ -591,6 +591,13 @@ public class BMPImageReader extends ImageReader implements BMPConstants { height = Math.abs(height); } + if (metadata.compression == BI_RGB) { + long imageDataSize = (width * height * (bitsPerPixel / 8)); + if (imageDataSize > (bitmapFileSize - bitmapOffset)) { + throw new IIOException(I18N.getString("BMPImageReader9")); + } + } + // Reset Image Layout so there's only one tile. //Define the color space ColorSpace colorSpace = ColorSpace.getInstance(ColorSpace.CS_sRGB); diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/iio-plugin.properties b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/iio-plugin.properties index 0705b99eee8..5b9e47b9215 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/iio-plugin.properties +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/iio-plugin.properties @@ -24,6 +24,7 @@ BMPImageReader5=Input has not been set. BMPImageReader6=Unable to read the image header. BMPImageReader7=Invalid bitmap offset. BMPImageReader8=Invalid bits per pixel in image header. +BMPImageReader9=Invalid width/height for BI_RGB image data. BMPImageWriter0=Output is not an ImageOutputStream. BMPImageWriter1=The image region to be encoded is empty. BMPImageWriter2=Only 1 or 3 band image is encoded. -- GitLab From ab9170957f76905251384a597c721c8f1c250c45 Mon Sep 17 00:00:00 2001 From: Weijun Wang Date: Tue, 22 Jun 2021 21:25:33 +0000 Subject: [PATCH 268/385] 8270212: ArrayIndexOutOfBoundsException in java.security.KeyFactory.generatePublic Reviewed-by: ahgross, valeriep --- .../security/util/DerIndefLenConverter.java | 163 ++++++++++-------- 1 file changed, 93 insertions(+), 70 deletions(-) diff --git a/src/java.base/share/classes/sun/security/util/DerIndefLenConverter.java b/src/java.base/share/classes/sun/security/util/DerIndefLenConverter.java index de8c2e5fb22..f2b88560ca3 100644 --- a/src/java.base/share/classes/sun/security/util/DerIndefLenConverter.java +++ b/src/java.base/share/classes/sun/security/util/DerIndefLenConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. * 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,12 @@ import java.util.ArrayList; import java.util.Arrays; /** - * A package private utility class to convert indefinite length DER + * A package private utility class to convert indefinite length BER * encoded byte arrays to definite length DER encoded byte arrays. - * + *

      + * Note: This class only substitute indefinite length octets to definite + * length octets. It does not update the contents even if they are not DER. + *

      * This assumes that the basic data structure is "tag, length, value" * triplet. In the case where the length is "indefinite", terminating * end-of-contents bytes are expected. @@ -42,26 +45,30 @@ import java.util.Arrays; */ class DerIndefLenConverter { - private static final int TAG_MASK = 0x1f; // bits 5-1 - private static final int FORM_MASK = 0x20; // bits 6 - private static final int CLASS_MASK = 0xC0; // bits 8 and 7 - private static final int LEN_LONG = 0x80; // bit 8 set private static final int LEN_MASK = 0x7f; // bits 7 - 1 - private static final int SKIP_EOC_BYTES = 2; private byte[] data, newData; private int newDataPos, dataPos, dataSize, index; private int unresolved = 0; + // A list to store each indefinite length occurrence. Whenever an indef + // length is seen, the position after the 0x80 byte is appended to the + // list as an integer. Whenever its matching EOC is seen, we know the + // actual length and the position value is substituted with a calculated + // length octets. At the end, the new DER encoding is a concatenation of + // all existing tags, existing definite length octets, existing contents, + // and the newly created definte length octets in this list. private ArrayList ndefsList = new ArrayList(); + // Length of extra bytes needed to convert indefinite encoding to definite. + // For each resolved indefinite length encoding, the starting 0x80 byte + // and the ending 00 00 bytes will be removed and a new definite length + // octets will be added. This value might be positive or negative. private int numOfTotalLenBytes = 0; - private boolean isEOC(int tag) { - return (((tag & TAG_MASK) == 0x00) && // EOC - ((tag & FORM_MASK) == 0x00) && // primitive - ((tag & CLASS_MASK) == 0x00)); // universal + private static boolean isEOC(byte[] data, int pos) { + return data[pos] == 0 && data[pos + 1] == 0; } // if bit 8 is set then it implies either indefinite length or long form @@ -70,9 +77,9 @@ class DerIndefLenConverter { } /* - * Default package private constructor + * Private constructor */ - DerIndefLenConverter() { } + private DerIndefLenConverter() { } /** * Checks whether the given length byte is of the form @@ -88,11 +95,14 @@ class DerIndefLenConverter { } /** - * Parse the tag and if it is an end-of-contents tag then - * add the current position to the eocList vector. + * Consumes the tag at {@code dataPos}. + *

      + * If it is EOC then replace the matching start position (i.e. the previous + * {@code dataPos} where an indefinite length was found by #parseLength) + * in {@code ndefsList} with a length octets for this section. */ private void parseTag() throws IOException { - if (isEOC(data[dataPos]) && (data[dataPos + 1] == 0)) { + if (isEOC(data, dataPos)) { int numOfEncapsulatedLenBytes = 0; Object elem = null; int index; @@ -103,6 +113,9 @@ class DerIndefLenConverter { if (elem instanceof Integer) { break; } else { + // For each existing converted part, 3 bytes (80 at the + // beginning and 00 00 at the end) are removed and a + // new length octets is added. numOfEncapsulatedLenBytes += ((byte[])elem).length - 3; } } @@ -114,6 +127,7 @@ class DerIndefLenConverter { numOfEncapsulatedLenBytes; byte[] sectionLenBytes = getLengthBytes(sectionLen); ndefsList.set(index, sectionLenBytes); + assert unresolved > 0; unresolved--; // Add the number of bytes required to represent this section @@ -130,34 +144,41 @@ class DerIndefLenConverter { * then skip the tag and its 1 byte length of zero. */ private void writeTag() { - if (dataPos == dataSize) + if (dataPos == dataSize) { return; - int tag = data[dataPos++]; - if (isEOC(tag) && (data[dataPos] == 0)) { - dataPos++; // skip length + } + assert dataPos + 1 < dataSize; + if (isEOC(data, dataPos)) { + dataPos += 2; // skip tag and length writeTag(); - } else - newData[newDataPos++] = (byte)tag; + } else { + newData[newDataPos++] = data[dataPos++]; + } } /** - * Parse the length and if it is an indefinite length then add - * the current position to the ndefsList vector. + * Parse the length octets started at {@code dataPos}. After this method + * is called, {@code dataPos} is placed after the length octets except + * -1 is returned. * - * @return the length of definite length data next, or -1 if there is - * not enough bytes to determine it + * @return a) the length of definite length data next + * b) -1, if it is a definite length data next but the length + * octets is not complete to determine the actual length + * c) 0, if it is an indefinite length. Also, append the current + * position to the {@code ndefsList} vector. * @throws IOException if invalid data is read */ private int parseLength() throws IOException { - int curLen = 0; - if (dataPos == dataSize) - return curLen; + if (dataPos == dataSize) { + return 0; + } int lenByte = data[dataPos++] & 0xff; if (isIndefinite(lenByte)) { ndefsList.add(dataPos); unresolved++; - return curLen; + return 0; } + int curLen = 0; if (isLongForm(lenByte)) { lenByte &= LEN_MASK; if (lenByte > 4) { @@ -179,14 +200,17 @@ class DerIndefLenConverter { } /** - * Write the length and if it is an indefinite length - * then calculate the definite length from the positions - * of the indefinite length and its matching EOC terminator. - * Then, write the value. + * Write the length and value. + *

      + * If it was definite length, just re-write the length and copy the value. + * If it was an indefinite length, copy the precalculated definite octets + * from {@code ndefsList}. There is no values here because they will be + * sub-encodings of a constructed encoding. */ private void writeLengthAndValue() throws IOException { - if (dataPos == dataSize) - return; + if (dataPos == dataSize) { + return; + } int curLen = 0; int lenByte = data[dataPos++] & 0xff; if (isIndefinite(lenByte)) { @@ -194,21 +218,21 @@ class DerIndefLenConverter { System.arraycopy(lenBytes, 0, newData, newDataPos, lenBytes.length); newDataPos += lenBytes.length; - return; - } - if (isLongForm(lenByte)) { - lenByte &= LEN_MASK; - for (int i = 0; i < lenByte; i++) { - curLen = (curLen << 8) + (data[dataPos++] & 0xff); - } - if (curLen < 0) { - throw new IOException("Invalid length bytes"); - } } else { - curLen = (lenByte & LEN_MASK); + if (isLongForm(lenByte)) { + lenByte &= LEN_MASK; + for (int i = 0; i < lenByte; i++) { + curLen = (curLen << 8) + (data[dataPos++] & 0xff); + } + if (curLen < 0) { + throw new IOException("Invalid length bytes"); + } + } else { + curLen = (lenByte & LEN_MASK); + } + writeLength(curLen); + writeValue(curLen); } - writeLength(curLen); - writeValue(curLen); } private void writeLength(int curLen) { @@ -296,19 +320,13 @@ class DerIndefLenConverter { return numOfLenBytes; } - /** - * Parse the value; - */ - private void parseValue(int curLen) { - dataPos += curLen; - } - /** * Write the value; */ private void writeValue(int curLen) { - for (int i=0; i < curLen; i++) - newData[newDataPos++] = data[dataPos++]; + System.arraycopy(data, dataPos, newData, newDataPos, curLen); + dataPos += curLen; + newDataPos += curLen; } /** @@ -323,10 +341,8 @@ class DerIndefLenConverter { */ byte[] convertBytes(byte[] indefData) throws IOException { data = indefData; - dataPos=0; index=0; + dataPos = 0; dataSize = data.length; - int len=0; - int unused = 0; // parse and set up the vectors of all the indefinite-lengths while (dataPos < dataSize) { @@ -335,14 +351,17 @@ class DerIndefLenConverter { return null; } parseTag(); - len = parseLength(); + int len = parseLength(); if (len < 0) { return null; } - parseValue(len); + dataPos += len; + if (dataPos < 0) { + // overflow + throw new IOException("Data overflow"); + } if (unresolved == 0) { - unused = dataSize - dataPos; - dataSize = dataPos; + assert !ndefsList.isEmpty() && ndefsList.get(0) instanceof byte[]; break; } } @@ -351,14 +370,18 @@ class DerIndefLenConverter { return null; } + int unused = dataSize - dataPos; + assert unused >= 0; + dataSize = dataPos; + newData = new byte[dataSize + numOfTotalLenBytes + unused]; - dataPos=0; newDataPos=0; index=0; + dataPos = 0; newDataPos = 0; index = 0; // write out the new byte array replacing all the indefinite-lengths // and EOCs while (dataPos < dataSize) { - writeTag(); - writeLengthAndValue(); + writeTag(); + writeLengthAndValue(); } System.arraycopy(indefData, dataSize, newData, dataSize + numOfTotalLenBytes, unused); @@ -395,7 +418,7 @@ class DerIndefLenConverter { if (result == null) { int next = in.read(); // This could block, but we need more if (next == -1) { - throw new IOException("not all indef len BER resolved"); + throw new IOException("not enough data to resolve indef len BER"); } int more = in.available(); // expand array to include next and more -- GitLab From 790dcc667dcf312a7cd807e1dd06e50c299e3ac3 Mon Sep 17 00:00:00 2001 From: Hai-May Chao Date: Wed, 30 Jun 2021 18:02:46 +0000 Subject: [PATCH 269/385] 8268506: More Manifest Digests Reviewed-by: xuelei, ahgross, weijun, rhalade --- .../sun/security/util/ManifestDigester.java | 10 +++++++--- .../sun/security/util/SignatureFileVerifier.java | 4 ++++ .../classes/jdk/security/jarsigner/JarSigner.java | 14 ++++++++++---- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/src/java.base/share/classes/sun/security/util/ManifestDigester.java b/src/java.base/share/classes/sun/security/util/ManifestDigester.java index 3920d8a6b76..969df7c0eb8 100644 --- a/src/java.base/share/classes/sun/security/util/ManifestDigester.java +++ b/src/java.base/share/classes/sun/security/util/ManifestDigester.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -331,8 +331,12 @@ public class ManifestDigester { * @see #MF_MAIN_ATTRS */ public Entry getMainAttsEntry(boolean oldStyle) { - mainAttsEntry.oldStyle = oldStyle; - return mainAttsEntry; + if (mainAttsEntry != null) { + mainAttsEntry.oldStyle = oldStyle; + return mainAttsEntry; + } else { + return null; + } } public Entry get(String name) { diff --git a/src/java.base/share/classes/sun/security/util/SignatureFileVerifier.java b/src/java.base/share/classes/sun/security/util/SignatureFileVerifier.java index 04e6e9a085f..1af7417b7f1 100644 --- a/src/java.base/share/classes/sun/security/util/SignatureFileVerifier.java +++ b/src/java.base/share/classes/sun/security/util/SignatureFileVerifier.java @@ -543,6 +543,10 @@ public class SignatureFileVerifier { MessageDigest digest = getDigest(algorithm); if (digest != null) { ManifestDigester.Entry mde = md.getMainAttsEntry(false); + if (mde == null) { + throw new SignatureException("Manifest Main Attribute check " + + "failed due to missing main attributes entry"); + } byte[] computedHash = mde.digest(digest); byte[] expectedHash = Base64.getMimeDecoder().decode((String)se.getValue()); diff --git a/src/jdk.jartool/share/classes/jdk/security/jarsigner/JarSigner.java b/src/jdk.jartool/share/classes/jdk/security/jarsigner/JarSigner.java index 4a17faec022..08fad553cc9 100644 --- a/src/jdk.jartool/share/classes/jdk/security/jarsigner/JarSigner.java +++ b/src/jdk.jartool/share/classes/jdk/security/jarsigner/JarSigner.java @@ -793,13 +793,19 @@ public final class JarSigner { ManifestDigester oldMd = new ManifestDigester(mfRawBytes); ManifestDigester newMd = new ManifestDigester(mfNewRawBytes); + ManifestDigester.Entry oldEntry = oldMd.getMainAttsEntry(); + // main attributes - if (manifest.getMainAttributes().equals( - oldManifest.getMainAttributes()) + if (oldEntry != null + && manifest.getMainAttributes().equals( + oldManifest.getMainAttributes()) && (manifest.getEntries().isEmpty() || - oldMd.getMainAttsEntry().isProperlyDelimited())) { - oldMd.getMainAttsEntry().reproduceRaw(baos); + oldEntry.isProperlyDelimited())) { + oldEntry.reproduceRaw(baos); } else { + if (newMd.getMainAttsEntry() == null) { + throw new SignatureException("Error getting new main attribute entry"); + } newMd.getMainAttsEntry().reproduceRaw(baos); } -- GitLab From 20e1a273c2de268c6540abfd78e985170cfa0c75 Mon Sep 17 00:00:00 2001 From: Hai-May Chao Date: Wed, 7 Jul 2021 00:49:23 +0000 Subject: [PATCH 270/385] 8268500: Better specified ParameterSpecs Reviewed-by: weijun, ahgross, rhalade --- .../share/classes/sun/security/pkcs/SignerInfo.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/java.base/share/classes/sun/security/pkcs/SignerInfo.java b/src/java.base/share/classes/sun/security/pkcs/SignerInfo.java index b651f43c184..1689672b7a9 100644 --- a/src/java.base/share/classes/sun/security/pkcs/SignerInfo.java +++ b/src/java.base/share/classes/sun/security/pkcs/SignerInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -515,6 +515,14 @@ public class SignerInfo implements DerEncoder { case "RSASSA-PSS": PSSParameterSpec spec = (PSSParameterSpec) SignatureUtil.getParamSpec(encAlg, encAlgId.getParameters()); + /* + * RFC 4056 section 3 for Signed-data: + * signatureAlgorithm MUST contain id-RSASSA-PSS. The algorithm + * parameters field MUST contain RSASSA-PSS-params. + */ + if (spec == null) { + throw new NoSuchAlgorithmException("Missing PSSParameterSpec for RSASSA-PSS algorithm"); + } if (!AlgorithmId.get(spec.getDigestAlgorithm()).equals(digAlgId)) { throw new NoSuchAlgorithmException("Incompatible digest algorithm"); } -- GitLab From 365a2d428cd67e5d9e01afc838e170132564133e Mon Sep 17 00:00:00 2001 From: Xue-Lei Andrew Fan Date: Thu, 8 Jul 2021 00:23:08 +0000 Subject: [PATCH 271/385] 8269618: Better session identification Reviewed-by: jnimeh, rhalade, ahgross --- .../sun/security/ssl/HelloCookieManager.java | 4 +- .../security/ssl/PreSharedKeyExtension.java | 3 +- .../sun/security/ssl/RandomCookie.java | 10 +-- .../sun/security/ssl/RenegoInfoExtension.java | 8 ++- .../classes/sun/security/ssl/SessionId.java | 3 +- .../classes/sun/security/util/ByteArrays.java | 67 +++++++++++++++++++ 6 files changed, 83 insertions(+), 12 deletions(-) create mode 100644 src/java.base/share/classes/sun/security/util/ByteArrays.java diff --git a/src/java.base/share/classes/sun/security/ssl/HelloCookieManager.java b/src/java.base/share/classes/sun/security/ssl/HelloCookieManager.java index 6880c929ab6..f2f7b0d5da4 100644 --- a/src/java.base/share/classes/sun/security/ssl/HelloCookieManager.java +++ b/src/java.base/share/classes/sun/security/ssl/HelloCookieManager.java @@ -208,7 +208,7 @@ abstract class HelloCookieManager { byte[] target = md.digest(secret); // 32 bytes target[0] = cookie[0]; - return Arrays.equals(target, cookie); + return MessageDigest.isEqual(target, cookie); } } @@ -361,7 +361,7 @@ abstract class HelloCookieManager { md.update(headerBytes); byte[] headerCookie = md.digest(secret); - if (!Arrays.equals(headerCookie, prevHeadCookie)) { + if (!MessageDigest.isEqual(headerCookie, prevHeadCookie)) { return false; } diff --git a/src/java.base/share/classes/sun/security/ssl/PreSharedKeyExtension.java b/src/java.base/share/classes/sun/security/ssl/PreSharedKeyExtension.java index 2d134f303fe..0b3481fbb19 100644 --- a/src/java.base/share/classes/sun/security/ssl/PreSharedKeyExtension.java +++ b/src/java.base/share/classes/sun/security/ssl/PreSharedKeyExtension.java @@ -31,7 +31,6 @@ import java.text.MessageFormat; import java.util.List; import java.util.ArrayList; import java.util.Locale; -import java.util.Arrays; import java.util.Collection; import javax.crypto.Mac; import javax.crypto.SecretKey; @@ -569,7 +568,7 @@ final class PreSharedKeyExtension { SecretKey binderKey = deriveBinderKey(shc, psk, session); byte[] computedBinder = computeBinder(shc, binderKey, session, pskBinderHash); - if (!Arrays.equals(binder, computedBinder)) { + if (!MessageDigest.isEqual(binder, computedBinder)) { throw shc.conContext.fatal(Alert.ILLEGAL_PARAMETER, "Incorect PSK binder value"); } diff --git a/src/java.base/share/classes/sun/security/ssl/RandomCookie.java b/src/java.base/share/classes/sun/security/ssl/RandomCookie.java index eb3d9500ca7..ef38196b2e7 100644 --- a/src/java.base/share/classes/sun/security/ssl/RandomCookie.java +++ b/src/java.base/share/classes/sun/security/ssl/RandomCookie.java @@ -25,10 +25,12 @@ package sun.security.ssl; +import sun.security.util.ByteArrays; + import java.io.*; import java.nio.ByteBuffer; +import java.security.MessageDigest; import java.security.SecureRandom; -import java.util.Arrays; /* * RandomCookie ... SSL hands standard format random cookies (nonces) @@ -111,7 +113,7 @@ final class RandomCookie { } boolean isHelloRetryRequest() { - return Arrays.equals(hrrRandomBytes, randomBytes); + return MessageDigest.isEqual(hrrRandomBytes, randomBytes); } // Used for client random validation of version downgrade protection. @@ -130,10 +132,10 @@ final class RandomCookie { } private boolean isT12Downgrade() { - return Arrays.equals(randomBytes, 24, 32, t12Protection, 0, 8); + return ByteArrays.isEqual(randomBytes, 24, 32, t12Protection, 0, 8); } private boolean isT11Downgrade() { - return Arrays.equals(randomBytes, 24, 32, t11Protection, 0, 8); + return ByteArrays.isEqual(randomBytes, 24, 32, t11Protection, 0, 8); } } diff --git a/src/java.base/share/classes/sun/security/ssl/RenegoInfoExtension.java b/src/java.base/share/classes/sun/security/ssl/RenegoInfoExtension.java index 732172a7341..2dbf7d0bf91 100644 --- a/src/java.base/share/classes/sun/security/ssl/RenegoInfoExtension.java +++ b/src/java.base/share/classes/sun/security/ssl/RenegoInfoExtension.java @@ -27,6 +27,7 @@ package sun.security.ssl; import java.io.IOException; import java.nio.ByteBuffer; +import java.security.MessageDigest; import java.text.MessageFormat; import java.util.Arrays; import java.util.Locale; @@ -37,6 +38,7 @@ import sun.security.ssl.SSLExtension.ExtensionConsumer; import static sun.security.ssl.SSLExtension.SH_RENEGOTIATION_INFO; import sun.security.ssl.SSLExtension.SSLExtensionSpec; import sun.security.ssl.SSLHandshake.HandshakeMessage; +import sun.security.util.ByteArrays; /** * Pack of the "renegotiation_info" extensions [RFC 5746]. @@ -239,7 +241,7 @@ final class RenegoInfoExtension { "renegotiation"); } else { // verify the client_verify_data value - if (!Arrays.equals(shc.conContext.clientVerifyData, + if (!MessageDigest.isEqual(shc.conContext.clientVerifyData, spec.renegotiatedConnection)) { throw shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, "Invalid renegotiation_info extension data: " + @@ -459,14 +461,14 @@ final class RenegoInfoExtension { } byte[] cvd = chc.conContext.clientVerifyData; - if (!Arrays.equals(spec.renegotiatedConnection, + if (!ByteArrays.isEqual(spec.renegotiatedConnection, 0, cvd.length, cvd, 0, cvd.length)) { throw chc.conContext.fatal(Alert.HANDSHAKE_FAILURE, "Invalid renegotiation_info in ServerHello: " + "unmatched client_verify_data value"); } byte[] svd = chc.conContext.serverVerifyData; - if (!Arrays.equals(spec.renegotiatedConnection, + if (!ByteArrays.isEqual(spec.renegotiatedConnection, cvd.length, infoLen, svd, 0, svd.length)) { throw chc.conContext.fatal(Alert.HANDSHAKE_FAILURE, "Invalid renegotiation_info in ServerHello: " + diff --git a/src/java.base/share/classes/sun/security/ssl/SessionId.java b/src/java.base/share/classes/sun/security/ssl/SessionId.java index f7dedc68fb3..95a524e736c 100644 --- a/src/java.base/share/classes/sun/security/ssl/SessionId.java +++ b/src/java.base/share/classes/sun/security/ssl/SessionId.java @@ -25,6 +25,7 @@ package sun.security.ssl; +import java.security.MessageDigest; import java.security.SecureRandom; import java.util.Arrays; import javax.net.ssl.SSLProtocolException; @@ -89,7 +90,7 @@ final class SessionId { if (obj instanceof SessionId) { SessionId that = (SessionId)obj; - return Arrays.equals(this.sessionId, that.sessionId); + return MessageDigest.isEqual(this.sessionId, that.sessionId); } return false; diff --git a/src/java.base/share/classes/sun/security/util/ByteArrays.java b/src/java.base/share/classes/sun/security/util/ByteArrays.java new file mode 100644 index 00000000000..1457489f4bf --- /dev/null +++ b/src/java.base/share/classes/sun/security/util/ByteArrays.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.security.util; + +/** + * A time-instance comparison of two byte arrays. + */ +public class ByteArrays { + // See the MessageDigest.isEqual(byte[] digesta, byte[] digestb) + // implementation. This is a potential enhancement of the + // MessageDigest class. + public static boolean isEqual(byte[] a, int aFromIndex, int aToIndex, + byte[] b, int bFromIndex, int bToIndex) { + if (a == b) { + return true; + } + + if (a == null || b == null) { + return false; + } + + if (a.length == 0) { + return b.length == 0; + } + + int lenA = aToIndex - aFromIndex; + int lenB = bToIndex - bFromIndex; + + if (lenB == 0) { + return lenA == 0; + } + + int result = 0; + result |= lenA - lenB; + + // time-constant comparison + for (int indexA = 0; indexA < lenA; indexA++) { + int indexB = ((indexA - lenB) >>> 31) * indexA; + result |= a[aFromIndex + indexA] ^ b[bFromIndex + indexB]; + } + + return result == 0; + } +} -- GitLab From c714707eac85b0771c86314f388f286c6a0b6f84 Mon Sep 17 00:00:00 2001 From: Xue-Lei Andrew Fan Date: Thu, 8 Jul 2021 04:37:39 +0000 Subject: [PATCH 272/385] 8268205: Enhance DTLS client handshake Reviewed-by: jnimeh, ahgross, rhalade --- .../sun/security/ssl/DTLSInputRecord.java | 37 +++++++++++++++++-- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/src/java.base/share/classes/sun/security/ssl/DTLSInputRecord.java b/src/java.base/share/classes/sun/security/ssl/DTLSInputRecord.java index 9fe425c49c8..931f45e68ff 100644 --- a/src/java.base/share/classes/sun/security/ssl/DTLSInputRecord.java +++ b/src/java.base/share/classes/sun/security/ssl/DTLSInputRecord.java @@ -567,6 +567,9 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { HashMap> holesMap; + // A map used to check duplicated handshake messages. + HashMap messageSeqMap; + HandshakeFlight() { this.handshakeType = HF_UNKNOWN; this.flightEpoch = 0; @@ -577,6 +580,7 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { this.maxRecordSeq = -1; this.holesMap = new HashMap<>(5); + this.messageSeqMap = new HashMap<>(5); } boolean isRetransmitOf(HandshakeFlight hs) { @@ -598,6 +602,7 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { hf.maxRecordSeq = this.maxRecordSeq; hf.holesMap = new HashMap<>(this.holesMap); + hf.messageSeqMap = new HashMap<>(this.messageSeqMap); return hf; } @@ -640,7 +645,7 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { } // Queue up a handshake message. - void queueUpHandshake(HandshakeFragment hsf) { + void queueUpHandshake(HandshakeFragment hsf) throws SSLProtocolException { if (!isDesirable(hsf)) { // Not a dedired record, discard it. return; @@ -707,6 +712,7 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { holes.add(new HoleDescriptor(0, hsf.messageLength)); } handshakeFlight.holesMap.put(hsf.handshakeType, holes); + handshakeFlight.messageSeqMap.put(hsf.handshakeType, hsf.messageSeq); } else if (holes.isEmpty()) { // Have got the full handshake message. This record may be // a handshake message retransmission. Discard this record. @@ -778,7 +784,8 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { } // Queue up a ChangeCipherSpec message - void queueUpChangeCipherSpec(RecordFragment rf) { + void queueUpChangeCipherSpec(RecordFragment rf) + throws SSLProtocolException { if (!isDesirable(rf)) { // Not a dedired record, discard it. return; @@ -807,7 +814,7 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { // Queue up a ciphertext message. // // Note: not yet be able to decrypt the message. - void queueUpFragment(RecordFragment rf) { + void queueUpFragment(RecordFragment rf) throws SSLProtocolException { if (!isDesirable(rf)) { // Not a dedired record, discard it. return; @@ -895,7 +902,7 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { // Is a desired record? // // Check for retransmission and lost records. - private boolean isDesirable(RecordFragment rf) { + private boolean isDesirable(RecordFragment rf) throws SSLProtocolException { // // Discard records old than the previous epoch. // @@ -970,6 +977,25 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { return false; } + // Unexpected duplicated handshake messages. + if (rf.recordEpoch == handshakeEpoch && + // For handshake messages only. + rf instanceof HandshakeFragment hsf && + // Check on the received handshake messages. + handshakeFlight.holesMap.containsKey(hsf.handshakeType)) { + Integer cachedMsgSeq = handshakeFlight.messageSeqMap.get( + hsf.handshakeType); + if (cachedMsgSeq != null && cachedMsgSeq != hsf.messageSeq) { + // Handshake messages of the same type but with different + // message sequence numbers are not allowed. + throw new SSLProtocolException( + "Two message sequence numbers are used for the " + + "same handshake message (" + + SSLHandshake.nameOf(hsf.handshakeType) + + ")"); + } + } + return true; } @@ -1086,6 +1112,9 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord { // cleanup holes map handshakeFlight.holesMap.clear(); + // cleanup handshake message sequence numbers map + handshakeFlight.messageSeqMap.clear(); + // Ready to accept new input record. flightIsReady = false; needToCheckFlight = false; -- GitLab From 9c4988daeb2098c26c02a6b31fbf88d01d03883a Mon Sep 17 00:00:00 2001 From: Jamil Nimeh Date: Thu, 8 Jul 2021 16:14:37 +0000 Subject: [PATCH 273/385] 8268193: Improve requests of certificates Reviewed-by: xuelei, rhalade, ahgross --- .../sun/security/ssl/CertificateRequest.java | 29 +++++++++++++++++++ .../security/ssl/ClientHandshakeContext.java | 7 ++++- .../sun/security/ssl/ServerKeyExchange.java | 13 ++++++++- 3 files changed, 47 insertions(+), 2 deletions(-) diff --git a/src/java.base/share/classes/sun/security/ssl/CertificateRequest.java b/src/java.base/share/classes/sun/security/ssl/CertificateRequest.java index e42f4886f0d..0c87727d96e 100644 --- a/src/java.base/share/classes/sun/security/ssl/CertificateRequest.java +++ b/src/java.base/share/classes/sun/security/ssl/CertificateRequest.java @@ -333,6 +333,16 @@ final class CertificateRequest { // clean up this consumer chc.handshakeConsumers.remove(SSLHandshake.CERTIFICATE_REQUEST.id); + chc.receivedCertReq = true; + + // If we're processing this message and the server's certificate + // message consumer has not already run then this is a state + // machine violation. + if (chc.handshakeConsumers.containsKey( + SSLHandshake.CERTIFICATE.id)) { + throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, + "Unexpected CertificateRequest handshake message"); + } SSLConsumer certStatCons = chc.handshakeConsumers.remove( SSLHandshake.CERTIFICATE_STATUS.id); @@ -659,6 +669,16 @@ final class CertificateRequest { // clean up this consumer chc.handshakeConsumers.remove(SSLHandshake.CERTIFICATE_REQUEST.id); + chc.receivedCertReq = true; + + // If we're processing this message and the server's certificate + // message consumer has not already run then this is a state + // machine violation. + if (chc.handshakeConsumers.containsKey( + SSLHandshake.CERTIFICATE.id)) { + throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, + "Unexpected CertificateRequest handshake message"); + } SSLConsumer certStatCons = chc.handshakeConsumers.remove( SSLHandshake.CERTIFICATE_STATUS.id); @@ -920,6 +940,15 @@ final class CertificateRequest { // clean up this consumer chc.handshakeConsumers.remove(SSLHandshake.CERTIFICATE_REQUEST.id); + chc.receivedCertReq = true; + + // Ensure that the CertificateRequest has not been sent prior + // to EncryptedExtensions + if (chc.handshakeConsumers.containsKey( + SSLHandshake.ENCRYPTED_EXTENSIONS.id)) { + throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, + "Unexpected CertificateRequest handshake message"); + } T13CertificateRequestMessage crm = new T13CertificateRequestMessage(chc, message); diff --git a/src/java.base/share/classes/sun/security/ssl/ClientHandshakeContext.java b/src/java.base/share/classes/sun/security/ssl/ClientHandshakeContext.java index 0ca4224c517..ff7690966bb 100644 --- a/src/java.base/share/classes/sun/security/ssl/ClientHandshakeContext.java +++ b/src/java.base/share/classes/sun/security/ssl/ClientHandshakeContext.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -90,6 +90,11 @@ class ClientHandshakeContext extends HandshakeContext { ClientHelloMessage initialClientHelloMsg = null; + // Flag to indicate receipt of a CertificateRequest message from + // the server. Because this is optional, we cannot guarantee + // the handshakeConsumers Map will always have it present there. + boolean receivedCertReq = false; + // PSK identity is selected in first Hello and used again after HRR byte[] pskIdentity; diff --git a/src/java.base/share/classes/sun/security/ssl/ServerKeyExchange.java b/src/java.base/share/classes/sun/security/ssl/ServerKeyExchange.java index b9c8febd238..7cfa8640c3c 100644 --- a/src/java.base/share/classes/sun/security/ssl/ServerKeyExchange.java +++ b/src/java.base/share/classes/sun/security/ssl/ServerKeyExchange.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 20121, Oracle and/or its affiliates. All rights reserved. * 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,6 +92,17 @@ final class ServerKeyExchange { // clean up this consumer chc.handshakeConsumers.remove(SSLHandshake.SERVER_KEY_EXCHANGE.id); + // Any receipt/consumption of the CertificateRequest before + // ServerKeyExchange is a state machine violation. We may not + // know for sure if an early CR message is a violation though until + // we have reached this point, due to other TLS features and + // optional messages. + if (chc.receivedCertReq) { + chc.receivedCertReq = false; // Reset flag + throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, + "Unexpected ServerKeyExchange handshake message"); + } + SSLConsumer certStatCons = chc.handshakeConsumers.remove( SSLHandshake.CERTIFICATE_STATUS.id); if (certStatCons != null) { -- GitLab From 44ce8673146ceb724ace75f4790f7f9c7d0e2bad Mon Sep 17 00:00:00 2001 From: Jamil Nimeh Date: Thu, 8 Jul 2021 17:17:34 +0000 Subject: [PATCH 274/385] 8270105: Fix ServerKeyExchange copyright Reviewed-by: jnimeh, weijun --- .../share/classes/sun/security/ssl/ServerKeyExchange.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/java.base/share/classes/sun/security/ssl/ServerKeyExchange.java b/src/java.base/share/classes/sun/security/ssl/ServerKeyExchange.java index 7cfa8640c3c..be5814acc50 100644 --- a/src/java.base/share/classes/sun/security/ssl/ServerKeyExchange.java +++ b/src/java.base/share/classes/sun/security/ssl/ServerKeyExchange.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 20121, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it -- GitLab From f2c5728a86729ebfd9303e3abef53b90dbf3d7f7 Mon Sep 17 00:00:00 2001 From: Jamil Nimeh Date: Thu, 8 Jul 2021 21:08:49 +0000 Subject: [PATCH 275/385] 8268199: Correct certificate requests Reviewed-by: xuelei, ahgross, rhalade --- .../sun/security/ssl/CertificateRequest.java | 29 +++++++++++++++++-- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/src/java.base/share/classes/sun/security/ssl/CertificateRequest.java b/src/java.base/share/classes/sun/security/ssl/CertificateRequest.java index 0c87727d96e..e13fcd6b973 100644 --- a/src/java.base/share/classes/sun/security/ssl/CertificateRequest.java +++ b/src/java.base/share/classes/sun/security/ssl/CertificateRequest.java @@ -31,6 +31,7 @@ import java.security.PrivateKey; import java.security.cert.X509Certificate; import java.text.MessageFormat; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashSet; @@ -729,7 +730,7 @@ final class CertificateRequest { // the SSLPossession. Instead, the choosePossession method // will use the accepted signature schemes in the message to // determine the set of acceptable certificate types to select from. - SSLPossession pos = choosePossession(chc); + SSLPossession pos = choosePossession(chc, crm); if (pos == null) { return; } @@ -739,8 +740,8 @@ final class CertificateRequest { SSLHandshake.CERTIFICATE_VERIFY); } - private static SSLPossession choosePossession(HandshakeContext hc) - throws IOException { + private static SSLPossession choosePossession(HandshakeContext hc, + T12CertificateRequestMessage crm) throws IOException { if (hc.peerRequestedCertSignSchemes == null || hc.peerRequestedCertSignSchemes.isEmpty()) { if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { @@ -750,6 +751,15 @@ final class CertificateRequest { return null; } + // Put the CR key type into a more friendly format for searching + List crKeyTypes = new ArrayList<>( + Arrays.asList(crm.getKeyTypes())); + // For TLS 1.2 only if RSA is a requested key type then we + // should also allow RSASSA-PSS. + if (crKeyTypes.contains("RSA")) { + crKeyTypes.add("RSASSA-PSS"); + } + Collection checkedKeyTypes = new HashSet<>(); List supportedKeyTypes = new ArrayList<>(); for (SignatureScheme ss : hc.peerRequestedCertSignSchemes) { @@ -784,6 +794,19 @@ final class CertificateRequest { "Unsupported authentication scheme: " + ss.name); } continue; + } else { + // Any auth object will have a set of allowed key types. + // This set should share at least one common algorithm with + // the CR's allowed key types. + if (Collections.disjoint(crKeyTypes, + Arrays.asList(ka.keyTypes))) { + if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + SSLLogger.warning( + "Unsupported authentication scheme: " + + ss.name); + } + continue; + } } supportedKeyTypes.add(ss.keyAlgorithm); } -- GitLab From 3ab356335dfe3c8ece88797de22b75fef247bd39 Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Mon, 12 Jul 2021 15:37:22 +0000 Subject: [PATCH 276/385] 8265574: Improve handling of sheets Reviewed-by: azvegint, prr, rhalade, mschoene, ahgross --- .../classes/javax/swing/text/rtf/RTFReader.java | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/java.desktop/share/classes/javax/swing/text/rtf/RTFReader.java b/src/java.desktop/share/classes/javax/swing/text/rtf/RTFReader.java index 0867e40defe..9d8bf130aa8 100644 --- a/src/java.desktop/share/classes/javax/swing/text/rtf/RTFReader.java +++ b/src/java.desktop/share/classes/javax/swing/text/rtf/RTFReader.java @@ -1002,19 +1002,27 @@ class StylesheetDestination return true; } - public Style realize() + public Style realize() { + return realize(null); + } + + private Style realize(Set alreadyMetBasisIndexSet) { Style basis = null; Style next = null; + if (alreadyMetBasisIndexSet == null) { + alreadyMetBasisIndexSet = new HashSet<>(); + } + if (realizedStyle != null) return realizedStyle; - if (basedOn != STYLENUMBER_NONE) { + if (basedOn != STYLENUMBER_NONE && alreadyMetBasisIndexSet.add(basedOn)) { StyleDefiningDestination styleDest; - styleDest = definedStyles.get(Integer.valueOf(basedOn)); + styleDest = definedStyles.get(basedOn); if (styleDest != null && styleDest != this) { - basis = styleDest.realize(); + basis = styleDest.realize(alreadyMetBasisIndexSet); } } -- GitLab From af82404b3cd04c00212c19afcaa703bb3e56f40e Mon Sep 17 00:00:00 2001 From: Jamsheed Mohammed C M Date: Thu, 15 Jul 2021 21:05:00 +0000 Subject: [PATCH 277/385] 8269624: Enhance method selection support Reviewed-by: vlivanov, rhalade, thartmann, iignatyev, jwilhelm, ahgross --- src/hotspot/share/code/dependencies.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/hotspot/share/code/dependencies.cpp b/src/hotspot/share/code/dependencies.cpp index 0eb6c58fb42..8ca9c59fc82 100644 --- a/src/hotspot/share/code/dependencies.cpp +++ b/src/hotspot/share/code/dependencies.cpp @@ -1842,6 +1842,26 @@ Klass* Dependencies::find_witness_AME(InstanceKlass* ctxk, Method* m, KlassDepCh return NULL; } +// This function is used by find_unique_concrete_method(non vtable based) +// to check whether subtype method overrides the base method. +static bool overrides(Method* sub_m, Method* base_m) { + assert(base_m != NULL, "base method should be non null"); + if (sub_m == NULL) { + return false; + } + /** + * If base_m is public or protected then sub_m always overrides. + * If base_m is !public, !protected and !private (i.e. base_m is package private) + * then sub_m should be in the same package as that of base_m. + * For package private base_m this is conservative approach as it allows only subset of all allowed cases in + * the jvm specification. + **/ + if (base_m->is_public() || base_m->is_protected() || + base_m->method_holder()->is_same_class_package(sub_m->method_holder())) { + return true; + } + return false; +} // Find the set of all non-abstract methods under ctxk that match m. // (The method m must be defined or inherited in ctxk.) @@ -1879,6 +1899,9 @@ Method* Dependencies::find_unique_concrete_method(InstanceKlass* ctxk, Method* m } else if (Dependencies::find_witness_AME(ctxk, fm) != NULL) { // Found a concrete subtype which does not override abstract root method. return NULL; + } else if (!overrides(fm, m)) { + // Found method doesn't override abstract root method. + return NULL; } assert(Dependencies::is_concrete_root_method(fm, ctxk) == Dependencies::is_concrete_method(m, ctxk), "mismatch"); #ifndef PRODUCT -- GitLab From 4e4a3cf657fc5bf34e47e5ef6ebe9e73038dc605 Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Fri, 16 Jul 2021 03:46:32 +0000 Subject: [PATCH 278/385] 8269763: The JEditorPane is blank after JDK-8265167 Reviewed-by: azvegint, prr --- .../share/classes/javax/swing/text/rtf/RTFParser.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/java.desktop/share/classes/javax/swing/text/rtf/RTFParser.java b/src/java.desktop/share/classes/javax/swing/text/rtf/RTFParser.java index 9b38c5cff57..259b63ed8ee 100644 --- a/src/java.desktop/share/classes/javax/swing/text/rtf/RTFParser.java +++ b/src/java.desktop/share/classes/javax/swing/text/rtf/RTFParser.java @@ -310,7 +310,8 @@ abstract class RTFParser extends AbstractFilter if (binaryBytesLeft > 0) { binaryBuf.write(ch); binaryBytesLeft--; - } else { + } + if (binaryBytesLeft == 0) { state = S_text; specialsTable = savedSpecials; savedSpecials = null; -- GitLab From 333b9d57150b0c4518f0fac1b0002a6f8a924080 Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Fri, 16 Jul 2021 16:25:11 +0000 Subject: [PATCH 279/385] 8265580: Enhanced style for RTF kit Reviewed-by: rhalade, azvegint, prr, mschoene --- .../javax/swing/text/rtf/RTFReader.java | 60 ++++++++++--------- 1 file changed, 32 insertions(+), 28 deletions(-) diff --git a/src/java.desktop/share/classes/javax/swing/text/rtf/RTFReader.java b/src/java.desktop/share/classes/javax/swing/text/rtf/RTFReader.java index 9d8bf130aa8..add3a86a891 100644 --- a/src/java.desktop/share/classes/javax/swing/text/rtf/RTFReader.java +++ b/src/java.desktop/share/classes/javax/swing/text/rtf/RTFReader.java @@ -36,7 +36,11 @@ import java.security.AccessController; import java.security.PrivilegedAction; import java.util.Dictionary; import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; import java.util.Hashtable; +import java.util.Map; +import java.util.Set; import java.util.Vector; import javax.swing.text.AttributeSet; @@ -85,12 +89,12 @@ class RTFReader extends RTFParser Dictionary fontTable; /** This array maps color indices to Color objects. */ Color[] colorTable; - /** This array maps character style numbers to Style objects. */ - Style[] characterStyles; - /** This array maps paragraph style numbers to Style objects. */ - Style[] paragraphStyles; - /** This array maps section style numbers to Style objects. */ - Style[] sectionStyles; + /** This Map maps character style numbers to Style objects. */ + Map characterStyles; + /** This Map maps paragraph style numbers to Style objects. */ + Map paragraphStyles; + /** This Map maps section style numbers to Style objects. */ + Map sectionStyles; /** This is the RTF version number, extracted from the \rtf keyword. * The version information is currently not used. */ @@ -861,9 +865,9 @@ class StylesheetDestination public void close() { - Vector