From 67979eb0771ff834d6d3d18ba5a8bfe161cfc2ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20Gr=C3=B6nlund?= Date: Wed, 17 Jul 2024 11:17:10 +0000 Subject: [PATCH 001/353] 8334781: JFR crash: assert(((((JfrTraceIdBits::load(klass)) & ((JfrTraceIdEpoch::this_epoch_method_and_class_bits()))) != 0))) failed: invariant Reviewed-by: egahlin --- .../recorder/checkpoint/types/jfrTypeSet.cpp | 4 ++++ .../checkpoint/types/jfrTypeSetUtils.hpp | 4 ++++ .../checkpoint/types/traceid/jfrTraceId.cpp | 18 +++++++++--------- .../traceid/jfrTraceIdLoadBarrier.inline.hpp | 4 ++-- .../types/traceid/jfrTraceIdMacros.hpp | 7 ++++++- .../share/jfr/support/jfrTraceIdExtension.hpp | 9 +++++---- .../share/prims/jvmtiRedefineClasses.cpp | 2 +- 7 files changed, 31 insertions(+), 17 deletions(-) diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp index 0c94765575239..203ec3a3ec494 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp @@ -310,7 +310,9 @@ static void set_serialized(const T* ptr) { assert(ptr != nullptr, "invariant"); if (current_epoch()) { CLEAR_THIS_EPOCH_CLEARED_BIT(ptr); + assert(!IS_THIS_EPOCH_CLEARED_BIT_SET(ptr), "invariant"); } + assert(IS_PREVIOUS_EPOCH_CLEARED_BIT_SET(ptr), "invariant"); SET_SERIALIZED(ptr); assert(IS_SERIALIZED(ptr), "invariant"); } @@ -929,9 +931,11 @@ void set_serialized(MethodPtr method) { assert(method != nullptr, "invariant"); if (current_epoch()) { CLEAR_THIS_EPOCH_METHOD_CLEARED_BIT(method); + assert(!IS_THIS_EPOCH_METHOD_CLEARED_BIT_SET(method), "invariant"); } assert(unloading() ? true : METHOD_IS_NOT_SERIALIZED(method), "invariant"); SET_METHOD_SERIALIZED(method); + assert(IS_PREVIOUS_EPOCH_METHOD_CLEARED_BIT_SET(method), "invariant"); assert(METHOD_IS_SERIALIZED(method), "invariant"); } diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp index 237745b13d93e..bfff7eaaf1b03 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp @@ -96,6 +96,8 @@ class ClearArtifact { assert(IS_NOT_TRANSIENT(value), "invariant"); SET_PREVIOUS_EPOCH_CLEARED_BIT(value); CLEAR_PREVIOUS_EPOCH_METHOD_AND_CLASS(value); + assert(IS_THIS_EPOCH_CLEARED_BIT_SET(value), "invariant"); + assert(IS_PREVIOUS_EPOCH_CLEARED_BIT_SET(value), "invariant"); return true; } }; @@ -111,6 +113,8 @@ class ClearArtifact { assert(METHOD_IS_NOT_TRANSIENT(method), "invariant"); SET_PREVIOUS_EPOCH_METHOD_CLEARED_BIT(method); CLEAR_PREVIOUS_EPOCH_METHOD_FLAG(method); + assert(IS_THIS_EPOCH_METHOD_CLEARED_BIT_SET(method), "invariant"); + assert(IS_PREVIOUS_EPOCH_METHOD_CLEARED_BIT_SET(method), "invariant"); return true; } }; diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceId.cpp b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceId.cpp index f07078eaf06de..d2973f748729a 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceId.cpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceId.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,22 +50,22 @@ static traceid atomic_inc(traceid volatile* const dest, traceid stride = 1) { static traceid next_class_id() { static volatile traceid class_id_counter = LAST_TYPE_ID + 1; // + 1 is for the void.class primitive - return atomic_inc(&class_id_counter) << TRACE_ID_SHIFT; + return (atomic_inc(&class_id_counter) << TRACE_ID_SHIFT) | EPOCH_CLEARED_BITS; } static traceid next_module_id() { static volatile traceid module_id_counter = 0; - return atomic_inc(&module_id_counter) << TRACE_ID_SHIFT; + return (atomic_inc(&module_id_counter) << TRACE_ID_SHIFT) | EPOCH_CLEARED_BITS; } static traceid next_package_id() { static volatile traceid package_id_counter = 0; - return atomic_inc(&package_id_counter) << TRACE_ID_SHIFT; + return (atomic_inc(&package_id_counter) << TRACE_ID_SHIFT) | EPOCH_CLEARED_BITS; } static traceid next_class_loader_data_id() { static volatile traceid cld_id_counter = 0; - return atomic_inc(&cld_id_counter) << TRACE_ID_SHIFT; + return (atomic_inc(&cld_id_counter) << TRACE_ID_SHIFT) | EPOCH_CLEARED_BITS; } static bool found_jdk_internal_event_klass = false; @@ -201,18 +201,18 @@ traceid JfrTraceId::load_raw(jclass jc) { // used by CDS / APPCDS as part of "remove_unshareable_info" void JfrTraceId::remove(const Klass* k) { assert(k != nullptr, "invariant"); - // Mask off and store the event flags. + // Mask off and store the event flags and epoch clear bits. // This mechanism will retain the event specific flags // in the archive, allowing for event flag restoration // when renewing the traceid on klass revival. - k->set_trace_id(EVENT_KLASS_MASK(k)); + k->set_trace_id(EPOCH_CLEARED_BITS | EVENT_KLASS_MASK(k)); } // used by CDS / APPCDS as part of "remove_unshareable_info" void JfrTraceId::remove(const Method* method) { assert(method != nullptr, "invariant"); - // Clear all bits. - method->set_trace_flags(0); + // Clear tag bits and set epoch cleared bits. + method->set_trace_flags(static_cast(EPOCH_CLEARED_BITS)); } // used by CDS / APPCDS as part of "restore_unshareable_info" diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdLoadBarrier.inline.hpp b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdLoadBarrier.inline.hpp index ed30233527400..5f986121ea020 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdLoadBarrier.inline.hpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdLoadBarrier.inline.hpp @@ -157,9 +157,9 @@ inline traceid JfrTraceIdLoadBarrier::load_leakp(const Klass* klass) { inline traceid JfrTraceIdLoadBarrier::load_leakp(const Klass* klass, const Method* method) { assert(klass != nullptr, "invariant"); - assert(METHOD_AND_CLASS_USED_THIS_EPOCH(klass), "invariant"); assert(method != nullptr, "invariant"); assert(klass == method->method_holder(), "invariant"); + assert(METHOD_AND_CLASS_USED_THIS_EPOCH(klass), "invariant"); if (should_tag(method)) { // the method is already logically tagged, just like the klass, // but because of redefinition, the latest Method* @@ -174,9 +174,9 @@ inline traceid JfrTraceIdLoadBarrier::load_leakp(const Klass* klass, const Metho inline traceid JfrTraceIdLoadBarrier::load_leakp_previuos_epoch(const Klass* klass, const Method* method) { assert(klass != nullptr, "invariant"); - assert(METHOD_AND_CLASS_USED_PREVIOUS_EPOCH(klass), "invariant"); assert(method != nullptr, "invariant"); assert(klass == method->method_holder(), "invariant"); + assert(METHOD_AND_CLASS_USED_PREVIOUS_EPOCH(klass), "invariant"); if (METHOD_FLAG_NOT_USED_PREVIOUS_EPOCH(method)) { // the method is already logically tagged, just like the klass, // but because of redefinition, the latest Method* diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdMacros.hpp b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdMacros.hpp index 3736c070f0ac9..f53eecad2cf9e 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdMacros.hpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdMacros.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,6 +48,7 @@ #define EPOCH_0_CLEARED_BIT (EPOCH_0_CLEARED_META_BIT << META_SHIFT) #define EPOCH_1_CLEARED_META_BIT (BIT << 1) #define EPOCH_1_CLEARED_BIT (EPOCH_1_CLEARED_META_BIT << META_SHIFT) +#define EPOCH_CLEARED_BITS (EPOCH_1_CLEARED_BIT | EPOCH_0_CLEARED_BIT) #define LEAKP_META_BIT (BIT << 2) #define LEAKP_BIT (LEAKP_META_BIT << META_SHIFT) #define TRANSIENT_META_BIT (BIT << 3) @@ -136,6 +137,8 @@ #define IS_TRANSIENT(ptr) (TRACE_ID_PREDICATE(ptr, TRANSIENT_BIT)) #define IS_NOT_TRANSIENT(ptr) (!(IS_TRANSIENT(ptr))) #define SET_SERIALIZED(ptr) (TRACE_ID_META_TAG(ptr, SERIALIZED_META_BIT)) +#define IS_THIS_EPOCH_CLEARED_BIT_SET(ptr) (TRACE_ID_PREDICATE(ptr, (THIS_EPOCH_BIT << META_SHIFT))) +#define IS_PREVIOUS_EPOCH_CLEARED_BIT_SET(ptr) (TRACE_ID_PREDICATE(ptr, (PREVIOUS_EPOCH_BIT << META_SHIFT))) #define IS_SERIALIZED(ptr) (TRACE_ID_PREDICATE(ptr, SERIALIZED_BIT)) #define IS_NOT_SERIALIZED(ptr) (!(IS_SERIALIZED(ptr))) #define SHOULD_TAG(ptr) (NOT_USED_THIS_EPOCH(ptr)) @@ -161,5 +164,7 @@ #define CLEAR_THIS_EPOCH_METHOD_CLEARED_BIT(ptr) (METHOD_META_MASK_CLEAR(ptr,(~(THIS_EPOCH_BIT)))) #define IS_THIS_EPOCH_METHOD_CLEARED(ptr) (METHOD_FLAG_PREDICATE(method, THIS_EPOCH_BIT)) #define IS_PREVIOUS_EPOCH_METHOD_CLEARED(ptr) (METHOD_FLAG_PREDICATE(method, PREVIOUS_EPOCH_BIT)) +#define IS_THIS_EPOCH_METHOD_CLEARED_BIT_SET(ptr) (METHOD_FLAG_PREDICATE(ptr, (THIS_EPOCH_BIT << META_SHIFT))) +#define IS_PREVIOUS_EPOCH_METHOD_CLEARED_BIT_SET(ptr) (METHOD_FLAG_PREDICATE(ptr, (PREVIOUS_EPOCH_BIT << META_SHIFT))) #endif // SHARE_JFR_RECORDER_CHECKPOINT_TYPES_TRACEID_JFRTRACEIDMACROS_HPP diff --git a/src/hotspot/share/jfr/support/jfrTraceIdExtension.hpp b/src/hotspot/share/jfr/support/jfrTraceIdExtension.hpp index 353e5c3f07c2b..c73ece42645c3 100644 --- a/src/hotspot/share/jfr/support/jfrTraceIdExtension.hpp +++ b/src/hotspot/share/jfr/support/jfrTraceIdExtension.hpp @@ -44,11 +44,13 @@ #define REMOVE_METHOD_ID(method) JfrTraceId::remove(method); #define RESTORE_ID(k) JfrTraceId::restore(k); +static constexpr const uint16_t cleared_epoch_bits = 512 | 256; + class JfrTraceFlag { private: mutable uint16_t _flags; public: - JfrTraceFlag() : _flags(0) {} + JfrTraceFlag() : _flags(cleared_epoch_bits) {} bool is_set(uint16_t flag) const { return (_flags & flag) != 0; } @@ -96,9 +98,8 @@ class JfrTraceFlag { uint8_t* trace_meta_addr() const { \ return _trace_flags.meta_addr(); \ } \ - void copy_trace_flags(uint8_t src_flags) const { \ - uint8_t flags = *_trace_flags.flags_addr(); \ - _trace_flags.set_flags(flags | src_flags); \ + void copy_trace_flags(uint16_t rhs_flags) const { \ + _trace_flags.set_flags(_trace_flags.flags() | rhs_flags); \ } #endif // SHARE_JFR_SUPPORT_JFRTRACEIDEXTENSION_HPP diff --git a/src/hotspot/share/prims/jvmtiRedefineClasses.cpp b/src/hotspot/share/prims/jvmtiRedefineClasses.cpp index 84010493dbcb6..344ef7802a2a6 100644 --- a/src/hotspot/share/prims/jvmtiRedefineClasses.cpp +++ b/src/hotspot/share/prims/jvmtiRedefineClasses.cpp @@ -1174,7 +1174,7 @@ jvmtiError VM_RedefineClasses::compare_and_normalize_class_versions( } } } - JFR_ONLY(k_new_method->copy_trace_flags(*k_old_method->trace_flags_addr());) + JFR_ONLY(k_new_method->copy_trace_flags(k_old_method->trace_flags());) log_trace(redefine, class, normalize) ("Method matched: new: %s [%d] == old: %s [%d]", k_new_method->name_and_sig_as_C_string(), ni, k_old_method->name_and_sig_as_C_string(), oi); From 871362870ea8dc5f4ac186876e91023116891a5b Mon Sep 17 00:00:00 2001 From: Suchismith Roy Date: Wed, 17 Jul 2024 11:24:08 +0000 Subject: [PATCH 002/353] 8334217: [AIX] Misleading error messages after JDK-8320005 Reviewed-by: jkern, mbaesken --- src/hotspot/os/aix/os_aix.cpp | 11 ++++++----- src/hotspot/os/aix/porting_aix.cpp | 5 ++++- src/hotspot/os/aix/porting_aix.hpp | 2 +- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/hotspot/os/aix/os_aix.cpp b/src/hotspot/os/aix/os_aix.cpp index dce12db3935b3..79e3175f1b655 100644 --- a/src/hotspot/os/aix/os_aix.cpp +++ b/src/hotspot/os/aix/os_aix.cpp @@ -1016,7 +1016,7 @@ bool os::dll_address_to_library_name(address addr, char* buf, return true; } -static void* dll_load_library(const char *filename, char *ebuf, int ebuflen) { +static void* dll_load_library(const char *filename, int *eno, char *ebuf, int ebuflen) { log_info(os)("attempting shared library load of %s", filename); if (ebuf && ebuflen > 0) { @@ -1044,7 +1044,7 @@ static void* dll_load_library(const char *filename, char *ebuf, int ebuflen) { void* result; const char* error_report = nullptr; JFR_ONLY(NativeLibraryLoadEvent load_event(filename, &result);) - result = Aix_dlopen(filename, dflags, &error_report); + result = Aix_dlopen(filename, dflags, eno, &error_report); if (result != nullptr) { Events::log_dll_message(nullptr, "Loaded shared library %s", filename); // Reload dll cache. Don't do this in signal handling. @@ -1076,12 +1076,13 @@ void *os::dll_load(const char *filename, char *ebuf, int ebuflen) { const char new_extension[] = ".a"; STATIC_ASSERT(sizeof(old_extension) >= sizeof(new_extension)); // First try to load the existing file. - result = dll_load_library(filename, ebuf, ebuflen); + int eno=0; + result = dll_load_library(filename, &eno, ebuf, ebuflen); // If the load fails,we try to reload by changing the extension to .a for .so files only. // Shared object in .so format dont have braces, hence they get removed for archives with members. - if (result == nullptr && pointer_to_dot != nullptr && strcmp(pointer_to_dot, old_extension) == 0) { + if (result == nullptr && eno == ENOENT && pointer_to_dot != nullptr && strcmp(pointer_to_dot, old_extension) == 0) { snprintf(pointer_to_dot, sizeof(old_extension), "%s", new_extension); - result = dll_load_library(file_path, ebuf, ebuflen); + result = dll_load_library(file_path, &eno, ebuf, ebuflen); } FREE_C_HEAP_ARRAY(char, file_path); return result; diff --git a/src/hotspot/os/aix/porting_aix.cpp b/src/hotspot/os/aix/porting_aix.cpp index ac0cc8d53d81d..cbc45d3e12234 100644 --- a/src/hotspot/os/aix/porting_aix.cpp +++ b/src/hotspot/os/aix/porting_aix.cpp @@ -1035,7 +1035,7 @@ static bool search_file_in_LIBPATH(const char* path, struct stat64x* stat) { // specific AIX versions for ::dlopen() and ::dlclose(), which handles the struct g_handletable // This way we mimic dl handle equality for a library // opened a second time, as it is implemented on other platforms. -void* Aix_dlopen(const char* filename, int Flags, const char** error_report) { +void* Aix_dlopen(const char* filename, int Flags, int *eno, const char** error_report) { assert(error_report != nullptr, "error_report is nullptr"); void* result; struct stat64x libstat; @@ -1047,6 +1047,7 @@ void* Aix_dlopen(const char* filename, int Flags, const char** error_report) { assert(result == nullptr, "dll_load: Could not stat() file %s, but dlopen() worked; Have to improve stat()", filename); #endif *error_report = "Could not load module .\nSystem error: No such file or directory"; + *eno = ENOENT; return nullptr; } else { @@ -1090,6 +1091,7 @@ void* Aix_dlopen(const char* filename, int Flags, const char** error_report) { p_handletable = new_tab; } // Library not yet loaded; load it, then store its handle in handle table + errno = 0; result = ::dlopen(filename, Flags); if (result != nullptr) { g_handletable_used++; @@ -1101,6 +1103,7 @@ void* Aix_dlopen(const char* filename, int Flags, const char** error_report) { } else { // error analysis when dlopen fails + *eno = errno; *error_report = ::dlerror(); if (*error_report == nullptr) { *error_report = "dlerror returned no error description"; diff --git a/src/hotspot/os/aix/porting_aix.hpp b/src/hotspot/os/aix/porting_aix.hpp index 109eceee3fca5..15f1e0afc549c 100644 --- a/src/hotspot/os/aix/porting_aix.hpp +++ b/src/hotspot/os/aix/porting_aix.hpp @@ -115,6 +115,6 @@ class AixMisc { }; -void* Aix_dlopen(const char* filename, int Flags, const char** error_report); +void* Aix_dlopen(const char* filename, int Flags, int *eno, const char** error_report); #endif // OS_AIX_PORTING_AIX_HPP From 6df7acbc74922d297852044596045a8b32636423 Mon Sep 17 00:00:00 2001 From: Pavel Rappo Date: Wed, 17 Jul 2024 12:20:17 +0000 Subject: [PATCH 003/353] 8299080: Wrong default value of snippet lang attribute Reviewed-by: jjg --- .../formats/html/taglets/SnippetTaglet.java | 77 ++++----- .../formats/html/taglets/snippet/Parser.java | 7 +- .../testMarkdown/TestMarkdownTaglets.java | 4 +- .../doclet/testSnippetTag/SnippetTester.java | 4 +- .../testSnippetTag/TestSnippetMarkup.java | 2 +- .../doclet/testSnippetTag/TestSnippetTag.java | 150 +++++++++++++++--- 6 files changed, 174 insertions(+), 70 deletions(-) diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SnippetTaglet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SnippetTaglet.java index f03b3d1bde150..0642b37406420 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SnippetTaglet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SnippetTaglet.java @@ -26,6 +26,8 @@ package jdk.javadoc.internal.doclets.formats.html.taglets; import java.io.IOException; +import java.net.URI; +import java.nio.file.Path; import java.util.EnumSet; import java.util.HashMap; import java.util.HashSet; @@ -65,41 +67,16 @@ import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; import jdk.javadoc.internal.doclets.toolkit.util.Utils; +import static jdk.javadoc.internal.doclets.formats.html.taglets.SnippetTaglet.Language.*; + /** * A taglet that represents the {@code @snippet} tag. */ public class SnippetTaglet extends BaseTaglet { public enum Language { - - JAVA("java"), - PROPERTIES("properties"); - - private static final Map languages; - - static { - Map tmp = new HashMap<>(); - for (var language : values()) { - String id = Objects.requireNonNull(language.identifier); - if (tmp.put(id, language) != null) - throw new IllegalStateException(); // 1-1 correspondence - } - languages = Map.copyOf(tmp); - } - - Language(String id) { - identifier = id; - } - - private final String identifier; - - public static Optional of(String identifier) { - if (identifier == null) - return Optional.empty(); - return Optional.ofNullable(languages.get(identifier)); - } - - public String getIdentifier() {return identifier;} + JAVA, + PROPERTIES; } SnippetTaglet(HtmlConfiguration config) { @@ -361,18 +338,30 @@ private Content generateContent(Element holder, DocTree tag) } } - String lang = null; + String lang; AttributeTree langAttr = attributes.get("lang"); - if (langAttr != null) { + + if (langAttr != null) { // the lang attribute overrides everything else lang = stringValueOf(langAttr); - } else if (containsClass) { + } else if (inlineContent != null && externalContent == null) { // an inline snippet lang = "java"; - } else if (containsFile) { - lang = languageFromFileName(fileObject.getName()); + } else if (externalContent != null) { // an external or a hybrid snippet + if (containsClass) { // the class attribute means Java + lang = "java"; + } else { + var uri = fileObject.toUri(); + var path = uri.getPath() != null ? uri.getPath() : ""; + var fileName = path.substring(path.lastIndexOf('/') + 1); + lang = languageFromFileName(fileName); + } + } else { + throw new AssertionError(); } - Optional language = Language.of(lang); - + var language = switch (lang) { + case "properties" -> PROPERTIES; + case null, default -> JAVA; + }; // TODO cache parsed external snippet (WeakHashMap) @@ -482,7 +471,7 @@ private static String diff(String inline, String external) { """.formatted(inline, external); } - private StyledText parse(Resources resources, Diags diags, Optional language, String content) throws ParseException { + private StyledText parse(Resources resources, Diags diags, Language language, String content) throws ParseException { Parser.Result result = new Parser(resources).parse(diags, language, content); result.actions().forEach(Action::perform); return result.text(); @@ -505,13 +494,15 @@ private static String stringValueOf(AttributeTree at) throws BadSnippetException } private String languageFromFileName(String fileName) { - // TODO: find a way to extend/customize the list of recognized file name extensions - if (fileName.endsWith(".java")) { - return "java"; - } else if (fileName.endsWith(".properties")) { - return "properties"; + // The assumption is simple: a file extension is the language + // identifier. + // Was about to use Path.getExtension introduced in 8057113, but then + // learned that it was removed in 8298303. + int lastPeriod = fileName.lastIndexOf('.'); + if (lastPeriod <= 0) { + return null; } - return null; + return (lastPeriod == fileName.length() - 1) ? null : fileName.substring(lastPeriod + 1); } private void error(TagletWriter writer, Element holder, DocTree tag, String key, Object... args) { diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/snippet/Parser.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/snippet/Parser.java index 907c2231a5c3f..61e687391de9a 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/snippet/Parser.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/snippet/Parser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -89,9 +89,8 @@ public Parser(Resources resources) { this.markupParser = new MarkupParser(resources); } - public Result parse(SnippetTaglet.Diags diags, Optional language, String source) throws ParseException { - SnippetTaglet.Language lang = language.orElse(SnippetTaglet.Language.JAVA); - var p = switch (lang) { + public Result parse(SnippetTaglet.Diags diags, SnippetTaglet.Language language, String source) throws ParseException { + var p = switch (language) { case JAVA -> JAVA_COMMENT; case PROPERTIES -> PROPERTIES_COMMENT; }; diff --git a/test/langtools/jdk/javadoc/doclet/testMarkdown/TestMarkdownTaglets.java b/test/langtools/jdk/javadoc/doclet/testMarkdown/TestMarkdownTaglets.java index abf7bb13593bd..d00eab1b74fd3 100644 --- a/test/langtools/jdk/javadoc/doclet/testMarkdown/TestMarkdownTaglets.java +++ b/test/langtools/jdk/javadoc/doclet/testMarkdown/TestMarkdownTaglets.java @@ -121,7 +121,7 @@ public void snippet_wrapped() { }
-
   this is snippet_standalone
+                    
   this is snippet_standalone
                     
@@ -131,7 +131,7 @@ public void snippet_wrapped() { }

First sentence.

Before.

-
   this is a snippet_wrapped
+                    
   this is a snippet_wrapped
                     
diff --git a/test/langtools/jdk/javadoc/doclet/testSnippetTag/SnippetTester.java b/test/langtools/jdk/javadoc/doclet/testSnippetTag/SnippetTester.java index 48d4fb75fc2e6..a0430126b1034 100644 --- a/test/langtools/jdk/javadoc/doclet/testSnippetTag/SnippetTester.java +++ b/test/langtools/jdk/javadoc/doclet/testSnippetTag/SnippetTester.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * 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,7 @@ protected void checkOutputEither(Output out, String first, String... other) { protected String getSnippetHtmlRepresentation(String pathToHtmlFile, String content) { - return getSnippetHtmlRepresentation(pathToHtmlFile, content, Optional.empty(), Optional.empty()); + return getSnippetHtmlRepresentation(pathToHtmlFile, content, Optional.of("java"), Optional.empty()); } protected String getSnippetHtmlRepresentation(String pathToHtmlFile, diff --git a/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestSnippetMarkup.java b/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestSnippetMarkup.java index 9a332fde1a9a8..627827582152e 100644 --- a/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestSnippetMarkup.java +++ b/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestSnippetMarkup.java @@ -366,7 +366,7 @@ public class A { case%s()
%s -
""".formatted(index, getSnippetHtmlRepresentation("A.html", t.expectedOutput(), Optional.empty(), Optional.of("snippet-case" + index + "()2"))); + """.formatted(index, getSnippetHtmlRepresentation("A.html", t.expectedOutput(), Optional.of("java"), Optional.of("snippet-case" + index + "()2"))); checkOutput("A.html", true, html); }); } diff --git a/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestSnippetTag.java b/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestSnippetTag.java index 7e79232ef72a2..413de03d23bb7 100644 --- a/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestSnippetTag.java +++ b/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestSnippetTag.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8266666 8275788 8276964 + * @bug 8266666 8275788 8276964 8299080 * @summary Implementation for snippets * @library /tools/lib ../../lib * @modules jdk.compiler/com.sun.tools.javac.api @@ -108,27 +108,27 @@ record SnippetAttributes(String content, String id, String lang) { } {@snippet id="foo1" : Hello, Snippet! } - """, "foo1", null), + """, "foo1", "java"), new SnippetAttributes(""" {@snippet id="foo2": Hello, Snippet! } - """, "foo2", null), + """, "foo2", "java"), new SnippetAttributes(""" {@snippet id='foo3' : Hello, Snippet! } - """, "foo3", null), + """, "foo3", "java"), new SnippetAttributes(""" {@snippet id='foo4': Hello, Snippet! } - """, "foo4", null), + """, "foo4", "java"), new SnippetAttributes(""" {@snippet id=foo5 : Hello, Snippet! } - """, "foo5", null), + """, "foo5", "java"), // (1) Haven't yet decided on this one. It's a consistency issue. On the one // hand, `:` is considered a part of a javadoc tag's name (e.g. JDK-4750173); // on the other hand, snippet markup treats `:` (next-line modifier) as a value @@ -137,28 +137,28 @@ record SnippetAttributes(String content, String id, String lang) { } // {@snippet id=foo6: // Hello, Snippet! // } -// """, "foo6", null), +// """, "foo6", "java"), new SnippetAttributes(""" {@snippet id="" : Hello, Snippet! } - """, null, null), + """, null, "java"), new SnippetAttributes(""" {@snippet id="": Hello, Snippet! } - """, null, null), + """, null, "java"), new SnippetAttributes(""" {@snippet id='': Hello, Snippet! } - """, null, null), + """, null, "java"), new SnippetAttributes(""" {@snippet id=: Hello, Snippet! } - """, null, null), + """, null, "java"), new SnippetAttributes(""" {@snippet lang="java" : Hello, Snippet! @@ -880,7 +880,7 @@ record TestCase(String input, String expectedOutput) { } """ case%s()
- %s""".formatted(id, getSnippetHtmlRepresentation("pkg/A.html", t.expectedOutput(), Optional.empty(), + %s""".formatted(id, getSnippetHtmlRepresentation("pkg/A.html", t.expectedOutput(), Optional.of("java"), Optional.of("snippet-case" + id + "()2")))); }); } @@ -973,7 +973,7 @@ record TestCase(String input, Function expectedTransformation) { """ case%s()
- %s""".formatted(index, getSnippetHtmlRepresentation("pkg/A.html", expectedOutput, Optional.empty(), + %s""".formatted(index, getSnippetHtmlRepresentation("pkg/A.html", expectedOutput, Optional.of("txt"), Optional.of("snippet-case" + index + "()2")))); }); } @@ -1552,7 +1552,7 @@ record TestCase(Snippet snippet, String expectedOutput) { } """ case%s()
- %s""".formatted(index, getSnippetHtmlRepresentation("pkg/A.html", t.expectedOutput(), Optional.empty(), + %s""".formatted(index, getSnippetHtmlRepresentation("pkg/A.html", t.expectedOutput(), Optional.of("java"), Optional.of("snippet-case" + index + "()2")))); }); } @@ -1666,13 +1666,13 @@ public void testPositiveInlineTagMarkup_SyntaxCurly(Path base) throws Exception """ case0()
- """ + getSnippetHtmlRepresentation("pkg/A.html", "", Optional.empty(), + """ + getSnippetHtmlRepresentation("pkg/A.html", "", Optional.of("txt"), Optional.of("snippet-case0()2"))); checkOutput("pkg/A.html", true, """ case1()
- """ + getSnippetHtmlRepresentation("pkg/A.html", "", Optional.empty(), + """ + getSnippetHtmlRepresentation("pkg/A.html", "", Optional.of("txt"), Optional.of("snippet-case1()2"))); } @@ -1851,12 +1851,126 @@ record TestCase(Snippet snippet, String expectedOutput) { } """ case%s()
- %s""".formatted(index, getSnippetHtmlRepresentation("pkg/A.html", t.expectedOutput(), Optional.empty(), + %s""".formatted(index, getSnippetHtmlRepresentation("pkg/A.html", t.expectedOutput(), Optional.of("java"), Optional.of("snippet-case" + index + "()2")))); }); } @Test + public void testPositiveExternalHybridLangAttribute(Path base) throws Exception { + + Path srcDir = base.resolve("src"); + Path outDir = base.resolve("out"); + + record TestCase(String tag, String expectedContent, String expectedLang) { } + + final var testCases = List.of( + // -------------------- external snippets -------------------- + // if there's no file extension and no lang attribute, then + // markup is that of "java" and the class="language-" attribute + // is absent + new TestCase(""" + {@snippet file=".file"} + """, """ + # @highlight substring=hi: + hi there + """, null), + new TestCase(""" + {@snippet file="file"} + """, """ + # @highlight substring=hi: + hi there + """, null), + // if the file extension differs from the value of the lang + // attribute, which is set to "java", "properties" or other, + // then the class="language-" attribute is that of lang and + // markup is that of "properties" for lang=properties and + // markup is that of "java" for anything else + new TestCase(""" + {@snippet file="File.java" lang=properties} + """, """ + hi there // @highlight substring=there + """, "properties"), + new TestCase(""" + {@snippet file="file.properties" lang=java} + """, """ + # @highlight substring=hi: + hi there + """, "java"), + new TestCase(""" + {@snippet file="File.java" lang=txt} + """, """ + # @highlight substring=hi: + hi there + """, "txt"), + // if there's no file extension, but the lang attribute is set + // to "java", "properties", or other, then the class="language-" + // attribute is that of lang and markup is that of "properties" + // for lang=properties and markup is that of "java" for + // anything else + new TestCase(""" + {@snippet file="file" lang=properties} + """, """ + hi there // @highlight substring=there + """, "properties"), + new TestCase(""" + {@snippet file="file" lang=java} + """, """ + # @highlight substring=hi: + hi there + """, "java"), + new TestCase(""" + {@snippet file="file" lang=txt} + """, """ + # @highlight substring=hi: + hi there + """, "txt"), + // --------------------- hybrid snippets --------------------- + // the lang attribute "overrides" file extension + new TestCase(""" + {@snippet file="File.java" lang=properties: + # @highlight substring=hi: + hi there // @highlight substring=there + } + """, """ + hi there // @highlight substring=there + """, "properties"), + // if the lang attribute is absent, file extension determines + // markup and the the class="language-" attribute + new TestCase(""" + {@snippet file="file.properties": + # @highlight substring=hi: + hi there // @highlight substring=there + } + """, """ + hi there // @highlight substring=there + """, "properties") + ); + + for (var f : List.of(".file", "file", "File.java", "file.properties")) + addSnippetFile(srcDir, "pkg", f, """ + # @highlight substring=hi: + hi there // @highlight substring=there + """); + + ClassBuilder classBuilder = new ClassBuilder(tb, "pkg.A") + .setModifiers("public", "class"); + forEachNumbered(testCases, (s, i) -> classBuilder.addMembers( + MethodBuilder.parse("public void case%s() { }".formatted(i)).setComments(s.tag))); + classBuilder.write(srcDir); + javadoc("-d", outDir.toString(), + "-sourcepath", srcDir.toString(), + "pkg"); + checkExit(Exit.OK); + forEachNumbered(testCases, (t, i) -> checkOutput("pkg/A.html", true, """ + case%s()
+
+ %s + """.formatted(i, getSnippetHtmlRepresentation("pkg/A.html", t.expectedContent, Optional.ofNullable(t.expectedLang), + Optional.of("snippet-case" + i + "()2"))))); + } + + //@Test public void testNegativeHybridTag_FileNotFound(Path base) throws Exception { Path srcDir = base.resolve("src"); Path outDir = base.resolve("out"); @@ -2310,7 +2424,7 @@ record TestCase(Snippet snippet, String expectedOutput) { } """ case%s()
- %s""".formatted(index, getSnippetHtmlRepresentation("pkg/A.html", t.expectedOutput(), Optional.empty(), + %s""".formatted(index, getSnippetHtmlRepresentation("pkg/A.html", t.expectedOutput(), Optional.of("txt"), Optional.of("snippet-case" + index + "()2")))); }); } From 7ec55df34af98e9a80381dba7f7f2127f2248f73 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Wed, 17 Jul 2024 14:49:00 +0000 Subject: [PATCH 004/353] 8336638: Parallel: Remove redundant mangle in PSScavenge::invoke Reviewed-by: zgu --- src/hotspot/share/gc/parallel/psScavenge.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/hotspot/share/gc/parallel/psScavenge.cpp b/src/hotspot/share/gc/parallel/psScavenge.cpp index 929eca54a5ce9..f3d8d90f80483 100644 --- a/src/hotspot/share/gc/parallel/psScavenge.cpp +++ b/src/hotspot/share/gc/parallel/psScavenge.cpp @@ -344,6 +344,9 @@ bool PSScavenge::invoke(bool clear_soft_refs) { PSOldGen* old_gen = heap->old_gen(); PSAdaptiveSizePolicy* size_policy = heap->size_policy(); + assert(young_gen->to_space()->is_empty(), + "Attempt to scavenge with live objects in to_space"); + heap->increment_total_collections(); if (AdaptiveSizePolicy::should_update_eden_stats(gc_cause)) { @@ -379,10 +382,6 @@ bool PSScavenge::invoke(bool clear_soft_refs) { // Let the size policy know we're starting size_policy->minor_collection_begin(); - assert(young_gen->to_space()->is_empty(), - "Attempt to scavenge with live objects in to_space"); - young_gen->to_space()->clear(SpaceDecorator::Mangle); - #if COMPILER2_OR_JVMCI DerivedPointerTable::clear(); #endif From 10186ff48fe67aeb83c028b47f6b7e5105513cf3 Mon Sep 17 00:00:00 2001 From: Naoto Sato Date: Wed, 17 Jul 2024 16:25:36 +0000 Subject: [PATCH 005/353] 8336300: DateFormatSymbols#getInstanceRef returns non-cached instance Reviewed-by: joehw, iris, jlu, aturbanov --- .../classes/java/text/DateFormatSymbols.java | 16 +--------------- .../classes/java/text/SimpleDateFormat.java | 4 ++-- 2 files changed, 3 insertions(+), 17 deletions(-) diff --git a/src/java.base/share/classes/java/text/DateFormatSymbols.java b/src/java.base/share/classes/java/text/DateFormatSymbols.java index 372752bf737a4..f08f5e7833804 100644 --- a/src/java.base/share/classes/java/text/DateFormatSymbols.java +++ b/src/java.base/share/classes/java/text/DateFormatSymbols.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -351,20 +351,6 @@ public static final DateFormatSymbols getInstance(Locale locale) { throw new RuntimeException("DateFormatSymbols instance creation failed."); } - /** - * Returns a DateFormatSymbols provided by a provider or found in - * the cache. Note that this method returns a cached instance, - * not its clone. Therefore, the instance should never be given to - * an application. - */ - static final DateFormatSymbols getInstanceRef(Locale locale) { - DateFormatSymbols dfs = getProviderInstance(locale); - if (dfs != null) { - return dfs; - } - throw new RuntimeException("DateFormatSymbols instance creation failed."); - } - private static DateFormatSymbols getProviderInstance(Locale locale) { LocaleProviderAdapter adapter = LocaleProviderAdapter.getAdapter(DateFormatSymbolsProvider.class, locale); DateFormatSymbolsProvider provider = adapter.getDateFormatSymbolsProvider(); diff --git a/src/java.base/share/classes/java/text/SimpleDateFormat.java b/src/java.base/share/classes/java/text/SimpleDateFormat.java index 6f4aa130a4145..dbc7235cbc4e1 100644 --- a/src/java.base/share/classes/java/text/SimpleDateFormat.java +++ b/src/java.base/share/classes/java/text/SimpleDateFormat.java @@ -623,7 +623,7 @@ public SimpleDateFormat(String pattern, Locale locale) initializeCalendar(locale); this.pattern = pattern; - this.formatData = DateFormatSymbols.getInstanceRef(locale); + formatData = DateFormatSymbols.getInstance(locale); this.locale = locale; initialize(locale); } @@ -644,7 +644,7 @@ public SimpleDateFormat(String pattern, DateFormatSymbols formatSymbols) } this.pattern = pattern; - this.formatData = (DateFormatSymbols) formatSymbols.clone(); + formatData = (DateFormatSymbols) formatSymbols.clone(); this.locale = Locale.getDefault(Locale.Category.FORMAT); initializeCalendar(this.locale); initialize(this.locale); From bcb5e69505f6cc8a4f323924cd2c58e630595fc0 Mon Sep 17 00:00:00 2001 From: Vladimir Kozlov Date: Wed, 17 Jul 2024 18:46:00 +0000 Subject: [PATCH 006/353] 8335921: Fix HotSpot VM build without JVMTI Reviewed-by: dholmes, shade --- make/hotspot/lib/JvmFeatures.gmk | 2 +- src/hotspot/share/jfr/instrumentation/jfrJvmtiAgent.hpp | 8 ++++---- src/hotspot/share/jfr/periodic/jfrPeriodic.cpp | 7 ++++++- src/hotspot/share/jfr/recorder/jfrRecorder.cpp | 4 ++-- src/hotspot/share/jvmci/jvmciCompilerToVM.hpp | 2 ++ src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp | 4 ++-- src/hotspot/share/jvmci/vmStructs_jvmci.cpp | 2 +- test/jdk/jdk/jfr/event/runtime/TestAgentEvent.java | 4 ++-- 8 files changed, 20 insertions(+), 13 deletions(-) diff --git a/make/hotspot/lib/JvmFeatures.gmk b/make/hotspot/lib/JvmFeatures.gmk index c8a58465d524b..a0136870d8c3c 100644 --- a/make/hotspot/lib/JvmFeatures.gmk +++ b/make/hotspot/lib/JvmFeatures.gmk @@ -84,7 +84,7 @@ ifneq ($(call check-jvm-feature, jvmti), true) jvmtiImpl.cpp jvmtiManageCapabilities.cpp jvmtiRawMonitor.cpp jvmtiUtil.cpp jvmtiTrace.cpp \ jvmtiCodeBlobEvents.cpp jvmtiEnv.cpp jvmtiRedefineClasses.cpp jvmtiEnvBase.cpp jvmtiEnvThreadState.cpp \ jvmtiTagMap.cpp jvmtiEventController.cpp evmCompat.cpp jvmtiEnter.xsl jvmtiExport.cpp \ - jvmtiClassFileReconstituter.cpp jvmtiTagMapTable.cpp jvmtiAgent.cpp jvmtiAgentList.cpp + jvmtiClassFileReconstituter.cpp jvmtiTagMapTable.cpp jvmtiAgent.cpp jvmtiAgentList.cpp jfrJvmtiAgent.cpp endif ifneq ($(call check-jvm-feature, jvmci), true) diff --git a/src/hotspot/share/jfr/instrumentation/jfrJvmtiAgent.hpp b/src/hotspot/share/jfr/instrumentation/jfrJvmtiAgent.hpp index bd11cdb54ed5b..22c1b5c62560b 100644 --- a/src/hotspot/share/jfr/instrumentation/jfrJvmtiAgent.hpp +++ b/src/hotspot/share/jfr/instrumentation/jfrJvmtiAgent.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,10 +32,10 @@ class JfrJvmtiAgent : public JfrCHeapObj { private: JfrJvmtiAgent(); ~JfrJvmtiAgent(); - static bool create(); - static void destroy(); + static bool create() NOT_JVMTI_RETURN_(true); + static void destroy() NOT_JVMTI_RETURN; public: - static void retransform_classes(JNIEnv* env, jobjectArray classes, TRAPS); + static void retransform_classes(JNIEnv* env, jobjectArray classes, TRAPS) NOT_JVMTI_RETURN; }; #endif // SHARE_JFR_INSTRUMENTATION_JFRJVMTIAGENT_HPP diff --git a/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp index 65b23e3433a60..d9aae89b99341 100644 --- a/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp +++ b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -280,6 +280,7 @@ TRACE_REQUEST_FUNC(SystemProcess) { } } +#if INCLUDE_JVMTI template static void send_agent_event(AgentEvent& event, const JvmtiAgent* agent) { event.set_name(agent->name()); @@ -316,6 +317,10 @@ TRACE_REQUEST_FUNC(NativeAgent) { const JvmtiAgentList::Iterator xrun_agents_it = JvmtiAgentList::xrun_agents(); send_native_agent_events(xrun_agents_it); } +#else // INCLUDE_JVMTI +TRACE_REQUEST_FUNC(JavaAgent) {} +TRACE_REQUEST_FUNC(NativeAgent) {} +#endif // INCLUDE_JVMTI TRACE_REQUEST_FUNC(ThreadContextSwitchRate) { double rate = 0.0; diff --git a/src/hotspot/share/jfr/recorder/jfrRecorder.cpp b/src/hotspot/share/jfr/recorder/jfrRecorder.cpp index cc460f8c2aad6..9aebdcc0afa19 100644 --- a/src/hotspot/share/jfr/recorder/jfrRecorder.cpp +++ b/src/hotspot/share/jfr/recorder/jfrRecorder.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -238,7 +238,7 @@ bool JfrRecorder::on_create_vm_2() { } bool JfrRecorder::on_create_vm_3() { - assert(JvmtiEnvBase::get_phase() == JVMTI_PHASE_LIVE, "invalid init sequence"); + JVMTI_ONLY( assert(JvmtiEnvBase::get_phase() == JVMTI_PHASE_LIVE, "invalid init sequence"); ) return CDSConfig::is_dumping_archive() || launch_command_line_recordings(JavaThread::current()); } diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.hpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.hpp index 665656d0be441..8fdb96a303825 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.hpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.hpp @@ -126,12 +126,14 @@ class CompilerToVM { // Minimum alignment of an offset into CodeBuffer::SECT_CONSTS static int data_section_item_alignment; +#if INCLUDE_JVMTI /* * Pointer to JvmtiExport::_should_notify_object_alloc. * Exposed as an int* instead of an address so the * underlying type is part of the JVMCIVMStructs definition. */ static int* _should_notify_object_alloc; +#endif public: static void initialize(JVMCI_TRAPS); diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp index 02cf6baff7827..f1028b4b2bb7e 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp @@ -144,7 +144,7 @@ address CompilerToVM::Data::symbol_clinit; int CompilerToVM::Data::data_section_item_alignment; -int* CompilerToVM::Data::_should_notify_object_alloc; +JVMTI_ONLY( int* CompilerToVM::Data::_should_notify_object_alloc; ) void CompilerToVM::Data::initialize(JVMCI_TRAPS) { Klass_vtable_start_offset = in_bytes(Klass::vtable_start_offset()); @@ -230,7 +230,7 @@ void CompilerToVM::Data::initialize(JVMCI_TRAPS) { data_section_item_alignment = relocInfo::addr_unit(); - _should_notify_object_alloc = &JvmtiExport::_should_notify_object_alloc; + JVMTI_ONLY( _should_notify_object_alloc = &JvmtiExport::_should_notify_object_alloc; ) BarrierSet* bs = BarrierSet::barrier_set(); if (bs->is_a(BarrierSet::CardTableBarrierSet)) { diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp index f55c7bf91a9b6..1e2ca0e990edb 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -138,7 +138,7 @@ \ static_field(CompilerToVM::Data, data_section_item_alignment, int) \ \ - static_field(CompilerToVM::Data, _should_notify_object_alloc, int*) \ + JVMTI_ONLY(static_field(CompilerToVM::Data, _should_notify_object_alloc, int*)) \ \ static_field(Abstract_VM_Version, _features, uint64_t) \ \ diff --git a/test/jdk/jdk/jfr/event/runtime/TestAgentEvent.java b/test/jdk/jdk/jfr/event/runtime/TestAgentEvent.java index 3bba83ffbe483..9becd4677e1c6 100644 --- a/test/jdk/jdk/jfr/event/runtime/TestAgentEvent.java +++ b/test/jdk/jdk/jfr/event/runtime/TestAgentEvent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,7 +46,7 @@ * @test * @key jfr * @summary Tests Agent Loaded event by starting native and Java agents - * @requires vm.hasJFR + * @requires vm.hasJFR & vm.jvmti * * @library /test/lib * @modules java.instrument From 78cc0f9569535c72900cf4617e22cef99f695e61 Mon Sep 17 00:00:00 2001 From: Nizar Benalla Date: Wed, 17 Jul 2024 21:39:19 +0000 Subject: [PATCH 007/353] 8336091: Fix HTML warnings in the generated HTML files Reviewed-by: dholmes --- make/jdk/src/classes/build/tools/fixuppandoc/Main.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/make/jdk/src/classes/build/tools/fixuppandoc/Main.java b/make/jdk/src/classes/build/tools/fixuppandoc/Main.java index 4f76cbdfaf85c..3d76457b596b8 100644 --- a/make/jdk/src/classes/build/tools/fixuppandoc/Main.java +++ b/make/jdk/src/classes/build/tools/fixuppandoc/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -638,7 +638,7 @@ void write(PrintWriter out) { index++; } boolean updateEndTd = false; - Pattern styleAttr = Pattern.compile("(?.*style=\")(? + + +

underlined

+

not underlined

+

not underlined

+

underlined?

+

underlined?

+ + + """; + + private static final boolean[] underlined = {true, false, false, true, true}; + + public static void main(String[] args) { + final JEditorPane html = new JEditorPane("text/html", HTML); + html.setEditable(false); + + final Dimension size = html.getPreferredSize(); + html.setSize(size); + + BufferedImage image = new BufferedImage(size.width, size.height, + BufferedImage.TYPE_INT_RGB); + Graphics g = image.createGraphics(); + // Paint the editor pane to ensure all views are created + html.paint(g); + g.dispose(); + + int errorCount = 0; + String firstError = null; + + System.out.println("----- Views -----"); + final View bodyView = html.getUI() + .getRootView(html) + .getView(1) + .getView(1); + for (int i = 0; i < bodyView.getViewCount(); i++) { + View pView = bodyView.getView(i); + View contentView = getContentView(pView); + + Object decorationAttr = + contentView.getAttributes() + .getAttribute(CSS.Attribute.TEXT_DECORATION); + String decoration = decorationAttr == null + ? "none" : decorationAttr.toString(); + + System.out.println(i + ": " + decoration); + if (decoration.contains("underline") != underlined[i]) { + errorCount++; + if (firstError == null) { + firstError = "Line " + i + ": " + decoration + " vs " + + (underlined[i] ? "underline" : "none"); + } + } + } + + if (errorCount > 0) { + saveImage(image); + throw new RuntimeException(errorCount + " error(s) found, " + + "the first one: " + firstError); + } + } + + private static View getContentView(View parent) { + View view = parent.getView(0); + return view.getViewCount() > 0 + ? getContentView(view) + : view; + } + + private static void saveImage(BufferedImage image) { + try { + ImageIO.write(image, "png", + new File("html.png")); + } catch (IOException ignored) { } + } +} From 5ff7c57f9ff5428ef3d2aedd7e860bb1e8ff29ea Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Fri, 26 Jul 2024 12:10:21 +0000 Subject: [PATCH 109/353] 8337168: Optimize LocalDateTime.toString Reviewed-by: liach, naoto --- .../share/classes/java/time/LocalDate.java | 20 +++++++++++++------ .../classes/java/time/LocalDateTime.java | 8 ++++++-- .../share/classes/java/time/LocalTime.java | 12 +++++++++-- 3 files changed, 30 insertions(+), 10 deletions(-) diff --git a/src/java.base/share/classes/java/time/LocalDate.java b/src/java.base/share/classes/java/time/LocalDate.java index b0d7ad33c8a3e..2d71fb1ceca54 100644 --- a/src/java.base/share/classes/java/time/LocalDate.java +++ b/src/java.base/share/classes/java/time/LocalDate.java @@ -2147,11 +2147,20 @@ public int hashCode() { */ @Override public String toString() { + var buf = new StringBuilder(10); + formatTo(buf); + return buf.toString(); + } + + /** + * Prints the toString result to the given buf, avoiding extra string allocations. + * Requires extra capacity of 10 to avoid StringBuilder reallocation. + */ + void formatTo(StringBuilder buf) { int yearValue = year; int monthValue = month; int dayValue = day; int absYear = Math.abs(yearValue); - StringBuilder buf = new StringBuilder(10); if (absYear < 1000) { if (yearValue < 0) { buf.append('-'); @@ -2164,11 +2173,10 @@ public String toString() { } buf.append(yearValue); } - return buf.append(monthValue < 10 ? "-0" : "-") - .append(monthValue) - .append(dayValue < 10 ? "-0" : "-") - .append(dayValue) - .toString(); + buf.append(monthValue < 10 ? "-0" : "-") + .append(monthValue) + .append(dayValue < 10 ? "-0" : "-") + .append(dayValue); } //----------------------------------------------------------------------- diff --git a/src/java.base/share/classes/java/time/LocalDateTime.java b/src/java.base/share/classes/java/time/LocalDateTime.java index 024aa1dacbeda..d14afb7d78f9a 100644 --- a/src/java.base/share/classes/java/time/LocalDateTime.java +++ b/src/java.base/share/classes/java/time/LocalDateTime.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1965,7 +1965,11 @@ public int hashCode() { */ @Override public String toString() { - return date.toString() + 'T' + time.toString(); + var buf = new StringBuilder(29); + date.formatTo(buf); + buf.append('T'); + time.formatTo(buf); + return buf.toString(); } //----------------------------------------------------------------------- diff --git a/src/java.base/share/classes/java/time/LocalTime.java b/src/java.base/share/classes/java/time/LocalTime.java index fd2c5ce4d4563..f28f8d3c5998a 100644 --- a/src/java.base/share/classes/java/time/LocalTime.java +++ b/src/java.base/share/classes/java/time/LocalTime.java @@ -1631,7 +1631,16 @@ public int hashCode() { */ @Override public String toString() { - StringBuilder buf = new StringBuilder(18); + var buf = new StringBuilder(18); + formatTo(buf); + return buf.toString(); + } + + /** + * Prints the toString result to the given buf, avoiding extra string allocations. + * Requires extra capacity of 18 to avoid StringBuilder reallocation. + */ + void formatTo(StringBuilder buf) { int hourValue = hour; int minuteValue = minute; int secondValue = second; @@ -1657,7 +1666,6 @@ public String toString() { buf.append(digits); } } - return buf.toString(); } //----------------------------------------------------------------------- From 3abe8a6e5e459fb764b8cef2425be50fe1a83fab Mon Sep 17 00:00:00 2001 From: Tomas Zezula Date: Fri, 26 Jul 2024 14:42:24 +0000 Subject: [PATCH 110/353] 8336663: [JVMCI] VM Crash on ZGC due to incompatible handle returned by HotSpotJVMCIRuntime#getJObjectValue Reviewed-by: dnsimon, never --- src/hotspot/share/jvmci/jvmciCompilerToVM.cpp | 18 +++++++++++++ .../jdk/vm/ci/hotspot/CompilerToVM.java | 6 +++++ .../vm/ci/hotspot/HotSpotJVMCIRuntime.java | 26 +++++++++---------- 3 files changed, 37 insertions(+), 13 deletions(-) diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp index 5583ad8a6f5be..fb49e9baca2b9 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp @@ -94,6 +94,12 @@ static void requireInHotSpot(const char* caller, JVMCI_TRAPS) { } } +static void requireNotInHotSpot(const char* caller, JVMCI_TRAPS) { + if (JVMCIENV->is_hotspot()) { + JVMCI_THROW_MSG(IllegalStateException, err_msg("Cannot call %s from HotSpot", caller)); + } +} + class JVMCITraceMark : public StackObj { const char* _msg; public: @@ -702,6 +708,17 @@ C2V_VMENTRY_NULL(jobject, lookupJClass, (JNIEnv* env, jobject, jlong jclass_valu return JVMCIENV->get_jobject(result); C2V_END +C2V_VMENTRY_0(jlong, getJObjectValue, (JNIEnv* env, jobject, jobject constant_jobject)) + requireNotInHotSpot("getJObjectValue", JVMCI_CHECK_0); + if (!THREAD->has_last_Java_frame()) { + JVMCI_THROW_MSG_0(IllegalStateException, err_msg("Cannot call getJObjectValue without Java frame anchor")); + } + JVMCIObject constant = JVMCIENV->wrap(constant_jobject); + Handle constant_value = JVMCIENV->asConstant(constant, JVMCI_CHECK_0); + jobject jni_handle = JNIHandles::make_local(THREAD, constant_value()); + return reinterpret_cast(jni_handle); +C2V_END + C2V_VMENTRY_NULL(jobject, getUncachedStringInPool, (JNIEnv* env, jobject, ARGUMENT_PAIR(cp), jint index)) constantPoolHandle cp(THREAD, UNPACK_PAIR(ConstantPool, cp)); constantTag tag = cp->tag_at(index); @@ -3254,6 +3271,7 @@ JNINativeMethod CompilerToVM::methods[] = { {CC "shouldInlineMethod", CC "(" HS_METHOD2 ")Z", FN_PTR(shouldInlineMethod)}, {CC "lookupType", CC "(" STRING HS_KLASS2 "IZ)" HS_RESOLVED_TYPE, FN_PTR(lookupType)}, {CC "lookupJClass", CC "(J)" HS_RESOLVED_TYPE, FN_PTR(lookupJClass)}, + {CC "getJObjectValue", CC "(" OBJECTCONSTANT ")J", FN_PTR(getJObjectValue)}, {CC "getArrayType", CC "(C" HS_KLASS2 ")" HS_KLASS, FN_PTR(getArrayType)}, {CC "lookupClass", CC "(" CLASS ")" HS_RESOLVED_TYPE, FN_PTR(lookupClass)}, {CC "lookupNameInPool", CC "(" HS_CONSTANT_POOL2 "II)" STRING, FN_PTR(lookupNameInPool)}, diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java index 14646fd027521..593697545266d 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java @@ -289,6 +289,12 @@ HotSpotResolvedJavaType lookupType(ClassLoader classLoader, String name) throws native HotSpotResolvedJavaType lookupJClass(long jclass); + /** + * Gets the {@code jobject} value wrapped by {@code peerObject}. + * Must not be called if {@link Services#IS_IN_NATIVE_IMAGE} is {@code false}. + */ + native long getJObjectValue(HotSpotObjectConstantImpl peerObject); + /** * Resolves the entry at index {@code cpi} in {@code constantPool} to an interned String object. * diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java index 3dcf855ff230f..3fd92f8dee5df 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java @@ -925,23 +925,23 @@ JavaType lookupTypeInternal(String name, HotSpotResolvedObjectType accessingType } /** - * Gets the {@code jobject} value wrapped by {@code peerObject}. The returned "naked" value is - * only valid as long as {@code peerObject} is valid. Note that the latter may be shorter than - * the lifetime of {@code peerObject}. As such, this method should only be used to pass an - * object parameter across a JNI call from the JVMCI shared library to HotSpot. This method must - * only be called from within the JVMCI shared library. + * Gets the {@code jobject} value wrapped by {@code peerObject}. The returned value is + * a JNI local reference whose lifetime is scoped by the nearest Java caller (from + * HotSpot's perspective). You can use {@code PushLocalFrame} and {@code PopLocalFrame} to + * shorten the lifetime of the reference. The current thread's state must be + * {@code _thread_in_native}. A call from the JVMCI shared library (e.g. libgraal) is in such + * a state. * - * @param peerObject a reference to an object in the peer runtime - * @return the {@code jobject} value wrapped by {@code peerObject} + * @param peerObject a reference to an object in the HotSpot heap + * @return the {@code jobject} value unpacked from {@code peerObject} * @throws IllegalArgumentException if the current runtime is not the JVMCI shared library or - * {@code peerObject} is not a peer object reference + * {@code peerObject} is not a HotSpot heap object reference + * @throws IllegalStateException if not called from within the JVMCI shared library + * or if there is no Java caller frame on the stack + * (i.e., JavaThread::has_last_Java_frame returns false) */ public long getJObjectValue(HotSpotObjectConstant peerObject) { - if (peerObject instanceof IndirectHotSpotObjectConstantImpl) { - IndirectHotSpotObjectConstantImpl remote = (IndirectHotSpotObjectConstantImpl) peerObject; - return remote.getHandle(); - } - throw new IllegalArgumentException("Cannot get jobject value for " + peerObject + " (" + peerObject.getClass().getName() + ")"); + return compilerToVm.getJObjectValue((HotSpotObjectConstantImpl)peerObject); } @Override From 4bcb8f04ed3623da7c84dda28017f473cbc97e53 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Fri, 26 Jul 2024 15:45:12 +0000 Subject: [PATCH 111/353] 8337243: Fix more -Wzero-as-null-pointer-constant warnings in compiler code Reviewed-by: vlivanov, kvn --- src/hotspot/share/c1/c1_LIRGenerator.cpp | 4 ++-- src/hotspot/share/ci/ciConstantPoolCache.cpp | 4 ++-- src/hotspot/share/ci/ciStreams.cpp | 4 ++-- src/hotspot/share/code/codeCache.cpp | 4 ++-- src/hotspot/share/code/dependencies.cpp | 2 +- src/hotspot/share/code/nmethod.cpp | 2 +- src/hotspot/share/code/oopRecorder.cpp | 8 ++++---- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/hotspot/share/c1/c1_LIRGenerator.cpp b/src/hotspot/share/c1/c1_LIRGenerator.cpp index cd08413565808..7b519804bfecd 100644 --- a/src/hotspot/share/c1/c1_LIRGenerator.cpp +++ b/src/hotspot/share/c1/c1_LIRGenerator.cpp @@ -1300,7 +1300,7 @@ void LIRGenerator::do_isPrimitive(Intrinsic* x) { } __ move(new LIR_Address(rcvr.result(), java_lang_Class::klass_offset(), T_ADDRESS), temp, info); - __ cmp(lir_cond_notEqual, temp, LIR_OprFact::metadataConst(0)); + __ cmp(lir_cond_notEqual, temp, LIR_OprFact::metadataConst(nullptr)); __ cmove(lir_cond_notEqual, LIR_OprFact::intConst(0), LIR_OprFact::intConst(1), result, T_BOOLEAN); } @@ -1333,7 +1333,7 @@ void LIRGenerator::do_getModifiers(Intrinsic* x) { // Check if this is a Java mirror of primitive type, and select the appropriate klass. LIR_Opr klass = new_register(T_METADATA); - __ cmp(lir_cond_equal, recv_klass, LIR_OprFact::metadataConst(0)); + __ cmp(lir_cond_equal, recv_klass, LIR_OprFact::metadataConst(nullptr)); __ cmove(lir_cond_equal, prim_klass, recv_klass, klass, T_ADDRESS); // Get the answer. diff --git a/src/hotspot/share/ci/ciConstantPoolCache.cpp b/src/hotspot/share/ci/ciConstantPoolCache.cpp index 8dc9cfc75e14b..e831516b0f70b 100644 --- a/src/hotspot/share/ci/ciConstantPoolCache.cpp +++ b/src/hotspot/share/ci/ciConstantPoolCache.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,7 +37,7 @@ ciConstantPoolCache::ciConstantPoolCache(Arena* arena, int expected_size) { _elements = - new (arena) GrowableArray(arena, expected_size, 0, 0); + new (arena) GrowableArray(arena, expected_size, 0, nullptr); _keys = new (arena) GrowableArray(arena, expected_size, 0, 0); } diff --git a/src/hotspot/share/ci/ciStreams.cpp b/src/hotspot/share/ci/ciStreams.cpp index 8220910d74c34..18d2a46a6862c 100644 --- a/src/hotspot/share/ci/ciStreams.cpp +++ b/src/hotspot/share/ci/ciStreams.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -135,7 +135,7 @@ Bytecodes::Code ciBytecodeStream::next_wide_or_table(Bytecodes::Code bc) { // ------------------------------------------------------------------ // ciBytecodeStream::reset_to_bci void ciBytecodeStream::reset_to_bci( int bci ) { - _bc_start=_was_wide=0; + _bc_start = _was_wide = nullptr; _pc = _start+bci; } diff --git a/src/hotspot/share/code/codeCache.cpp b/src/hotspot/share/code/codeCache.cpp index 4a54fd8d0a9c2..ea01dd759587a 100644 --- a/src/hotspot/share/code/codeCache.cpp +++ b/src/hotspot/share/code/codeCache.cpp @@ -165,8 +165,8 @@ class CodeBlob_sizes { // Iterate over all CodeBlobs (cb) on the given CodeHeap #define FOR_ALL_BLOBS(cb, heap) for (CodeBlob* cb = first_blob(heap); cb != nullptr; cb = next_blob(heap, cb)) -address CodeCache::_low_bound = 0; -address CodeCache::_high_bound = 0; +address CodeCache::_low_bound = nullptr; +address CodeCache::_high_bound = nullptr; volatile int CodeCache::_number_of_nmethods_with_dependencies = 0; ExceptionCache* volatile CodeCache::_exception_cache_purge_list = nullptr; diff --git a/src/hotspot/share/code/dependencies.cpp b/src/hotspot/share/code/dependencies.cpp index 7d3b744313f12..074846e2e7919 100644 --- a/src/hotspot/share/code/dependencies.cpp +++ b/src/hotspot/share/code/dependencies.cpp @@ -72,7 +72,7 @@ void Dependencies::initialize(ciEnv* env) { #endif DEBUG_ONLY(_deps[end_marker] = nullptr); for (int i = (int)FIRST_TYPE; i < (int)TYPE_LIMIT; i++) { - _deps[i] = new(arena) GrowableArray(arena, 10, 0, 0); + _deps[i] = new(arena) GrowableArray(arena, 10, 0, nullptr); } _content_bytes = nullptr; _size_in_bytes = (size_t)-1; diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 54aeac6be0495..0bab731ac565e 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -3270,7 +3270,7 @@ void nmethod::print_recorded_oop(int log_n, int i) { if (value == Universe::non_oop_word()) { tty->print("non-oop word"); } else { - if (value == 0) { + if (value == nullptr) { tty->print("nullptr-oop"); } else { oop_at(i)->print_value_on(tty); diff --git a/src/hotspot/share/code/oopRecorder.cpp b/src/hotspot/share/code/oopRecorder.cpp index b8ecc1eccc0d1..fd13b1050410e 100644 --- a/src/hotspot/share/code/oopRecorder.cpp +++ b/src/hotspot/share/code/oopRecorder.cpp @@ -68,11 +68,11 @@ template void ValueRecorder::copy_values_to(nmethod* nm) { template void ValueRecorder::maybe_initialize() { if (_handles == nullptr) { if (_arena != nullptr) { - _handles = new(_arena) GrowableArray(_arena, 10, 0, 0); - _no_finds = new(_arena) GrowableArray( _arena, 10, 0, 0); + _handles = new(_arena) GrowableArray(_arena, 10, 0, T{}); + _no_finds = new(_arena) GrowableArray(_arena, 10, 0, 0); } else { - _handles = new GrowableArray(10, 0, 0); - _no_finds = new GrowableArray( 10, 0, 0); + _handles = new GrowableArray(10, 0, T{}); + _no_finds = new GrowableArray(10, 0, 0); } } } From f35af7171213c09107b99104a73022853bff91b0 Mon Sep 17 00:00:00 2001 From: Kelvin Nilsen Date: Fri, 26 Jul 2024 15:55:12 +0000 Subject: [PATCH 112/353] 8334315: Shenandoah: reduce GC logging noise Reviewed-by: wkemper, ysr, shade --- .../share/gc/shenandoah/shenandoahFreeSet.cpp | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp index 582c0d18d3ede..b47bb109031c8 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp @@ -48,19 +48,19 @@ static const char* partition_name(ShenandoahFreeSetPartitionId t) { #ifndef PRODUCT void ShenandoahRegionPartitions::dump_bitmap() const { - log_info(gc)("Mutator range [" SSIZE_FORMAT ", " SSIZE_FORMAT "], Collector range [" SSIZE_FORMAT ", " SSIZE_FORMAT "]", - _leftmosts[int(ShenandoahFreeSetPartitionId::Mutator)], - _rightmosts[int(ShenandoahFreeSetPartitionId::Mutator)], - _leftmosts[int(ShenandoahFreeSetPartitionId::Collector)], - _rightmosts[int(ShenandoahFreeSetPartitionId::Collector)]); - log_info(gc)("Empty Mutator range [" SSIZE_FORMAT ", " SSIZE_FORMAT - "], Empty Collector range [" SSIZE_FORMAT ", " SSIZE_FORMAT "]", - _leftmosts_empty[int(ShenandoahFreeSetPartitionId::Mutator)], - _rightmosts_empty[int(ShenandoahFreeSetPartitionId::Mutator)], - _leftmosts_empty[int(ShenandoahFreeSetPartitionId::Collector)], - _rightmosts_empty[int(ShenandoahFreeSetPartitionId::Collector)]); - - log_info(gc)("%6s: %18s %18s %18s", "index", "Mutator Bits", "Collector Bits", "NotFree Bits"); + log_debug(gc)("Mutator range [" SSIZE_FORMAT ", " SSIZE_FORMAT "], Collector range [" SSIZE_FORMAT ", " SSIZE_FORMAT "]", + _leftmosts[int(ShenandoahFreeSetPartitionId::Mutator)], + _rightmosts[int(ShenandoahFreeSetPartitionId::Mutator)], + _leftmosts[int(ShenandoahFreeSetPartitionId::Collector)], + _rightmosts[int(ShenandoahFreeSetPartitionId::Collector)]); + log_debug(gc)("Empty Mutator range [" SSIZE_FORMAT ", " SSIZE_FORMAT + "], Empty Collector range [" SSIZE_FORMAT ", " SSIZE_FORMAT "]", + _leftmosts_empty[int(ShenandoahFreeSetPartitionId::Mutator)], + _rightmosts_empty[int(ShenandoahFreeSetPartitionId::Mutator)], + _leftmosts_empty[int(ShenandoahFreeSetPartitionId::Collector)], + _rightmosts_empty[int(ShenandoahFreeSetPartitionId::Collector)]); + + log_debug(gc)("%6s: %18s %18s %18s", "index", "Mutator Bits", "Collector Bits", "NotFree Bits"); dump_bitmap_range(0, _max-1); } @@ -83,8 +83,8 @@ void ShenandoahRegionPartitions::dump_bitmap_row(idx_t region_idx) const { uintx collector_bits = _membership[int(ShenandoahFreeSetPartitionId::Collector)].bits_at(aligned_idx); uintx free_bits = mutator_bits | collector_bits; uintx notfree_bits = ~free_bits; - log_info(gc)(SSIZE_FORMAT_W(6) ": " SIZE_FORMAT_X_0 " 0x" SIZE_FORMAT_X_0 " 0x" SIZE_FORMAT_X_0, - aligned_idx, mutator_bits, collector_bits, notfree_bits); + log_debug(gc)(SSIZE_FORMAT_W(6) ": " SIZE_FORMAT_X_0 " 0x" SIZE_FORMAT_X_0 " 0x" SIZE_FORMAT_X_0, + aligned_idx, mutator_bits, collector_bits, notfree_bits); } #endif @@ -1060,8 +1060,8 @@ void ShenandoahFreeSet::move_regions_from_collector_to_mutator(size_t max_xfer_r } size_t collector_xfer = collector_empty_xfer + collector_not_empty_xfer; - log_info(gc)("At start of update refs, moving " SIZE_FORMAT "%s to Mutator free partition from Collector Reserve", - byte_size_in_proper_unit(collector_xfer), proper_unit_for_byte_size(collector_xfer)); + log_info(gc, ergo)("At start of update refs, moving " SIZE_FORMAT "%s to Mutator free partition from Collector Reserve", + byte_size_in_proper_unit(collector_xfer), proper_unit_for_byte_size(collector_xfer)); } void ShenandoahFreeSet::prepare_to_rebuild(size_t &cset_regions) { From 4f194f10a1481cdc9df4e6338f6cabd07a34c84c Mon Sep 17 00:00:00 2001 From: William Kemper Date: Fri, 26 Jul 2024 15:57:58 +0000 Subject: [PATCH 113/353] 8337241: Shenandoah: Normalize include guards Reviewed-by: shade --- src/hotspot/share/gc/shenandoah/shenandoahController.hpp | 6 +++--- src/hotspot/share/gc/shenandoah/shenandoahMarkBitMap.hpp | 6 +++--- .../share/gc/shenandoah/shenandoahMarkBitMap.inline.hpp | 6 +++--- .../share/gc/shenandoah/shenandoahReferenceProcessor.hpp | 6 +++--- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahController.hpp b/src/hotspot/share/gc/shenandoah/shenandoahController.hpp index 2808f30b44459..6c28ff4e969c7 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahController.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahController.hpp @@ -22,8 +22,8 @@ * */ -#ifndef LINUX_X86_64_SERVER_SLOWDEBUG_SHENANDOAHCONTROLLER_HPP -#define LINUX_X86_64_SERVER_SLOWDEBUG_SHENANDOAHCONTROLLER_HPP +#ifndef SHARE_GC_SHENANDOAH_SHENANDOAHCONTROLLER_HPP +#define SHARE_GC_SHENANDOAH_SHENANDOAHCONTROLLER_HPP #include "gc/shared/gcCause.hpp" #include "gc/shared/concurrentGCThread.hpp" @@ -102,4 +102,4 @@ class ShenandoahController: public ConcurrentGCThread { size_t get_gc_id(); void update_gc_id(); }; -#endif //LINUX_X86_64_SERVER_SLOWDEBUG_SHENANDOAHCONTROLLER_HPP +#endif // SHARE_GC_SHENANDOAH_SHENANDOAHCONTROLLER_HPP diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMarkBitMap.hpp b/src/hotspot/share/gc/shenandoah/shenandoahMarkBitMap.hpp index 40f48bae6f55a..06ea6a8e232b8 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMarkBitMap.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMarkBitMap.hpp @@ -23,8 +23,8 @@ * */ -#ifndef SHARE_VM_GC_SHENANDOAH_SHENANDOAHMARKBITMAP_HPP -#define SHARE_VM_GC_SHENANDOAH_SHENANDOAHMARKBITMAP_HPP +#ifndef SHARE_GC_SHENANDOAH_SHENANDOAHMARKBITMAP_HPP +#define SHARE_GC_SHENANDOAH_SHENANDOAHMARKBITMAP_HPP #include "memory/memRegion.hpp" #include "runtime/atomic.hpp" @@ -176,4 +176,4 @@ class ShenandoahMarkBitMap { }; -#endif // SHARE_VM_GC_SHENANDOAH_SHENANDOAHMARKBITMAP_HPP +#endif // SHARE_GC_SHENANDOAH_SHENANDOAHMARKBITMAP_HPP diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMarkBitMap.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahMarkBitMap.inline.hpp index 62c0eaea139a2..bf9261f47ac5c 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMarkBitMap.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMarkBitMap.inline.hpp @@ -23,8 +23,8 @@ * */ -#ifndef SHARE_VM_GC_SHENANDOAH_SHENANDOAHMARKBITMAP_INLINE_HPP -#define SHARE_VM_GC_SHENANDOAH_SHENANDOAHMARKBITMAP_INLINE_HPP +#ifndef SHARE_GC_SHENANDOAH_SHENANDOAHMARKBITMAP_INLINE_HPP +#define SHARE_GC_SHENANDOAH_SHENANDOAHMARKBITMAP_INLINE_HPP #include "gc/shenandoah/shenandoahMarkBitMap.hpp" @@ -205,4 +205,4 @@ inline void ShenandoahMarkBitMap::clear_range_of_words(idx_t beg, idx_t end) { } -#endif // SHARE_VM_GC_SHENANDOAH_SHENANDOAHMARKBITMAP_INLINE_HPP +#endif // SHARE_GC_SHENANDOAH_SHENANDOAHMARKBITMAP_INLINE_HPP diff --git a/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.hpp b/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.hpp index c4ecf8d359a17..fa5235517907e 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.hpp @@ -23,8 +23,8 @@ * */ -#ifndef SHARE_VM_GC_SHENANDOAH_SHENANDOAHREFERENCEPROCESSOR_HPP -#define SHARE_VM_GC_SHENANDOAH_SHENANDOAHREFERENCEPROCESSOR_HPP +#ifndef SHARE_GC_SHENANDOAH_SHENANDOAHREFERENCEPROCESSOR_HPP +#define SHARE_GC_SHENANDOAH_SHENANDOAHREFERENCEPROCESSOR_HPP #include "gc/shared/referenceDiscoverer.hpp" #include "gc/shared/referencePolicy.hpp" @@ -188,4 +188,4 @@ class ShenandoahReferenceProcessor : public ReferenceDiscoverer { void abandon_partial_discovery(); }; -#endif // SHARE_VM_GC_SHENANDOAH_SHENANDOAHREFERENCEPROCESSOR_HPP +#endif // SHARE_GC_SHENANDOAH_SHENANDOAHREFERENCEPROCESSOR_HPP From 0c3720b42176c7bc92105be87df7449973fbcea0 Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Fri, 26 Jul 2024 17:39:00 +0000 Subject: [PATCH 114/353] 8335131: Test "javax/swing/JColorChooser/Test6977726.java" failed on ubuntu x64 because "Preview" title is missing for GTK L&F Reviewed-by: dnguyen, psadhukhan --- test/jdk/javax/swing/JColorChooser/Test6977726.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/test/jdk/javax/swing/JColorChooser/Test6977726.java b/test/jdk/javax/swing/JColorChooser/Test6977726.java index a79931c93eb55..1ec72036f14d3 100644 --- a/test/jdk/javax/swing/JColorChooser/Test6977726.java +++ b/test/jdk/javax/swing/JColorChooser/Test6977726.java @@ -41,7 +41,14 @@ public static void main(String[] args) throws Exception { String instructions = """ Check that there is a panel with "Text Preview Panel" text and with title "Preview" in the JColorChooser. - Test passes if the panel is as described, test fails otherwise."""; + Test passes if the panel is as described, test fails otherwise. + + Note: "Preview" title is not applicable for GTK Look and Feel."""; + + // In case this test is run with GTK L&F, the preview panel title + // is missing due to the "ColorChooser.showPreviewPanelText" property + // which is set to "Boolean.FALSE" for GTK L&F. Test instructions are + // modified to reflect that "Preview" title is not applicable for GTK L&F. PassFailJFrame.builder() .title("Test6977726") From abc4ca5a8c440f8f3f36a9b35036772c5b5ee7ea Mon Sep 17 00:00:00 2001 From: Alex Menkov Date: Fri, 26 Jul 2024 17:55:35 +0000 Subject: [PATCH 115/353] 8330427: Obsolete -XX:+PreserveAllAnnotations Reviewed-by: dholmes, sspitsyn, coleenp --- .../share/classfile/classFileParser.cpp | 166 +++------------- .../share/classfile/classFileParser.hpp | 14 +- .../prims/jvmtiClassFileReconstituter.cpp | 34 +--- .../prims/jvmtiClassFileReconstituter.hpp | 7 - src/hotspot/share/runtime/arguments.cpp | 2 +- src/hotspot/share/runtime/globals.hpp | 4 - .../RetransformRecordAnnotation.java | 187 ------------------ 7 files changed, 39 insertions(+), 375 deletions(-) delete mode 100644 test/jdk/java/lang/instrument/RetransformRecordAnnotation.java diff --git a/src/hotspot/share/classfile/classFileParser.cpp b/src/hotspot/share/classfile/classFileParser.cpp index bceade3b51b95..ddde58e5d20b3 100644 --- a/src/hotspot/share/classfile/classFileParser.cpp +++ b/src/hotspot/share/classfile/classFileParser.cpp @@ -1227,12 +1227,8 @@ void ClassFileParser::parse_field_attributes(const ClassFileStream* const cfs, bool is_synthetic = false; const u1* runtime_visible_annotations = nullptr; int runtime_visible_annotations_length = 0; - const u1* runtime_invisible_annotations = nullptr; - int runtime_invisible_annotations_length = 0; const u1* runtime_visible_type_annotations = nullptr; int runtime_visible_type_annotations_length = 0; - const u1* runtime_invisible_type_annotations = nullptr; - int runtime_invisible_type_annotations_length = 0; bool runtime_invisible_annotations_exists = false; bool runtime_invisible_type_annotations_exists = false; const ConstantPool* const cp = _cp; @@ -1315,11 +1311,6 @@ void ClassFileParser::parse_field_attributes(const ClassFileStream* const cfs, return; } runtime_invisible_annotations_exists = true; - if (PreserveAllAnnotations) { - runtime_invisible_annotations_length = attribute_length; - runtime_invisible_annotations = cfs->current(); - assert(runtime_invisible_annotations != nullptr, "null invisible annotations"); - } cfs->skip_u1(attribute_length, CHECK); } else if (attribute_name == vmSymbols::tag_runtime_visible_type_annotations()) { if (runtime_visible_type_annotations != nullptr) { @@ -1339,11 +1330,6 @@ void ClassFileParser::parse_field_attributes(const ClassFileStream* const cfs, } else { runtime_invisible_type_annotations_exists = true; } - if (PreserveAllAnnotations) { - runtime_invisible_type_annotations_length = attribute_length; - runtime_invisible_type_annotations = cfs->current(); - assert(runtime_invisible_type_annotations != nullptr, "null invisible type annotations"); - } cfs->skip_u1(attribute_length, CHECK); } else { cfs->skip_u1(attribute_length, CHECK); // Skip unknown attributes @@ -1356,16 +1342,12 @@ void ClassFileParser::parse_field_attributes(const ClassFileStream* const cfs, *constantvalue_index_addr = constantvalue_index; *is_synthetic_addr = is_synthetic; *generic_signature_index_addr = generic_signature_index; - AnnotationArray* a = assemble_annotations(runtime_visible_annotations, + AnnotationArray* a = allocate_annotations(runtime_visible_annotations, runtime_visible_annotations_length, - runtime_invisible_annotations, - runtime_invisible_annotations_length, CHECK); parsed_annotations->set_field_annotations(a); - a = assemble_annotations(runtime_visible_type_annotations, + a = allocate_annotations(runtime_visible_type_annotations, runtime_visible_type_annotations_length, - runtime_invisible_type_annotations, - runtime_invisible_type_annotations_length, CHECK); parsed_annotations->set_field_type_annotations(a); return; @@ -2164,57 +2146,40 @@ void ClassFileParser::copy_localvariable_table(const ConstMethod* cm, void ClassFileParser::copy_method_annotations(ConstMethod* cm, const u1* runtime_visible_annotations, int runtime_visible_annotations_length, - const u1* runtime_invisible_annotations, - int runtime_invisible_annotations_length, const u1* runtime_visible_parameter_annotations, int runtime_visible_parameter_annotations_length, - const u1* runtime_invisible_parameter_annotations, - int runtime_invisible_parameter_annotations_length, const u1* runtime_visible_type_annotations, int runtime_visible_type_annotations_length, - const u1* runtime_invisible_type_annotations, - int runtime_invisible_type_annotations_length, const u1* annotation_default, int annotation_default_length, TRAPS) { AnnotationArray* a; - if (runtime_visible_annotations_length + - runtime_invisible_annotations_length > 0) { - a = assemble_annotations(runtime_visible_annotations, + if (runtime_visible_annotations_length > 0) { + a = allocate_annotations(runtime_visible_annotations, runtime_visible_annotations_length, - runtime_invisible_annotations, - runtime_invisible_annotations_length, CHECK); cm->set_method_annotations(a); } - if (runtime_visible_parameter_annotations_length + - runtime_invisible_parameter_annotations_length > 0) { - a = assemble_annotations(runtime_visible_parameter_annotations, + if (runtime_visible_parameter_annotations_length > 0) { + a = allocate_annotations(runtime_visible_parameter_annotations, runtime_visible_parameter_annotations_length, - runtime_invisible_parameter_annotations, - runtime_invisible_parameter_annotations_length, CHECK); cm->set_parameter_annotations(a); } if (annotation_default_length > 0) { - a = assemble_annotations(annotation_default, + a = allocate_annotations(annotation_default, annotation_default_length, - nullptr, - 0, CHECK); cm->set_default_annotations(a); } - if (runtime_visible_type_annotations_length + - runtime_invisible_type_annotations_length > 0) { - a = assemble_annotations(runtime_visible_type_annotations, + if (runtime_visible_type_annotations_length > 0) { + a = allocate_annotations(runtime_visible_type_annotations, runtime_visible_type_annotations_length, - runtime_invisible_type_annotations, - runtime_invisible_type_annotations_length, CHECK); cm->set_type_annotations(a); } @@ -2327,16 +2292,10 @@ Method* ClassFileParser::parse_method(const ClassFileStream* const cfs, MethodAnnotationCollector parsed_annotations; const u1* runtime_visible_annotations = nullptr; int runtime_visible_annotations_length = 0; - const u1* runtime_invisible_annotations = nullptr; - int runtime_invisible_annotations_length = 0; const u1* runtime_visible_parameter_annotations = nullptr; int runtime_visible_parameter_annotations_length = 0; - const u1* runtime_invisible_parameter_annotations = nullptr; - int runtime_invisible_parameter_annotations_length = 0; const u1* runtime_visible_type_annotations = nullptr; int runtime_visible_type_annotations_length = 0; - const u1* runtime_invisible_type_annotations = nullptr; - int runtime_invisible_type_annotations_length = 0; bool runtime_invisible_annotations_exists = false; bool runtime_invisible_type_annotations_exists = false; bool runtime_invisible_parameter_annotations_exists = false; @@ -2607,11 +2566,6 @@ Method* ClassFileParser::parse_method(const ClassFileStream* const cfs, return nullptr; } runtime_invisible_annotations_exists = true; - if (PreserveAllAnnotations) { - runtime_invisible_annotations_length = method_attribute_length; - runtime_invisible_annotations = cfs->current(); - assert(runtime_invisible_annotations != nullptr, "null invisible annotations"); - } cfs->skip_u1(method_attribute_length, CHECK_NULL); } else if (method_attribute_name == vmSymbols::tag_runtime_visible_parameter_annotations()) { if (runtime_visible_parameter_annotations != nullptr) { @@ -2632,12 +2586,6 @@ Method* ClassFileParser::parse_method(const ClassFileStream* const cfs, return nullptr; } runtime_invisible_parameter_annotations_exists = true; - if (PreserveAllAnnotations) { - runtime_invisible_parameter_annotations_length = method_attribute_length; - runtime_invisible_parameter_annotations = cfs->current(); - assert(runtime_invisible_parameter_annotations != nullptr, - "null invisible parameter annotations"); - } cfs->skip_u1(method_attribute_length, CHECK_NULL); } else if (method_attribute_name == vmSymbols::tag_annotation_default()) { if (annotation_default != nullptr) { @@ -2668,14 +2616,8 @@ Method* ClassFileParser::parse_method(const ClassFileStream* const cfs, "Multiple RuntimeInvisibleTypeAnnotations attributes for method in class file %s", THREAD); return nullptr; - } else { - runtime_invisible_type_annotations_exists = true; - } - if (PreserveAllAnnotations) { - runtime_invisible_type_annotations_length = method_attribute_length; - runtime_invisible_type_annotations = cfs->current(); - assert(runtime_invisible_type_annotations != nullptr, "null invisible type annotations"); } + runtime_invisible_type_annotations_exists = true; cfs->skip_u1(method_attribute_length, CHECK_NULL); } else { // Skip unknown attributes @@ -2709,12 +2651,9 @@ Method* ClassFileParser::parse_method(const ClassFileStream* const cfs, checked_exceptions_length, method_parameters_length, generic_signature_index, - runtime_visible_annotations_length + - runtime_invisible_annotations_length, - runtime_visible_parameter_annotations_length + - runtime_invisible_parameter_annotations_length, - runtime_visible_type_annotations_length + - runtime_invisible_type_annotations_length, + runtime_visible_annotations_length, + runtime_visible_parameter_annotations_length, + runtime_visible_type_annotations_length, annotation_default_length, 0); @@ -2806,16 +2745,10 @@ Method* ClassFileParser::parse_method(const ClassFileStream* const cfs, copy_method_annotations(m->constMethod(), runtime_visible_annotations, runtime_visible_annotations_length, - runtime_invisible_annotations, - runtime_invisible_annotations_length, runtime_visible_parameter_annotations, runtime_visible_parameter_annotations_length, - runtime_invisible_parameter_annotations, - runtime_invisible_parameter_annotations_length, runtime_visible_type_annotations, runtime_visible_type_annotations_length, - runtime_invisible_type_annotations, - runtime_invisible_type_annotations_length, annotation_default, annotation_default_length, CHECK_NULL); @@ -3295,13 +3228,9 @@ u4 ClassFileParser::parse_classfile_record_attribute(const ClassFileStream* cons u2 generic_sig_index = 0; const u1* runtime_visible_annotations = nullptr; int runtime_visible_annotations_length = 0; - const u1* runtime_invisible_annotations = nullptr; - int runtime_invisible_annotations_length = 0; bool runtime_invisible_annotations_exists = false; const u1* runtime_visible_type_annotations = nullptr; int runtime_visible_type_annotations_length = 0; - const u1* runtime_invisible_type_annotations = nullptr; - int runtime_invisible_type_annotations_length = 0; bool runtime_invisible_type_annotations_exists = false; // Expected attributes for record components are Signature, Runtime(In)VisibleAnnotations, @@ -3352,11 +3281,6 @@ u4 ClassFileParser::parse_classfile_record_attribute(const ClassFileStream* cons return 0; } runtime_invisible_annotations_exists = true; - if (PreserveAllAnnotations) { - runtime_invisible_annotations_length = attribute_length; - runtime_invisible_annotations = cfs->current(); - assert(runtime_invisible_annotations != nullptr, "null record component invisible annotation"); - } cfs->skip_u1(attribute_length, CHECK_0); } else if (attribute_name == vmSymbols::tag_runtime_visible_type_annotations()) { @@ -3379,11 +3303,6 @@ u4 ClassFileParser::parse_classfile_record_attribute(const ClassFileStream* cons return 0; } runtime_invisible_type_annotations_exists = true; - if (PreserveAllAnnotations) { - runtime_invisible_type_annotations_length = attribute_length; - runtime_invisible_type_annotations = cfs->current(); - assert(runtime_invisible_type_annotations != nullptr, "null record component invisible type annotation"); - } cfs->skip_u1(attribute_length, CHECK_0); } else { @@ -3393,15 +3312,11 @@ u4 ClassFileParser::parse_classfile_record_attribute(const ClassFileStream* cons calculate_attr_size += attribute_length; } // End of attributes For loop - AnnotationArray* annotations = assemble_annotations(runtime_visible_annotations, + AnnotationArray* annotations = allocate_annotations(runtime_visible_annotations, runtime_visible_annotations_length, - runtime_invisible_annotations, - runtime_invisible_annotations_length, CHECK_0); - AnnotationArray* type_annotations = assemble_annotations(runtime_visible_type_annotations, + AnnotationArray* type_annotations = allocate_annotations(runtime_visible_type_annotations, runtime_visible_type_annotations_length, - runtime_invisible_type_annotations, - runtime_invisible_type_annotations_length, CHECK_0); RecordComponent* record_component = @@ -3538,12 +3453,8 @@ void ClassFileParser::parse_classfile_attributes(const ClassFileStream* const cf bool parsed_bootstrap_methods_attribute = false; const u1* runtime_visible_annotations = nullptr; int runtime_visible_annotations_length = 0; - const u1* runtime_invisible_annotations = nullptr; - int runtime_invisible_annotations_length = 0; const u1* runtime_visible_type_annotations = nullptr; int runtime_visible_type_annotations_length = 0; - const u1* runtime_invisible_type_annotations = nullptr; - int runtime_invisible_type_annotations_length = 0; bool runtime_invisible_type_annotations_exists = false; bool runtime_invisible_annotations_exists = false; bool parsed_source_debug_ext_annotations_exist = false; @@ -3656,11 +3567,6 @@ void ClassFileParser::parse_classfile_attributes(const ClassFileStream* const cf return; } runtime_invisible_annotations_exists = true; - if (PreserveAllAnnotations) { - runtime_invisible_annotations_length = attribute_length; - runtime_invisible_annotations = cfs->current(); - assert(runtime_invisible_annotations != nullptr, "null invisible annotations"); - } cfs->skip_u1(attribute_length, CHECK); } else if (tag == vmSymbols::tag_enclosing_method()) { if (parsed_enclosingmethod_attribute) { @@ -3712,14 +3618,8 @@ void ClassFileParser::parse_classfile_attributes(const ClassFileStream* const cf classfile_parse_error( "Multiple RuntimeInvisibleTypeAnnotations attributes in class file %s", THREAD); return; - } else { - runtime_invisible_type_annotations_exists = true; - } - if (PreserveAllAnnotations) { - runtime_invisible_type_annotations_length = attribute_length; - runtime_invisible_type_annotations = cfs->current(); - assert(runtime_invisible_type_annotations != nullptr, "null invisible type annotations"); } + runtime_invisible_type_annotations_exists = true; cfs->skip_u1(attribute_length, CHECK); } else if (_major_version >= JAVA_11_VERSION) { if (tag == vmSymbols::tag_nest_members()) { @@ -3799,15 +3699,11 @@ void ClassFileParser::parse_classfile_attributes(const ClassFileStream* const cf cfs->skip_u1(attribute_length, CHECK); } } - _class_annotations = assemble_annotations(runtime_visible_annotations, + _class_annotations = allocate_annotations(runtime_visible_annotations, runtime_visible_annotations_length, - runtime_invisible_annotations, - runtime_invisible_annotations_length, CHECK); - _class_type_annotations = assemble_annotations(runtime_visible_type_annotations, + _class_type_annotations = allocate_annotations(runtime_visible_type_annotations, runtime_visible_type_annotations_length, - runtime_invisible_type_annotations, - runtime_invisible_type_annotations_length, CHECK); if (parsed_innerclasses_attribute || parsed_enclosingmethod_attribute) { @@ -3943,28 +3839,16 @@ void ClassFileParser::apply_parsed_class_metadata( clear_class_metadata(); } -AnnotationArray* ClassFileParser::assemble_annotations(const u1* const runtime_visible_annotations, - int runtime_visible_annotations_length, - const u1* const runtime_invisible_annotations, - int runtime_invisible_annotations_length, +AnnotationArray* ClassFileParser::allocate_annotations(const u1* const anno, + int anno_length, TRAPS) { AnnotationArray* annotations = nullptr; - if (runtime_visible_annotations != nullptr || - runtime_invisible_annotations != nullptr) { + if (anno != nullptr) { annotations = MetadataFactory::new_array(_loader_data, - runtime_visible_annotations_length + - runtime_invisible_annotations_length, - CHECK_(annotations)); - if (runtime_visible_annotations != nullptr) { - for (int i = 0; i < runtime_visible_annotations_length; i++) { - annotations->at_put(i, runtime_visible_annotations[i]); - } - } - if (runtime_invisible_annotations != nullptr) { - for (int i = 0; i < runtime_invisible_annotations_length; i++) { - int append = runtime_visible_annotations_length+i; - annotations->at_put(append, runtime_invisible_annotations[i]); - } + anno_length, + CHECK_(annotations)); + for (int i = 0; i < anno_length; i++) { + annotations->at_put(i, anno[i]); } } return annotations; diff --git a/src/hotspot/share/classfile/classFileParser.hpp b/src/hotspot/share/classfile/classFileParser.hpp index f43303722a8ab..69d1f357ca55d 100644 --- a/src/hotspot/share/classfile/classFileParser.hpp +++ b/src/hotspot/share/classfile/classFileParser.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -347,10 +347,8 @@ class ClassFileParser { TRAPS); // Annotations handling - AnnotationArray* assemble_annotations(const u1* const runtime_visible_annotations, - int runtime_visible_annotations_length, - const u1* const runtime_invisible_annotations, - int runtime_invisible_annotations_length, + AnnotationArray* allocate_annotations(const u1* const anno, + int anno_length, TRAPS); void set_precomputed_flags(InstanceKlass* k); @@ -514,16 +512,10 @@ class ClassFileParser { void copy_method_annotations(ConstMethod* cm, const u1* runtime_visible_annotations, int runtime_visible_annotations_length, - const u1* runtime_invisible_annotations, - int runtime_invisible_annotations_length, const u1* runtime_visible_parameter_annotations, int runtime_visible_parameter_annotations_length, - const u1* runtime_invisible_parameter_annotations, - int runtime_invisible_parameter_annotations_length, const u1* runtime_visible_type_annotations, int runtime_visible_type_annotations_length, - const u1* runtime_invisible_type_annotations, - int runtime_invisible_type_annotations_length, const u1* annotation_default, int annotation_default_length, TRAPS); diff --git a/src/hotspot/share/prims/jvmtiClassFileReconstituter.cpp b/src/hotspot/share/prims/jvmtiClassFileReconstituter.cpp index 8d7ffdf4835ba..ceed1d8ad952a 100644 --- a/src/hotspot/share/prims/jvmtiClassFileReconstituter.cpp +++ b/src/hotspot/share/prims/jvmtiClassFileReconstituter.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -119,10 +119,10 @@ void JvmtiClassFileReconstituter::write_field_infos() { write_signature_attribute(generic_signature_index); } if (anno != nullptr) { - write_annotations_attribute("RuntimeVisibleAnnotations", "RuntimeInvisibleAnnotations", anno); + write_annotations_attribute("RuntimeVisibleAnnotations", anno); } if (type_anno != nullptr) { - write_annotations_attribute("RuntimeVisibleTypeAnnotations", "RuntimeInvisibleTypeAnnotations", type_anno); + write_annotations_attribute("RuntimeVisibleTypeAnnotations", type_anno); } } } @@ -380,20 +380,6 @@ void JvmtiClassFileReconstituter::write_annotations_attribute(const char* attr_n memcpy(writeable_address(length), annos->adr_at(0), length); } -void JvmtiClassFileReconstituter::write_annotations_attribute(const char* attr_name, - const char* fallback_attr_name, - AnnotationArray* annos) { - TempNewSymbol sym = SymbolTable::probe(attr_name, (int)strlen(attr_name)); - if (sym != nullptr) { - if (symbol_to_cpool_index(sym) != 0) { - write_annotations_attribute(attr_name, annos); - return; - } - } - // use fallback name - write_annotations_attribute(fallback_attr_name, annos); -} - // BootstrapMethods_attribute { // u2 attribute_name_index; // u4 attribute_length; @@ -533,10 +519,10 @@ void JvmtiClassFileReconstituter::write_record_attribute() { write_signature_attribute(component->generic_signature_index()); } if (component->annotations() != nullptr) { - write_annotations_attribute("RuntimeVisibleAnnotations", "RuntimeInvisibleAnnotations", component->annotations()); + write_annotations_attribute("RuntimeVisibleAnnotations", component->annotations()); } if (component->type_annotations() != nullptr) { - write_annotations_attribute("RuntimeVisibleTypeAnnotations", "RuntimeInvisibleTypeAnnotations", component->type_annotations()); + write_annotations_attribute("RuntimeVisibleTypeAnnotations", component->type_annotations()); } } } @@ -775,13 +761,13 @@ void JvmtiClassFileReconstituter::write_method_info(const methodHandle& method) write_signature_attribute(generic_signature_index); } if (anno != nullptr) { - write_annotations_attribute("RuntimeVisibleAnnotations", "RuntimeInvisibleAnnotations", anno); + write_annotations_attribute("RuntimeVisibleAnnotations", anno); } if (param_anno != nullptr) { - write_annotations_attribute("RuntimeVisibleParameterAnnotations", "RuntimeInvisibleParameterAnnotations", param_anno); + write_annotations_attribute("RuntimeVisibleParameterAnnotations", param_anno); } if (type_anno != nullptr) { - write_annotations_attribute("RuntimeVisibleTypeAnnotations", "RuntimeInvisibleTypeAnnotations", type_anno); + write_annotations_attribute("RuntimeVisibleTypeAnnotations", type_anno); } } @@ -841,10 +827,10 @@ void JvmtiClassFileReconstituter::write_class_attributes() { write_source_debug_extension_attribute(); } if (anno != nullptr) { - write_annotations_attribute("RuntimeVisibleAnnotations", "RuntimeInvisibleAnnotations", anno); + write_annotations_attribute("RuntimeVisibleAnnotations", anno); } if (type_anno != nullptr) { - write_annotations_attribute("RuntimeVisibleTypeAnnotations", "RuntimeInvisibleTypeAnnotations", type_anno); + write_annotations_attribute("RuntimeVisibleTypeAnnotations", type_anno); } if (ik()->nest_host_index() != 0) { write_nest_host_attribute(); diff --git a/src/hotspot/share/prims/jvmtiClassFileReconstituter.hpp b/src/hotspot/share/prims/jvmtiClassFileReconstituter.hpp index 2f36a2877d262..015042a8543a7 100644 --- a/src/hotspot/share/prims/jvmtiClassFileReconstituter.hpp +++ b/src/hotspot/share/prims/jvmtiClassFileReconstituter.hpp @@ -117,13 +117,6 @@ class JvmtiClassFileReconstituter : public JvmtiConstantPoolReconstituter { void write_signature_attribute(u2 generic_signaure_index); void write_attribute_name_index(const char* name); void write_annotations_attribute(const char* attr_name, AnnotationArray* annos); - // With PreserveAllAnnotations option "runtime invisible" annotations - // (RuntimeInvisibleAnnotations/RuntimeInvisibleTypeAnnotations/RuntimeInvisibleParameterAnnotations) - // are considered "runtime visible" and ClassFileReconstituter writes them as - // RuntimeVisibleAnnotations/RuntimeVisibleTypeAnnotations/RuntimeVisibleParameterAnnotations. - // This helper method is for the corner case when "runtime visible" attribute name is not presents - // in the class constant pool and the annotations are written with fallback "runtime invisible" name. - void write_annotations_attribute(const char* attr_name, const char* fallback_attr_name, AnnotationArray* annos); void write_bootstrapmethod_attribute(); void write_nest_host_attribute(); void write_nest_members_attribute(); diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index d353c5a162ae3..966f4855789e4 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -503,7 +503,6 @@ static SpecialFlag const special_jvm_flags[] = { { "RequireSharedSpaces", JDK_Version::jdk(18), JDK_Version::jdk(19), JDK_Version::undefined() }, { "UseSharedSpaces", JDK_Version::jdk(18), JDK_Version::jdk(19), JDK_Version::undefined() }, { "DontYieldALot", JDK_Version::jdk(23), JDK_Version::jdk(24), JDK_Version::jdk(25) }, - { "PreserveAllAnnotations", JDK_Version::jdk(23), JDK_Version::jdk(24), JDK_Version::jdk(25) }, { "UseNotificationThread", JDK_Version::jdk(23), JDK_Version::jdk(24), JDK_Version::jdk(25) }, { "LockingMode", JDK_Version::jdk(24), JDK_Version::jdk(26), JDK_Version::jdk(27) }, // --- Deprecated alias flags (see also aliased_jvm_flags) - sorted by obsolete_in then expired_in: @@ -513,6 +512,7 @@ static SpecialFlag const special_jvm_flags[] = { { "MetaspaceReclaimPolicy", JDK_Version::undefined(), JDK_Version::jdk(21), JDK_Version::undefined() }, + { "PreserveAllAnnotations", JDK_Version::jdk(23), JDK_Version::jdk(24), JDK_Version::jdk(25) }, { "UseEmptySlotsInSupers", JDK_Version::jdk(23), JDK_Version::jdk(24), JDK_Version::jdk(25) }, { "OldSize", JDK_Version::jdk(23), JDK_Version::jdk(24), JDK_Version::jdk(25) }, #if defined(X86) diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp index 7a7a3769ac90f..562549f247efd 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -795,10 +795,6 @@ const int ObjectAlignmentInBytes = 8; "but not all -Xrun libraries may support the state of the VM " \ "at this time") \ \ - product(bool, PreserveAllAnnotations, false, \ - "(Deprecated) Preserve RuntimeInvisibleAnnotations as well " \ - "as RuntimeVisibleAnnotations") \ - \ develop(uintx, PreallocatedOutOfMemoryErrorCount, 4, \ "Number of OutOfMemoryErrors preallocated with backtrace") \ \ diff --git a/test/jdk/java/lang/instrument/RetransformRecordAnnotation.java b/test/jdk/java/lang/instrument/RetransformRecordAnnotation.java deleted file mode 100644 index 90d76d1f923e7..0000000000000 --- a/test/jdk/java/lang/instrument/RetransformRecordAnnotation.java +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test - * @bug 8315575 8328137 - * @summary test that records with invisible annotation can be retransformed - * - * @library /test/lib - * @run shell MakeJAR.sh retransformAgent - * @run main/othervm -javaagent:retransformAgent.jar -Xlog:redefine+class=trace RetransformRecordAnnotation - * @run main/othervm -javaagent:retransformAgent.jar -XX:+PreserveAllAnnotations -Xlog:redefine+class=trace RetransformRecordAnnotation - */ - -import java.io.File; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; -import java.lang.instrument.ClassFileTransformer; -import java.nio.file.Files; -import java.security.ProtectionDomain; - -public class RetransformRecordAnnotation extends AInstrumentationTestCase { - - @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE}) - @Retention(RetentionPolicy.RUNTIME) - @interface RuntimeTypeAnno {} - - @Retention(RetentionPolicy.RUNTIME) - @interface RuntimeParamAnno { - String s() default "foo"; - } - - @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE}) - @Retention(RetentionPolicy.CLASS) - @interface ClassTypeAnno {} - - @Retention(RetentionPolicy.CLASS) - @interface ClassParamAnno { - String s() default "bar"; - } - - @RuntimeTypeAnno - @RuntimeParamAnno(s = "1") - public record VisibleAnnos(@RuntimeTypeAnno @RuntimeParamAnno(s = "2") Object o, Object other) { - } - - @ClassTypeAnno - @ClassParamAnno(s = "3") - public record InvisibleAnnos(@ClassTypeAnno @ClassParamAnno(s = "4") Object o, Object other) { - } - - @RuntimeTypeAnno - @RuntimeParamAnno(s = "5") - @ClassTypeAnno - @ClassParamAnno(s = "6") - public record MixedAnnos(@RuntimeTypeAnno @RuntimeParamAnno(s = "7") - @ClassTypeAnno @ClassParamAnno(s = "8") Object o, Object other) { - } - - public static void main (String[] args) throws Throwable { - ATestCaseScaffold test = new RetransformRecordAnnotation(); - test.beVerbose(); - test.runTest(); - } - - private Transformer transformer; - - public RetransformRecordAnnotation() throws Throwable { - super("RetransformRecordAnnotation"); - } - - private void log(Object o) { - System.out.println(String.valueOf(o)); - } - - // Retransforms target class using provided class bytes; - private void retransform(Class targetClass, byte[] classBytes) throws Throwable { - transformer.prepare(targetClass, classBytes); - fInst.retransformClasses(targetClass); - assertTrue(targetClass.getName() + " was not seen by transform()", - transformer.getSeenClassBytes() != null); - } - - protected final void doRunTest() throws Throwable { - transformer = new Transformer(); - fInst.addTransformer(transformer, true); - - { - log("Sanity: retransform to original class bytes"); - retransform(InvisibleAnnos.class, loadClassBytes(InvisibleAnnos.class)); - log(""); - } - - // The following testcases use null as new class bytes (i.e. no transform is performed). - // However, it is enough for testing purposes as the JvmtiClassFileReconstituter is still involved - // in preparation of the initial class bytes. - { - log("Test: retransform VisibleAnnos to null"); - retransform(VisibleAnnos.class, null); - log(""); - } - - { - log("Test: retransform InvisibleAnnos to null"); - retransform(InvisibleAnnos.class, null); - log(""); - } - - { - log("Test: retransform MixedAnnos to null"); - retransform(MixedAnnos.class, null); - log(""); - } - } - - private byte[] loadClassBytes(Class cls) throws Exception { - String classFileName = cls.getName() + ".class"; - File classFile = new File(System.getProperty("test.classes", "."), classFileName); - log("Reading test class from " + classFile); - byte[] classBytes = Files.readAllBytes(classFile.toPath()); - log("Read " + classBytes.length + " bytes."); - return classBytes; - } - - public class Transformer implements ClassFileTransformer { - private String targetClassName; - private byte[] seenClassBytes; - private byte[] newClassBytes; - - public Transformer() { - } - - // Prepares transformer for Instrumentation.retransformClasses. - public void prepare(Class targetClass, byte[] classBytes) { - targetClassName = targetClass.getName(); - newClassBytes = classBytes; - seenClassBytes = null; - } - - byte[] getSeenClassBytes() { - return seenClassBytes; - } - - public String toString() { - return Transformer.this.getClass().getName(); - } - - public byte[] transform(ClassLoader loader, String className, - Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) { - - if (className.equals(targetClassName)) { - log(this + ".transform() sees '" + className - + "' of " + classfileBuffer.length + " bytes."); - seenClassBytes = classfileBuffer; - if (newClassBytes != null) { - log(this + ".transform() sets new classbytes for '" + className - + "' of " + newClassBytes.length + " bytes."); - } - return newClassBytes; - } - - return null; - } - } -} From 034297a6bd9bfcea7fa48792f54c84a6e976b319 Mon Sep 17 00:00:00 2001 From: Fernando Guallini Date: Fri, 26 Jul 2024 18:51:12 +0000 Subject: [PATCH 116/353] 8336240: Test com/sun/crypto/provider/Cipher/DES/PerformanceTest.java fails with java.lang.ArithmeticException Reviewed-by: wetmore --- test/jdk/ProblemList.txt | 1 - test/jdk/TEST.groups | 1 - .../provider/Cipher/DES/PerformanceTest.java | 19 +++++++++++-------- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 05e42b4933046..8e627e27d7a8e 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -606,7 +606,6 @@ sun/security/smartcardio/TestExclusive.java 8039280 generic- sun/security/smartcardio/TestMultiplePresent.java 8039280 generic-all sun/security/smartcardio/TestPresent.java 8039280 generic-all sun/security/smartcardio/TestTransmit.java 8039280 generic-all -com/sun/crypto/provider/Cipher/DES/PerformanceTest.java 8039280 generic-all com/sun/security/auth/callback/TextCallbackHandler/Password.java 8039280 generic-all com/sun/security/sasl/gsskerb/AuthOnly.java 8039280 generic-all com/sun/security/sasl/gsskerb/ConfSecurityLayer.java 8039280 generic-all diff --git a/test/jdk/TEST.groups b/test/jdk/TEST.groups index 6a5be3736e859..55ae0e9c67b14 100644 --- a/test/jdk/TEST.groups +++ b/test/jdk/TEST.groups @@ -621,7 +621,6 @@ jdk_core_manual_no_input = \ jdk_security_manual_no_input = \ :jdk_security_infra \ - com/sun/crypto/provider/Cipher/DES/PerformanceTest.java \ com/sun/crypto/provider/Cipher/AEAD/GCMIncrementByte4.java \ com/sun/crypto/provider/Cipher/AEAD/GCMIncrementDirect4.java \ com/sun/security/auth/callback/TextCallbackHandler/Password.java \ diff --git a/test/jdk/com/sun/crypto/provider/Cipher/DES/PerformanceTest.java b/test/jdk/com/sun/crypto/provider/Cipher/DES/PerformanceTest.java index 698acd083b4c9..33167cafbd90f 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/DES/PerformanceTest.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/DES/PerformanceTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,11 +26,8 @@ * @bug 0000000 * @summary This test checks performance of various ciphers. * @author Jan Luehe - * @run main/manual PerformanceTest */ -import java.security.*; import java.security.spec.*; -import java.io.*; import javax.crypto.*; import javax.crypto.spec.*; @@ -178,14 +175,16 @@ public void runTest(byte[] data, int count) throws Exception { long start, end; cipher.init(Cipher.ENCRYPT_MODE, cipherKey, params); - start = System.currentTimeMillis(); + start = getTimeInMicroseconds(); for (int i=0; i Date: Sat, 27 Jul 2024 22:54:47 +0000 Subject: [PATCH 117/353] 8337245: Fix wrong comment of StringConcatHelper Reviewed-by: phh, redestad --- .../share/classes/java/lang/StringConcatHelper.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/java.base/share/classes/java/lang/StringConcatHelper.java b/src/java.base/share/classes/java/lang/StringConcatHelper.java index 0b4a8992d6c83..486e115369ea6 100644 --- a/src/java.base/share/classes/java/lang/StringConcatHelper.java +++ b/src/java.base/share/classes/java/lang/StringConcatHelper.java @@ -185,7 +185,7 @@ static long prepend(long indexCoder, byte[] buf, boolean value, String prefix) { * @param indexCoder final char index in the buffer, along with coder packed * into higher bits. * @param buf buffer to append to - * @param value boolean value to encode + * @param value char value to encode * @param prefix a constant to prepend before value * @return updated index (coder value retained) */ @@ -211,7 +211,7 @@ static long prepend(long indexCoder, byte[] buf, char value, String prefix) { * @param indexCoder final char index in the buffer, along with coder packed * into higher bits. * @param buf buffer to append to - * @param value boolean value to encode + * @param value int value to encode * @param prefix a constant to prepend before value * @return updated index (coder value retained) */ @@ -237,7 +237,7 @@ static long prepend(long indexCoder, byte[] buf, int value, String prefix) { * @param indexCoder final char index in the buffer, along with coder packed * into higher bits. * @param buf buffer to append to - * @param value boolean value to encode + * @param value long value to encode * @param prefix a constant to prepend before value * @return updated index (coder value retained) */ From 90641a601c9385b5e76e1abc5362ace3ab1fff3d Mon Sep 17 00:00:00 2001 From: Tobias Hartmann Date: Mon, 29 Jul 2024 05:05:32 +0000 Subject: [PATCH 118/353] 8336095: Use-after-free in Superword leads to memory corruption Reviewed-by: epeter, kvn, rrich --- src/hotspot/share/opto/loopnode.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hotspot/share/opto/loopnode.hpp b/src/hotspot/share/opto/loopnode.hpp index 7d78bf5021c22..6070acc4624b0 100644 --- a/src/hotspot/share/opto/loopnode.hpp +++ b/src/hotspot/share/opto/loopnode.hpp @@ -611,6 +611,7 @@ class IdealLoopTree : public ResourceObj { _head(head), _tail(tail), _phase(phase), _local_loop_unroll_limit(0), _local_loop_unroll_factor(0), + _body(Compile::current()->comp_arena()), _nest(0), _irreducible(0), _has_call(0), _has_sfpt(0), _rce_candidate(0), _has_range_checks(0), _has_range_checks_computed(0), _safepts(nullptr), From 657c0bddf90b537ac653817571532705a6e3643a Mon Sep 17 00:00:00 2001 From: Tobias Hartmann Date: Mon, 29 Jul 2024 05:31:10 +0000 Subject: [PATCH 119/353] 8336999: Verification for resource area allocated data structures in C2 Reviewed-by: chagedorn, kvn --- src/hotspot/share/ci/ciReplay.cpp | 2 ++ src/hotspot/share/libadt/vectset.cpp | 4 ++++ src/hotspot/share/libadt/vectset.hpp | 10 +++------- src/hotspot/share/memory/allocation.cpp | 5 +++-- src/hotspot/share/memory/allocation.hpp | 4 ++-- src/hotspot/share/opto/block.cpp | 8 ++++++-- src/hotspot/share/opto/block.hpp | 9 ++++++--- src/hotspot/share/opto/domgraph.cpp | 3 --- src/hotspot/share/opto/loopnode.cpp | 1 + src/hotspot/share/opto/loopnode.hpp | 4 ++++ src/hotspot/share/opto/node.cpp | 8 ++++++++ src/hotspot/share/opto/node.hpp | 7 +++++-- src/hotspot/share/opto/phaseX.cpp | 1 + src/hotspot/share/opto/vector.cpp | 6 +++--- 14 files changed, 48 insertions(+), 24 deletions(-) diff --git a/src/hotspot/share/ci/ciReplay.cpp b/src/hotspot/share/ci/ciReplay.cpp index 3ed71806b078b..fd29e0cf85741 100644 --- a/src/hotspot/share/ci/ciReplay.cpp +++ b/src/hotspot/share/ci/ciReplay.cpp @@ -132,6 +132,7 @@ class CompileReplay : public StackObj { char* _bufptr; char* _buffer; int _buffer_length; + ReallocMark _nesting; // Safety checks for arena reallocation // "compile" data ciKlass* _iklass; @@ -601,6 +602,7 @@ class CompileReplay : public StackObj { int buffer_pos = 0; while(c != EOF) { if (buffer_pos + 1 >= _buffer_length) { + _nesting.check(); // Check if a reallocation in the resource arena is safe int new_length = _buffer_length * 2; // Next call will throw error in case of OOM. _buffer = REALLOC_RESOURCE_ARRAY(char, _buffer, _buffer_length, new_length); diff --git a/src/hotspot/share/libadt/vectset.cpp b/src/hotspot/share/libadt/vectset.cpp index 9c711a7021b5a..b0d5d100400e7 100644 --- a/src/hotspot/share/libadt/vectset.cpp +++ b/src/hotspot/share/libadt/vectset.cpp @@ -48,6 +48,10 @@ void VectorSet::init(Arena* arena) { // Expand the existing set to a bigger size void VectorSet::grow(uint new_word_capacity) { + _nesting.check(_set_arena); // Check if a potential reallocation in the arena is safe + if (new_word_capacity < _size) { + return; // No need to grow + } assert(new_word_capacity < (1U << 30), ""); uint x = next_power_of_2(new_word_capacity); if (x > _data_size) { diff --git a/src/hotspot/share/libadt/vectset.hpp b/src/hotspot/share/libadt/vectset.hpp index d55837c3b2b88..c6ea4490cbf43 100644 --- a/src/hotspot/share/libadt/vectset.hpp +++ b/src/hotspot/share/libadt/vectset.hpp @@ -46,6 +46,7 @@ class VectorSet : public AnyObj { // Allocated words uint _data_size; Arena* _set_arena; + ReallocMark _nesting; // Safety checks for arena reallocation void init(Arena* arena); // Grow vector to required word capacity @@ -77,10 +78,7 @@ class VectorSet : public AnyObj { // bool test_set(uint elem) { uint32_t word = elem >> word_bits; - if (word >= _size) { - // Then grow - grow(word); - } + grow(word); uint32_t mask = 1U << (elem & bit_mask); uint32_t data = _data[word]; _data[word] = data | mask; @@ -109,9 +107,7 @@ class VectorSet : public AnyObj { // Fast inlined set void set(uint elem) { uint32_t word = elem >> word_bits; - if (word >= _size) { - grow(word); - } + grow(word); uint32_t mask = 1U << (elem & bit_mask); _data[word] |= mask; } diff --git a/src/hotspot/share/memory/allocation.cpp b/src/hotspot/share/memory/allocation.cpp index 0f05bdda461f4..0f2ff7840b8d2 100644 --- a/src/hotspot/share/memory/allocation.cpp +++ b/src/hotspot/share/memory/allocation.cpp @@ -237,9 +237,10 @@ ReallocMark::ReallocMark() { #endif } -void ReallocMark::check() { +void ReallocMark::check(Arena* arena) { #ifdef ASSERT - if (_nesting != Thread::current()->resource_area()->nesting()) { + if ((arena == nullptr || arena == Thread::current()->resource_area()) && + _nesting != Thread::current()->resource_area()->nesting()) { fatal("allocation bug: array could grow within nested ResourceMark"); } #endif diff --git a/src/hotspot/share/memory/allocation.hpp b/src/hotspot/share/memory/allocation.hpp index 495ca66d86785..da5f7b1983002 100644 --- a/src/hotspot/share/memory/allocation.hpp +++ b/src/hotspot/share/memory/allocation.hpp @@ -556,8 +556,8 @@ class ReallocMark: public StackObj { NOT_PRODUCT(int _nesting;) public: - ReallocMark() PRODUCT_RETURN; - void check() PRODUCT_RETURN; + ReallocMark() PRODUCT_RETURN; + void check(Arena* arena = nullptr) PRODUCT_RETURN; }; // Uses mmapped memory for all allocations. All allocations are initially diff --git a/src/hotspot/share/opto/block.cpp b/src/hotspot/share/opto/block.cpp index 78774ff2fd1c3..1af085cd1282d 100644 --- a/src/hotspot/share/opto/block.cpp +++ b/src/hotspot/share/opto/block.cpp @@ -39,7 +39,10 @@ #include "utilities/powerOfTwo.hpp" void Block_Array::grow( uint i ) { - assert(i >= Max(), "must be an overflow"); + _nesting.check(_arena); // Check if a potential reallocation in the arena is safe + if (i < Max()) { + return; // No need to grow + } debug_only(_limit = i+1); if( i < _size ) return; if( !_size ) { @@ -374,6 +377,7 @@ void Block::dump(const PhaseCFG* cfg) const { PhaseCFG::PhaseCFG(Arena* arena, RootNode* root, Matcher& matcher) : Phase(CFG) , _root(root) +, _blocks(arena) , _block_arena(arena) , _regalloc(nullptr) , _scheduling_for_pressure(false) @@ -1417,7 +1421,7 @@ UnionFind::UnionFind( uint max ) : _cnt(max), _max(max), _indices(NEW_RESOURCE_A } void UnionFind::extend( uint from_idx, uint to_idx ) { - _nesting.check(); + _nesting.check(); // Check if a potential reallocation in the resource arena is safe if( from_idx >= _max ) { uint size = 16; while( size <= from_idx ) size <<=1; diff --git a/src/hotspot/share/opto/block.hpp b/src/hotspot/share/opto/block.hpp index e48b50b06ae8a..231c09949037d 100644 --- a/src/hotspot/share/opto/block.hpp +++ b/src/hotspot/share/opto/block.hpp @@ -51,6 +51,7 @@ class Block_Array : public ArenaObj { uint _size; // allocated size, as opposed to formal limit debug_only(uint _limit;) // limit to formal domain Arena *_arena; // Arena to allocate in + ReallocMark _nesting; // Safety checks for arena reallocation protected: Block **_blocks; void grow( uint i ); // Grow array node to fit @@ -68,7 +69,7 @@ class Block_Array : public ArenaObj { Block *operator[] ( uint i ) const // Lookup, or assert for not mapped { assert( i < Max(), "oob" ); return _blocks[i]; } // Extend the mapping: index i maps to Block *n. - void map( uint i, Block *n ) { if( i>=Max() ) grow(i); _blocks[i] = n; } + void map( uint i, Block *n ) { grow(i); _blocks[i] = n; } uint Max() const { debug_only(return _limit); return _size; } }; @@ -77,7 +78,9 @@ class Block_List : public Block_Array { friend class VMStructs; public: uint _cnt; - Block_List() : Block_Array(Thread::current()->resource_area()), _cnt(0) {} + Block_List() : Block_List(Thread::current()->resource_area()) { } + Block_List(Arena* a) : Block_Array(a), _cnt(0) { } + void push( Block *b ) { map(_cnt++,b); } Block *pop() { return _blocks[--_cnt]; } Block *rpop() { Block *b = _blocks[0]; _blocks[0]=_blocks[--_cnt]; return b;} @@ -655,7 +658,7 @@ class PhaseCFG : public Phase { class UnionFind : public ResourceObj { uint _cnt, _max; uint* _indices; - ReallocMark _nesting; // assertion check for reallocations + ReallocMark _nesting; // Safety checks for arena reallocation public: UnionFind( uint max ); void reset( uint max ); // Reset to identity map for [0..max] diff --git a/src/hotspot/share/opto/domgraph.cpp b/src/hotspot/share/opto/domgraph.cpp index 46cf3316af51e..363005d1181c2 100644 --- a/src/hotspot/share/opto/domgraph.cpp +++ b/src/hotspot/share/opto/domgraph.cpp @@ -61,9 +61,6 @@ struct Tarjan { // Compute the dominator tree of the CFG. The CFG must already have been // constructed. This is the Lengauer & Tarjan O(E-alpha(E,V)) algorithm. void PhaseCFG::build_dominator_tree() { - // Pre-grow the blocks array, prior to the ResourceMark kicking in - _blocks.map(number_of_blocks(), nullptr); - ResourceMark rm; // Setup mappings from my Graph to Tarjan's stuff and back // Note: Tarjan uses 1-based arrays diff --git a/src/hotspot/share/opto/loopnode.cpp b/src/hotspot/share/opto/loopnode.cpp index 85e6f03d4280d..45e59f4e21680 100644 --- a/src/hotspot/share/opto/loopnode.cpp +++ b/src/hotspot/share/opto/loopnode.cpp @@ -5248,6 +5248,7 @@ bool IdealLoopTree::verify_tree(IdealLoopTree* loop_verify) const { //------------------------------set_idom--------------------------------------- void PhaseIdealLoop::set_idom(Node* d, Node* n, uint dom_depth) { + _nesting.check(); // Check if a potential reallocation in the resource arena is safe uint idx = d->_idx; if (idx >= _idom_size) { uint newsize = next_power_of_2(idx); diff --git a/src/hotspot/share/opto/loopnode.hpp b/src/hotspot/share/opto/loopnode.hpp index 6070acc4624b0..24101ea07a002 100644 --- a/src/hotspot/share/opto/loopnode.hpp +++ b/src/hotspot/share/opto/loopnode.hpp @@ -841,6 +841,8 @@ class PhaseIdealLoop : public PhaseTransform { uint *_preorders; uint _max_preorder; + ReallocMark _nesting; // Safety checks for arena reallocation + const PhaseIdealLoop* _verify_me; bool _verify_only; @@ -853,6 +855,7 @@ class PhaseIdealLoop : public PhaseTransform { // Allocate _preorders[] array void reallocate_preorders() { + _nesting.check(); // Check if a potential re-allocation in the resource arena is safe if ( _max_preorder < C->unique() ) { _preorders = REALLOC_RESOURCE_ARRAY(uint, _preorders, _max_preorder, C->unique()); _max_preorder = C->unique(); @@ -863,6 +866,7 @@ class PhaseIdealLoop : public PhaseTransform { // Check to grow _preorders[] array for the case when build_loop_tree_impl() // adds new nodes. void check_grow_preorders( ) { + _nesting.check(); // Check if a potential re-allocation in the resource arena is safe if ( _max_preorder < C->unique() ) { uint newsize = _max_preorder<<1; // double size of array _preorders = REALLOC_RESOURCE_ARRAY(uint, _preorders, _max_preorder, newsize); diff --git a/src/hotspot/share/opto/node.cpp b/src/hotspot/share/opto/node.cpp index 6cf6ff2094e83..f36770e67ea6c 100644 --- a/src/hotspot/share/opto/node.cpp +++ b/src/hotspot/share/opto/node.cpp @@ -2766,6 +2766,10 @@ const RegMask &Node::in_RegMask(uint) const { } void Node_Array::grow(uint i) { + _nesting.check(_a); // Check if a potential reallocation in the arena is safe + if (i < _max) { + return; // No need to grow + } assert(_max > 0, "invariant"); uint old = _max; _max = next_power_of_2(i); @@ -2973,6 +2977,10 @@ void Unique_Node_List::remove_useless_nodes(VectorSet &useful) { //============================================================================= void Node_Stack::grow() { + _nesting.check(_a); // Check if a potential reallocation in the arena is safe + if (_inode_top < _inode_max) { + return; // No need to grow + } size_t old_top = pointer_delta(_inode_top,_inodes,sizeof(INode)); // save _top size_t old_max = pointer_delta(_inode_max,_inodes,sizeof(INode)); size_t max = old_max << 1; // max * 2 diff --git a/src/hotspot/share/opto/node.hpp b/src/hotspot/share/opto/node.hpp index ae379c4833a56..10e1e7b100696 100644 --- a/src/hotspot/share/opto/node.hpp +++ b/src/hotspot/share/opto/node.hpp @@ -1596,6 +1596,8 @@ class Node_Array : public AnyObj { Arena* _a; // Arena to allocate in uint _max; Node** _nodes; + ReallocMark _nesting; // Safety checks for arena reallocation + void grow( uint i ); // Grow array node to fit public: Node_Array(Arena* a, uint max = OptoNodeListSize) : _a(a), _max(max) { @@ -1614,7 +1616,7 @@ class Node_Array : public AnyObj { Node* at(uint i) const { assert(i<_max,"oob"); return _nodes[i]; } Node** adr() { return _nodes; } // Extend the mapping: index i maps to Node *n. - void map( uint i, Node *n ) { if( i>=_max ) grow(i); _nodes[i] = n; } + void map( uint i, Node *n ) { grow(i); _nodes[i] = n; } void insert( uint i, Node *n ); void remove( uint i ); // Remove, preserving order // Clear all entries in _nodes to null but keep storage @@ -1844,6 +1846,7 @@ class Node_Stack { INode *_inode_max; // End of _inodes == _inodes + _max INode *_inodes; // Array storage for the stack Arena *_a; // Arena to allocate in + ReallocMark _nesting; // Safety checks for arena reallocation void grow(); public: Node_Stack(int size) { @@ -1867,7 +1870,7 @@ class Node_Stack { } void push(Node *n, uint i) { ++_inode_top; - if (_inode_top >= _inode_max) grow(); + grow(); INode *top = _inode_top; // optimization top->node = n; top->indx = i; diff --git a/src/hotspot/share/opto/phaseX.cpp b/src/hotspot/share/opto/phaseX.cpp index 96e9f10880841..dae4a5c68a36f 100644 --- a/src/hotspot/share/opto/phaseX.cpp +++ b/src/hotspot/share/opto/phaseX.cpp @@ -2351,6 +2351,7 @@ void Node::replace_by(Node *new_node) { //============================================================================= //----------------------------------------------------------------------------- void Type_Array::grow( uint i ) { + assert(_a == Compile::current()->comp_arena(), "Should be allocated in comp_arena"); if( !_max ) { _max = 1; _types = (const Type**)_a->Amalloc( _max * sizeof(Type*) ); diff --git a/src/hotspot/share/opto/vector.cpp b/src/hotspot/share/opto/vector.cpp index 1b4d64e20b174..9ab62c282d124 100644 --- a/src/hotspot/share/opto/vector.cpp +++ b/src/hotspot/share/opto/vector.cpp @@ -184,7 +184,7 @@ void PhaseVector::scalarize_vbox_node(VectorBoxNode* vec_box) { // Process merged VBAs if (EnableVectorAggressiveReboxing) { - Unique_Node_List calls(C->comp_arena()); + Unique_Node_List calls; for (DUIterator_Fast imax, i = vec_box->fast_outs(imax); i < imax; i++) { Node* use = vec_box->fast_out(i); if (use->is_CallJava()) { @@ -238,9 +238,9 @@ void PhaseVector::scalarize_vbox_node(VectorBoxNode* vec_box) { } // Process debug uses at safepoints - Unique_Node_List safepoints(C->comp_arena()); + Unique_Node_List safepoints; - Unique_Node_List worklist(C->comp_arena()); + Unique_Node_List worklist; worklist.push(vec_box); while (worklist.size() > 0) { Node* n = worklist.pop(); From dab2a0b5978cdd3fad693e4c120a84bb64a3ccde Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Mon, 29 Jul 2024 09:10:25 +0000 Subject: [PATCH 120/353] 8337222: gc/TestDisableExplicitGC.java fails due to unexpected CodeCache GC Reviewed-by: iwalulya, shade --- test/hotspot/jtreg/gc/TestDisableExplicitGC.java | 1 + 1 file changed, 1 insertion(+) diff --git a/test/hotspot/jtreg/gc/TestDisableExplicitGC.java b/test/hotspot/jtreg/gc/TestDisableExplicitGC.java index 9a0b61900dde7..08fda78baaa1b 100644 --- a/test/hotspot/jtreg/gc/TestDisableExplicitGC.java +++ b/test/hotspot/jtreg/gc/TestDisableExplicitGC.java @@ -26,6 +26,7 @@ /* * @test TestDisableExplicitGC * @requires vm.opt.DisableExplicitGC == null + * @requires vm.compMode != "Xcomp" * @summary Verify GC behavior with DisableExplicitGC flag. * @library /test/lib * @modules java.base/jdk.internal.misc From db168d9e10c4a302b743ee208e24ba7303fec582 Mon Sep 17 00:00:00 2001 From: Jan Kratochvil Date: Mon, 29 Jul 2024 09:18:56 +0000 Subject: [PATCH 121/353] 8336966: Alpine Linux x86_64 compilation error: sendfile64 Reviewed-by: bpb --- src/java.base/linux/native/libnio/ch/FileDispatcherImpl.c | 2 +- src/java.base/linux/native/libnio/fs/LinuxNativeDispatcher.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/java.base/linux/native/libnio/ch/FileDispatcherImpl.c b/src/java.base/linux/native/libnio/ch/FileDispatcherImpl.c index 02d3c57f1f34b..efbd0ca568478 100644 --- a/src/java.base/linux/native/libnio/ch/FileDispatcherImpl.c +++ b/src/java.base/linux/native/libnio/ch/FileDispatcherImpl.c @@ -114,7 +114,7 @@ Java_sun_nio_ch_FileDispatcherImpl_transferTo0(JNIEnv *env, jobject this, return n; } - n = sendfile64(dstFD, srcFD, &offset, (size_t)count); + n = sendfile(dstFD, srcFD, &offset, (size_t)count); if (n < 0) { if (errno == EAGAIN) return IOS_UNAVAILABLE; diff --git a/src/java.base/linux/native/libnio/fs/LinuxNativeDispatcher.c b/src/java.base/linux/native/libnio/fs/LinuxNativeDispatcher.c index 95f78ffa135b1..c90e99dda07b3 100644 --- a/src/java.base/linux/native/libnio/fs/LinuxNativeDispatcher.c +++ b/src/java.base/linux/native/libnio/fs/LinuxNativeDispatcher.c @@ -211,7 +211,7 @@ Java_sun_nio_fs_LinuxNativeDispatcher_directCopy0 } do { - RESTARTABLE(sendfile64(dst, src, NULL, count), bytes_sent); + RESTARTABLE(sendfile(dst, src, NULL, count), bytes_sent); if (bytes_sent < 0) { if (errno == EAGAIN) return IOS_UNAVAILABLE; From 9124a94e383f5bc6a3376eecc97ee8bd22f9e420 Mon Sep 17 00:00:00 2001 From: Erik Gahlin Date: Mon, 29 Jul 2024 09:52:38 +0000 Subject: [PATCH 122/353] 8337165: Test jdk/jfr/event/gc/stacktrace/TestG1YoungAllocationPendingStackTrace.java failed: IndexOutOfBoundsException: Index 64 out of bounds for length 64 Reviewed-by: phh --- .../gc/stacktrace/TestDefNewAllocationPendingStackTrace.java | 4 +++- .../TestG1HumongousAllocationPendingStackTrace.java | 4 +++- .../gc/stacktrace/TestG1OldAllocationPendingStackTrace.java | 4 +++- .../stacktrace/TestG1YoungAllocationPendingStackTrace.java | 4 +++- .../TestMarkSweepCompactAllocationPendingStackTrace.java | 4 +++- .../TestMetaspaceG1GCAllocationPendingStackTrace.java | 5 +++-- .../TestMetaspaceParallelGCAllocationPendingStackTrace.java | 4 +++- .../TestMetaspaceSerialGCAllocationPendingStackTrace.java | 4 +++- .../TestParallelMarkSweepAllocationPendingStackTrace.java | 4 +++- .../TestParallelScavengeAllocationPendingStackTrace.java | 4 +++- 10 files changed, 30 insertions(+), 11 deletions(-) diff --git a/test/jdk/jdk/jfr/event/gc/stacktrace/TestDefNewAllocationPendingStackTrace.java b/test/jdk/jdk/jfr/event/gc/stacktrace/TestDefNewAllocationPendingStackTrace.java index 2f290a748c20d..fa91d77e2fbee 100644 --- a/test/jdk/jdk/jfr/event/gc/stacktrace/TestDefNewAllocationPendingStackTrace.java +++ b/test/jdk/jdk/jfr/event/gc/stacktrace/TestDefNewAllocationPendingStackTrace.java @@ -29,7 +29,9 @@ * * @requires vm.gc == "null" | vm.gc == "Serial" * @library /test/lib /test/jdk - * @run main/othervm -XX:+UseSerialGC -Xlog:gc* jdk.jfr.event.gc.stacktrace.TestDefNewAllocationPendingStackTrace + * @run main/othervm -XX:+UseSerialGC -Xlog:gc* + * -XX:FlightRecorderOptions:stackdepth=256 + * jdk.jfr.event.gc.stacktrace.TestDefNewAllocationPendingStackTrace */ public class TestDefNewAllocationPendingStackTrace { diff --git a/test/jdk/jdk/jfr/event/gc/stacktrace/TestG1HumongousAllocationPendingStackTrace.java b/test/jdk/jdk/jfr/event/gc/stacktrace/TestG1HumongousAllocationPendingStackTrace.java index 2df5d95f5240e..ad633ea26de25 100644 --- a/test/jdk/jdk/jfr/event/gc/stacktrace/TestG1HumongousAllocationPendingStackTrace.java +++ b/test/jdk/jdk/jfr/event/gc/stacktrace/TestG1HumongousAllocationPendingStackTrace.java @@ -29,7 +29,9 @@ * * @requires vm.gc == "null" | vm.gc == "G1" * @library /test/lib /test/jdk - * @run main/othervm -XX:+UseG1GC -Xlog:gc* -Xmx64M -XX:InitiatingHeapOccupancyPercent=100 jdk.jfr.event.gc.stacktrace.TestG1HumongousAllocationPendingStackTrace + * @run main/othervm -XX:+UseG1GC -Xlog:gc* -Xmx64M -XX:InitiatingHeapOccupancyPercent=100 + * -XX:FlightRecorderOptions:stackdepth=256 + * jdk.jfr.event.gc.stacktrace.TestG1HumongousAllocationPendingStackTrace */ public class TestG1HumongousAllocationPendingStackTrace { diff --git a/test/jdk/jdk/jfr/event/gc/stacktrace/TestG1OldAllocationPendingStackTrace.java b/test/jdk/jdk/jfr/event/gc/stacktrace/TestG1OldAllocationPendingStackTrace.java index 3541f117e1e07..1cf75ff8fac1c 100644 --- a/test/jdk/jdk/jfr/event/gc/stacktrace/TestG1OldAllocationPendingStackTrace.java +++ b/test/jdk/jdk/jfr/event/gc/stacktrace/TestG1OldAllocationPendingStackTrace.java @@ -29,7 +29,9 @@ * * @requires vm.gc == "null" | vm.gc == "G1" * @library /test/lib /test/jdk - * @run main/othervm -XX:MaxNewSize=10M -Xmx128M -XX:+UseG1GC -Xlog:gc* jdk.jfr.event.gc.stacktrace.TestG1OldAllocationPendingStackTrace + * @run main/othervm -XX:MaxNewSize=10M -Xmx128M -XX:+UseG1GC -Xlog:gc* + * -XX:FlightRecorderOptions:stackdepth=256 + * jdk.jfr.event.gc.stacktrace.TestG1OldAllocationPendingStackTrace */ public class TestG1OldAllocationPendingStackTrace { diff --git a/test/jdk/jdk/jfr/event/gc/stacktrace/TestG1YoungAllocationPendingStackTrace.java b/test/jdk/jdk/jfr/event/gc/stacktrace/TestG1YoungAllocationPendingStackTrace.java index e5b7f849173b3..7259ff5f4457a 100644 --- a/test/jdk/jdk/jfr/event/gc/stacktrace/TestG1YoungAllocationPendingStackTrace.java +++ b/test/jdk/jdk/jfr/event/gc/stacktrace/TestG1YoungAllocationPendingStackTrace.java @@ -29,7 +29,9 @@ * * @requires vm.gc == "null" | vm.gc == "G1" * @library /test/lib /test/jdk - * @run main/othervm -XX:+UseG1GC -Xlog:gc* jdk.jfr.event.gc.stacktrace.TestG1YoungAllocationPendingStackTrace + * @run main/othervm -XX:+UseG1GC -Xlog:gc* + * -XX:FlightRecorderOptions:stackdepth=256 + * jdk.jfr.event.gc.stacktrace.TestG1YoungAllocationPendingStackTrace */ public class TestG1YoungAllocationPendingStackTrace { diff --git a/test/jdk/jdk/jfr/event/gc/stacktrace/TestMarkSweepCompactAllocationPendingStackTrace.java b/test/jdk/jdk/jfr/event/gc/stacktrace/TestMarkSweepCompactAllocationPendingStackTrace.java index e7f5e709d15b7..c06862ad2e6f9 100644 --- a/test/jdk/jdk/jfr/event/gc/stacktrace/TestMarkSweepCompactAllocationPendingStackTrace.java +++ b/test/jdk/jdk/jfr/event/gc/stacktrace/TestMarkSweepCompactAllocationPendingStackTrace.java @@ -29,7 +29,9 @@ * * @requires vm.gc == "null" | vm.gc == "Serial" * @library /test/lib /test/jdk - * @run main/othervm -XX:MaxNewSize=10M -Xmx64M -XX:+UseSerialGC -Xlog:gc* jdk.jfr.event.gc.stacktrace.TestMarkSweepCompactAllocationPendingStackTrace + * @run main/othervm -XX:MaxNewSize=10M -Xmx64M -XX:+UseSerialGC -Xlog:gc* + * -XX:FlightRecorderOptions:stackdepth=256 + * jdk.jfr.event.gc.stacktrace.TestMarkSweepCompactAllocationPendingStackTrace */ public class TestMarkSweepCompactAllocationPendingStackTrace { diff --git a/test/jdk/jdk/jfr/event/gc/stacktrace/TestMetaspaceG1GCAllocationPendingStackTrace.java b/test/jdk/jdk/jfr/event/gc/stacktrace/TestMetaspaceG1GCAllocationPendingStackTrace.java index 81cf4191c6ed3..c74eeefa793f4 100644 --- a/test/jdk/jdk/jfr/event/gc/stacktrace/TestMetaspaceG1GCAllocationPendingStackTrace.java +++ b/test/jdk/jdk/jfr/event/gc/stacktrace/TestMetaspaceG1GCAllocationPendingStackTrace.java @@ -28,9 +28,10 @@ * * @requires vm.gc == "null" | vm.gc == "G1" * @library /test/lib /test/jdk - * @run main/othervm -XX:+UseG1GC -Xlog:gc* -XX:MaxMetaspaceSize=64M jdk.jfr.event.gc.stacktrace.TestMetaspaceG1GCAllocationPendingStackTrace + * @run main/othervm -XX:+UseG1GC -Xlog:gc* -XX:MaxMetaspaceSize=64M + * -XX:FlightRecorderOptions:stackdepth=256 + * jdk.jfr.event.gc.stacktrace.TestMetaspaceG1GCAllocationPendingStackTrace */ - public class TestMetaspaceG1GCAllocationPendingStackTrace { public static void main(String[] args) throws Exception { diff --git a/test/jdk/jdk/jfr/event/gc/stacktrace/TestMetaspaceParallelGCAllocationPendingStackTrace.java b/test/jdk/jdk/jfr/event/gc/stacktrace/TestMetaspaceParallelGCAllocationPendingStackTrace.java index ab31fe644bf75..cc66902401504 100644 --- a/test/jdk/jdk/jfr/event/gc/stacktrace/TestMetaspaceParallelGCAllocationPendingStackTrace.java +++ b/test/jdk/jdk/jfr/event/gc/stacktrace/TestMetaspaceParallelGCAllocationPendingStackTrace.java @@ -29,7 +29,9 @@ * * @requires vm.gc == "null" | vm.gc == "Parallel" * @library /test/lib /test/jdk - * @run main/othervm -XX:+UseParallelGC -Xlog:gc* -XX:MaxMetaspaceSize=64M jdk.jfr.event.gc.stacktrace.TestMetaspaceParallelGCAllocationPendingStackTrace + * @run main/othervm -XX:+UseParallelGC -Xlog:gc* -XX:MaxMetaspaceSize=64M + * -XX:FlightRecorderOptions:stackdepth=256 + * jdk.jfr.event.gc.stacktrace.TestMetaspaceParallelGCAllocationPendingStackTrace */ public class TestMetaspaceParallelGCAllocationPendingStackTrace { diff --git a/test/jdk/jdk/jfr/event/gc/stacktrace/TestMetaspaceSerialGCAllocationPendingStackTrace.java b/test/jdk/jdk/jfr/event/gc/stacktrace/TestMetaspaceSerialGCAllocationPendingStackTrace.java index 83aa4fb522ef8..7f0ce364b6a88 100644 --- a/test/jdk/jdk/jfr/event/gc/stacktrace/TestMetaspaceSerialGCAllocationPendingStackTrace.java +++ b/test/jdk/jdk/jfr/event/gc/stacktrace/TestMetaspaceSerialGCAllocationPendingStackTrace.java @@ -29,7 +29,9 @@ * * @requires vm.gc == "null" | vm.gc == "Serial" * @library /test/lib /test/jdk - * @run main/othervm -XX:+UseSerialGC -Xlog:gc* -XX:MaxMetaspaceSize=64M jdk.jfr.event.gc.stacktrace.TestMetaspaceSerialGCAllocationPendingStackTrace + * @run main/othervm -XX:+UseSerialGC -Xlog:gc* -XX:MaxMetaspaceSize=64M + * -XX:FlightRecorderOptions:stackdepth=256 + * jdk.jfr.event.gc.stacktrace.TestMetaspaceSerialGCAllocationPendingStackTrace */ public class TestMetaspaceSerialGCAllocationPendingStackTrace { diff --git a/test/jdk/jdk/jfr/event/gc/stacktrace/TestParallelMarkSweepAllocationPendingStackTrace.java b/test/jdk/jdk/jfr/event/gc/stacktrace/TestParallelMarkSweepAllocationPendingStackTrace.java index 5ab67d2561a6f..ebd1efccfeef9 100644 --- a/test/jdk/jdk/jfr/event/gc/stacktrace/TestParallelMarkSweepAllocationPendingStackTrace.java +++ b/test/jdk/jdk/jfr/event/gc/stacktrace/TestParallelMarkSweepAllocationPendingStackTrace.java @@ -29,7 +29,9 @@ * * @requires vm.gc == "null" | vm.gc == "Parallel" * @library /test/lib /test/jdk - * @run main/othervm -XX:MaxNewSize=10M -Xmx64M -XX:+UseParallelGC -Xlog:gc* jdk.jfr.event.gc.stacktrace.TestParallelMarkSweepAllocationPendingStackTrace + * @run main/othervm -XX:MaxNewSize=10M -Xmx64M -XX:+UseParallelGC -Xlog:gc* + * -XX:FlightRecorderOptions:stackdepth=256 + * jdk.jfr.event.gc.stacktrace.TestParallelMarkSweepAllocationPendingStackTrace */ public class TestParallelMarkSweepAllocationPendingStackTrace { diff --git a/test/jdk/jdk/jfr/event/gc/stacktrace/TestParallelScavengeAllocationPendingStackTrace.java b/test/jdk/jdk/jfr/event/gc/stacktrace/TestParallelScavengeAllocationPendingStackTrace.java index 08ec7ffd05c89..6dbbc16e2836b 100644 --- a/test/jdk/jdk/jfr/event/gc/stacktrace/TestParallelScavengeAllocationPendingStackTrace.java +++ b/test/jdk/jdk/jfr/event/gc/stacktrace/TestParallelScavengeAllocationPendingStackTrace.java @@ -29,7 +29,9 @@ * * @requires vm.gc == "null" | vm.gc == "Parallel" * @library /test/lib /test/jdk - * @run main/othervm -XX:+UseParallelGC -Xlog:gc* jdk.jfr.event.gc.stacktrace.TestParallelScavengeAllocationPendingStackTrace + * @run main/othervm -XX:+UseParallelGC -Xlog:gc* + * -XX:FlightRecorderOptions:stackdepth=256 + * jdk.jfr.event.gc.stacktrace.TestParallelScavengeAllocationPendingStackTrace */ public class TestParallelScavengeAllocationPendingStackTrace { From cd52ad80a82c8165424722dcddd37d6584137031 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Mon, 29 Jul 2024 12:30:57 +0000 Subject: [PATCH 123/353] 8337267: [REDO] G1: Refactor G1RebuildRSAndScrubTask Reviewed-by: gli, tschatzl --- .../gc/g1/g1ConcurrentRebuildAndScrub.cpp | 156 +++++++----------- 1 file changed, 56 insertions(+), 100 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1ConcurrentRebuildAndScrub.cpp b/src/hotspot/share/gc/g1/g1ConcurrentRebuildAndScrub.cpp index 1b6b1eed7b13b..f62d42069004f 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentRebuildAndScrub.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentRebuildAndScrub.cpp @@ -87,14 +87,19 @@ class G1RebuildRSAndScrubTask : public WorkerTask { _processed_words += processed; } - // Yield if enough has been processed; returns if the concurrent marking cycle - // has been aborted for any reason. - bool yield_if_necessary() { + // Yield if enough has been processed. Return whether we should stop + // processing this region because either the concurrent marking cycle has been + // aborted or the region has been reclaimed. + bool yield_if_necessary(G1HeapRegion* hr) { if (_processed_words >= ProcessingYieldLimitInWords) { reset_processed_words(); - _cm->do_yield_check(); + // If a yield occurs (potential young-gc pause), must recheck for + // potential regions reclamation. + if (_cm->do_yield_check() && !should_rebuild_or_scrub(hr)) { + return true; + } } - return _cm->has_aborted(); + return _cm->has_aborted() || !should_rebuild_or_scrub(hr); } // Returns whether the top at rebuild start value for the given region indicates @@ -111,8 +116,7 @@ class G1RebuildRSAndScrubTask : public WorkerTask { // Helper used by both humongous objects and when chunking an object larger than the // G1RebuildRemSetChunkSize. The heap region is needed check whether the region has // been reclaimed during yielding. - // Returns true if marking has been aborted or false if completed. - bool scan_large_object(G1HeapRegion* hr, const oop obj, MemRegion scan_range) { + void scan_large_object(G1HeapRegion* hr, const oop obj, MemRegion scan_range) { HeapWord* start = scan_range.start(); HeapWord* limit = scan_range.end(); do { @@ -122,20 +126,14 @@ class G1RebuildRSAndScrubTask : public WorkerTask { // Update processed words and yield, for humongous objects we will yield // after each chunk. add_processed_words(mr.word_size()); - bool mark_aborted = yield_if_necessary(); - if (mark_aborted) { - return true; - } else if (!should_rebuild_or_scrub(hr)) { - // We need to check should_rebuild_or_scrub() again because the region might - // have been reclaimed during above yield/safepoint. - log_trace(gc, marking)("Rebuild aborted for reclaimed region: %u", hr->hrm_index()); - return false; + + if (yield_if_necessary(hr)) { + return; } // Step to next chunk of the large object. start = mr.end(); } while (start < limit); - return false; } // Scan for references into regions that need remembered set update for the given @@ -165,102 +163,66 @@ class G1RebuildRSAndScrubTask : public WorkerTask { return obj_size; } - // Scrub a range of dead objects starting at scrub_start. Will never scrub past limit. - HeapWord* scrub_to_next_live(G1HeapRegion* hr, HeapWord* scrub_start, HeapWord* limit) { - assert(!_bitmap->is_marked(scrub_start), "Should not scrub live object"); - - HeapWord* scrub_end = _bitmap->get_next_marked_addr(scrub_start, limit); - hr->fill_range_with_dead_objects(scrub_start, scrub_end); - - // Return the next object to handle. - return scrub_end; - } - - // Scan the given region from bottom to parsable_bottom. Returns whether marking has - // been aborted. - bool scan_and_scrub_to_pb(G1HeapRegion* hr, HeapWord* start, HeapWord* const limit) { - - while (start < limit) { - if (_bitmap->is_marked(start)) { - // Live object, need to scan to rebuild remembered sets for this object. - start += scan_object(hr, start); - } else { - // Found dead object (which klass has potentially been unloaded). Scrub to next - // marked object and continue. - start = scrub_to_next_live(hr, start, limit); - } - - bool mark_aborted = yield_if_necessary(); - if (mark_aborted) { - return true; - } else if (!should_rebuild_or_scrub(hr)) { - // We need to check should_rebuild_or_scrub() again because the region might - // have been reclaimed during above yield/safepoint. - log_trace(gc, marking)("Scan and scrub aborted for reclaimed region: %u", hr->hrm_index()); - return false; - } - } - return false; - } - - // Scan the given region from parsable_bottom to tars. Returns whether marking has - // been aborted. - bool scan_from_pb_to_tars(G1HeapRegion* hr, HeapWord* start, HeapWord* const limit) { - - while (start < limit) { - start += scan_object(hr, start); - // Avoid stalling safepoints and stop iteration if mark cycle has been aborted. - bool mark_aborted = yield_if_necessary(); - if (mark_aborted) { - return true; - } else if (!should_rebuild_or_scrub(hr)) { - // We need to check should_rebuild_or_scrub() again because the region might - // have been reclaimed during above yield/safepoint. - log_trace(gc, marking)("Scan aborted for reclaimed region: %u", hr->hrm_index()); - return false; - } + // Scan or scrub depending on if addr is marked. + HeapWord* scan_or_scrub(G1HeapRegion* hr, HeapWord* addr, HeapWord* limit) { + if (_bitmap->is_marked(addr)) { + // Live object, need to scan to rebuild remembered sets for this object. + return addr + scan_object(hr, addr); + } else { + // Found dead object (which klass has potentially been unloaded). Scrub to next marked object. + HeapWord* scrub_end = _bitmap->get_next_marked_addr(addr, limit); + hr->fill_range_with_dead_objects(addr, scrub_end); + // Return the next object to handle. + return scrub_end; } - return false; } - // Scan and scrub the given region to tars. Returns whether marking has - // been aborted. - bool scan_and_scrub_region(G1HeapRegion* hr, HeapWord* const pb) { + // Scan and scrub the given region to tars. + void scan_and_scrub_region(G1HeapRegion* hr, HeapWord* const pb) { assert(should_rebuild_or_scrub(hr), "must be"); log_trace(gc, marking)("Scrub and rebuild region: " HR_FORMAT " pb: " PTR_FORMAT " TARS: " PTR_FORMAT " TAMS: " PTR_FORMAT, HR_FORMAT_PARAMS(hr), p2i(pb), p2i(_cm->top_at_rebuild_start(hr)), p2i(_cm->top_at_mark_start(hr))); - if (scan_and_scrub_to_pb(hr, hr->bottom(), pb)) { - log_trace(gc, marking)("Scan and scrub aborted for region: %u", hr->hrm_index()); - return true; - } + { + // Step 1: Scan the given region from bottom to parsable_bottom. + HeapWord* start = hr->bottom(); + HeapWord* limit = pb; + while (start < limit) { + start = scan_or_scrub(hr, start, limit); - // Yielding during scrubbing and scanning might have reclaimed the region, so need to - // re-check after above. - if (!should_rebuild_or_scrub(hr)) { - return false; + if (yield_if_necessary(hr)) { + return; + } + } } + // Scrubbing completed for this region - notify that we are done with it, resetting // pb to bottom. hr->note_end_of_scrubbing(); - // Rebuild from TAMS (= parsable_bottom) to TARS. - if (scan_from_pb_to_tars(hr, pb, _cm->top_at_rebuild_start(hr))) { - log_trace(gc, marking)("Rebuild aborted for region: %u (%s)", hr->hrm_index(), hr->get_short_type_str()); - return true; + { + // Step 2: Rebuild from TAMS (= parsable_bottom) to TARS. + HeapWord* start = pb; + HeapWord* limit = _cm->top_at_rebuild_start(hr); + while (start < limit) { + start += scan_object(hr, start); + + if (yield_if_necessary(hr)) { + return; + } + } } - return false; } // Scan a humongous region for remembered set updates. Scans in chunks to avoid - // stalling safepoints. Returns whether the concurrent marking phase has been aborted. - bool scan_humongous_region(G1HeapRegion* hr, HeapWord* const pb) { + // stalling safepoints. + void scan_humongous_region(G1HeapRegion* hr, HeapWord* const pb) { assert(should_rebuild_or_scrub(hr), "must be"); if (!_should_rebuild_remset) { // When not rebuilding there is nothing to do for humongous objects. - return false; + return; } // At this point we should only have live humongous objects, that @@ -278,12 +240,7 @@ class G1RebuildRSAndScrubTask : public WorkerTask { HeapWord* humongous_end = hr->humongous_start_region()->bottom() + humongous->size(); MemRegion mr(hr->bottom(), MIN2(hr->top(), humongous_end)); - bool mark_aborted = scan_large_object(hr, humongous, mr); - if (mark_aborted) { - log_trace(gc, marking)("Rebuild aborted for region: %u (%s)", hr->hrm_index(), hr->get_short_type_str()); - return true; - } - return false; + scan_large_object(hr, humongous, mr); } public: @@ -312,17 +269,16 @@ class G1RebuildRSAndScrubTask : public WorkerTask { return false; } - bool mark_aborted; if (hr->needs_scrubbing()) { // This is a region with potentially unparsable (dead) objects. - mark_aborted = scan_and_scrub_region(hr, pb); + scan_and_scrub_region(hr, pb); } else { assert(hr->is_humongous(), "must be, but %u is %s", hr->hrm_index(), hr->get_short_type_str()); // No need to scrub humongous, but we should scan it to rebuild remsets. - mark_aborted = scan_humongous_region(hr, pb); + scan_humongous_region(hr, pb); } - return mark_aborted; + return _cm->has_aborted(); } }; From ee365d75cca6f33e5781fe514e557caba2b67c32 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Mon, 29 Jul 2024 13:37:56 +0000 Subject: [PATCH 124/353] 8336342: Fix known X11 library locations in sysroot Reviewed-by: jwaters, phh, prr --- make/autoconf/lib-x11.m4 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/make/autoconf/lib-x11.m4 b/make/autoconf/lib-x11.m4 index b1902a432a1e0..6849b4a26c776 100644 --- a/make/autoconf/lib-x11.m4 +++ b/make/autoconf/lib-x11.m4 @@ -71,9 +71,9 @@ AC_DEFUN_ONCE([LIB_SETUP_X11], elif test -f "$SYSROOT/usr/lib/libX11.so"; then x_libraries="$SYSROOT/usr/lib" elif test -f "$SYSROOT/usr/lib/$OPENJDK_TARGET_CPU-$OPENJDK_TARGET_OS-$OPENJDK_TARGET_ABI/libX11.so"; then - x_libraries="$SYSROOT/usr/lib/$OPENJDK_TARGET_CPU-$OPENJDK_TARGET_OS-$OPENJDK_TARGET_ABI/libX11.so" + x_libraries="$SYSROOT/usr/lib/$OPENJDK_TARGET_CPU-$OPENJDK_TARGET_OS-$OPENJDK_TARGET_ABI" elif test -f "$SYSROOT/usr/lib/$OPENJDK_TARGET_CPU_AUTOCONF-$OPENJDK_TARGET_OS-$OPENJDK_TARGET_ABI/libX11.so"; then - x_libraries="$SYSROOT/usr/lib/$OPENJDK_TARGET_CPU_AUTOCONF-$OPENJDK_TARGET_OS-$OPENJDK_TARGET_ABI/libX11.so" + x_libraries="$SYSROOT/usr/lib/$OPENJDK_TARGET_CPU_AUTOCONF-$OPENJDK_TARGET_OS-$OPENJDK_TARGET_ABI" fi fi fi From c23d37e10a429c0e7248593b07ef1ccdcd34bd1c Mon Sep 17 00:00:00 2001 From: Naoto Sato Date: Mon, 29 Jul 2024 16:43:25 +0000 Subject: [PATCH 125/353] 8337300: java/lang/Process/WaitForDuration.java leaves child process behind Reviewed-by: alanb, iris, bpb --- test/jdk/java/lang/Process/WaitForDuration.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/test/jdk/java/lang/Process/WaitForDuration.java b/test/jdk/java/lang/Process/WaitForDuration.java index d9172b305a0c0..76c69e36d1357 100644 --- a/test/jdk/java/lang/Process/WaitForDuration.java +++ b/test/jdk/java/lang/Process/WaitForDuration.java @@ -55,9 +55,14 @@ static Stream durations() { @MethodSource("durations") void testEdgeDurations(Duration d, int sleepMillis, boolean expected) throws IOException, InterruptedException { - var pb = ProcessTools.createTestJavaProcessBuilder( - WaitForDuration.class.getSimpleName(), Integer.toString(sleepMillis)); - assertEquals(expected, pb.start().waitFor(d)); + var child = ProcessTools.createTestJavaProcessBuilder( + WaitForDuration.class.getSimpleName(), Integer.toString(sleepMillis)) + .start(); + try { + assertEquals(expected, child.waitFor(d)); + } finally { + child.destroy(); + } } @Test From c4e6255ac3ec5520c4cb6d0d4ad9013da177ba88 Mon Sep 17 00:00:00 2001 From: Chris Plummer Date: Mon, 29 Jul 2024 16:55:38 +0000 Subject: [PATCH 126/353] 8332738: Debug agent can deadlock on callbackLock when using StackFrame.PopFrames Reviewed-by: sspitsyn, amenkov --- .../share/native/libjdwp/eventHandler.c | 18 +++++++++++++++--- .../share/native/libjdwp/eventHandler.h | 5 ++++- .../share/native/libjdwp/invoker.c | 10 +++++++--- .../share/native/libjdwp/stepControl.c | 6 ++++-- .../share/native/libjdwp/threadControl.c | 17 +++++++++++------ 5 files changed, 41 insertions(+), 15 deletions(-) diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/eventHandler.c b/src/jdk.jdwp.agent/share/native/libjdwp/eventHandler.c index f91f16104ca35..cf2de8061195b 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/eventHandler.c +++ b/src/jdk.jdwp.agent/share/native/libjdwp/eventHandler.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -93,8 +93,8 @@ static jrawMonitorID callbackBlock; * not blocking might mean that a return would continue execution of * some java thread in the middle of VM_DEATH, this seems troubled. * - * WARNING: No not 'return' or 'goto' out of the BEGIN_CALLBACK/END_CALLBACK - * block, this will mess up the count. + * WARNING: Do not 'return' or 'goto' out of the BEGIN_CALLBACK/END_CALLBACK + * block. This will mess up the active_callbacks count. */ #define BEGIN_CALLBACK() \ @@ -1709,6 +1709,18 @@ eventHandler_unlock(void) debugMonitorExit(handlerLock); } +void +callback_lock(void) +{ + debugMonitorEnter(callbackLock); +} + +void +callback_unlock(void) +{ + debugMonitorExit(callbackLock); +} + /***** handler creation *****/ HandlerNode * diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/eventHandler.h b/src/jdk.jdwp.agent/share/native/libjdwp/eventHandler.h index c4a7aa0c4412b..096b1ed795ac6 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/eventHandler.h +++ b/src/jdk.jdwp.agent/share/native/libjdwp/eventHandler.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -78,6 +78,9 @@ void eventHandler_waitForActiveCallbacks(); void eventHandler_lock(void); void eventHandler_unlock(void); +void callback_lock(void); +void callback_unlock(void); + jboolean eventHandler_synthesizeUnloadEvent(char *signature, JNIEnv *env); jclass getMethodClass(jvmtiEnv *jvmti_env, jmethodID method); diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/invoker.c b/src/jdk.jdwp.agent/share/native/libjdwp/invoker.c index e1b4d2f3ab6d6..4b32430ad7be0 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/invoker.c +++ b/src/jdk.jdwp.agent/share/native/libjdwp/invoker.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -719,7 +719,9 @@ invoker_completeInvokeRequest(jthread thread) exc = NULL; id = 0; - eventHandler_lock(); /* for proper lock order */ + callback_lock(); /* for proper lock order in threadControl getLocks() */ + eventHandler_lock(); /* for proper lock order in threadControl getLocks() */ + stepControl_lock(); /* for proper lock order in threadControl getLocks() */ debugMonitorEnter(invokerLock); request = threadControl_getInvokeRequest(thread); @@ -772,7 +774,7 @@ invoker_completeInvokeRequest(jthread thread) * We cannot delete saved exception or return value references * since otherwise a deleted handle would escape when writing * the response to the stream. Instead, we clean those refs up - * after writing the respone. + * after writing the response. */ deleteGlobalArgumentRefs(env, request); @@ -790,7 +792,9 @@ invoker_completeInvokeRequest(jthread thread) * Give up the lock before I/O operation */ debugMonitorExit(invokerLock); + stepControl_unlock(); eventHandler_unlock(); + callback_unlock(); if (!detached) { outStream_initReply(&out, id); diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/stepControl.c b/src/jdk.jdwp.agent/share/native/libjdwp/stepControl.c index 0611e8fc2138c..aeec8175b1738 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/stepControl.c +++ b/src/jdk.jdwp.agent/share/native/libjdwp/stepControl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -805,7 +805,8 @@ stepControl_beginStep(JNIEnv *env, jthread thread, jint size, jint depth, LOG_STEP(("stepControl_beginStep: thread=%p,size=%d,depth=%d", thread, size, depth)); - eventHandler_lock(); /* for proper lock order */ + callback_lock(); /* for proper lock order in threadControl getLocks() */ + eventHandler_lock(); /* for proper lock order in threadControl getLocks() */ stepControl_lock(); step = threadControl_getStepRequest(thread); @@ -852,6 +853,7 @@ stepControl_beginStep(JNIEnv *env, jthread thread, jint size, jint depth, stepControl_unlock(); eventHandler_unlock(); + callback_unlock(); return error; } diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c b/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c index 00c34844c986a..220e004097945 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c +++ b/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c @@ -642,26 +642,31 @@ getLocks(void) * thread) needs to be grabbed here. This allows thread control * code to safely suspend and resume the application threads * while ensuring they don't hold a critical lock. + * + * stepControl_beginStep() grabs the eventHandler lock and stepControl lock + * before eventually ending up here, so we need to maintain that order here. + * Similarly, invoker_completeInvokeRequest() grabs the eventHandler lock + * and invoker lock. */ - + callback_lock(); eventHandler_lock(); + stepControl_lock(); invoker_lock(); eventHelper_lock(); - stepControl_lock(); - commonRef_lock(); debugMonitorEnter(threadLock); - + commonRef_lock(); } static void releaseLocks(void) { - debugMonitorExit(threadLock); commonRef_unlock(); - stepControl_unlock(); + debugMonitorExit(threadLock); eventHelper_unlock(); invoker_unlock(); + stepControl_unlock(); eventHandler_unlock(); + callback_unlock(); } void From a86244f83cc4e234bdf8dc2c8d87640b6aab8463 Mon Sep 17 00:00:00 2001 From: Archie Cobbs Date: Mon, 29 Jul 2024 19:16:39 +0000 Subject: [PATCH 127/353] 6381729: Javadoc for generic constructor doesn't document type parameter Reviewed-by: jjg, liach --- .../html/AbstractExecutableMemberWriter.java | 21 ++++++- .../formats/html/AbstractMemberWriter.java | 12 +--- .../doclets/formats/html/ClassUseWriter.java | 2 +- .../formats/html/ConstructorWriter.java | 59 ++++++++++++++----- .../doclets/formats/html/Signatures.java | 6 +- .../doclet/testErasure/TestErasure.java | 15 +++-- .../testTypeParams/TestTypeParameters.java | 24 +++++++- .../testTypeParams/pkg/CtorTypeParam.java | 29 +++++++++ 8 files changed, 133 insertions(+), 35 deletions(-) create mode 100644 test/langtools/jdk/javadoc/doclet/testTypeParams/pkg/CtorTypeParam.java diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractExecutableMemberWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractExecutableMemberWriter.java index 4e929130b667f..f6ad4cf05dfab 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractExecutableMemberWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractExecutableMemberWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,7 @@ import javax.lang.model.element.ElementKind; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.TypeElement; +import javax.lang.model.element.TypeParameterElement; import javax.lang.model.element.VariableElement; import javax.lang.model.type.DeclaredType; import javax.lang.model.type.ExecutableType; @@ -130,6 +131,24 @@ protected void addInheritedSummaryLink(TypeElement te, Element member, Content t target.add(writer.getDocLink(PLAIN, te, member, name(member))); } + /** + * Adds the generic type parameters. + * + * @param member the member to add the generic type parameters for + * @param target the content to which the generic type parameters will be added + */ + protected void addTypeParameters(ExecutableElement member, Content target) { + Content typeParameters = getTypeParameters(member); + target.add(typeParameters); + // Add explicit line break between method type parameters and + // return type in member summary table to avoid random wrapping. + if (typeParameters.charCount() > 10) { + target.add(new HtmlTree(TagName.BR)); + } else { + target.add(Entity.NO_BREAK_SPACE); + } + } + /** * Add the parameter for the executable member. * diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractMemberWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractMemberWriter.java index caeb6c35e6d66..af1f7ef1fe6cb 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractMemberWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractMemberWriter.java @@ -466,16 +466,8 @@ protected void addModifiersAndType(Element member, TypeMirror type, ? ((ExecutableElement)member).getTypeParameters() : null; if (list != null && !list.isEmpty()) { - Content typeParameters = ((AbstractExecutableMemberWriter) this) - .getTypeParameters((ExecutableElement)member); - code.add(typeParameters); - // Add explicit line break between method type parameters and - // return type in member summary table to avoid random wrapping. - if (typeParameters.charCount() > 10) { - code.add(new HtmlTree(TagName.BR)); - } else { - code.add(Entity.NO_BREAK_SPACE); - } + ((AbstractExecutableMemberWriter) this) + .addTypeParameters((ExecutableElement)member, code); } code.add( writer.getLink(new HtmlLinkInfo(configuration, 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 e949b4ddc6831..94e66f1eed610 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 @@ -142,7 +142,7 @@ public ClassUseWriter(HtmlConfiguration configuration, methodSubWriter = new MethodWriter(this); constrSubWriter = new ConstructorWriter(this); - constrSubWriter.setFoundNonPubConstructor(true); + constrSubWriter.setShowConstructorModifiers(true); fieldSubWriter = new FieldWriter(this); classSubWriter = new NestedClassWriter(this); } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstructorWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstructorWriter.java index 1c4af2faf9782..c5fb332a0087b 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstructorWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstructorWriter.java @@ -31,6 +31,7 @@ import javax.lang.model.element.Element; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.TypeElement; +import javax.lang.model.element.TypeParameterElement; import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; import jdk.javadoc.internal.doclets.formats.html.markup.Entity; @@ -53,7 +54,17 @@ public class ConstructorWriter extends AbstractExecutableMemberWriter { */ private ExecutableElement currentConstructor; - private boolean foundNonPubConstructor = false; + /** + * If any constructors are non-public, then we want the modifiers shown in the summary. + * This implies we need a three-column summary. + */ + private boolean showConstructorModifiers = false; + + /** + * Whether any constructors have type parameters. + * This implies we need a three column summary. + */ + private boolean hasTypeParamsConstructor = false; /** * Construct a new member writer for constructors. @@ -65,11 +76,7 @@ public ConstructorWriter(ClassWriter writer) { // the following must be done before the summary table is generated var constructors = getVisibleMembers(VisibleMemberTable.Kind.CONSTRUCTORS); - for (Element constructor : constructors) { - if (utils.isProtected(constructor) || utils.isPrivate(constructor)) { - setFoundNonPubConstructor(true); - } - } + analyzeConstructors(constructors); } /** @@ -94,11 +101,7 @@ public void buildDetails(Content target) { protected void buildConstructorDoc(Content target) { var constructors = getVisibleMembers(VisibleMemberTable.Kind.CONSTRUCTORS); if (!constructors.isEmpty()) { - for (Element constructor : constructors) { - if (utils.isProtected(constructor) || utils.isPrivate(constructor)) { - setFoundNonPubConstructor(true); - } - } + analyzeConstructors(constructors); Content constructorDetailsHeader = getConstructorDetailsHeader(target); Content memberList = getMemberList(); @@ -126,6 +129,24 @@ protected void buildConstructorDoc(Content target) { } } + // Calculate "showConstructorModifiers" and "hasTypeParamsConstructor" + private void analyzeConstructors(List constructors) { + for (Element constructor : constructors) { + if (utils.isProtected(constructor) || utils.isPrivate(constructor)) { + setShowConstructorModifiers(true); + } + List list = ((ExecutableElement)constructor).getTypeParameters(); + if (list != null && !list.isEmpty()) { + hasTypeParamsConstructor = true; + } + } + } + + // Does the constructor summary need three columnns or just two? + protected boolean threeColumnSummary() { + return showConstructorModifiers || hasTypeParamsConstructor; + } + @Override protected void buildSignature(Content target) { target.add(getSignature(currentConstructor)); @@ -201,6 +222,7 @@ protected Content getConstructorHeaderContent(ExecutableElement constructor) { protected Content getSignature(ExecutableElement constructor) { return new Signatures.MemberSignature(constructor, this) + .setTypeParameters(getTypeParameters(constructor)) .setParameters(getParameters(constructor, true)) .setExceptions(getExceptions(constructor)) .setAnnotations(writer.getAnnotationInfo(constructor, true)) @@ -231,8 +253,8 @@ protected Content getConstructorDetails(Content memberDetailsHeader, Content mem .add(memberDetails)); } - protected void setFoundNonPubConstructor(boolean foundNonPubConstructor) { - this.foundNonPubConstructor = foundNonPubConstructor; + protected void setShowConstructorModifiers(boolean showConstructorModifiers) { + this.showConstructorModifiers = showConstructorModifiers; } @Override @@ -244,7 +266,7 @@ public void addSummaryLabel(Content content) { @Override public TableHeader getSummaryTableHeader(Element member) { - if (foundNonPubConstructor) { + if (threeColumnSummary()) { return new TableHeader(contents.modifierLabel, contents.constructorLabel, contents.descriptionLabel); } else { @@ -256,7 +278,7 @@ public TableHeader getSummaryTableHeader(Element member) { protected Table createSummaryTable() { List bodyRowStyles; - if (foundNonPubConstructor) { + if (threeColumnSummary()) { bodyRowStyles = Arrays.asList(HtmlStyle.colFirst, HtmlStyle.colConstructorName, HtmlStyle.colLast); } else { @@ -276,7 +298,7 @@ public void addInheritedSummaryLabel(TypeElement typeElement, Content content) { @Override protected void addSummaryType(Element member, Content content) { - if (foundNonPubConstructor) { + if (threeColumnSummary()) { var code = new HtmlTree(TagName.CODE); if (utils.isProtected(member)) { code.add("protected "); @@ -288,6 +310,11 @@ protected void addSummaryType(Element member, Content content) { code.add( resources.getText("doclet.Package_private")); } + ExecutableElement constructor = (ExecutableElement)member; + List list = constructor.getTypeParameters(); + if (list != null && !list.isEmpty()) { + addTypeParameters(constructor, code); + } content.add(code); } } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Signatures.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Signatures.java index f4f472de9f99a..afc0648fa79c2 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Signatures.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Signatures.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -529,6 +529,7 @@ private void appendModifiers(Content target) { private int appendTypeParameters(Content target, int lastLineSeparator) { // Apply different wrapping strategies for type parameters // depending on the combined length of type parameters and return type. + // Note return type will be null if this is a constructor. int typeParamLength = typeParameters.charCount(); if (typeParamLength >= TYPE_PARAMS_MAX_INLINE_LENGTH) { @@ -539,9 +540,10 @@ private int appendTypeParameters(Content target, int lastLineSeparator) { int lineLength = target.charCount() - lastLineSeparator; int newLastLineSeparator = lastLineSeparator; + int returnTypeLength = returnType != null ? returnType.charCount() : 0; // sum below includes length of modifiers plus type params added above - if (lineLength + returnType.charCount() > RETURN_TYPE_MAX_LINE_LENGTH) { + if (lineLength + returnTypeLength > RETURN_TYPE_MAX_LINE_LENGTH) { target.add(Text.NL); newLastLineSeparator = target.charCount(); } else { diff --git a/test/langtools/jdk/javadoc/doclet/testErasure/TestErasure.java b/test/langtools/jdk/javadoc/doclet/testErasure/TestErasure.java index 3c9f9b6fd9d3b..f80074c50e250 100644 --- a/test/langtools/jdk/javadoc/doclet/testErasure/TestErasure.java +++ b/test/langtools/jdk/javadoc/doclet/testErasure/TestErasure.java @@ -82,15 +82,19 @@ class Y { }

Constructor Summary

Constructors
-
-
Constructor
+
+
Modifier
+
Constructor
Description
+
 
\ Foo(T arg)
 
+
 <T extends X>
\ Foo(T arg)
 
+
 <T extends Y>
\ Foo(T arg)
 
@@ -188,13 +192,16 @@ class X { }

Constructor Summary

Constructors
-
-
Constructor
+
+
Modifier
+
Constructor
Description
+
 
\ Foo\ (T arg)
 
+
 <T extends X>
\ Foo(T arg)
 
diff --git a/test/langtools/jdk/javadoc/doclet/testTypeParams/TestTypeParameters.java b/test/langtools/jdk/javadoc/doclet/testTypeParams/TestTypeParameters.java index 7f586b3539d76..0d95ee38cdc94 100644 --- a/test/langtools/jdk/javadoc/doclet/testTypeParams/TestTypeParameters.java +++ b/test/langtools/jdk/javadoc/doclet/testTypeParams/TestTypeParameters.java @@ -23,12 +23,13 @@ /* * @test - * @bug 4927167 4974929 7010344 8025633 8081854 8182765 8187288 8261976 + * @bug 4927167 4974929 6381729 7010344 8025633 8081854 8182765 8187288 8261976 * @summary When the type parameters are more than 10 characters in length, * make sure there is a line break between type params and return type * in member summary. Also, test for type parameter links in package-summary and * class-use pages. The class/annotation pages should check for type * parameter links in the class/annotation signature section when -linksource is set. + * Verify that generic type parameters on constructors are documented. * @library ../../lib * @modules jdk.javadoc/jdk.javadoc.internal.tool * @build javadoc.tester.* @@ -94,4 +95,25 @@ public class ParamTest2<java.util.List<? extends Foo4>>>"""); } + + @Test + public void test3() { + javadoc("-d", "out-3", + "-Xdoclint:none", + "--no-platform-links", + "-sourcepath", testSrc, + "pkg"); + checkExit(Exit.OK); + + checkOutput("pkg/CtorTypeParam.html", true, + """ +
 <T extends java.lang.Runnable>
+ +
 
""", + """ +
public\ +  <T extends java.lang.Runnable>\ +  CtorTypeParam()
"""); + } } diff --git a/test/langtools/jdk/javadoc/doclet/testTypeParams/pkg/CtorTypeParam.java b/test/langtools/jdk/javadoc/doclet/testTypeParams/pkg/CtorTypeParam.java new file mode 100644 index 0000000000000..a7f2309475d28 --- /dev/null +++ b/test/langtools/jdk/javadoc/doclet/testTypeParams/pkg/CtorTypeParam.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package pkg; + +public class CtorTypeParam { + public CtorTypeParam() { + } +} From bd36b6ae5d0d760670a0bd722878614a6cd553d6 Mon Sep 17 00:00:00 2001 From: Justin Lu Date: Mon, 29 Jul 2024 19:28:14 +0000 Subject: [PATCH 128/353] 8337285: Examine java.text.DecimalFormat API for api/implXxx tag usage Reviewed-by: naoto, liach --- .../classes/java/text/DecimalFormat.java | 57 +++++++++---------- 1 file changed, 27 insertions(+), 30 deletions(-) diff --git a/src/java.base/share/classes/java/text/DecimalFormat.java b/src/java.base/share/classes/java/text/DecimalFormat.java index 07a1c6932e7e3..c04abbd042f57 100644 --- a/src/java.base/share/classes/java/text/DecimalFormat.java +++ b/src/java.base/share/classes/java/text/DecimalFormat.java @@ -430,16 +430,15 @@ public class DecimalFormat extends NumberFormat { * for the default {@link java.util.Locale.Category#FORMAT FORMAT} locale. * This is a convenient way to obtain a * DecimalFormat when internationalization is not the main concern. - *

- * To obtain standard formats for a given locale, use the factory methods - * on NumberFormat such as getNumberInstance. These factories will - * return the most appropriate sub-class of NumberFormat for a given - * locale. * - * @see java.text.NumberFormat#getInstance - * @see java.text.NumberFormat#getNumberInstance - * @see java.text.NumberFormat#getCurrencyInstance - * @see java.text.NumberFormat#getPercentInstance + * @apiNote To obtain standard formats for a given locale, use the + * {@code NumberFormat} factory methods such as {@link + * NumberFormat#getNumberInstance(Locale)}. These factories will return the most + * appropriate subclass of NumberFormat for a given locale. + * @see NumberFormat#getInstance(Locale) + * @see NumberFormat#getNumberInstance(Locale) + * @see NumberFormat#getCurrencyInstance(Locale) + * @see NumberFormat#getPercentInstance(Locale) */ @SuppressWarnings("this-escape") public DecimalFormat() { @@ -464,19 +463,18 @@ public DecimalFormat() { * DecimalFormat when internationalization is not the main concern. * The number of maximum integer digits is usually not derived from the pattern. * See the note in the {@link ##patterns Patterns} section for more detail. - *

- * To obtain standard formats for a given locale, use the factory methods - * on NumberFormat such as getNumberInstance. These factories will - * return the most appropriate sub-class of NumberFormat for a given - * locale. * + * @apiNote To obtain standard formats for a given locale, use the + * {@code NumberFormat} factory methods such as {@link + * NumberFormat#getNumberInstance(Locale)}. These factories will return the most + * appropriate subclass of NumberFormat for a given locale. * @param pattern a non-localized pattern string. * @throws NullPointerException if {@code pattern} is null * @throws IllegalArgumentException if the given pattern is invalid. - * @see java.text.NumberFormat#getInstance - * @see java.text.NumberFormat#getNumberInstance - * @see java.text.NumberFormat#getCurrencyInstance - * @see java.text.NumberFormat#getPercentInstance + * @see NumberFormat#getInstance(Locale) + * @see NumberFormat#getNumberInstance(Locale) + * @see NumberFormat#getCurrencyInstance(Locale) + * @see NumberFormat#getPercentInstance(Locale) */ @SuppressWarnings("this-escape") public DecimalFormat(String pattern) { @@ -492,21 +490,20 @@ public DecimalFormat(String pattern) { * behavior of the format. * The number of maximum integer digits is usually not derived from the pattern. * See the note in the {@link ##patterns Patterns} section for more detail. - *

- * To obtain standard formats for a given - * locale, use the factory methods on NumberFormat such as - * getInstance or getCurrencyInstance. If you need only minor adjustments - * to a standard format, you can modify the format returned by - * a NumberFormat factory method. * + * @apiNote To obtain standard formats for a given locale, use the + * {@code NumberFormat} factory methods such as {@link + * NumberFormat#getInstance(Locale)} or {@link NumberFormat#getCurrencyInstance(Locale)}. + * If you need only minor adjustments to a standard format, you can modify + * the format returned by a NumberFormat factory method. * @param pattern a non-localized pattern string * @param symbols the set of symbols to be used * @throws NullPointerException if any of the given arguments is null * @throws IllegalArgumentException if the given pattern is invalid - * @see java.text.NumberFormat#getInstance - * @see java.text.NumberFormat#getNumberInstance - * @see java.text.NumberFormat#getCurrencyInstance - * @see java.text.NumberFormat#getPercentInstance + * @see NumberFormat#getInstance(Locale) + * @see NumberFormat#getNumberInstance(Locale) + * @see NumberFormat#getCurrencyInstance(Locale) + * @see NumberFormat#getPercentInstance(Locale) * @see java.text.DecimalFormatSymbols */ @SuppressWarnings("this-escape") @@ -522,8 +519,8 @@ public DecimalFormat (String pattern, DecimalFormatSymbols symbols) { * Formats a number and appends the resulting text to the given string * buffer. * The number can be of any subclass of {@link java.lang.Number}. - *

- * This implementation uses the maximum precision permitted. + * + * @implSpec This implementation uses the maximum precision permitted. * @param number the number to format * @param toAppendTo the {@code StringBuffer} to which the formatted * text is to be appended From ab27090aa085283233851410827767785b3b7b1f Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Mon, 29 Jul 2024 21:58:08 +0000 Subject: [PATCH 129/353] 8337225: Demote maxStack and maxLocals from CodeModel to CodeAttribute Reviewed-by: asotona --- .../java/lang/classfile/CodeModel.java | 12 +- .../classfile/attribute/CodeAttribute.java | 10 ++ .../classfile/impl/AbstractUnboundModel.java | 9 +- .../classfile/impl/BufferedCodeBuilder.java | 40 ++---- .../classfile/impl/BufferedFieldBuilder.java | 9 +- .../classfile/impl/BufferedMethodBuilder.java | 13 +- .../jdk/internal/classfile/impl/CodeImpl.java | 2 +- .../classfile/impl/DirectCodeBuilder.java | 11 +- .../classfile/impl/TerminalCodeBuilder.java | 16 +++ test/jdk/jdk/classfile/BuilderBlockTest.java | 117 +++++++++++++++--- test/jdk/jdk/classfile/CorpusTest.java | 7 +- .../DiscontinuedInstructionsTest.java | 3 +- test/jdk/jdk/classfile/StackMapsTest.java | 3 +- 13 files changed, 165 insertions(+), 87 deletions(-) diff --git a/src/java.base/share/classes/java/lang/classfile/CodeModel.java b/src/java.base/share/classes/java/lang/classfile/CodeModel.java index 45488561c1ab3..ba816f2080581 100644 --- a/src/java.base/share/classes/java/lang/classfile/CodeModel.java +++ b/src/java.base/share/classes/java/lang/classfile/CodeModel.java @@ -43,17 +43,7 @@ @PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API) public sealed interface CodeModel extends CompoundElement, AttributedElement, MethodElement - permits CodeAttribute, BufferedCodeBuilder.Model, CodeImpl { - - /** - * {@return the maximum size of the local variable table} - */ - int maxLocals(); - - /** - * {@return the maximum size of the operand stack} - */ - int maxStack(); + permits CodeAttribute, BufferedCodeBuilder.Model { /** * {@return the enclosing method, if known} diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/CodeAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/CodeAttribute.java index 02cbcee810f64..7a4f5886580cc 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/CodeAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/CodeAttribute.java @@ -47,6 +47,16 @@ public sealed interface CodeAttribute extends Attribute, CodeModel permits BoundAttribute.BoundCodeAttribute { + /** + * {@return the maximum size of the local variable table} + */ + int maxLocals(); + + /** + * {@return the maximum size of the operand stack} + */ + int maxStack(); + /** * {@return The length of the code array in bytes} */ diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractUnboundModel.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractUnboundModel.java index 788bdffe1cd5b..2926be9dad7dc 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractUnboundModel.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractUnboundModel.java @@ -35,7 +35,7 @@ public abstract sealed class AbstractUnboundModel extends AbstractElement - implements CompoundElement, AttributedElement, Util.Writable + implements CompoundElement, AttributedElement permits BufferedCodeBuilder.Model, BufferedFieldBuilder.Model, BufferedMethodBuilder.Model { private final List elements; private List> attributes; @@ -63,8 +63,11 @@ public List elementList() { public List> attributes() { if (attributes == null) attributes = elements.stream() - .filter(e -> e instanceof Attribute) - .>map(e -> (Attribute) e) + .>mapMulti((e, sink) -> { + if (e instanceof Attribute attr) { + sink.accept(attr); + } + }) .toList(); return attributes; } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedCodeBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedCodeBuilder.java index 4743c58607c84..7f041633d8a20 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedCodeBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedCodeBuilder.java @@ -32,9 +32,6 @@ import java.lang.classfile.Label; import java.lang.classfile.MethodModel; import java.lang.classfile.instruction.ExceptionCatch; -import java.lang.classfile.instruction.IncrementInstruction; -import java.lang.classfile.instruction.LoadInstruction; -import java.lang.classfile.instruction.StoreInstruction; import java.util.ArrayList; import java.util.List; @@ -47,7 +44,6 @@ public final class BufferedCodeBuilder private final ClassFileImpl context; private final List elements = new ArrayList<>(); private final LabelImpl startLabel, endLabel; - private final CodeModel original; private final MethodInfo methodInfo; private boolean finished; private int maxLocals; @@ -60,12 +56,8 @@ public BufferedCodeBuilder(MethodInfo methodInfo, this.context = context; this.startLabel = new LabelImpl(this, -1); this.endLabel = new LabelImpl(this, -1); - this.original = original; this.methodInfo = methodInfo; - this.maxLocals = Util.maxLocals(methodInfo.methodFlags(), methodInfo.methodTypeSymbol()); - if (original != null) - this.maxLocals = Math.max(this.maxLocals, original.maxLocals()); - + this.maxLocals = TerminalCodeBuilder.setupTopLocal(methodInfo, original); elements.add(startLabel); } @@ -162,27 +154,16 @@ private Model() { @Override public List exceptionHandlers() { return elements.stream() - .filter(x -> x instanceof ExceptionCatch) - .map(x -> (ExceptionCatch) x) + .mapMulti((x, sink) -> { + if (x instanceof ExceptionCatch ec) { + sink.accept(ec); + } + }) .toList(); } - @Override - public int maxLocals() { - for (CodeElement element : elements) { - if (element instanceof LoadInstruction i) - maxLocals = Math.max(maxLocals, i.slot() + i.typeKind().slotSize()); - else if (element instanceof StoreInstruction i) - maxLocals = Math.max(maxLocals, i.slot() + i.typeKind().slotSize()); - else if (element instanceof IncrementInstruction i) - maxLocals = Math.max(maxLocals, i.slot() + 1); - } - return maxLocals; - } - - @Override - public int maxStack() { - throw new UnsupportedOperationException("nyi"); + int curTopLocal() { + return BufferedCodeBuilder.this.curTopLocal(); } @Override @@ -200,11 +181,6 @@ public void accept(CodeBuilder cb) { }); } - @Override - public void writeTo(BufWriterImpl buf) { - DirectCodeBuilder.build(methodInfo, cb -> elements.forEach(cb), constantPool, context, null).writeTo(buf); - } - @Override public String toString() { return String.format("CodeModel[id=%s]", Integer.toHexString(System.identityHashCode(this))); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedFieldBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedFieldBuilder.java index 660a999f2a3e5..66ecf10598afb 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedFieldBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedFieldBuilder.java @@ -103,7 +103,7 @@ public Utf8Entry fieldType() { @Override public void writeTo(DirectClassBuilder builder) { - builder.withField(name, desc, new Consumer() { + builder.withField(name, desc, new Consumer<>() { @Override public void accept(FieldBuilder fieldBuilder) { elements.forEach(fieldBuilder); @@ -111,13 +111,6 @@ public void accept(FieldBuilder fieldBuilder) { }); } - @Override - public void writeTo(BufWriterImpl buf) { - DirectFieldBuilder fb = new DirectFieldBuilder(constantPool, context, name, desc, null); - elements.forEach(fb); - fb.writeTo(buf); - } - @Override public String toString() { return String.format("FieldModel[fieldName=%s, fieldType=%s, flags=%d]", name.stringValue(), desc.stringValue(), flags.flagsMask()); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedMethodBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedMethodBuilder.java index 880c6717db87c..b93ad1185ab3b 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedMethodBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedMethodBuilder.java @@ -196,7 +196,11 @@ public int parameterSlot(int paramNo) { @Override public Optional code() { - throw new UnsupportedOperationException("nyi"); + return elements.stream().mapMulti((e, sink) -> { + if (e instanceof CodeModel cm) { + sink.accept(cm); + } + }).findFirst(); } @Override @@ -209,13 +213,6 @@ public void accept(MethodBuilder mb) { }); } - @Override - public void writeTo(BufWriterImpl buf) { - DirectMethodBuilder mb = new DirectMethodBuilder(constantPool, context, name, desc, methodFlags(), null); - elements.forEach(mb); - mb.writeTo(buf); - } - @Override public String toString() { return String.format("MethodModel[methodName=%s, methodType=%s, flags=%d]", diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/CodeImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/CodeImpl.java index 7669cbfdd30ca..d4719fad0b1c2 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/CodeImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/CodeImpl.java @@ -43,7 +43,7 @@ public final class CodeImpl extends BoundAttribute.BoundCodeAttribute - implements CodeModel, LabelContext { + implements LabelContext { static final Instruction[] SINGLETON_INSTRUCTIONS = new Instruction[256]; diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java index 536750ebd2f0e..a7652ac369b16 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java @@ -127,12 +127,10 @@ private DirectCodeBuilder(MethodInfo methodInfo, this.transformFwdJumps = transformFwdJumps; this.transformBackJumps = context.shortJumpsOption() == ClassFile.ShortJumpsOption.FIX_SHORT_JUMPS; bytecodesBufWriter = (original instanceof CodeImpl cai) ? new BufWriterImpl(constantPool, context, cai.codeLength()) - : new BufWriterImpl(constantPool, context); + : new BufWriterImpl(constantPool, context); this.startLabel = new LabelImpl(this, 0); this.endLabel = new LabelImpl(this, -1); - this.topLocal = Util.maxLocals(methodInfo.methodFlags(), methodInfo.methodTypeSymbol()); - if (original != null) - this.topLocal = Math.max(this.topLocal, original.maxLocals()); + this.topLocal = TerminalCodeBuilder.setupTopLocal(methodInfo, original); } @Override @@ -312,8 +310,9 @@ public void writeBody(BufWriterImpl b) { private void writeCounters(boolean codeMatch, BufWriterImpl buf) { if (codeMatch) { - buf.writeU2(original.maxStack()); - buf.writeU2(original.maxLocals()); + var originalAttribute = (CodeImpl) original; + buf.writeU2(originalAttribute.maxStack()); + buf.writeU2(originalAttribute.maxLocals()); } else { StackCounter cntr = StackCounter.of(DirectCodeBuilder.this, buf); buf.writeU2(cntr.maxStack()); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/TerminalCodeBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/TerminalCodeBuilder.java index 6e3ca516bf480..054ea91992869 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/TerminalCodeBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/TerminalCodeBuilder.java @@ -25,8 +25,24 @@ package jdk.internal.classfile.impl; import java.lang.classfile.CodeBuilder; +import java.lang.classfile.CodeModel; +import java.lang.classfile.attribute.CodeAttribute; public sealed interface TerminalCodeBuilder extends CodeBuilder, LabelContext permits DirectCodeBuilder, BufferedCodeBuilder { int curTopLocal(); + + static int setupTopLocal(MethodInfo methodInfo, CodeModel original) { + int paramSlots = Util.maxLocals(methodInfo.methodFlags(), methodInfo.methodTypeSymbol()); + if (original == null) { + return paramSlots; + } + if (original instanceof CodeAttribute attr) { + return Math.max(paramSlots, attr.maxLocals()); + } + if (original instanceof BufferedCodeBuilder.Model buffered) { + return Math.max(paramSlots, buffered.curTopLocal()); + } + throw new InternalError("Unknown code model " + original); + } } diff --git a/test/jdk/jdk/classfile/BuilderBlockTest.java b/test/jdk/jdk/classfile/BuilderBlockTest.java index c8e13b79f7280..a2fb361ca2c7a 100644 --- a/test/jdk/jdk/classfile/BuilderBlockTest.java +++ b/test/jdk/jdk/classfile/BuilderBlockTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,36 +23,48 @@ /* * @test + * @bug 8337225 * @summary Testing ClassFile builder blocks. * @run junit BuilderBlockTest */ +import java.io.IOException; +import java.lang.classfile.AccessFlags; +import java.lang.classfile.Attributes; +import java.lang.classfile.ClassFile; +import java.lang.classfile.ClassTransform; +import java.lang.classfile.CodeBuilder; +import java.lang.classfile.CodeElement; +import java.lang.classfile.CodeTransform; +import java.lang.classfile.Label; +import java.lang.classfile.MethodModel; +import java.lang.classfile.MethodTransform; +import java.lang.classfile.Opcode; +import java.lang.classfile.TypeKind; +import java.lang.classfile.constantpool.StringEntry; +import java.lang.classfile.instruction.ConstantInstruction; import java.lang.constant.ClassDesc; - -import static java.lang.constant.ConstantDescs.*; - import java.lang.constant.MethodTypeDesc; +import java.lang.reflect.AccessFlag; import java.lang.reflect.Method; +import java.net.URI; import java.nio.file.Path; -import java.nio.file.Paths; import helpers.ByteArrayClassLoader; -import java.lang.classfile.AccessFlags; -import java.lang.reflect.AccessFlag; -import java.lang.classfile.ClassFile; -import java.lang.classfile.Label; -import java.lang.classfile.Opcode; -import java.lang.classfile.TypeKind; import jdk.internal.classfile.impl.LabelImpl; -import static org.junit.jupiter.api.Assertions.*; import org.junit.jupiter.api.Test; +import static java.lang.constant.ConstantDescs.CD_int; +import static java.lang.constant.ConstantDescs.CD_void; + +import static org.junit.jupiter.api.Assertions.*; + /** * BuilderBlockTest */ class BuilderBlockTest { - static final String testClassName = "AdaptCodeTest$TestClass"; - static final Path testClassPath = Paths.get("target/test-classes/" + testClassName + ".class"); + static final String testClassName = "BuilderBlockTest$TestClass"; + static final Path testClassPath = Path.of(URI.create(BuilderBlockTest.class.getResource(testClassName + ".class").toString())); @Test void testStartEnd() throws Exception { @@ -305,4 +317,81 @@ void testAllocateLocalIfThen() { })); }); } + + private static final CodeTransform ALLOCATE_LOCAL_EXAMINER = CodeTransform.ofStateful(() -> new CodeTransform() { + boolean foundItem = false; + + @Override + public void atStart(CodeBuilder builder) { + foundItem = false; + } + + @Override + public void accept(CodeBuilder cob, CodeElement coe) { + cob.with(coe); + if (coe instanceof ConstantInstruction.LoadConstantInstruction ldc + && ldc.constantEntry() instanceof StringEntry se + && se.utf8().equalsString("Output")) { + assertFalse(foundItem); + foundItem = true; + var i = cob.allocateLocal(TypeKind.IntType); + assertEquals(7, i, "Allocated new int slot"); + } + } + + @Override + public void atEnd(CodeBuilder builder) { + assertTrue(foundItem); + } + }); + + // Test updating local variable slot management from + // source code models in transformingCode; + // CodeBuilder.transform(CodeModel, CodeTransform) is + // not managed for now + @Test + void testAllocateLocalTransformingCodeAttribute() throws IOException { + var cf = ClassFile.of(); + var code = cf.parse(testClassPath) + .methods() + .stream() + .filter(f -> f.methodName().equalsString("work")) + .findFirst() + .orElseThrow() + .findAttribute(Attributes.code()) + .orElseThrow(); + ClassFile.of().build(ClassDesc.of("Foo"), cb -> cb + .withMethod("foo", MethodTypeDesc.ofDescriptor("(IJI)V"), 0, mb -> mb + .transformCode(code, ALLOCATE_LOCAL_EXAMINER))); + } + + @Test + void testAllocateLocalTransformingBufferedCode() throws IOException { + var cf = ClassFile.of(); + var testClass = cf.parse(testClassPath); + ClassTransform bufferingTransform = (clb, cle) -> { + if (cle instanceof MethodModel mm && mm.methodName().equalsString("work")) { + clb.withMethodBody(mm.methodName(), mm.methodType(), mm.flags().flagsMask(), cob -> { + int d = cob.allocateLocal(TypeKind.IntType); + int e = cob.allocateLocal(TypeKind.IntType); + + assertEquals(5, d); + assertEquals(6, e); + + mm.code().ifPresent(code -> code.forEach(cob)); + }); + } + }; + cf.transformClass(testClass, bufferingTransform.andThen(ClassTransform.transformingMethods(MethodTransform.transformingCode(ALLOCATE_LOCAL_EXAMINER)))); + } + + public static class TestClass { + public void work(int a, long b, int c) { + int d = Math.addExact(a, 25); + int e = Math.multiplyExact(d, c); + System.out.println("Output"); + System.out.println(e + b); + throw new IllegalArgumentException("foo"); + } + } } diff --git a/test/jdk/jdk/classfile/CorpusTest.java b/test/jdk/jdk/classfile/CorpusTest.java index a2af166797827..631e2f8afaa1b 100644 --- a/test/jdk/jdk/classfile/CorpusTest.java +++ b/test/jdk/jdk/classfile/CorpusTest.java @@ -39,6 +39,7 @@ import org.junit.jupiter.api.parallel.ExecutionMode; import java.io.ByteArrayInputStream; +import java.lang.classfile.attribute.CodeAttribute; import java.util.*; import static helpers.ClassRecord.assertEqualsDeep; @@ -222,9 +223,11 @@ void testNullAdaptations(Path path) throws Exception { var m1 = itStack.next(); var m2 = itNoStack.next(); var text1 = m1.methodName().stringValue() + m1.methodType().stringValue() + ": " - + m1.code().map(c -> c.maxLocals() + " / " + c.maxStack()).orElse("-"); + + m1.code().map(CodeAttribute.class::cast) + .map(c -> c.maxLocals() + " / " + c.maxStack()).orElse("-"); var text2 = m2.methodName().stringValue() + m2.methodType().stringValue() + ": " - + m2.code().map(c -> c.maxLocals() + " / " + c.maxStack()).orElse("-"); + + m2.code().map(CodeAttribute.class::cast) + .map(c -> c.maxLocals() + " / " + c.maxStack()).orElse("-"); assertEquals(text1, text2); } assertFalse(itNoStack.hasNext()); diff --git a/test/jdk/jdk/classfile/DiscontinuedInstructionsTest.java b/test/jdk/jdk/classfile/DiscontinuedInstructionsTest.java index 9070f0b1d4513..5e51e585634d0 100644 --- a/test/jdk/jdk/classfile/DiscontinuedInstructionsTest.java +++ b/test/jdk/jdk/classfile/DiscontinuedInstructionsTest.java @@ -26,6 +26,7 @@ * @summary Testing ClassFile handling JSR and RET instructions. * @run junit DiscontinuedInstructionsTest */ +import java.lang.classfile.attribute.CodeAttribute; import java.lang.constant.ClassDesc; import java.lang.constant.MethodTypeDesc; import java.util.ArrayList; @@ -63,7 +64,7 @@ void testJsrAndRetProcessing() throws Exception { .pop() .with(DiscontinuedInstruction.RetInstruction.of(355)))); - var c = cc.parse(bytes).methods().get(0).code().get(); + var c = (CodeAttribute) cc.parse(bytes).methods().get(0).code().get(); assertEquals(356, c.maxLocals()); assertEquals(6, c.maxStack()); diff --git a/test/jdk/jdk/classfile/StackMapsTest.java b/test/jdk/jdk/classfile/StackMapsTest.java index 211490c3f8e75..a5109dd2a18a4 100644 --- a/test/jdk/jdk/classfile/StackMapsTest.java +++ b/test/jdk/jdk/classfile/StackMapsTest.java @@ -30,6 +30,7 @@ */ import java.lang.classfile.*; +import java.lang.classfile.attribute.CodeAttribute; import java.lang.classfile.components.ClassPrinter; import java.net.URI; import java.nio.file.FileSystem; @@ -329,7 +330,7 @@ void testEmptyCounters(ClassFile.StackMapsOption option) { var cm = ClassFile.of().parse(bytes); for (var method : cm.methods()) { var name = method.methodName(); - var code = method.code().orElseThrow(); + var code = (CodeAttribute) method.code().orElseThrow(); if (name.equalsString("a")) { assertEquals(0, code.maxLocals()); // static method assertEquals(0, code.maxStack()); From 7e21d4c1916d6690b717911179314c26a0da5ed9 Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Tue, 30 Jul 2024 03:03:43 +0000 Subject: [PATCH 130/353] 8337268: Redundant Math.ceil in StyleSheet.ListPainter#drawShape Reviewed-by: prr, aivanov --- .../share/classes/javax/swing/text/html/StyleSheet.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/java.desktop/share/classes/javax/swing/text/html/StyleSheet.java b/src/java.desktop/share/classes/javax/swing/text/html/StyleSheet.java index 0790060f5e8c8..9b8e33b4c6b03 100644 --- a/src/java.desktop/share/classes/javax/swing/text/html/StyleSheet.java +++ b/src/java.desktop/share/classes/javax/swing/text/html/StyleSheet.java @@ -2391,7 +2391,7 @@ void drawShape(Graphics g, CSS.Value type, int ax, int ay, int aw, // Position shape to the middle of the html text. int gap = isLeftToRight ? - (bulletgap + size/3) : (aw + bulletgap); int x = ax + gap; - int y = Math.max(ay, ay + (int)Math.ceil(ah/2)); + int y = Math.max(ay, ay + ah/2); if (type == CSS.Value.SQUARE) { g.drawRect(x, y, size/3, size/3); From bc7c255b156bf3bb3fd8c3f622b8127ab27e7c7a Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Tue, 30 Jul 2024 07:24:22 +0000 Subject: [PATCH 131/353] 8337416: Fix -Wzero-as-null-pointer-constant warnings in misc. runtime code Reviewed-by: dholmes, jwaters --- src/hotspot/share/logging/logConfiguration.cpp | 2 +- src/hotspot/share/memory/metaspace/metachunk.cpp | 2 +- src/hotspot/share/memory/metaspace/rootChunkArea.cpp | 4 ++-- src/hotspot/share/memory/virtualspace.cpp | 2 +- src/hotspot/share/oops/constantPool.cpp | 2 +- src/hotspot/share/oops/instanceKlass.cpp | 4 ++-- src/hotspot/share/oops/method.cpp | 4 ++-- src/hotspot/share/runtime/arguments.cpp | 6 +++--- src/hotspot/share/runtime/javaThread.cpp | 6 +++--- src/hotspot/share/runtime/vframeArray.cpp | 2 +- 10 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/hotspot/share/logging/logConfiguration.cpp b/src/hotspot/share/logging/logConfiguration.cpp index 3a54d1f4e6369..87b195f4fbfdd 100644 --- a/src/hotspot/share/logging/logConfiguration.cpp +++ b/src/hotspot/share/logging/logConfiguration.cpp @@ -370,7 +370,7 @@ bool LogConfiguration::parse_command_line_arguments(const char* opts) { // Split the option string to its colon separated components. char* str = copy; - char* substrings[4] = {0}; + char* substrings[4] = {}; for (int i = 0 ; i < 4; i++) { substrings[i] = str; diff --git a/src/hotspot/share/memory/metaspace/metachunk.cpp b/src/hotspot/share/memory/metaspace/metachunk.cpp index 3d67aac80160e..0bf7e98f13022 100644 --- a/src/hotspot/share/memory/metaspace/metachunk.cpp +++ b/src/hotspot/share/memory/metaspace/metachunk.cpp @@ -253,7 +253,7 @@ void Metachunk::verify_neighborhood() const { } } -volatile MetaWord dummy = 0; +volatile MetaWord dummy = nullptr; void Metachunk::verify() const { // Note. This should be called under CLD lock protection. diff --git a/src/hotspot/share/memory/metaspace/rootChunkArea.cpp b/src/hotspot/share/memory/metaspace/rootChunkArea.cpp index ee3af35a5b8b4..24377ec25ad12 100644 --- a/src/hotspot/share/memory/metaspace/rootChunkArea.cpp +++ b/src/hotspot/share/memory/metaspace/rootChunkArea.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2020, 2022 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -59,7 +59,7 @@ RootChunkArea::~RootChunkArea() { // root chunk header. It will be partly initialized. // Note: this just allocates a memory-less header; memory itself is allocated inside VirtualSpaceNode. Metachunk* RootChunkArea::alloc_root_chunk_header(VirtualSpaceNode* node) { - assert(_first_chunk == 0, "already have a root"); + assert(_first_chunk == nullptr, "already have a root"); Metachunk* c = ChunkHeaderPool::pool()->allocate_chunk_header(); c->initialize(node, const_cast(_base), chunklevel::ROOT_CHUNK_LEVEL); _first_chunk = c; diff --git a/src/hotspot/share/memory/virtualspace.cpp b/src/hotspot/share/memory/virtualspace.cpp index 7df35bbeec88e..c27e607353af1 100644 --- a/src/hotspot/share/memory/virtualspace.cpp +++ b/src/hotspot/share/memory/virtualspace.cpp @@ -159,7 +159,7 @@ static char* reserve_memory(char* requested_address, const size_t size, // If the memory was requested at a particular address, use // os::attempt_reserve_memory_at() to avoid mapping over something // important. If the reservation fails, return null. - if (requested_address != 0) { + if (requested_address != nullptr) { assert(is_aligned(requested_address, alignment), "Requested address " PTR_FORMAT " must be aligned to " SIZE_FORMAT, p2i(requested_address), alignment); diff --git a/src/hotspot/share/oops/constantPool.cpp b/src/hotspot/share/oops/constantPool.cpp index 35a1d95b6e647..1c295e10b21db 100644 --- a/src/hotspot/share/oops/constantPool.cpp +++ b/src/hotspot/share/oops/constantPool.cpp @@ -2065,7 +2065,7 @@ static void print_cpool_bytes(jint cnt, u1 *bytes) { size += ent_size; } printf("Cpool size: %d\n", size); - fflush(0); + fflush(nullptr); return; } /* end print_cpool_bytes */ diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp index 930f8cf177116..650279db1bee3 100644 --- a/src/hotspot/share/oops/instanceKlass.cpp +++ b/src/hotspot/share/oops/instanceKlass.cpp @@ -2779,9 +2779,9 @@ void InstanceKlass::release_C_heap_structures(bool release_sub_metadata) { #if INCLUDE_JVMTI // Deallocate breakpoint records - if (breakpoints() != 0x0) { + if (breakpoints() != nullptr) { methods_do(clear_all_breakpoints); - assert(breakpoints() == 0x0, "should have cleared breakpoints"); + assert(breakpoints() == nullptr, "should have cleared breakpoints"); } // deallocate the cached class file diff --git a/src/hotspot/share/oops/method.cpp b/src/hotspot/share/oops/method.cpp index e5ba0d610314b..f4dcd4f149302 100644 --- a/src/hotspot/share/oops/method.cpp +++ b/src/hotspot/share/oops/method.cpp @@ -322,7 +322,7 @@ void Method::mask_for(const methodHandle& this_mh, int bci, InterpreterOopMap* m } int Method::bci_from(address bcp) const { - if (is_native() && bcp == 0) { + if (is_native() && bcp == nullptr) { return 0; } // Do not have a ResourceMark here because AsyncGetCallTrace stack walking code @@ -345,7 +345,7 @@ int Method::validate_bci(int bci) const { int Method::validate_bci_from_bcp(address bcp) const { // keep bci as -1 if not a valid bci int bci = -1; - if (bcp == 0 || bcp == code_base()) { + if (bcp == nullptr || bcp == code_base()) { // code_size() may return 0 and we allow 0 here // the method may be native bci = 0; diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index 966f4855789e4..1bded2916504f 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -102,7 +102,7 @@ size_t Arguments::_default_SharedBaseAddress = SharedBaseAddress; bool Arguments::_enable_preview = false; -LegacyGCLogging Arguments::_legacyGCLogging = { 0, 0 }; +LegacyGCLogging Arguments::_legacyGCLogging = { nullptr, 0 }; // These are not set by the JDK's built-in launchers, but they can be set by // programs that embed the JVM using JNI_CreateJavaVM. See comments around @@ -1850,11 +1850,11 @@ bool Arguments::is_bad_option(const JavaVMOption* option, jboolean ignore, } static const char* user_assertion_options[] = { - "-da", "-ea", "-disableassertions", "-enableassertions", 0 + "-da", "-ea", "-disableassertions", "-enableassertions", nullptr }; static const char* system_assertion_options[] = { - "-dsa", "-esa", "-disablesystemassertions", "-enablesystemassertions", 0 + "-dsa", "-esa", "-disablesystemassertions", "-enablesystemassertions", nullptr }; bool Arguments::parse_uint(const char* value, diff --git a/src/hotspot/share/runtime/javaThread.cpp b/src/hotspot/share/runtime/javaThread.cpp index a3eef07ba0ac9..b69ab708afa52 100644 --- a/src/hotspot/share/runtime/javaThread.cpp +++ b/src/hotspot/share/runtime/javaThread.cpp @@ -470,8 +470,8 @@ JavaThread::JavaThread(MEMFLAGS flags) : #endif // INCLUDE_JVMCI _exception_oop(oop()), - _exception_pc(0), - _exception_handler_pc(0), + _exception_pc(nullptr), + _exception_handler_pc(nullptr), _is_method_handle_return(0), _jni_active_critical(0), @@ -483,7 +483,7 @@ JavaThread::JavaThread(MEMFLAGS flags) : _frames_to_pop_failed_realloc(0), _cont_entry(nullptr), - _cont_fastpath(0), + _cont_fastpath(nullptr), _cont_fastpath_thread_state(1), _held_monitor_count(0), _jni_monitor_count(0), diff --git a/src/hotspot/share/runtime/vframeArray.cpp b/src/hotspot/share/runtime/vframeArray.cpp index d3bbbc283992a..1b26abf740287 100644 --- a/src/hotspot/share/runtime/vframeArray.cpp +++ b/src/hotspot/share/runtime/vframeArray.cpp @@ -321,7 +321,7 @@ void vframeArrayElement::unpack_on_stack(int caller_actual_parameters, "should be held, after move_to"); } if (ProfileInterpreter) { - iframe()->interpreter_frame_set_mdp(0); // clear out the mdp. + iframe()->interpreter_frame_set_mdp(nullptr); // clear out the mdp. } iframe()->interpreter_frame_set_bcp(bcp); if (ProfileInterpreter) { From 9e6e0a8f341389215f0db6b2260f2b16351f02be Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Tue, 30 Jul 2024 08:27:27 +0000 Subject: [PATCH 132/353] 8336343: Add more known sysroot library locations for ALSA Reviewed-by: phh, prr, ihse --- make/autoconf/lib-alsa.m4 | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/make/autoconf/lib-alsa.m4 b/make/autoconf/lib-alsa.m4 index 19a91f94809f0..8d0fb324cd092 100644 --- a/make/autoconf/lib-alsa.m4 +++ b/make/autoconf/lib-alsa.m4 @@ -70,6 +70,25 @@ AC_DEFUN_ONCE([LIB_SETUP_ALSA], PKG_CHECK_MODULES(ALSA, alsa, [ALSA_FOUND=yes], [ALSA_FOUND=no]) fi fi + if test "x$ALSA_FOUND" = xno; then + # If we have sysroot set, and no explicit library location is set, + # look at known locations in sysroot. + if test "x$SYSROOT" != "x" && test "x${with_alsa_lib}" == x; then + if test -f "$SYSROOT/usr/lib64/libasound.so" && test "x$OPENJDK_TARGET_CPU_BITS" = x64; then + ALSA_LIBS="-L$SYSROOT/usr/lib64 -lasound" + ALSA_FOUND=yes + elif test -f "$SYSROOT/usr/lib/libasound.so"; then + ALSA_LIBS="-L$SYSROOT/usr/lib -lasound" + ALSA_FOUND=yes + elif test -f "$SYSROOT/usr/lib/$OPENJDK_TARGET_CPU-$OPENJDK_TARGET_OS-$OPENJDK_TARGET_ABI/libasound.so"; then + ALSA_LIBS="-L$SYSROOT/usr/lib/$OPENJDK_TARGET_CPU-$OPENJDK_TARGET_OS-$OPENJDK_TARGET_ABI -lasound" + ALSA_FOUND=yes + elif test -f "$SYSROOT/usr/lib/$OPENJDK_TARGET_CPU_AUTOCONF-$OPENJDK_TARGET_OS-$OPENJDK_TARGET_ABI/libasound.so"; then + ALSA_LIBS="-L$SYSROOT/usr/lib/$OPENJDK_TARGET_CPU_AUTOCONF-$OPENJDK_TARGET_OS-$OPENJDK_TARGET_ABI -lasound" + ALSA_FOUND=yes + fi + fi + fi if test "x$ALSA_FOUND" = xno; then AC_CHECK_HEADERS([alsa/asoundlib.h], [ From 156f0b4332bf076165898417cf6678d2fc32df5c Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Tue, 30 Jul 2024 08:29:23 +0000 Subject: [PATCH 133/353] 8337213: Shenandoah: Add verification for class mirrors Reviewed-by: rkennke, wkemper --- .../share/gc/shenandoah/shenandoahAsserts.cpp | 19 +++++++++++++++++++ .../gc/shenandoah/shenandoahVerifier.cpp | 15 +++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahAsserts.cpp b/src/hotspot/share/gc/shenandoah/shenandoahAsserts.cpp index beb4a1d289239..5215aa749aea1 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahAsserts.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahAsserts.cpp @@ -250,6 +250,25 @@ void ShenandoahAsserts::assert_correct(void* interior_loc, oop obj, const char* file, line); } } + + // Do additional checks for special objects: their fields can hold metadata as well. + // We want to check class loading/unloading did not corrupt them. + + if (java_lang_Class::is_instance(obj)) { + Metadata* klass = obj->metadata_field(java_lang_Class::klass_offset()); + if (klass != nullptr && !Metaspace::contains(klass)) { + print_failure(_safe_all, obj, interior_loc, nullptr, "Shenandoah assert_correct failed", + "Instance class mirror should point to Metaspace", + file, line); + } + + Metadata* array_klass = obj->metadata_field(java_lang_Class::array_klass_offset()); + if (array_klass != nullptr && !Metaspace::contains(array_klass)) { + print_failure(_safe_all, obj, interior_loc, nullptr, "Shenandoah assert_correct failed", + "Array class mirror should point to Metaspace", + file, line); + } + } } void ShenandoahAsserts::assert_in_correct_region(void* interior_loc, oop obj, const char* file, int line) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp index f67cafdb8fe7c..694736cea426c 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp @@ -212,6 +212,21 @@ class ShenandoahVerifyOopClosure : public BasicOopIterateClosure { fwd_reg = obj_reg; } + // Do additional checks for special objects: their fields can hold metadata as well. + // We want to check class loading/unloading did not corrupt them. + + if (java_lang_Class::is_instance(obj)) { + Metadata* klass = obj->metadata_field(java_lang_Class::klass_offset()); + check(ShenandoahAsserts::_safe_oop, obj, + klass == nullptr || Metaspace::contains(klass), + "Instance class mirror should point to Metaspace"); + + Metadata* array_klass = obj->metadata_field(java_lang_Class::array_klass_offset()); + check(ShenandoahAsserts::_safe_oop, obj, + array_klass == nullptr || Metaspace::contains(array_klass), + "Array class mirror should point to Metaspace"); + } + // ------------ obj and fwd are safe at this point -------------- switch (_options._verify_marked) { From 7ac531181c25815577ba2f6f426e1da270e4f589 Mon Sep 17 00:00:00 2001 From: Amit Kumar Date: Tue, 30 Jul 2024 09:32:27 +0000 Subject: [PATCH 134/353] 8331126: [s390x] secondary_super_cache does not scale well Reviewed-by: lucy, aph, mdoerr --- src/hotspot/cpu/s390/macroAssembler_s390.cpp | 296 +++++++++++++++++++ src/hotspot/cpu/s390/macroAssembler_s390.hpp | 25 ++ src/hotspot/cpu/s390/s390.ad | 44 +++ src/hotspot/cpu/s390/stubGenerator_s390.cpp | 54 +++- src/hotspot/cpu/s390/vm_version_s390.cpp | 11 +- src/hotspot/cpu/s390/vm_version_s390.hpp | 2 + 6 files changed, 429 insertions(+), 3 deletions(-) diff --git a/src/hotspot/cpu/s390/macroAssembler_s390.cpp b/src/hotspot/cpu/s390/macroAssembler_s390.cpp index 66d6f25f0fd4a..72d10ee80aae1 100644 --- a/src/hotspot/cpu/s390/macroAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/macroAssembler_s390.cpp @@ -1,6 +1,7 @@ /* * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2016, 2024 SAP SE. All rights reserved. + * Copyright 2024 IBM Corporation. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -3152,6 +3153,301 @@ void MacroAssembler::check_klass_subtype(Register sub_klass, BLOCK_COMMENT("} check_klass_subtype"); } +// scans r_count pointer sized words at [r_addr] for occurrence of r_value, +// generic (r_count must be >0) +// iff found: CC eq, r_result == 0 +void MacroAssembler::repne_scan(Register r_addr, Register r_value, Register r_count, Register r_result) { + NearLabel L_loop, L_exit; + + BLOCK_COMMENT("repne_scan {"); +#ifdef ASSERT + z_chi(r_count, 0); + asm_assert(bcondHigh, "count must be positive", 11); +#endif + + clear_reg(r_result, true /* whole_reg */, false /* set_cc */); // sets r_result=0, let's hope that search will be successful + + bind(L_loop); + z_cg(r_value, Address(r_addr)); + z_bre(L_exit); // branch on success + z_la(r_addr, wordSize, r_addr); + z_brct(r_count, L_loop); + + // z_brct above doesn't change CC. + // If we reach here, then the value in r_value is not present. Set r_result to 1. + z_lghi(r_result, 1); + + bind(L_exit); + BLOCK_COMMENT("} repne_scan"); +} + +// Ensure that the inline code and the stub are using the same registers. +#define LOOKUP_SECONDARY_SUPERS_TABLE_REGISTERS \ +do { \ + assert(r_super_klass == Z_ARG1 && \ + r_array_base == Z_ARG5 && \ + r_array_length == Z_ARG4 && \ + (r_array_index == Z_ARG3 || r_array_index == noreg) && \ + (r_sub_klass == Z_ARG2 || r_sub_klass == noreg) && \ + (r_bitmap == Z_R10 || r_bitmap == noreg) && \ + (r_result == Z_R11 || r_result == noreg), "registers must match s390.ad"); \ +} while(0) + +// Note: this method also kills Z_R1_scratch register on machines older than z15 +void MacroAssembler::lookup_secondary_supers_table(Register r_sub_klass, + Register r_super_klass, + Register r_temp1, + Register r_temp2, + Register r_temp3, + Register r_temp4, + Register r_result, + u1 super_klass_slot) { + NearLabel L_done, L_failure; + + BLOCK_COMMENT("lookup_secondary_supers_table {"); + + const Register + r_array_base = r_temp1, + r_array_length = r_temp2, + r_array_index = r_temp3, + r_bitmap = r_temp4; + + LOOKUP_SECONDARY_SUPERS_TABLE_REGISTERS; + + z_lg(r_bitmap, Address(r_sub_klass, Klass::bitmap_offset())); + + // First check the bitmap to see if super_klass might be present. If + // the bit is zero, we are certain that super_klass is not one of + // the secondary supers. + u1 bit = super_klass_slot; + int shift_count = Klass::SECONDARY_SUPERS_TABLE_MASK - bit; + + z_sllg(r_array_index, r_bitmap, shift_count); // take the bit to 63rd location + + // Initialize r_result with 0 (indicating success). If searching fails, r_result will be loaded + // with 1 (failure) at the end of this method. + clear_reg(r_result, true /* whole_reg */, false /* set_cc */); // r_result = 0 + + // We test the MSB of r_array_index, i.e., its sign bit + testbit(r_array_index, 63); + z_bfalse(L_failure); // if not set, then jump!!! + + // We will consult the secondary-super array. + z_lg(r_array_base, Address(r_sub_klass, Klass::secondary_supers_offset())); + + // The value i in r_array_index is >= 1, so even though r_array_base + // points to the length, we don't need to adjust it to point to the + // data. + assert(Array::base_offset_in_bytes() == wordSize, "Adjust this code"); + + // Get the first array index that can contain super_klass. + if (bit != 0) { + pop_count_long(r_array_index, r_array_index, Z_R1_scratch); // kills Z_R1_scratch on machines older than z15 + + // NB! r_array_index is off by 1. It is compensated by keeping r_array_base off by 1 word. + z_sllg(r_array_index, r_array_index, LogBytesPerWord); // scale + } else { + // Actually use index 0, but r_array_base and r_array_index are off by 1 word + // such that the sum is precise. + z_lghi(r_array_index, BytesPerWord); // for slow path (scaled) + } + + z_cg(r_super_klass, Address(r_array_base, r_array_index)); + branch_optimized(bcondEqual, L_done); // found a match; success + + // Is there another entry to check? Consult the bitmap. + testbit(r_bitmap, (bit + 1) & Klass::SECONDARY_SUPERS_TABLE_MASK); + z_bfalse(L_failure); + + // Linear probe. Rotate the bitmap so that the next bit to test is + // in Bit 2 for the look-ahead check in the slow path. + if (bit != 0) { + z_rllg(r_bitmap, r_bitmap, 64-bit); // rotate right + } + + // Calls into the stub generated by lookup_secondary_supers_table_slow_path. + // Arguments: r_super_klass, r_array_base, r_array_index, r_bitmap. + // Kills: r_array_length. + // Returns: r_result + + call_stub(StubRoutines::lookup_secondary_supers_table_slow_path_stub()); + + z_bru(L_done); // pass whatever result we got from a slow path + + bind(L_failure); + // TODO: use load immediate on condition and z_bru above will not be required + z_lghi(r_result, 1); + + bind(L_done); + BLOCK_COMMENT("} lookup_secondary_supers_table"); + + if (VerifySecondarySupers) { + verify_secondary_supers_table(r_sub_klass, r_super_klass, r_result, + r_temp1, r_temp2, r_temp3); + } +} + +// Called by code generated by check_klass_subtype_slow_path +// above. This is called when there is a collision in the hashed +// lookup in the secondary supers array. +void MacroAssembler::lookup_secondary_supers_table_slow_path(Register r_super_klass, + Register r_array_base, + Register r_array_index, + Register r_bitmap, + Register r_result, + Register r_temp1) { + assert_different_registers(r_super_klass, r_array_base, r_array_index, r_bitmap, r_result, r_temp1); + + const Register + r_array_length = r_temp1, + r_sub_klass = noreg; + + LOOKUP_SECONDARY_SUPERS_TABLE_REGISTERS; + + BLOCK_COMMENT("lookup_secondary_supers_table_slow_path {"); + NearLabel L_done, L_failure; + + // Load the array length. + z_llgf(r_array_length, Address(r_array_base, Array::length_offset_in_bytes())); + + // And adjust the array base to point to the data. + // NB! + // Effectively increments the current slot index by 1. + assert(Array::base_offset_in_bytes() == wordSize, ""); + add2reg(r_array_base, Array::base_offset_in_bytes()); + + // Linear probe + NearLabel L_huge; + + // The bitmap is full to bursting. + z_cghi(r_bitmap, Klass::SECONDARY_SUPERS_BITMAP_FULL); + z_bre(L_huge); + + // NB! Our caller has checked bits 0 and 1 in the bitmap. The + // current slot (at secondary_supers[r_array_index]) has not yet + // been inspected, and r_array_index may be out of bounds if we + // wrapped around the end of the array. + + { // This is conventional linear probing, but instead of terminating + // when a null entry is found in the table, we maintain a bitmap + // in which a 0 indicates missing entries. + // The check above guarantees there are 0s in the bitmap, so the loop + // eventually terminates. + +#ifdef ASSERT + // r_result is set to 0 by lookup_secondary_supers_table. + // clear_reg(r_result, true /* whole_reg */, false /* set_cc */); + z_cghi(r_result, 0); + asm_assert(bcondEqual, "r_result required to be 0, used by z_locgr", 44); + + // We should only reach here after having found a bit in the bitmap. + z_ltgr(r_array_length, r_array_length); + asm_assert(bcondHigh, "array_length > 0, should hold", 22); +#endif // ASSERT + + // Compute limit in r_array_length + add2reg(r_array_length, -1); + z_sllg(r_array_length, r_array_length, LogBytesPerWord); + + NearLabel L_loop; + bind(L_loop); + + // Check for wraparound. + z_cgr(r_array_index, r_array_length); + z_locgr(r_array_index, r_result, bcondHigh); // r_result is containing 0 + + z_cg(r_super_klass, Address(r_array_base, r_array_index)); + z_bre(L_done); // success + + // look-ahead check: if Bit 2 is 0, we're done + testbit(r_bitmap, 2); + z_bfalse(L_failure); + + z_rllg(r_bitmap, r_bitmap, 64-1); // rotate right + add2reg(r_array_index, BytesPerWord); + + z_bru(L_loop); + } + + { // Degenerate case: more than 64 secondary supers. + // FIXME: We could do something smarter here, maybe a vectorized + // comparison or a binary search, but is that worth any added + // complexity? + + bind(L_huge); + repne_scan(r_array_base, r_super_klass, r_array_length, r_result); + + z_bru(L_done); // forward the result we got from repne_scan + } + + bind(L_failure); + z_lghi(r_result, 1); + + bind(L_done); + BLOCK_COMMENT("} lookup_secondary_supers_table_slow_path"); +} + +// Make sure that the hashed lookup and a linear scan agree. +void MacroAssembler::verify_secondary_supers_table(Register r_sub_klass, + Register r_super_klass, + Register r_result /* expected */, + Register r_temp1, + Register r_temp2, + Register r_temp3) { + assert_different_registers(r_sub_klass, r_super_klass, r_result, r_temp1, r_temp2, r_temp3); + + const Register + r_array_base = r_temp1, + r_array_length = r_temp2, + r_array_index = r_temp3, + r_bitmap = noreg; // unused + + const Register r_one = Z_R0_scratch; + z_lghi(r_one, 1); // for locgr down there, to a load result for failure + + LOOKUP_SECONDARY_SUPERS_TABLE_REGISTERS; + + BLOCK_COMMENT("verify_secondary_supers_table {"); + + Label L_passed, L_failure; + + // We will consult the secondary-super array. + z_lg(r_array_base, Address(r_sub_klass, in_bytes(Klass::secondary_supers_offset()))); + + // Load the array length. + z_llgf(r_array_length, Address(r_array_base, Array::length_offset_in_bytes())); + + // And adjust the array base to point to the data. + z_aghi(r_array_base, Array::base_offset_in_bytes()); + + const Register r_linear_result = r_array_index; // reuse + z_chi(r_array_length, 0); + z_locgr(r_linear_result, r_one, bcondNotHigh); // load failure if array_length <= 0 + z_brc(bcondNotHigh, L_failure); + repne_scan(r_array_base, r_super_klass, r_array_length, r_linear_result); + bind(L_failure); + + z_cr(r_result, r_linear_result); + z_bre(L_passed); + + assert_different_registers(Z_ARG1, r_sub_klass, r_linear_result, r_result); + lgr_if_needed(Z_ARG1, r_super_klass); + assert_different_registers(Z_ARG2, r_linear_result, r_result); + lgr_if_needed(Z_ARG2, r_sub_klass); + assert_different_registers(Z_ARG3, r_result); + z_lgr(Z_ARG3, r_linear_result); + z_lgr(Z_ARG4, r_result); + const char* msg = "mismatch"; + load_const_optimized(Z_ARG5, (address)msg); + + call_VM_leaf(CAST_FROM_FN_PTR(address, Klass::on_secondary_supers_verification_failure)); + should_not_reach_here(); + + bind(L_passed); + + BLOCK_COMMENT("} verify_secondary_supers_table"); +} + void MacroAssembler::clinit_barrier(Register klass, Register thread, Label* L_fast_path, Label* L_slow_path) { assert(L_fast_path != nullptr || L_slow_path != nullptr, "at least one is required"); diff --git a/src/hotspot/cpu/s390/macroAssembler_s390.hpp b/src/hotspot/cpu/s390/macroAssembler_s390.hpp index 684741d79db2f..90210eb28c3ad 100644 --- a/src/hotspot/cpu/s390/macroAssembler_s390.hpp +++ b/src/hotspot/cpu/s390/macroAssembler_s390.hpp @@ -708,6 +708,31 @@ class MacroAssembler: public Assembler { Label* L_success, Label* L_failure); + void repne_scan(Register r_addr, Register r_value, Register r_count, Register r_scratch); + + void lookup_secondary_supers_table(Register r_sub_klass, + Register r_super_klass, + Register r_temp1, + Register r_temp2, + Register r_temp3, + Register r_temp4, + Register r_result, + u1 super_klass_slot); + + void lookup_secondary_supers_table_slow_path(Register r_super_klass, + Register r_array_base, + Register r_array_index, + Register r_bitmap, + Register r_result, + Register r_temp1); + + void verify_secondary_supers_table(Register r_sub_klass, + Register r_super_klass, + Register r_result /* expected */, + Register r_temp1, + Register r_temp2, + Register r_temp3); + // Simplified, combined version, good for typical uses. // Falls through on failure. void check_klass_subtype(Register sub_klass, diff --git a/src/hotspot/cpu/s390/s390.ad b/src/hotspot/cpu/s390/s390.ad index 0fe3840b9b53c..e3dcfdb8759da 100644 --- a/src/hotspot/cpu/s390/s390.ad +++ b/src/hotspot/cpu/s390/s390.ad @@ -356,6 +356,8 @@ reg_class z_rarg3_ptr_reg(Z_R4_H,Z_R4); reg_class z_rarg4_ptr_reg(Z_R5_H,Z_R5); reg_class z_rarg5_ptr_reg(Z_R6_H,Z_R6); reg_class z_thread_ptr_reg(Z_R8_H,Z_R8); +reg_class z_r10_ptr_reg(Z_R10_H, Z_R10); +reg_class z_r11_ptr_reg(Z_R11_H, Z_R11); reg_class z_ptr_reg( /*Z_R0_H,Z_R0*/ // R0 @@ -2985,6 +2987,8 @@ operand iRegP() %{ match(rarg5RegP); match(revenRegP); match(roddRegP); + match(r10TempRegP); + match(r11TempRegP); format %{ %} interface(REG_INTER); %} @@ -2997,6 +3001,20 @@ operand threadRegP() %{ interface(REG_INTER); %} +operand r10TempRegP() %{ + constraint(ALLOC_IN_RC(z_r10_ptr_reg)); + match(iRegP); + format %{ %} + interface(REG_INTER); +%} + +operand r11TempRegP() %{ + constraint(ALLOC_IN_RC(z_r11_ptr_reg)); + match(iRegP); + format %{ %} + interface(REG_INTER); +%} + operand noArg_iRegP() %{ constraint(ALLOC_IN_RC(z_no_arg_ptr_reg)); match(iRegP); @@ -9560,6 +9578,32 @@ instruct partialSubtypeCheck(rarg1RegP index, rarg2RegP sub, rarg3RegP super, fl ins_pipe(pipe_class_dummy); %} +instruct partialSubtypeCheckConstSuper(rarg2RegP sub, rarg1RegP super, immP super_con, + r11TempRegP result, rarg5RegP temp1, rarg4RegP temp2, + rarg3RegP temp3, r10TempRegP temp4, flagsReg pcc) %{ + match(Set result (PartialSubtypeCheck sub (Binary super super_con))); + predicate(UseSecondarySupersTable); + effect(KILL pcc, TEMP temp1, TEMP temp2, TEMP temp3, TEMP temp4); + ins_cost(7 * DEFAULT_COST); // needs to be less than competing nodes + format %{ "partialSubtypeCheck $result, $sub, $super, $super_con" %} + + ins_encode %{ + u1 super_klass_slot = ((Klass*)$super_con$$constant)->hash_slot(); + if (InlineSecondarySupersTest) { + __ lookup_secondary_supers_table($sub$$Register, $super$$Register, + $temp1$$Register, $temp2$$Register, $temp3$$Register, + $temp4$$Register, $result$$Register, super_klass_slot); + } else { + AddressLiteral stub_address(StubRoutines::lookup_secondary_supers_table_stub(super_klass_slot)); + __ load_const_optimized(Z_ARG4, stub_address); + __ z_basr(Z_R14, Z_ARG4); + } + + %} + + ins_pipe(pipe_class_dummy); +%} + instruct partialSubtypeCheck_vs_zero(flagsReg pcc, rarg2RegP sub, rarg3RegP super, immP0 zero, rarg1RegP index, rarg4RegP scratch1, rarg5RegP scratch2) %{ match(Set pcc (CmpI (PartialSubtypeCheck sub super) zero)); diff --git a/src/hotspot/cpu/s390/stubGenerator_s390.cpp b/src/hotspot/cpu/s390/stubGenerator_s390.cpp index dfd20730b8476..556c0d4703d54 100644 --- a/src/hotspot/cpu/s390/stubGenerator_s390.cpp +++ b/src/hotspot/cpu/s390/stubGenerator_s390.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2016, 2023 SAP SE. All rights reserved. + * Copyright (c) 2016, 2024 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -705,6 +705,50 @@ class StubGenerator: public StubCodeGenerator { return start; } + address generate_lookup_secondary_supers_table_stub(u1 super_klass_index) { + StubCodeMark mark(this, "StubRoutines", "lookup_secondary_supers_table"); + + const Register + r_super_klass = Z_ARG1, + r_sub_klass = Z_ARG2, + r_array_index = Z_ARG3, + r_array_length = Z_ARG4, + r_array_base = Z_ARG5, + r_bitmap = Z_R10, + r_result = Z_R11; + address start = __ pc(); + + __ lookup_secondary_supers_table(r_sub_klass, r_super_klass, + r_array_base, r_array_length, r_array_index, + r_bitmap, r_result, super_klass_index); + + __ z_br(Z_R14); + + return start; + } + + // Slow path implementation for UseSecondarySupersTable. + address generate_lookup_secondary_supers_table_slow_path_stub() { + StubCodeMark mark(this, "StubRoutines", "lookup_secondary_supers_table_slow_path"); + + address start = __ pc(); + + const Register + r_super_klass = Z_ARG1, + r_array_base = Z_ARG5, + r_temp1 = Z_ARG4, + r_array_index = Z_ARG3, + r_bitmap = Z_R10, + r_result = Z_R11; + + __ lookup_secondary_supers_table_slow_path(r_super_klass, r_array_base, + r_array_index, r_bitmap, r_result, r_temp1); + + __ z_br(Z_R14); + + return start; + } + #if !defined(PRODUCT) // Wrapper which calls oopDesc::is_oop_or_null() // Only called by MacroAssembler::verify_oop @@ -3247,6 +3291,14 @@ class StubGenerator: public StubCodeGenerator { StubRoutines::_montgomerySquare = CAST_FROM_FN_PTR(address, SharedRuntime::montgomery_square); } + if (UseSecondarySupersTable) { + StubRoutines::_lookup_secondary_supers_table_slow_path_stub = generate_lookup_secondary_supers_table_slow_path_stub(); + if (!InlineSecondarySupersTest) { + for (int slot = 0; slot < Klass::SECONDARY_SUPERS_TABLE_SIZE; slot++) { + StubRoutines::_lookup_secondary_supers_table_stubs[slot] = generate_lookup_secondary_supers_table_stub(slot); + } + } + } #endif #endif // COMPILER2_OR_JVMCI } diff --git a/src/hotspot/cpu/s390/vm_version_s390.cpp b/src/hotspot/cpu/s390/vm_version_s390.cpp index af0903884fb4f..4b17ff4594ccf 100644 --- a/src/hotspot/cpu/s390/vm_version_s390.cpp +++ b/src/hotspot/cpu/s390/vm_version_s390.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2016, 2023 SAP SE. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -272,6 +272,13 @@ void VM_Version::initialize() { FLAG_SET_DEFAULT(UseSHA, false); } + if (UseSecondarySupersTable && VM_Version::get_model_index() < 5 /* z196/z11 */) { + if (!FLAG_IS_DEFAULT(UseSecondarySupersTable)) { + warning("UseSecondarySupersTable requires z196 or later."); + } + FLAG_SET_DEFAULT(UseSecondarySupersTable, false); + } + #ifdef COMPILER2 if (FLAG_IS_DEFAULT(UseMultiplyToLenIntrinsic)) { FLAG_SET_DEFAULT(UseMultiplyToLenIntrinsic, true); diff --git a/src/hotspot/cpu/s390/vm_version_s390.hpp b/src/hotspot/cpu/s390/vm_version_s390.hpp index 4f963c4e4851a..31fdedc59f642 100644 --- a/src/hotspot/cpu/s390/vm_version_s390.hpp +++ b/src/hotspot/cpu/s390/vm_version_s390.hpp @@ -413,6 +413,8 @@ class VM_Version: public Abstract_VM_Version { // s390 supports fast class initialization checks static bool supports_fast_class_init_checks() { return true; } + constexpr static bool supports_secondary_supers_table() { return true; } + constexpr static bool supports_recursive_lightweight_locking() { return true; } // CPU feature query functions From 0325ab8d2353f29ac40ff4b028cbc29bff40c59b Mon Sep 17 00:00:00 2001 From: Kevin Walls Date: Tue, 30 Jul 2024 10:44:31 +0000 Subject: [PATCH 135/353] 8335610: DiagnosticFramework: CmdLine::is_executable() correction Reviewed-by: dholmes, jsjolen --- src/hotspot/share/services/diagnosticFramework.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/services/diagnosticFramework.hpp b/src/hotspot/share/services/diagnosticFramework.hpp index e8881c2364611..357482ec5a14d 100644 --- a/src/hotspot/share/services/diagnosticFramework.hpp +++ b/src/hotspot/share/services/diagnosticFramework.hpp @@ -67,7 +67,7 @@ class CmdLine : public StackObj { const char* cmd_addr() const { return _cmd; } size_t cmd_len() const { return _cmd_len; } bool is_empty() const { return _cmd_len == 0; } - bool is_executable() const { return is_empty() || _cmd[0] != '#'; } + bool is_executable() const { return !is_empty() && _cmd[0] != '#'; } bool is_stop() const { return !is_empty() && strncmp("stop", _cmd, _cmd_len) == 0; } }; From 8162832832ac6e8c17f942e718e309a3489e0da6 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Tue, 30 Jul 2024 12:40:35 +0000 Subject: [PATCH 136/353] 8333354: ubsan: frame.inline.hpp:91:25: and src/hotspot/share/runtime/frame.inline.hpp:88:29: runtime error: member call on null pointer of type 'const struct SmallRegisterMap' Co-authored-by: Kim Barrett Reviewed-by: rrich, clanger --- .../smallRegisterMap_aarch64.inline.hpp | 20 +++++++--------- .../cpu/arm/smallRegisterMap_arm.inline.hpp | 15 ++++++------ .../cpu/ppc/smallRegisterMap_ppc.inline.hpp | 24 +++++++------------ .../riscv/smallRegisterMap_riscv.inline.hpp | 20 +++++++--------- .../cpu/s390/smallRegisterMap_s390.inline.hpp | 15 ++++++------ .../cpu/x86/smallRegisterMap_x86.inline.hpp | 21 +++++++--------- .../cpu/zero/smallRegisterMap_zero.inline.hpp | 15 ++++++------ src/hotspot/share/oops/stackChunkOop.cpp | 2 +- .../share/oops/stackChunkOop.inline.hpp | 2 +- .../share/runtime/continuationFreezeThaw.cpp | 14 +++++------ 10 files changed, 67 insertions(+), 81 deletions(-) diff --git a/src/hotspot/cpu/aarch64/smallRegisterMap_aarch64.inline.hpp b/src/hotspot/cpu/aarch64/smallRegisterMap_aarch64.inline.hpp index db38b9cf5dfe3..dcba233c9dc75 100644 --- a/src/hotspot/cpu/aarch64/smallRegisterMap_aarch64.inline.hpp +++ b/src/hotspot/cpu/aarch64/smallRegisterMap_aarch64.inline.hpp @@ -30,8 +30,15 @@ // Java frames don't have callee saved registers (except for rfp), so we can use a smaller RegisterMap class SmallRegisterMap { + constexpr SmallRegisterMap() = default; + ~SmallRegisterMap() = default; + NONCOPYABLE(SmallRegisterMap); + public: - static constexpr SmallRegisterMap* instance = nullptr; + static const SmallRegisterMap* instance() { + static constexpr SmallRegisterMap the_instance{}; + return &the_instance; + } private: static void assert_is_rfp(VMReg r) NOT_DEBUG_RETURN DEBUG_ONLY({ assert (r == rfp->as_VMReg() || r == rfp->as_VMReg()->next(), "Reg: %s", r->name()); }) @@ -48,17 +55,6 @@ class SmallRegisterMap { return map; } - SmallRegisterMap() {} - - SmallRegisterMap(const RegisterMap* map) { - #ifdef ASSERT - for(int i = 0; i < RegisterMap::reg_count; i++) { - VMReg r = VMRegImpl::as_VMReg(i); - if (map->location(r, (intptr_t*)nullptr) != nullptr) assert_is_rfp(r); - } - #endif - } - inline address location(VMReg reg, intptr_t* sp) const { assert_is_rfp(reg); return (address)(sp - frame::sender_sp_offset); diff --git a/src/hotspot/cpu/arm/smallRegisterMap_arm.inline.hpp b/src/hotspot/cpu/arm/smallRegisterMap_arm.inline.hpp index 4186eafd35f59..08adbbd89d892 100644 --- a/src/hotspot/cpu/arm/smallRegisterMap_arm.inline.hpp +++ b/src/hotspot/cpu/arm/smallRegisterMap_arm.inline.hpp @@ -30,8 +30,15 @@ // Java frames don't have callee saved registers (except for rfp), so we can use a smaller RegisterMap class SmallRegisterMap { + constexpr SmallRegisterMap() = default; + ~SmallRegisterMap() = default; + NONCOPYABLE(SmallRegisterMap); + public: - static constexpr SmallRegisterMap* instance = nullptr; + static const SmallRegisterMap* instance() { + static constexpr SmallRegisterMap the_instance{}; + return &the_instance; + } private: static void assert_is_rfp(VMReg r) NOT_DEBUG_RETURN DEBUG_ONLY({ Unimplemented(); }) @@ -46,12 +53,6 @@ class SmallRegisterMap { return map; } - SmallRegisterMap() {} - - SmallRegisterMap(const RegisterMap* map) { - Unimplemented(); - } - inline address location(VMReg reg, intptr_t* sp) const { Unimplemented(); return nullptr; diff --git a/src/hotspot/cpu/ppc/smallRegisterMap_ppc.inline.hpp b/src/hotspot/cpu/ppc/smallRegisterMap_ppc.inline.hpp index 8c96f51fd88eb..a6246cd7e74fb 100644 --- a/src/hotspot/cpu/ppc/smallRegisterMap_ppc.inline.hpp +++ b/src/hotspot/cpu/ppc/smallRegisterMap_ppc.inline.hpp @@ -30,9 +30,16 @@ // Java frames don't have callee saved registers, so we can use a smaller RegisterMap class SmallRegisterMap { + constexpr SmallRegisterMap() = default; + ~SmallRegisterMap() = default; + NONCOPYABLE(SmallRegisterMap); + public: - static constexpr SmallRegisterMap* instance = nullptr; -public: + static const SmallRegisterMap* instance() { + static constexpr SmallRegisterMap the_instance{}; + return &the_instance; + } + // as_RegisterMap is used when we didn't want to templatize and abstract over RegisterMap type to support SmallRegisterMap // Consider enhancing SmallRegisterMap to support those cases const RegisterMap* as_RegisterMap() const { return nullptr; } @@ -44,19 +51,6 @@ class SmallRegisterMap { return map; } - SmallRegisterMap() {} - - SmallRegisterMap(const RegisterMap* map) { -#ifdef ASSERT - for(int i = 0; i < RegisterMap::reg_count; i++) { - VMReg r = VMRegImpl::as_VMReg(i); - if (map->location(r, (intptr_t*)nullptr) != nullptr) { - assert(false, "Reg: %s", r->name()); // Should not reach here - } - } -#endif - } - inline address location(VMReg reg, intptr_t* sp) const { assert(false, "Reg: %s", reg->name()); return nullptr; diff --git a/src/hotspot/cpu/riscv/smallRegisterMap_riscv.inline.hpp b/src/hotspot/cpu/riscv/smallRegisterMap_riscv.inline.hpp index 93adaadcef6b9..9fc4f1d7b0a70 100644 --- a/src/hotspot/cpu/riscv/smallRegisterMap_riscv.inline.hpp +++ b/src/hotspot/cpu/riscv/smallRegisterMap_riscv.inline.hpp @@ -30,8 +30,15 @@ // Java frames don't have callee saved registers (except for fp), so we can use a smaller RegisterMap class SmallRegisterMap { + constexpr SmallRegisterMap() = default; + ~SmallRegisterMap() = default; + NONCOPYABLE(SmallRegisterMap); + public: - static constexpr SmallRegisterMap* instance = nullptr; + static const SmallRegisterMap* instance() { + static constexpr SmallRegisterMap the_instance{}; + return &the_instance; + } private: static void assert_is_fp(VMReg r) NOT_DEBUG_RETURN DEBUG_ONLY({ assert (r == fp->as_VMReg() || r == fp->as_VMReg()->next(), "Reg: %s", r->name()); }) @@ -48,17 +55,6 @@ class SmallRegisterMap { return map; } - SmallRegisterMap() {} - - SmallRegisterMap(const RegisterMap* map) { - #ifdef ASSERT - for(int i = 0; i < RegisterMap::reg_count; i++) { - VMReg r = VMRegImpl::as_VMReg(i); - if (map->location(r, (intptr_t*)nullptr) != nullptr) assert_is_fp(r); - } - #endif - } - inline address location(VMReg reg, intptr_t* sp) const { assert_is_fp(reg); return (address)(sp - 2); diff --git a/src/hotspot/cpu/s390/smallRegisterMap_s390.inline.hpp b/src/hotspot/cpu/s390/smallRegisterMap_s390.inline.hpp index 8c74eb7dd6dbf..625d17cf99233 100644 --- a/src/hotspot/cpu/s390/smallRegisterMap_s390.inline.hpp +++ b/src/hotspot/cpu/s390/smallRegisterMap_s390.inline.hpp @@ -30,8 +30,15 @@ // Java frames don't have callee saved registers (except for rfp), so we can use a smaller RegisterMap class SmallRegisterMap { + constexpr SmallRegisterMap() = default; + ~SmallRegisterMap() = default; + NONCOPYABLE(SmallRegisterMap); + public: - static constexpr SmallRegisterMap* instance = nullptr; + static const SmallRegisterMap* instance() { + static constexpr SmallRegisterMap the_instance{}; + return &the_instance; + } private: static void assert_is_rfp(VMReg r) NOT_DEBUG_RETURN DEBUG_ONLY({ Unimplemented(); }) @@ -46,12 +53,6 @@ class SmallRegisterMap { return map; } - SmallRegisterMap() {} - - SmallRegisterMap(const RegisterMap* map) { - Unimplemented(); - } - inline address location(VMReg reg, intptr_t* sp) const { Unimplemented(); return nullptr; diff --git a/src/hotspot/cpu/x86/smallRegisterMap_x86.inline.hpp b/src/hotspot/cpu/x86/smallRegisterMap_x86.inline.hpp index 5f21939a3aa17..63212a686afc0 100644 --- a/src/hotspot/cpu/x86/smallRegisterMap_x86.inline.hpp +++ b/src/hotspot/cpu/x86/smallRegisterMap_x86.inline.hpp @@ -30,8 +30,16 @@ // Java frames don't have callee saved registers (except for rbp), so we can use a smaller RegisterMap class SmallRegisterMap { + constexpr SmallRegisterMap() = default; + ~SmallRegisterMap() = default; + NONCOPYABLE(SmallRegisterMap); + public: - static constexpr SmallRegisterMap* instance = nullptr; + static const SmallRegisterMap* instance() { + static constexpr SmallRegisterMap the_instance{}; + return &the_instance; + } + private: static void assert_is_rbp(VMReg r) NOT_DEBUG_RETURN DEBUG_ONLY({ assert(r == rbp->as_VMReg() || r == rbp->as_VMReg()->next(), "Reg: %s", r->name()); }) @@ -48,17 +56,6 @@ class SmallRegisterMap { return map; } - SmallRegisterMap() {} - - SmallRegisterMap(const RegisterMap* map) { - #ifdef ASSERT - for(int i = 0; i < RegisterMap::reg_count; i++) { - VMReg r = VMRegImpl::as_VMReg(i); - if (map->location(r, (intptr_t*)nullptr) != nullptr) assert_is_rbp(r); - } - #endif - } - inline address location(VMReg reg, intptr_t* sp) const { assert_is_rbp(reg); return (address)(sp - frame::sender_sp_offset); diff --git a/src/hotspot/cpu/zero/smallRegisterMap_zero.inline.hpp b/src/hotspot/cpu/zero/smallRegisterMap_zero.inline.hpp index b85ead32fd22e..51fb114f59585 100644 --- a/src/hotspot/cpu/zero/smallRegisterMap_zero.inline.hpp +++ b/src/hotspot/cpu/zero/smallRegisterMap_zero.inline.hpp @@ -30,8 +30,15 @@ // Java frames don't have callee saved registers (except for rfp), so we can use a smaller RegisterMap class SmallRegisterMap { + constexpr SmallRegisterMap() = default; + ~SmallRegisterMap() = default; + NONCOPYABLE(SmallRegisterMap); + public: - static constexpr SmallRegisterMap* instance = nullptr; + static const SmallRegisterMap* instance() { + static constexpr SmallRegisterMap the_instance{}; + return &the_instance; + } private: static void assert_is_rfp(VMReg r) NOT_DEBUG_RETURN DEBUG_ONLY({ Unimplemented(); }) @@ -46,12 +53,6 @@ class SmallRegisterMap { return map; } - SmallRegisterMap() {} - - SmallRegisterMap(const RegisterMap* map) { - Unimplemented(); - } - inline address location(VMReg reg, intptr_t* sp) const { Unimplemented(); return nullptr; diff --git a/src/hotspot/share/oops/stackChunkOop.cpp b/src/hotspot/share/oops/stackChunkOop.cpp index 8d230b334c88f..344fef1530837 100644 --- a/src/hotspot/share/oops/stackChunkOop.cpp +++ b/src/hotspot/share/oops/stackChunkOop.cpp @@ -125,7 +125,7 @@ static int num_java_frames(const StackChunkFrameStream& f) { int stackChunkOopDesc::num_java_frames() const { int n = 0; for (StackChunkFrameStream f(const_cast(this)); !f.is_done(); - f.next(SmallRegisterMap::instance)) { + f.next(SmallRegisterMap::instance())) { if (!f.is_stub()) { n += ::num_java_frames(f); } diff --git a/src/hotspot/share/oops/stackChunkOop.inline.hpp b/src/hotspot/share/oops/stackChunkOop.inline.hpp index 54f1423fd1cd9..a54b8159e7ef5 100644 --- a/src/hotspot/share/oops/stackChunkOop.inline.hpp +++ b/src/hotspot/share/oops/stackChunkOop.inline.hpp @@ -201,7 +201,7 @@ inline void stackChunkOopDesc::iterate_stack(StackChunkFrameClosureType* closure template inline void stackChunkOopDesc::iterate_stack(StackChunkFrameClosureType* closure) { - const SmallRegisterMap* map = SmallRegisterMap::instance; + const SmallRegisterMap* map = SmallRegisterMap::instance(); assert(!map->in_cont(), ""); StackChunkFrameStream f(this); diff --git a/src/hotspot/share/runtime/continuationFreezeThaw.cpp b/src/hotspot/share/runtime/continuationFreezeThaw.cpp index ea0647fd518e0..0e4640b6a9f4d 100644 --- a/src/hotspot/share/runtime/continuationFreezeThaw.cpp +++ b/src/hotspot/share/runtime/continuationFreezeThaw.cpp @@ -1865,7 +1865,7 @@ int ThawBase::remove_top_compiled_frame_from_chunk(stackChunkOop chunk, int &arg const int frame_size = f.cb()->frame_size(); argsize = f.stack_argsize(); - f.next(SmallRegisterMap::instance, true /* stop */); + f.next(SmallRegisterMap::instance(), true /* stop */); empty = f.is_done(); assert(!empty || argsize == chunk->argsize(), ""); @@ -2075,7 +2075,7 @@ bool ThawBase::recurse_thaw_java_frame(frame& caller, int num_frames) { int argsize = _stream.stack_argsize(); - _stream.next(SmallRegisterMap::instance); + _stream.next(SmallRegisterMap::instance()); assert(_stream.to_frame().is_empty() == _stream.is_done(), ""); // we never leave a compiled caller of an interpreted frame as the top frame in the chunk @@ -2183,7 +2183,7 @@ NOINLINE void ThawBase::recurse_thaw_interpreted_frame(const frame& hf, frame& c assert(hf.is_interpreted_frame(), ""); if (UNLIKELY(seen_by_gc())) { - _cont.tail()->do_barriers(_stream, SmallRegisterMap::instance); + _cont.tail()->do_barriers(_stream, SmallRegisterMap::instance()); } const bool is_bottom_frame = recurse_thaw_java_frame(caller, num_frames); @@ -2226,7 +2226,7 @@ NOINLINE void ThawBase::recurse_thaw_interpreted_frame(const frame& hf, frame& c if (!is_bottom_frame) { // can only fix caller once this frame is thawed (due to callee saved regs) - _cont.tail()->fix_thawed_frame(caller, SmallRegisterMap::instance); + _cont.tail()->fix_thawed_frame(caller, SmallRegisterMap::instance()); } else if (_cont.tail()->has_bitmap() && locals > 0) { assert(hf.is_heap_frame(), "should be"); address start = (address)(heap_frame_bottom - locals); @@ -2243,7 +2243,7 @@ void ThawBase::recurse_thaw_compiled_frame(const frame& hf, frame& caller, int n assert(_cont.is_preempted() || !stub_caller, "stub caller not at preemption"); if (!stub_caller && UNLIKELY(seen_by_gc())) { // recurse_thaw_stub_frame already invoked our barriers with a full regmap - _cont.tail()->do_barriers(_stream, SmallRegisterMap::instance); + _cont.tail()->do_barriers(_stream, SmallRegisterMap::instance()); } const bool is_bottom_frame = recurse_thaw_java_frame(caller, num_frames); @@ -2302,7 +2302,7 @@ void ThawBase::recurse_thaw_compiled_frame(const frame& hf, frame& caller, int n if (!is_bottom_frame) { // can only fix caller once this frame is thawed (due to callee saved regs); this happens on the stack - _cont.tail()->fix_thawed_frame(caller, SmallRegisterMap::instance); + _cont.tail()->fix_thawed_frame(caller, SmallRegisterMap::instance()); } else if (_cont.tail()->has_bitmap() && added_argsize > 0) { address start = (address)(heap_frame_top + ContinuationHelper::CompiledFrame::size(hf) + frame::metadata_words_at_top); int stack_args_slots = f.cb()->as_nmethod()->num_stack_arg_slots(false /* rounded */); @@ -2384,7 +2384,7 @@ void ThawBase::finish_thaw(frame& f) { f.set_sp(align_down(f.sp(), frame::frame_alignment)); } push_return_frame(f); - chunk->fix_thawed_frame(f, SmallRegisterMap::instance); // can only fix caller after push_return_frame (due to callee saved regs) + chunk->fix_thawed_frame(f, SmallRegisterMap::instance()); // can only fix caller after push_return_frame (due to callee saved regs) assert(_cont.is_empty() == _cont.last_frame().is_empty(), ""); From 79bdd811876d75974536aac088bae1719387c97f Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Tue, 30 Jul 2024 13:38:11 +0000 Subject: [PATCH 137/353] 8336763: Parallel: Merge PCMarkAndPushClosure and PCIterateMarkAndPushClosure Reviewed-by: gli, zgu --- .../share/gc/parallel/psCompactionManager.cpp | 15 +++++---- .../share/gc/parallel/psCompactionManager.hpp | 20 +++++++++++- .../parallel/psCompactionManager.inline.hpp | 32 ++++--------------- .../share/gc/parallel/psParallelCompact.cpp | 22 ++++++------- 4 files changed, 44 insertions(+), 45 deletions(-) diff --git a/src/hotspot/share/gc/parallel/psCompactionManager.cpp b/src/hotspot/share/gc/parallel/psCompactionManager.cpp index b95c7c619af7d..d9f2749230e4c 100644 --- a/src/hotspot/share/gc/parallel/psCompactionManager.cpp +++ b/src/hotspot/share/gc/parallel/psCompactionManager.cpp @@ -54,7 +54,9 @@ Monitor* ParCompactionManager::_shadow_region_monitor = nullptr; PreservedMarksSet* ParCompactionManager::_preserved_marks_set = nullptr; -ParCompactionManager::ParCompactionManager(PreservedMarks* preserved_marks) { +ParCompactionManager::ParCompactionManager(PreservedMarks* preserved_marks, + ReferenceProcessor* ref_processor) + : _mark_and_push_closure(this, ref_processor) { ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); @@ -66,8 +68,9 @@ ParCompactionManager::ParCompactionManager(PreservedMarks* preserved_marks) { } void ParCompactionManager::initialize(ParMarkBitMap* mbm) { - assert(ParallelScavengeHeap::heap() != nullptr, - "Needed for initialization"); + assert(ParallelScavengeHeap::heap() != nullptr, "Needed for initialization"); + assert(PSParallelCompact::ref_processor() != nullptr, "precondition"); + assert(ParallelScavengeHeap::heap()->workers().max_workers() != 0, "Not initialized?"); _mark_bitmap = mbm; @@ -85,15 +88,13 @@ void ParCompactionManager::initialize(ParMarkBitMap* mbm) { // Create and register the ParCompactionManager(s) for the worker threads. for(uint i=0; iget(i)); + _manager_array[i] = new ParCompactionManager(_preserved_marks_set->get(i), + PSParallelCompact::ref_processor()); oop_task_queues()->register_queue(i, _manager_array[i]->oop_stack()); _objarray_task_queues->register_queue(i, &_manager_array[i]->_objarray_stack); region_task_queues()->register_queue(i, _manager_array[i]->region_stack()); } - assert(ParallelScavengeHeap::heap()->workers().max_workers() != 0, - "Not initialized?"); - _shadow_region_array = new (mtGC) GrowableArray(10, mtGC); _shadow_region_monitor = new Monitor(Mutex::nosafepoint, "CompactionManager_lock"); diff --git a/src/hotspot/share/gc/parallel/psCompactionManager.hpp b/src/hotspot/share/gc/parallel/psCompactionManager.hpp index 0dd68d2e2f7c7..da1609a32d8eb 100644 --- a/src/hotspot/share/gc/parallel/psCompactionManager.hpp +++ b/src/hotspot/share/gc/parallel/psCompactionManager.hpp @@ -25,6 +25,7 @@ #ifndef SHARE_GC_PARALLEL_PSCOMPACTIONMANAGER_HPP #define SHARE_GC_PARALLEL_PSCOMPACTIONMANAGER_HPP +#include "classfile/classLoaderData.hpp" #include "gc/parallel/psParallelCompact.hpp" #include "gc/shared/preservedMarks.hpp" #include "gc/shared/stringdedup/stringDedup.hpp" @@ -40,6 +41,19 @@ class ObjectStartArray; class ParallelCompactData; class ParMarkBitMap; +class PCMarkAndPushClosure: public ClaimMetadataVisitingOopIterateClosure { + ParCompactionManager* _compaction_manager; + + template void do_oop_work(T* p); +public: + PCMarkAndPushClosure(ParCompactionManager* cm, ReferenceProcessor* rp) : + ClaimMetadataVisitingOopIterateClosure(ClassLoaderData::_claim_stw_fullgc_mark, rp), + _compaction_manager(cm) { } + + virtual void do_oop(oop* p) { do_oop_work(p); } + virtual void do_oop(narrowOop* p) { do_oop_work(p); } +}; + class ParCompactionManager : public CHeapObj { friend class MarkFromRootsTask; friend class ParallelCompactRefProcProxyTask; @@ -47,6 +61,7 @@ class ParCompactionManager : public CHeapObj { friend class ParMarkBitMap; friend class PSParallelCompact; friend class FillDensePrefixAndCompactionTask; + friend class PCAddThreadRootsMarkingTaskClosure; private: typedef OverflowTaskQueue OopTaskQueue; @@ -71,6 +86,7 @@ class ParCompactionManager : public CHeapObj { ObjArrayTaskQueue _objarray_stack; size_t _next_shadow_region; + PCMarkAndPushClosure _mark_and_push_closure; // Is there a way to reuse the _oop_stack for the // saving empty regions? For now just create a different // type of TaskQueue. @@ -104,7 +120,9 @@ class ParCompactionManager : public CHeapObj { // objArray stack, otherwise returns false and the task is invalid. bool publish_or_pop_objarray_tasks(ObjArrayTask& task); - ParCompactionManager(PreservedMarks* preserved_marks); + ParCompactionManager(PreservedMarks* preserved_marks, + ReferenceProcessor* ref_processor); + // Array of task queues. Needed by the task terminator. static RegionTaskQueueSet* region_task_queues() { return _region_task_queues; } OopTaskQueue* oop_stack() { return &_oop_stack; } diff --git a/src/hotspot/share/gc/parallel/psCompactionManager.inline.hpp b/src/hotspot/share/gc/parallel/psCompactionManager.inline.hpp index 22acc11beec3c..0b92862223826 100644 --- a/src/hotspot/share/gc/parallel/psCompactionManager.inline.hpp +++ b/src/hotspot/share/gc/parallel/psCompactionManager.inline.hpp @@ -41,29 +41,10 @@ #include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" -class PCMarkAndPushClosure: public OopClosure { -private: - ParCompactionManager* _compaction_manager; -public: - PCMarkAndPushClosure(ParCompactionManager* cm) : _compaction_manager(cm) { } - - template void do_oop_work(T* p) { _compaction_manager->mark_and_push(p); } - virtual void do_oop(oop* p) { do_oop_work(p); } - virtual void do_oop(narrowOop* p) { do_oop_work(p); } -}; - -class PCIterateMarkAndPushClosure: public ClaimMetadataVisitingOopIterateClosure { -private: - ParCompactionManager* _compaction_manager; -public: - PCIterateMarkAndPushClosure(ParCompactionManager* cm, ReferenceProcessor* rp) : - ClaimMetadataVisitingOopIterateClosure(ClassLoaderData::_claim_stw_fullgc_mark, rp), - _compaction_manager(cm) { } - - template void do_oop_work(T* p) { _compaction_manager->mark_and_push(p); } - virtual void do_oop(oop* p) { do_oop_work(p); } - virtual void do_oop(narrowOop* p) { do_oop_work(p); } -}; +template +inline void PCMarkAndPushClosure::do_oop_work(T* p) { + _compaction_manager->mark_and_push(p); +} inline bool ParCompactionManager::steal(int queue_num, oop& t) { return oop_task_queues()->steal(queue_num, t); @@ -161,13 +142,12 @@ inline void ParCompactionManager::follow_array(objArrayOop obj, int index) { inline void ParCompactionManager::follow_contents(oop obj) { assert(PSParallelCompact::mark_bitmap()->is_marked(obj), "should be marked"); - PCIterateMarkAndPushClosure cl(this, PSParallelCompact::ref_processor()); if (obj->is_objArray()) { - cl.do_klass(obj->klass()); + _mark_and_push_closure.do_klass(obj->klass()); follow_array(objArrayOop(obj), 0); } else { - obj->oop_iterate(&cl); + obj->oop_iterate(&_mark_and_push_closure); } } diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.cpp b/src/hotspot/share/gc/parallel/psParallelCompact.cpp index f41108d1a597f..4d54f11805ac2 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.cpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.cpp @@ -1188,10 +1188,11 @@ class PCAddThreadRootsMarkingTaskClosure : public ThreadClosure { ParCompactionManager* cm = ParCompactionManager::gc_thread_compaction_manager(_worker_id); - PCMarkAndPushClosure mark_and_push_closure(cm); - MarkingNMethodClosure mark_and_push_in_blobs(&mark_and_push_closure, !NMethodToOopClosure::FixRelocations, true /* keepalive nmethods */); + MarkingNMethodClosure mark_and_push_in_blobs(&cm->_mark_and_push_closure, + !NMethodToOopClosure::FixRelocations, + true /* keepalive nmethods */); - thread->oops_do(&mark_and_push_closure, &mark_and_push_in_blobs); + thread->oops_do(&cm->_mark_and_push_closure, &mark_and_push_in_blobs); // Do the real work cm->follow_marking_stacks(); @@ -1232,22 +1233,22 @@ class MarkFromRootsTask : public WorkerTask { virtual void work(uint worker_id) { ParCompactionManager* cm = ParCompactionManager::gc_thread_compaction_manager(worker_id); cm->create_marking_stats_cache(); - PCMarkAndPushClosure mark_and_push_closure(cm); - { - CLDToOopClosure cld_closure(&mark_and_push_closure, ClassLoaderData::_claim_stw_fullgc_mark); + CLDToOopClosure cld_closure(&cm->_mark_and_push_closure, ClassLoaderData::_claim_stw_fullgc_mark); ClassLoaderDataGraph::always_strong_cld_do(&cld_closure); // Do the real work cm->follow_marking_stacks(); } - PCAddThreadRootsMarkingTaskClosure closure(worker_id); - Threads::possibly_parallel_threads_do(true /* is_par */, &closure); + { + PCAddThreadRootsMarkingTaskClosure closure(worker_id); + Threads::possibly_parallel_threads_do(_active_workers > 1 /* is_par */, &closure); + } // Mark from OopStorages { - _oop_storage_set_par_state.oops_do(&mark_and_push_closure); + _oop_storage_set_par_state.oops_do(&cm->_mark_and_push_closure); // Do the real work cm->follow_marking_stacks(); } @@ -1269,10 +1270,9 @@ class ParallelCompactRefProcProxyTask : public RefProcProxyTask { void work(uint worker_id) override { assert(worker_id < _max_workers, "sanity"); ParCompactionManager* cm = (_tm == RefProcThreadModel::Single) ? ParCompactionManager::get_vmthread_cm() : ParCompactionManager::gc_thread_compaction_manager(worker_id); - PCMarkAndPushClosure keep_alive(cm); BarrierEnqueueDiscoveredFieldClosure enqueue; ParCompactionManager::FollowStackClosure complete_gc(cm, (_tm == RefProcThreadModel::Single) ? nullptr : &_terminator, worker_id); - _rp_task->rp_work(worker_id, PSParallelCompact::is_alive_closure(), &keep_alive, &enqueue, &complete_gc); + _rp_task->rp_work(worker_id, PSParallelCompact::is_alive_closure(), &cm->_mark_and_push_closure, &enqueue, &complete_gc); } void prepare_run_task_hook() override { From 41486131481164a559aa534807fe1a77a7d29fc8 Mon Sep 17 00:00:00 2001 From: Erik Gahlin Date: Tue, 30 Jul 2024 13:47:58 +0000 Subject: [PATCH 138/353] 8335907: JFR: Make SettingControls more robust Reviewed-by: mgronlun --- .../jdk/jfr/internal/EventControl.java | 8 +- .../jfr/internal/settings/BooleanSetting.java | 83 +++++ .../jfr/internal/settings/CutoffSetting.java | 32 +- .../jfr/internal/settings/EnabledSetting.java | 28 +- .../jfr/internal/settings/LevelSetting.java | 17 +- .../jfr/internal/settings/PeriodSetting.java | 24 +- .../internal/settings/StackTraceSetting.java | 31 +- .../internal/settings/ThresholdSetting.java | 30 +- .../internal/settings/ThrottleSetting.java | 102 +++--- .../jfr/internal/settings/ThrottleUnit.java | 82 ----- .../BooleanValue.java => util/Rate.java} | 66 ++-- .../jdk/jfr/internal/util/TimespanUnit.java | 53 +++ .../classes/jdk/jfr/internal/util/Utils.java | 8 + .../jdk/jfr/internal/util/ValueFormatter.java | 21 +- .../jdk/jfr/internal/util/ValueParser.java | 11 +- .../jfr/api/settings/TestSettingControl.java | 319 ++++++++++++++++++ 16 files changed, 610 insertions(+), 305 deletions(-) create mode 100644 src/jdk.jfr/share/classes/jdk/jfr/internal/settings/BooleanSetting.java delete mode 100644 src/jdk.jfr/share/classes/jdk/jfr/internal/settings/ThrottleUnit.java rename src/jdk.jfr/share/classes/jdk/jfr/internal/{settings/BooleanValue.java => util/Rate.java} (50%) create mode 100644 src/jdk.jfr/share/classes/jdk/jfr/internal/util/TimespanUnit.java create mode 100644 test/jdk/jdk/jfr/api/settings/TestSettingControl.java diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/EventControl.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/EventControl.java index 71569c30273be..f086bbf884701 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/EventControl.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/EventControl.java @@ -299,7 +299,7 @@ private static Control defineEnabled(PlatformEventType type) { } private static Control defineThreshold(PlatformEventType type) { - String def = type.getAnnotationValue(Threshold.class, "0 ns"); + String def = type.getAnnotationValue(Threshold.class, ThresholdSetting.DEFAULT_VALUE); type.add(PrivateAccess.getInstance().newSettingDescriptor(TYPE_THRESHOLD, Threshold.NAME, def, Collections.emptyList())); return new Control(new ThresholdSetting(type), def); } @@ -311,13 +311,13 @@ private static Control defineStackTrace(PlatformEventType type) { } private static Control defineCutoff(PlatformEventType type) { - String def = type.getAnnotationValue(Cutoff.class, Cutoff.INFINITY); + String def = type.getAnnotationValue(Cutoff.class, CutoffSetting.DEFAULT_VALUE); type.add(PrivateAccess.getInstance().newSettingDescriptor(TYPE_CUTOFF, Cutoff.NAME, def, Collections.emptyList())); return new Control(new CutoffSetting(type), def); } private static Control defineThrottle(PlatformEventType type) { - String def = type.getAnnotationValue(Throttle.class, Throttle.DEFAULT); + String def = type.getAnnotationValue(Throttle.class, ThrottleSetting.DEFAULT_VALUE); type.add(PrivateAccess.getInstance().newSettingDescriptor(TYPE_THROTTLE, Throttle.NAME, def, Collections.emptyList())); return new Control(new ThrottleSetting(type), def); } @@ -330,7 +330,7 @@ private static Control defineLevel(PlatformEventType type) { } private static Control definePeriod(PlatformEventType type) { - String def = type.getAnnotationValue(Period.class, "everyChunk"); + String def = type.getAnnotationValue(Period.class, PeriodSetting.DEFAULT_VALUE); type.add(PrivateAccess.getInstance().newSettingDescriptor(TYPE_PERIOD, PeriodSetting.NAME, def, Collections.emptyList())); return new Control(new PeriodSetting(type), def); } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/BooleanSetting.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/BooleanSetting.java new file mode 100644 index 0000000000000..72ffcac72c926 --- /dev/null +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/BooleanSetting.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jfr.internal.settings; + +import java.util.Objects; +import java.util.Set; + +import jdk.jfr.internal.PlatformEventType; + +abstract class BooleanSetting extends JDKSettingControl { + private final PlatformEventType eventType; + private final String defaultValue; + private String value; + + public BooleanSetting(PlatformEventType eventType, String defaultValue) { + this.eventType = Objects.requireNonNull(eventType); + this.defaultValue = defaultValue; + this.value = defaultValue; + if (parse(defaultValue) == null) { + throw new InternalError("Only 'true' or 'false' is allowed with class BooleanSetting"); + } + } + + protected abstract void apply(PlatformEventType eventType, boolean value); + + @Override + public String combine(Set values) { + if (values.contains("true")) { + return "true"; + } + if (values.contains("false")) { + return "false"; + } + return defaultValue; + } + + @Override + public void setValue(String value) { + Boolean b = parse(value); + if (b != null) { + apply(eventType, b.booleanValue()); + this.value = value; + } + } + + @Override + public String getValue() { + return value; + } + + private static Boolean parse(String value) { + if ("true".equals(value)) { + return Boolean.TRUE; + } + if ("false".equals(value)) { + return Boolean.FALSE; + } + return null; + } +} diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/CutoffSetting.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/CutoffSetting.java index 553336b59e242..68950d71b63d7 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/CutoffSetting.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/CutoffSetting.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,8 @@ package jdk.jfr.internal.settings; +import static jdk.jfr.internal.util.ValueParser.MISSING; + import java.util.Objects; import java.util.Set; @@ -43,8 +45,8 @@ @Name(Type.SETTINGS_PREFIX + "Cutoff") @Timespan public final class CutoffSetting extends JDKSettingControl { - - private String value = "0 ns"; + public static final String DEFAULT_VALUE = ValueParser.INFINITY; + private String value = DEFAULT_VALUE; private final PlatformEventType eventType; public CutoffSetting(PlatformEventType eventType) { @@ -54,22 +56,24 @@ public CutoffSetting(PlatformEventType eventType) { @Override public String combine(Set values) { long max = 0; - String text = "0 ns"; + String text = null; for (String value : values) { - long l = ValueParser.parseTimespanWithInfinity(value); - if (l > max) { + long nanos = ValueParser.parseTimespanWithInfinity(value, MISSING); + if (nanos != MISSING && nanos > max) { text = value; - max = l; + max = nanos; } } - return text; + return Objects.requireNonNullElse(text, DEFAULT_VALUE); } @Override public void setValue(String value) { - long l = ValueParser.parseTimespanWithInfinity(value); - this.value = value; - eventType.setCutoff(l); + long nanos = ValueParser.parseTimespanWithInfinity(value, MISSING); + if (nanos != MISSING) { + eventType.setCutoff(nanos); + this.value = value; + } } @Override @@ -81,10 +85,6 @@ public static long parseValueSafe(String value) { if (value == null) { return 0L; } - try { - return ValueParser.parseTimespanWithInfinity(value); - } catch (NumberFormatException nfe) { - return 0L; - } + return ValueParser.parseTimespanWithInfinity(value, 0L); } } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/EnabledSetting.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/EnabledSetting.java index 77a57a9b75b0d..e81bce484f3ea 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/EnabledSetting.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/EnabledSetting.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,9 +25,6 @@ package jdk.jfr.internal.settings; -import java.util.Objects; -import java.util.Set; - import jdk.jfr.Description; import jdk.jfr.BooleanFlag; import jdk.jfr.Label; @@ -41,33 +38,18 @@ @Description("Record event") @Name(Type.SETTINGS_PREFIX + "Enabled") @BooleanFlag -public final class EnabledSetting extends JDKSettingControl { - private final BooleanValue booleanValue; - private final PlatformEventType eventType; - +public final class EnabledSetting extends BooleanSetting { public EnabledSetting(PlatformEventType eventType, String defaultValue) { - this.booleanValue = BooleanValue.valueOf(defaultValue); - this.eventType = Objects.requireNonNull(eventType); - } - - @Override - public String combine(Set values) { - return booleanValue.union(values); + super(eventType, defaultValue); } @Override - public void setValue(String value) { - booleanValue.setValue(value); - eventType.setEnabled(booleanValue.getBoolean()); + protected void apply(PlatformEventType eventType, boolean value) { + eventType.setEnabled(value); if (eventType.isEnabled() && !eventType.isJVM()) { if (!eventType.isInstrumented()) { eventType.markForInstrumentation(true); } } } - - @Override - public String getValue() { - return booleanValue.getValue(); - } } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/LevelSetting.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/LevelSetting.java index b6aa7500d4b68..9531f75c9257a 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/LevelSetting.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/LevelSetting.java @@ -47,30 +47,29 @@ public final class LevelSetting extends JDKSettingControl { public LevelSetting(PlatformEventType eventType, String[] levels) { this.eventType = Objects.requireNonNull(eventType); this.levels = Arrays.asList(Objects.requireNonNull(levels)); + this.value = levels[0]; } @Override public String combine(Set values) { - int maxIndex = 0; + int maxIndex = 0; // index 0 contains the default value for (String value : values) { - maxIndex = Math.max(maxIndex, indexOf(value)); + maxIndex = Math.max(maxIndex, levels.indexOf(value)); } return levels.get(maxIndex); } @Override public void setValue(String value) { - this.value = value; - this.eventType.setLevel(indexOf(value)); + int index = levels.indexOf(value); + if (index != -1) { + this.eventType.setLevel(index); + this.value = value; + } } @Override public String getValue() { return value; } - - private int indexOf(String value) { - int index = levels.indexOf(value); - return index < 0 ? 0 : index; - } } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/PeriodSetting.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/PeriodSetting.java index 05b5a08a3bb71..22fef2691aa91 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/PeriodSetting.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/PeriodSetting.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,6 +35,7 @@ import jdk.jfr.internal.PlatformEventType; import jdk.jfr.internal.Type; import jdk.jfr.internal.util.ValueParser; +import static jdk.jfr.internal.util.ValueParser.MISSING; @MetadataDefinition @Label("Period") @@ -46,6 +47,7 @@ public final class PeriodSetting extends JDKSettingControl { public static final String EVERY_CHUNK = "everyChunk"; public static final String BEGIN_CHUNK = "beginChunk"; public static final String END_CHUNK = "endChunk"; + public static final String DEFAULT_VALUE = EVERY_CHUNK; public static final String NAME = "period"; private final PlatformEventType eventType; private String value = EVERY_CHUNK; @@ -56,7 +58,6 @@ public PeriodSetting(PlatformEventType eventType) { @Override public String combine(Set values) { - boolean beginChunk = false; boolean endChunk = false; Long min = null; @@ -74,15 +75,11 @@ public String combine(Set values) { endChunk = true; break; default: - long l = ValueParser.parseTimespanWithInfinity(value); - // Always accept first specified value - if (min == null) { - text = value; - min = l; - } else { - if (l < min) { + long nanos = ValueParser.parseTimespanWithInfinity(value, MISSING); + if (nanos != MISSING) { + if (min == null || nanos < min) { text = value; - min = l; + min = nanos; } } } @@ -97,7 +94,7 @@ public String combine(Set values) { if (!beginChunk && endChunk) { return END_CHUNK; } - return EVERY_CHUNK; // also default + return DEFAULT_VALUE; // "everyChunk" is default } @Override @@ -113,7 +110,10 @@ public void setValue(String value) { eventType.setPeriod(0, false, true); break; default: - long nanos = ValueParser.parseTimespanWithInfinity(value); + long nanos = ValueParser.parseTimespanWithInfinity(value, MISSING); + if (nanos == MISSING) { + return; + } if (nanos == 0 || nanos == Long.MAX_VALUE) { eventType.setPeriod(nanos, false, false); } else { diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/StackTraceSetting.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/StackTraceSetting.java index cfd85a0f240ca..45489ebc691c8 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/StackTraceSetting.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/StackTraceSetting.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,11 +25,8 @@ package jdk.jfr.internal.settings; -import java.util.Objects; -import java.util.Set; - -import jdk.jfr.Description; import jdk.jfr.BooleanFlag; +import jdk.jfr.Description; import jdk.jfr.Label; import jdk.jfr.MetadataDefinition; import jdk.jfr.Name; @@ -41,30 +38,16 @@ @Name(Type.SETTINGS_PREFIX + "StackTrace") @Description("Record stack traces") @BooleanFlag -public final class StackTraceSetting extends JDKSettingControl { - private static final long typeId = Type.getTypeId(StackTraceSetting.class); - private final BooleanValue booleanValue; - private final PlatformEventType eventType; +public final class StackTraceSetting extends BooleanSetting { + private static final long typeId = Type.getTypeId(StackTraceSetting.class); public StackTraceSetting(PlatformEventType eventType, String defaultValue) { - this.booleanValue = BooleanValue.valueOf(defaultValue); - this.eventType = Objects.requireNonNull(eventType); - } - - @Override - public String combine(Set values) { - return booleanValue.union(values); - } - - @Override - public void setValue(String value) { - booleanValue.setValue(value); - eventType.setStackTraceEnabled(booleanValue.getBoolean()); + super(eventType, defaultValue); } @Override - public String getValue() { - return booleanValue.getValue(); + protected void apply(PlatformEventType eventType, boolean value) { + eventType.setStackTraceEnabled(value); } public static boolean isType(long typeId) { diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/ThresholdSetting.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/ThresholdSetting.java index 1a7138b11cd93..8870417f9dd35 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/ThresholdSetting.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/ThresholdSetting.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,8 @@ package jdk.jfr.internal.settings; +import static jdk.jfr.internal.util.ValueParser.MISSING; + import java.util.Objects; import java.util.Set; @@ -36,14 +38,16 @@ import jdk.jfr.internal.PlatformEventType; import jdk.jfr.internal.Type; import jdk.jfr.internal.util.ValueParser; + @MetadataDefinition @Label("Threshold") @Name(Type.SETTINGS_PREFIX + "Threshold") @Description("Record event with duration above or equal to threshold") @Timespan public final class ThresholdSetting extends JDKSettingControl { + public static final String DEFAULT_VALUE = "0 ns"; private static final long typeId = Type.getTypeId(ThresholdSetting.class); - private String value = "0 ns"; + private String value = DEFAULT_VALUE; private final PlatformEventType eventType; public ThresholdSetting(PlatformEventType eventType) { @@ -55,26 +59,24 @@ public String combine(Set values) { Long min = null; String text = null; for (String value : values) { - long l = ValueParser.parseTimespanWithInfinity(value); - // always accept first value - if (min == null) { - min = l; - text = value; - } else { - if (l < min) { + long nanos = ValueParser.parseTimespanWithInfinity(value, MISSING); + if (nanos != MISSING) { + if (min == null || nanos < min) { text = value; - min = l; + min = nanos; } } } - return text == null ? "0 ns" : text; + return Objects.requireNonNullElse(text, DEFAULT_VALUE); } @Override public void setValue(String value) { - long l = ValueParser.parseTimespanWithInfinity(value); - this.value = value; - eventType.setThreshold(l); + long nanos = ValueParser.parseTimespanWithInfinity(value, MISSING); + if (nanos != MISSING) { + eventType.setThreshold(nanos); + this.value = value; + } } @Override diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/ThrottleSetting.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/ThrottleSetting.java index 457502963891f..55757050b80fd 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/ThrottleSetting.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/ThrottleSetting.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2020, Datadog, Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -26,6 +26,9 @@ package jdk.jfr.internal.settings; +import static jdk.jfr.internal.util.TimespanUnit.SECONDS; +import static jdk.jfr.internal.util.TimespanUnit.MILLISECONDS; + import java.util.Objects; import java.util.Set; @@ -34,17 +37,20 @@ import jdk.jfr.MetadataDefinition; import jdk.jfr.Name; import jdk.jfr.internal.PlatformEventType; +import jdk.jfr.internal.Throttle; import jdk.jfr.internal.Type; +import jdk.jfr.internal.util.Rate; +import jdk.jfr.internal.util.TimespanUnit; +import jdk.jfr.internal.util.Utils; @MetadataDefinition @Label("Event Emission Throttle") @Description("Throttles the emission rate for an event") @Name(Type.SETTINGS_PREFIX + "Throttle") public final class ThrottleSetting extends JDKSettingControl { - static final String OFF_TEXT = "off"; - private static final long OFF = -2; - private String value = "0/s"; + public static final String DEFAULT_VALUE = Throttle.DEFAULT; private final PlatformEventType eventType; + private String value = DEFAULT_VALUE; public ThrottleSetting(PlatformEventType eventType) { this.eventType = Objects.requireNonNull(eventType); @@ -52,75 +58,51 @@ public ThrottleSetting(PlatformEventType eventType) { @Override public String combine(Set values) { - long max = OFF; - String text = "off"; + Rate max = null; + String text = null; for (String value : values) { - long l = parseValueSafe(value); - if (l > max) { - text = value; - max = l; + Rate rate = Rate.of(value); + if (rate != null) { + if (max == null || rate.isHigher(max)) { + text = value; + max = rate; + } } } - return text; + // "off" is default + return Objects.requireNonNullElse(text, DEFAULT_VALUE); } - private static long parseValueSafe(String s) { - long value = 0L; - try { - value = parseThrottleValue(s); - } catch (NumberFormatException nfe) { + @Override + public void setValue(String value) { + if ("off".equals(value)) { + eventType.setThrottle(-2, 1000); + this.value = value; + return; } - return value; - } - @Override - public void setValue(String s) { - long size = 0; - long millis = 1000; - try { - size = parseThrottleValue(s); - millis = parseThrottleTimeUnit(s); - this.value = s; - } catch (NumberFormatException nfe) { + Rate rate = Rate.of(value); + if (rate != null) { + long millis = 1000; + long samples = rate.amount(); + TimespanUnit unit = rate.unit(); + // if unit is more than 1 s, set millis + if (unit.nanos > SECONDS.nanos) { + millis = unit.nanos / MILLISECONDS.nanos; + } + // if unit is less than 1 s, scale samples + if (unit.nanos < SECONDS.nanos) { + long perSecond = SECONDS.nanos / unit.nanos; + samples *= Utils.multiplyOverflow(samples, perSecond, Long.MAX_VALUE); + } + eventType.setThrottle(samples, millis); + this.value = value; } - eventType.setThrottle(size, millis); } @Override public String getValue() { return value; } - - private static long parseThrottleValue(String s) { - if (s.equals(OFF_TEXT)) { - return OFF; - } - String parsedValue = parseThrottleString(s, true); - long normalizedValue = 0; - try { - normalizedValue = ThrottleUnit.normalizeValueAsMillis(Long.parseLong(parsedValue), s); - } catch (NumberFormatException nfe) { - throwThrottleNumberFormatException(s); - } - return normalizedValue; - } - - private static long parseThrottleTimeUnit(String s) { - return ThrottleUnit.asMillis(s); - } - - // Expected input format is "x/y" where x is a non-negative long - // and y is a time unit. Split the string at the delimiter. - static String parseThrottleString(String s, boolean value) { - String[] split = s.split("/"); - if (split.length != 2) { - throwThrottleNumberFormatException(s); - } - return value ? split[0].trim() : split[1].trim(); - } - - private static void throwThrottleNumberFormatException(String s) { - throw new NumberFormatException("'" + s + "' is not valid. Should be a non-negative numeric value followed by a delimiter. i.e. '/', and then followed by a unit e.g. 100/s."); - } } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/ThrottleUnit.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/ThrottleUnit.java deleted file mode 100644 index ec2fafc7656ae..0000000000000 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/ThrottleUnit.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2020, Datadog, Inc. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package jdk.jfr.internal.settings; - -import java.util.concurrent.TimeUnit; - -enum ThrottleUnit { - NANOSECONDS("ns", TimeUnit.SECONDS.toNanos(1), TimeUnit.SECONDS.toMillis(1)), - MICROSECONDS("us", TimeUnit.SECONDS.toNanos(1) / 1000, TimeUnit.SECONDS.toMillis(1)), - MILLISECONDS("ms", TimeUnit.SECONDS.toMillis(1), TimeUnit.SECONDS.toMillis(1)), - SECONDS("s", 1, TimeUnit.SECONDS.toMillis(1)), - MINUTES("m", 1, TimeUnit.MINUTES.toMillis(1)), - HOUR("h", 1, TimeUnit.HOURS.toMillis(1)), - DAY("d", 1, TimeUnit.DAYS.toMillis(1)); - - private final String text; - private final long factor; - private final long millis; - - ThrottleUnit(String t, long factor, long millis) { - this.text = t; - this.factor = factor; - this.millis = millis; - } - - private static ThrottleUnit parse(String s) { - if (s.equals(ThrottleSetting.OFF_TEXT)) { - return MILLISECONDS; - } - return unit(ThrottleSetting.parseThrottleString(s, false)); - } - - private static ThrottleUnit unit(String s) { - if (s.endsWith("ns") || s.endsWith("us") || s.endsWith("ms")) { - return value(s.substring(s.length() - 2)); - } - if (s.endsWith("s") || s.endsWith("m") || s.endsWith("h") || s.endsWith("d")) { - return value(s.substring(s.length() - 1)); - } - throw new NumberFormatException("'" + s + "' is not a valid time unit."); - } - - private static ThrottleUnit value(String s) { - for (ThrottleUnit t : values()) { - if (t.text.equals(s)) { - return t; - } - } - throw new NumberFormatException("'" + s + "' is not a valid time unit."); - } - - static long asMillis(String s) { - return parse(s).millis; - } - - static long normalizeValueAsMillis(long value, String s) { - return value * parse(s).factor; - } - } \ No newline at end of file diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/BooleanValue.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/util/Rate.java similarity index 50% rename from src/jdk.jfr/share/classes/jdk/jfr/internal/settings/BooleanValue.java rename to src/jdk.jfr/share/classes/jdk/jfr/internal/util/Rate.java index d8f46d76787cd..f32436a5e0feb 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/BooleanValue.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/util/Rate.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,53 +22,37 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ +package jdk.jfr.internal.util; -package jdk.jfr.internal.settings; +public record Rate(long amount, TimespanUnit unit) { -import java.util.Set; - -/** - * Helper class for settings that use boolean numbers - * - */ -final class BooleanValue { - private String value = "false"; - private boolean booleanValue; - - private BooleanValue(boolean b) { - booleanValue = b; - value = b ? "true" : "false"; - } - - public String union(Set values) { - for (String v : values) { - if ("true".equals(v)) { - return "true"; + public static Rate of(String text) { + String[] splitted = text.split("/"); + if (splitted.length != 2) { + return null; + } + String value = splitted[0].strip(); + String unit = splitted[1].strip(); + TimespanUnit tu = TimespanUnit.fromText(unit); + if (unit == null) { + return null; + } + try { + long v = Long.parseLong(value); + if (v >= 0) { + return new Rate(v, tu); } + } catch (NumberFormatException nfe) { + // Ignore } - return "false"; - } - - public void setValue(String value) { - this.value = value; - this.booleanValue = Boolean.valueOf(value); + return null; } - public final String getValue() { - return this.value; + public boolean isHigher(Rate that) { + return this.inNanos() > that.inNanos(); } - public boolean getBoolean() { - return booleanValue; - } - - public static BooleanValue valueOf(String defaultValue) { - if ("true".equals(defaultValue)) { - return new BooleanValue(true); - } - if ("false".equals(defaultValue)) { - return new BooleanValue(false); - } - throw new InternalError("Unknown default value for settings '" + defaultValue + "'"); + private double inNanos() { + return (double) amount / unit.nanos; } } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/util/TimespanUnit.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/util/TimespanUnit.java new file mode 100644 index 0000000000000..9026f59b68b88 --- /dev/null +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/util/TimespanUnit.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jfr.internal.util; + +public enum TimespanUnit { + NANOSECONDS ("ns", 1L, 1000), + MICROSECONDS("us", 1000L, 1000), + MILLISECONDS("ms", 1_000_000L, 1000), + SECONDS ("s", 1_000_000_000L, 60), + MINUTES ("m", 60 * 1_000_000_000L, 60), + HOURS ("h", 60 * 60 * 1_000_000_000L, 24), + DAYS ("d", 24 * 60 * 60 * 1_000_000_000L, 7); + public final String text; + public final long nanos; + public final int size; + TimespanUnit(String text, long nanos, int size) { + this.text = text; + this.nanos = nanos; + this.size = size; + } + + public static TimespanUnit fromText(String text) { + for (TimespanUnit tu : values()) { + // Case-sensitive by design + if (tu.text.equals(text)) { + return tu; + } + } + return null; + } +} diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/util/Utils.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/util/Utils.java index ae83727096a2a..b5ae906c71cb1 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/util/Utils.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/util/Utils.java @@ -430,4 +430,12 @@ public static boolean isJDKClass(Class type) { // but only if it is safe and there is a mechanism to register event // classes in other modules besides jdk.jfr and java.base. } + + public static long multiplyOverflow(long a, long b, long defaultValue) { + try { + return Math.multiplyExact(a, b); + } catch (ArithmeticException ae) { + return defaultValue; + } + } } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/util/ValueFormatter.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/util/ValueFormatter.java index 8fd47dbf5b3c7..53a11101944fa 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/util/ValueFormatter.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/util/ValueFormatter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,23 +40,6 @@ import jdk.jfr.consumer.RecordedMethod; public final class ValueFormatter { - private static enum TimespanUnit { - NANOSECONDS("ns", 1000), - MICROSECONDS("us", 1000), - MILLISECONDS("ms", 1000), - SECONDS("s", 60), MINUTES("m", 60), - HOURS("h", 24), - DAYS("d", 7); - - private final String text; - private final long amount; - - TimespanUnit(String unit, long amount) { - this.text = unit; - this.amount = amount; - } - } - private static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("HH:mm:ss"); private static final Duration MICRO_SECOND = Duration.ofNanos(1_000); private static final Duration SECOND = Duration.ofSeconds(1); @@ -82,7 +65,7 @@ public static String formatTimespan(Duration dValue, String separation) { TimespanUnit result = TimespanUnit.NANOSECONDS; for (TimespanUnit unit : TimespanUnit.values()) { result = unit; - long amount = unit.amount; + long amount = unit.size; if (result == TimespanUnit.DAYS || value < amount || value % amount != 0) { break; } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/util/ValueParser.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/util/ValueParser.java index 730c83daaae67..e4482c9236887 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/util/ValueParser.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/util/ValueParser.java @@ -32,7 +32,16 @@ import static java.util.concurrent.TimeUnit.SECONDS; public final class ValueParser { - private static final String INFINITY = "infinity"; + public static final String INFINITY = "infinity"; + public static final long MISSING = Long.MIN_VALUE; + + public static long parseTimespanWithInfinity(String s, long defaultValue) { + try { + return parseTimespanWithInfinity(s); + } catch (NumberFormatException nfe) { + return defaultValue; + } + } public static long parseTimespanWithInfinity(String s) { if (INFINITY.equals(s)) { diff --git a/test/jdk/jdk/jfr/api/settings/TestSettingControl.java b/test/jdk/jdk/jfr/api/settings/TestSettingControl.java new file mode 100644 index 0000000000000..5543953482d63 --- /dev/null +++ b/test/jdk/jdk/jfr/api/settings/TestSettingControl.java @@ -0,0 +1,319 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jfr.api.settings; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.Instant; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; + +import jdk.jfr.EventType; +import jdk.jfr.FlightRecorder; +import jdk.jfr.Recording; +import jdk.jfr.SettingDescriptor; +import jdk.jfr.consumer.RecordedEvent; +import jdk.jfr.consumer.RecordingFile; + +/** + * @test + * @summary Tests that methods on all SettingControls have expected behavior. + * @key jfr + * @requires vm.hasJFR + * @library /test/lib /test/jdk + * @run main/othervm jdk.jfr.api.settings.TestSettingControl + */ +public class TestSettingControl { + record SettingTest(String setting, String defaultValue, String event, List exampleValues) { + public String eventSettingName() { + return event + "#" + setting; + } + } + + // Example values should be listed in precedence order with the lowest precedence first. + static List SETTING_TESTS = List.of( + new SettingTest("enabled", "false", "jdk.JavaMonitorWait",List.of("false", "true")), + new SettingTest("stackTrace", "true", "jdk.JavaMonitorWait", List.of("false", "true")), + new SettingTest("threshold", "0 ns", "jdk.JavaMonitorWait", List.of("infinity", "10 ms", "0 ns")), + new SettingTest("level", "forRemoval", "jdk.DeprecatedInvocation", List.of("off", "forRemoval")), + new SettingTest("period", "everyChunk", "jdk.ExceptionStatistics", List.of("everyChunk", "60 s", "1 s")), + new SettingTest("cutoff", "infinity", "jdk.OldObjectSample", List.of("0 ms", "1 s", "infinity")), + new SettingTest("throttle", "off", "jdk.ObjectAllocationSample", List.of("off", "100/s", "10/ms")) + ); + + public static void main(String... args) throws Exception { + testTesting(); + testDefault(); + testDefaultWithInvalid(); + testPrecedence(); + testPrecedenceWithInvalid(); + } + + // Ensure that all known SettingControl/types are tested at least once + private static void testTesting() throws Exception { + Set foundSettings = new HashSet<>(); + for (EventType eventType : allEventTypes()) { + for (SettingDescriptor s : eventType.getSettingDescriptors()) { + foundSettings.add(s.getName()); + } + } + for (SettingTest st : SETTING_TESTS) { + foundSettings.remove(st.setting()); + } + if (!foundSettings.isEmpty()) { + throw new Exception("All event SettingControls should be tested. Missing test for " + foundSettings); + } + } + + // Ensure that the default values for all SettingControls are correct + private static void testDefault() throws Exception { + for (SettingTest settingTest : SETTING_TESTS) { + SettingDescriptor s = findSettingDescriptor(settingTest); + if (!settingTest.defaultValue().equals(s.getDefaultValue())) { + String message = "Incorrect default value " + quote(s.getDefaultValue()); + message += " for setting " + settingTest.eventSettingName() + ". "; + message += "Expected " + quote(settingTest.defaultValue()); + throw new Exception(message); + } + } + } + + // Ensure that default settings are used if an invalid setting is specified. + private static void testDefaultWithInvalid() throws Exception { + Map settings = createEnabledMap(); + for (SettingTest settingTest : SETTING_TESTS) { + settings.put(settingTest.eventSettingName(), "%#&2672g"); + } + Map result = check("testDefaultWithInvalid", List.of(settings)); + for (var entry : new ArrayList<>(result.entrySet())) { + String key = entry.getKey(); + String removed = result.remove(key); + if (removed == null) { + throw new Exception("Expected setting " + quote(key) + " to exist"); + } + String setting = key.substring(key.indexOf("#") + 1); + SettingTest st = findSettingTest(setting); + if (st == null) { + throw new Exception("Found unexpected setting " + quote(key)); + } + if (!removed.equals(st.defaultValue())) { + String message = "Expected default value " + quote(st.defaultValue()); + message += " for setting " + quote(setting) + " when"; + message += " an invalid settings value was specified"; + throw new Exception(message); + } + } + if (!result.isEmpty()) { + throw new Exception("Found unexpected setting when testing preserved default"); + } + } + + // Only enabled events will use settings + private static Map createEnabledMap() { + Map settings = new TreeMap<>(); + for (SettingTest settingTest : SETTING_TESTS) { + settings.put(settingTest.event + "#enabled", "true"); + } + return settings; + } + + // Ensure that precedence are respected when multiple settings are specified + private static void testPrecedence() throws Exception { + testPrecedence("testPrecedence"); + } + + // Ensure that precedence are respected when an incorrect setting is used + private static void testPrecedenceWithInvalid() throws Exception { + testPrecedence("testPrecedenceWithInvalid"); + } + + // * * * HELPER METHODS * * * + + private static void testPrecedence(String testName) throws Exception { + List> settingsList = new ArrayList<>(); + int maxExamples = 0; + for (SettingTest t : SETTING_TESTS) { + maxExamples = Math.max(t.exampleValues().size(), maxExamples); + } + for (int i = 0; i < maxExamples; i++) { + Map settings = createEnabledMap(); + for (SettingTest settingTest : SETTING_TESTS) { + List examples = settingTest.exampleValues(); + String name = settingTest.eventSettingName(); + if (i < examples.size()) { + settings.put(name, examples.get(i)); + } + // Insert the invalid setting first + if (testName.contains("Invalid") && i == 0) { + settings.put(name, "%#&2672g"); + } + } + settingsList.add(settings); + } + Map results = check(testName, settingsList); + Map reversed = check(testName + "-reversed", settingsList.reversed()); + if (!reversed.equals(results)) { + throw new Exception("Active settings should not depend on the order event settings are applied"); + } + for (SettingTest t : SETTING_TESTS) { + String expected = t.exampleValues().get(t.exampleValues().size() - 1); + String found = results.get(t.eventSettingName()); + if (!expected.equals(found)) { + throw new Exception("Expected " + expected + " to be used with setting " + quote(t.setting()) + ", not " + quote(found)); + } + } + } + + private static Map check(String testName, List> settingsList) throws Exception { + System.out.println("*** Check for " + testName + " ****"); + System.out.println("Input:"); + int index = 0; + for (var settings : settingsList) { + System.out.println("Setting[" + index + "] = {"); + for (var e : settings.entrySet()) { + System.out.println(" " + e.getKey() + "=" + e.getValue()); + } + System.out.println("}"); + index++; + } + int settingsCount = settingsList.size(); + + // Start a recording for each settings + List recordings = new ArrayList<>(); + for (int i = 0; i < settingsCount; i++) { + Recording r = new Recording(); + Map settings = settingsList.get(i); + settings.put("jdk.ActiveSetting#enabled", "true"); + r.setSettings(settings); + r.start(); + recordings.add(r); + } + + // Stop all recordings + for (Recording r : recordings) { + r.stop(); + } + + // Dump the innermost recording + Path p = Path.of("recording.jfr"); + Recording inner = recordings.get(settingsCount - 1); + inner.dump(p); + + // Close all recordings + for (Recording r : recordings) { + r.close(); + } + System.out.println("Result:"); + Map r = lastSettings(p); + for (var e : r.entrySet()) { + System.out.println(e.getKey() + "=" + e.getValue()); + } + System.out.println("*************"); + System.out.println(); + Files.delete(p); + return r; + } + + private static SettingTest findSettingTest(String name) throws Exception { + for (SettingTest settingTest : SETTING_TESTS) { + if (name.equals(settingTest.setting())) { + return settingTest; + } + } + return null; + } + + private static Map lastSettings(Path p) throws Exception { + List events = RecordingFile.readAllEvents(p); + Instant timestamp = findLastActiveSetting(events); + Map lastInnerMostSettings = new HashMap<>(); + for (SettingTest t : SETTING_TESTS) { + long id = eventTypeNameToId(t.event()); + for (RecordedEvent event : events) { + if (event.getEventType().getName().equals("jdk.ActiveSetting")) { + if (event.getStartTime().equals(timestamp) && id == event.getLong("id")) { + String name = event.getString("name"); + String value = event.getString("value"); + if (t.setting.equals(name)) { + String fullName = t.event() + "#" + name; + String previous = lastInnerMostSettings.put(fullName, value); + if (previous != null) { + throw new Exception("Expected only one ActiveSetting event per event setting"); + } + } + } + } + } + } + return lastInnerMostSettings; + } + + private static Instant findLastActiveSetting(List events) { + Instant lastTimestamp = null; + for (RecordedEvent event : events) { + if (event.getEventType().getName().equals("jdk.ActiveSetting")) { + Instant t = event.getStartTime(); + if (lastTimestamp == null || t.isBefore(lastTimestamp)) { + lastTimestamp = t; + } + } + } + return lastTimestamp; + } + + private static long eventTypeNameToId(String name) throws Exception { + for (EventType eventType : allEventTypes()) { + if (eventType.getName().equals(name)) { + return eventType.getId(); + } + } + throw new Exception("Could not find event type with name " + name); + } + + private static SettingDescriptor findSettingDescriptor(SettingTest settingTest) throws Exception { + for (EventType eventType : allEventTypes()) { + if (eventType.getName().equals(settingTest.event())) { + for (SettingDescriptor s : eventType.getSettingDescriptors()) { + if (settingTest.setting().equals(s.getName())) { + return s; + } + } + } + } + throw new Exception("Could not find setting with name " + settingTest.event() + "#" + settingTest.setting()); + } + + private static List allEventTypes() { + return FlightRecorder.getFlightRecorder().getEventTypes(); + } + + private static String quote(String text) { + return "'" + text + "'"; + } +} From 1cb27f7e2355ccb911bb274fc004e5bc57fd5dc9 Mon Sep 17 00:00:00 2001 From: Neethu Prasad Date: Tue, 30 Jul 2024 14:08:17 +0000 Subject: [PATCH 139/353] 8334230: Optimize C2 classes layout Reviewed-by: shade, kvn, thartmann --- src/hotspot/share/gc/shared/c2/barrierSetC2.hpp | 4 ++-- src/hotspot/share/libadt/vectset.hpp | 2 +- src/hotspot/share/opto/callnode.hpp | 4 ++-- src/hotspot/share/opto/memnode.cpp | 8 ++++---- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/hotspot/share/gc/shared/c2/barrierSetC2.hpp b/src/hotspot/share/gc/shared/c2/barrierSetC2.hpp index d03f416ff689b..c1485c069c83c 100644 --- a/src/hotspot/share/gc/shared/c2/barrierSetC2.hpp +++ b/src/hotspot/share/gc/shared/c2/barrierSetC2.hpp @@ -102,10 +102,10 @@ class C2AccessValuePtr: public C2AccessValue { class C2Access: public StackObj { protected: DecoratorSet _decorators; - BasicType _type; Node* _base; C2AccessValuePtr& _addr; Node* _raw_access; + BasicType _type; uint8_t _barrier_data; void fixup_decorators(); @@ -114,10 +114,10 @@ class C2Access: public StackObj { C2Access(DecoratorSet decorators, BasicType type, Node* base, C2AccessValuePtr& addr) : _decorators(decorators), - _type(type), _base(base), _addr(addr), _raw_access(nullptr), + _type(type), _barrier_data(0) {} diff --git a/src/hotspot/share/libadt/vectset.hpp b/src/hotspot/share/libadt/vectset.hpp index c6ea4490cbf43..eafa60db1fee2 100644 --- a/src/hotspot/share/libadt/vectset.hpp +++ b/src/hotspot/share/libadt/vectset.hpp @@ -42,9 +42,9 @@ class VectorSet : public AnyObj { // Used 32-bit words uint _size; - uint32_t* _data; // Allocated words uint _data_size; + uint32_t* _data; Arena* _set_arena; ReallocMark _nesting; // Safety checks for arena reallocation diff --git a/src/hotspot/share/opto/callnode.hpp b/src/hotspot/share/opto/callnode.hpp index 818640a6f6575..120bb112ec56b 100644 --- a/src/hotspot/share/opto/callnode.hpp +++ b/src/hotspot/share/opto/callnode.hpp @@ -754,18 +754,18 @@ class CallJavaNode : public CallNode { virtual bool cmp( const Node &n ) const; virtual uint size_of() const; // Size is bigger + ciMethod* _method; // Method being direct called bool _optimized_virtual; bool _method_handle_invoke; bool _override_symbolic_info; // Override symbolic call site info from bytecode - ciMethod* _method; // Method being direct called bool _arg_escape; // ArgEscape in parameter list public: CallJavaNode(const TypeFunc* tf , address addr, ciMethod* method) : CallNode(tf, addr, TypePtr::BOTTOM), + _method(method), _optimized_virtual(false), _method_handle_invoke(false), _override_symbolic_info(false), - _method(method), _arg_escape(false) { init_class_id(Class_CallJava); diff --git a/src/hotspot/share/opto/memnode.cpp b/src/hotspot/share/opto/memnode.cpp index 438dc5c1f64e6..c7f0fb9fc3202 100644 --- a/src/hotspot/share/opto/memnode.cpp +++ b/src/hotspot/share/opto/memnode.cpp @@ -2723,13 +2723,13 @@ uint StoreNode::hash() const { // class ArrayPointer { private: - const bool _is_valid; // The parsing succeeded const Node* _pointer; // The final pointer to the position in the array const Node* _base; // Base address of the array const jlong _constant_offset; // Sum of collected constant offsets const Node* _int_offset; // (optional) Offset behind LShiftL and ConvI2L - const jint _int_offset_shift; // (optional) Shift value for int_offset const GrowableArray* _other_offsets; // List of other AddP offsets + const jint _int_offset_shift; // (optional) Shift value for int_offset + const bool _is_valid; // The parsing succeeded ArrayPointer(const bool is_valid, const Node* pointer, @@ -2738,13 +2738,13 @@ class ArrayPointer { const Node* int_offset, const jint int_offset_shift, const GrowableArray* other_offsets) : - _is_valid(is_valid), _pointer(pointer), _base(base), _constant_offset(constant_offset), _int_offset(int_offset), + _other_offsets(other_offsets), _int_offset_shift(int_offset_shift), - _other_offsets(other_offsets) + _is_valid(is_valid) { assert(_pointer != nullptr, "must always have pointer"); assert(is_valid == (_base != nullptr), "have base exactly if valid"); From 2c9fd9016f4675448a62380ff2b86533020e690f Mon Sep 17 00:00:00 2001 From: Vanitha B P Date: Tue, 30 Jul 2024 15:04:57 +0000 Subject: [PATCH 140/353] 8336315: tools/jpackage/windows/WinChildProcessTest.java Failed: Check is calculator process is alive Reviewed-by: asemenyuk, almatvee --- .../jpackage/apps/ChildProcessAppLauncher.java | 17 +++++++++++------ .../jpackage/windows/WinChildProcessTest.java | 17 ++++++++--------- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/test/jdk/tools/jpackage/apps/ChildProcessAppLauncher.java b/test/jdk/tools/jpackage/apps/ChildProcessAppLauncher.java index 11be90bc45622..b599488b563f1 100644 --- a/test/jdk/tools/jpackage/apps/ChildProcessAppLauncher.java +++ b/test/jdk/tools/jpackage/apps/ChildProcessAppLauncher.java @@ -26,12 +26,17 @@ import java.nio.file.Path; public class ChildProcessAppLauncher { - - public static void main(String[] args) throws IOException { - String calcPath = Path.of(System.getenv("SystemRoot"), "system32", "calc.exe").toString(); - ProcessBuilder processBuilder = new ProcessBuilder(calcPath); + public static void main(String[] args) throws IOException, InterruptedException { + if (args.length == 1 && "noexit".equals(args[0])) { + var lock = new Object(); + synchronized (lock) { + lock.wait(); + } + } else { + var childPath = System.getProperty("jpackage.app-path"); // get the path to the current jpackage app launcher + ProcessBuilder processBuilder = new ProcessBuilder(childPath, "noexit"); //ChildProcessAppLauncher acts as third party app Process process = processBuilder.start(); - System.out.println("Calc id=" + process.pid()); - System.exit(0); + System.out.println("Child id=" + process.pid()); + } } } diff --git a/test/jdk/tools/jpackage/windows/WinChildProcessTest.java b/test/jdk/tools/jpackage/windows/WinChildProcessTest.java index 2928f7f1c5ffe..4fa7581d2b5c9 100644 --- a/test/jdk/tools/jpackage/windows/WinChildProcessTest.java +++ b/test/jdk/tools/jpackage/windows/WinChildProcessTest.java @@ -53,7 +53,7 @@ public class WinChildProcessTest { @Test public static void test() throws Throwable { - long calcPid = 0; + long childPid = 0; try { JPackageCommand cmd = JPackageCommand .helloAppImage(TEST_APP_JAVA + "*Hello"); @@ -68,21 +68,20 @@ public static void test() throws Throwable { .execute(0).getOutput(); String pidStr = output.get(0); - // parse calculator PID - calcPid = Long.parseLong(pidStr.split("=", 2)[1]); + // parse child PID + childPid = Long.parseLong(pidStr.split("=", 2)[1]); // Check whether the termination of third party application launcher // also terminating the launched third party application // If third party application is not terminated the test is // successful else failure - Optional processHandle = ProcessHandle.of(calcPid); + Optional processHandle = ProcessHandle.of(childPid); boolean isAlive = processHandle.isPresent() && processHandle.get().isAlive(); - System.out.println("Is Alive " + isAlive); - TKit.assertTrue(isAlive, "Check is calculator process is alive"); + TKit.assertTrue(isAlive, "Check is child process is alive"); } finally { - // Kill only a specific calculator instance - Runtime.getRuntime().exec("taskkill /F /PID " + calcPid); + // Kill only a specific child instance + Runtime.getRuntime().exec("taskkill /F /PID " + childPid); } } -} \ No newline at end of file +} From a91f9ba84906dae10b050e15307ba0f0f05af3e4 Mon Sep 17 00:00:00 2001 From: Gerard Ziemski Date: Tue, 30 Jul 2024 15:22:25 +0000 Subject: [PATCH 141/353] 8301403: Eliminate memory allocations in JVMFlag::printFlags during signal handling Reviewed-by: stuefe, jsjolen, dholmes --- src/hotspot/share/runtime/flags/jvmFlag.cpp | 37 ++++++++++--------- src/hotspot/share/utilities/bitMap.cpp | 5 --- src/hotspot/share/utilities/bitMap.hpp | 18 ++++++--- .../share/utilities/globalDefinitions.hpp | 10 ++--- 4 files changed, 36 insertions(+), 34 deletions(-) diff --git a/src/hotspot/share/runtime/flags/jvmFlag.cpp b/src/hotspot/share/runtime/flags/jvmFlag.cpp index 1917cd4b1980d..c465a942e5c68 100644 --- a/src/hotspot/share/runtime/flags/jvmFlag.cpp +++ b/src/hotspot/share/runtime/flags/jvmFlag.cpp @@ -31,6 +31,7 @@ #include "runtime/flags/jvmFlagAccess.hpp" #include "runtime/flags/jvmFlagLookup.hpp" #include "runtime/globals_extension.hpp" +#include "utilities/bitMap.hpp" #include "utilities/defaultStream.hpp" #include "utilities/stringUtils.hpp" @@ -692,7 +693,7 @@ void JVMFlag::printFlags(outputStream* out, bool withComments, bool printRanges, // called as part of error reporting, so handle native OOMs gracefully. // The last entry is the null entry. - const size_t length = JVMFlag::numFlags - 1; + constexpr size_t length = (sizeof(flagTable) / sizeof(JVMFlag)) - 1; // Print if (!printRanges) { @@ -701,26 +702,26 @@ void JVMFlag::printFlags(outputStream* out, bool withComments, bool printRanges, out->print_cr("[Global flags ranges]"); } - // Sort - JVMFlag** array = NEW_C_HEAP_ARRAY_RETURN_NULL(JVMFlag*, length, mtArguments); - if (array != nullptr) { - for (size_t i = 0; i < length; i++) { - array[i] = &flagTable[i]; - } - qsort(array, length, sizeof(JVMFlag*), compare_flags); - + BitMap::bm_word_t iteratorArray[BitMap::calc_size_in_words(length)]; + BitMapView iteratorMarkers(iteratorArray, length); + iteratorMarkers.clear_range(0, length); + // Print the flag with best sort value, then mark it. + for (size_t j = 0; j < length; j++) { + JVMFlag* bestFlag = nullptr; + size_t bestFlagIndex = 0; for (size_t i = 0; i < length; i++) { - if (array[i]->is_unlocked() && !(skipDefaults && array[i]->is_default())) { - array[i]->print_on(out, withComments, printRanges); + const bool skip = (skipDefaults && flagTable[i].is_default()); + const bool visited = iteratorMarkers.at(i); + if (!visited && flagTable[i].is_unlocked() && !skip) { + if ((bestFlag == nullptr) || (strcmp(bestFlag->name(), flagTable[i].name()) > 0)) { + bestFlag = &flagTable[i]; + bestFlagIndex = i; + } } } - FREE_C_HEAP_ARRAY(JVMFlag*, array); - } else { - // OOM? Print unsorted. - for (size_t i = 0; i < length; i++) { - if (flagTable[i].is_unlocked() && !(skipDefaults && flagTable[i].is_default())) { - flagTable[i].print_on(out, withComments, printRanges); - } + if (bestFlag != nullptr) { + bestFlag->print_on(out, withComments, printRanges); + iteratorMarkers.at_put(bestFlagIndex, true); } } } diff --git a/src/hotspot/share/utilities/bitMap.cpp b/src/hotspot/share/utilities/bitMap.cpp index 9bd5c8e000643..a07807070918f 100644 --- a/src/hotspot/share/utilities/bitMap.cpp +++ b/src/hotspot/share/utilities/bitMap.cpp @@ -197,11 +197,6 @@ bm_word_t* CHeapBitMap::reallocate(bm_word_t* map, size_t old_size_in_words, siz } #ifdef ASSERT -void BitMap::verify_size(idx_t size_in_bits) { - assert(size_in_bits <= max_size_in_bits(), - "out of bounds: " SIZE_FORMAT, size_in_bits); -} - void BitMap::verify_index(idx_t bit) const { assert(bit < _size, "BitMap index out of bounds: " SIZE_FORMAT " >= " SIZE_FORMAT, diff --git a/src/hotspot/share/utilities/bitMap.hpp b/src/hotspot/share/utilities/bitMap.hpp index 0d592de7cd077..5db12badbc95e 100644 --- a/src/hotspot/share/utilities/bitMap.hpp +++ b/src/hotspot/share/utilities/bitMap.hpp @@ -67,16 +67,16 @@ class BitMap { protected: // The maximum allowable size of a bitmap, in words or bits. // Limit max_size_in_bits so aligning up to a word boundary never overflows. - static idx_t max_size_in_words() { return raw_to_words_align_down(~idx_t(0)); } - static idx_t max_size_in_bits() { return max_size_in_words() * BitsPerWord; } + constexpr static idx_t max_size_in_words() { return raw_to_words_align_down(~idx_t(0)); } + constexpr static idx_t max_size_in_bits() { return max_size_in_words() * BitsPerWord; } // Assumes relevant validity checking for bit has already been done. - static idx_t raw_to_words_align_up(idx_t bit) { + constexpr static idx_t raw_to_words_align_up(idx_t bit) { return raw_to_words_align_down(bit + (BitsPerWord - 1)); } // Assumes relevant validity checking for bit has already been done. - static idx_t raw_to_words_align_down(idx_t bit) { + constexpr static idx_t raw_to_words_align_down(idx_t bit) { return bit >> LogBitsPerWord; } @@ -195,7 +195,7 @@ class BitMap { void pretouch(); // Accessing - static idx_t calc_size_in_words(size_t size_in_bits) { + constexpr static idx_t calc_size_in_words(size_t size_in_bits) { verify_size(size_in_bits); return raw_to_words_align_up(size_in_bits); } @@ -257,7 +257,13 @@ class BitMap { // Verification. // Verify size_in_bits does not exceed max_size_in_bits(). - static void verify_size(idx_t size_in_bits) NOT_DEBUG_RETURN; + constexpr static void verify_size(idx_t size_in_bits) { +#ifdef ASSERT + assert(size_in_bits <= max_size_in_bits(), + "out of bounds: " SIZE_FORMAT, size_in_bits); +#endif + } + // Verify bit is less than size(). void verify_index(idx_t bit) const NOT_DEBUG_RETURN; // Verify bit is not greater than size(). diff --git a/src/hotspot/share/utilities/globalDefinitions.hpp b/src/hotspot/share/utilities/globalDefinitions.hpp index 74817a35e7706..b7be6dc04bfa5 100644 --- a/src/hotspot/share/utilities/globalDefinitions.hpp +++ b/src/hotspot/share/utilities/globalDefinitions.hpp @@ -222,9 +222,9 @@ FORBID_C_FUNCTION(void* reallocf(void *ptr, size_t size), "don't use"); const int LogBytesPerShort = 1; const int LogBytesPerInt = 2; #ifdef _LP64 -const int LogBytesPerWord = 3; +constexpr int LogBytesPerWord = 3; #else -const int LogBytesPerWord = 2; +constexpr int LogBytesPerWord = 2; #endif const int LogBytesPerLong = 3; @@ -233,16 +233,16 @@ const int BytesPerInt = 1 << LogBytesPerInt; const int BytesPerWord = 1 << LogBytesPerWord; const int BytesPerLong = 1 << LogBytesPerLong; -const int LogBitsPerByte = 3; +constexpr int LogBitsPerByte = 3; const int LogBitsPerShort = LogBitsPerByte + LogBytesPerShort; const int LogBitsPerInt = LogBitsPerByte + LogBytesPerInt; -const int LogBitsPerWord = LogBitsPerByte + LogBytesPerWord; +constexpr int LogBitsPerWord = LogBitsPerByte + LogBytesPerWord; const int LogBitsPerLong = LogBitsPerByte + LogBytesPerLong; const int BitsPerByte = 1 << LogBitsPerByte; const int BitsPerShort = 1 << LogBitsPerShort; const int BitsPerInt = 1 << LogBitsPerInt; -const int BitsPerWord = 1 << LogBitsPerWord; +constexpr int BitsPerWord = 1 << LogBitsPerWord; const int BitsPerLong = 1 << LogBitsPerLong; const int WordAlignmentMask = (1 << LogBytesPerWord) - 1; From 6154a2129ba505b7163a1998792296827a056750 Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Tue, 30 Jul 2024 17:41:38 +0000 Subject: [PATCH 142/353] 8336032: Enforce immutability of Lists used by ClassFile API Reviewed-by: asotona --- .../classes/java/lang/classfile/AttributedElement.java | 5 +++-- .../classes/java/lang/classfile/ClassSignature.java | 2 +- .../classes/java/lang/classfile/CompoundElement.java | 3 ++- .../internal/classfile/impl/AbstractUnboundModel.java | 5 +++-- .../jdk/internal/classfile/impl/BoundAttribute.java | 4 ++-- .../internal/classfile/impl/BufferedCodeBuilder.java | 2 +- .../internal/classfile/impl/BufferedFieldBuilder.java | 2 +- .../internal/classfile/impl/BufferedMethodBuilder.java | 2 +- .../jdk/internal/classfile/impl/StackMapDecoder.java | 4 ++++ .../jdk/internal/classfile/impl/UnboundAttribute.java | 10 +++++++++- .../internal/classfile/impl/verifier/VerifierImpl.java | 3 ++- 11 files changed, 29 insertions(+), 13 deletions(-) diff --git a/src/java.base/share/classes/java/lang/classfile/AttributedElement.java b/src/java.base/share/classes/java/lang/classfile/AttributedElement.java index 63b2f1e03a939..d66806ca93b43 100644 --- a/src/java.base/share/classes/java/lang/classfile/AttributedElement.java +++ b/src/java.base/share/classes/java/lang/classfile/AttributedElement.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ package java.lang.classfile; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Optional; @@ -83,6 +84,6 @@ default > List findAttributes(AttributeMapper attr) list.add(t); } } - return list; + return Collections.unmodifiableList(list); } } diff --git a/src/java.base/share/classes/java/lang/classfile/ClassSignature.java b/src/java.base/share/classes/java/lang/classfile/ClassSignature.java index 852d5f9baf4f1..5c55950547eb6 100644 --- a/src/java.base/share/classes/java/lang/classfile/ClassSignature.java +++ b/src/java.base/share/classes/java/lang/classfile/ClassSignature.java @@ -76,7 +76,7 @@ public static ClassSignature of(List typeParameters, Signature.ClassTypeSig superclassSignature, Signature.ClassTypeSig... superinterfaceSignatures) { return new SignaturesImpl.ClassSignatureImpl( - requireNonNull(typeParameters), + List.copyOf(requireNonNull(typeParameters)), requireNonNull(superclassSignature), List.of(superinterfaceSignatures)); } diff --git a/src/java.base/share/classes/java/lang/classfile/CompoundElement.java b/src/java.base/share/classes/java/lang/classfile/CompoundElement.java index 12904c9dd596e..9fcf02204cb13 100644 --- a/src/java.base/share/classes/java/lang/classfile/CompoundElement.java +++ b/src/java.base/share/classes/java/lang/classfile/CompoundElement.java @@ -25,6 +25,7 @@ package java.lang.classfile; import java.util.ArrayList; +import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Spliterator; @@ -90,7 +91,7 @@ public void accept(E e) { list.add(e); } }); - return list; + return Collections.unmodifiableList(list); } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractUnboundModel.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractUnboundModel.java index 2926be9dad7dc..9502ff7b246c9 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractUnboundModel.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractUnboundModel.java @@ -24,6 +24,7 @@ */ package jdk.internal.classfile.impl; +import java.util.Collections; import java.util.List; import java.util.function.Consumer; import java.util.stream.Stream; @@ -37,11 +38,11 @@ public abstract sealed class AbstractUnboundModel extends AbstractElement implements CompoundElement, AttributedElement permits BufferedCodeBuilder.Model, BufferedFieldBuilder.Model, BufferedMethodBuilder.Model { - private final List elements; + final List elements; private List> attributes; public AbstractUnboundModel(List elements) { - this.elements = elements; + this.elements = Collections.unmodifiableList(elements); } @Override diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BoundAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BoundAttribute.java index a0428d9d09d37..d5ed0c14bcef4 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BoundAttribute.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BoundAttribute.java @@ -39,6 +39,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Objects; import java.util.Optional; import java.util.function.Function; @@ -134,7 +135,6 @@ public static List> readAttributes(AttributedElement enclosing, Cla var filled = new ArrayList>(size); int p = pos + 2; int cfLen = reader.classfileLength(); - var apo = ((ClassReaderImpl)reader).context().attributesProcessingOption(); for (int i = 0; i < size; ++i) { Utf8Entry name = reader.readEntry(p, Utf8Entry.class); int len = reader.readInt(p + 2); @@ -148,7 +148,7 @@ public static List> readAttributes(AttributedElement enclosing, Cla mapper = customAttributes.apply(name); } if (mapper != null) { - filled.add((Attribute)mapper.readAttribute(enclosing, reader, p)); + filled.add((Attribute) Objects.requireNonNull(mapper.readAttribute(enclosing, reader, p))); } else { AttributeMapper fakeMapper = new AttributeMapper<>() { @Override diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedCodeBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedCodeBuilder.java index 7f041633d8a20..b690f8dbfe70a 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedCodeBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedCodeBuilder.java @@ -148,7 +148,7 @@ public final class Model implements CodeModel { private Model() { - super(elements); + super(BufferedCodeBuilder.this.elements); } @Override diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedFieldBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedFieldBuilder.java index 66ecf10598afb..d9732a0a14d1d 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedFieldBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedFieldBuilder.java @@ -78,7 +78,7 @@ public final class Model extends AbstractUnboundModel implements FieldModel { public Model() { - super(elements); + super(BufferedFieldBuilder.this.elements); } @Override diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedMethodBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedMethodBuilder.java index b93ad1185ab3b..d8c4ba5f95112 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedMethodBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedMethodBuilder.java @@ -156,7 +156,7 @@ public final class Model extends AbstractUnboundModel implements MethodModel, MethodInfo { public Model() { - super(elements); + super(BufferedMethodBuilder.this.elements); } @Override diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapDecoder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapDecoder.java index 2ea8922d3267c..d0bf91171acfe 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapDecoder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapDecoder.java @@ -285,5 +285,9 @@ public static record StackMapFrameImpl(int frameType, List locals, List stack) implements StackMapFrameInfo { + public StackMapFrameImpl { + locals = List.copyOf(locals); + stack = List.copyOf(stack); + } } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/UnboundAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/impl/UnboundAttribute.java index 6d71497f693ed..6b64511fd5a13 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/UnboundAttribute.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/UnboundAttribute.java @@ -92,6 +92,8 @@ import java.lang.classfile.constantpool.PackageEntry; import java.lang.classfile.constantpool.Utf8Entry; +import jdk.internal.access.SharedSecrets; + public abstract sealed class UnboundAttribute> extends AbstractElement implements Attribute, Util.Writable { @@ -627,7 +629,13 @@ public static final class UnboundRuntimeInvisibleParameterAnnotationsAttribute public UnboundRuntimeInvisibleParameterAnnotationsAttribute(List> elements) { super(Attributes.runtimeInvisibleParameterAnnotations()); - this.elements = List.copyOf(elements); + // deep copy + var array = elements.toArray().clone(); + for (int i = 0; i < array.length; i++) { + array[i] = List.copyOf((List) array[i]); + } + + this.elements = SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArray(array); } @Override diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerifierImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerifierImpl.java index 33733c5572a73..74cdb881a744a 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerifierImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerifierImpl.java @@ -26,6 +26,7 @@ import java.nio.ByteBuffer; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.function.Consumer; import java.lang.classfile.ClassHierarchyResolver; @@ -133,7 +134,7 @@ public static List verify(ClassModel classModel, ClassHierarchyReso errors.addAll(inference_verify(klass)); } } - return errors; + return Collections.unmodifiableList(errors); } finally { log_info(logger, "End class verification for: %s", clsName); } From 93c19ac73c2feb8d6191bc5da98b4a9c8e2b5590 Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Tue, 30 Jul 2024 17:41:49 +0000 Subject: [PATCH 143/353] 8337219: AccessFlags factories do not require necessary arguments Reviewed-by: asotona --- .../java/lang/classfile/AccessFlags.java | 50 +---------------- .../java/lang/classfile/ClassBuilder.java | 6 ++- .../java/lang/classfile/FieldBuilder.java | 6 ++- .../java/lang/classfile/MethodBuilder.java | 6 ++- .../classfile/impl/BufferedFieldBuilder.java | 3 +- .../classfile/impl/BufferedMethodBuilder.java | 2 +- .../internal/classfile/impl/ClassImpl.java | 2 +- .../internal/classfile/impl/FieldImpl.java | 3 +- .../internal/classfile/impl/MethodImpl.java | 3 +- .../com/sun/tools/javap/ClassWriter.java | 35 ++++++------ test/jdk/jdk/classfile/AccessFlagsTest.java | 54 ++++++++++++++----- test/jdk/jdk/classfile/BuilderBlockTest.java | 17 +++--- .../jdk/classfile/BuilderTryCatchTest.java | 13 ++--- test/jdk/jdk/classfile/LDCTest.java | 8 +-- test/jdk/jdk/classfile/LowAdaptTest.java | 6 ++- test/jdk/jdk/classfile/LvtTest.java | 12 ++--- test/jdk/jdk/classfile/OneToOneTest.java | 9 ++-- test/jdk/jdk/classfile/SwapTest.java | 11 ++-- test/jdk/jdk/classfile/WriteTest.java | 14 ++--- .../classfile/examples/ExampleGallery.java | 2 +- .../openjdk/bench/jdk/classfile/Write.java | 9 ++-- 21 files changed, 131 insertions(+), 140 deletions(-) diff --git a/src/java.base/share/classes/java/lang/classfile/AccessFlags.java b/src/java.base/share/classes/java/lang/classfile/AccessFlags.java index 283094b81d629..6c6ac75e64896 100644 --- a/src/java.base/share/classes/java/lang/classfile/AccessFlags.java +++ b/src/java.base/share/classes/java/lang/classfile/AccessFlags.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -64,52 +64,4 @@ public sealed interface AccessFlags * method, or field} */ AccessFlag.Location location(); - - /** - * {@return an {@linkplain AccessFlags} for a class} - * @param mask the flags to be set, as a bit mask - */ - static AccessFlags ofClass(int mask) { - return new AccessFlagsImpl(AccessFlag.Location.CLASS, mask); - } - - /** - * {@return an {@linkplain AccessFlags} for a class} - * @param flags the flags to be set - */ - static AccessFlags ofClass(AccessFlag... flags) { - return new AccessFlagsImpl(AccessFlag.Location.CLASS, flags); - } - - /** - * {@return an {@linkplain AccessFlags} for a field} - * @param mask the flags to be set, as a bit mask - */ - static AccessFlags ofField(int mask) { - return new AccessFlagsImpl(AccessFlag.Location.FIELD, mask); - } - - /** - * {@return an {@linkplain AccessFlags} for a field} - * @param flags the flags to be set - */ - static AccessFlags ofField(AccessFlag... flags) { - return new AccessFlagsImpl(AccessFlag.Location.FIELD, flags); - } - - /** - * {@return an {@linkplain AccessFlags} for a method} - * @param mask the flags to be set, as a bit mask - */ - static AccessFlags ofMethod(int mask) { - return new AccessFlagsImpl(AccessFlag.Location.METHOD, mask); - } - - /** - * {@return an {@linkplain AccessFlags} for a method} - * @param flags the flags to be set - */ - static AccessFlags ofMethod(AccessFlag... flags) { - return new AccessFlagsImpl(AccessFlag.Location.METHOD, flags); - } } diff --git a/src/java.base/share/classes/java/lang/classfile/ClassBuilder.java b/src/java.base/share/classes/java/lang/classfile/ClassBuilder.java index a55b93e7c07f4..7ad6e94df3fce 100644 --- a/src/java.base/share/classes/java/lang/classfile/ClassBuilder.java +++ b/src/java.base/share/classes/java/lang/classfile/ClassBuilder.java @@ -34,6 +34,8 @@ import java.lang.classfile.constantpool.ClassEntry; import java.lang.classfile.constantpool.Utf8Entry; + +import jdk.internal.classfile.impl.AccessFlagsImpl; import jdk.internal.classfile.impl.ChainedClassBuilder; import jdk.internal.classfile.impl.DirectClassBuilder; import jdk.internal.classfile.impl.Util; @@ -73,7 +75,7 @@ default ClassBuilder withVersion(int major, int minor) { * @return this builder */ default ClassBuilder withFlags(int flags) { - return with(AccessFlags.ofClass(flags)); + return with(new AccessFlagsImpl(AccessFlag.Location.CLASS, flags)); } /** @@ -82,7 +84,7 @@ default ClassBuilder withFlags(int flags) { * @return this builder */ default ClassBuilder withFlags(AccessFlag... flags) { - return with(AccessFlags.ofClass(flags)); + return with(new AccessFlagsImpl(AccessFlag.Location.CLASS, flags)); } /** diff --git a/src/java.base/share/classes/java/lang/classfile/FieldBuilder.java b/src/java.base/share/classes/java/lang/classfile/FieldBuilder.java index c0e733676f77c..d9a8f6b2fc325 100644 --- a/src/java.base/share/classes/java/lang/classfile/FieldBuilder.java +++ b/src/java.base/share/classes/java/lang/classfile/FieldBuilder.java @@ -26,6 +26,8 @@ package java.lang.classfile; import java.lang.classfile.constantpool.Utf8Entry; + +import jdk.internal.classfile.impl.AccessFlagsImpl; import jdk.internal.classfile.impl.ChainedFieldBuilder; import jdk.internal.classfile.impl.TerminalFieldBuilder; import java.lang.reflect.AccessFlag; @@ -55,7 +57,7 @@ public sealed interface FieldBuilder * @return this builder */ default FieldBuilder withFlags(int flags) { - return with(AccessFlags.ofField(flags)); + return with(new AccessFlagsImpl(AccessFlag.Location.FIELD, flags)); } /** @@ -64,7 +66,7 @@ default FieldBuilder withFlags(int flags) { * @return this builder */ default FieldBuilder withFlags(AccessFlag... flags) { - return with(AccessFlags.ofField(flags)); + return with(new AccessFlagsImpl(AccessFlag.Location.FIELD, flags)); } } diff --git a/src/java.base/share/classes/java/lang/classfile/MethodBuilder.java b/src/java.base/share/classes/java/lang/classfile/MethodBuilder.java index 4cf34c95ed079..7c230760f6934 100644 --- a/src/java.base/share/classes/java/lang/classfile/MethodBuilder.java +++ b/src/java.base/share/classes/java/lang/classfile/MethodBuilder.java @@ -28,6 +28,8 @@ import java.util.function.Consumer; import java.lang.classfile.constantpool.Utf8Entry; + +import jdk.internal.classfile.impl.AccessFlagsImpl; import jdk.internal.classfile.impl.ChainedMethodBuilder; import jdk.internal.classfile.impl.TerminalMethodBuilder; import java.lang.reflect.AccessFlag; @@ -55,7 +57,7 @@ public sealed interface MethodBuilder * @return this builder */ default MethodBuilder withFlags(int flags) { - return with(AccessFlags.ofMethod(flags)); + return with(new AccessFlagsImpl(AccessFlag.Location.METHOD, flags)); } /** @@ -64,7 +66,7 @@ default MethodBuilder withFlags(int flags) { * @return this builder */ default MethodBuilder withFlags(AccessFlag... flags) { - return with(AccessFlags.ofMethod(flags)); + return with(new AccessFlagsImpl(AccessFlag.Location.METHOD, flags)); } /** diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedFieldBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedFieldBuilder.java index d9732a0a14d1d..d165ddd3928fd 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedFieldBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedFieldBuilder.java @@ -24,6 +24,7 @@ */ package jdk.internal.classfile.impl; +import java.lang.reflect.AccessFlag; import java.util.ArrayList; import java.util.List; import java.util.Optional; @@ -50,7 +51,7 @@ public BufferedFieldBuilder(SplitConstantPool constantPool, this.context = context; this.name = name; this.desc = type; - this.flags = AccessFlags.ofField(); + this.flags = new AccessFlagsImpl(AccessFlag.Location.FIELD); } @Override diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedMethodBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedMethodBuilder.java index d8c4ba5f95112..4a9e9b111ce08 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedMethodBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BufferedMethodBuilder.java @@ -66,7 +66,7 @@ public BufferedMethodBuilder(SplitConstantPool constantPool, this.context = context; this.name = nameInfo; this.desc = typeInfo; - this.flags = AccessFlags.ofMethod(flags); + this.flags = new AccessFlagsImpl(AccessFlag.Location.METHOD, flags); this.original = original; } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassImpl.java index eab283a8c6030..c6b9be5c76a99 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassImpl.java @@ -101,7 +101,7 @@ public int classfileLength() { @Override public AccessFlags flags() { - return AccessFlags.ofClass(reader.flags()); + return new AccessFlagsImpl(AccessFlag.Location.CLASS, reader.flags()); } @Override diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/FieldImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/FieldImpl.java index ab42b96084a0f..a71593a57120e 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/FieldImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/FieldImpl.java @@ -24,6 +24,7 @@ */ package jdk.internal.classfile.impl; +import java.lang.reflect.AccessFlag; import java.util.List; import java.util.Optional; import java.util.function.Consumer; @@ -48,7 +49,7 @@ public FieldImpl(ClassReader reader, int startPos, int endPos, int attributesPos @Override public AccessFlags flags() { - return AccessFlags.ofField(reader.readU2(startPos)); + return new AccessFlagsImpl(AccessFlag.Location.FIELD, reader.readU2(startPos)); } @Override diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/MethodImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/MethodImpl.java index 40223d58d6b1c..032b18600a897 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/MethodImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/MethodImpl.java @@ -28,6 +28,7 @@ import java.lang.classfile.*; import java.lang.classfile.constantpool.Utf8Entry; +import java.lang.reflect.AccessFlag; import java.util.List; import java.util.Optional; import java.util.function.Consumer; @@ -51,7 +52,7 @@ public MethodImpl(ClassReader reader, int startPos, int endPos, int attrStart) { @Override public AccessFlags flags() { - return AccessFlags.ofMethod(reader.readU2(startPos)); + return new AccessFlagsImpl(AccessFlag.Location.METHOD, reader.readU2(startPos)); } @Override diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/javap/ClassWriter.java b/src/jdk.jdeps/share/classes/com/sun/tools/javap/ClassWriter.java index 2483e99e49ad9..764f93bd54aeb 100644 --- a/src/jdk.jdeps/share/classes/com/sun/tools/javap/ClassWriter.java +++ b/src/jdk.jdeps/share/classes/com/sun/tools/javap/ClassWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,10 +25,12 @@ package com.sun.tools.javap; +import java.lang.reflect.AccessFlag; import java.net.URI; import java.text.DateFormat; import java.util.Collection; import java.util.Date; +import java.util.EnumSet; import java.util.List; import java.util.Set; @@ -149,7 +151,7 @@ public boolean write(ClassModel cm) { indent(-1); } - writeModifiers(getClassModifiers(cm.flags().flagsMask())); + writeModifiers(getClassModifiers(cm.flags())); if ((classModel.flags().flagsMask() & ACC_MODULE) != 0) { var attr = classModel.findAttribute(Attributes.module()); @@ -210,7 +212,7 @@ public boolean write(ClassModel cm) { println("minor version: " + classModel.minorVersion()); println("major version: " + classModel.majorVersion()); writeList(String.format("flags: (0x%04x) ", cm.flags().flagsMask()), - getClassFlags(cm.flags().flagsMask()), "\n"); + getClassFlags(cm.flags()), "\n"); print("this_class: #");print(() -> classModel.thisClass().index()); tab(); print(() -> "// " + classModel.thisClass().asInternalName()); @@ -416,7 +418,7 @@ protected void writeField(FieldModel f) { if (!options.checkAccess(f.flags().flagsMask())) return; - var flags = AccessFlags.ofField(f.flags().flagsMask()); + var flags = f.flags(); writeModifiers(flagsReportUnknown(flags).stream().filter(fl -> fl.sourceModifier()) .map(fl -> Modifier.toString(fl.mask())).toList()); print(() -> sigPrinter.print( @@ -794,9 +796,16 @@ else switch (c) { } } - private Set getClassModifiers(int mask) { - return getModifiers(flagsReportUnknown(AccessFlags.ofClass((mask & ACC_INTERFACE) != 0 - ? mask & ~ACC_ABSTRACT : mask))); + private Set getClassModifiers(AccessFlags flags) { + var flagSet = flagsReportUnknown(flags); + Set set; + if (flagSet.contains(AccessFlag.INTERFACE)) { + set = EnumSet.copyOf(flagSet); + set.remove(AccessFlag.ABSTRACT); + } else { + set = flagSet; + } + return getModifiers(set); } private static Set getModifiers(Set flags) { @@ -806,16 +815,8 @@ private static Set getModifiers(Set flags) return s; } - private Set getClassFlags(int mask) { - return getFlags(mask, flagsReportUnknown(AccessFlags.ofClass(mask))); - } - - private Set getMethodFlags(int mask) { - return getFlags(mask, flagsReportUnknown(AccessFlags.ofMethod(mask))); - } - - private Set getFieldFlags(int mask) { - return getFlags(mask, flagsReportUnknown(AccessFlags.ofField(mask))); + private Set getClassFlags(AccessFlags flags) { + return getFlags(flags.flagsMask(), flagsReportUnknown(flags)); } private static Set getFlags(int mask, Set flags) { diff --git a/test/jdk/jdk/classfile/AccessFlagsTest.java b/test/jdk/jdk/classfile/AccessFlagsTest.java index 97c0d97f8f9f1..379dcddb9c86c 100644 --- a/test/jdk/jdk/classfile/AccessFlagsTest.java +++ b/test/jdk/jdk/classfile/AccessFlagsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,6 +26,9 @@ * @summary Testing ClassFile AccessFlags. * @run junit AccessFlagsTest */ +import java.lang.classfile.ClassFile; +import java.lang.constant.ClassDesc; +import java.util.Arrays; import java.util.EnumSet; import java.util.Random; import java.util.Set; @@ -34,6 +37,10 @@ import java.util.function.IntFunction; import java.lang.reflect.AccessFlag; import java.lang.classfile.AccessFlags; + +import static java.lang.classfile.ClassFile.ACC_STATIC; +import static java.lang.constant.ConstantDescs.CD_int; +import static java.lang.constant.ConstantDescs.MTD_void; import static org.junit.jupiter.api.Assertions.*; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.provider.EnumSource; @@ -45,15 +52,38 @@ class AccessFlagsTest { @EnumSource(names = { "CLASS", "METHOD", "FIELD" }) void testRandomAccessFlagsConverions(AccessFlag.Location ctx) { IntFunction intFactory = switch (ctx) { - case CLASS -> AccessFlags::ofClass; - case METHOD -> AccessFlags::ofMethod; - case FIELD -> AccessFlags::ofField; + case CLASS -> v -> { + var bytes = ClassFile.of().build(ClassDesc.of("Test"), clb -> clb.withFlags(v)); + return ClassFile.of().parse(bytes).flags(); + }; + case METHOD -> v -> { + var bytes = ClassFile.of().build(ClassDesc.of("Test"), clb -> + clb.withMethod("test", MTD_void, v & ACC_STATIC, mb -> mb.withFlags(v))); + return ClassFile.of().parse(bytes).methods().getFirst().flags(); + }; + case FIELD -> v -> { + var bytes = ClassFile.of().build(ClassDesc.of("Test"), clb -> + clb.withField("test", CD_int, fb -> fb.withFlags(v))); + return ClassFile.of().parse(bytes).fields().getFirst().flags(); + }; default -> null; }; Function flagsFactory = switch (ctx) { - case CLASS -> AccessFlags::ofClass; - case METHOD -> AccessFlags::ofMethod; - case FIELD -> AccessFlags::ofField; + case CLASS -> v -> { + var bytes = ClassFile.of().build(ClassDesc.of("Test"), clb -> clb.withFlags(v)); + return ClassFile.of().parse(bytes).flags(); + }; + case METHOD -> v -> { + boolean hasStatic = Arrays.stream(v).anyMatch(f -> f == AccessFlag.STATIC); + var bytes = ClassFile.of().build(ClassDesc.of("Test"), clb -> + clb.withMethod("test", MTD_void, hasStatic ? ACC_STATIC : 0, mb -> mb.withFlags(v))); + return ClassFile.of().parse(bytes).methods().getFirst().flags(); + }; + case FIELD -> v -> { + var bytes = ClassFile.of().build(ClassDesc.of("Test"), clb -> + clb.withField("test", CD_int, fb -> fb.withFlags(v))); + return ClassFile.of().parse(bytes).fields().getFirst().flags(); + }; default -> null; }; @@ -72,11 +102,11 @@ void testRandomAccessFlagsConverions(AccessFlag.Location ctx) { @Test void testInvalidFlagsUse() { - assertAll( - () -> assertThrowsForInvalidFlagsUse(AccessFlags::ofClass), - () -> assertThrowsForInvalidFlagsUse(AccessFlags::ofField), - () -> assertThrowsForInvalidFlagsUse(AccessFlags::ofMethod) - ); + ClassFile.of().build(ClassDesc.of("Test"), clb -> { + assertThrowsForInvalidFlagsUse(clb::withFlags); + clb.withMethod("test", MTD_void, ACC_STATIC, mb -> assertThrowsForInvalidFlagsUse(mb::withFlags)); + clb.withField("test", CD_int, fb -> assertThrowsForInvalidFlagsUse(fb::withFlags)); + }); } void assertThrowsForInvalidFlagsUse(Consumer factory) { diff --git a/test/jdk/jdk/classfile/BuilderBlockTest.java b/test/jdk/jdk/classfile/BuilderBlockTest.java index a2fb361ca2c7a..30a44491e6cea 100644 --- a/test/jdk/jdk/classfile/BuilderBlockTest.java +++ b/test/jdk/jdk/classfile/BuilderBlockTest.java @@ -28,7 +28,6 @@ * @run junit BuilderBlockTest */ import java.io.IOException; -import java.lang.classfile.AccessFlags; import java.lang.classfile.Attributes; import java.lang.classfile.ClassFile; import java.lang.classfile.ClassTransform; @@ -53,6 +52,8 @@ import jdk.internal.classfile.impl.LabelImpl; import org.junit.jupiter.api.Test; +import static java.lang.classfile.ClassFile.ACC_PUBLIC; +import static java.lang.classfile.ClassFile.ACC_STATIC; import static java.lang.constant.ConstantDescs.CD_int; import static java.lang.constant.ConstantDescs.CD_void; @@ -116,7 +117,7 @@ void testIfThenReturn() throws Exception { byte[] bytes = ClassFile.of().build(ClassDesc.of("Foo"), cb -> { cb.withFlags(AccessFlag.PUBLIC); cb.withMethod("foo", MethodTypeDesc.of(CD_int, CD_int), - AccessFlags.ofMethod(AccessFlag.PUBLIC, AccessFlag.STATIC).flagsMask(), + ACC_PUBLIC | ACC_STATIC, mb -> mb.withCode(xb -> xb.iload(0) .ifThen(xxb -> xxb.iconst_1().ireturn()) .iconst_2() @@ -135,7 +136,7 @@ void testIfThenElseReturn() throws Exception { byte[] bytes = ClassFile.of().build(ClassDesc.of("Foo"), cb -> { cb.withFlags(AccessFlag.PUBLIC); cb.withMethod("foo", MethodTypeDesc.of(CD_int, CD_int), - AccessFlags.ofMethod(AccessFlag.PUBLIC, AccessFlag.STATIC).flagsMask(), + ACC_PUBLIC | ACC_STATIC, mb -> mb.withCode(xb -> xb.iload(0) .ifThenElse(xxb -> xxb.iconst_1().ireturn(), xxb -> xxb.iconst_2().ireturn()))); @@ -153,7 +154,7 @@ void testIfThenBadOpcode() { ClassFile.of().build(ClassDesc.of("Foo"), cb -> { cb.withFlags(AccessFlag.PUBLIC); cb.withMethod("foo", MethodTypeDesc.of(CD_int, CD_int, CD_int), - AccessFlags.ofMethod(AccessFlag.PUBLIC, AccessFlag.STATIC).flagsMask(), + ACC_PUBLIC | ACC_STATIC, mb -> mb.withCode(xb -> { xb.iload(0); xb.iload(1); @@ -173,7 +174,7 @@ void testIfThenElseImplicitBreak() throws Exception { byte[] bytes = ClassFile.of().build(ClassDesc.of("Foo"), cb -> { cb.withFlags(AccessFlag.PUBLIC); cb.withMethod("foo", MethodTypeDesc.of(CD_int, CD_int), - AccessFlags.ofMethod(AccessFlag.PUBLIC, AccessFlag.STATIC).flagsMask(), + ACC_PUBLIC | ACC_STATIC, mb -> mb.withCode(xb -> xb.iload(0) .ifThenElse(xxb -> xxb.iconst_1().istore(2), xxb -> xxb.iconst_2().istore(2)) @@ -193,7 +194,7 @@ void testIfThenElseExplicitBreak() throws Exception { byte[] bytes = ClassFile.of().build(ClassDesc.of("Foo"), cb -> { cb.withFlags(AccessFlag.PUBLIC); cb.withMethod("foo", MethodTypeDesc.of(CD_int, CD_int), - AccessFlags.ofMethod(AccessFlag.PUBLIC, AccessFlag.STATIC).flagsMask(), + ACC_PUBLIC | ACC_STATIC, mb -> mb.withCode(xb -> xb.iload(0) .ifThenElse(xxb -> xxb.iconst_1().istore(2).goto_(xxb.breakLabel()), xxb -> xxb.iconst_2().istore(2).goto_(xxb.breakLabel())) @@ -212,7 +213,7 @@ void testIfThenElseOpcode() throws Exception { byte[] bytes = ClassFile.of().build(ClassDesc.of("Foo"), cb -> { cb.withFlags(AccessFlag.PUBLIC); cb.withMethod("foo", MethodTypeDesc.of(CD_int, CD_int, CD_int), - AccessFlags.ofMethod(AccessFlag.PUBLIC, AccessFlag.STATIC).flagsMask(), + ACC_PUBLIC | ACC_STATIC, mb -> mb.withCode(xb -> xb.iload(0) .iload(1) @@ -237,7 +238,7 @@ void testIfThenElseBadOpcode() { ClassFile.of().build(ClassDesc.of("Foo"), cb -> { cb.withFlags(AccessFlag.PUBLIC); cb.withMethod("foo", MethodTypeDesc.of(CD_int, CD_int, CD_int), - AccessFlags.ofMethod(AccessFlag.PUBLIC, AccessFlag.STATIC).flagsMask(), + ACC_PUBLIC | ACC_STATIC, mb -> mb.withCode(xb -> { xb.iload(0); xb.iload(1); diff --git a/test/jdk/jdk/classfile/BuilderTryCatchTest.java b/test/jdk/jdk/classfile/BuilderTryCatchTest.java index 666b36e11a796..192125c4bb6f2 100644 --- a/test/jdk/jdk/classfile/BuilderTryCatchTest.java +++ b/test/jdk/jdk/classfile/BuilderTryCatchTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,7 +27,6 @@ * @run junit BuilderTryCatchTest */ -import java.lang.classfile.AccessFlags; import java.lang.classfile.ClassFile; import java.lang.classfile.CodeBuilder; import java.lang.classfile.CompoundElement; @@ -35,6 +34,9 @@ import java.lang.classfile.TypeKind; import java.lang.classfile.instruction.BranchInstruction; import java.lang.classfile.instruction.ExceptionCatch; + +import static java.lang.classfile.ClassFile.ACC_PUBLIC; +import static java.lang.classfile.ClassFile.ACC_STATIC; import static org.junit.jupiter.api.Assertions.*; import org.junit.jupiter.api.Test; @@ -43,7 +45,6 @@ import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; -import java.lang.reflect.AccessFlag; import java.nio.file.Files; import java.nio.file.Path; import java.util.List; @@ -184,7 +185,7 @@ void testTryEmptyCatch() { void testEmptyTry() { byte[] bytes = ClassFile.of().build(ClassDesc.of("C"), cb -> { cb.withMethod("main", MethodTypeDesc.of(CD_String, CD_String.arrayType()), - AccessFlags.ofMethod(AccessFlag.PUBLIC, AccessFlag.STATIC).flagsMask(), mb -> { + ACC_PUBLIC | ACC_STATIC, mb -> { mb.withCode(xb -> { int stringSlot = xb.allocateLocal(TypeKind.ReferenceType); xb.loadConstant("S"); @@ -215,7 +216,7 @@ void testEmptyTry() { void testLocalAllocation() throws Throwable { byte[] bytes = ClassFile.of().build(ClassDesc.of("C"), cb -> { cb.withMethod("main", MethodTypeDesc.of(CD_String, CD_String.arrayType()), - AccessFlags.ofMethod(AccessFlag.PUBLIC, AccessFlag.STATIC).flagsMask(), mb -> { + ACC_PUBLIC | ACC_STATIC, mb -> { mb.withCode(xb -> { int stringSlot = xb.allocateLocal(TypeKind.ReferenceType); xb.loadConstant("S"); @@ -278,7 +279,7 @@ void testLocalAllocation() throws Throwable { static byte[] generateTryCatchMethod(Consumer c) { byte[] bytes = ClassFile.of().build(ClassDesc.of("C"), cb -> { cb.withMethod("main", MethodTypeDesc.of(CD_String, CD_String.arrayType()), - AccessFlags.ofMethod(AccessFlag.PUBLIC, AccessFlag.STATIC).flagsMask(), mb -> { + ACC_PUBLIC | ACC_STATIC, mb -> { mb.withCode(xb -> { int stringSlot = xb.allocateLocal(TypeKind.ReferenceType); xb.loadConstant("S"); diff --git a/test/jdk/jdk/classfile/LDCTest.java b/test/jdk/jdk/classfile/LDCTest.java index 1e7639de4bb99..7379218840e30 100644 --- a/test/jdk/jdk/classfile/LDCTest.java +++ b/test/jdk/jdk/classfile/LDCTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,9 @@ * @run junit LDCTest */ import java.lang.constant.ClassDesc; + +import static java.lang.classfile.ClassFile.ACC_PUBLIC; +import static java.lang.classfile.ClassFile.ACC_STATIC; import static java.lang.constant.ConstantDescs.*; import java.lang.constant.MethodTypeDesc; @@ -38,7 +41,6 @@ import org.junit.jupiter.api.Test; import static helpers.TestConstants.MTD_VOID; import static java.lang.classfile.Opcode.*; -import static java.lang.classfile.TypeKind.VoidType; import java.lang.classfile.instruction.ConstantInstruction; class LDCTest { @@ -56,7 +58,7 @@ void testLDCisConvertedToLDCW() throws Exception { ) .withMethod("main", MethodTypeDesc.of(CD_void, CD_String.arrayType()), - AccessFlags.ofMethod(AccessFlag.PUBLIC, AccessFlag.STATIC).flagsMask(), + ACC_PUBLIC | ACC_STATIC, mb -> mb.withCode(c0 -> { ConstantPoolBuilder cpb = cb.constantPool(); for (int i = 0; i <= 256/2 + 2; i++) { // two entries per String diff --git a/test/jdk/jdk/classfile/LowAdaptTest.java b/test/jdk/jdk/classfile/LowAdaptTest.java index 9fa2620913b16..d47141a885a26 100644 --- a/test/jdk/jdk/classfile/LowAdaptTest.java +++ b/test/jdk/jdk/classfile/LowAdaptTest.java @@ -27,6 +27,9 @@ * @run junit LowAdaptTest */ import java.lang.constant.ClassDesc; + +import static java.lang.classfile.ClassFile.ACC_PUBLIC; +import static java.lang.classfile.ClassFile.ACC_STATIC; import static java.lang.constant.ConstantDescs.*; import java.lang.constant.DirectMethodHandleDesc; import java.lang.constant.DynamicCallSiteDesc; @@ -35,7 +38,6 @@ import java.net.URI; import java.nio.file.Paths; -import java.lang.classfile.AccessFlags; import java.lang.reflect.AccessFlag; import java.lang.classfile.ClassModel; import java.lang.classfile.ClassFile; @@ -75,7 +77,7 @@ void testAdapt() throws Exception { cl.methods().forEach(cb::with); cb.withMethod("doit", MethodTypeDesc.of(CD_int, CD_int), - AccessFlags.ofMethod(AccessFlag.PUBLIC, AccessFlag.STATIC).flagsMask(), + ACC_PUBLIC | ACC_STATIC, mb -> mb.withCode(xb -> { xb.invokedynamic(indy); xb.astore(1); diff --git a/test/jdk/jdk/classfile/LvtTest.java b/test/jdk/jdk/classfile/LvtTest.java index 3d7898097980f..d95a4fb7b29ac 100644 --- a/test/jdk/jdk/classfile/LvtTest.java +++ b/test/jdk/jdk/classfile/LvtTest.java @@ -35,13 +35,10 @@ import java.lang.constant.ClassDesc; import java.net.URI; import java.nio.file.Files; -import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; -import java.lang.classfile.AccessFlags; import java.lang.classfile.Attributes; import java.lang.classfile.attribute.SourceFileAttribute; import java.lang.classfile.constantpool.ConstantPoolBuilder; @@ -58,11 +55,10 @@ import static helpers.TestConstants.MTD_VOID; import static helpers.TestUtil.ExpectedLvRecord; import static helpers.TestUtil.ExpectedLvtRecord; +import static java.lang.classfile.ClassFile.ACC_PUBLIC; +import static java.lang.classfile.ClassFile.ACC_STATIC; import static java.lang.constant.ConstantDescs.*; import java.lang.constant.MethodTypeDesc; -import static java.lang.classfile.Opcode.*; -import static java.lang.classfile.Opcode.INVOKEVIRTUAL; -import static java.lang.classfile.TypeKind.VoidType; import static org.junit.jupiter.api.Assertions.*; class LvtTest { @@ -128,7 +124,7 @@ void testCreateLoadLVT() throws Exception { ) ) .withMethod("main", MethodTypeDesc.of(CD_void, CD_String.arrayType()), - AccessFlags.ofMethod(AccessFlag.PUBLIC, AccessFlag.STATIC).flagsMask(), + ACC_PUBLIC | ACC_STATIC, mb -> mb .withCode(c0 -> { ConstantPoolBuilder cpb = cb.constantPool(); @@ -243,7 +239,7 @@ void testCreateLoadLVTT() throws Exception { ) .withMethod("m", MethodTypeDesc.of(CD_Object, CD_Object.arrayType()), - ClassFile.ACC_PUBLIC, + ACC_PUBLIC, mb -> mb.withFlags(AccessFlag.PUBLIC) .withCode(c0 -> { ConstantPoolBuilder cpb = cb.constantPool(); diff --git a/test/jdk/jdk/classfile/OneToOneTest.java b/test/jdk/jdk/classfile/OneToOneTest.java index b20d07025e620..4e21cbebbe331 100644 --- a/test/jdk/jdk/classfile/OneToOneTest.java +++ b/test/jdk/jdk/classfile/OneToOneTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,18 +27,19 @@ * @run junit OneToOneTest */ import java.lang.constant.ClassDesc; + +import static java.lang.classfile.ClassFile.ACC_PUBLIC; +import static java.lang.classfile.ClassFile.ACC_STATIC; import static java.lang.constant.ConstantDescs.*; import java.lang.constant.MethodTypeDesc; import java.util.List; -import java.lang.classfile.AccessFlags; import java.lang.reflect.AccessFlag; import java.lang.classfile.ClassModel; import java.lang.classfile.ClassFile; import java.lang.classfile.Instruction; import java.lang.classfile.Label; import java.lang.classfile.MethodModel; -import java.lang.classfile.TypeKind; import java.lang.classfile.attribute.SourceFileAttribute; import static org.junit.jupiter.api.Assertions.*; import org.junit.jupiter.api.Test; @@ -74,7 +75,7 @@ void testClassWriteRead() { ) ) .withMethod("main", MethodTypeDesc.of(CD_void, CD_String.arrayType()), - AccessFlags.ofMethod(AccessFlag.STATIC, AccessFlag.PUBLIC).flagsMask(), + ACC_PUBLIC | ACC_STATIC, mb -> mb.withCode(c0 -> { Label loopTop = c0.newLabel(); Label loopEnd = c0.newLabel(); diff --git a/test/jdk/jdk/classfile/SwapTest.java b/test/jdk/jdk/classfile/SwapTest.java index 10c0d66d5131c..71ea6189aa61e 100644 --- a/test/jdk/jdk/classfile/SwapTest.java +++ b/test/jdk/jdk/classfile/SwapTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,8 +27,10 @@ * @run junit SwapTest */ -import java.lang.classfile.AccessFlags; import java.lang.classfile.ClassFile; + +import static java.lang.classfile.ClassFile.ACC_PUBLIC; +import static java.lang.classfile.ClassFile.ACC_STATIC; import static org.junit.jupiter.api.Assertions.*; import org.junit.jupiter.api.Test; @@ -38,9 +40,6 @@ import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; -import static java.lang.reflect.AccessFlag.PUBLIC; -import static java.lang.reflect.AccessFlag.STATIC; - class SwapTest { @Test void testTryCatchCatchAll() throws Throwable { @@ -48,7 +47,7 @@ void testTryCatchCatchAll() throws Throwable { MethodTypeDesc mtd = mt.describeConstable().get(); byte[] bytes = ClassFile.of().build(ClassDesc.of("C"), cb -> { - cb.withMethodBody("m", mtd, AccessFlags.ofMethod(PUBLIC, STATIC).flagsMask(), xb -> { + cb.withMethodBody("m", mtd, ACC_PUBLIC | ACC_STATIC, xb -> { xb.aload(0); // 0 xb.aload(1); // 1, 0 xb.swap(); // 0, 1 diff --git a/test/jdk/jdk/classfile/WriteTest.java b/test/jdk/jdk/classfile/WriteTest.java index b4af9135d12bd..72d847c474c4b 100644 --- a/test/jdk/jdk/classfile/WriteTest.java +++ b/test/jdk/jdk/classfile/WriteTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,20 +30,16 @@ import java.lang.constant.MethodTypeDesc; import helpers.TestConstants; -import java.lang.classfile.AccessFlags; import java.lang.reflect.AccessFlag; import java.lang.classfile.ClassFile; -import java.lang.classfile.TypeKind; import java.lang.classfile.Label; import java.lang.classfile.attribute.SourceFileAttribute; import org.junit.jupiter.api.Test; import static helpers.TestConstants.MTD_VOID; +import static java.lang.classfile.ClassFile.ACC_PUBLIC; +import static java.lang.classfile.ClassFile.ACC_STATIC; import static java.lang.constant.ConstantDescs.*; -import static java.lang.classfile.Opcode.*; -import static java.lang.classfile.TypeKind.IntType; -import static java.lang.classfile.TypeKind.ReferenceType; -import static java.lang.classfile.TypeKind.VoidType; class WriteTest { @@ -61,7 +57,7 @@ void testJavapWrite() { ) ) .withMethod("main", MethodTypeDesc.of(CD_void, CD_String.arrayType()), - AccessFlags.ofMethod(AccessFlag.PUBLIC, AccessFlag.STATIC).flagsMask(), + ACC_PUBLIC | ACC_STATIC, mb -> mb.withCode(c0 -> { Label loopTop = c0.newLabel(); Label loopEnd = c0.newLabel(); @@ -102,7 +98,7 @@ void testPrimitiveWrite() { ) ) .withMethod("main", MethodTypeDesc.of(CD_void, CD_String.arrayType()), - AccessFlags.ofMethod(AccessFlag.PUBLIC, AccessFlag.STATIC).flagsMask(), + ACC_PUBLIC | ACC_STATIC, mb -> mb.withCode(c0 -> { Label loopTop = c0.newLabel(); Label loopEnd = c0.newLabel(); diff --git a/test/jdk/jdk/classfile/examples/ExampleGallery.java b/test/jdk/jdk/classfile/examples/ExampleGallery.java index 7de4a78ffbf86..f37f6b1b74da7 100644 --- a/test/jdk/jdk/classfile/examples/ExampleGallery.java +++ b/test/jdk/jdk/classfile/examples/ExampleGallery.java @@ -207,7 +207,7 @@ public byte[] changeFieldSig(ClassModel cm) { public byte[] changeFieldFlags(ClassModel cm) { return ClassFile.of().transformClass(cm, ClassTransform.transformingFields((fb, fe) -> { switch (fe) { - case AccessFlags a -> fb.with(AccessFlags.ofField(a.flagsMask() & ~ClassFile.ACC_PUBLIC & ~ClassFile.ACC_PROTECTED)); + case AccessFlags a -> fb.withFlags(a.flagsMask() & ~ClassFile.ACC_PUBLIC & ~ClassFile.ACC_PROTECTED); default -> fb.with(fe); } })); diff --git a/test/micro/org/openjdk/bench/jdk/classfile/Write.java b/test/micro/org/openjdk/bench/jdk/classfile/Write.java index 59d07b05927b7..e5304f0e51c77 100644 --- a/test/micro/org/openjdk/bench/jdk/classfile/Write.java +++ b/test/micro/org/openjdk/bench/jdk/classfile/Write.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,7 +22,6 @@ */ package org.openjdk.bench.jdk.classfile; -import java.lang.classfile.AccessFlags; import java.lang.reflect.AccessFlag; import java.lang.classfile.ClassFile; import java.lang.classfile.TypeKind; @@ -30,6 +29,8 @@ import jdk.internal.org.objectweb.asm.*; import org.openjdk.jmh.annotations.*; import java.io.FileOutputStream; +import static java.lang.classfile.ClassFile.ACC_PUBLIC; +import static java.lang.classfile.ClassFile.ACC_STATIC; import static java.lang.constant.ConstantDescs.*; import java.nio.file.Files; @@ -148,7 +149,7 @@ public byte[] jdkTree() { ); for (int xi = 0; xi < 40; ++xi) { cb.withMethod("main" + ((xi == 0) ? "" : "" + xi), MTD_void_StringArray, - AccessFlags.ofMethod(AccessFlag.STATIC, AccessFlag.PUBLIC).flagsMask(), + ACC_PUBLIC | ACC_STATIC, mb -> mb.withCode(c0 -> { java.lang.classfile.Label loopTop = c0.newLabel(); java.lang.classfile.Label loopEnd = c0.newLabel(); @@ -196,7 +197,7 @@ public byte[] jdkTreePrimitive() { ); for (int xi = 0; xi < 40; ++xi) { cb.withMethod("main" + ((xi == 0) ? "" : "" + xi), MTD_void_StringArray, - AccessFlags.ofMethod(AccessFlag.STATIC, AccessFlag.PUBLIC).flagsMask(), + ACC_PUBLIC | ACC_STATIC, mb -> mb.withCode(c0 -> { java.lang.classfile.Label loopTop = c0.newLabel(); java.lang.classfile.Label loopEnd = c0.newLabel(); From f5c9e8f1229f3aa00743119a2dee3e15d57048d8 Mon Sep 17 00:00:00 2001 From: Sonia Zaldana Calles Date: Tue, 30 Jul 2024 18:40:37 +0000 Subject: [PATCH 144/353] 8334492: DiagnosticCommands (jcmd) should accept %p in output filenames and substitute PID Reviewed-by: kevinw, stuefe, lmesnik --- src/hotspot/share/code/codeCache.cpp | 14 ++-- src/hotspot/share/code/codeCache.hpp | 4 ++ .../share/prims/wbtestmethods/parserTests.cpp | 10 ++- .../share/services/diagnosticArgument.cpp | 17 +++-- .../share/services/diagnosticArgument.hpp | 3 +- .../share/services/diagnosticCommand.cpp | 32 +++------ .../cds/appcds/jcmd/JCmdTestDumpBase.java | 6 +- .../cds/appcds/jcmd/JCmdTestStaticDump.java | 9 ++- .../jtreg/serviceability/ParserTest.java | 31 ++++++++- .../tools/jcmd/TestJcmdPIDSubstitution.java | 66 +++++++++++++++++++ .../whitebox/parser/DiagnosticCommand.java | 4 +- 11 files changed, 157 insertions(+), 39 deletions(-) create mode 100644 test/jdk/sun/tools/jcmd/TestJcmdPIDSubstitution.java diff --git a/src/hotspot/share/code/codeCache.cpp b/src/hotspot/share/code/codeCache.cpp index ea01dd759587a..a491dd62f070e 100644 --- a/src/hotspot/share/code/codeCache.cpp +++ b/src/hotspot/share/code/codeCache.cpp @@ -1790,15 +1790,17 @@ void CodeCache::log_state(outputStream* st) { #ifdef LINUX void CodeCache::write_perf_map(const char* filename, outputStream* st) { MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); - - // Perf expects to find the map file at /tmp/perf-.map - // if the file name is not specified. - char fname[32]; + char fname[JVM_MAXPATHLEN]; if (filename == nullptr) { - jio_snprintf(fname, sizeof(fname), "/tmp/perf-%d.map", os::current_process_id()); + // Invocation outside of jcmd requires pid substitution. + if (!Arguments::copy_expand_pid(DEFAULT_PERFMAP_FILENAME, + strlen(DEFAULT_PERFMAP_FILENAME), + fname, JVM_MAXPATHLEN)) { + st->print_cr("Warning: Not writing perf map as pid substitution failed."); + return; + } filename = fname; } - fileStream fs(filename, "w"); if (!fs.is_open()) { st->print_cr("Warning: Failed to create %s for perf map", filename); diff --git a/src/hotspot/share/code/codeCache.hpp b/src/hotspot/share/code/codeCache.hpp index 565f600453e69..b724268b65000 100644 --- a/src/hotspot/share/code/codeCache.hpp +++ b/src/hotspot/share/code/codeCache.hpp @@ -80,6 +80,10 @@ class ShenandoahParallelCodeHeapIterator; class NativePostCallNop; class DeoptimizationScope; +#ifdef LINUX +#define DEFAULT_PERFMAP_FILENAME "/tmp/perf-%p.map" +#endif + class CodeCache : AllStatic { friend class VMStructs; friend class JVMCIVMStructs; diff --git a/src/hotspot/share/prims/wbtestmethods/parserTests.cpp b/src/hotspot/share/prims/wbtestmethods/parserTests.cpp index 2845aa9aa104e..efcf2b070d03b 100644 --- a/src/hotspot/share/prims/wbtestmethods/parserTests.cpp +++ b/src/hotspot/share/prims/wbtestmethods/parserTests.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -127,6 +127,14 @@ static void fill_in_parser(DCmdParser* parser, oop argument) } else { parser->add_dcmd_option(argument); } + } else if (strcmp(type, "FILE") == 0) { + DCmdArgument* argument = + new DCmdArgument(name, desc, "FILE", mandatory); + if (isarg) { + parser->add_dcmd_argument(argument); + } else { + parser->add_dcmd_option(argument); + } } } diff --git a/src/hotspot/share/services/diagnosticArgument.cpp b/src/hotspot/share/services/diagnosticArgument.cpp index 94f2d3e1eb124..5fd565a605a44 100644 --- a/src/hotspot/share/services/diagnosticArgument.cpp +++ b/src/hotspot/share/services/diagnosticArgument.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -189,9 +189,18 @@ template <> void DCmdArgument::parse_value(const char* str, destroy_value(); } else { // Use realloc as we may have a default set. - _value = REALLOC_C_HEAP_ARRAY(char, _value, len + 1, mtInternal); - int n = os::snprintf(_value, len + 1, "%.*s", (int)len, str); - assert((size_t)n <= len, "Unexpected number of characters in string"); + if (strcmp(type(), "FILE") == 0) { + _value = REALLOC_C_HEAP_ARRAY(char, _value, JVM_MAXPATHLEN, mtInternal); + if (!Arguments::copy_expand_pid(str, len, _value, JVM_MAXPATHLEN)) { + stringStream error_msg; + error_msg.print("File path invalid or too long: %s", str); + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), error_msg.base()); + } + } else { + _value = REALLOC_C_HEAP_ARRAY(char, _value, len + 1, mtInternal); + int n = os::snprintf(_value, len + 1, "%.*s", (int)len, str); + assert((size_t)n <= len, "Unexpected number of characters in string"); + } } } diff --git a/src/hotspot/share/services/diagnosticArgument.hpp b/src/hotspot/share/services/diagnosticArgument.hpp index c9683ce4a2196..1451ea34f86ca 100644 --- a/src/hotspot/share/services/diagnosticArgument.hpp +++ b/src/hotspot/share/services/diagnosticArgument.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,7 @@ #include "classfile/vmSymbols.hpp" #include "memory/allocation.hpp" +#include "runtime/arguments.hpp" #include "runtime/javaThread.hpp" #include "runtime/os.hpp" #include "utilities/exceptions.hpp" diff --git a/src/hotspot/share/services/diagnosticCommand.cpp b/src/hotspot/share/services/diagnosticCommand.cpp index e6328e95abd9e..7a2c083814614 100644 --- a/src/hotspot/share/services/diagnosticCommand.cpp +++ b/src/hotspot/share/services/diagnosticCommand.cpp @@ -473,7 +473,7 @@ void FinalizerInfoDCmd::execute(DCmdSource source, TRAPS) { #if INCLUDE_SERVICES // Heap dumping/inspection supported HeapDumpDCmd::HeapDumpDCmd(outputStream* output, bool heap) : DCmdWithParser(output, heap), - _filename("filename","Name of the dump file", "STRING",true), + _filename("filename","Name of the dump file", "FILE",true), _all("-all", "Dump all objects, including unreachable objects", "BOOLEAN", false, "false"), _gzip("-gz", "If specified, the heap dump is written in gzipped format " @@ -852,20 +852,15 @@ void CodeCacheDCmd::execute(DCmdSource source, TRAPS) { } #ifdef LINUX -#define DEFAULT_PERFMAP_FILENAME "/tmp/perf-.map" - PerfMapDCmd::PerfMapDCmd(outputStream* output, bool heap) : DCmdWithParser(output, heap), - _filename("filename", "Name of the map file", "STRING", false, DEFAULT_PERFMAP_FILENAME) + _filename("filename", "Name of the map file", "FILE", false, DEFAULT_PERFMAP_FILENAME) { _dcmdparser.add_dcmd_argument(&_filename); } void PerfMapDCmd::execute(DCmdSource source, TRAPS) { - // The check for _filename.is_set() is because we don't want to use - // DEFAULT_PERFMAP_FILENAME, since it is meant as a description - // of the default, not the actual default. - CodeCache::write_perf_map(_filename.is_set() ? _filename.value() : nullptr, output()); + CodeCache::write_perf_map(_filename.value(), output()); } #endif // LINUX @@ -997,12 +992,12 @@ void ClassesDCmd::execute(DCmdSource source, TRAPS) { } #if INCLUDE_CDS -#define DEFAULT_CDS_ARCHIVE_FILENAME "java_pid_.jsa" +#define DEFAULT_CDS_ARCHIVE_FILENAME "java_pid%p_.jsa" DumpSharedArchiveDCmd::DumpSharedArchiveDCmd(outputStream* output, bool heap) : DCmdWithParser(output, heap), _suboption("subcmd", "static_dump | dynamic_dump", "STRING", true), - _filename("filename", "Name of shared archive to be dumped", "STRING", false, + _filename("filename", "Name of shared archive to be dumped", "FILE", false, DEFAULT_CDS_ARCHIVE_FILENAME) { _dcmdparser.add_dcmd_argument(&_suboption); @@ -1040,7 +1035,7 @@ void DumpSharedArchiveDCmd::execute(DCmdSource source, TRAPS) { // call CDS.dumpSharedArchive Handle fileh; if (file != nullptr) { - fileh = java_lang_String::create_from_str(_filename.value(), CHECK); + fileh = java_lang_String::create_from_str(file, CHECK); } Symbol* cds_name = vmSymbols::jdk_internal_misc_CDS(); Klass* cds_klass = SystemDictionary::resolve_or_fail(cds_name, true /*throw error*/, CHECK); @@ -1105,7 +1100,7 @@ ThreadDumpToFileDCmd::ThreadDumpToFileDCmd(outputStream* output, bool heap) : DCmdWithParser(output, heap), _overwrite("-overwrite", "May overwrite existing file", "BOOLEAN", false, "false"), _format("-format", "Output format (\"plain\" or \"json\")", "STRING", false, "plain"), - _filepath("filepath", "The file path to the output file", "STRING", true) { + _filepath("filepath", "The file path to the output file", "FILE", true) { _dcmdparser.add_dcmd_option(&_overwrite); _dcmdparser.add_dcmd_option(&_format); _dcmdparser.add_dcmd_argument(&_filepath); @@ -1186,23 +1181,16 @@ void SystemMapDCmd::execute(DCmdSource source, TRAPS) { MemMapPrinter::print_all_mappings(output()); } -static constexpr char default_filename[] = "vm_memory_map_.txt"; +static constexpr char default_filename[] = "vm_memory_map_%p.txt"; SystemDumpMapDCmd::SystemDumpMapDCmd(outputStream* output, bool heap) : DCmdWithParser(output, heap), - _filename("-F", "file path", "STRING", false, default_filename) { + _filename("-F", "file path", "FILE", false, default_filename) { _dcmdparser.add_dcmd_option(&_filename); } void SystemDumpMapDCmd::execute(DCmdSource source, TRAPS) { - stringStream defaultname; - const char* name = nullptr; - if (_filename.is_set()) { - name = _filename.value(); - } else { - defaultname.print("vm_memory_map_%d.txt", os::current_process_id()); - name = defaultname.base(); - } + const char* name = _filename.value(); fileStream fs(name); if (fs.is_open()) { if (!MemTracker::enabled()) { diff --git a/test/hotspot/jtreg/runtime/cds/appcds/jcmd/JCmdTestDumpBase.java b/test/hotspot/jtreg/runtime/cds/appcds/jcmd/JCmdTestDumpBase.java index ad7b8e97b81a2..eedefaa1ba16f 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/jcmd/JCmdTestDumpBase.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/jcmd/JCmdTestDumpBase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -190,6 +190,10 @@ protected static OutputAnalyzer test(String fileName, long pid, PidJcmdExecutor cmdExecutor = new PidJcmdExecutor(String.valueOf(pid)); OutputAnalyzer output = cmdExecutor.execute(jcmd, true/*silent*/); + if (archiveFileName.contains("%p")) { + archiveFileName = archiveFileName.replace("%p", "%d").formatted(pid); + } + if (expectOK) { output.shouldHaveExitValue(0); checkFileExistence(archiveFileName, true); diff --git a/test/hotspot/jtreg/runtime/cds/appcds/jcmd/JCmdTestStaticDump.java b/test/hotspot/jtreg/runtime/cds/appcds/jcmd/JCmdTestStaticDump.java index a95eaf672c1dc..08ccf9b7f2af5 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/jcmd/JCmdTestStaticDump.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/jcmd/JCmdTestStaticDump.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -87,6 +87,13 @@ static void test() throws Exception { } app.stopApp(); + // Test static dump with file name containing %p + print2ln(test_count++ + " Test static dump with given file name containing %p."); + app = createLingeredApp("-cp", allJars); + pid = app.getPid(); + test("%p.jsa", pid, noBoot, EXPECT_PASS, STATIC_MESSAGES); + app.stopApp(); + // Test static dump with flags with which dumping should fail // This test will result classes.jsa in default server dir if -XX:SharedArchiveFile= not set. print2ln(test_count++ + " Test static dump with flags with which dumping should fail."); diff --git a/test/hotspot/jtreg/serviceability/ParserTest.java b/test/hotspot/jtreg/serviceability/ParserTest.java index 70d666d2ed0ab..7c304af243c2e 100644 --- a/test/hotspot/jtreg/serviceability/ParserTest.java +++ b/test/hotspot/jtreg/serviceability/ParserTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,6 +33,7 @@ import java.math.BigInteger; +import jdk.test.lib.process.ProcessTools; import jdk.test.whitebox.parser.DiagnosticCommand; import jdk.test.whitebox.parser.DiagnosticCommand.DiagnosticArgumentType; import jdk.test.whitebox.WhiteBox; @@ -49,6 +50,7 @@ public ParserTest() throws Exception { testQuotes(); testMemorySize(); testSingleLetterArg(); + testFileName(); } public static void main(String... args) throws Exception { @@ -159,6 +161,33 @@ public void testSingleLetterArg() throws Exception { parse("value", "v", "flag v", ' ', args); } + public void testFileName() throws Exception { + // --- Testing options + long pid = ProcessTools.getProcessId(); + + // Test pid gets injected into %p + String name = "name"; + DiagnosticCommand arg = new DiagnosticCommand(name, + "desc", DiagnosticArgumentType.FILE, + false, null); + DiagnosticCommand[] args = {arg}; + parse(name, "file%d.txt".formatted(pid), name + "=file%p.txt", args); + + // Test custom file name with no %p + parse(name, "myFile.txt", name + "=myFile.txt", args); + + // --- Testing arguments + + // Test pid gets injected into %p + arg = new DiagnosticCommand(name, "desc", DiagnosticArgumentType.FILE, true, + false, null); + args = new DiagnosticCommand[]{arg}; + parse(name, "file%d.txt".formatted(pid), "file%p.txt", args); + + // Test custom file name with no %p + parse(name, "myFile.txt", "myFile.txt", args); + } + public void testMemorySize() throws Exception { String name = "name"; String defaultValue = "1024"; diff --git a/test/jdk/sun/tools/jcmd/TestJcmdPIDSubstitution.java b/test/jdk/sun/tools/jcmd/TestJcmdPIDSubstitution.java new file mode 100644 index 0000000000000..f462ea1a52b0d --- /dev/null +++ b/test/jdk/sun/tools/jcmd/TestJcmdPIDSubstitution.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, Red Hat Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 8334492 + * @summary Test to verify jcmd accepts %p in output filenames and substitutes for PID + * @library /test/lib + * @modules java.base/jdk.internal.misc + * java.management + * @run driver TestJcmdPIDSubstitution + * + */ + +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +public class TestJcmdPIDSubstitution { + + private static final String FILENAME = "myfile%p"; + + public static void main(String[] args) throws Exception { + verifyOutputFilenames("Thread.dump_to_file", FILENAME); + verifyOutputFilenames("GC.heap_dump", FILENAME); + verifyOutputFilenames("Compiler.perfmap", FILENAME); + verifyOutputFilenames("System.dump_map", "-F=%s".formatted(FILENAME)); + } + + private static void verifyOutputFilenames(String... args) throws Exception { + long pid = ProcessTools.getProcessId(); + String test_dir = System.getProperty("test.dir", "."); + Path path = Paths.get("%s/myfile%d".formatted(test_dir, pid)); + OutputAnalyzer output = JcmdBase.jcmd(args); + output.shouldHaveExitValue(0); + if (Files.exists(path)) { + Files.delete(path); + } else { + throw new Exception("File %s was not created as expected for diagnostic cmd %s".formatted(path, args[0])); + } + } +} diff --git a/test/lib/jdk/test/whitebox/parser/DiagnosticCommand.java b/test/lib/jdk/test/whitebox/parser/DiagnosticCommand.java index adb699bac6a41..6b7efa2dc8752 100644 --- a/test/lib/jdk/test/whitebox/parser/DiagnosticCommand.java +++ b/test/lib/jdk/test/whitebox/parser/DiagnosticCommand.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,7 @@ public class DiagnosticCommand { public enum DiagnosticArgumentType { - JLONG, BOOLEAN, STRING, NANOTIME, STRINGARRAY, MEMORYSIZE + JLONG, BOOLEAN, STRING, NANOTIME, STRINGARRAY, MEMORYSIZE, FILE } private String name; From 6c3ba5a6c47d29908ddaf58582ee8d26bb8779f9 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Tue, 30 Jul 2024 21:19:50 +0000 Subject: [PATCH 145/353] 8337415: Remove inappropriate Atomic access in FreeListAllocator Reviewed-by: tschatzl, shade --- src/hotspot/share/gc/shared/freeListAllocator.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/gc/shared/freeListAllocator.cpp b/src/hotspot/share/gc/shared/freeListAllocator.cpp index f33c6fcb14b6e..ef7d12ab0242f 100644 --- a/src/hotspot/share/gc/shared/freeListAllocator.cpp +++ b/src/hotspot/share/gc/shared/freeListAllocator.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -88,7 +88,7 @@ void FreeListAllocator::delete_list(FreeNode* list) { FreeListAllocator::~FreeListAllocator() { uint index = Atomic::load(&_active_pending_list); NodeList pending_list = _pending_lists[index].take_all(); - delete_list(Atomic::load(&pending_list._head)); + delete_list(pending_list._head); delete_list(_free_list.pop_all()); } @@ -106,7 +106,7 @@ size_t FreeListAllocator::free_count() const { size_t FreeListAllocator::pending_count() const { uint index = Atomic::load(&_active_pending_list); - return _pending_lists[index].count();; + return _pending_lists[index].count(); } // To solve the ABA problem, popping a node from the _free_list is performed within From d39e7af2e5d28df43c0b2dad770f41adede5cc29 Mon Sep 17 00:00:00 2001 From: David Holmes Date: Tue, 30 Jul 2024 22:35:14 +0000 Subject: [PATCH 146/353] 8320561: Inconsistency in monitorinflation logging Reviewed-by: stefank, shade --- src/hotspot/share/runtime/synchronizer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/runtime/synchronizer.cpp b/src/hotspot/share/runtime/synchronizer.cpp index 047f6703b545c..2d45163d0f4a2 100644 --- a/src/hotspot/share/runtime/synchronizer.cpp +++ b/src/hotspot/share/runtime/synchronizer.cpp @@ -2074,7 +2074,7 @@ void ObjectSynchronizer::chk_in_use_entry(ObjectMonitor* n, outputStream* out, void ObjectSynchronizer::log_in_use_monitor_details(outputStream* out, bool log_all) { if (_in_use_list.count() > 0) { stringStream ss; - out->print_cr("In-use monitor info:"); + out->print_cr("In-use monitor info%s:", log_all ? "" : " (eliding idle monitors)"); out->print_cr("(B -> is_busy, H -> has hash code, L -> lock status)"); out->print_cr("%18s %s %18s %18s", "monitor", "BHL", "object", "object type"); From 5b7bb40d1f5a8e1261cc252db2a09b5e4f07e5f0 Mon Sep 17 00:00:00 2001 From: David Holmes Date: Tue, 30 Jul 2024 22:35:28 +0000 Subject: [PATCH 147/353] 8325002: Exceptions::fthrow needs to ensure it truncates to a valid utf8 string Reviewed-by: djelinski, stuefe --- src/hotspot/share/utilities/exceptions.cpp | 27 +++++- src/hotspot/share/utilities/utf8.cpp | 63 +++++++++++++ src/hotspot/share/utilities/utf8.hpp | 3 +- test/hotspot/gtest/utilities/test_utf8.cpp | 104 ++++++++++++++++++++- 4 files changed, 194 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/utilities/exceptions.cpp b/src/hotspot/share/utilities/exceptions.cpp index c8f458dfa31ad..034444839ab50 100644 --- a/src/hotspot/share/utilities/exceptions.cpp +++ b/src/hotspot/share/utilities/exceptions.cpp @@ -43,6 +43,7 @@ #include "runtime/atomic.hpp" #include "utilities/events.hpp" #include "utilities/exceptions.hpp" +#include "utilities/utf8.hpp" // Limit exception message components to 64K (the same max as Symbols) #define MAX_LEN 65535 @@ -262,8 +263,32 @@ void Exceptions::fthrow(JavaThread* thread, const char* file, int line, Symbol* va_list ap; va_start(ap, format); char msg[max_msg_size]; - os::vsnprintf(msg, max_msg_size, format, ap); + int ret = os::vsnprintf(msg, max_msg_size, format, ap); va_end(ap); + + // If ret == -1 then either there was a format conversion error, or the required buffer size + // exceeds INT_MAX and so couldn't be returned (undocumented behaviour of vsnprintf). Depending + // on the platform the buffer may be filled to its capacity (Linux), filled to the conversion + // that encountered the overflow (macOS), or is empty (Windows), so it is possible we + // have a truncated UTF-8 sequence. Similarly, if the buffer was too small and ret >= max_msg_size + // we may also have a truncated UTF-8 sequence. In such cases we need to fix the buffer so the UTF-8 + // sequence is valid. + if (ret == -1 || ret >= max_msg_size) { + int len = (int) strlen(msg); + if (len > 0) { + // Truncation will only happen if the buffer was filled by vsnprintf, + // otherwise vsnprintf already terminated filling it at a well-defined point. + // But as this is not a clearly specified area we will perform our own UTF8 + // truncation anyway - though for those well-defined termination points it + // will be a no-op. + UTF8::truncate_to_legal_utf8((unsigned char*)msg, len + 1); + } + } + // UTF8::is_legal_utf8 should actually be called is_legal_utf8_class_name as the final + // parameter controls a check for a specific character appearing in the "name", which is only + // allowed for classfile versions <= 47. We pass `true` so that we allow such strings as this code + // know nothing about the actual string content. + assert(UTF8::is_legal_utf8((const unsigned char*)msg, (int)strlen(msg), true), "must be"); _throw_msg(thread, file, line, h_name, msg); } diff --git a/src/hotspot/share/utilities/utf8.cpp b/src/hotspot/share/utilities/utf8.cpp index 6fd877120df40..47cbb04da4b2c 100644 --- a/src/hotspot/share/utilities/utf8.cpp +++ b/src/hotspot/share/utilities/utf8.cpp @@ -392,6 +392,69 @@ bool UTF8::is_legal_utf8(const unsigned char* buffer, int length, return true; } +// Return true if `b` could be the starting byte of an encoded 2,3 or 6 +// byte sequence. +static bool is_starting_byte(unsigned char b) { + return b >= 0xC0 && b <= 0xEF; +} + +// Takes an incoming buffer that was valid UTF-8, but which has been truncated such that +// the last encoding may be partial, and returns the same buffer with a NUL-terminator +// inserted such that any partial encoding has gone. +// Note: if the incoming buffer is already valid then we may still drop the last encoding. +// To avoid that the caller can choose to check for validity first. +// The incoming buffer is still expected to be NUL-terminated. +// The incoming buffer is expected to be a realistic size - we assert if it is too small. +void UTF8::truncate_to_legal_utf8(unsigned char* buffer, int length) { + assert(length > 5, "invalid length"); + assert(buffer[length - 1] == '\0', "Buffer should be NUL-terminated"); + + if (buffer[length - 2] < 128) { // valid "ascii" - common case + return; + } + + // Modified UTF-8 encodes characters in sequences of 1, 2, 3 or 6 bytes. + // The last byte is invalid if it is: + // - the 1st byte of a 2, 3 or 6 byte sequence + // 0b110xxxxx + // 0b1110xxxx + // 0b11101101 + // - the 2nd byte of a 3 or 6 byte sequence + // 0b10xxxxxx + // 0b1010xxxx + // - the 3rd, 4th or 5th byte of a 6 byte sequence + // 0b10xxxxxx + // 0b11101101 + // 0b1011xxxx + // + // Rather than checking all possible situations we simplify things noting that as we have already + // got a truncated string, then dropping one more character is not significant. So we work from the + // end of the buffer looking for the first byte that can be the starting byte of a UTF-8 encoded sequence, + // then we insert NUL at that location to terminate the buffer. There is an added complexity with 6 byte + // encodings as the first and fourth bytes are the same and overlap with the 3 byte encoding. + + for (int index = length - 2; index > 0; index--) { + if (is_starting_byte(buffer[index])) { + if (buffer[index] == 0xED) { + // Could be first byte of 3 or 6, or fourth byte of 6. + // If fourth the previous three bytes will encode a high + // surrogate value in the range EDA080 to EDAFBF. We only + // need to check for EDA to establish this as the "missing" + // values in EDAxxx would not be valid 3 byte encodings. + if ((index - 3) >= 0 && + (buffer[index - 3] == 0xED) && + ((buffer[index - 2] & 0xF0) == 0xA0)) { + assert(buffer[index - 1] >= 0x80 && buffer[index - 1] <= 0xBF, "sanity check"); + // It was fourth byte so truncate 3 bytes earlier + index -= 3; + } + } + buffer[index] = '\0'; + break; + } + } +} + //------------------------------------------------------------------------------------- bool UNICODE::is_latin1(jchar c) { diff --git a/src/hotspot/share/utilities/utf8.hpp b/src/hotspot/share/utilities/utf8.hpp index 80346f7da7ddb..9a18dd0ff93b7 100644 --- a/src/hotspot/share/utilities/utf8.hpp +++ b/src/hotspot/share/utilities/utf8.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -88,6 +88,7 @@ class UTF8 : AllStatic { static bool is_legal_utf8(const unsigned char* buffer, int length, bool version_leq_47); + static void truncate_to_legal_utf8(unsigned char* buffer, int length); }; diff --git a/test/hotspot/gtest/utilities/test_utf8.cpp b/test/hotspot/gtest/utilities/test_utf8.cpp index ffd8121075be8..80f6671207bbd 100644 --- a/test/hotspot/gtest/utilities/test_utf8.cpp +++ b/test/hotspot/gtest/utilities/test_utf8.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,6 +22,8 @@ */ #include "precompiled.hpp" +#include "nmt/memflags.hpp" +#include "runtime/os.hpp" #include "utilities/utf8.hpp" #include "unittest.hpp" @@ -101,5 +103,105 @@ TEST_VM(utf8, jbyte_length) { UNICODE::as_utf8(str, 19, res, i); EXPECT_TRUE(test_stamp(res + i, sizeof(res) - i)); } +} + +TEST_VM(utf8, truncation) { + + // Test that truncation removes partial encodings as expected. + + const char orig_bytes[] = { 'A', 'B', 'C', 'D', 'E', '\0' }; + const int orig_length = sizeof(orig_bytes)/sizeof(char); + ASSERT_TRUE(UTF8::is_legal_utf8((const unsigned char*)orig_bytes, orig_length - 1, false)); + const char* orig_str = &orig_bytes[0]; + ASSERT_EQ((int)strlen(orig_str), orig_length - 1); + + unsigned char* temp_bytes; + const char* temp_str; + char* utf8; + int n_utf8; // Number of bytes in the encoding + + // Test 1: a valid UTF8 "ascii" ending string should be returned as-is + + temp_bytes = (unsigned char*) os::malloc(sizeof(unsigned char) * orig_length, mtTest); + strcpy((char*)temp_bytes, orig_str); + temp_str = (const char*) temp_bytes; + UTF8::truncate_to_legal_utf8(temp_bytes, orig_length); + ASSERT_EQ((int)strlen(temp_str), orig_length - 1) << "bytes should be unchanged"; + ASSERT_EQ(strcmp(orig_str, temp_str), 0) << "bytes should be unchanged"; + os::free(temp_bytes); + + // Test 2: a UTF8 sequence that "ends" with a 2-byte encoding + // drops the 2-byte encoding + + jchar two_byte_char[] = { 0x00D1 }; // N with tilde + n_utf8 = 2; + utf8 = (char*) os::malloc(sizeof(char) * (n_utf8 + 1), mtTest); // plus NUL + UNICODE::convert_to_utf8(two_byte_char, 1, utf8); + int utf8_len = (int)strlen(utf8); + ASSERT_EQ(utf8_len, n_utf8) << "setup error"; + + // Now drop zero or one byte from the end and check it truncates as expected + for (int drop = 0; drop < n_utf8; drop++) { + int temp_len = orig_length + utf8_len - drop; + temp_bytes = (unsigned char*) os::malloc(sizeof(unsigned char) * temp_len, mtTest); + temp_str = (const char*) temp_bytes; + strcpy((char*)temp_bytes, orig_str); + strncat((char*)temp_bytes, utf8, utf8_len - drop); + ASSERT_EQ((int)strlen(temp_str), temp_len - 1) << "setup error"; + UTF8::truncate_to_legal_utf8(temp_bytes, temp_len); + ASSERT_EQ((int)strlen(temp_str), orig_length - 1) << "bytes should be truncated to original length"; + ASSERT_EQ(strcmp(orig_str, temp_str), 0) << "bytes should be truncated to original"; + os::free(temp_bytes); + } + os::free(utf8); + + // Test 3: a UTF8 sequence that "ends" with a 3-byte encoding + // drops the 3-byte encoding + n_utf8 = 3; + jchar three_byte_char[] = { 0x0800 }; + utf8 = (char*) os::malloc(sizeof(char) * (n_utf8 + 1), mtTest); // plus NUL + UNICODE::convert_to_utf8(three_byte_char, 1, utf8); + utf8_len = (int)strlen(utf8); + ASSERT_EQ(utf8_len, n_utf8) << "setup error"; + + // Now drop zero, to two bytes from the end and check it truncates as expected + for (int drop = 0; drop < n_utf8; drop++) { + int temp_len = orig_length + utf8_len - drop; + temp_bytes = (unsigned char*) os::malloc(sizeof(unsigned char) * temp_len, mtTest); + temp_str = (const char*) temp_bytes; + strcpy((char*)temp_bytes, orig_str); + strncat((char*)temp_bytes, utf8, utf8_len - drop); + ASSERT_EQ((int)strlen(temp_str), temp_len - 1) << "setup error"; + UTF8::truncate_to_legal_utf8(temp_bytes, temp_len); + ASSERT_EQ((int)strlen(temp_str), orig_length - 1) << "bytes should be truncated to original length"; + ASSERT_EQ(strcmp(orig_str, temp_str), 0) << "bytes should be truncated to original"; + os::free(temp_bytes); + } + os::free(utf8); + + // Test 4: a UTF8 sequence that "ends" with a 6-byte encoding + // drops the 6-byte encoding + n_utf8 = 6; + jchar six_byte_char[] = { 0xD801, 0xDC37 }; // U+10437 as its UTF-16 surrogate pairs + utf8 = (char*) os::malloc(sizeof(char) * (n_utf8 + 1), mtTest); // plus NUL + UNICODE::convert_to_utf8(six_byte_char, 2, utf8); + utf8_len = (int)strlen(utf8); + ASSERT_EQ(utf8_len, n_utf8) << "setup error"; + + // Now drop zero to five bytes from the end and check it truncates as expected + for (int drop = 0; drop < n_utf8; drop++) { + int temp_len = orig_length + utf8_len - drop; + temp_bytes = (unsigned char*) os::malloc(sizeof(unsigned char) * temp_len, mtTest); + temp_str = (const char*) temp_bytes; + strcpy((char*)temp_bytes, orig_str); + strncat((char*)temp_bytes, utf8, utf8_len - drop); + ASSERT_EQ((int)strlen(temp_str), temp_len - 1) << "setup error"; + UTF8::truncate_to_legal_utf8(temp_bytes, temp_len); + ASSERT_EQ((int)strlen(temp_str), orig_length - 1) << "bytes should be truncated to original length"; + ASSERT_EQ(strcmp(orig_str, temp_str), 0) << "bytes should be truncated to original"; + os::free(temp_bytes); + } + os::free(utf8); + } From 1c6fef8f1cd12b26de9d31799a6516ce4399313f Mon Sep 17 00:00:00 2001 From: David Holmes Date: Wed, 31 Jul 2024 00:58:52 +0000 Subject: [PATCH 148/353] 8337515: JVM_DumpAllStacks is dead code Reviewed-by: kvn --- src/hotspot/share/include/jvm.h | 3 --- src/hotspot/share/prims/jvm.cpp | 8 -------- 2 files changed, 11 deletions(-) diff --git a/src/hotspot/share/include/jvm.h b/src/hotspot/share/include/jvm.h index a18e9bffc85df..6082af55487e2 100644 --- a/src/hotspot/share/include/jvm.h +++ b/src/hotspot/share/include/jvm.h @@ -295,9 +295,6 @@ JVM_HoldsLock(JNIEnv *env, jclass threadClass, jobject obj); JNIEXPORT jobject JNICALL JVM_GetStackTrace(JNIEnv *env, jobject thread); -JNIEXPORT void JNICALL -JVM_DumpAllStacks(JNIEnv *env, jclass unused); - JNIEXPORT jobjectArray JNICALL JVM_GetAllThreads(JNIEnv *env, jclass dummy); diff --git a/src/hotspot/share/prims/jvm.cpp b/src/hotspot/share/prims/jvm.cpp index 7a8c07477dcb7..6aabb65ca4023 100644 --- a/src/hotspot/share/prims/jvm.cpp +++ b/src/hotspot/share/prims/jvm.cpp @@ -3119,14 +3119,6 @@ JVM_ENTRY(jobject, JVM_GetStackTrace(JNIEnv *env, jobject jthread)) return JNIHandles::make_local(THREAD, trace); JVM_END -JVM_ENTRY(void, JVM_DumpAllStacks(JNIEnv* env, jclass)) - VM_PrintThreads op; - VMThread::execute(&op); - if (JvmtiExport::should_post_data_dump()) { - JvmtiExport::post_data_dump(); - } -JVM_END - JVM_ENTRY(void, JVM_SetNativeThreadName(JNIEnv* env, jobject jthread, jstring name)) // We don't use a ThreadsListHandle here because the current thread // must be alive. From e63d01654e0b702b3a8c0c4de97a6bb6893fbd1f Mon Sep 17 00:00:00 2001 From: Ashutosh Mehra Date: Wed, 31 Jul 2024 01:36:37 +0000 Subject: [PATCH 149/353] 8337031: Improvements to CompilationMemoryStatistic Reviewed-by: kvn, stuefe --- .../compiler/compilationMemoryStatistic.cpp | 145 ++++++++++-------- .../compiler/compilationMemoryStatistic.hpp | 54 +++++-- src/hotspot/share/memory/arena.cpp | 13 ++ src/hotspot/share/memory/arena.hpp | 24 ++- .../print/CompileCommandPrintMemStat.java | 11 +- .../compiler/CompilerMemoryStatisticTest.java | 6 +- 6 files changed, 155 insertions(+), 98 deletions(-) diff --git a/src/hotspot/share/compiler/compilationMemoryStatistic.cpp b/src/hotspot/share/compiler/compilationMemoryStatistic.cpp index 07d8ec41598d9..4cc2043656efa 100644 --- a/src/hotspot/share/compiler/compilationMemoryStatistic.cpp +++ b/src/hotspot/share/compiler/compilationMemoryStatistic.cpp @@ -51,29 +51,36 @@ #include "utilities/quickSort.hpp" #include "utilities/resourceHash.hpp" -ArenaStatCounter::ArenaStatCounter() : - _current(0), _start(0), _peak(0), - _na(0), _ra(0), - _limit(0), _hit_limit(false), _limit_in_process(false), - _na_at_peak(0), _ra_at_peak(0), _live_nodes_at_peak(0) -{} - -size_t ArenaStatCounter::peak_since_start() const { - return _peak > _start ? _peak - _start : 0; +ArenaStatCounter::ArenaStatCounter() { + reset(); +} + +void ArenaStatCounter::reset() { + _current = 0; + _peak = 0; + _current_by_tag.clear(); + _peak_by_tag.clear(); + _limit = 0; + _hit_limit = false; + _limit_in_process = false; + _live_nodes_at_peak = 0; + _active = false; } void ArenaStatCounter::start(size_t limit) { - _peak = _start = _current; + reset(); + _active = true; _limit = limit; - _hit_limit = false; } -void ArenaStatCounter::end(){ +void ArenaStatCounter::end() { _limit = 0; _hit_limit = false; + _active = false; } void ArenaStatCounter::update_c2_node_count() { + assert(_active, "compilaton has not yet started"); #ifdef COMPILER2 CompilerThread* const th = Thread::current()->as_Compiler_thread(); const CompileTask* const task = th->task(); @@ -90,33 +97,27 @@ void ArenaStatCounter::update_c2_node_count() { // Account an arena allocation or de-allocation. bool ArenaStatCounter::account(ssize_t delta, int tag) { + assert(_active, "compilaton has not yet started"); bool rc = false; #ifdef ASSERT // Note: if this fires, we free more arena memory under the scope of the // CompilationMemoryHistoryMark than we allocate. This cannot be since we // assume arena allocations in CompilerThread to be stack bound and symmetric. assert(delta >= 0 || ((ssize_t)_current + delta) >= 0, - "Negative overflow (d=%zd %zu %zu %zu)", delta, _current, _start, _peak); + "Negative overflow (d=%zd %zu %zu)", delta, _current, _peak); #endif // Update totals _current += delta; - // Update detail counter - switch ((Arena::Tag)tag) { - case Arena::Tag::tag_ra: _ra += delta; break; - case Arena::Tag::tag_node: _na += delta; break; - default: // ignore - break; - }; + _current_by_tag.add(tag, delta); // Did we reach a peak? if (_current > _peak) { _peak = _current; - assert(delta > 0, "Sanity (%zu %zu %zu)", _current, _start, _peak); - _na_at_peak = _na; - _ra_at_peak = _ra; + assert(delta > 0, "Sanity (%zu %zu)", _current, _peak); update_c2_node_count(); + _peak_by_tag = _current_by_tag; rc = true; // Did we hit the memory limit? - if (!_hit_limit && _limit > 0 && peak_since_start() > _limit) { + if (!_hit_limit && _limit > 0 && _peak > _limit) { _hit_limit = true; } } @@ -124,9 +125,15 @@ bool ArenaStatCounter::account(ssize_t delta, int tag) { } void ArenaStatCounter::print_on(outputStream* st) const { - st->print("%zu [na %zu ra %zu]", peak_since_start(), _na_at_peak, _ra_at_peak); + st->print("%zu [", _peak); + for (int tag = 0; tag < _peak_by_tag.element_count(); tag++) { + if (_peak_by_tag.counter(tag) > 0) { + st->print("%s %zu ", _peak_by_tag.tag_name(tag), _peak_by_tag.counter(tag)); + } + } + st->print("]"); #ifdef ASSERT - st->print(" (%zu->%zu->%zu)", _start, _peak, _current); + st->print(" (%zu->%zu)", _peak, _current); #endif } @@ -186,10 +193,8 @@ class MemStatEntry : public CHeapObj { // peak usage, bytes, over all arenas size_t _total; - // usage in node arena when total peaked - size_t _na_at_peak; - // usage in resource area when total peaked - size_t _ra_at_peak; + // usage per arena tag when total peaked + ArenaCountersByTag _peak_by_tag; // number of nodes (c2 only) when total peaked unsigned _live_nodes_at_peak; const char* _result; @@ -199,8 +204,9 @@ class MemStatEntry : public CHeapObj { MemStatEntry(FullMethodName method) : _method(method), _comptype(compiler_c1), _time(0), _num_recomp(0), _thread(nullptr), _limit(0), - _total(0), _na_at_peak(0), _ra_at_peak(0), _live_nodes_at_peak(0), + _total(0), _live_nodes_at_peak(0), _result(nullptr) { + _peak_by_tag.clear(); } void set_comptype(CompilerType comptype) { _comptype = comptype; } @@ -210,8 +216,7 @@ class MemStatEntry : public CHeapObj { void inc_recompilation() { _num_recomp++; } void set_total(size_t n) { _total = n; } - void set_na_at_peak(size_t n) { _na_at_peak = n; } - void set_ra_at_peak(size_t n) { _ra_at_peak = n; } + void set_peak_by_tag(ArenaCountersByTag peak_by_tag) { _peak_by_tag = peak_by_tag; } void set_live_nodes_at_peak(unsigned n) { _live_nodes_at_peak = n; } void set_result(const char* s) { _result = s; } @@ -219,21 +224,34 @@ class MemStatEntry : public CHeapObj { size_t total() const { return _total; } static void print_legend(outputStream* st) { +#define LEGEND_KEY_FMT "%11s" st->print_cr("Legend:"); - st->print_cr(" total : memory allocated via arenas while compiling"); - st->print_cr(" NA : ...how much in node arenas (if c2)"); - st->print_cr(" RA : ...how much in resource areas"); - st->print_cr(" result : Result: 'ok' finished successfully, 'oom' hit memory limit, 'err' compilation failed"); - st->print_cr(" #nodes : ...how many nodes (c2 only)"); - st->print_cr(" limit : memory limit, if set"); - st->print_cr(" time : time of last compilation (sec)"); - st->print_cr(" type : compiler type"); - st->print_cr(" #rc : how often recompiled"); - st->print_cr(" thread : compiler thread"); + st->print_cr(" " LEGEND_KEY_FMT ": %s", "total", "memory allocated via arenas while compiling"); + for (int tag = 0; tag < Arena::tag_count(); tag++) { + st->print_cr(" " LEGEND_KEY_FMT ": %s", Arena::tag_name[tag], Arena::tag_desc[tag]); + } + st->print_cr(" " LEGEND_KEY_FMT ": %s", "result", "Result: 'ok' finished successfully, 'oom' hit memory limit, 'err' compilation failed"); + st->print_cr(" " LEGEND_KEY_FMT ": %s", "#nodes", "...how many nodes (c2 only)"); + st->print_cr(" " LEGEND_KEY_FMT ": %s", "limit", "memory limit, if set"); + st->print_cr(" " LEGEND_KEY_FMT ": %s", "time", "time taken for last compilation (sec)"); + st->print_cr(" " LEGEND_KEY_FMT ": %s", "type", "compiler type"); + st->print_cr(" " LEGEND_KEY_FMT ": %s", "#rc", "how often recompiled"); + st->print_cr(" " LEGEND_KEY_FMT ": %s", "thread", "compiler thread"); +#undef LEGEND_KEY_FMT } static void print_header(outputStream* st) { - st->print_cr("total NA RA result #nodes limit time type #rc thread method"); +#define SIZE_FMT "%-10s" + st->print(SIZE_FMT, "total"); + for (int tag = 0; tag < Arena::tag_count(); tag++) { + st->print(SIZE_FMT, Arena::tag_name[tag]); + } +#define HDR_FMT1 "%-8s%-8s%-8s%-8s" +#define HDR_FMT2 "%-6s%-4s%-19s%s" + + st->print(HDR_FMT1, "result", "#nodes", "limit", "time"); + st->print(HDR_FMT2, "type", "#rc", "thread", "method"); + st->print_cr(""); } void print_on(outputStream* st, bool human_readable) const { @@ -247,21 +265,14 @@ class MemStatEntry : public CHeapObj { } col += 10; st->fill_to(col); - // NA - if (human_readable) { - st->print(PROPERFMT " ", PROPERFMTARGS(_na_at_peak)); - } else { - st->print("%zu ", _na_at_peak); - } - col += 10; st->fill_to(col); - - // RA - if (human_readable) { - st->print(PROPERFMT " ", PROPERFMTARGS(_ra_at_peak)); - } else { - st->print("%zu ", _ra_at_peak); + for (int tag = 0; tag < Arena::tag_count(); tag++) { + if (human_readable) { + st->print(PROPERFMT " ", PROPERFMTARGS(_peak_by_tag.counter(tag))); + } else { + st->print("%zu ", _peak_by_tag.counter(tag)); + } + col += 10; st->fill_to(col); } - col += 10; st->fill_to(col); // result? st->print("%s ", _result ? _result : ""); @@ -296,7 +307,7 @@ class MemStatEntry : public CHeapObj { col += 4; st->fill_to(col); // Thread - st->print(PTR_FORMAT " ", p2i(_thread)); + st->print(PTR_FORMAT " ", p2i(_thread)); // MethodName char buf[1024]; @@ -341,7 +352,7 @@ class MemStatTable : public: void add(const FullMethodName& fmn, CompilerType comptype, - size_t total, size_t na_at_peak, size_t ra_at_peak, + size_t total, ArenaCountersByTag peak_by_tag, unsigned live_nodes_at_peak, size_t limit, const char* result) { assert_lock_strong(NMTCompilationCostHistory_lock); MemStatTableKey key(fmn, comptype); @@ -360,8 +371,7 @@ class MemStatTable : e->set_comptype(comptype); e->inc_recompilation(); e->set_total(total); - e->set_na_at_peak(na_at_peak); - e->set_ra_at_peak(ra_at_peak); + e->set_peak_by_tag(peak_by_tag); e->set_live_nodes_at_peak(live_nodes_at_peak); e->set_limit(limit); e->set_result(result); @@ -427,7 +437,7 @@ void CompilationMemoryStatistic::on_end_compilation() { const bool print = directive->should_print_memstat(); // Store memory used in task, for later processing by JFR - task->set_arena_bytes(arena_stat->peak_since_start()); + task->set_arena_bytes(arena_stat->peak()); // Store result // For this to work, we must call on_end_compilation() at a point where @@ -447,9 +457,8 @@ void CompilationMemoryStatistic::on_end_compilation() { assert(_the_table != nullptr, "not initialized"); _the_table->add(fmn, ct, - arena_stat->peak_since_start(), // total - arena_stat->na_at_peak(), - arena_stat->ra_at_peak(), + arena_stat->peak(), // total + arena_stat->peak_by_tag(), arena_stat->live_nodes_at_peak(), arena_stat->limit(), result); @@ -511,7 +520,7 @@ void CompilationMemoryStatistic::on_arena_change(ssize_t diff, const Arena* aren bool hit_limit_before = arena_stat->hit_limit(); - if (arena_stat->account(diff, (int)arena->get_tag())) { // new peak? + if (arena_stat->is_active() && arena_stat->account(diff, (int)arena->get_tag())) { // new peak? // Limit handling if (arena_stat->hit_limit()) { @@ -545,7 +554,7 @@ void CompilationMemoryStatistic::on_arena_change(ssize_t diff, const Arena* aren } ss.print("Hit MemLimit %s(limit: %zu now: %zu)", (hit_limit_before ? "again " : ""), - arena_stat->limit(), arena_stat->peak_since_start()); + arena_stat->limit(), arena_stat->peak()); } // log if needed diff --git a/src/hotspot/share/compiler/compilationMemoryStatistic.hpp b/src/hotspot/share/compiler/compilationMemoryStatistic.hpp index d7cccad17fda8..d669cc1472295 100644 --- a/src/hotspot/share/compiler/compilationMemoryStatistic.hpp +++ b/src/hotspot/share/compiler/compilationMemoryStatistic.hpp @@ -29,48 +29,70 @@ #include "compiler/compilerDefinitions.hpp" #include "memory/allocation.hpp" #include "memory/allStatic.hpp" +#include "memory/arena.hpp" #include "utilities/globalDefinitions.hpp" class outputStream; class Symbol; class DirectiveSet; -// Counters for allocations from one arena +// Helper class to wrap the array of arena tags for easier processing +class ArenaCountersByTag { +private: + size_t _counter[Arena::tag_count()]; + +public: + int element_count() const { return Arena::tag_count(); } + const char* tag_name(int tag) const { return Arena::tag_name[tag]; } + + size_t counter(int tag) const { + assert(tag < element_count(), "invalid tag %d", tag); + return _counter[tag]; + } + + void add(int tag, size_t value) { + assert(tag < element_count(), "invalid tag %d", tag); + _counter[tag] += value; + } + + void clear() { + memset(_counter, 0, sizeof(size_t) * element_count()); + } +}; + +// Counters for allocations from arenas during compilation class ArenaStatCounter : public CHeapObj { // Current bytes, total size_t _current; - // bytes when compilation started - size_t _start; // bytes at last peak, total size_t _peak; - // Current bytes used for node arenas, total - size_t _na; - // Current bytes used for resource areas - size_t _ra; + // Current bytes used by arenas per tag + ArenaCountersByTag _current_by_tag; + // Peak composition: + ArenaCountersByTag _peak_by_tag; // MemLimit handling size_t _limit; bool _hit_limit; bool _limit_in_process; - // Peak composition: - // Size of node arena when total peaked (c2 only) - size_t _na_at_peak; - // Size of resource area when total peaked - size_t _ra_at_peak; + // When to start accounting + bool _active; + // Number of live nodes when total peaked (c2 only) unsigned _live_nodes_at_peak; void update_c2_node_count(); + void reset(); + public: ArenaStatCounter(); // Size of peak since last compilation - size_t peak_since_start() const; + size_t peak() const { return _peak; } // Peak details - size_t na_at_peak() const { return _na_at_peak; } - size_t ra_at_peak() const { return _ra_at_peak; } + ArenaCountersByTag peak_by_tag() const { return _peak_by_tag; } unsigned live_nodes_at_peak() const { return _live_nodes_at_peak; } // Mark the start and end of a compilation. @@ -89,7 +111,7 @@ class ArenaStatCounter : public CHeapObj { bool hit_limit() const { return _hit_limit; } bool limit_in_process() const { return _limit_in_process; } void set_limit_in_process(bool v) { _limit_in_process = v; } - + bool is_active() const { return _active; } }; class CompilationMemoryStatistic : public AllStatic { diff --git a/src/hotspot/share/memory/arena.cpp b/src/hotspot/share/memory/arena.cpp index 0399c6922e38d..435a8cfdd584f 100644 --- a/src/hotspot/share/memory/arena.cpp +++ b/src/hotspot/share/memory/arena.cpp @@ -44,6 +44,19 @@ STATIC_ASSERT(is_aligned((int)Chunk::init_size, ARENA_AMALLOC_ALIGNMENT)); STATIC_ASSERT(is_aligned((int)Chunk::medium_size, ARENA_AMALLOC_ALIGNMENT)); STATIC_ASSERT(is_aligned((int)Chunk::size, ARENA_AMALLOC_ALIGNMENT)); + +const char* Arena::tag_name[] = { +#define ARENA_TAG_STRING(name, str, desc) XSTR(name), + DO_ARENA_TAG(ARENA_TAG_STRING) +#undef ARENA_TAG_STRING +}; + +const char* Arena::tag_desc[] = { +#define ARENA_TAG_DESC(name, str, desc) XSTR(desc), + DO_ARENA_TAG(ARENA_TAG_DESC) +#undef ARENA_TAG_DESC +}; + // MT-safe pool of same-sized chunks to reduce malloc/free thrashing // NB: not using Mutex because pools are used before Threads are initialized class ChunkPool { diff --git a/src/hotspot/share/memory/arena.hpp b/src/hotspot/share/memory/arena.hpp index 1ca8a78782541..1f3c5eb4e8bac 100644 --- a/src/hotspot/share/memory/arena.hpp +++ b/src/hotspot/share/memory/arena.hpp @@ -83,17 +83,29 @@ class Chunk { bool contains(char* p) const { return bottom() <= p && p <= top(); } }; +#define DO_ARENA_TAG(FN) \ + FN(other, Others, Other arenas) \ + FN(ra, RA, Resource areas) \ + FN(ha, HA, Handle area) \ + FN(node, NA, Node arena) \ + // Fast allocation of memory class Arena : public CHeapObjBase { public: - - enum class Tag : uint8_t { - tag_other = 0, - tag_ra, // resource area - tag_ha, // handle area - tag_node // C2 Node arena + enum class Tag: uint8_t { +#define ARENA_TAG_ENUM(name, str, desc) tag_##name, + DO_ARENA_TAG(ARENA_TAG_ENUM) +#undef ARENA_TAG_ENUM + tag_count }; + constexpr static int tag_count() { + return static_cast(Tag::tag_count); + } + + static const char* tag_name[static_cast(Arena::Tag::tag_count)]; + static const char* tag_desc[static_cast(Arena::Tag::tag_count)]; + private: const MEMFLAGS _flags; // Memory tracking flags const Tag _tag; diff --git a/test/hotspot/jtreg/compiler/print/CompileCommandPrintMemStat.java b/test/hotspot/jtreg/compiler/print/CompileCommandPrintMemStat.java index c2689d883721b..2dbf46fd04025 100644 --- a/test/hotspot/jtreg/compiler/print/CompileCommandPrintMemStat.java +++ b/test/hotspot/jtreg/compiler/print/CompileCommandPrintMemStat.java @@ -77,16 +77,17 @@ private static void test(String include, String exclude) throws Exception { // Should see final report // Looks like this: - // total NA RA result #nodes limit time type #rc thread method - // 2149912 0 1986272 ok - - 0.101 c1 1 0x000000015180a600 jdk/internal/org/objectweb/asm/Frame::execute((IILjdk/internal/org/objectweb/asm/Symbol;Ljdk/internal/org/objectweb/asm/SymbolTable;)V) oa.shouldMatch("total.*method"); + // total Others RA HA NA result #nodes limit time type #rc thread method + // 523648 32728 490920 0 0 ok - - 0.250 c1 1 0x00007f4ec00d4ac0 java/lang/Class::descriptorString(()Ljava/lang/String;) // or - // 537784 98184 208536 ok 267 - 0.096 c2 1 0x0000000153019c00 jdk/internal/classfile/impl/BufWriterImpl::writeU1((I)V) 4521912 0 1986272 ok - - 0.101 c1 1 0x000000015180a600 jdk/internal/org/objectweb/asm/Frame::execute((IILjdk/internal/org/objectweb/asm/Symbol;Ljdk/internal/org/objectweb/asm/SymbolTable;)V) oa.shouldMatch("total.*method"); - oa.shouldMatch("\\d+ +\\d+ +\\d+ +ok +(\\d+|-) +.*" + expectedNameIncl + ".*"); + // 1898600 853176 750872 0 294552 ok 934 - 1.501 c2 1 0x00007f4ec00d3330 java/lang/String::replace((CC)Ljava/lang/String;) + oa.shouldMatch("total.*method"); + oa.shouldMatch("\\d+ +(\\d+ +){4}ok +(\\d+|-) +.*" + expectedNameIncl + ".*"); // In debug builds, we have a default memory limit enabled. That implies MemStat. Therefore we // expect to see all methods, not just the one we specified on the command line. if (Platform.isDebugBuild()) { - oa.shouldMatch("\\d+ +\\d+ +\\d+ +ok +(\\d+|-) +.*" + expectedNameExcl + ".*"); + oa.shouldMatch("\\d+ +(\\d+ +){4}ok +(\\d+|-) +.*" + expectedNameExcl + ".*"); } else { oa.shouldNotMatch(".*" + expectedNameExcl + ".*"); } diff --git a/test/hotspot/jtreg/serviceability/dcmd/compiler/CompilerMemoryStatisticTest.java b/test/hotspot/jtreg/serviceability/dcmd/compiler/CompilerMemoryStatisticTest.java index 7d4a38db47b48..02bc77263d805 100644 --- a/test/hotspot/jtreg/serviceability/dcmd/compiler/CompilerMemoryStatisticTest.java +++ b/test/hotspot/jtreg/serviceability/dcmd/compiler/CompilerMemoryStatisticTest.java @@ -47,9 +47,9 @@ public static void main(String args[]) throws Exception { out.shouldHaveExitValue(0); // Looks like this: - // total NA RA result #nodes time type #rc thread method - // 211488 66440 77624 ok 13 0.057 c2 2 0x00007fb49428db70 compiler/print/CompileCommandPrintMemStat$TestMain::method1(()V) + // total Others RA HA NA result #nodes limit time type #rc thread method + // 1898600 853176 750872 0 294552 ok 934 - 1.501 c2 1 0x00007f4ec00d3330 java/lang/String::replace((CC)Ljava/lang/String;) out.shouldMatch("total.*method"); - out.shouldMatch("\\d+ +\\d+ +\\d+ +\\S+ +\\d+.*java.*\\(.*\\)"); + out.shouldMatch("\\d+ +(\\d+ +){4}\\S+ +\\d+.*java.*\\(.*\\)"); } } From de0b50400a4155554c83d5c3346ab1ec5353df61 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Wed, 31 Jul 2024 08:08:15 +0000 Subject: [PATCH 150/353] 8336912: G1: Undefined behavior for G1ConfidencePercent=0 Reviewed-by: ayang, sangheki --- src/hotspot/share/gc/g1/g1_globals.hpp | 2 +- .../jtreg/gc/arguments/TestG1PercentageOptions.java | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1_globals.hpp b/src/hotspot/share/gc/g1/g1_globals.hpp index af1ac1f70c64b..c8016ddc0ddf5 100644 --- a/src/hotspot/share/gc/g1/g1_globals.hpp +++ b/src/hotspot/share/gc/g1/g1_globals.hpp @@ -112,7 +112,7 @@ \ product(uint, G1ConfidencePercent, 50, \ "Confidence level for MMU/pause predictions") \ - range(0, 100) \ + range(1, 100) \ \ product(uintx, G1SummarizeRSetStatsPeriod, 0, DIAGNOSTIC, \ "The period (in number of GCs) at which we will generate " \ diff --git a/test/hotspot/jtreg/gc/arguments/TestG1PercentageOptions.java b/test/hotspot/jtreg/gc/arguments/TestG1PercentageOptions.java index e8ee2598c9ad2..48345da250a8e 100644 --- a/test/hotspot/jtreg/gc/arguments/TestG1PercentageOptions.java +++ b/test/hotspot/jtreg/gc/arguments/TestG1PercentageOptions.java @@ -51,14 +51,14 @@ private static final class OptionDescription { } } - private static final String[] defaultValid = new String[] { - "0", "1", "50", "95", "100" }; - private static final String[] defaultInvalid = new String[] { - "-10", "110", "bad" }; + private static final String[] rangeOneToHundredValid = new String[] { + "1", "50", "95", "100" }; + private static final String[] rangeOneToHundredInvalid = new String[] { + "0", "-10", "110", "bad" }; // All of the G1 product arguments that are percentages. private static final OptionDescription[] percentOptions = new OptionDescription[] { - new OptionDescription("G1ConfidencePercent", defaultValid, defaultInvalid) + new OptionDescription("G1ConfidencePercent", rangeOneToHundredValid, rangeOneToHundredInvalid) // Other percentage options are not yet validated by argument processing. }; From 9b428dda8fb86ed595b05f3c930b3ce9c341db9b Mon Sep 17 00:00:00 2001 From: David Leopoldseder Date: Wed, 31 Jul 2024 09:40:47 +0000 Subject: [PATCH 151/353] 8336242: compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/SimpleDebugInfoTest.java failed assert(oopDesc::is_oop_or_null(val)) failed: bad oop found (again) Reviewed-by: dnsimon, never --- .../vm/ci/code/test/SimpleDebugInfoTest.java | 80 ------------------- 1 file changed, 80 deletions(-) diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/SimpleDebugInfoTest.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/SimpleDebugInfoTest.java index c7d8d2cf83064..e77ac8dc4f998 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/SimpleDebugInfoTest.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/SimpleDebugInfoTest.java @@ -200,84 +200,4 @@ public void testStackLong() { testLongOnStack(compiler); testLongInLocal(compiler); } - - public static Class objectOnStack() { - return SimpleDebugInfoTest.class; - } - - private void testObjectOnStack(DebugInfoCompiler compiler) { - test(compiler, getMethod("objectOnStack"), 2, JavaKind.Object); - } - - public static Class objectInLocal() { - Class local = SimpleDebugInfoTest.class; - return local; - } - - private void testObjectInLocal(DebugInfoCompiler compiler) { - test(compiler, getMethod("objectInLocal"), 3, JavaKind.Object); - } - - @Test - public void testConstObject() { - ResolvedJavaType type = metaAccess.lookupJavaType(objectOnStack()); - DebugInfoCompiler compiler = (asm, values) -> { - values[0] = constantReflection.asJavaClass(type); - return null; - }; - testObjectOnStack(compiler); - testObjectInLocal(compiler); - } - - @Test - public void testRegObject() { - ResolvedJavaType type = metaAccess.lookupJavaType(objectOnStack()); - DebugInfoCompiler compiler = (asm, values) -> { - Register reg = asm.emitLoadPointer((HotSpotConstant) constantReflection.asJavaClass(type)); - values[0] = reg.asValue(asm.getValueKind(JavaKind.Object)); - return null; - }; - testObjectOnStack(compiler); - testObjectInLocal(compiler); - } - - @Test - public void testStackObject() { - ResolvedJavaType type = metaAccess.lookupJavaType(objectOnStack()); - DebugInfoCompiler compiler = (asm, values) -> { - Register reg = asm.emitLoadPointer((HotSpotConstant) constantReflection.asJavaClass(type)); - values[0] = asm.emitPointerToStack(reg); - return null; - }; - testObjectOnStack(compiler); - testObjectInLocal(compiler); - } - - @Test - public void testRegNarrowObject() { - Assume.assumeTrue(config.useCompressedOops); - ResolvedJavaType type = metaAccess.lookupJavaType(objectOnStack()); - DebugInfoCompiler compiler = (asm, values) -> { - HotSpotConstant wide = (HotSpotConstant) constantReflection.asJavaClass(type); - Register reg = asm.emitLoadPointer((HotSpotConstant) wide.compress()); - values[0] = reg.asValue(asm.narrowOopKind); - return null; - }; - testObjectOnStack(compiler); - testObjectInLocal(compiler); - } - - @Test - public void testStackNarrowObject() { - Assume.assumeTrue(config.useCompressedOops); - ResolvedJavaType type = metaAccess.lookupJavaType(objectOnStack()); - DebugInfoCompiler compiler = (asm, values) -> { - HotSpotConstant wide = (HotSpotConstant) constantReflection.asJavaClass(type); - Register reg = asm.emitLoadPointer((HotSpotConstant) wide.compress()); - values[0] = asm.emitNarrowPointerToStack(reg); - return null; - }; - testObjectOnStack(compiler); - testObjectInLocal(compiler); - } } From c73b3cb5996723c5a15c833a9da059b79c99cf9c Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Wed, 31 Jul 2024 12:56:43 +0000 Subject: [PATCH 152/353] 8336635: Add IR test for Reference.refersTo intrinsic Reviewed-by: thartmann, kvn --- .../c2/irTests/gc/ReferenceRefersToTests.java | 156 ++++++++++++++++++ 1 file changed, 156 insertions(+) create mode 100644 test/hotspot/jtreg/compiler/c2/irTests/gc/ReferenceRefersToTests.java diff --git a/test/hotspot/jtreg/compiler/c2/irTests/gc/ReferenceRefersToTests.java b/test/hotspot/jtreg/compiler/c2/irTests/gc/ReferenceRefersToTests.java new file mode 100644 index 0000000000000..7cf7c72c8fd89 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/irTests/gc/ReferenceRefersToTests.java @@ -0,0 +1,156 @@ +/* + * 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. + */ +package compiler.c2.irTests.gc; + +import jdk.test.lib.Asserts; +import compiler.lib.ir_framework.*; +import jdk.test.whitebox.gc.GC; + +import java.lang.ref.*; +import java.util.*; + +/* + * @test + * @bug 8256999 + * @summary Test that Reference.refersTo intrinsics are properly handled + * @library /test/lib / + * @build jdk.test.whitebox.WhiteBox + * @requires vm.compiler2.enabled + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI compiler.c2.irTests.gc.ReferenceRefersToTests + */ +public class ReferenceRefersToTests { + + private static String[] args(String... add) { + List args = new ArrayList<>(); + + // Use PerMethodTrapLimit=0 to compile all branches in the intrinsics. + args.add("-XX:PerMethodTrapLimit=0"); + + // Forcefully inline all methods to reach the intrinsic code. + args.add("-XX:CompileCommand=inline,compiler.c2.irTests.gc.ReferenceRefersToTests::*"); + args.add("-XX:CompileCommand=inline,java.lang.ref.Reference::*"); + args.add("-XX:CompileCommand=inline,java.lang.ref.PhantomReference::*"); + + // Mix in test config code. + args.addAll(Arrays.asList(add)); + + return args.toArray(new String[0]); + } + + public static void main(String[] args) { + TestFramework framework = new TestFramework(); + + int idx = 0; + if (GC.isSelectedErgonomically() && GC.Serial.isSupported()) { + // Serial does not have any barriers in refersTo. + framework.addScenarios(new Scenario(idx++, args( + "-XX:+UseSerialGC" + ))); + } + if (GC.isSelectedErgonomically() && GC.Parallel.isSupported()) { + // Parallel does not have any barriers in refersTo. + framework.addScenarios(new Scenario(idx++, args( + "-XX:+UseParallelGC" + ))); + } + if (GC.isSelectedErgonomically() && GC.G1.isSupported()) { + // G1 nominally needs keep-alive barriers for Reference loads, + // but should not have them for refersTo. + framework.addScenarios(new Scenario(idx++, args( + "-XX:+UseG1GC" + ))); + } + if (GC.isSelectedErgonomically() && GC.Shenandoah.isSupported()) { + // Shenandoah nominally needs keep-alive barriers for Reference loads, + // but should not have them for refersTo. We only care to check that + // SATB barrier is not emitted. Shenandoah would also emit LRB barrier, + // which would false-negative the test. + framework.addScenarios(new Scenario(idx++, args( + "-XX:+UnlockDiagnosticVMOptions", + "-XX:ShenandoahGCMode=passive", + "-XX:+ShenandoahSATBBarrier", + "-XX:+UseShenandoahGC" + ))); + } + if (GC.isSelectedErgonomically() && GC.Z.isSupported()) { + // ZGC does not emit barriers in IR. + framework.addScenarios(new Scenario(idx++, args( + "-XX:+UseZGC" + ))); + } + framework.start(); + } + + static final Object REF = new Object(); + + static final SoftReference SR = new SoftReference<>(REF); + static final WeakReference WR = new WeakReference<>(REF); + static final PhantomReference PR = new PhantomReference<>(REF, null); + + // Verify that we are left with a single load of Reference.referent and no stores. + // This serves as a signal that no GC barriers are emitted in IR. + + @Test + @IR(counts = { IRNode.LOAD, "1" }) + @IR(failOn = { IRNode.STORE }) + public boolean soft_null() { + return SR.refersTo(null); + } + + @Test + @IR(counts = { IRNode.LOAD, "1" }) + @IR(failOn = { IRNode.STORE }) + public boolean soft_ref() { + return SR.refersTo(REF); + } + + @Test + @IR(counts = { IRNode.LOAD, "1" }) + @IR(failOn = { IRNode.STORE }) + public boolean weak_null() { + return WR.refersTo(null); + } + + @Test + @IR(counts = { IRNode.LOAD, "1" }) + @IR(failOn = { IRNode.STORE }) + public boolean weak_ref() { + return WR.refersTo(REF); + } + + @Test + @IR(counts = { IRNode.LOAD, "1" }) + @IR(failOn = { IRNode.STORE }) + public boolean phantom_null() { + return PR.refersTo(null); + } + + @Test + @IR(counts = { IRNode.LOAD, "1" }) + @IR(failOn = { IRNode.STORE }) + public boolean phantom_ref() { + return PR.refersTo(REF); + } + +} From 07dd725025a54035436a76ac4c0a8bb2b12e264a Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Wed, 31 Jul 2024 13:15:52 +0000 Subject: [PATCH 153/353] 8337418: Fix -Wzero-as-null-pointer-constant warnings in prims code Reviewed-by: dholmes, shade, jwaters, sspitsyn --- src/hotspot/share/prims/jni.cpp | 22 +++++++++++----------- src/hotspot/share/prims/jvm.cpp | 6 +++--- src/hotspot/share/prims/jvmtiExport.cpp | 6 +++--- src/hotspot/share/prims/jvmtiTrace.cpp | 2 +- src/hotspot/share/prims/methodHandles.cpp | 3 --- src/hotspot/share/prims/perf.cpp | 6 +++--- src/hotspot/share/prims/unsafe.cpp | 4 ++-- 7 files changed, 23 insertions(+), 26 deletions(-) diff --git a/src/hotspot/share/prims/jni.cpp b/src/hotspot/share/prims/jni.cpp index ae040d661380e..a91d7375761e2 100644 --- a/src/hotspot/share/prims/jni.cpp +++ b/src/hotspot/share/prims/jni.cpp @@ -1148,7 +1148,7 @@ JNI_ENTRY(ResultType, \ jni_Call##Result##Method(JNIEnv *env, jobject obj, jmethodID methodID, ...)) \ \ EntryProbe; \ - ResultType ret = 0;\ + ResultType ret{}; \ DT_RETURN_MARK_FOR(Result, Call##Result##Method, ResultType, \ (const ResultType&)ret);\ \ @@ -1203,7 +1203,7 @@ JNI_ENTRY(ResultType, \ jni_Call##Result##MethodV(JNIEnv *env, jobject obj, jmethodID methodID, va_list args)) \ \ EntryProbe;\ - ResultType ret = 0;\ + ResultType ret{}; \ DT_RETURN_MARK_FOR(Result, Call##Result##MethodV, ResultType, \ (const ResultType&)ret);\ \ @@ -1254,7 +1254,7 @@ DEFINE_CALLMETHODV(jdouble, Double, T_DOUBLE JNI_ENTRY(ResultType, \ jni_Call##Result##MethodA(JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args)) \ EntryProbe; \ - ResultType ret = 0;\ + ResultType ret{}; \ DT_RETURN_MARK_FOR(Result, Call##Result##MethodA, ResultType, \ (const ResultType&)ret);\ \ @@ -1546,7 +1546,7 @@ JNI_ENTRY(ResultType, \ jni_CallStatic##Result##Method(JNIEnv *env, jclass cls, jmethodID methodID, ...)) \ \ EntryProbe; \ - ResultType ret = 0;\ + ResultType ret{}; \ DT_RETURN_MARK_FOR(Result, CallStatic##Result##Method, ResultType, \ (const ResultType&)ret);\ \ @@ -1601,7 +1601,7 @@ JNI_ENTRY(ResultType, \ jni_CallStatic##Result##MethodV(JNIEnv *env, jclass cls, jmethodID methodID, va_list args)) \ \ EntryProbe; \ - ResultType ret = 0;\ + ResultType ret{}; \ DT_RETURN_MARK_FOR(Result, CallStatic##Result##MethodV, ResultType, \ (const ResultType&)ret);\ \ @@ -1657,7 +1657,7 @@ JNI_ENTRY(ResultType, \ jni_CallStatic##Result##MethodA(JNIEnv *env, jclass cls, jmethodID methodID, const jvalue *args)) \ \ EntryProbe; \ - ResultType ret = 0;\ + ResultType ret{}; \ DT_RETURN_MARK_FOR(Result, CallStatic##Result##MethodA, ResultType, \ (const ResultType&)ret);\ \ @@ -1750,7 +1750,7 @@ DT_RETURN_MARK_DECL(GetFieldID, jfieldID JNI_ENTRY(jfieldID, jni_GetFieldID(JNIEnv *env, jclass clazz, const char *name, const char *sig)) HOTSPOT_JNI_GETFIELDID_ENTRY(env, clazz, (char *) name, (char *) sig); - jfieldID ret = 0; + jfieldID ret = nullptr; DT_RETURN_MARK(GetFieldID, jfieldID, (const jfieldID&)ret); Klass* k = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(clazz)); @@ -3035,12 +3035,12 @@ extern "C" void* JNICALL jni_GetDirectBufferAddress(JNIEnv *env, jobject buf) if (!directBufferSupportInitializeEnded) { if (!initializeDirectBufferSupport(env, thread)) { - return 0; + return nullptr; } } if ((buf != nullptr) && (!env->IsInstanceOf(buf, directBufferClass))) { - return 0; + return nullptr; } ret = (void*)(intptr_t)env->GetLongField(buf, directBufferAddressField); @@ -3647,8 +3647,8 @@ static jint JNI_CreateJavaVM_inner(JavaVM **vm, void **penv, void *args) { } // Creation failed. We must reset vm_created - *vm = 0; - *(JNIEnv**)penv = 0; + *vm = nullptr; + *(JNIEnv**)penv = nullptr; // reset vm_created last to avoid race condition. Use OrderAccess to // control both compiler and architectural-based reordering. assert(vm_created == IN_PROGRESS, "must be"); diff --git a/src/hotspot/share/prims/jvm.cpp b/src/hotspot/share/prims/jvm.cpp index 6aabb65ca4023..4f63ebdf9d518 100644 --- a/src/hotspot/share/prims/jvm.cpp +++ b/src/hotspot/share/prims/jvm.cpp @@ -3747,7 +3747,7 @@ JVM_ENTRY(jobjectArray, JVM_DumpThreads(JNIEnv *env, jclass threadClass, jobject // Check if threads is null if (threads == nullptr) { - THROW_(vmSymbols::java_lang_NullPointerException(), 0); + THROW_NULL(vmSymbols::java_lang_NullPointerException()); } objArrayOop a = objArrayOop(JNIHandles::resolve_non_null(threads)); @@ -3755,13 +3755,13 @@ JVM_ENTRY(jobjectArray, JVM_DumpThreads(JNIEnv *env, jclass threadClass, jobject int num_threads = ah->length(); // check if threads is non-empty array if (num_threads == 0) { - THROW_(vmSymbols::java_lang_IllegalArgumentException(), 0); + THROW_NULL(vmSymbols::java_lang_IllegalArgumentException()); } // check if threads is not an array of objects of Thread class Klass* k = ObjArrayKlass::cast(ah->klass())->element_klass(); if (k != vmClasses::Thread_klass()) { - THROW_(vmSymbols::java_lang_IllegalArgumentException(), 0); + THROW_NULL(vmSymbols::java_lang_IllegalArgumentException()); } ResourceMark rm(THREAD); diff --git a/src/hotspot/share/prims/jvmtiExport.cpp b/src/hotspot/share/prims/jvmtiExport.cpp index c2b6d27986b94..f79116f5ebeb0 100644 --- a/src/hotspot/share/prims/jvmtiExport.cpp +++ b/src/hotspot/share/prims/jvmtiExport.cpp @@ -2068,7 +2068,7 @@ void JvmtiExport::post_exception_throw(JavaThread *thread, Method* method, addre jmethodID catch_jmethodID; if (current_bci < 0) { - catch_jmethodID = 0; + catch_jmethodID = nullptr; current_bci = 0; } else { catch_jmethodID = jem.to_jmethodID(current_mh); @@ -2105,8 +2105,8 @@ void JvmtiExport::notice_unwind_due_to_exception(JavaThread *thread, Method* met JvmtiTrace::safe_get_thread_name(thread), (mh() == nullptr) ? "null" : mh()->klass_name()->as_C_string(), (mh() == nullptr) ? "null" : mh()->name()->as_C_string(), - location==0? "no location:" : "", - location==0? 0 : location - mh()->code_base(), + location == nullptr ? "no location:" : "", + location == nullptr ? 0 : location - mh()->code_base(), in_handler_frame? "in handler frame" : "not handler frame" )); if (state->is_exception_detected()) { diff --git a/src/hotspot/share/prims/jvmtiTrace.cpp b/src/hotspot/share/prims/jvmtiTrace.cpp index 002f59957eab7..c5fb95c931b93 100644 --- a/src/hotspot/share/prims/jvmtiTrace.cpp +++ b/src/hotspot/share/prims/jvmtiTrace.cpp @@ -261,7 +261,7 @@ void JvmtiTrace::shutdown() { const char* JvmtiTrace::enum_name(const char** names, const jint* values, jint value) { - for (int index = 0; names[index] != 0; ++index) { + for (int index = 0; names[index] != nullptr; ++index) { if (values[index] == value) { return names[index]; } diff --git a/src/hotspot/share/prims/methodHandles.cpp b/src/hotspot/share/prims/methodHandles.cpp index fd10f0723bff0..473ac396997bd 100644 --- a/src/hotspot/share/prims/methodHandles.cpp +++ b/src/hotspot/share/prims/methodHandles.cpp @@ -436,7 +436,6 @@ Symbol* MethodHandles::signature_polymorphic_intrinsic_name(vmIntrinsics::ID iid case vmIntrinsics::_linkToNative: return vmSymbols::linkToNative_name(); default: fatal("unexpected intrinsic id: %d %s", vmIntrinsics::as_int(iid), vmIntrinsics::name_at(iid)); - return 0; } } @@ -449,7 +448,6 @@ Bytecodes::Code MethodHandles::signature_polymorphic_intrinsic_bytecode(vmIntrin case vmIntrinsics::_invokeBasic: return Bytecodes::_invokehandle; default: fatal("unexpected id: (%d) %s", (uint)id, vmIntrinsics::name_at(id)); - return Bytecodes::_illegal; } } @@ -463,7 +461,6 @@ int MethodHandles::signature_polymorphic_intrinsic_ref_kind(vmIntrinsics::ID iid case vmIntrinsics::_linkToInterface: return JVM_REF_invokeInterface; default: fatal("unexpected intrinsic id: %d %s", vmIntrinsics::as_int(iid), vmIntrinsics::name_at(iid)); - return 0; } } diff --git a/src/hotspot/share/prims/perf.cpp b/src/hotspot/share/prims/perf.cpp index f10854b529459..9ff831dded9fa 100644 --- a/src/hotspot/share/prims/perf.cpp +++ b/src/hotspot/share/prims/perf.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -68,7 +68,7 @@ PERF_ENTRY(jobject, Perf_Attach(JNIEnv *env, jobject unused, int vmid)) PerfWrapper("Perf_Attach"); - char* address = 0; + char* address = nullptr; size_t capacity = 0; // attach to the PerfData memory region for the specified VM @@ -90,7 +90,7 @@ PERF_ENTRY(void, Perf_Detach(JNIEnv *env, jobject unused, jobject buffer)) return; } - void* address = 0; + void* address = nullptr; jlong capacity = 0; // get buffer address and capacity diff --git a/src/hotspot/share/prims/unsafe.cpp b/src/hotspot/share/prims/unsafe.cpp index 942d9100c29ea..1be157b2e44eb 100644 --- a/src/hotspot/share/prims/unsafe.cpp +++ b/src/hotspot/share/prims/unsafe.cpp @@ -652,7 +652,7 @@ static jclass Unsafe_DefineClass_impl(JNIEnv *env, jstring name, jbyteArray data jbyte *body; char *utfName = nullptr; - jclass result = 0; + jclass result = nullptr; char buf[128]; assert(data != nullptr, "Class bytes must not be null"); @@ -665,7 +665,7 @@ static jclass Unsafe_DefineClass_impl(JNIEnv *env, jstring name, jbyteArray data body = NEW_C_HEAP_ARRAY_RETURN_NULL(jbyte, length, mtInternal); if (body == nullptr) { throw_new(env, "java/lang/OutOfMemoryError"); - return 0; + return nullptr; } env->GetByteArrayRegion(data, offset, length, body); From 61386c199a3b29457c002ad31a23990b7f6f88fd Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Wed, 31 Jul 2024 13:17:30 +0000 Subject: [PATCH 154/353] 8337523: Fix -Wzero-as-null-pointer-constant warnings in jvmci code Reviewed-by: chagedorn, shade --- src/hotspot/share/jvmci/jvmciCodeInstaller.cpp | 4 ++-- src/hotspot/share/jvmci/jvmciCompilerToVM.cpp | 4 ++-- src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp | 2 +- src/hotspot/share/jvmci/jvmciRuntime.cpp | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp b/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp index c62257bd23b1c..79bc97f53ac6b 100644 --- a/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp +++ b/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -664,7 +664,7 @@ JVMCI::CodeInstallResult CodeInstaller::install_runtime_stub(CodeBlob*& cb, GrowableArray *stubs_to_free = nullptr; #ifdef ASSERT const char* val = Arguments::PropertyList_get_value(Arguments::system_properties(), "test.jvmci.forceRuntimeStubAllocFail"); - if (val != nullptr && strstr(name , val) != 0) { + if (val != nullptr && strstr(name , val) != nullptr) { stubs_to_free = new GrowableArray(); JVMCI_event_1("forcing allocation of %s in code cache to fail", name); } diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp index fb49e9baca2b9..5a9b18fc4d3db 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp @@ -424,7 +424,7 @@ C2V_VMENTRY_NULL(jobject, getResolvedJavaMethod, (JNIEnv* env, jobject, jobject C2V_VMENTRY_NULL(jobject, getConstantPool, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass_or_method), jboolean is_klass)) ConstantPool* cp = nullptr; - if (UNPACK_PAIR(address, klass_or_method) == 0) { + if (UNPACK_PAIR(address, klass_or_method) == nullptr) { JVMCI_THROW_NULL(NullPointerException); } if (!is_klass) { @@ -1098,7 +1098,7 @@ C2V_END C2V_VMENTRY_0(jlong, getMaxCallTargetOffset, (JNIEnv* env, jobject, jlong addr)) address target_addr = (address) addr; - if (target_addr != 0x0) { + if (target_addr != nullptr) { int64_t off_low = (int64_t)target_addr - ((int64_t)CodeCache::low_bound() + sizeof(int)); int64_t off_high = (int64_t)target_addr - ((int64_t)CodeCache::high_bound() + sizeof(int)); return MAX2(ABS(off_low), ABS(off_high)); diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp index f1028b4b2bb7e..2116133e56e97 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp @@ -240,7 +240,7 @@ void CompilerToVM::Data::initialize(JVMCI_TRAPS) { cardtable_shift = CardTable::card_shift(); } else { // No card mark barriers - cardtable_start_address = 0; + cardtable_start_address = nullptr; cardtable_shift = 0; } diff --git a/src/hotspot/share/jvmci/jvmciRuntime.cpp b/src/hotspot/share/jvmci/jvmciRuntime.cpp index 371a6540898b3..ad0430787aa13 100644 --- a/src/hotspot/share/jvmci/jvmciRuntime.cpp +++ b/src/hotspot/share/jvmci/jvmciRuntime.cpp @@ -628,7 +628,7 @@ JRT_LEAF(oopDesc*, JVMCIRuntime::load_and_clear_exception(JavaThread* thread)) oop exception = thread->exception_oop(); assert(exception != nullptr, "npe"); thread->set_exception_oop(nullptr); - thread->set_exception_pc(0); + thread->set_exception_pc(nullptr); return exception; JRT_END From 7121d71b516b415c7c11e3643731cd32d4057aa6 Mon Sep 17 00:00:00 2001 From: Gui Cao Date: Wed, 31 Jul 2024 14:43:35 +0000 Subject: [PATCH 155/353] 8337421: RISC-V: client VM build failure after JDK-8335191 Reviewed-by: fyang, mli --- src/hotspot/cpu/riscv/stubGenerator_riscv.cpp | 12 +- src/hotspot/cpu/riscv/vm_version_riscv.cpp | 197 +++++++++--------- src/hotspot/cpu/riscv/vm_version_riscv.hpp | 2 + 3 files changed, 107 insertions(+), 104 deletions(-) diff --git a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp index 2a9faee7e2fdf..f78d7261e40a5 100644 --- a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp +++ b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp @@ -5936,7 +5936,6 @@ static const int64_t right_3_bits = right_n_bits(3); } void generate_compiler_stubs() { -#if COMPILER2_OR_JVMCI #ifdef COMPILER2 if (UseMulAddIntrinsic) { StubRoutines::_mulAdd = generate_mulAdd(); @@ -5970,7 +5969,6 @@ static const int64_t right_3_bits = right_n_bits(3); StubRoutines::_bigIntegerLeftShiftWorker = generate_bigIntegerLeftShift(); StubRoutines::_bigIntegerRightShiftWorker = generate_bigIntegerRightShift(); } -#endif // COMPILER2 if (UseSHA256Intrinsics) { Sha2Generator sha2(_masm, this); @@ -5984,10 +5982,6 @@ static const int64_t right_3_bits = right_n_bits(3); StubRoutines::_sha512_implCompressMB = sha2.generate_sha512_implCompress(true); } - generate_compare_long_strings(); - - generate_string_indexof_stubs(); - if (UseMD5Intrinsics) { StubRoutines::_md5_implCompress = generate_md5_implCompress(false, "md5_implCompress"); StubRoutines::_md5_implCompressMB = generate_md5_implCompress(true, "md5_implCompressMB"); @@ -6006,7 +6000,11 @@ static const int64_t right_3_bits = right_n_bits(3); StubRoutines::_updateBytesAdler32 = generate_updateBytesAdler32(); } -#endif // COMPILER2_OR_JVMCI + generate_compare_long_strings(); + + generate_string_indexof_stubs(); + +#endif // COMPILER2 } public: diff --git a/src/hotspot/cpu/riscv/vm_version_riscv.cpp b/src/hotspot/cpu/riscv/vm_version_riscv.cpp index d5a74d186062f..ac2d6cde1a227 100644 --- a/src/hotspot/cpu/riscv/vm_version_riscv.cpp +++ b/src/hotspot/cpu/riscv/vm_version_riscv.cpp @@ -58,6 +58,13 @@ void VM_Version::useRVA23U64Profile() { } void VM_Version::initialize() { + common_initialize(); +#ifdef COMPILER2 + c2_initialize(); +#endif // COMPILER2 +} + +void VM_Version::common_initialize() { _supports_atomic_getset4 = true; _supports_atomic_getadd4 = true; _supports_atomic_getset8 = true; @@ -152,10 +159,6 @@ void VM_Version::initialize() { FLAG_SET_DEFAULT(UseVectorizedMismatchIntrinsic, false); } - if (FLAG_IS_DEFAULT(UseMD5Intrinsics)) { - FLAG_SET_DEFAULT(UseMD5Intrinsics, true); - } - if (FLAG_IS_DEFAULT(UsePoly1305Intrinsics)) { FLAG_SET_DEFAULT(UsePoly1305Intrinsics, true); } @@ -230,15 +233,105 @@ void VM_Version::initialize() { _initial_vector_length = cpu_vector_length(); } } +} #ifdef COMPILER2 - c2_initialize(); -#endif // COMPILER2 +void VM_Version::c2_initialize() { + if (UseCMoveUnconditionally) { + FLAG_SET_DEFAULT(UseCMoveUnconditionally, false); + } + + if (ConditionalMoveLimit > 0) { + FLAG_SET_DEFAULT(ConditionalMoveLimit, 0); + } - // NOTE: Make sure codes dependent on UseRVV are put after c2_initialize(), + if (!UseRVV) { + FLAG_SET_DEFAULT(MaxVectorSize, 0); + FLAG_SET_DEFAULT(UseRVVForBigIntegerShiftIntrinsics, false); + } else { + if (!FLAG_IS_DEFAULT(MaxVectorSize) && MaxVectorSize != _initial_vector_length) { + warning("Current system does not support RVV vector length for MaxVectorSize %d. Set MaxVectorSize to %d", + (int)MaxVectorSize, _initial_vector_length); + } + MaxVectorSize = _initial_vector_length; + if (MaxVectorSize < 16) { + warning("RVV does not support vector length less than 16 bytes. Disabling RVV."); + UseRVV = false; + FLAG_SET_DEFAULT(MaxVectorSize, 0); + } + } + + // NOTE: Make sure codes dependent on UseRVV are put after MaxVectorSize initialize, // as there are extra checks inside it which could disable UseRVV // in some situations. + if (FLAG_IS_DEFAULT(UseVectorizedHashCodeIntrinsic)) { + FLAG_SET_DEFAULT(UseVectorizedHashCodeIntrinsic, true); + } + + if (!UseZicbop) { + if (!FLAG_IS_DEFAULT(AllocatePrefetchStyle)) { + warning("Zicbop is not available on this CPU"); + } + FLAG_SET_DEFAULT(AllocatePrefetchStyle, 0); + } else { + // Limit AllocatePrefetchDistance so that it does not exceed the + // static constraint of 512 defined in runtime/globals.hpp. + if (FLAG_IS_DEFAULT(AllocatePrefetchDistance)) { + FLAG_SET_DEFAULT(AllocatePrefetchDistance, MIN2(512, 3 * (int)CacheLineSize)); + } + if (FLAG_IS_DEFAULT(AllocatePrefetchStepSize)) { + FLAG_SET_DEFAULT(AllocatePrefetchStepSize, (int)CacheLineSize); + } + if (FLAG_IS_DEFAULT(PrefetchScanIntervalInBytes)) { + FLAG_SET_DEFAULT(PrefetchScanIntervalInBytes, 3 * (int)CacheLineSize); + } + if (FLAG_IS_DEFAULT(PrefetchCopyIntervalInBytes)) { + FLAG_SET_DEFAULT(PrefetchCopyIntervalInBytes, 3 * (int)CacheLineSize); + } + + if (PrefetchCopyIntervalInBytes != -1 && + ((PrefetchCopyIntervalInBytes & 7) || (PrefetchCopyIntervalInBytes >= 32768))) { + warning("PrefetchCopyIntervalInBytes must be -1, or a multiple of 8 and < 32768"); + PrefetchCopyIntervalInBytes &= ~7; + if (PrefetchCopyIntervalInBytes >= 32768) { + PrefetchCopyIntervalInBytes = 32760; + } + } + if (AllocatePrefetchDistance !=-1 && (AllocatePrefetchDistance & 7)) { + warning("AllocatePrefetchDistance must be multiple of 8"); + AllocatePrefetchDistance &= ~7; + } + if (AllocatePrefetchStepSize & 7) { + warning("AllocatePrefetchStepSize must be multiple of 8"); + AllocatePrefetchStepSize &= ~7; + } + } + + if (FLAG_IS_DEFAULT(UseMulAddIntrinsic)) { + FLAG_SET_DEFAULT(UseMulAddIntrinsic, true); + } + + if (FLAG_IS_DEFAULT(UseMultiplyToLenIntrinsic)) { + FLAG_SET_DEFAULT(UseMultiplyToLenIntrinsic, true); + } + + if (FLAG_IS_DEFAULT(UseSquareToLenIntrinsic)) { + FLAG_SET_DEFAULT(UseSquareToLenIntrinsic, true); + } + + if (FLAG_IS_DEFAULT(UseMontgomeryMultiplyIntrinsic)) { + FLAG_SET_DEFAULT(UseMontgomeryMultiplyIntrinsic, true); + } + + if (FLAG_IS_DEFAULT(UseMontgomerySquareIntrinsic)) { + FLAG_SET_DEFAULT(UseMontgomerySquareIntrinsic, true); + } + + if (FLAG_IS_DEFAULT(UseMD5Intrinsics)) { + FLAG_SET_DEFAULT(UseMD5Intrinsics, true); + } + // Adler32 if (UseRVV) { if (FLAG_IS_DEFAULT(UseAdler32Intrinsics)) { @@ -332,96 +425,6 @@ void VM_Version::initialize() { FLAG_SET_DEFAULT(UseSHA, false); } } - -#ifdef COMPILER2 -void VM_Version::c2_initialize() { - if (UseCMoveUnconditionally) { - FLAG_SET_DEFAULT(UseCMoveUnconditionally, false); - } - - if (ConditionalMoveLimit > 0) { - FLAG_SET_DEFAULT(ConditionalMoveLimit, 0); - } - - if (!UseRVV) { - FLAG_SET_DEFAULT(MaxVectorSize, 0); - FLAG_SET_DEFAULT(UseRVVForBigIntegerShiftIntrinsics, false); - } else { - if (!FLAG_IS_DEFAULT(MaxVectorSize) && MaxVectorSize != _initial_vector_length) { - warning("Current system does not support RVV vector length for MaxVectorSize %d. Set MaxVectorSize to %d", - (int)MaxVectorSize, _initial_vector_length); - } - MaxVectorSize = _initial_vector_length; - if (MaxVectorSize < 16) { - warning("RVV does not support vector length less than 16 bytes. Disabling RVV."); - UseRVV = false; - FLAG_SET_DEFAULT(MaxVectorSize, 0); - } - } - - if (FLAG_IS_DEFAULT(UseVectorizedHashCodeIntrinsic)) { - FLAG_SET_DEFAULT(UseVectorizedHashCodeIntrinsic, true); - } - - if (!UseZicbop) { - if (!FLAG_IS_DEFAULT(AllocatePrefetchStyle)) { - warning("Zicbop is not available on this CPU"); - } - FLAG_SET_DEFAULT(AllocatePrefetchStyle, 0); - } else { - // Limit AllocatePrefetchDistance so that it does not exceed the - // static constraint of 512 defined in runtime/globals.hpp. - if (FLAG_IS_DEFAULT(AllocatePrefetchDistance)) { - FLAG_SET_DEFAULT(AllocatePrefetchDistance, MIN2(512, 3 * (int)CacheLineSize)); - } - if (FLAG_IS_DEFAULT(AllocatePrefetchStepSize)) { - FLAG_SET_DEFAULT(AllocatePrefetchStepSize, (int)CacheLineSize); - } - if (FLAG_IS_DEFAULT(PrefetchScanIntervalInBytes)) { - FLAG_SET_DEFAULT(PrefetchScanIntervalInBytes, 3 * (int)CacheLineSize); - } - if (FLAG_IS_DEFAULT(PrefetchCopyIntervalInBytes)) { - FLAG_SET_DEFAULT(PrefetchCopyIntervalInBytes, 3 * (int)CacheLineSize); - } - - if (PrefetchCopyIntervalInBytes != -1 && - ((PrefetchCopyIntervalInBytes & 7) || (PrefetchCopyIntervalInBytes >= 32768))) { - warning("PrefetchCopyIntervalInBytes must be -1, or a multiple of 8 and < 32768"); - PrefetchCopyIntervalInBytes &= ~7; - if (PrefetchCopyIntervalInBytes >= 32768) { - PrefetchCopyIntervalInBytes = 32760; - } - } - if (AllocatePrefetchDistance !=-1 && (AllocatePrefetchDistance & 7)) { - warning("AllocatePrefetchDistance must be multiple of 8"); - AllocatePrefetchDistance &= ~7; - } - if (AllocatePrefetchStepSize & 7) { - warning("AllocatePrefetchStepSize must be multiple of 8"); - AllocatePrefetchStepSize &= ~7; - } - } - - if (FLAG_IS_DEFAULT(UseMulAddIntrinsic)) { - FLAG_SET_DEFAULT(UseMulAddIntrinsic, true); - } - - if (FLAG_IS_DEFAULT(UseMultiplyToLenIntrinsic)) { - FLAG_SET_DEFAULT(UseMultiplyToLenIntrinsic, true); - } - - if (FLAG_IS_DEFAULT(UseSquareToLenIntrinsic)) { - FLAG_SET_DEFAULT(UseSquareToLenIntrinsic, true); - } - - if (FLAG_IS_DEFAULT(UseMontgomeryMultiplyIntrinsic)) { - FLAG_SET_DEFAULT(UseMontgomeryMultiplyIntrinsic, true); - } - - if (FLAG_IS_DEFAULT(UseMontgomerySquareIntrinsic)) { - FLAG_SET_DEFAULT(UseMontgomerySquareIntrinsic, true); - } -} #endif // COMPILER2 void VM_Version::initialize_cpu_information(void) { diff --git a/src/hotspot/cpu/riscv/vm_version_riscv.hpp b/src/hotspot/cpu/riscv/vm_version_riscv.hpp index 9556e2dc9ad5d..bd4bfe86d9bf7 100644 --- a/src/hotspot/cpu/riscv/vm_version_riscv.hpp +++ b/src/hotspot/cpu/riscv/vm_version_riscv.hpp @@ -264,6 +264,8 @@ class VM_Version : public Abstract_VM_Version { static uint32_t cpu_vector_length(); static uint32_t _initial_vector_length; + static void common_initialize(); + #ifdef COMPILER2 static void c2_initialize(); #endif // COMPILER2 From f2ba2ebbcaba2784b24e7fe94c235ca652f7c9a2 Mon Sep 17 00:00:00 2001 From: Jasmine Karthikeyan Date: Wed, 31 Jul 2024 15:16:21 +0000 Subject: [PATCH 156/353] 8331090: Run Ideal_minmax before de-canonicalizing CMoves Reviewed-by: thartmann, epeter --- src/hotspot/share/opto/movenode.cpp | 13 +++++--- .../compiler/c2/irTests/TestIfMinMax.java | 32 +++++++++++++++++-- 2 files changed, 37 insertions(+), 8 deletions(-) diff --git a/src/hotspot/share/opto/movenode.cpp b/src/hotspot/share/opto/movenode.cpp index eb0a914b99433..dc65afff26f0f 100644 --- a/src/hotspot/share/opto/movenode.cpp +++ b/src/hotspot/share/opto/movenode.cpp @@ -91,17 +91,20 @@ Node *CMoveNode::Ideal(PhaseGVN *phase, bool can_reshape) { phase->type(in(IfTrue)) == Type::TOP) { return nullptr; } - // Canonicalize the node by moving constants to the right input. - if (in(Condition)->is_Bool() && phase->type(in(IfFalse))->singleton() && !phase->type(in(IfTrue))->singleton()) { - BoolNode* b = in(Condition)->as_Bool()->negate(phase); - return make(in(Control), phase->transform(b), in(IfTrue), in(IfFalse), _type); - } + // Check for Min/Max patterns. This is called before constants are pushed to the right input, as that transform can + // make BoolTests non-canonical. Node* minmax = Ideal_minmax(phase, this); if (minmax != nullptr) { return minmax; } + // Canonicalize the node by moving constants to the right input. + if (in(Condition)->is_Bool() && phase->type(in(IfFalse))->singleton() && !phase->type(in(IfTrue))->singleton()) { + BoolNode* b = in(Condition)->as_Bool()->negate(phase); + return make(in(Control), phase->transform(b), in(IfTrue), in(IfFalse), _type); + } + return nullptr; } diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestIfMinMax.java b/test/hotspot/jtreg/compiler/c2/irTests/TestIfMinMax.java index 41402036aea0e..e232895257a48 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/TestIfMinMax.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestIfMinMax.java @@ -30,7 +30,7 @@ /* * @test - * @bug 8324655 8329797 + * @bug 8324655 8329797 8331090 * @key randomness * @summary Test that if expressions are properly folded into min/max nodes * @requires os.arch != "riscv64" @@ -505,7 +505,27 @@ public void checkTestMinLongVector(Object[] vals) { } } - @Run(test = { "testMinI1", "testMinI2", "testMaxI1", "testMaxI2", "testMinI1E", "testMinI2E", "testMaxI1E", "testMaxI2E" }) + @Test + @IR(failOn = { IRNode.IF }, counts = { IRNode.MIN_I, "1" }) + public int testMinIConst(int a) { + if (a > 65535) { + a = 65535; + } + + return a; + } + + @Test + @IR(phase = { CompilePhase.BEFORE_MACRO_EXPANSION }, failOn = { IRNode.IF }, counts = { IRNode.MIN_L, "1" }) + public long testMinLConst(long a) { + if (a > 65535) { + a = 65535; + } + + return a; + } + + @Run(test = { "testMinI1", "testMinI2", "testMaxI1", "testMaxI2", "testMinI1E", "testMinI2E", "testMaxI1E", "testMaxI2E", "testMinIConst" }) public void runTestIntegers() { testIntegers(10, 20); testIntegers(20, 10); @@ -526,9 +546,12 @@ public void testIntegers(int a, int b) { Asserts.assertEQ(a >= b ? b : a, testMinI2E(a, b)); Asserts.assertEQ(a >= b ? a : b, testMaxI1E(a, b)); Asserts.assertEQ(a <= b ? b : a, testMaxI2E(a, b)); + + Asserts.assertEQ(a > 65535 ? 65535 : a, testMinIConst(a)); + Asserts.assertEQ(b > 65535 ? 65535 : b, testMinIConst(b)); } - @Run(test = { "testMinL1", "testMinL2", "testMaxL1", "testMaxL2", "testMinL1E", "testMinL2E", "testMaxL1E", "testMaxL2E" }) + @Run(test = { "testMinL1", "testMinL2", "testMaxL1", "testMaxL2", "testMinL1E", "testMinL2E", "testMaxL1E", "testMaxL2E", "testMinLConst" }) public void runTestLongs() { testLongs(10, 20); testLongs(20, 10); @@ -551,5 +574,8 @@ public void testLongs(long a, long b) { Asserts.assertEQ(a >= b ? b : a, testMinL2E(a, b)); Asserts.assertEQ(a >= b ? a : b, testMaxL1E(a, b)); Asserts.assertEQ(a <= b ? b : a, testMaxL2E(a, b)); + + Asserts.assertEQ(a > 65535L ? 65535L : a, testMinLConst(a)); + Asserts.assertEQ(b > 65535L ? 65535L : b, testMinLConst(b)); } } From fdb4350fcecef1915cdbc27ece24153a1b6c884d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Lund=C3=A9n?= Date: Wed, 31 Jul 2024 16:05:42 +0000 Subject: [PATCH 157/353] 8324345: Stack overflow during C2 compilation when splitting memory phi Reviewed-by: thartmann, kvn --- src/hotspot/share/opto/escape.cpp | 15 ++++-- src/hotspot/share/opto/escape.hpp | 6 +-- .../TestFindInstMemRecursion.java | 49 +++++++++++++++++++ .../VectorReplicateLongSpecialImmTest.java | 2 +- 4 files changed, 63 insertions(+), 9 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/escapeAnalysis/TestFindInstMemRecursion.java diff --git a/src/hotspot/share/opto/escape.cpp b/src/hotspot/share/opto/escape.cpp index 2ca722148b61e..eb6887f11baf6 100644 --- a/src/hotspot/share/opto/escape.cpp +++ b/src/hotspot/share/opto/escape.cpp @@ -3879,7 +3879,7 @@ PhiNode *ConnectionGraph::create_split_phi(PhiNode *orig_phi, int alias_idx, Gro // Return a new version of Memory Phi "orig_phi" with the inputs having the // specified alias index. // -PhiNode *ConnectionGraph::split_memory_phi(PhiNode *orig_phi, int alias_idx, GrowableArray &orig_phi_worklist) { +PhiNode *ConnectionGraph::split_memory_phi(PhiNode *orig_phi, int alias_idx, GrowableArray &orig_phi_worklist, uint rec_depth) { assert(alias_idx != Compile::AliasIdxBot, "can't split out bottom memory"); Compile *C = _compile; PhaseGVN* igvn = _igvn; @@ -3895,7 +3895,7 @@ PhiNode *ConnectionGraph::split_memory_phi(PhiNode *orig_phi, int alias_idx, Gro bool finished = false; while(!finished) { while (idx < phi->req()) { - Node *mem = find_inst_mem(phi->in(idx), alias_idx, orig_phi_worklist); + Node *mem = find_inst_mem(phi->in(idx), alias_idx, orig_phi_worklist, rec_depth + 1); if (mem != nullptr && mem->is_Phi()) { PhiNode *newphi = create_split_phi(mem->as_Phi(), alias_idx, orig_phi_worklist, new_phi_created); if (new_phi_created) { @@ -4037,7 +4037,12 @@ void ConnectionGraph::move_inst_mem(Node* n, GrowableArray &orig_phi // Search memory chain of "mem" to find a MemNode whose address // is the specified alias index. // -Node* ConnectionGraph::find_inst_mem(Node *orig_mem, int alias_idx, GrowableArray &orig_phis) { +#define FIND_INST_MEM_RECURSION_DEPTH_LIMIT 1000 +Node* ConnectionGraph::find_inst_mem(Node *orig_mem, int alias_idx, GrowableArray &orig_phis, uint rec_depth) { + if (rec_depth > FIND_INST_MEM_RECURSION_DEPTH_LIMIT) { + _compile->record_failure(_invocation > 0 ? C2Compiler::retry_no_iterative_escape_analysis() : C2Compiler::retry_no_escape_analysis()); + return nullptr; + } if (orig_mem == nullptr) { return orig_mem; } @@ -4111,7 +4116,7 @@ Node* ConnectionGraph::find_inst_mem(Node *orig_mem, int alias_idx, GrowableArra if (result == mmem->base_memory()) { // Didn't find instance memory, search through general slice recursively. result = mmem->memory_at(C->get_general_index(alias_idx)); - result = find_inst_mem(result, alias_idx, orig_phis); + result = find_inst_mem(result, alias_idx, orig_phis, rec_depth + 1); if (C->failing()) { return nullptr; } @@ -4179,7 +4184,7 @@ Node* ConnectionGraph::find_inst_mem(Node *orig_mem, int alias_idx, GrowableArra orig_phis.append_if_missing(mphi); } else if (C->get_alias_index(t) != alias_idx) { // Create a new Phi with the specified alias index type. - result = split_memory_phi(mphi, alias_idx, orig_phis); + result = split_memory_phi(mphi, alias_idx, orig_phis, rec_depth + 1); } } // the result is either MemNode, PhiNode, InitializeNode. diff --git a/src/hotspot/share/opto/escape.hpp b/src/hotspot/share/opto/escape.hpp index 658c8f6e8feca..32e70be219ab0 100644 --- a/src/hotspot/share/opto/escape.hpp +++ b/src/hotspot/share/opto/escape.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -549,10 +549,10 @@ class ConnectionGraph: public ArenaObj { bool split_AddP(Node *addp, Node *base); PhiNode *create_split_phi(PhiNode *orig_phi, int alias_idx, GrowableArray &orig_phi_worklist, bool &new_created); - PhiNode *split_memory_phi(PhiNode *orig_phi, int alias_idx, GrowableArray &orig_phi_worklist); + PhiNode *split_memory_phi(PhiNode *orig_phi, int alias_idx, GrowableArray &orig_phi_worklist, uint rec_depth); void move_inst_mem(Node* n, GrowableArray &orig_phis); - Node* find_inst_mem(Node* mem, int alias_idx,GrowableArray &orig_phi_worklist); + Node* find_inst_mem(Node* mem, int alias_idx,GrowableArray &orig_phi_worklist, uint rec_depth = 0); Node* step_through_mergemem(MergeMemNode *mmem, int alias_idx, const TypeOopPtr *toop); Node_Array _node_map; // used for bookkeeping during type splitting diff --git a/test/hotspot/jtreg/compiler/escapeAnalysis/TestFindInstMemRecursion.java b/test/hotspot/jtreg/compiler/escapeAnalysis/TestFindInstMemRecursion.java new file mode 100644 index 0000000000000..90a5ff92cd3ac --- /dev/null +++ b/test/hotspot/jtreg/compiler/escapeAnalysis/TestFindInstMemRecursion.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8324345 + * @summary Ensure that ConnectionGraph::find_inst_mem does not cause a stack + * overflow. + * + * @run main/othervm -Xcomp -XX:CompileThreshold=10 -XX:-TieredCompilation + * -XX:CompileCommand=CompileOnly,javax.swing.plaf.basic.BasicLookAndFeel::initComponentDefaults + * -XX:CompileCommand=MemLimit,*.*,0 + * compiler.escapeAnalysis.TestFindInstMemRecursion + * + */ + +package compiler.escapeAnalysis; + +import javax.swing.*; +import javax.swing.plaf.metal.*; + +public class TestFindInstMemRecursion { + public static void main(String[] args) throws Exception { + LookAndFeel lookAndFeel = new MetalLookAndFeel(); + for (int i = 0; i < 20; ++i) { + UIManager.setLookAndFeel(lookAndFeel); + } + } +} diff --git a/test/hotspot/jtreg/compiler/vectorapi/VectorReplicateLongSpecialImmTest.java b/test/hotspot/jtreg/compiler/vectorapi/VectorReplicateLongSpecialImmTest.java index e2ad716d1fa95..b885abb632a44 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/VectorReplicateLongSpecialImmTest.java +++ b/test/hotspot/jtreg/compiler/vectorapi/VectorReplicateLongSpecialImmTest.java @@ -36,7 +36,7 @@ * @library /test/lib * @requires os.arch == "aarch64" * @modules jdk.incubator.vector - * @run testng/othervm -XX:UseSVE=0 -XX:-TieredCompilation -XX:CompileThreshold=100 compiler.vectorapi.VectorReplicateLongSpecialImmTest + * @run testng/othervm -XX:UseSVE=0 -XX:-TieredCompilation -XX:CompileThreshold=100 -XX:+IgnoreUnrecognizedVMOptions -XX:CompileCommand=MemLimit,*.*,0 compiler.vectorapi.VectorReplicateLongSpecialImmTest */ public class VectorReplicateLongSpecialImmTest { From e4c7850c177899a5da6f5050cb0647a6e1a75d31 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Wed, 31 Jul 2024 16:24:07 +0000 Subject: [PATCH 158/353] 8337027: Parallel: Obsolete BaseFootPrintEstimate Reviewed-by: tschatzl, kbarrett --- src/hotspot/share/gc/parallel/psAdaptiveSizePolicy.cpp | 10 +++------- src/hotspot/share/gc/parallel/psAdaptiveSizePolicy.hpp | 5 ++--- .../share/gc/parallel/psGCAdaptivePolicyCounters.cpp | 7 +------ .../share/gc/parallel/psGCAdaptivePolicyCounters.hpp | 8 +------- src/hotspot/share/gc/shared/gc_globals.hpp | 4 ---- src/hotspot/share/runtime/arguments.cpp | 5 ++--- .../classes/sun/jvmstat/perfdata/resources/aliasmap | 2 -- 7 files changed, 9 insertions(+), 32 deletions(-) diff --git a/src/hotspot/share/gc/parallel/psAdaptiveSizePolicy.cpp b/src/hotspot/share/gc/parallel/psAdaptiveSizePolicy.cpp index cfdb7e9eb29dd..288a21fd35d05 100644 --- a/src/hotspot/share/gc/parallel/psAdaptiveSizePolicy.cpp +++ b/src/hotspot/share/gc/parallel/psAdaptiveSizePolicy.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -205,8 +205,6 @@ void PSAdaptiveSizePolicy::compute_eden_space_size( bool is_full_gc) { // Update statistics - // Time statistics are updated as we go, update footprint stats here - _avg_base_footprint->sample(BaseFootPrintEstimate); avg_young_live()->sample(young_live); avg_eden_live()->sample(eden_live); @@ -363,8 +361,7 @@ void PSAdaptiveSizePolicy::compute_eden_space_size( log_debug(gc, ergo)("Live_space: " SIZE_FORMAT " free_space: " SIZE_FORMAT, live_space(), free_space()); - log_trace(gc, ergo)("Base_footprint: " SIZE_FORMAT " avg_young_live: " SIZE_FORMAT " avg_old_live: " SIZE_FORMAT, - (size_t)_avg_base_footprint->average(), + log_trace(gc, ergo)("avg_young_live: " SIZE_FORMAT " avg_old_live: " SIZE_FORMAT, (size_t)avg_young_live()->average(), (size_t)avg_old_live()->average()); @@ -535,8 +532,7 @@ void PSAdaptiveSizePolicy::compute_old_gen_free_space( log_debug(gc, ergo)("Live_space: " SIZE_FORMAT " free_space: " SIZE_FORMAT, live_space(), free_space()); - log_trace(gc, ergo)("Base_footprint: " SIZE_FORMAT " avg_young_live: " SIZE_FORMAT " avg_old_live: " SIZE_FORMAT, - (size_t)_avg_base_footprint->average(), + log_trace(gc, ergo)("avg_young_live: " SIZE_FORMAT " avg_old_live: " SIZE_FORMAT, (size_t)avg_young_live()->average(), (size_t)avg_old_live()->average()); diff --git a/src/hotspot/share/gc/parallel/psAdaptiveSizePolicy.hpp b/src/hotspot/share/gc/parallel/psAdaptiveSizePolicy.hpp index 90e1e60db9495..4fab160dcb4fb 100644 --- a/src/hotspot/share/gc/parallel/psAdaptiveSizePolicy.hpp +++ b/src/hotspot/share/gc/parallel/psAdaptiveSizePolicy.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -145,8 +145,7 @@ class PSAdaptiveSizePolicy : public AdaptiveSizePolicy { // Footprint accessors size_t live_space() const { - return (size_t)(avg_base_footprint()->average() + - avg_young_live()->average() + + return (size_t)(avg_young_live()->average() + avg_old_live()->average()); } size_t free_space() const { diff --git a/src/hotspot/share/gc/parallel/psGCAdaptivePolicyCounters.cpp b/src/hotspot/share/gc/parallel/psGCAdaptivePolicyCounters.cpp index 20e14b73ac390..ed96c5c418157 100644 --- a/src/hotspot/share/gc/parallel/psGCAdaptivePolicyCounters.cpp +++ b/src/hotspot/share/gc/parallel/psGCAdaptivePolicyCounters.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -107,10 +107,6 @@ PSGCAdaptivePolicyCounters::PSGCAdaptivePolicyCounters(const char* name_arg, _free_space = PerfDataManager::create_variable(SUN_GC, cname, PerfData::U_Bytes, ps_size_policy()->free_space(), CHECK); - cname = PerfDataManager::counter_name(name_space(), "avgBaseFootprint"); - _avg_base_footprint = PerfDataManager::create_variable(SUN_GC, cname, - PerfData::U_Bytes, (jlong) ps_size_policy()->avg_base_footprint()->average(), CHECK); - cname = PerfDataManager::counter_name(name_space(), "liveAtLastFullGc"); _live_at_last_full_gc_counter = PerfDataManager::create_variable(SUN_GC, cname, @@ -157,7 +153,6 @@ void PSGCAdaptivePolicyCounters::update_counters_from_policy() { update_decrement_tenuring_threshold_for_survivor_limit(); update_live_space(); update_free_space(); - update_avg_base_footprint(); update_change_old_gen_for_maj_pauses(); update_change_young_gen_for_maj_pauses(); diff --git a/src/hotspot/share/gc/parallel/psGCAdaptivePolicyCounters.hpp b/src/hotspot/share/gc/parallel/psGCAdaptivePolicyCounters.hpp index 620c761004ecd..ad84eb4368b80 100644 --- a/src/hotspot/share/gc/parallel/psGCAdaptivePolicyCounters.hpp +++ b/src/hotspot/share/gc/parallel/psGCAdaptivePolicyCounters.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,7 +50,6 @@ class PSGCAdaptivePolicyCounters : public GCAdaptivePolicyCounters { PerfVariable* _avg_major_interval; PerfVariable* _live_space; PerfVariable* _free_space; - PerfVariable* _avg_base_footprint; PerfVariable* _live_at_last_full_gc_counter; PerfVariable* _old_capacity; @@ -142,11 +141,6 @@ class PSGCAdaptivePolicyCounters : public GCAdaptivePolicyCounters { _free_space->set_value(ps_size_policy()->free_space()); } - inline void update_avg_base_footprint() { - _avg_base_footprint->set_value( - (jlong)(ps_size_policy()->avg_base_footprint()->average()) - ); - } inline void update_avg_old_live() { _avg_old_live_counter->set_value( (jlong)(ps_size_policy()->avg_old_live()->average()) diff --git a/src/hotspot/share/gc/shared/gc_globals.hpp b/src/hotspot/share/gc/shared/gc_globals.hpp index 66496544b9627..34bc638c9baca 100644 --- a/src/hotspot/share/gc/shared/gc_globals.hpp +++ b/src/hotspot/share/gc/shared/gc_globals.hpp @@ -422,10 +422,6 @@ "Initial ratio of young generation/survivor space size") \ range(0, max_uintx) \ \ - product(size_t, BaseFootPrintEstimate, 256*M, \ - "Estimate of footprint other than Java Heap") \ - range(0, max_uintx) \ - \ product(bool, UseGCOverheadLimit, true, \ "Use policy to limit of proportion of time spent in GC " \ "before an OutOfMemory error is thrown") \ diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index 1bded2916504f..23b5330044148 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -521,6 +521,8 @@ static SpecialFlag const special_jvm_flags[] = { { "RTMRetryCount", JDK_Version::jdk(23), JDK_Version::jdk(24), JDK_Version::jdk(25) }, #endif // X86 + + { "BaseFootPrintEstimate", JDK_Version::undefined(), JDK_Version::jdk(24), JDK_Version::jdk(25) }, { "HeapFirstMaximumCompactionCount", JDK_Version::undefined(), JDK_Version::jdk(24), JDK_Version::jdk(25) }, { "UseVtableBasedCHA", JDK_Version::undefined(), JDK_Version::jdk(24), JDK_Version::jdk(25) }, #ifdef ASSERT @@ -1653,9 +1655,6 @@ jint Arguments::set_aggressive_heap_flags() { #endif // Increase some data structure sizes for efficiency - if (FLAG_SET_CMDLINE(BaseFootPrintEstimate, MaxHeapSize) != JVMFlag::SUCCESS) { - return JNI_EINVAL; - } if (FLAG_SET_CMDLINE(ResizeTLAB, false) != JVMFlag::SUCCESS) { return JNI_EINVAL; } diff --git a/src/jdk.internal.jvmstat/share/classes/sun/jvmstat/perfdata/resources/aliasmap b/src/jdk.internal.jvmstat/share/classes/sun/jvmstat/perfdata/resources/aliasmap index 5993acf701f51..001ce5b5cac4d 100644 --- a/src/jdk.internal.jvmstat/share/classes/sun/jvmstat/perfdata/resources/aliasmap +++ b/src/jdk.internal.jvmstat/share/classes/sun/jvmstat/perfdata/resources/aliasmap @@ -404,8 +404,6 @@ alias sun.gc.lastCause // 1.5.0 b39 hotspot.gc.last_cause // 1.4.2_02 // sun.gc.policy -alias sun.gc.policy.avgBaseFootprint // 1.5.0 b39 - hotspot.gc.policy.avg_base_footprint // 1.5.0 b21 alias sun.gc.policy.avgMajorIntervalTime // 1.5.0 b39 hotspot.gc.policy.avg_major_interval // 1.5.0 b21 alias sun.gc.policy.avgMajorPauseTime // 1.5.0 b39 From 8f039b56294604271c8ee896aca49d325b5472e5 Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Wed, 31 Jul 2024 17:55:01 +0000 Subject: [PATCH 159/353] 8336919: Cleanup and rename tags in placeholders code Co-authored-by: Frederic Parain Reviewed-by: iklam, fparain, dholmes --- .../share/classfile/classFileParser.cpp | 14 ++- src/hotspot/share/classfile/placeholders.cpp | 49 +++++------ src/hotspot/share/classfile/placeholders.hpp | 36 ++++---- .../share/classfile/systemDictionary.cpp | 86 ++++++++++--------- .../share/classfile/systemDictionary.hpp | 20 +++-- .../gtest/classfile/test_placeholders.cpp | 8 +- 6 files changed, 111 insertions(+), 102 deletions(-) diff --git a/src/hotspot/share/classfile/classFileParser.cpp b/src/hotspot/share/classfile/classFileParser.cpp index ddde58e5d20b3..407078d64fc57 100644 --- a/src/hotspot/share/classfile/classFileParser.cpp +++ b/src/hotspot/share/classfile/classFileParser.cpp @@ -835,14 +835,12 @@ void ClassFileParser::parse_interfaces(const ClassFileStream* const stream, guarantee_property(unresolved_klass->char_at(0) != JVM_SIGNATURE_ARRAY, "Bad interface name in class file %s", CHECK); - // Call resolve_super so class circularity is checked - interf = SystemDictionary::resolve_super_or_fail( - _class_name, - unresolved_klass, - Handle(THREAD, _loader_data->class_loader()), - _protection_domain, - false, - CHECK); + // Call resolve on the interface class name with class circularity checking + interf = SystemDictionary::resolve_super_or_fail(_class_name, + unresolved_klass, + Handle(THREAD, _loader_data->class_loader()), + _protection_domain, + false, CHECK); } if (!interf->is_interface()) { diff --git a/src/hotspot/share/classfile/placeholders.cpp b/src/hotspot/share/classfile/placeholders.cpp index a6a86473ea794..38d359efcc245 100644 --- a/src/hotspot/share/classfile/placeholders.cpp +++ b/src/hotspot/share/classfile/placeholders.cpp @@ -95,8 +95,8 @@ SeenThread* PlaceholderEntry::actionToQueue(PlaceholderTable::classloadAction ac case PlaceholderTable::LOAD_INSTANCE: queuehead = _loadInstanceThreadQ; break; - case PlaceholderTable::LOAD_SUPER: - queuehead = _superThreadQ; + case PlaceholderTable::DETECT_CIRCULARITY: + queuehead = _circularityThreadQ; break; case PlaceholderTable::DEFINE_CLASS: queuehead = _defineThreadQ; @@ -111,8 +111,8 @@ void PlaceholderEntry::set_threadQ(SeenThread* seenthread, PlaceholderTable::cla case PlaceholderTable::LOAD_INSTANCE: _loadInstanceThreadQ = seenthread; break; - case PlaceholderTable::LOAD_SUPER: - _superThreadQ = seenthread; + case PlaceholderTable::DETECT_CIRCULARITY: + _circularityThreadQ = seenthread; break; case PlaceholderTable::DEFINE_CLASS: _defineThreadQ = seenthread; @@ -188,10 +188,10 @@ bool PlaceholderEntry::remove_seen_thread(JavaThread* thread, PlaceholderTable:: } -void PlaceholderEntry::set_supername(Symbol* supername) { +void PlaceholderEntry::set_next_klass_name(Symbol* next_klass_name) { assert_locked_or_safepoint(SystemDictionary_lock); - assert(_supername == nullptr || _supername->refcount() > 1, "must be referenced also by the loader"); - _supername = supername; + assert(_next_klass_name == nullptr || _next_klass_name->refcount() > 1, "must be referenced also by the loader"); + _next_klass_name = next_klass_name; } // Placeholder objects represent classes currently being loaded. @@ -199,12 +199,12 @@ void PlaceholderEntry::set_supername(Symbol* supername) { // SystemDictionary_lock, so we don't need special precautions // on store ordering here. static PlaceholderEntry* add_entry(Symbol* class_name, ClassLoaderData* loader_data, - Symbol* supername){ + Symbol* next_klass_name){ assert_locked_or_safepoint(SystemDictionary_lock); assert(class_name != nullptr, "adding nullptr obj"); PlaceholderEntry entry; - entry.set_supername(supername); + entry.set_next_klass_name(next_klass_name); PlaceholderKey key(class_name, loader_data); bool created; PlaceholderEntry* table_copy = _placeholders->put_if_absent(key, entry, &created); @@ -230,7 +230,7 @@ PlaceholderEntry* PlaceholderTable::get_entry(Symbol* class_name, ClassLoaderDat static const char* action_to_string(PlaceholderTable::classloadAction action) { switch (action) { case PlaceholderTable::LOAD_INSTANCE: return "LOAD_INSTANCE"; - case PlaceholderTable::LOAD_SUPER: return "LOAD_SUPER"; + case PlaceholderTable::DETECT_CIRCULARITY: return "DETECT_CIRCULARITY"; case PlaceholderTable::DEFINE_CLASS: return "DEFINE_CLASS"; } return ""; @@ -250,20 +250,21 @@ inline void log(Symbol* name, PlaceholderEntry* entry, const char* function, Pla // If no entry exists, add a placeholder entry // If entry exists, reuse entry // For both, push SeenThread for classloadAction -// If LOAD_SUPER, this is used for circularity detection for instanceklass loading. +// If DETECT_CIRCULARITY, this is used for circularity detection for instanceklass loading. PlaceholderEntry* PlaceholderTable::find_and_add(Symbol* name, ClassLoaderData* loader_data, classloadAction action, - Symbol* supername, + Symbol* next_klass_name, JavaThread* thread) { - assert(action != LOAD_SUPER || supername != nullptr, "must have a super class name"); + assert(action != DETECT_CIRCULARITY || next_klass_name != nullptr, + "must have a class name for the next step in the class resolution recursion"); PlaceholderEntry* probe = get_entry(name, loader_data); if (probe == nullptr) { // Nothing found, add place holder - probe = add_entry(name, loader_data, supername); + probe = add_entry(name, loader_data, next_klass_name); } else { - if (action == LOAD_SUPER) { - probe->set_supername(supername); + if (action == DETECT_CIRCULARITY) { + probe->set_next_klass_name(next_klass_name); } } probe->add_seen_thread(thread, action); @@ -295,11 +296,11 @@ void PlaceholderTable::find_and_remove(Symbol* name, ClassLoaderData* loader_dat assert(probe != nullptr, "must find an entry"); log(name, probe, "find_and_remove", action); probe->remove_seen_thread(thread, action); - if (probe->superThreadQ() == nullptr) { - probe->set_supername(nullptr); + if (probe->circularityThreadQ() == nullptr) { + probe->set_next_klass_name(nullptr); } // If no other threads using this entry, and this thread is not using this entry for other states - if ((probe->superThreadQ() == nullptr) && (probe->loadInstanceThreadQ() == nullptr) + if ((probe->circularityThreadQ() == nullptr) && (probe->loadInstanceThreadQ() == nullptr) && (probe->defineThreadQ() == nullptr) && (probe->definer() == nullptr)) { remove_entry(name, loader_data); } @@ -312,9 +313,9 @@ void PlaceholderKey::print_on(outputStream* st) const { } void PlaceholderEntry::print_on(outputStream* st) const { - if (supername() != nullptr) { - st->print(", supername "); - supername()->print_value_on(st); + if (next_klass_name() != nullptr) { + st->print(", next_klass_name "); + next_klass_name()->print_value_on(st); } if (definer() != nullptr) { st->print(", definer "); @@ -328,8 +329,8 @@ void PlaceholderEntry::print_on(outputStream* st) const { st->print("loadInstanceThreadQ threads:"); SeenThread::print_action_queue(loadInstanceThreadQ(), st); st->cr(); - st->print("superThreadQ threads:"); - SeenThread::print_action_queue(superThreadQ(), st); + st->print("circularityThreadQ threads:"); + SeenThread::print_action_queue(circularityThreadQ(), st); st->cr(); st->print("defineThreadQ threads:"); SeenThread::print_action_queue(defineThreadQ(), st); diff --git a/src/hotspot/share/classfile/placeholders.hpp b/src/hotspot/share/classfile/placeholders.hpp index 7f83cf5d058b9..6348f76a14eea 100644 --- a/src/hotspot/share/classfile/placeholders.hpp +++ b/src/hotspot/share/classfile/placeholders.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,15 +41,15 @@ class PlaceholderTable : public AllStatic { // caller claims ownership of that action // For parallel classloading: // multiple LOAD_INSTANCE threads can proceed in parallel - // multiple LOAD_SUPER threads can proceed in parallel - // LOAD_SUPER needed to check for class circularity + // multiple DETECT_CIRCULARITY threads can proceed in parallel + // DETECT_CIRCULARITY needed to check for class circularity // DEFINE_CLASS: ultimately define class must be single threaded // on a class/classloader basis // so the head of that queue owns the token // and the rest of the threads return the result the first thread gets enum classloadAction { LOAD_INSTANCE = 1, // calling load_instance_class - LOAD_SUPER = 2, // loading superclass for this class + DETECT_CIRCULARITY = 2, // loading while detecting class circularity DEFINE_CLASS = 3 // find_or_define class }; static void initialize(); @@ -81,13 +81,13 @@ class SeenThread; class PlaceholderEntry { friend class PlaceholderTable; private: - SymbolHandle _supername; - JavaThread* _definer; // owner of define token - InstanceKlass* _instanceKlass; // InstanceKlass from successful define - SeenThread* _superThreadQ; // doubly-linked queue of Threads loading a superclass for this class - SeenThread* _loadInstanceThreadQ; // loadInstance thread - // This can't be multiple threads since class loading waits for - // this token to be removed. + SymbolHandle _next_klass_name; // next step in the recursive process of class loading + JavaThread* _definer; // owner of define token + InstanceKlass* _instanceKlass; // InstanceKlass from successful define + SeenThread* _circularityThreadQ; // doubly-linked queue of Threads loading with circularity detection + SeenThread* _loadInstanceThreadQ; // loadInstance thread + // This can't be multiple threads since class loading + // waits for this token to be removed. SeenThread* _defineThreadQ; // queue of Threads trying to define this class // including _definer @@ -99,8 +99,8 @@ class PlaceholderEntry { void add_seen_thread(JavaThread* thread, PlaceholderTable::classloadAction action); bool remove_seen_thread(JavaThread* thread, PlaceholderTable::classloadAction action); - SeenThread* superThreadQ() const { return _superThreadQ; } - void set_superThreadQ(SeenThread* SeenThread) { _superThreadQ = SeenThread; } + SeenThread* circularityThreadQ() const { return _circularityThreadQ; } + void set_circularityThreadQ(SeenThread* SeenThread) { _circularityThreadQ = SeenThread; } SeenThread* loadInstanceThreadQ() const { return _loadInstanceThreadQ; } void set_loadInstanceThreadQ(SeenThread* SeenThread) { _loadInstanceThreadQ = SeenThread; } @@ -110,10 +110,10 @@ class PlaceholderEntry { public: PlaceholderEntry() : _definer(nullptr), _instanceKlass(nullptr), - _superThreadQ(nullptr), _loadInstanceThreadQ(nullptr), _defineThreadQ(nullptr) { } + _circularityThreadQ(nullptr), _loadInstanceThreadQ(nullptr), _defineThreadQ(nullptr) { } - Symbol* supername() const { return _supername; } - void set_supername(Symbol* supername); + Symbol* next_klass_name() const { return _next_klass_name; } + void set_next_klass_name(Symbol* next_klass_name); JavaThread* definer() const {return _definer; } void set_definer(JavaThread* definer) { _definer = definer; } @@ -121,8 +121,8 @@ class PlaceholderEntry { InstanceKlass* instance_klass() const {return _instanceKlass; } void set_instance_klass(InstanceKlass* ik) { _instanceKlass = ik; } - bool super_load_in_progress() { - return (_superThreadQ != nullptr); + bool circularity_detection_in_progress() { + return (_circularityThreadQ != nullptr); } bool instance_load_in_progress() { diff --git a/src/hotspot/share/classfile/systemDictionary.cpp b/src/hotspot/share/classfile/systemDictionary.cpp index 852416e30f5d2..3016d41b28923 100644 --- a/src/hotspot/share/classfile/systemDictionary.cpp +++ b/src/hotspot/share/classfile/systemDictionary.cpp @@ -399,32 +399,32 @@ static inline void log_circularity_error(Symbol* name, PlaceholderEntry* probe) // superclass checks on its own thread to catch class circularity and // to avoid deadlock. // -// resolve_super_or_fail adds a LOAD_SUPER placeholder to the placeholder table before calling -// resolve_instance_class_or_null. ClassCircularityError is detected when a LOAD_SUPER or LOAD_INSTANCE +// resolve_with_circularity_detection adds a DETECT_CIRCULARITY placeholder to the placeholder table before calling +// resolve_instance_class_or_null. ClassCircularityError is detected when a DETECT_CIRCULARITY or LOAD_INSTANCE // placeholder for the same thread, class, classloader is found. // This can be seen with logging option: -Xlog:class+load+placeholders=debug. // -InstanceKlass* SystemDictionary::resolve_super_or_fail(Symbol* class_name, - Symbol* super_name, - Handle class_loader, - Handle protection_domain, - bool is_superclass, - TRAPS) { - - assert(super_name != nullptr, "null superclass for resolving"); - assert(!Signature::is_array(super_name), "invalid superclass name"); +InstanceKlass* SystemDictionary::resolve_with_circularity_detection(Symbol* class_name, + Symbol* next_name, + Handle class_loader, + Handle protection_domain, + bool is_superclass, + TRAPS) { + + assert(next_name != nullptr, "null superclass for resolving"); + assert(!Signature::is_array(next_name), "invalid superclass name"); #if INCLUDE_CDS if (CDSConfig::is_dumping_static_archive()) { // Special processing for handling UNREGISTERED shared classes. InstanceKlass* k = SystemDictionaryShared::lookup_super_for_unregistered_class(class_name, - super_name, is_superclass); + next_name, is_superclass); if (k) { return k; } } #endif // INCLUDE_CDS - // If klass is already loaded, just return the superclass or superinterface. + // If class_name is already loaded, just return the superclass or superinterface. // Make sure there's a placeholder for the class_name before resolving. // This is used as a claim that this thread is currently loading superclass/classloader // and for ClassCircularity checks. @@ -439,28 +439,27 @@ InstanceKlass* SystemDictionary::resolve_super_or_fail(Symbol* class_name, InstanceKlass* klassk = dictionary->find_class(THREAD, class_name); InstanceKlass* quicksuperk; // To support parallel loading: if class is done loading, just return the superclass - // if the super_name matches class->super()->name() and if the class loaders match. - // Otherwise, a LinkageError will be thrown later. + // if the next_name matches class->super()->name() and if the class loaders match. if (klassk != nullptr && is_superclass && - ((quicksuperk = klassk->java_super()) != nullptr) && - ((quicksuperk->name() == super_name) && - (quicksuperk->class_loader() == class_loader()))) { - return quicksuperk; + ((quicksuperk = klassk->java_super()) != nullptr) && + ((quicksuperk->name() == next_name) && + (quicksuperk->class_loader() == class_loader()))) { + return quicksuperk; } else { // Must check ClassCircularity before checking if superclass is already loaded. PlaceholderEntry* probe = PlaceholderTable::get_entry(class_name, loader_data); - if (probe && probe->check_seen_thread(THREAD, PlaceholderTable::LOAD_SUPER)) { + if (probe && probe->check_seen_thread(THREAD, PlaceholderTable::DETECT_CIRCULARITY)) { log_circularity_error(class_name, probe); throw_circularity_error = true; } } if (!throw_circularity_error) { - // Be careful not to exit resolve_super without removing this placeholder. + // Be careful not to exit resolve_with_circularity_detection without removing this placeholder. PlaceholderEntry* newprobe = PlaceholderTable::find_and_add(class_name, loader_data, - PlaceholderTable::LOAD_SUPER, - super_name, THREAD); + PlaceholderTable::DETECT_CIRCULARITY, + next_name, THREAD); } } @@ -471,7 +470,7 @@ InstanceKlass* SystemDictionary::resolve_super_or_fail(Symbol* class_name, // Resolve the superclass or superinterface, check results on return InstanceKlass* superk = - SystemDictionary::resolve_instance_class_or_null(super_name, + SystemDictionary::resolve_instance_class_or_null(next_name, class_loader, protection_domain, THREAD); @@ -479,13 +478,13 @@ InstanceKlass* SystemDictionary::resolve_super_or_fail(Symbol* class_name, // Clean up placeholder entry. { MutexLocker mu(THREAD, SystemDictionary_lock); - PlaceholderTable::find_and_remove(class_name, loader_data, PlaceholderTable::LOAD_SUPER, THREAD); + PlaceholderTable::find_and_remove(class_name, loader_data, PlaceholderTable::DETECT_CIRCULARITY, THREAD); SystemDictionary_lock->notify_all(); } // Check for pending exception or null superk, and throw exception if (HAS_PENDING_EXCEPTION || superk == nullptr) { - handle_resolution_exception(super_name, true, CHECK_NULL); + handle_resolution_exception(next_name, true, CHECK_NULL); } return superk; @@ -502,13 +501,15 @@ static void handle_parallel_super_load(Symbol* name, Handle class_loader, Handle protection_domain, TRAPS) { - // superk is not used; resolve_super_or_fail is called for circularity check only. - Klass* superk = SystemDictionary::resolve_super_or_fail(name, - superclassname, - class_loader, - protection_domain, - true, - CHECK); + // The result superk is not used; resolve_with_circularity_detection is called for circularity check only. + // This passes true to is_superclass even though it might not be the super class in order to perform the + // optimization anyway. + Klass* superk = SystemDictionary::resolve_with_circularity_detection(name, + superclassname, + class_loader, + protection_domain, + true, + CHECK); } // Bootstrap and non-parallel capable class loaders use the LOAD_INSTANCE placeholder to @@ -536,7 +537,7 @@ static InstanceKlass* handle_parallel_loading(JavaThread* current, // Wait until the first thread has finished loading this class. Also wait until all the // threads trying to load its superclass have removed their placeholders. while (oldprobe != nullptr && - (oldprobe->instance_load_in_progress() || oldprobe->super_load_in_progress())) { + (oldprobe->instance_load_in_progress() || oldprobe->circularity_detection_in_progress())) { // LOAD_INSTANCE placeholders are used to implement parallel capable class loading // for the bootclass loader. @@ -575,8 +576,9 @@ InstanceKlass* SystemDictionary::resolve_instance_class_or_null(Symbol* name, Handle protection_domain, TRAPS) { // name must be in the form of "java/lang/Object" -- cannot be "Ljava/lang/Object;" + DEBUG_ONLY(ResourceMark rm(THREAD)); assert(name != nullptr && !Signature::is_array(name) && - !Signature::has_envelope(name), "invalid class name"); + !Signature::has_envelope(name), "invalid class name: %s", name == nullptr ? "nullptr" : name->as_C_string()); EventClassLoad class_load_start_event; @@ -607,7 +609,7 @@ InstanceKlass* SystemDictionary::resolve_instance_class_or_null(Symbol* name, Handle lockObject = get_loader_lock_or_null(class_loader); ObjectLocker ol(lockObject, THREAD); - bool super_load_in_progress = false; + bool circularity_detection_in_progress = false; InstanceKlass* loaded_class = nullptr; SymbolHandle superclassname; // Keep alive while loading in parallel thread. @@ -625,9 +627,9 @@ InstanceKlass* SystemDictionary::resolve_instance_class_or_null(Symbol* name, loaded_class = check; } else { PlaceholderEntry* placeholder = PlaceholderTable::get_entry(name, loader_data); - if (placeholder != nullptr && placeholder->super_load_in_progress()) { - super_load_in_progress = true; - superclassname = placeholder->supername(); + if (placeholder != nullptr && placeholder->circularity_detection_in_progress()) { + circularity_detection_in_progress = true; + superclassname = placeholder->next_klass_name(); assert(superclassname != nullptr, "superclass has to have a name"); } } @@ -635,7 +637,7 @@ InstanceKlass* SystemDictionary::resolve_instance_class_or_null(Symbol* name, // If the class is in the placeholder table with super_class set, // handle superclass loading in progress. - if (super_load_in_progress) { + if (circularity_detection_in_progress) { handle_parallel_super_load(name, superclassname, class_loader, protection_domain, @@ -1052,8 +1054,8 @@ bool SystemDictionary::check_shared_class_super_type(InstanceKlass* klass, Insta } } - Klass *found = resolve_super_or_fail(klass->name(), super_type->name(), - class_loader, protection_domain, is_superclass, CHECK_0); + Klass *found = resolve_with_circularity_detection(klass->name(), super_type->name(), + class_loader, protection_domain, is_superclass, CHECK_0); if (found == super_type) { return true; } else { diff --git a/src/hotspot/share/classfile/systemDictionary.hpp b/src/hotspot/share/classfile/systemDictionary.hpp index 6355de9c4ceb5..ee50aa38dd0cf 100644 --- a/src/hotspot/share/classfile/systemDictionary.hpp +++ b/src/hotspot/share/classfile/systemDictionary.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -102,15 +102,23 @@ class SystemDictionary : AllStatic { return resolve_or_null(class_name, Handle(), Handle(), THREAD); } + static InstanceKlass* resolve_with_circularity_detection(Symbol* class_name, + Symbol* next_name, + Handle class_loader, + Handle protection_domain, + bool is_superclass, + TRAPS); + // Resolve a superclass or superinterface. Called from ClassFileParser, // parse_interfaces, resolve_instance_class_or_null, load_shared_class // "class_name" is the class whose super class or interface is being resolved. - static InstanceKlass* resolve_super_or_fail(Symbol* class_name, - Symbol* super_name, + static InstanceKlass* resolve_super_or_fail(Symbol* class_name, Symbol* super_name, Handle class_loader, - Handle protection_domain, - bool is_superclass, - TRAPS); + Handle protection_domain, bool is_superclass, TRAPS) { + return resolve_with_circularity_detection(class_name, super_name, class_loader, protection_domain, + is_superclass, THREAD); + } + private: // Parse the stream to create a hidden class. // Used by jvm_lookup_define_class. diff --git a/test/hotspot/gtest/classfile/test_placeholders.cpp b/test/hotspot/gtest/classfile/test_placeholders.cpp index 4179a1fc695da..8cd9536271e23 100644 --- a/test/hotspot/gtest/classfile/test_placeholders.cpp +++ b/test/hotspot/gtest/classfile/test_placeholders.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -49,7 +49,7 @@ TEST_VM(PlaceholderTable, supername) { { MutexLocker ml(THREAD, SystemDictionary_lock); - PlaceholderTable::classloadAction super_action = PlaceholderTable::LOAD_SUPER; + PlaceholderTable::classloadAction super_action = PlaceholderTable::DETECT_CIRCULARITY; PlaceholderTable::classloadAction define_action = PlaceholderTable::DEFINE_CLASS; // DefineClass A and D @@ -71,7 +71,7 @@ TEST_VM(PlaceholderTable, supername) { // Another thread comes in and finds A loading Super PlaceholderEntry* placeholder = PlaceholderTable::get_entry(A, loader_data); - SymbolHandle supername = placeholder->supername(); + SymbolHandle supername = placeholder->next_klass_name(); // Other thread is done before handle_parallel_super_load PlaceholderTable::find_and_remove(A, loader_data, super_action, THREAD); @@ -86,7 +86,7 @@ TEST_VM(PlaceholderTable, supername) { // Refcount should be 3: one in table for class A, one in table for class D // and one locally with SymbolHandle keeping it alive placeholder = PlaceholderTable::get_entry(A, loader_data); - supername = placeholder->supername(); + supername = placeholder->next_klass_name(); EXPECT_EQ(super->refcount(), 3) << "super class name refcount should be 3"; // Second thread's done too From a45bb55ddb6abfa520a2e4d7a5cd4d638a526efd Mon Sep 17 00:00:00 2001 From: Erik Gahlin Date: Wed, 31 Jul 2024 17:58:52 +0000 Subject: [PATCH 160/353] 8337501: JFR: Use TimespanUnit Reviewed-by: mgronlun --- .../jdk/jfr/internal/dcmd/ArgumentParser.java | 18 +++++-------- .../jdk/jfr/internal/jfc/model/Utilities.java | 12 ++++----- .../jdk/jfr/internal/util/TimespanUnit.java | 26 ++++++++++++------- .../jdk/jfr/internal/util/ValueParser.java | 26 +++++-------------- 4 files changed, 35 insertions(+), 47 deletions(-) diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/ArgumentParser.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/ArgumentParser.java index a614516d295bc..c14ce6025ce9b 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/ArgumentParser.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/ArgumentParser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * 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.Set; import java.util.StringJoiner; import jdk.jfr.internal.util.SpellChecker; +import jdk.jfr.internal.util.TimespanUnit; final class ArgumentParser { private final Map options = new HashMap<>(); @@ -302,16 +303,11 @@ private Object parseNanotime(String name, String text) { } throw new IllegalArgumentException("Integer parsing error nanotime value: unit required"); } - return switch(unit) { - case "ns" -> time; - case "us" -> time * 1000; - case "ms" -> time * 1000 * 1000; - case "s" -> time * 1000 * 1000 * 1000; - case "m" -> time * 60 * 1000 * 1000 * 1000; - case "h" -> time * 60 * 60* 1000 * 1000 * 1000; - case "d" -> time * 24 * 60 * 60 * 1000 * 1000 * 1000; - default -> throw new IllegalArgumentException("Integer parsing error nanotime value: illegal unit"); - }; + TimespanUnit tu = TimespanUnit.fromText(unit); + if (tu == null) { + throw new IllegalArgumentException("Integer parsing error nanotime value: illegal unit"); + } + return tu.toNanos(time); } int indexOfUnit(String text) { diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/jfc/model/Utilities.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/jfc/model/Utilities.java index 76e834fe6eb3c..281a0c5794967 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/jfc/model/Utilities.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/jfc/model/Utilities.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,11 +25,9 @@ package jdk.jfr.internal.jfc.model; import java.util.StringJoiner; +import jdk.jfr.internal.util.TimespanUnit; public final class Utilities { - private static final String[] UNITS = new String[] { - "ns", "us", "ns", "ms", "s", "m", "h", "d" // order matters - }; static XmlElement instantiate(Class type) { try { @@ -104,9 +102,9 @@ static void checkValid(String value, Object... valid) { static String parseTimespan(String s) { StringBuilder sb = new StringBuilder(); try { - for (String unit : UNITS) { - if (s.endsWith(unit)) { - return parseForUnit(s, unit); + for (TimespanUnit timespan : TimespanUnit.values()) { + if (s.endsWith(timespan.text)) { + return parseForUnit(s, timespan.text); } } Long.parseLong(s); diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/util/TimespanUnit.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/util/TimespanUnit.java index 9026f59b68b88..0fdde833bebd3 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/util/TimespanUnit.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/util/TimespanUnit.java @@ -24,21 +24,29 @@ */ package jdk.jfr.internal.util; +import java.util.concurrent.TimeUnit; + public enum TimespanUnit { - NANOSECONDS ("ns", 1L, 1000), - MICROSECONDS("us", 1000L, 1000), - MILLISECONDS("ms", 1_000_000L, 1000), - SECONDS ("s", 1_000_000_000L, 60), - MINUTES ("m", 60 * 1_000_000_000L, 60), - HOURS ("h", 60 * 60 * 1_000_000_000L, 24), - DAYS ("d", 24 * 60 * 60 * 1_000_000_000L, 7); + NANOSECONDS ("ns", TimeUnit.NANOSECONDS, 1000), + MICROSECONDS("us", TimeUnit.MICROSECONDS, 1000), + MILLISECONDS("ms", TimeUnit.MILLISECONDS, 1000), + SECONDS ("s", TimeUnit.SECONDS, 60), + MINUTES ("m", TimeUnit.MINUTES, 60), + HOURS ("h", TimeUnit.HOURS, 24), + DAYS ("d", TimeUnit.DAYS, 7); public final String text; public final long nanos; public final int size; - TimespanUnit(String text, long nanos, int size) { + private final TimeUnit timeUnit; + TimespanUnit(String text, TimeUnit tu, int size) { this.text = text; - this.nanos = nanos; + this.nanos = tu.toNanos(1); this.size = size; + this.timeUnit = tu; + } + + public long toNanos(long value) { + return timeUnit.toNanos(value); } public static TimespanUnit fromText(String text) { diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/util/ValueParser.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/util/ValueParser.java index e4482c9236887..cf112d3beb543 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/util/ValueParser.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/util/ValueParser.java @@ -51,26 +51,12 @@ public static long parseTimespanWithInfinity(String s) { } public static long parseTimespan(String s) { - if (s.endsWith("ns")) { - return Long.parseLong(s.substring(0, s.length() - 2).trim()); - } - if (s.endsWith("us")) { - return MICROSECONDS.toNanos(Long.parseLong(s.substring(0, s.length() - 2).trim())); - } - if (s.endsWith("ms")) { - return MILLISECONDS.toNanos(Long.parseLong(s.substring(0, s.length() - 2).trim())); - } - if (s.endsWith("s")) { - return SECONDS.toNanos(Long.parseLong(s.substring(0, s.length() - 1).trim())); - } - if (s.endsWith("m")) { - return MINUTES.toNanos(Long.parseLong(s.substring(0, s.length() - 1).trim())); - } - if (s.endsWith("h")) { - return HOURS.toNanos(Long.parseLong(s.substring(0, s.length() - 1).trim())); - } - if (s.endsWith("d")) { - return DAYS.toNanos(Long.parseLong(s.substring(0, s.length() - 1).trim())); + for (TimespanUnit unit : TimespanUnit.values()) { + String text = unit.text; + if (s.endsWith(text)) { + long value = Long.parseLong(s.substring(0, s.length() - text.length()).strip()); + return unit.toNanos(value); + } } try { From 97f7c03dd0ff389abefed7ea2a7257bcb42e0754 Mon Sep 17 00:00:00 2001 From: Sonia Zaldana Calles Date: Wed, 31 Jul 2024 18:05:49 +0000 Subject: [PATCH 161/353] 8336495: Remove unnecessary casts in output.cpp Reviewed-by: chagedorn, kvn --- src/hotspot/share/opto/output.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/opto/output.cpp b/src/hotspot/share/opto/output.cpp index 42374a0bcd4f8..b3f251bb361ba 100644 --- a/src/hotspot/share/opto/output.cpp +++ b/src/hotspot/share/opto/output.cpp @@ -716,7 +716,7 @@ ObjectValue* PhaseOutput::sv_for_node_id(GrowableArray *objs, int id) { for (int i = 0; i < objs->length(); i++) { assert(objs->at(i)->is_object(), "corrupt object cache"); - ObjectValue* sv = (ObjectValue*) objs->at(i); + ObjectValue* sv = objs->at(i)->as_ObjectValue(); if (sv->id() == id) { return sv; } @@ -755,7 +755,7 @@ void PhaseOutput::FillLocArray( int idx, MachSafePointNode* sfpt, Node *local, if (local->is_SafePointScalarObject()) { SafePointScalarObjectNode* spobj = local->as_SafePointScalarObject(); - ObjectValue* sv = (ObjectValue*) sv_for_node_id(objs, spobj->_idx); + ObjectValue* sv = sv_for_node_id(objs, spobj->_idx); if (sv == nullptr) { ciKlass* cik = t->is_oopptr()->exact_klass(); assert(cik->is_instance_klass() || @@ -987,7 +987,7 @@ bool PhaseOutput::contains_as_scalarized_obj(JVMState* jvms, MachSafePointNode* continue; } - ObjectValue* other = (ObjectValue*) sv_for_node_id(objs, n->_idx); + ObjectValue* other = sv_for_node_id(objs, n->_idx); if (ov == other) { return true; } From 8af2ef35b6f9399b6d25ff7a4a72ad283df63f03 Mon Sep 17 00:00:00 2001 From: Alex Menkov Date: Wed, 31 Jul 2024 20:02:25 +0000 Subject: [PATCH 162/353] 8331015: Obsolete -XX:+UseNotificationThread Reviewed-by: dholmes, kevinw, sspitsyn, coleenp --- .../recorder/repository/jfrEmergencyDump.cpp | 4 ++-- src/hotspot/share/runtime/arguments.cpp | 2 +- src/hotspot/share/runtime/globals.hpp | 3 --- src/hotspot/share/runtime/mutexLocker.cpp | 9 ++------ src/hotspot/share/runtime/serviceThread.cpp | 22 +------------------ .../share/services/lowMemoryDetector.hpp | 5 ++--- src/hotspot/share/services/management.cpp | 5 ++--- 7 files changed, 10 insertions(+), 40 deletions(-) diff --git a/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp b/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp index e0bbd8a6ddc28..0759d02cb7c23 100644 --- a/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp +++ b/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -497,7 +497,7 @@ static bool prepare_for_emergency_dump(Thread* thread) { Service_lock->unlock(); } - if (UseNotificationThread && Notification_lock->owned_by_self()) { + if (Notification_lock->owned_by_self()) { Notification_lock->unlock(); } diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index 23b5330044148..9086a5f6c7121 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -503,7 +503,6 @@ static SpecialFlag const special_jvm_flags[] = { { "RequireSharedSpaces", JDK_Version::jdk(18), JDK_Version::jdk(19), JDK_Version::undefined() }, { "UseSharedSpaces", JDK_Version::jdk(18), JDK_Version::jdk(19), JDK_Version::undefined() }, { "DontYieldALot", JDK_Version::jdk(23), JDK_Version::jdk(24), JDK_Version::jdk(25) }, - { "UseNotificationThread", JDK_Version::jdk(23), JDK_Version::jdk(24), JDK_Version::jdk(25) }, { "LockingMode", JDK_Version::jdk(24), JDK_Version::jdk(26), JDK_Version::jdk(27) }, // --- Deprecated alias flags (see also aliased_jvm_flags) - sorted by obsolete_in then expired_in: { "CreateMinidumpOnCrash", JDK_Version::jdk(9), JDK_Version::undefined(), JDK_Version::undefined() }, @@ -512,6 +511,7 @@ static SpecialFlag const special_jvm_flags[] = { { "MetaspaceReclaimPolicy", JDK_Version::undefined(), JDK_Version::jdk(21), JDK_Version::undefined() }, + { "UseNotificationThread", JDK_Version::jdk(23), JDK_Version::jdk(24), JDK_Version::jdk(25) }, { "PreserveAllAnnotations", JDK_Version::jdk(23), JDK_Version::jdk(24), JDK_Version::jdk(25) }, { "UseEmptySlotsInSupers", JDK_Version::jdk(23), JDK_Version::jdk(24), JDK_Version::jdk(25) }, { "OldSize", JDK_Version::jdk(23), JDK_Version::jdk(24), JDK_Version::jdk(25) }, diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp index 562549f247efd..61efc0b93764d 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -952,9 +952,6 @@ const int ObjectAlignmentInBytes = 8; product(bool, EnableThreadSMRStatistics, trueInDebug, DIAGNOSTIC, \ "Enable Thread SMR Statistics") \ \ - product(bool, UseNotificationThread, true, \ - "(Deprecated) Use Notification Thread") \ - \ product(bool, Inline, true, \ "Enable inlining") \ \ diff --git a/src/hotspot/share/runtime/mutexLocker.cpp b/src/hotspot/share/runtime/mutexLocker.cpp index add47738db0bc..a63014d78a171 100644 --- a/src/hotspot/share/runtime/mutexLocker.cpp +++ b/src/hotspot/share/runtime/mutexLocker.cpp @@ -235,13 +235,8 @@ void mutex_init() { MUTEX_DEFN(Patching_lock , PaddedMutex , nosafepoint); // used for safepointing and code patching. MUTEX_DEFN(MonitorDeflation_lock , PaddedMonitor, nosafepoint); // used for monitor deflation thread operations - MUTEX_DEFN(Service_lock , PaddedMonitor, service); // used for service thread operations - - if (UseNotificationThread) { - MUTEX_DEFN(Notification_lock , PaddedMonitor, service); // used for notification thread operations - } else { - Notification_lock = Service_lock; - } + MUTEX_DEFN(Service_lock , PaddedMonitor, service); // used for service thread operations + MUTEX_DEFN(Notification_lock , PaddedMonitor, service); // used for notification thread operations MUTEX_DEFN(JmethodIdCreation_lock , PaddedMutex , nosafepoint-2); // used for creating jmethodIDs. MUTEX_DEFN(InvokeMethodTypeTable_lock , PaddedMutex , safepoint); diff --git a/src/hotspot/share/runtime/serviceThread.cpp b/src/hotspot/share/runtime/serviceThread.cpp index f02e5062e672e..a81285ac97c0b 100644 --- a/src/hotspot/share/runtime/serviceThread.cpp +++ b/src/hotspot/share/runtime/serviceThread.cpp @@ -81,10 +81,7 @@ static void cleanup_oopstorages() { void ServiceThread::service_thread_entry(JavaThread* jt, TRAPS) { while (true) { - bool sensors_changed = false; bool has_jvmti_events = false; - bool has_gc_notification_event = false; - bool has_dcmd_notification_event = false; bool stringtable_work = false; bool symboltable_work = false; bool finalizerservice_work = false; @@ -113,10 +110,7 @@ void ServiceThread::service_thread_entry(JavaThread* jt, TRAPS) { // only the first recognized bit of work, to avoid frequently true early // tests from potentially starving later work. Hence the use of // arithmetic-or to combine results; we don't want short-circuiting. - while (((sensors_changed = (!UseNotificationThread && LowMemoryDetector::has_pending_requests())) | - (has_jvmti_events = _jvmti_service_queue.has_events()) | - (has_gc_notification_event = (!UseNotificationThread && GCNotifier::has_event())) | - (has_dcmd_notification_event = (!UseNotificationThread && DCmdFactory::has_pending_jmx_notification())) | + while (((has_jvmti_events = _jvmti_service_queue.has_events()) | (stringtable_work = StringTable::has_work()) | (symboltable_work = SymbolTable::has_work()) | (finalizerservice_work = FinalizerService::has_work()) | @@ -158,20 +152,6 @@ void ServiceThread::service_thread_entry(JavaThread* jt, TRAPS) { _jvmti_event = nullptr; // reset } - if (!UseNotificationThread) { - if (sensors_changed) { - LowMemoryDetector::process_sensor_changes(jt); - } - - if(has_gc_notification_event) { - GCNotifier::sendNotification(CHECK); - } - - if(has_dcmd_notification_event) { - DCmdFactory::send_notification(CHECK); - } - } - if (resolved_method_table_work) { ResolvedMethodTable::do_concurrent_work(jt); } diff --git a/src/hotspot/share/services/lowMemoryDetector.hpp b/src/hotspot/share/services/lowMemoryDetector.hpp index 5c1201b4641a8..73491ea8412de 100644 --- a/src/hotspot/share/services/lowMemoryDetector.hpp +++ b/src/hotspot/share/services/lowMemoryDetector.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -61,8 +61,7 @@ // // May need to deal with hysteresis effect. // -// Memory detection code runs in the Notification thread or -// ServiceThread depending on UseNotificationThread flag. +// Memory detection code runs in the Notification thread. class OopClosure; class MemoryPool; diff --git a/src/hotspot/share/services/management.cpp b/src/hotspot/share/services/management.cpp index a9bb72a481a57..2c9f36c098d07 100644 --- a/src/hotspot/share/services/management.cpp +++ b/src/hotspot/share/services/management.cpp @@ -149,9 +149,8 @@ void Management::init() { } void Management::initialize(TRAPS) { - if (UseNotificationThread) { - NotificationThread::initialize(); - } + NotificationThread::initialize(); + if (ManagementServer) { ResourceMark rm(THREAD); HandleMark hm(THREAD); From 65646b5f81279a7fcef3ea04ef9894cf66f77a5a Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Thu, 1 Aug 2024 03:35:43 +0000 Subject: [PATCH 163/353] 8337457: Redundant Math.round call in AquaProgressBarUI#getStringPlacement Reviewed-by: azvegint --- .../macosx/classes/com/apple/laf/AquaProgressBarUI.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/java.desktop/macosx/classes/com/apple/laf/AquaProgressBarUI.java b/src/java.desktop/macosx/classes/com/apple/laf/AquaProgressBarUI.java index bf66a1b4b0878..71500f3a95c92 100644 --- a/src/java.desktop/macosx/classes/com/apple/laf/AquaProgressBarUI.java +++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaProgressBarUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -256,7 +256,7 @@ protected Point getStringPlacement(final Graphics g, final String progressString y = oldX; } - return new Point(x + Math.round(width / 2 - stringWidth / 2), y + ((height + fontSizer.getAscent() - fontSizer.getLeading() - fontSizer.getDescent()) / 2) - 1); + return new Point(x + (width / 2 - stringWidth / 2), y + ((height + fontSizer.getAscent() - fontSizer.getLeading() - fontSizer.getDescent()) / 2) - 1); } static Dimension getCircularPreferredSize() { From cf1230a5f7e5ae4c72ec6243fff1d0b0eb27779a Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Thu, 1 Aug 2024 07:28:29 +0000 Subject: [PATCH 164/353] 8337546: Remove unused GCCause::_adaptive_size_policy Reviewed-by: tschatzl, kbarrett --- src/hotspot/share/gc/shared/gcCause.cpp | 3 --- src/hotspot/share/gc/shared/gcCause.hpp | 8 +------- .../share/classes/sun/jvm/hotspot/gc/shared/GCCause.java | 2 -- .../event/gc/collection/TestGCCauseWithParallelOld.java | 2 +- 4 files changed, 2 insertions(+), 13 deletions(-) diff --git a/src/hotspot/share/gc/shared/gcCause.cpp b/src/hotspot/share/gc/shared/gcCause.cpp index 426154fdca3e7..2be7ef7be076a 100644 --- a/src/hotspot/share/gc/shared/gcCause.cpp +++ b/src/hotspot/share/gc/shared/gcCause.cpp @@ -78,9 +78,6 @@ const char* GCCause::to_string(GCCause::Cause cause) { case _metadata_GC_clear_soft_refs: return "Metadata GC Clear Soft References"; - case _adaptive_size_policy: - return "Ergonomics"; - case _g1_inc_collection_pause: return "G1 Evacuation Pause"; diff --git a/src/hotspot/share/gc/shared/gcCause.hpp b/src/hotspot/share/gc/shared/gcCause.hpp index 152ca787fc2f7..f244d17c1ab92 100644 --- a/src/hotspot/share/gc/shared/gcCause.hpp +++ b/src/hotspot/share/gc/shared/gcCause.hpp @@ -66,8 +66,6 @@ class GCCause : public AllStatic { _metadata_GC_threshold, _metadata_GC_clear_soft_refs, - _adaptive_size_policy, - _g1_inc_collection_pause, _g1_compaction_pause, _g1_humongous_allocation, @@ -110,20 +108,16 @@ class GCCause : public AllStatic { // Causes for collection of the tenured gernation inline static bool is_tenured_allocation_failure_gc(GCCause::Cause cause) { - // _adaptive_size_policy for a full collection after a young GC // _allocation_failure is the generic cause a collection which could result // in the collection of the tenured generation if there is not enough space // in the tenured generation to support a young GC. - return (cause == GCCause::_adaptive_size_policy || - cause == GCCause::_allocation_failure); + return cause == GCCause::_allocation_failure; } // Causes for collection of the young generation inline static bool is_allocation_failure_gc(GCCause::Cause cause) { // _allocation_failure is the generic cause a collection for allocation failure - // _adaptive_size_policy is for a collection done before a full GC return (cause == GCCause::_allocation_failure || - cause == GCCause::_adaptive_size_policy || cause == GCCause::_shenandoah_allocation_failure_evac); } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/GCCause.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/GCCause.java index 4320f61bf36a9..b301f77439067 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/GCCause.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/GCCause.java @@ -48,8 +48,6 @@ public enum GCCause { _metadata_GC_threshold ("Metadata GC Threshold"), _metadata_GC_clear_soft_refs ("Metadata GC Clear Soft References"), - _adaptive_size_policy ("Ergonomics"), - _g1_inc_collection_pause ("G1 Evacuation Pause"), _g1_compaction_pause ("G1 Compaction Pause"), _g1_humongous_allocation ("G1 Humongous Allocation"), diff --git a/test/jdk/jdk/jfr/event/gc/collection/TestGCCauseWithParallelOld.java b/test/jdk/jdk/jfr/event/gc/collection/TestGCCauseWithParallelOld.java index 0715d3c5c2deb..4d8f697d83719 100644 --- a/test/jdk/jdk/jfr/event/gc/collection/TestGCCauseWithParallelOld.java +++ b/test/jdk/jdk/jfr/event/gc/collection/TestGCCauseWithParallelOld.java @@ -39,7 +39,7 @@ public static void main(String[] args) throws Exception { String testID = "ParallelOld"; String[] vmFlags = {"-XX:+UseParallelGC"}; String[] gcNames = {GCHelper.gcParallelScavenge, GCHelper.gcParallelOld}; - String[] gcCauses = {"Allocation Failure", "Ergonomics", "System.gc()", "GCLocker Initiated GC"}; + String[] gcCauses = {"Allocation Failure", "System.gc()", "GCLocker Initiated GC"}; GCGarbageCollectionUtil.test(testID, vmFlags, gcNames, gcCauses); } } From 8eb56845e46e8e4867915c8c079adfe1196dcbbc Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Thu, 1 Aug 2024 07:28:39 +0000 Subject: [PATCH 165/353] 8337550: Add documentation to TestOutOfMemoryDuringInit.java Reviewed-by: dholmes --- .../runtime/ClassInitErrors/TestOutOfMemoryDuringInit.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/hotspot/jtreg/runtime/ClassInitErrors/TestOutOfMemoryDuringInit.java b/test/hotspot/jtreg/runtime/ClassInitErrors/TestOutOfMemoryDuringInit.java index 1001ede544741..2f8d0fee72171 100644 --- a/test/hotspot/jtreg/runtime/ClassInitErrors/TestOutOfMemoryDuringInit.java +++ b/test/hotspot/jtreg/runtime/ClassInitErrors/TestOutOfMemoryDuringInit.java @@ -44,6 +44,10 @@ static class Nested { static void forceInit() { } static { while (theList != null) { + // Use the minimal allocation size to push heap occupation to + // the limit, ensuring there is not enough memory to create the + // ExceptionInInitializerError that the VM tries to create when + // the clinit throws the OOM. theList.add(new Object()); } } From f174bbd3baf351ae9248b70454b3bc5a89acd7c6 Mon Sep 17 00:00:00 2001 From: Kevin Walls Date: Thu, 1 Aug 2024 08:14:17 +0000 Subject: [PATCH 166/353] 8337473: Remove sun/management/jdp tests from ProblemList on Linux-aarch64, MacOSX Reviewed-by: dcubed --- test/jdk/ProblemList.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 8e627e27d7a8e..9fed8bb0c22df 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -515,9 +515,9 @@ java/lang/management/MemoryMXBean/Pending.java 8158837 generic- java/lang/management/MemoryMXBean/PendingAllGC.sh 8158837 generic-all java/lang/management/ThreadMXBean/ThreadMXBeanStateTest.java 8247426 generic-all -sun/management/jdp/JdpDefaultsTest.java 8241865,8308807 linux-aarch64,macosx-all,aix-ppc64 -sun/management/jdp/JdpJmxRemoteDynamicPortTest.java 8241865,8308807 macosx-all,aix-ppc64 -sun/management/jdp/JdpSpecificAddressTest.java 8241865,8308807 macosx-all,aix-ppc64 +sun/management/jdp/JdpDefaultsTest.java 8308807 aix-ppc64 +sun/management/jdp/JdpJmxRemoteDynamicPortTest.java 8308807 aix-ppc64 +sun/management/jdp/JdpSpecificAddressTest.java 8308807 aix-ppc64 sun/management/jdp/JdpOffTest.java 8308807 aix-ppc64 ############################################################################ From c6f0a35e9e3eeaab1e238e8712051a626b337e0b Mon Sep 17 00:00:00 2001 From: Matthew Donovan Date: Thu, 1 Aug 2024 11:40:44 +0000 Subject: [PATCH 167/353] 8333317: Test sun/security/pkcs11/sslecc/ClientJSSEServerJSSE.java failed with: Invalid ECDH ServerKeyExchange signature Reviewed-by: rhalade --- test/jdk/ProblemList.txt | 2 +- test/jdk/sun/security/pkcs11/PKCS11Test.java | 2 +- .../security/pkcs11/Signature/TestDSAKeyLength.java | 10 +++++++--- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 9fed8bb0c22df..f8bdfd26e8f79 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -613,7 +613,7 @@ com/sun/security/sasl/gsskerb/NoSecurityLayer.java 8039280 generic- sun/security/provider/PolicyFile/GrantAllPermToExtWhenNoPolicy.java 8039280 generic-all sun/security/provider/PolicyParser/PrincipalExpansionError.java 8039280 generic-all -sun/security/pkcs11/sslecc/ClientJSSEServerJSSE.java 8316183,8333317 generic-all +sun/security/pkcs11/sslecc/ClientJSSEServerJSSE.java 8316183 linux-ppc64le ############################################################################ diff --git a/test/jdk/sun/security/pkcs11/PKCS11Test.java b/test/jdk/sun/security/pkcs11/PKCS11Test.java index 2810040e376a6..9cb29eb8507a1 100644 --- a/test/jdk/sun/security/pkcs11/PKCS11Test.java +++ b/test/jdk/sun/security/pkcs11/PKCS11Test.java @@ -82,7 +82,7 @@ public abstract class PKCS11Test { // Version of the NSS artifact. This coincides with the version of // the NSS version - private static final String NSS_BUNDLE_VERSION = "3.96"; + private static final String NSS_BUNDLE_VERSION = "3.101"; private static final String NSSLIB = "jpg.tests.jdk.nsslib"; static double nss_version = -1; diff --git a/test/jdk/sun/security/pkcs11/Signature/TestDSAKeyLength.java b/test/jdk/sun/security/pkcs11/Signature/TestDSAKeyLength.java index a2d7f67fa32cc..b2ab96c90c62a 100644 --- a/test/jdk/sun/security/pkcs11/Signature/TestDSAKeyLength.java +++ b/test/jdk/sun/security/pkcs11/Signature/TestDSAKeyLength.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,8 +48,12 @@ public static void main(String[] args) throws Exception { @Override protected boolean skipTest(Provider provider) { - if (isNSS(provider) && (getNSSVersion() == 0.0 || getNSSVersion() >= 3.14)) { - System.out.println("Skip testing NSS " + getNSSVersion()); + double version = getNSSVersion(); + String[] versionStrs = Double.toString(version).split("\\."); + int major = Integer.parseInt(versionStrs[0]); + int minor = Integer.parseInt(versionStrs[1]); + if (isNSS(provider) && (version == 0.0 || (major >= 3 && minor >= 14))) { + System.out.println("Skip testing NSS " + version); return true; } From 022899a7eb0100bd6d738471f52e5028e3e5f18e Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Thu, 1 Aug 2024 13:39:49 +0000 Subject: [PATCH 168/353] 8337641: G1: Remove unused G1CollectedHeap::alloc_highest_free_region Reviewed-by: tschatzl --- src/hotspot/share/gc/g1/g1CollectedHeap.cpp | 14 ------------ src/hotspot/share/gc/g1/g1CollectedHeap.hpp | 4 ---- .../share/gc/g1/g1HeapRegionManager.cpp | 22 ------------------- .../share/gc/g1/g1HeapRegionManager.hpp | 5 ----- 4 files changed, 45 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index afd7b8948598e..3b8fb145f1692 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp @@ -2941,20 +2941,6 @@ void G1CollectedHeap::retire_gc_alloc_region(G1HeapRegion* alloc_region, G1HeapRegionPrinter::retire(alloc_region); } -G1HeapRegion* G1CollectedHeap::alloc_highest_free_region() { - bool expanded = false; - uint index = _hrm.find_highest_free(&expanded); - - if (index != G1_NO_HRM_INDEX) { - if (expanded) { - log_debug(gc, ergo, heap)("Attempt heap expansion (requested address range outside heap bounds). region size: " SIZE_FORMAT "B", - G1HeapRegion::GrainWords * HeapWordSize); - } - return _hrm.allocate_free_regions_starting_at(index, 1); - } - return nullptr; -} - void G1CollectedHeap::mark_evac_failure_object(uint worker_id, const oop obj, size_t obj_size) const { assert(!_cm->is_marked_in_bitmap(obj), "must be"); diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp index ec3cf8eafe3a0..59ade93967872 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp @@ -669,10 +669,6 @@ class G1CollectedHeap : public CollectedHeap { // Allocates a new heap region instance. G1HeapRegion* new_heap_region(uint hrs_index, MemRegion mr); - // Allocate the highest free region in the reserved heap. This will commit - // regions as necessary. - G1HeapRegion* alloc_highest_free_region(); - // Frees a region by resetting its metadata and adding it to the free list // passed as a parameter (this is usually a local list which will be appended // to the master free list later or null if free list management is handled diff --git a/src/hotspot/share/gc/g1/g1HeapRegionManager.cpp b/src/hotspot/share/gc/g1/g1HeapRegionManager.cpp index b37e65f8b868a..2369a0f7812ea 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionManager.cpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionManager.cpp @@ -529,28 +529,6 @@ void G1HeapRegionManager::iterate(G1HeapRegionIndexClosure* blk) const { } } -uint G1HeapRegionManager::find_highest_free(bool* expanded) { - // Loop downwards from the highest region index, looking for an - // entry which is either free or not yet committed. If not yet - // committed, expand at that index. - for (uint curr = reserved_length(); curr-- > 0;) { - G1HeapRegion* hr = _regions.get_by_index(curr); - if (hr == nullptr || !is_available(curr)) { - // Found uncommitted and free region, expand to make it available for use. - expand_exact(curr, 1, nullptr); - assert(at(curr)->is_free(), "Region (%u) must be available and free after expand", curr); - - *expanded = true; - return curr; - } - if (hr->is_free()) { - *expanded = false; - return curr; - } - } - return G1_NO_HRM_INDEX; -} - bool G1HeapRegionManager::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()); diff --git a/src/hotspot/share/gc/g1/g1HeapRegionManager.hpp b/src/hotspot/share/gc/g1/g1HeapRegionManager.hpp index d3f1843f07dbf..81bca4ce6381c 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionManager.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionManager.hpp @@ -256,11 +256,6 @@ class G1HeapRegionManager: public CHeapObj { G1HeapRegion* next_region_in_heap(const G1HeapRegion* r) const; - // Find the highest free or uncommitted region in the reserved heap, - // and if uncommitted, commit it. If none are available, return G1_NO_HRM_INDEX. - // Set the 'expanded' boolean true if a new region was committed. - uint find_highest_free(bool* expanded); - // 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. From 27af80ef9e676aaf9016279ff0c7990e2cdfe9ed Mon Sep 17 00:00:00 2001 From: Jorn Vernee Date: Thu, 1 Aug 2024 14:36:03 +0000 Subject: [PATCH 169/353] 8324260: java/foreign/TestStubAllocFailure.java run timeout with -Xcomp Reviewed-by: alanb, jpai, shade --- test/jdk/java/foreign/TestStubAllocFailure.java | 1 + 1 file changed, 1 insertion(+) diff --git a/test/jdk/java/foreign/TestStubAllocFailure.java b/test/jdk/java/foreign/TestStubAllocFailure.java index b20b3e88ea221..154b455e3f286 100644 --- a/test/jdk/java/foreign/TestStubAllocFailure.java +++ b/test/jdk/java/foreign/TestStubAllocFailure.java @@ -25,6 +25,7 @@ * @test * @library ../ /test/lib * @requires jdk.foreign.linker != "FALLBACK" + * @requires vm.compMode != "Xcomp" * @run testng/othervm/native * --enable-native-access=ALL-UNNAMED * TestStubAllocFailure From 9fe6e2316aef8fd125a7905cff2a2d9ae5d26109 Mon Sep 17 00:00:00 2001 From: Hannes Greule Date: Thu, 1 Aug 2024 14:41:25 +0000 Subject: [PATCH 170/353] 8335638: Calling VarHandle.{access-mode} methods reflectively throws wrong exception Reviewed-by: liach --- src/hotspot/share/prims/methodHandles.cpp | 57 ++++++++++++++++++- .../VarHandles/VarHandleTestReflection.java | 25 +++++++- 2 files changed, 77 insertions(+), 5 deletions(-) diff --git a/src/hotspot/share/prims/methodHandles.cpp b/src/hotspot/share/prims/methodHandles.cpp index 473ac396997bd..4f33055d6a3fe 100644 --- a/src/hotspot/share/prims/methodHandles.cpp +++ b/src/hotspot/share/prims/methodHandles.cpp @@ -1360,6 +1360,18 @@ JVM_ENTRY(jobject, MH_invokeExact_UOE(JNIEnv* env, jobject mh, jobjectArray args } JVM_END +/** + * Throws a java/lang/UnsupportedOperationException unconditionally. + * This is required by the specification of VarHandle.{access-mode} if + * invoked directly. + */ +JVM_ENTRY(jobject, VH_UOE(JNIEnv* env, jobject vh, jobjectArray args)) { + THROW_MSG_NULL(vmSymbols::java_lang_UnsupportedOperationException(), "VarHandle access mode methods cannot be invoked reflectively"); + return nullptr; +} +JVM_END + + /// JVM_RegisterMethodHandleMethods #define LANG "Ljava/lang/" @@ -1399,6 +1411,40 @@ static JNINativeMethod MH_methods[] = { {CC "invoke", CC "([" OBJ ")" OBJ, FN_PTR(MH_invoke_UOE)}, {CC "invokeExact", CC "([" OBJ ")" OBJ, FN_PTR(MH_invokeExact_UOE)} }; +static JNINativeMethod VH_methods[] = { + // UnsupportedOperationException throwers + {CC "get", CC "([" OBJ ")" OBJ, FN_PTR(VH_UOE)}, + {CC "set", CC "([" OBJ ")V", FN_PTR(VH_UOE)}, + {CC "getVolatile", CC "([" OBJ ")" OBJ, FN_PTR(VH_UOE)}, + {CC "setVolatile", CC "([" OBJ ")V", FN_PTR(VH_UOE)}, + {CC "getAcquire", CC "([" OBJ ")" OBJ, FN_PTR(VH_UOE)}, + {CC "setRelease", CC "([" OBJ ")V", FN_PTR(VH_UOE)}, + {CC "getOpaque", CC "([" OBJ ")" OBJ, FN_PTR(VH_UOE)}, + {CC "setOpaque", CC "([" OBJ ")V", FN_PTR(VH_UOE)}, + {CC "compareAndSet", CC "([" OBJ ")Z", FN_PTR(VH_UOE)}, + {CC "compareAndExchange", CC "([" OBJ ")" OBJ, FN_PTR(VH_UOE)}, + {CC "compareAndExchangeAcquire", CC "([" OBJ ")" OBJ, FN_PTR(VH_UOE)}, + {CC "compareAndExchangeRelease", CC "([" OBJ ")" OBJ, FN_PTR(VH_UOE)}, + {CC "weakCompareAndSetPlain", CC "([" OBJ ")Z", FN_PTR(VH_UOE)}, + {CC "weakCompareAndSet", CC "([" OBJ ")Z", FN_PTR(VH_UOE)}, + {CC "weakCompareAndSetAcquire", CC "([" OBJ ")Z", FN_PTR(VH_UOE)}, + {CC "weakCompareAndSetRelease", CC "([" OBJ ")Z", FN_PTR(VH_UOE)}, + {CC "getAndSet", CC "([" OBJ ")" OBJ, FN_PTR(VH_UOE)}, + {CC "getAndSetAcquire", CC "([" OBJ ")" OBJ, FN_PTR(VH_UOE)}, + {CC "getAndSetRelease", CC "([" OBJ ")" OBJ, FN_PTR(VH_UOE)}, + {CC "getAndAdd", CC "([" OBJ ")" OBJ, FN_PTR(VH_UOE)}, + {CC "getAndAddAcquire", CC "([" OBJ ")" OBJ, FN_PTR(VH_UOE)}, + {CC "getAndAddRelease", CC "([" OBJ ")" OBJ, FN_PTR(VH_UOE)}, + {CC "getAndBitwiseOr", CC "([" OBJ ")" OBJ, FN_PTR(VH_UOE)}, + {CC "getAndBitwiseOrAcquire", CC "([" OBJ ")" OBJ, FN_PTR(VH_UOE)}, + {CC "getAndBitwiseOrRelease", CC "([" OBJ ")" OBJ, FN_PTR(VH_UOE)}, + {CC "getAndBitwiseAnd", CC "([" OBJ ")" OBJ, FN_PTR(VH_UOE)}, + {CC "getAndBitwiseAndAcquire", CC "([" OBJ ")" OBJ, FN_PTR(VH_UOE)}, + {CC "getAndBitwiseAndRelease", CC "([" OBJ ")" OBJ, FN_PTR(VH_UOE)}, + {CC "getAndBitwiseXor", CC "([" OBJ ")" OBJ, FN_PTR(VH_UOE)}, + {CC "getAndBitwiseXorAcquire", CC "([" OBJ ")" OBJ, FN_PTR(VH_UOE)}, + {CC "getAndBitwiseXorRelease", CC "([" OBJ ")" OBJ, FN_PTR(VH_UOE)} +}; /** * This one function is exported, used by NativeLookup. @@ -1406,9 +1452,12 @@ static JNINativeMethod MH_methods[] = { JVM_ENTRY(void, JVM_RegisterMethodHandleMethods(JNIEnv *env, jclass MHN_class)) { assert(!MethodHandles::enabled(), "must not be enabled"); assert(vmClasses::MethodHandle_klass() != nullptr, "should be present"); + assert(vmClasses::VarHandle_klass() != nullptr, "should be present"); - oop mirror = vmClasses::MethodHandle_klass()->java_mirror(); - jclass MH_class = (jclass) JNIHandles::make_local(THREAD, mirror); + oop mh_mirror = vmClasses::MethodHandle_klass()->java_mirror(); + oop vh_mirror = vmClasses::VarHandle_klass()->java_mirror(); + jclass MH_class = (jclass) JNIHandles::make_local(THREAD, mh_mirror); + jclass VH_class = (jclass) JNIHandles::make_local(THREAD, vh_mirror); { ThreadToNativeFromVM ttnfv(thread); @@ -1420,6 +1469,10 @@ JVM_ENTRY(void, JVM_RegisterMethodHandleMethods(JNIEnv *env, jclass MHN_class)) status = env->RegisterNatives(MH_class, MH_methods, sizeof(MH_methods)/sizeof(JNINativeMethod)); guarantee(status == JNI_OK && !env->ExceptionOccurred(), "register java.lang.invoke.MethodHandle natives"); + + status = env->RegisterNatives(VH_class, VH_methods, sizeof(VH_methods)/sizeof(JNINativeMethod)); + guarantee(status == JNI_OK && !env->ExceptionOccurred(), + "register java.lang.invoke.VarHandle natives"); } log_debug(methodhandles, indy)("MethodHandle support loaded (using LambdaForms)"); diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestReflection.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestReflection.java index 652272ca8a8f4..b20e18d263edd 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestReflection.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestReflection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,6 +33,7 @@ import java.lang.invoke.MethodHandleInfo; import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.stream.Stream; @@ -52,15 +53,33 @@ static VarHandle handle() throws Exception { } @Test(dataProvider = "accessModesProvider", expectedExceptions = IllegalArgumentException.class) - public void methodInvocation(VarHandle.AccessMode accessMode) throws Exception { + public void methodInvocationArgumentMismatch(VarHandle.AccessMode accessMode) throws Exception { VarHandle v = handle(); - // Try a reflective invoke using a Method + // Try a reflective invoke using a Method, with no arguments Method vhm = VarHandle.class.getMethod(accessMode.methodName(), Object[].class); vhm.invoke(v, new Object[]{}); } + @Test(dataProvider = "accessModesProvider") + public void methodInvocationMatchingArguments(VarHandle.AccessMode accessMode) throws Exception { + VarHandle v = handle(); + + // Try a reflective invoke using a Method, with the minimal required arguments + + Method vhm = VarHandle.class.getMethod(accessMode.methodName(), Object[].class); + Object arg = new Object[0]; + try { + vhm.invoke(v, arg); + } catch (InvocationTargetException e) { + if (!(e.getCause() instanceof UnsupportedOperationException)) { + throw new RuntimeException("expected UnsupportedOperationException but got: " + + e.getCause().getClass().getName(), e); + } + } + } + @Test(dataProvider = "accessModesProvider", expectedExceptions = UnsupportedOperationException.class) public void methodHandleInvoke(VarHandle.AccessMode accessMode) throws Throwable { VarHandle v = handle(); From f1fa64b6b67f2eef916b8d92eb522ccb19035e12 Mon Sep 17 00:00:00 2001 From: Mark Powers Date: Thu, 1 Aug 2024 16:37:20 +0000 Subject: [PATCH 171/353] 4966250: SSLSessionContext.setSessionTimeout() documentation could be updated Reviewed-by: mullan --- .../javax/net/ssl/SSLSessionContext.java | 48 ++++++++++--------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/src/java.base/share/classes/javax/net/ssl/SSLSessionContext.java b/src/java.base/share/classes/javax/net/ssl/SSLSessionContext.java index e4b2560415fc2..fd5ef0bcc5868 100644 --- a/src/java.base/share/classes/javax/net/ssl/SSLSessionContext.java +++ b/src/java.base/share/classes/javax/net/ssl/SSLSessionContext.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,8 +30,8 @@ /** - * A SSLSessionContext represents a set of - * SSLSessions associated with a single entity. For example, + * A {@code SSLSessionContext} represents a set of + * {@code SSLSession}s associated with a single entity. For example, * it could be associated with a server or client who participates in many * sessions concurrently. *

@@ -41,7 +41,7 @@ * Session contexts may not contain all sessions. For example, stateless * sessions are not stored in the session context. *

- * There are SSLSessionContext parameters that affect how + * There are {@code SSLSessionContext} parameters that affect how * sessions are stored: *

    *
  • Sessions can be set to expire after a specified @@ -50,7 +50,7 @@ * can be limited. *
* A session can be retrieved based on its session id, and all session id's - * in a SSLSessionContext can be listed. + * in a {@code SSLSessionContext} can be listed. * * @see SSLSession * @@ -61,19 +61,19 @@ public interface SSLSessionContext { /** - * Returns the SSLSession bound to the specified session id. + * Returns the {@code SSLSession} bound to the specified session id. * * @param sessionId the Session identifier - * @return the SSLSession or null if + * @return the {@code SSLSession} or null if * the specified session id does not refer to a valid SSLSession. * - * @throws NullPointerException if sessionId is null. + * @throws NullPointerException if {@code sessionId} is null. */ SSLSession getSession(byte[] sessionId); /** * Returns an Enumeration of all known session id's grouped under this - * SSLSessionContext. + * {@code SSLSessionContext}. *

Session contexts may not contain all sessions. For example, * stateless sessions are not stored in the session context. * @@ -82,16 +82,17 @@ public interface SSLSessionContext { Enumeration getIds(); /** - * Sets the timeout limit for SSLSession objects grouped - * under this SSLSessionContext. + * Sets the timeout limit for {@code SSLSession} objects grouped + * under this {@code SSLSessionContext}. *

* If the timeout limit is set to 't' seconds, a session exceeds the * timeout limit 't' seconds after its creation time. * When the timeout limit is exceeded for a session, the - * SSLSession object is invalidated and future connections - * cannot resume or rejoin the session. + * {@code SSLSession} object is marked so that future connections + * cannot resume or rejoin the session. Active sessions can continue + * to be used so long as resume and rejoin operations are not attempted. * A check for sessions exceeding the timeout is made immediately whenever - * the timeout limit is changed for this SSLSessionContext. + * the timeout limit is changed for this {@code SSLSessionContext}. * * @apiNote Note that the JDK Implementation uses default values for both * the session cache size and timeout. See @@ -109,17 +110,18 @@ public interface SSLSessionContext { void setSessionTimeout(int seconds); /** - * Returns the timeout limit of SSLSession objects grouped - * under this SSLSessionContext. + * Returns the timeout limit of {@code SSLSession} objects grouped + * under this {@code SSLSessionContext}. *

* If the timeout limit is set to 't' seconds, a session exceeds the * timeout limit 't' seconds after its creation time. * When the timeout limit is exceeded for a session, the - * SSLSession object is invalidated and future connections - * cannot resume or rejoin the session. + * {@code SSLSession} object is marked so that future connections + * cannot resume or rejoin the session. Active sessions can continue + * to be used so long as resume and rejoin operations are not attempted. * A check for sessions exceeding the timeout limit is made immediately * whenever the timeout limit is changed for this - * SSLSessionContext. + * {@code SSLSessionContext}. * * @implNote The JDK implementation returns the session timeout as set by * the {@code setSessionTimeout} method, or if not set, a default @@ -133,8 +135,8 @@ public interface SSLSessionContext { int getSessionTimeout(); /** - * Sets the size of the cache used for storing SSLSession - * objects grouped under this SSLSessionContext. + * Sets the size of the cache used for storing {@code SSLSession} + * objects grouped under this {@code SSLSessionContext}. * * @apiNote Note that the JDK Implementation uses default values for both * the session cache size and timeout. See @@ -152,8 +154,8 @@ public interface SSLSessionContext { void setSessionCacheSize(int size); /** - * Returns the size of the cache used for storing SSLSession - * objects grouped under this SSLSessionContext. + * Returns the size of the cache used for storing {@code SSLSession} + * objects grouped under this {@code SSLSessionContext}. * * @implNote The JDK implementation returns the cache size as set by * the {@code setSessionCacheSize} method, or if not set, the From 21e86d10a726fe707febb0111f5b80d8d1d29f03 Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Thu, 1 Aug 2024 19:02:33 +0000 Subject: [PATCH 172/353] 8334405: java/nio/channels/Selector/SelectWithConsumer.java#id0 failed in testWakeupDuringSelect Reviewed-by: dfuchs, alanb, vtewari --- .../channels/Selector/SelectWithConsumer.java | 51 ++++++++++++++----- 1 file changed, 37 insertions(+), 14 deletions(-) diff --git a/test/jdk/java/nio/channels/Selector/SelectWithConsumer.java b/test/jdk/java/nio/channels/Selector/SelectWithConsumer.java index de8b48ec22d98..41edb207239e3 100644 --- a/test/jdk/java/nio/channels/Selector/SelectWithConsumer.java +++ b/test/jdk/java/nio/channels/Selector/SelectWithConsumer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -308,11 +308,10 @@ public void testTimeout() throws Exception { Pipe.SinkChannel sink = p.sink(); source.configureBlocking(false); source.register(sel, SelectionKey.OP_READ); - long start = System.currentTimeMillis(); + long start = millisTime(); int n = sel.select(k -> assertTrue(false), 1000L); - long duration = System.currentTimeMillis() - start; + expectDuration(start, 500, Long.MAX_VALUE); assertTrue(n == 0); - assertTrue(duration > 500, "select took " + duration + " ms"); } finally { closePipe(p); } @@ -332,11 +331,10 @@ public void testWakeupBeforeSelect() throws Exception { // select(Consumer, timeout) try (Selector sel = Selector.open()) { sel.wakeup(); - long start = System.currentTimeMillis(); + long start = millisTime(); int n = sel.select(k -> assertTrue(false), 60*1000); - long duration = System.currentTimeMillis() - start; + expectDuration(start, 0, 20_000); assertTrue(n == 0); - assertTrue(duration < 5000, "select took " + duration + " ms"); } } @@ -354,12 +352,10 @@ public void testWakeupDuringSelect() throws Exception { // select(Consumer, timeout) try (Selector sel = Selector.open()) { scheduleWakeup(sel, 1, SECONDS); - long start = System.currentTimeMillis(); + long start = millisTime(); int n = sel.select(k -> assertTrue(false), 60*1000); - long duration = System.currentTimeMillis() - start; + expectDuration(start, 0, 20_000); assertTrue(n == 0); - assertTrue(duration > 500 && duration < 10*1000, - "select took " + duration + " ms"); } } @@ -381,11 +377,10 @@ public void testInterruptBeforeSelect() throws Exception { // select(Consumer, timeout) try (Selector sel = Selector.open()) { Thread.currentThread().interrupt(); - long start = System.currentTimeMillis(); + long start = millisTime(); int n = sel.select(k -> assertTrue(false), 60*1000); - long duration = System.currentTimeMillis() - start; + expectDuration(start, 0, 20_000); assertTrue(n == 0); - assertTrue(duration < 5000, "select took " + duration + " ms"); assertTrue(Thread.currentThread().isInterrupted()); assertTrue(sel.isOpen()); } finally { @@ -762,4 +757,32 @@ static ByteBuffer messageBuffer() { throw new RuntimeException(e); } } + + /** + * Returns the current time in milliseconds. + */ + private static long millisTime() { + long now = System.nanoTime(); + return TimeUnit.MILLISECONDS.convert(now, TimeUnit.NANOSECONDS); + } + + /** + * Check the duration of a task. The method will fail with an + * AssertionError if the millisecond duration does not satisfy: + * + * duration >= min && duration <= max + * + * Note that the inequalities are not strict, i.e., are inclusive. + * + * @param start start time, in milliseconds + * @param min minimum expected duration, in milliseconds + * @param max maximum expected duration, in milliseconds + */ + private static void expectDuration(long start, long min, long max) { + long duration = millisTime() - start; + assertTrue(duration >= min, + "Duration " + duration + "ms, expected >= " + min + "ms"); + assertTrue(duration <= max, + "Duration " + duration + "ms, expected <= " + max + "ms"); + } } From dc35f3e8a84c8f622a4cabb8aee0f96de2e2ea30 Mon Sep 17 00:00:00 2001 From: Sandhya Viswanathan Date: Thu, 1 Aug 2024 23:02:23 +0000 Subject: [PATCH 173/353] 8337062: x86_64: Unordered add/mul reduction support for vector api Reviewed-by: jbhateja, sgibbons --- src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp | 119 ++++++++++++++++ src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp | 18 +++ src/hotspot/cpu/x86/x86.ad | 132 +++++++++++++++++- .../vector/Double128VectorTests.java | 25 ++-- .../vector/Double256VectorTests.java | 25 ++-- .../vector/Double512VectorTests.java | 25 ++-- .../incubator/vector/Double64VectorTests.java | 25 ++-- .../vector/DoubleMaxVectorTests.java | 25 ++-- .../incubator/vector/Float128VectorTests.java | 25 ++-- .../incubator/vector/Float256VectorTests.java | 25 ++-- .../incubator/vector/Float512VectorTests.java | 25 ++-- .../incubator/vector/Float64VectorTests.java | 25 ++-- .../incubator/vector/FloatMaxVectorTests.java | 25 ++-- test/jdk/jdk/incubator/vector/gen-template.sh | 3 +- .../Unit-Reduction-Masked-op.template | 2 +- .../templates/Unit-Reduction-op.template | 2 +- .../vector/templates/Unit-header.template | 17 ++- 17 files changed, 416 insertions(+), 127 deletions(-) diff --git a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp index 66a782ba9c622..faab09b7c17b4 100644 --- a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp @@ -1786,6 +1786,16 @@ void C2_MacroAssembler::reduce_operation_128(BasicType typ, int opcode, XMMRegis } } +void C2_MacroAssembler::unordered_reduce_operation_128(BasicType typ, int opcode, XMMRegister dst, XMMRegister src) { + switch (opcode) { + case Op_AddReductionVF: addps(dst, src); break; + case Op_AddReductionVD: addpd(dst, src); break; + case Op_MulReductionVF: mulps(dst, src); break; + case Op_MulReductionVD: mulpd(dst, src); break; + default: assert(false, "%s", NodeClassNames[opcode]); + } +} + void C2_MacroAssembler::reduce_operation_256(BasicType typ, int opcode, XMMRegister dst, XMMRegister src1, XMMRegister src2) { int vector_len = Assembler::AVX_256bit; @@ -1834,6 +1844,18 @@ void C2_MacroAssembler::reduce_operation_256(BasicType typ, int opcode, XMMRegis } } +void C2_MacroAssembler::unordered_reduce_operation_256(BasicType typ, int opcode, XMMRegister dst, XMMRegister src1, XMMRegister src2) { + int vector_len = Assembler::AVX_256bit; + + switch (opcode) { + case Op_AddReductionVF: vaddps(dst, src1, src2, vector_len); break; + case Op_AddReductionVD: vaddpd(dst, src1, src2, vector_len); break; + case Op_MulReductionVF: vmulps(dst, src1, src2, vector_len); break; + case Op_MulReductionVD: vmulpd(dst, src1, src2, vector_len); break; + default: assert(false, "%s", NodeClassNames[opcode]); + } +} + void C2_MacroAssembler::reduce_fp(int opcode, int vlen, XMMRegister dst, XMMRegister src, XMMRegister vtmp1, XMMRegister vtmp2) { @@ -1852,6 +1874,24 @@ void C2_MacroAssembler::reduce_fp(int opcode, int vlen, } } +void C2_MacroAssembler::unordered_reduce_fp(int opcode, int vlen, + XMMRegister dst, XMMRegister src, + XMMRegister vtmp1, XMMRegister vtmp2) { + switch (opcode) { + case Op_AddReductionVF: + case Op_MulReductionVF: + unorderedReduceF(opcode, vlen, dst, src, vtmp1, vtmp2); + break; + + case Op_AddReductionVD: + case Op_MulReductionVD: + unorderedReduceD(opcode, vlen, dst, src, vtmp1, vtmp2); + break; + + default: assert(false, "%s", NodeClassNames[opcode]); + } +} + void C2_MacroAssembler::reduceB(int opcode, int vlen, Register dst, Register src1, XMMRegister src2, XMMRegister vtmp1, XMMRegister vtmp2) { @@ -1954,6 +1994,45 @@ void C2_MacroAssembler::reduceD(int opcode, int vlen, XMMRegister dst, XMMRegist } } +void C2_MacroAssembler::unorderedReduceF(int opcode, int vlen, XMMRegister dst, XMMRegister src, XMMRegister vtmp1, XMMRegister vtmp2) { + switch (vlen) { + case 2: + assert(vtmp1 == xnoreg, ""); + assert(vtmp2 == xnoreg, ""); + unorderedReduce2F(opcode, dst, src); + break; + case 4: + assert(vtmp2 == xnoreg, ""); + unorderedReduce4F(opcode, dst, src, vtmp1); + break; + case 8: + unorderedReduce8F(opcode, dst, src, vtmp1, vtmp2); + break; + case 16: + unorderedReduce16F(opcode, dst, src, vtmp1, vtmp2); + break; + default: assert(false, "wrong vector length"); + } +} + +void C2_MacroAssembler::unorderedReduceD(int opcode, int vlen, XMMRegister dst, XMMRegister src, XMMRegister vtmp1, XMMRegister vtmp2) { + switch (vlen) { + case 2: + assert(vtmp1 == xnoreg, ""); + assert(vtmp2 == xnoreg, ""); + unorderedReduce2D(opcode, dst, src); + break; + case 4: + assert(vtmp2 == xnoreg, ""); + unorderedReduce4D(opcode, dst, src, vtmp1); + break; + case 8: + unorderedReduce8D(opcode, dst, src, vtmp1, vtmp2); + break; + default: assert(false, "wrong vector length"); + } +} + void C2_MacroAssembler::reduce2I(int opcode, Register dst, Register src1, XMMRegister src2, XMMRegister vtmp1, XMMRegister vtmp2) { if (opcode == Op_AddReductionVI) { if (vtmp1 != src2) { @@ -2181,6 +2260,29 @@ void C2_MacroAssembler::reduce16F(int opcode, XMMRegister dst, XMMRegister src, reduce8F(opcode, dst, vtmp1, vtmp1, vtmp2); } +void C2_MacroAssembler::unorderedReduce2F(int opcode, XMMRegister dst, XMMRegister src) { + pshufd(dst, src, 0x1); + reduce_operation_128(T_FLOAT, opcode, dst, src); +} + +void C2_MacroAssembler::unorderedReduce4F(int opcode, XMMRegister dst, XMMRegister src, XMMRegister vtmp) { + pshufd(vtmp, src, 0xE); + unordered_reduce_operation_128(T_FLOAT, opcode, vtmp, src); + unorderedReduce2F(opcode, dst, vtmp); +} + +void C2_MacroAssembler::unorderedReduce8F(int opcode, XMMRegister dst, XMMRegister src, XMMRegister vtmp1, XMMRegister vtmp2) { + vextractf128_high(vtmp1, src); + unordered_reduce_operation_128(T_FLOAT, opcode, vtmp1, src); + unorderedReduce4F(opcode, dst, vtmp1, vtmp2); +} + +void C2_MacroAssembler::unorderedReduce16F(int opcode, XMMRegister dst, XMMRegister src, XMMRegister vtmp1, XMMRegister vtmp2) { + vextractf64x4_high(vtmp2, src); + unordered_reduce_operation_256(T_FLOAT, opcode, vtmp2, vtmp2, src); + unorderedReduce8F(opcode, dst, vtmp2, vtmp1, vtmp2); +} + void C2_MacroAssembler::reduce2D(int opcode, XMMRegister dst, XMMRegister src, XMMRegister vtmp) { reduce_operation_128(T_DOUBLE, opcode, dst, src); pshufd(vtmp, src, 0xE); @@ -2199,6 +2301,23 @@ void C2_MacroAssembler::reduce8D(int opcode, XMMRegister dst, XMMRegister src, X reduce4D(opcode, dst, vtmp1, vtmp1, vtmp2); } +void C2_MacroAssembler::unorderedReduce2D(int opcode, XMMRegister dst, XMMRegister src) { + pshufd(dst, src, 0xE); + reduce_operation_128(T_DOUBLE, opcode, dst, src); +} + +void C2_MacroAssembler::unorderedReduce4D(int opcode, XMMRegister dst, XMMRegister src, XMMRegister vtmp) { + vextractf128_high(vtmp, src); + unordered_reduce_operation_128(T_DOUBLE, opcode, vtmp, src); + unorderedReduce2D(opcode, dst, vtmp); +} + +void C2_MacroAssembler::unorderedReduce8D(int opcode, XMMRegister dst, XMMRegister src, XMMRegister vtmp1, XMMRegister vtmp2) { + vextractf64x4_high(vtmp2, src); + unordered_reduce_operation_256(T_DOUBLE, opcode, vtmp2, vtmp2, src); + unorderedReduce4D(opcode, dst, vtmp2, vtmp1); +} + void C2_MacroAssembler::evmovdqu(BasicType type, KRegister kmask, XMMRegister dst, Address src, bool merge, int vector_len) { MacroAssembler::evmovdqu(type, kmask, dst, src, merge, vector_len); } diff --git a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp index e268ed3dd7a46..af57546b3d143 100644 --- a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp @@ -149,6 +149,9 @@ void reduce_fp(int opcode, int vlen, XMMRegister dst, XMMRegister src, XMMRegister vtmp1, XMMRegister vtmp2 = xnoreg); + void unordered_reduce_fp(int opcode, int vlen, + XMMRegister dst, XMMRegister src, + XMMRegister vtmp1 = xnoreg, XMMRegister vtmp2 = xnoreg); void reduceB(int opcode, int vlen, Register dst, Register src1, XMMRegister src2, XMMRegister vtmp1, XMMRegister vtmp2); void mulreduceB(int opcode, int vlen, Register dst, Register src1, XMMRegister src2, XMMRegister vtmp1, XMMRegister vtmp2); void reduceS(int opcode, int vlen, Register dst, Register src1, XMMRegister src2, XMMRegister vtmp1, XMMRegister vtmp2); @@ -161,6 +164,8 @@ private: void reduceF(int opcode, int vlen, XMMRegister dst, XMMRegister src, XMMRegister vtmp1, XMMRegister vtmp2); void reduceD(int opcode, int vlen, XMMRegister dst, XMMRegister src, XMMRegister vtmp1, XMMRegister vtmp2); + void unorderedReduceF(int opcode, int vlen, XMMRegister dst, XMMRegister src, XMMRegister vtmp1, XMMRegister vtmp2); + void unorderedReduceD(int opcode, int vlen, XMMRegister dst, XMMRegister src, XMMRegister vtmp1, XMMRegister vtmp2); // Int Reduction void reduce2I (int opcode, Register dst, Register src1, XMMRegister src2, XMMRegister vtmp1, XMMRegister vtmp2); @@ -197,14 +202,27 @@ void reduce8F (int opcode, XMMRegister dst, XMMRegister src, XMMRegister vtmp1, XMMRegister vtmp2); void reduce16F(int opcode, XMMRegister dst, XMMRegister src, XMMRegister vtmp1, XMMRegister vtmp2); + // Unordered Float Reduction + void unorderedReduce2F(int opcode, XMMRegister dst, XMMRegister src); + void unorderedReduce4F(int opcode, XMMRegister dst, XMMRegister src, XMMRegister vtmp); + void unorderedReduce8F(int opcode, XMMRegister dst, XMMRegister src, XMMRegister vtmp1, XMMRegister vtmp2); + void unorderedReduce16F(int opcode, XMMRegister dst, XMMRegister src, XMMRegister vtmp1, XMMRegister vtmp2); + // Double Reduction void reduce2D(int opcode, XMMRegister dst, XMMRegister src, XMMRegister vtmp); void reduce4D(int opcode, XMMRegister dst, XMMRegister src, XMMRegister vtmp1, XMMRegister vtmp2); void reduce8D(int opcode, XMMRegister dst, XMMRegister src, XMMRegister vtmp1, XMMRegister vtmp2); + // Unordered Double Reduction + void unorderedReduce2D(int opcode, XMMRegister dst, XMMRegister src); + void unorderedReduce4D(int opcode, XMMRegister dst, XMMRegister src, XMMRegister vtmp); + void unorderedReduce8D(int opcode, XMMRegister dst, XMMRegister src, XMMRegister vtmp1, XMMRegister vtmp2); + // Base reduction instruction void reduce_operation_128(BasicType typ, int opcode, XMMRegister dst, XMMRegister src); void reduce_operation_256(BasicType typ, int opcode, XMMRegister dst, XMMRegister src1, XMMRegister src2); + void unordered_reduce_operation_128(BasicType typ, int opcode, XMMRegister dst, XMMRegister src); + void unordered_reduce_operation_256(BasicType typ, int opcode, XMMRegister dst, XMMRegister src1, XMMRegister src2); public: #ifdef _LP64 diff --git a/src/hotspot/cpu/x86/x86.ad b/src/hotspot/cpu/x86/x86.ad index d90ba901ac0a8..2b29dd14e4b27 100644 --- a/src/hotspot/cpu/x86/x86.ad +++ b/src/hotspot/cpu/x86/x86.ad @@ -5109,7 +5109,7 @@ instruct reductionL_avx512dq(rRegL dst, rRegL src1, vec src2, vec vtmp1, vec vtm // =======================Float Reduction========================================== instruct reductionF128(regF dst, vec src, vec vtmp) %{ - predicate(Matcher::vector_length(n->in(2)) <= 4); // src + predicate(n->as_Reduction()->requires_strict_order() && Matcher::vector_length(n->in(2)) <= 4); // src match(Set dst (AddReductionVF dst src)); match(Set dst (MulReductionVF dst src)); effect(TEMP dst, TEMP vtmp); @@ -5123,7 +5123,7 @@ instruct reductionF128(regF dst, vec src, vec vtmp) %{ %} instruct reduction8F(regF dst, vec src, vec vtmp1, vec vtmp2) %{ - predicate(Matcher::vector_length(n->in(2)) == 8); // src + predicate(n->as_Reduction()->requires_strict_order() && Matcher::vector_length(n->in(2)) == 8); // src match(Set dst (AddReductionVF dst src)); match(Set dst (MulReductionVF dst src)); effect(TEMP dst, TEMP vtmp1, TEMP vtmp2); @@ -5137,7 +5137,7 @@ instruct reduction8F(regF dst, vec src, vec vtmp1, vec vtmp2) %{ %} instruct reduction16F(regF dst, legVec src, legVec vtmp1, legVec vtmp2) %{ - predicate(Matcher::vector_length(n->in(2)) == 16); // src + predicate(n->as_Reduction()->requires_strict_order() && Matcher::vector_length(n->in(2)) == 16); // src match(Set dst (AddReductionVF dst src)); match(Set dst (MulReductionVF dst src)); effect(TEMP dst, TEMP vtmp1, TEMP vtmp2); @@ -5150,10 +5150,79 @@ instruct reduction16F(regF dst, legVec src, legVec vtmp1, legVec vtmp2) %{ ins_pipe( pipe_slow ); %} + +instruct unordered_reduction2F(regF dst, regF src1, vec src2) %{ + // Non-strictly ordered floating-point add/mul reduction for floats. This rule is + // intended for the VectorAPI (which allows for non-strictly ordered add/mul reduction). + // src1 contains reduction identity + predicate(!n->as_Reduction()->requires_strict_order() && Matcher::vector_length(n->in(2)) == 2); // src2 + match(Set dst (AddReductionVF src1 src2)); + match(Set dst (MulReductionVF src1 src2)); + effect(TEMP dst); + format %{ "vector_reduction_float $dst,$src1,$src2 ;" %} + ins_encode %{ + int opcode = this->ideal_Opcode(); + int vlen = Matcher::vector_length(this, $src2); + __ unordered_reduce_fp(opcode, vlen, $dst$$XMMRegister, $src2$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct unordered_reduction4F(regF dst, regF src1, vec src2, vec vtmp) %{ + // Non-strictly ordered floating-point add/mul reduction for floats. This rule is + // intended for the VectorAPI (which allows for non-strictly ordered add/mul reduction). + // src1 contains reduction identity + predicate(!n->as_Reduction()->requires_strict_order() && Matcher::vector_length(n->in(2)) == 4); // src2 + match(Set dst (AddReductionVF src1 src2)); + match(Set dst (MulReductionVF src1 src2)); + effect(TEMP dst, TEMP vtmp); + format %{ "vector_reduction_float $dst,$src1,$src2 ; using $vtmp as TEMP" %} + ins_encode %{ + int opcode = this->ideal_Opcode(); + int vlen = Matcher::vector_length(this, $src2); + __ unordered_reduce_fp(opcode, vlen, $dst$$XMMRegister, $src2$$XMMRegister, $vtmp$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct unordered_reduction8F(regF dst, regF src1, vec src2, vec vtmp1, vec vtmp2) %{ + // Non-strictly ordered floating-point add/mul reduction for floats. This rule is + // intended for the VectorAPI (which allows for non-strictly ordered add/mul reduction). + // src1 contains reduction identity + predicate(!n->as_Reduction()->requires_strict_order() && Matcher::vector_length(n->in(2)) == 8); // src2 + match(Set dst (AddReductionVF src1 src2)); + match(Set dst (MulReductionVF src1 src2)); + effect(TEMP dst, TEMP vtmp1, TEMP vtmp2); + format %{ "vector_reduction_float $dst,$src1,$src2 ; using $vtmp1, $vtmp2 as TEMP" %} + ins_encode %{ + int opcode = this->ideal_Opcode(); + int vlen = Matcher::vector_length(this, $src2); + __ unordered_reduce_fp(opcode, vlen, $dst$$XMMRegister, $src2$$XMMRegister, $vtmp1$$XMMRegister, $vtmp2$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct unordered_reduction16F(regF dst, regF src1, legVec src2, legVec vtmp1, legVec vtmp2) %{ + // Non-strictly ordered floating-point add/mul reduction for floats. This rule is + // intended for the VectorAPI (which allows for non-strictly ordered add/mul reduction). + // src1 contains reduction identity + predicate(!n->as_Reduction()->requires_strict_order() && Matcher::vector_length(n->in(2)) == 16); // src2 + match(Set dst (AddReductionVF src1 src2)); + match(Set dst (MulReductionVF src1 src2)); + effect(TEMP dst, TEMP vtmp1, TEMP vtmp2); + format %{ "vector_reduction_float $dst,$src1,$src2 ; using $vtmp1, $vtmp2 as TEMP" %} + ins_encode %{ + int opcode = this->ideal_Opcode(); + int vlen = Matcher::vector_length(this, $src2); + __ unordered_reduce_fp(opcode, vlen, $dst$$XMMRegister, $src2$$XMMRegister, $vtmp1$$XMMRegister, $vtmp2$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + // =======================Double Reduction========================================== instruct reduction2D(regD dst, vec src, vec vtmp) %{ - predicate(Matcher::vector_length(n->in(2)) == 2); // src + predicate(n->as_Reduction()->requires_strict_order() && Matcher::vector_length(n->in(2)) == 2); // src match(Set dst (AddReductionVD dst src)); match(Set dst (MulReductionVD dst src)); effect(TEMP dst, TEMP vtmp); @@ -5167,7 +5236,7 @@ instruct reduction2D(regD dst, vec src, vec vtmp) %{ %} instruct reduction4D(regD dst, vec src, vec vtmp1, vec vtmp2) %{ - predicate(Matcher::vector_length(n->in(2)) == 4); // src + predicate(n->as_Reduction()->requires_strict_order() && Matcher::vector_length(n->in(2)) == 4); // src match(Set dst (AddReductionVD dst src)); match(Set dst (MulReductionVD dst src)); effect(TEMP dst, TEMP vtmp1, TEMP vtmp2); @@ -5181,7 +5250,7 @@ instruct reduction4D(regD dst, vec src, vec vtmp1, vec vtmp2) %{ %} instruct reduction8D(regD dst, legVec src, legVec vtmp1, legVec vtmp2) %{ - predicate(Matcher::vector_length(n->in(2)) == 8); // src + predicate(n->as_Reduction()->requires_strict_order() && Matcher::vector_length(n->in(2)) == 8); // src match(Set dst (AddReductionVD dst src)); match(Set dst (MulReductionVD dst src)); effect(TEMP dst, TEMP vtmp1, TEMP vtmp2); @@ -5194,6 +5263,57 @@ instruct reduction8D(regD dst, legVec src, legVec vtmp1, legVec vtmp2) %{ ins_pipe( pipe_slow ); %} +instruct unordered_reduction2D(regD dst, regD src1, vec src2) %{ + // Non-strictly ordered floating-point add/mul reduction for doubles. This rule is + // intended for the VectorAPI (which allows for non-strictly ordered add/mul reduction). + // src1 contains reduction identity + predicate(!n->as_Reduction()->requires_strict_order() && Matcher::vector_length(n->in(2)) == 2); // src2 + match(Set dst (AddReductionVD src1 src2)); + match(Set dst (MulReductionVD src1 src2)); + effect(TEMP dst); + format %{ "vector_reduction_double $dst,$src1,$src2 ;" %} + ins_encode %{ + int opcode = this->ideal_Opcode(); + int vlen = Matcher::vector_length(this, $src2); + __ unordered_reduce_fp(opcode, vlen, $dst$$XMMRegister, $src2$$XMMRegister); +%} + ins_pipe( pipe_slow ); +%} + +instruct unordered_reduction4D(regD dst, regD src1, vec src2, vec vtmp) %{ + // Non-strictly ordered floating-point add/mul reduction for doubles. This rule is + // intended for the VectorAPI (which allows for non-strictly ordered add/mul reduction). + // src1 contains reduction identity + predicate(!n->as_Reduction()->requires_strict_order() && Matcher::vector_length(n->in(2)) == 4); // src2 + match(Set dst (AddReductionVD src1 src2)); + match(Set dst (MulReductionVD src1 src2)); + effect(TEMP dst, TEMP vtmp); + format %{ "vector_reduction_double $dst,$src1,$src2 ; using $vtmp as TEMP" %} + ins_encode %{ + int opcode = this->ideal_Opcode(); + int vlen = Matcher::vector_length(this, $src2); + __ unordered_reduce_fp(opcode, vlen, $dst$$XMMRegister, $src2$$XMMRegister, $vtmp$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct unordered_reduction8D(regD dst, regD src1, legVec src2, legVec vtmp1, legVec vtmp2) %{ + // Non-strictly ordered floating-point add/mul reduction for doubles. This rule is + // intended for the VectorAPI (which allows for non-strictly ordered add/mul reduction). + // src1 contains reduction identity + predicate(!n->as_Reduction()->requires_strict_order() && Matcher::vector_length(n->in(2)) == 8); // src2 + match(Set dst (AddReductionVD src1 src2)); + match(Set dst (MulReductionVD src1 src2)); + effect(TEMP dst, TEMP vtmp1, TEMP vtmp2); + format %{ "vector_reduction_double $dst,$src1,$src2 ; using $vtmp1, $vtmp2 as TEMP" %} + ins_encode %{ + int opcode = this->ideal_Opcode(); + int vlen = Matcher::vector_length(this, $src2); + __ unordered_reduce_fp(opcode, vlen, $dst$$XMMRegister, $src2$$XMMRegister, $vtmp1$$XMMRegister, $vtmp2$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + // =======================Byte Reduction========================================== #ifdef _LP64 diff --git a/test/jdk/jdk/incubator/vector/Double128VectorTests.java b/test/jdk/jdk/incubator/vector/Double128VectorTests.java index 577b1f2691201..81c915ba7cf85 100644 --- a/test/jdk/jdk/incubator/vector/Double128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Double128VectorTests.java @@ -63,8 +63,11 @@ public class Double128VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); - // for floating point reduction ops that may introduce rounding errors - private static final double RELATIVE_ROUNDING_ERROR = (double)0.000001; + // for floating point addition reduction ops that may introduce rounding errors + private static final double RELATIVE_ROUNDING_ERROR_FACTOR_ADD = (double)10.0; + + // for floating point multiplication reduction ops that may introduce rounding errors + private static final double RELATIVE_ROUNDING_ERROR_FACTOR_MUL = (double)50.0; static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 128); @@ -129,16 +132,16 @@ static void assertReductionArraysEquals(double[] r, double rc, double[] a, static void assertReductionArraysEquals(double[] r, double rc, double[] a, FReductionOp f, FReductionAllOp fa, - double relativeError) { + double relativeErrorFactor) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError)); + Assert.assertEquals(rc, fa.apply(a), Math.ulp(rc) * relativeErrorFactor); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError)); + Assert.assertEquals(r[i], f.apply(a, i), Math.ulp(r[i]) * relativeErrorFactor); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a), Math.ulp(rc) * relativeErrorFactor, "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i), Math.ulp(r[i]) * relativeErrorFactor, "at index #" + i); } } @@ -2194,7 +2197,7 @@ static void ADDReduceDouble128VectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - Double128VectorTests::ADDReduce, Double128VectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR); + Double128VectorTests::ADDReduce, Double128VectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR_FACTOR_ADD); } static double ADDReduceMasked(double[] a, int idx, boolean[] mask) { @@ -2240,7 +2243,7 @@ static void ADDReduceDouble128VectorTestsMasked(IntFunction fa, IntFun } assertReductionArraysEqualsMasked(r, ra, a, mask, - Double128VectorTests::ADDReduceMasked, Double128VectorTests::ADDReduceAllMasked, RELATIVE_ROUNDING_ERROR); + Double128VectorTests::ADDReduceMasked, Double128VectorTests::ADDReduceAllMasked, RELATIVE_ROUNDING_ERROR_FACTOR_ADD); } static double MULReduce(double[] a, int idx) { @@ -2283,7 +2286,7 @@ static void MULReduceDouble128VectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - Double128VectorTests::MULReduce, Double128VectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR); + Double128VectorTests::MULReduce, Double128VectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR_FACTOR_MUL); } static double MULReduceMasked(double[] a, int idx, boolean[] mask) { @@ -2329,7 +2332,7 @@ static void MULReduceDouble128VectorTestsMasked(IntFunction fa, IntFun } assertReductionArraysEqualsMasked(r, ra, a, mask, - Double128VectorTests::MULReduceMasked, Double128VectorTests::MULReduceAllMasked, RELATIVE_ROUNDING_ERROR); + Double128VectorTests::MULReduceMasked, Double128VectorTests::MULReduceAllMasked, RELATIVE_ROUNDING_ERROR_FACTOR_MUL); } static double MINReduce(double[] a, int idx) { diff --git a/test/jdk/jdk/incubator/vector/Double256VectorTests.java b/test/jdk/jdk/incubator/vector/Double256VectorTests.java index b8ecc5e6e691c..5824941d80618 100644 --- a/test/jdk/jdk/incubator/vector/Double256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Double256VectorTests.java @@ -63,8 +63,11 @@ public class Double256VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); - // for floating point reduction ops that may introduce rounding errors - private static final double RELATIVE_ROUNDING_ERROR = (double)0.000001; + // for floating point addition reduction ops that may introduce rounding errors + private static final double RELATIVE_ROUNDING_ERROR_FACTOR_ADD = (double)10.0; + + // for floating point multiplication reduction ops that may introduce rounding errors + private static final double RELATIVE_ROUNDING_ERROR_FACTOR_MUL = (double)50.0; static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 256); @@ -129,16 +132,16 @@ static void assertReductionArraysEquals(double[] r, double rc, double[] a, static void assertReductionArraysEquals(double[] r, double rc, double[] a, FReductionOp f, FReductionAllOp fa, - double relativeError) { + double relativeErrorFactor) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError)); + Assert.assertEquals(rc, fa.apply(a), Math.ulp(rc) * relativeErrorFactor); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError)); + Assert.assertEquals(r[i], f.apply(a, i), Math.ulp(r[i]) * relativeErrorFactor); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a), Math.ulp(rc) * relativeErrorFactor, "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i), Math.ulp(r[i]) * relativeErrorFactor, "at index #" + i); } } @@ -2194,7 +2197,7 @@ static void ADDReduceDouble256VectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - Double256VectorTests::ADDReduce, Double256VectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR); + Double256VectorTests::ADDReduce, Double256VectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR_FACTOR_ADD); } static double ADDReduceMasked(double[] a, int idx, boolean[] mask) { @@ -2240,7 +2243,7 @@ static void ADDReduceDouble256VectorTestsMasked(IntFunction fa, IntFun } assertReductionArraysEqualsMasked(r, ra, a, mask, - Double256VectorTests::ADDReduceMasked, Double256VectorTests::ADDReduceAllMasked, RELATIVE_ROUNDING_ERROR); + Double256VectorTests::ADDReduceMasked, Double256VectorTests::ADDReduceAllMasked, RELATIVE_ROUNDING_ERROR_FACTOR_ADD); } static double MULReduce(double[] a, int idx) { @@ -2283,7 +2286,7 @@ static void MULReduceDouble256VectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - Double256VectorTests::MULReduce, Double256VectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR); + Double256VectorTests::MULReduce, Double256VectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR_FACTOR_MUL); } static double MULReduceMasked(double[] a, int idx, boolean[] mask) { @@ -2329,7 +2332,7 @@ static void MULReduceDouble256VectorTestsMasked(IntFunction fa, IntFun } assertReductionArraysEqualsMasked(r, ra, a, mask, - Double256VectorTests::MULReduceMasked, Double256VectorTests::MULReduceAllMasked, RELATIVE_ROUNDING_ERROR); + Double256VectorTests::MULReduceMasked, Double256VectorTests::MULReduceAllMasked, RELATIVE_ROUNDING_ERROR_FACTOR_MUL); } static double MINReduce(double[] a, int idx) { diff --git a/test/jdk/jdk/incubator/vector/Double512VectorTests.java b/test/jdk/jdk/incubator/vector/Double512VectorTests.java index 57e68cb207602..895cf243eb7e3 100644 --- a/test/jdk/jdk/incubator/vector/Double512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Double512VectorTests.java @@ -63,8 +63,11 @@ public class Double512VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); - // for floating point reduction ops that may introduce rounding errors - private static final double RELATIVE_ROUNDING_ERROR = (double)0.000001; + // for floating point addition reduction ops that may introduce rounding errors + private static final double RELATIVE_ROUNDING_ERROR_FACTOR_ADD = (double)10.0; + + // for floating point multiplication reduction ops that may introduce rounding errors + private static final double RELATIVE_ROUNDING_ERROR_FACTOR_MUL = (double)50.0; static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 512); @@ -129,16 +132,16 @@ static void assertReductionArraysEquals(double[] r, double rc, double[] a, static void assertReductionArraysEquals(double[] r, double rc, double[] a, FReductionOp f, FReductionAllOp fa, - double relativeError) { + double relativeErrorFactor) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError)); + Assert.assertEquals(rc, fa.apply(a), Math.ulp(rc) * relativeErrorFactor); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError)); + Assert.assertEquals(r[i], f.apply(a, i), Math.ulp(r[i]) * relativeErrorFactor); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a), Math.ulp(rc) * relativeErrorFactor, "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i), Math.ulp(r[i]) * relativeErrorFactor, "at index #" + i); } } @@ -2194,7 +2197,7 @@ static void ADDReduceDouble512VectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - Double512VectorTests::ADDReduce, Double512VectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR); + Double512VectorTests::ADDReduce, Double512VectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR_FACTOR_ADD); } static double ADDReduceMasked(double[] a, int idx, boolean[] mask) { @@ -2240,7 +2243,7 @@ static void ADDReduceDouble512VectorTestsMasked(IntFunction fa, IntFun } assertReductionArraysEqualsMasked(r, ra, a, mask, - Double512VectorTests::ADDReduceMasked, Double512VectorTests::ADDReduceAllMasked, RELATIVE_ROUNDING_ERROR); + Double512VectorTests::ADDReduceMasked, Double512VectorTests::ADDReduceAllMasked, RELATIVE_ROUNDING_ERROR_FACTOR_ADD); } static double MULReduce(double[] a, int idx) { @@ -2283,7 +2286,7 @@ static void MULReduceDouble512VectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - Double512VectorTests::MULReduce, Double512VectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR); + Double512VectorTests::MULReduce, Double512VectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR_FACTOR_MUL); } static double MULReduceMasked(double[] a, int idx, boolean[] mask) { @@ -2329,7 +2332,7 @@ static void MULReduceDouble512VectorTestsMasked(IntFunction fa, IntFun } assertReductionArraysEqualsMasked(r, ra, a, mask, - Double512VectorTests::MULReduceMasked, Double512VectorTests::MULReduceAllMasked, RELATIVE_ROUNDING_ERROR); + Double512VectorTests::MULReduceMasked, Double512VectorTests::MULReduceAllMasked, RELATIVE_ROUNDING_ERROR_FACTOR_MUL); } static double MINReduce(double[] a, int idx) { diff --git a/test/jdk/jdk/incubator/vector/Double64VectorTests.java b/test/jdk/jdk/incubator/vector/Double64VectorTests.java index 04ba2729398cd..4414e36b0deb6 100644 --- a/test/jdk/jdk/incubator/vector/Double64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Double64VectorTests.java @@ -63,8 +63,11 @@ public class Double64VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); - // for floating point reduction ops that may introduce rounding errors - private static final double RELATIVE_ROUNDING_ERROR = (double)0.000001; + // for floating point addition reduction ops that may introduce rounding errors + private static final double RELATIVE_ROUNDING_ERROR_FACTOR_ADD = (double)10.0; + + // for floating point multiplication reduction ops that may introduce rounding errors + private static final double RELATIVE_ROUNDING_ERROR_FACTOR_MUL = (double)50.0; static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 64); @@ -129,16 +132,16 @@ static void assertReductionArraysEquals(double[] r, double rc, double[] a, static void assertReductionArraysEquals(double[] r, double rc, double[] a, FReductionOp f, FReductionAllOp fa, - double relativeError) { + double relativeErrorFactor) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError)); + Assert.assertEquals(rc, fa.apply(a), Math.ulp(rc) * relativeErrorFactor); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError)); + Assert.assertEquals(r[i], f.apply(a, i), Math.ulp(r[i]) * relativeErrorFactor); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a), Math.ulp(rc) * relativeErrorFactor, "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i), Math.ulp(r[i]) * relativeErrorFactor, "at index #" + i); } } @@ -2194,7 +2197,7 @@ static void ADDReduceDouble64VectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - Double64VectorTests::ADDReduce, Double64VectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR); + Double64VectorTests::ADDReduce, Double64VectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR_FACTOR_ADD); } static double ADDReduceMasked(double[] a, int idx, boolean[] mask) { @@ -2240,7 +2243,7 @@ static void ADDReduceDouble64VectorTestsMasked(IntFunction fa, IntFunc } assertReductionArraysEqualsMasked(r, ra, a, mask, - Double64VectorTests::ADDReduceMasked, Double64VectorTests::ADDReduceAllMasked, RELATIVE_ROUNDING_ERROR); + Double64VectorTests::ADDReduceMasked, Double64VectorTests::ADDReduceAllMasked, RELATIVE_ROUNDING_ERROR_FACTOR_ADD); } static double MULReduce(double[] a, int idx) { @@ -2283,7 +2286,7 @@ static void MULReduceDouble64VectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - Double64VectorTests::MULReduce, Double64VectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR); + Double64VectorTests::MULReduce, Double64VectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR_FACTOR_MUL); } static double MULReduceMasked(double[] a, int idx, boolean[] mask) { @@ -2329,7 +2332,7 @@ static void MULReduceDouble64VectorTestsMasked(IntFunction fa, IntFunc } assertReductionArraysEqualsMasked(r, ra, a, mask, - Double64VectorTests::MULReduceMasked, Double64VectorTests::MULReduceAllMasked, RELATIVE_ROUNDING_ERROR); + Double64VectorTests::MULReduceMasked, Double64VectorTests::MULReduceAllMasked, RELATIVE_ROUNDING_ERROR_FACTOR_MUL); } static double MINReduce(double[] a, int idx) { diff --git a/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.java b/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.java index 474ef0043c9eb..271d1f12aba56 100644 --- a/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.java @@ -68,8 +68,11 @@ static VectorShape getMaxBit() { private static final int Max = 256; // juts so we can do N/Max - // for floating point reduction ops that may introduce rounding errors - private static final double RELATIVE_ROUNDING_ERROR = (double)0.000001; + // for floating point addition reduction ops that may introduce rounding errors + private static final double RELATIVE_ROUNDING_ERROR_FACTOR_ADD = (double)10.0; + + // for floating point multiplication reduction ops that may introduce rounding errors + private static final double RELATIVE_ROUNDING_ERROR_FACTOR_MUL = (double)50.0; static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / Max); @@ -134,16 +137,16 @@ static void assertReductionArraysEquals(double[] r, double rc, double[] a, static void assertReductionArraysEquals(double[] r, double rc, double[] a, FReductionOp f, FReductionAllOp fa, - double relativeError) { + double relativeErrorFactor) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError)); + Assert.assertEquals(rc, fa.apply(a), Math.ulp(rc) * relativeErrorFactor); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError)); + Assert.assertEquals(r[i], f.apply(a, i), Math.ulp(r[i]) * relativeErrorFactor); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a), Math.ulp(rc) * relativeErrorFactor, "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i), Math.ulp(r[i]) * relativeErrorFactor, "at index #" + i); } } @@ -2199,7 +2202,7 @@ static void ADDReduceDoubleMaxVectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - DoubleMaxVectorTests::ADDReduce, DoubleMaxVectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR); + DoubleMaxVectorTests::ADDReduce, DoubleMaxVectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR_FACTOR_ADD); } static double ADDReduceMasked(double[] a, int idx, boolean[] mask) { @@ -2245,7 +2248,7 @@ static void ADDReduceDoubleMaxVectorTestsMasked(IntFunction fa, IntFun } assertReductionArraysEqualsMasked(r, ra, a, mask, - DoubleMaxVectorTests::ADDReduceMasked, DoubleMaxVectorTests::ADDReduceAllMasked, RELATIVE_ROUNDING_ERROR); + DoubleMaxVectorTests::ADDReduceMasked, DoubleMaxVectorTests::ADDReduceAllMasked, RELATIVE_ROUNDING_ERROR_FACTOR_ADD); } static double MULReduce(double[] a, int idx) { @@ -2288,7 +2291,7 @@ static void MULReduceDoubleMaxVectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - DoubleMaxVectorTests::MULReduce, DoubleMaxVectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR); + DoubleMaxVectorTests::MULReduce, DoubleMaxVectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR_FACTOR_MUL); } static double MULReduceMasked(double[] a, int idx, boolean[] mask) { @@ -2334,7 +2337,7 @@ static void MULReduceDoubleMaxVectorTestsMasked(IntFunction fa, IntFun } assertReductionArraysEqualsMasked(r, ra, a, mask, - DoubleMaxVectorTests::MULReduceMasked, DoubleMaxVectorTests::MULReduceAllMasked, RELATIVE_ROUNDING_ERROR); + DoubleMaxVectorTests::MULReduceMasked, DoubleMaxVectorTests::MULReduceAllMasked, RELATIVE_ROUNDING_ERROR_FACTOR_MUL); } static double MINReduce(double[] a, int idx) { diff --git a/test/jdk/jdk/incubator/vector/Float128VectorTests.java b/test/jdk/jdk/incubator/vector/Float128VectorTests.java index 5d503860ee94b..a634aeffe5431 100644 --- a/test/jdk/jdk/incubator/vector/Float128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Float128VectorTests.java @@ -63,8 +63,11 @@ public class Float128VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); - // for floating point reduction ops that may introduce rounding errors - private static final float RELATIVE_ROUNDING_ERROR = (float)0.000001; + // for floating point addition reduction ops that may introduce rounding errors + private static final float RELATIVE_ROUNDING_ERROR_FACTOR_ADD = (float)10.0; + + // for floating point multiplication reduction ops that may introduce rounding errors + private static final float RELATIVE_ROUNDING_ERROR_FACTOR_MUL = (float)50.0; static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 128); @@ -129,16 +132,16 @@ static void assertReductionArraysEquals(float[] r, float rc, float[] a, static void assertReductionArraysEquals(float[] r, float rc, float[] a, FReductionOp f, FReductionAllOp fa, - float relativeError) { + float relativeErrorFactor) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError)); + Assert.assertEquals(rc, fa.apply(a), Math.ulp(rc) * relativeErrorFactor); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError)); + Assert.assertEquals(r[i], f.apply(a, i), Math.ulp(r[i]) * relativeErrorFactor); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a), Math.ulp(rc) * relativeErrorFactor, "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i), Math.ulp(r[i]) * relativeErrorFactor, "at index #" + i); } } @@ -2205,7 +2208,7 @@ static void ADDReduceFloat128VectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - Float128VectorTests::ADDReduce, Float128VectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR); + Float128VectorTests::ADDReduce, Float128VectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR_FACTOR_ADD); } static float ADDReduceMasked(float[] a, int idx, boolean[] mask) { @@ -2251,7 +2254,7 @@ static void ADDReduceFloat128VectorTestsMasked(IntFunction fa, IntFunct } assertReductionArraysEqualsMasked(r, ra, a, mask, - Float128VectorTests::ADDReduceMasked, Float128VectorTests::ADDReduceAllMasked, RELATIVE_ROUNDING_ERROR); + Float128VectorTests::ADDReduceMasked, Float128VectorTests::ADDReduceAllMasked, RELATIVE_ROUNDING_ERROR_FACTOR_ADD); } static float MULReduce(float[] a, int idx) { @@ -2294,7 +2297,7 @@ static void MULReduceFloat128VectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - Float128VectorTests::MULReduce, Float128VectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR); + Float128VectorTests::MULReduce, Float128VectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR_FACTOR_MUL); } static float MULReduceMasked(float[] a, int idx, boolean[] mask) { @@ -2340,7 +2343,7 @@ static void MULReduceFloat128VectorTestsMasked(IntFunction fa, IntFunct } assertReductionArraysEqualsMasked(r, ra, a, mask, - Float128VectorTests::MULReduceMasked, Float128VectorTests::MULReduceAllMasked, RELATIVE_ROUNDING_ERROR); + Float128VectorTests::MULReduceMasked, Float128VectorTests::MULReduceAllMasked, RELATIVE_ROUNDING_ERROR_FACTOR_MUL); } static float MINReduce(float[] a, int idx) { diff --git a/test/jdk/jdk/incubator/vector/Float256VectorTests.java b/test/jdk/jdk/incubator/vector/Float256VectorTests.java index 7c38b370b12a4..d9509ff3152b7 100644 --- a/test/jdk/jdk/incubator/vector/Float256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Float256VectorTests.java @@ -63,8 +63,11 @@ public class Float256VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); - // for floating point reduction ops that may introduce rounding errors - private static final float RELATIVE_ROUNDING_ERROR = (float)0.000001; + // for floating point addition reduction ops that may introduce rounding errors + private static final float RELATIVE_ROUNDING_ERROR_FACTOR_ADD = (float)10.0; + + // for floating point multiplication reduction ops that may introduce rounding errors + private static final float RELATIVE_ROUNDING_ERROR_FACTOR_MUL = (float)50.0; static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 256); @@ -129,16 +132,16 @@ static void assertReductionArraysEquals(float[] r, float rc, float[] a, static void assertReductionArraysEquals(float[] r, float rc, float[] a, FReductionOp f, FReductionAllOp fa, - float relativeError) { + float relativeErrorFactor) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError)); + Assert.assertEquals(rc, fa.apply(a), Math.ulp(rc) * relativeErrorFactor); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError)); + Assert.assertEquals(r[i], f.apply(a, i), Math.ulp(r[i]) * relativeErrorFactor); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a), Math.ulp(rc) * relativeErrorFactor, "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i), Math.ulp(r[i]) * relativeErrorFactor, "at index #" + i); } } @@ -2205,7 +2208,7 @@ static void ADDReduceFloat256VectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - Float256VectorTests::ADDReduce, Float256VectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR); + Float256VectorTests::ADDReduce, Float256VectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR_FACTOR_ADD); } static float ADDReduceMasked(float[] a, int idx, boolean[] mask) { @@ -2251,7 +2254,7 @@ static void ADDReduceFloat256VectorTestsMasked(IntFunction fa, IntFunct } assertReductionArraysEqualsMasked(r, ra, a, mask, - Float256VectorTests::ADDReduceMasked, Float256VectorTests::ADDReduceAllMasked, RELATIVE_ROUNDING_ERROR); + Float256VectorTests::ADDReduceMasked, Float256VectorTests::ADDReduceAllMasked, RELATIVE_ROUNDING_ERROR_FACTOR_ADD); } static float MULReduce(float[] a, int idx) { @@ -2294,7 +2297,7 @@ static void MULReduceFloat256VectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - Float256VectorTests::MULReduce, Float256VectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR); + Float256VectorTests::MULReduce, Float256VectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR_FACTOR_MUL); } static float MULReduceMasked(float[] a, int idx, boolean[] mask) { @@ -2340,7 +2343,7 @@ static void MULReduceFloat256VectorTestsMasked(IntFunction fa, IntFunct } assertReductionArraysEqualsMasked(r, ra, a, mask, - Float256VectorTests::MULReduceMasked, Float256VectorTests::MULReduceAllMasked, RELATIVE_ROUNDING_ERROR); + Float256VectorTests::MULReduceMasked, Float256VectorTests::MULReduceAllMasked, RELATIVE_ROUNDING_ERROR_FACTOR_MUL); } static float MINReduce(float[] a, int idx) { diff --git a/test/jdk/jdk/incubator/vector/Float512VectorTests.java b/test/jdk/jdk/incubator/vector/Float512VectorTests.java index 70e4e1ea24f6f..83326abe54e0f 100644 --- a/test/jdk/jdk/incubator/vector/Float512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Float512VectorTests.java @@ -63,8 +63,11 @@ public class Float512VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); - // for floating point reduction ops that may introduce rounding errors - private static final float RELATIVE_ROUNDING_ERROR = (float)0.000001; + // for floating point addition reduction ops that may introduce rounding errors + private static final float RELATIVE_ROUNDING_ERROR_FACTOR_ADD = (float)10.0; + + // for floating point multiplication reduction ops that may introduce rounding errors + private static final float RELATIVE_ROUNDING_ERROR_FACTOR_MUL = (float)50.0; static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 512); @@ -129,16 +132,16 @@ static void assertReductionArraysEquals(float[] r, float rc, float[] a, static void assertReductionArraysEquals(float[] r, float rc, float[] a, FReductionOp f, FReductionAllOp fa, - float relativeError) { + float relativeErrorFactor) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError)); + Assert.assertEquals(rc, fa.apply(a), Math.ulp(rc) * relativeErrorFactor); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError)); + Assert.assertEquals(r[i], f.apply(a, i), Math.ulp(r[i]) * relativeErrorFactor); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a), Math.ulp(rc) * relativeErrorFactor, "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i), Math.ulp(r[i]) * relativeErrorFactor, "at index #" + i); } } @@ -2205,7 +2208,7 @@ static void ADDReduceFloat512VectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - Float512VectorTests::ADDReduce, Float512VectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR); + Float512VectorTests::ADDReduce, Float512VectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR_FACTOR_ADD); } static float ADDReduceMasked(float[] a, int idx, boolean[] mask) { @@ -2251,7 +2254,7 @@ static void ADDReduceFloat512VectorTestsMasked(IntFunction fa, IntFunct } assertReductionArraysEqualsMasked(r, ra, a, mask, - Float512VectorTests::ADDReduceMasked, Float512VectorTests::ADDReduceAllMasked, RELATIVE_ROUNDING_ERROR); + Float512VectorTests::ADDReduceMasked, Float512VectorTests::ADDReduceAllMasked, RELATIVE_ROUNDING_ERROR_FACTOR_ADD); } static float MULReduce(float[] a, int idx) { @@ -2294,7 +2297,7 @@ static void MULReduceFloat512VectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - Float512VectorTests::MULReduce, Float512VectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR); + Float512VectorTests::MULReduce, Float512VectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR_FACTOR_MUL); } static float MULReduceMasked(float[] a, int idx, boolean[] mask) { @@ -2340,7 +2343,7 @@ static void MULReduceFloat512VectorTestsMasked(IntFunction fa, IntFunct } assertReductionArraysEqualsMasked(r, ra, a, mask, - Float512VectorTests::MULReduceMasked, Float512VectorTests::MULReduceAllMasked, RELATIVE_ROUNDING_ERROR); + Float512VectorTests::MULReduceMasked, Float512VectorTests::MULReduceAllMasked, RELATIVE_ROUNDING_ERROR_FACTOR_MUL); } static float MINReduce(float[] a, int idx) { diff --git a/test/jdk/jdk/incubator/vector/Float64VectorTests.java b/test/jdk/jdk/incubator/vector/Float64VectorTests.java index 65a71504561ed..efae7f1fc3c97 100644 --- a/test/jdk/jdk/incubator/vector/Float64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Float64VectorTests.java @@ -63,8 +63,11 @@ public class Float64VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); - // for floating point reduction ops that may introduce rounding errors - private static final float RELATIVE_ROUNDING_ERROR = (float)0.000001; + // for floating point addition reduction ops that may introduce rounding errors + private static final float RELATIVE_ROUNDING_ERROR_FACTOR_ADD = (float)10.0; + + // for floating point multiplication reduction ops that may introduce rounding errors + private static final float RELATIVE_ROUNDING_ERROR_FACTOR_MUL = (float)50.0; static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 64); @@ -129,16 +132,16 @@ static void assertReductionArraysEquals(float[] r, float rc, float[] a, static void assertReductionArraysEquals(float[] r, float rc, float[] a, FReductionOp f, FReductionAllOp fa, - float relativeError) { + float relativeErrorFactor) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError)); + Assert.assertEquals(rc, fa.apply(a), Math.ulp(rc) * relativeErrorFactor); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError)); + Assert.assertEquals(r[i], f.apply(a, i), Math.ulp(r[i]) * relativeErrorFactor); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a), Math.ulp(rc) * relativeErrorFactor, "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i), Math.ulp(r[i]) * relativeErrorFactor, "at index #" + i); } } @@ -2205,7 +2208,7 @@ static void ADDReduceFloat64VectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - Float64VectorTests::ADDReduce, Float64VectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR); + Float64VectorTests::ADDReduce, Float64VectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR_FACTOR_ADD); } static float ADDReduceMasked(float[] a, int idx, boolean[] mask) { @@ -2251,7 +2254,7 @@ static void ADDReduceFloat64VectorTestsMasked(IntFunction fa, IntFuncti } assertReductionArraysEqualsMasked(r, ra, a, mask, - Float64VectorTests::ADDReduceMasked, Float64VectorTests::ADDReduceAllMasked, RELATIVE_ROUNDING_ERROR); + Float64VectorTests::ADDReduceMasked, Float64VectorTests::ADDReduceAllMasked, RELATIVE_ROUNDING_ERROR_FACTOR_ADD); } static float MULReduce(float[] a, int idx) { @@ -2294,7 +2297,7 @@ static void MULReduceFloat64VectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - Float64VectorTests::MULReduce, Float64VectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR); + Float64VectorTests::MULReduce, Float64VectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR_FACTOR_MUL); } static float MULReduceMasked(float[] a, int idx, boolean[] mask) { @@ -2340,7 +2343,7 @@ static void MULReduceFloat64VectorTestsMasked(IntFunction fa, IntFuncti } assertReductionArraysEqualsMasked(r, ra, a, mask, - Float64VectorTests::MULReduceMasked, Float64VectorTests::MULReduceAllMasked, RELATIVE_ROUNDING_ERROR); + Float64VectorTests::MULReduceMasked, Float64VectorTests::MULReduceAllMasked, RELATIVE_ROUNDING_ERROR_FACTOR_MUL); } static float MINReduce(float[] a, int idx) { diff --git a/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java b/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java index f6b05fb6bc7ec..fdd3e042f77f2 100644 --- a/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java @@ -68,8 +68,11 @@ static VectorShape getMaxBit() { private static final int Max = 256; // juts so we can do N/Max - // for floating point reduction ops that may introduce rounding errors - private static final float RELATIVE_ROUNDING_ERROR = (float)0.000001; + // for floating point addition reduction ops that may introduce rounding errors + private static final float RELATIVE_ROUNDING_ERROR_FACTOR_ADD = (float)10.0; + + // for floating point multiplication reduction ops that may introduce rounding errors + private static final float RELATIVE_ROUNDING_ERROR_FACTOR_MUL = (float)50.0; static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / Max); @@ -134,16 +137,16 @@ static void assertReductionArraysEquals(float[] r, float rc, float[] a, static void assertReductionArraysEquals(float[] r, float rc, float[] a, FReductionOp f, FReductionAllOp fa, - float relativeError) { + float relativeErrorFactor) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError)); + Assert.assertEquals(rc, fa.apply(a), Math.ulp(rc) * relativeErrorFactor); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError)); + Assert.assertEquals(r[i], f.apply(a, i), Math.ulp(r[i]) * relativeErrorFactor); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a), Math.ulp(rc) * relativeErrorFactor, "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i), Math.ulp(r[i]) * relativeErrorFactor, "at index #" + i); } } @@ -2210,7 +2213,7 @@ static void ADDReduceFloatMaxVectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - FloatMaxVectorTests::ADDReduce, FloatMaxVectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR); + FloatMaxVectorTests::ADDReduce, FloatMaxVectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR_FACTOR_ADD); } static float ADDReduceMasked(float[] a, int idx, boolean[] mask) { @@ -2256,7 +2259,7 @@ static void ADDReduceFloatMaxVectorTestsMasked(IntFunction fa, IntFunct } assertReductionArraysEqualsMasked(r, ra, a, mask, - FloatMaxVectorTests::ADDReduceMasked, FloatMaxVectorTests::ADDReduceAllMasked, RELATIVE_ROUNDING_ERROR); + FloatMaxVectorTests::ADDReduceMasked, FloatMaxVectorTests::ADDReduceAllMasked, RELATIVE_ROUNDING_ERROR_FACTOR_ADD); } static float MULReduce(float[] a, int idx) { @@ -2299,7 +2302,7 @@ static void MULReduceFloatMaxVectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - FloatMaxVectorTests::MULReduce, FloatMaxVectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR); + FloatMaxVectorTests::MULReduce, FloatMaxVectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR_FACTOR_MUL); } static float MULReduceMasked(float[] a, int idx, boolean[] mask) { @@ -2345,7 +2348,7 @@ static void MULReduceFloatMaxVectorTestsMasked(IntFunction fa, IntFunct } assertReductionArraysEqualsMasked(r, ra, a, mask, - FloatMaxVectorTests::MULReduceMasked, FloatMaxVectorTests::MULReduceAllMasked, RELATIVE_ROUNDING_ERROR); + FloatMaxVectorTests::MULReduceMasked, FloatMaxVectorTests::MULReduceAllMasked, RELATIVE_ROUNDING_ERROR_FACTOR_MUL); } static float MINReduce(float[] a, int idx) { diff --git a/test/jdk/jdk/incubator/vector/gen-template.sh b/test/jdk/jdk/incubator/vector/gen-template.sh index 5a7167c0b31cf..375287bef2d44 100644 --- a/test/jdk/jdk/incubator/vector/gen-template.sh +++ b/test/jdk/jdk/incubator/vector/gen-template.sh @@ -1,6 +1,6 @@ #!/bin/bash # -# Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -221,7 +221,6 @@ function gen_op_tmpl { replace_variables $unit_filename $unit_output "$kernel" "$test" "$op" "$init" "$guard" "$masked" "$op_name" "$kernel_smoke" local gen_perf_tests=$generate_perf_tests - gen_perf_tests=true if [[ $template == *"-Broadcast-"* ]] || [[ $template == "Miscellaneous" ]] || [[ $template == *"Compare-Masked"* ]] || [[ $template == *"Compare-Broadcast"* ]]; then gen_perf_tests=false diff --git a/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Masked-op.template b/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Masked-op.template index 3b306ce387aac..3c68b72215dda 100644 --- a/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Masked-op.template +++ b/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Masked-op.template @@ -4,7 +4,7 @@ [[KERNEL]] assertReductionArraysEqualsMasked(r, ra, a, mask, #if[FP] - $vectorteststype$::[[TEST]]ReduceMasked, $vectorteststype$::[[TEST]]ReduceAllMasked, RELATIVE_ROUNDING_ERROR); + $vectorteststype$::[[TEST]]ReduceMasked, $vectorteststype$::[[TEST]]ReduceAllMasked, RELATIVE_ROUNDING_ERROR_FACTOR_[[TEST]]); #else[FP] $vectorteststype$::[[TEST]]ReduceMasked, $vectorteststype$::[[TEST]]ReduceAllMasked); #end[FP] diff --git a/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-op.template b/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-op.template index 5c68968870840..5638940045dc6 100644 --- a/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-op.template +++ b/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-op.template @@ -4,7 +4,7 @@ [[KERNEL]] assertReductionArraysEquals(r, ra, a, #if[FP] - $vectorteststype$::[[TEST]]Reduce, $vectorteststype$::[[TEST]]ReduceAll, RELATIVE_ROUNDING_ERROR); + $vectorteststype$::[[TEST]]Reduce, $vectorteststype$::[[TEST]]ReduceAll, RELATIVE_ROUNDING_ERROR_FACTOR_[[TEST]]); #else[FP] $vectorteststype$::[[TEST]]Reduce, $vectorteststype$::[[TEST]]ReduceAll); #end[FP] diff --git a/test/jdk/jdk/incubator/vector/templates/Unit-header.template b/test/jdk/jdk/incubator/vector/templates/Unit-header.template index bc1ee75a5c665..38ab617824437 100644 --- a/test/jdk/jdk/incubator/vector/templates/Unit-header.template +++ b/test/jdk/jdk/incubator/vector/templates/Unit-header.template @@ -96,8 +96,11 @@ public class $vectorteststype$ extends AbstractVectorTest { private static final $type$ CONST_SHIFT = $Boxtype$.SIZE / 2; #end[BITWISE] #if[FP] - // for floating point reduction ops that may introduce rounding errors - private static final $type$ RELATIVE_ROUNDING_ERROR = ($type$)0.000001; + // for floating point addition reduction ops that may introduce rounding errors + private static final $type$ RELATIVE_ROUNDING_ERROR_FACTOR_ADD = ($type$)10.0; + + // for floating point multiplication reduction ops that may introduce rounding errors + private static final $type$ RELATIVE_ROUNDING_ERROR_FACTOR_MUL = ($type$)50.0; #end[FP] static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / $bits$); @@ -177,16 +180,16 @@ public class $vectorteststype$ extends AbstractVectorTest { static void assertReductionArraysEquals($type$[] r, $type$ rc, $type$[] a, FReductionOp f, FReductionAllOp fa, - $type$ relativeError) { + $type$ relativeErrorFactor) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError)); + Assert.assertEquals(rc, fa.apply(a), Math.ulp(rc) * relativeErrorFactor); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError)); + Assert.assertEquals(r[i], f.apply(a, i), Math.ulp(r[i]) * relativeErrorFactor); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a), Math.ulp(rc) * relativeErrorFactor, "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i), Math.ulp(r[i]) * relativeErrorFactor, "at index #" + i); } } #end[FP] From a89b525189fbc0559be9edc0de9f4288ca676139 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Fri, 2 Aug 2024 10:51:25 +0000 Subject: [PATCH 174/353] 8337721: G1: Remove unused G1CollectedHeap::young_collection_verify_type Reviewed-by: tschatzl --- src/hotspot/share/gc/g1/g1CollectedHeap.cpp | 10 ---------- src/hotspot/share/gc/g1/g1CollectedHeap.hpp | 1 - 2 files changed, 11 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index 3b8fb145f1692..aa99fbecbee54 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp @@ -2336,16 +2336,6 @@ void G1CollectedHeap::start_new_collection_set() { _cm->verify_no_collection_set_oops(); } -G1HeapVerifier::G1VerifyType G1CollectedHeap::young_collection_verify_type() const { - if (collector_state()->in_concurrent_start_gc()) { - return G1HeapVerifier::G1VerifyConcurrentStart; - } else if (collector_state()->in_young_only_phase()) { - return G1HeapVerifier::G1VerifyYoungNormal; - } else { - return G1HeapVerifier::G1VerifyMixed; - } -} - void G1CollectedHeap::verify_before_young_collection(G1HeapVerifier::G1VerifyType type) { if (!VerifyBeforeGC) { return; diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp index 59ade93967872..ea087aae6621f 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp @@ -752,7 +752,6 @@ class G1CollectedHeap : public CollectedHeap { // of the incremental collection pause, executed by the vm thread. void do_collection_pause_at_safepoint_helper(); - G1HeapVerifier::G1VerifyType young_collection_verify_type() const; void verify_before_young_collection(G1HeapVerifier::G1VerifyType type); void verify_after_young_collection(G1HeapVerifier::G1VerifyType type); From 328a0533b2ee6793130dfb68d931e0ebd60c6b5d Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Fri, 2 Aug 2024 11:47:26 +0000 Subject: [PATCH 175/353] 8335059: Consider renaming ClassLoaderData::keep_alive Reviewed-by: dholmes, stefank --- .../gc/shared/barrierSetAssembler_aarch64.cpp | 4 +-- .../ppc/gc/shared/barrierSetAssembler_ppc.cpp | 4 +-- .../gc/shared/barrierSetAssembler_riscv.cpp | 4 +-- .../x86/gc/shared/barrierSetAssembler_x86.cpp | 4 +-- .../share/classfile/classLoaderData.cpp | 26 +++++++++---------- .../share/classfile/classLoaderData.hpp | 25 ++++++++++-------- .../share/classfile/classLoaderDataGraph.cpp | 10 +++---- src/hotspot/share/classfile/javaClasses.cpp | 2 +- src/hotspot/share/classfile/moduleEntry.cpp | 2 +- src/hotspot/share/prims/jvm.cpp | 2 +- 10 files changed, 42 insertions(+), 41 deletions(-) diff --git a/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.cpp index 073d992235517..0161843036bc5 100644 --- a/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -375,7 +375,7 @@ void BarrierSetAssembler::c2i_entry_barrier(MacroAssembler* masm) { __ load_method_holder_cld(rscratch1, rmethod); // Is it a strong CLD? - __ ldrw(rscratch2, Address(rscratch1, ClassLoaderData::keep_alive_offset())); + __ ldrw(rscratch2, Address(rscratch1, ClassLoaderData::keep_alive_ref_count_offset())); __ cbnz(rscratch2, method_live); // Is it a weak but alive CLD? diff --git a/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.cpp b/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.cpp index 16de0b6a7ddd5..956b082d194b4 100644 --- a/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2018, 2022 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -238,7 +238,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. - __ lwz(tmp2, in_bytes(ClassLoaderData::keep_alive_offset()), tmp1_class_loader_data); + __ lwz(tmp2, in_bytes(ClassLoaderData::keep_alive_ref_count_offset()), tmp1_class_loader_data); __ cmpdi(CCR0, tmp2, 0); __ bne(CCR0, skip_barrier); diff --git a/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp b/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp index 0f3850809775c..efdf3765965f7 100644 --- a/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2020, 2023, Huawei Technologies Co., Ltd. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -326,7 +326,7 @@ void BarrierSetAssembler::c2i_entry_barrier(MacroAssembler* masm) { __ load_method_holder_cld(t0, xmethod); // Is it a strong CLD? - __ lwu(t1, Address(t0, ClassLoaderData::keep_alive_offset())); + __ lwu(t1, Address(t0, ClassLoaderData::keep_alive_ref_count_offset())); __ bnez(t1, method_live); // Is it a weak but alive CLD? diff --git a/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.cpp index 64ad743067476..cd0e43b68bf9e 100644 --- a/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -423,7 +423,7 @@ void BarrierSetAssembler::c2i_entry_barrier(MacroAssembler* masm) { __ load_method_holder_cld(tmp1, rbx); // Is it a strong CLD? - __ cmpl(Address(tmp1, ClassLoaderData::keep_alive_offset()), 0); + __ cmpl(Address(tmp1, ClassLoaderData::keep_alive_ref_count_offset()), 0); __ jcc(Assembler::greater, method_live); // Is it a weak but alive CLD? diff --git a/src/hotspot/share/classfile/classLoaderData.cpp b/src/hotspot/share/classfile/classLoaderData.cpp index de4490e73f326..fab012456d922 100644 --- a/src/hotspot/share/classfile/classLoaderData.cpp +++ b/src/hotspot/share/classfile/classLoaderData.cpp @@ -141,7 +141,7 @@ ClassLoaderData::ClassLoaderData(Handle h_class_loader, bool has_class_mirror_ho // A non-strong hidden class loader data doesn't have anything to keep // it from being unloaded during parsing of the non-strong hidden class. // The null-class-loader should always be kept alive. - _keep_alive((has_class_mirror_holder || h_class_loader.is_null()) ? 1 : 0), + _keep_alive_ref_count((has_class_mirror_holder || h_class_loader.is_null()) ? 1 : 0), _claim(0), _handles(), _klasses(nullptr), _packages(nullptr), _modules(nullptr), _unnamed_module(nullptr), _dictionary(nullptr), @@ -345,26 +345,26 @@ void ClassLoaderData::demote_strong_roots() { // while the class is being parsed, and if the class appears on the module fixup list. // Due to the uniqueness that no other class shares the hidden class' name or // ClassLoaderData, no other non-GC thread has knowledge of the hidden class while -// it is being defined, therefore _keep_alive is not volatile or atomic. -void ClassLoaderData::inc_keep_alive() { +// it is being defined, therefore _keep_alive_ref_count is not volatile or atomic. +void ClassLoaderData::inc_keep_alive_ref_count() { if (has_class_mirror_holder()) { - assert(_keep_alive > 0, "Invalid keep alive increment count"); - _keep_alive++; + assert(_keep_alive_ref_count > 0, "Invalid keep alive increment count"); + _keep_alive_ref_count++; } } -void ClassLoaderData::dec_keep_alive() { +void ClassLoaderData::dec_keep_alive_ref_count() { if (has_class_mirror_holder()) { - assert(_keep_alive > 0, "Invalid keep alive decrement count"); - if (_keep_alive == 1) { - // When the keep_alive counter is 1, the oop handle area is a strong root, + assert(_keep_alive_ref_count > 0, "Invalid keep alive decrement count"); + if (_keep_alive_ref_count == 1) { + // When the keep_alive_ref_count counter is 1, the oop handle area is a strong root, // acting as input to the GC tracing. Such strong roots are part of the // snapshot-at-the-beginning, and can not just be pulled out from the // system when concurrent GCs are running at the same time, without // invoking the right barriers. demote_strong_roots(); } - _keep_alive--; + _keep_alive_ref_count--; } } @@ -680,8 +680,8 @@ oop ClassLoaderData::holder_no_keepalive() const { // Unloading support bool ClassLoaderData::is_alive() const { - bool alive = keep_alive() // null class loader and incomplete non-strong hidden class. - || (_holder.peek() != nullptr); // and not cleaned by the GC weak handle processing. + bool alive = (_keep_alive_ref_count > 0) // null class loader and incomplete non-strong hidden class. + || (_holder.peek() != nullptr); // and not cleaned by the GC weak handle processing. return alive; } @@ -1009,7 +1009,7 @@ void ClassLoaderData::print_on(outputStream* out) const { out->print_cr(" - unloading %s", _unloading ? "true" : "false"); out->print_cr(" - class mirror holder %s", _has_class_mirror_holder ? "true" : "false"); out->print_cr(" - modified oops %s", _modified_oops ? "true" : "false"); - out->print_cr(" - keep alive %d", _keep_alive); + out->print_cr(" - _keep_alive_ref_count %d", _keep_alive_ref_count); out->print (" - claim "); switch(_claim) { case _claim_none: out->print_cr("none"); break; diff --git a/src/hotspot/share/classfile/classLoaderData.hpp b/src/hotspot/share/classfile/classLoaderData.hpp index c9d025aded141..19dbb0b1b3650 100644 --- a/src/hotspot/share/classfile/classLoaderData.hpp +++ b/src/hotspot/share/classfile/classLoaderData.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -125,10 +125,10 @@ class ClassLoaderData : public CHeapObj { // Remembered sets support for the oops in the class loader data. bool _modified_oops; // Card Table Equivalent - int _keep_alive; // if this CLD is kept alive. - // Used for non-strong hidden classes and the - // boot class loader. _keep_alive does not need to be volatile or - // atomic since there is one unique CLD per non-strong hidden class. + int _keep_alive_ref_count; // if this CLD should not be considered eligible for unloading. + // Used for non-strong hidden classes and the + // boot class loader. _keep_alive_ref_count does not need to be volatile or + // atomic since there is one unique CLD per non-strong hidden class. volatile int _claim; // non-zero if claimed, for example during GC traces. // To avoid applying oop closure more than once. @@ -205,12 +205,14 @@ class ClassLoaderData : public CHeapObj { bool has_modified_oops() { return _modified_oops; } oop holder_no_keepalive() const; + // Resolving the holder keeps this CLD alive for the current GC cycle. oop holder() const; + void keep_alive() const { (void)holder(); } void classes_do(void f(Klass* const)); private: - bool keep_alive() const { return _keep_alive > 0; } + int keep_alive_ref_count() const { return _keep_alive_ref_count; } void loaded_classes_do(KlassClosure* klass_closure); void classes_do(void f(InstanceKlass*)); @@ -302,9 +304,10 @@ class ClassLoaderData : public CHeapObj { return _unloading; } - // Used to refcount a non-strong hidden class's s CLD in order to indicate their aliveness. - void inc_keep_alive(); - void dec_keep_alive(); + // Used to refcount a non-strong hidden class's CLD in order to force its aliveness during + // loading, when gc tracing may not find this CLD alive through the holder. + void inc_keep_alive_ref_count(); + void dec_keep_alive_ref_count(); void initialize_holder(Handle holder); @@ -335,8 +338,8 @@ class ClassLoaderData : public CHeapObj { bool modules_defined() { return (_modules != nullptr); } // Offsets - static ByteSize holder_offset() { return byte_offset_of(ClassLoaderData, _holder); } - static ByteSize keep_alive_offset() { return byte_offset_of(ClassLoaderData, _keep_alive); } + static ByteSize holder_offset() { return byte_offset_of(ClassLoaderData, _holder); } + static ByteSize keep_alive_ref_count_offset() { return byte_offset_of(ClassLoaderData, _keep_alive_ref_count); } // Loaded class dictionary Dictionary* dictionary() const { return _dictionary; } diff --git a/src/hotspot/share/classfile/classLoaderDataGraph.cpp b/src/hotspot/share/classfile/classLoaderDataGraph.cpp index adec6dbdeeeaa..c7051cd58e7d6 100644 --- a/src/hotspot/share/classfile/classLoaderDataGraph.cpp +++ b/src/hotspot/share/classfile/classLoaderDataGraph.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -201,7 +201,7 @@ void ClassLoaderDataGraph::cld_do(CLDClosure* cl) { void ClassLoaderDataGraph::roots_cld_do(CLDClosure* strong, CLDClosure* weak) { assert_is_safepoint_or_gc(); for (ClassLoaderData* cld = Atomic::load_acquire(&_head); cld != nullptr; cld = cld->next()) { - CLDClosure* closure = cld->keep_alive() ? strong : weak; + CLDClosure* closure = (cld->keep_alive_ref_count() > 0) ? strong : weak; if (closure != nullptr) { closure->do_cld(cld); } @@ -309,8 +309,7 @@ void ClassLoaderDataGraph::modules_do_keepalive(void f(ModuleEntry*)) { assert_locked_or_safepoint(Module_lock); ClassLoaderDataGraphIterator iter; while (ClassLoaderData* cld = iter.get_next()) { - // Keep the holder alive. - (void)cld->holder(); + cld->keep_alive(); cld->modules_do(f); } } @@ -334,8 +333,7 @@ void ClassLoaderDataGraph::packages_do(void f(PackageEntry*)) { void ClassLoaderDataGraph::loaded_classes_do_keepalive(KlassClosure* klass_closure) { ClassLoaderDataGraphIterator iter; while (ClassLoaderData* cld = iter.get_next()) { - // Keep the holder alive. - (void)cld->holder(); + cld->keep_alive(); cld->loaded_classes_do(klass_closure); } } diff --git a/src/hotspot/share/classfile/javaClasses.cpp b/src/hotspot/share/classfile/javaClasses.cpp index a0b5b73c6d449..b1b74bbba05cf 100644 --- a/src/hotspot/share/classfile/javaClasses.cpp +++ b/src/hotspot/share/classfile/javaClasses.cpp @@ -963,7 +963,7 @@ void java_lang_Class::set_mirror_module_field(JavaThread* current, Klass* k, Han // Keep list of classes needing java.base module fixup if (!ModuleEntryTable::javabase_defined()) { assert(k->java_mirror() != nullptr, "Class's mirror is null"); - k->class_loader_data()->inc_keep_alive(); + k->class_loader_data()->inc_keep_alive_ref_count(); assert(fixup_module_field_list() != nullptr, "fixup_module_field_list not initialized"); fixup_module_field_list()->push(k); } else { diff --git a/src/hotspot/share/classfile/moduleEntry.cpp b/src/hotspot/share/classfile/moduleEntry.cpp index 6c60d60d21192..af4332ca6912e 100644 --- a/src/hotspot/share/classfile/moduleEntry.cpp +++ b/src/hotspot/share/classfile/moduleEntry.cpp @@ -705,7 +705,7 @@ void ModuleEntryTable::patch_javabase_entries(JavaThread* current, Handle module { java_lang_Class::fixup_module_field(k, module_handle); } - k->class_loader_data()->dec_keep_alive(); + k->class_loader_data()->dec_keep_alive_ref_count(); } delete java_lang_Class::fixup_module_field_list(); diff --git a/src/hotspot/share/prims/jvm.cpp b/src/hotspot/share/prims/jvm.cpp index 4f63ebdf9d518..1e3806474b540 100644 --- a/src/hotspot/share/prims/jvm.cpp +++ b/src/hotspot/share/prims/jvm.cpp @@ -1032,7 +1032,7 @@ static jclass jvm_lookup_define_class(jclass lookup, const char *name, // The hidden class loader data has been artificially been kept alive to // this point. The mirror and any instances of this class have to keep // it alive afterwards. - ik->class_loader_data()->dec_keep_alive(); + ik->class_loader_data()->dec_keep_alive_ref_count(); if (is_nestmate && log_is_enabled(Debug, class, nestmates)) { ModuleEntry* module = ik->module(); From 066db6eb21e9c9202857f9f6adfcd537a0b82160 Mon Sep 17 00:00:00 2001 From: Alexey Ivanov Date: Fri, 2 Aug 2024 13:06:22 +0000 Subject: [PATCH 176/353] 8337274: Remove repeated 'the' in StyleSheet.create{Small,Large}AttributeSet Reviewed-by: achung, honkar, prr --- .../share/classes/javax/swing/text/html/StyleSheet.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/java.desktop/share/classes/javax/swing/text/html/StyleSheet.java b/src/java.desktop/share/classes/javax/swing/text/html/StyleSheet.java index 9b8e33b4c6b03..64d2e0e3bbf8a 100644 --- a/src/java.desktop/share/classes/javax/swing/text/html/StyleSheet.java +++ b/src/java.desktop/share/classes/javax/swing/text/html/StyleSheet.java @@ -724,7 +724,7 @@ public AttributeSet removeAttributes(AttributeSet old, AttributeSet attrs) { * to return an AttributeSet that provides some sort of * attribute conversion. * - * @param a The set of attributes to be represented in the + * @param a The set of attributes to be represented in * the compact form. */ protected SmallAttributeSet createSmallAttributeSet(AttributeSet a) { @@ -740,7 +740,7 @@ protected SmallAttributeSet createSmallAttributeSet(AttributeSet a) { * to return a MutableAttributeSet that provides some sort of * attribute conversion. * - * @param a The set of attributes to be represented in the + * @param a The set of attributes to be represented in * the larger form. */ protected MutableAttributeSet createLargeAttributeSet(AttributeSet a) { @@ -2173,7 +2173,7 @@ public static final class ListPainter implements Serializable { /** * Returns a string that represents the value * of the HTML.Attribute.TYPE attribute. - * If this attributes is not defined, then + * If this attributes is not defined, * then the type defaults to "disc" unless * the tag is on Ordered list. In the case * of the latter, the default type is "decimal". From f2e1205abf915c7f036c58292c6f4d8602cb0e64 Mon Sep 17 00:00:00 2001 From: Erik Gahlin Date: Fri, 2 Aug 2024 15:51:26 +0000 Subject: [PATCH 177/353] 8337676: JFR: Change the label of the throttle setting Reviewed-by: mgronlun --- .../classes/jdk/jfr/internal/settings/ThrottleSetting.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/ThrottleSetting.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/ThrottleSetting.java index 55757050b80fd..c18031d514f98 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/ThrottleSetting.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/ThrottleSetting.java @@ -44,7 +44,7 @@ import jdk.jfr.internal.util.Utils; @MetadataDefinition -@Label("Event Emission Throttle") +@Label("Throttle") @Description("Throttles the emission rate for an event") @Name(Type.SETTINGS_PREFIX + "Throttle") public final class ThrottleSetting extends JDKSettingControl { From 7deee745254e5f32b75a09d84ac5078a122c8b8d Mon Sep 17 00:00:00 2001 From: Jonathan Gibbons Date: Fri, 2 Aug 2024 17:53:23 +0000 Subject: [PATCH 178/353] 8335122: Reorganize internal low-level support for HTML in jdk.javadoc Reviewed-by: hannesw --- .../html/AbstractExecutableMemberWriter.java | 21 +- .../formats/html/AbstractMemberWriter.java | 23 +- .../html/AbstractOverviewIndexWriter.java | 15 +- .../formats/html/AbstractTreeWriter.java | 26 +- .../formats/html/AllClassesIndexWriter.java | 18 +- .../formats/html/AllPackagesIndexWriter.java | 17 +- .../html/AnnotationTypeMemberWriter.java | 27 +- .../doclets/formats/html/ClassUseWriter.java | 29 +- .../doclets/formats/html/ClassWriter.java | 49 +-- .../formats/html/ConstantsSummaryWriter.java | 33 ++- .../formats/html/ConstructorWriter.java | 33 ++- .../doclets/formats/html/Contents.java | 7 +- .../formats/html/DeprecatedListWriter.java | 14 +- .../doclets/formats/html/DocFilesHandler.java | 33 ++- .../formats/html/EnumConstantWriter.java | 23 +- .../formats/html/ExternalSpecsWriter.java | 17 +- .../doclets/formats/html/FieldWriter.java | 28 +- .../doclets/formats/html/Headings.java | 30 +- .../doclets/formats/html/HelpWriter.java | 41 +-- .../formats/html/HtmlDocletWriter.java | 86 +++--- .../doclets/formats/html/HtmlIds.java | 3 +- .../formats/html/HtmlIndexBuilder.java | 3 +- .../doclets/formats/html/HtmlLinkFactory.java | 15 +- .../doclets/formats/html/HtmlLinkInfo.java | 8 +- .../formats/html/IndexRedirectWriter.java | 18 +- .../doclets/formats/html/IndexWriter.java | 41 ++- .../doclets/formats/html/MarkerComments.java | 2 +- .../doclets/formats/html/MethodWriter.java | 28 +- .../formats/html/ModuleIndexWriter.java | 11 +- .../doclets/formats/html/ModuleWriter.java | 71 ++--- .../doclets/formats/html/Navigation.java | 48 +-- .../formats/html/NestedClassWriter.java | 22 +- .../formats/html/NewAPIListWriter.java | 16 +- .../formats/html/PackageIndexWriter.java | 11 +- .../formats/html/PackageTreeWriter.java | 20 +- .../formats/html/PackageUseWriter.java | 36 ++- .../doclets/formats/html/PackageWriter.java | 43 +-- .../formats/html/PreviewListWriter.java | 16 +- .../doclets/formats/html/PropertyWriter.java | 29 +- .../formats/html/RestrictedListWriter.java | 1 + .../doclets/formats/html/SearchWriter.java | 31 +- .../formats/html/SerialFieldWriter.java | 21 +- .../formats/html/SerialMethodWriter.java | 17 +- .../formats/html/SerializedFormWriter.java | 29 +- .../doclets/formats/html/Signatures.java | 78 ++--- .../formats/html/SourceToHTMLConverter.java | 22 +- .../formats/html/SubWriterHolderWriter.java | 31 +- .../formats/html/SummaryListWriter.java | 28 +- .../formats/html/SystemPropertiesWriter.java | 17 +- .../internal/doclets/formats/html/Table.java | 38 +-- .../doclets/formats/html/TableHeader.java | 18 +- .../doclets/formats/html/TableOfContents.java | 33 ++- .../doclets/formats/html/TreeWriter.java | 17 +- .../formats/html/markup/BodyContents.java | 9 +- .../doclets/formats/html/markup/Head.java | 11 +- .../doclets/formats/html/markup/HtmlAttr.java | 123 -------- .../formats/html/markup/HtmlDocument.java | 6 +- .../{HtmlStyle.java => HtmlStyles.java} | 8 +- .../doclets/formats/html/markup/Links.java | 11 +- .../doclets/formats/html/markup/TagName.java | 118 -------- .../formats/html/markup/package-info.java | 2 +- .../formats/html/taglets/BaseTaglet.java | 2 +- .../html/taglets/DeprecatedTaglet.java | 16 +- .../formats/html/taglets/DocRootTaglet.java | 4 +- .../formats/html/taglets/IndexTaglet.java | 2 +- .../html/taglets/InheritDocTaglet.java | 2 +- .../formats/html/taglets/LinkTaglet.java | 6 +- .../formats/html/taglets/LiteralTaglet.java | 6 +- .../formats/html/taglets/ParamTaglet.java | 8 +- .../formats/html/taglets/ReturnTaglet.java | 6 +- .../formats/html/taglets/SeeTaglet.java | 8 +- .../formats/html/taglets/SimpleTaglet.java | 8 +- .../formats/html/taglets/SnippetTaglet.java | 26 +- .../formats/html/taglets/SpecTaglet.java | 15 +- .../formats/html/taglets/SummaryTaglet.java | 2 +- .../html/taglets/SystemPropertyTaglet.java | 4 +- .../doclets/formats/html/taglets/Taglet.java | 6 +- .../formats/html/taglets/TagletWriter.java | 20 +- .../formats/html/taglets/ThrowsTaglet.java | 6 +- .../formats/html/taglets/UserTaglet.java | 4 +- .../formats/html/taglets/ValueTaglet.java | 4 +- .../jdk/javadoc/internal/doclint/Checker.java | 37 ++- .../formats/html/markup => html}/Comment.java | 4 +- .../{doclets/formats => }/html/Content.java | 2 +- .../html/markup => html}/ContentBuilder.java | 4 +- .../formats/html/markup => html}/DocType.java | 2 +- .../formats/html/markup => html}/Entity.java | 4 +- .../jdk/javadoc/internal/html/HtmlAttr.java | 275 +++++++++++++++++ .../formats/html/markup => html}/HtmlId.java | 2 +- .../jdk/javadoc/internal/html/HtmlStyle.java | 42 +++ .../internal/{doclint => html}/HtmlTag.java | 279 +++++------------- .../html/markup => html}/HtmlTree.java | 149 +++++----- .../html/markup => html}/ListBuilder.java | 4 +- .../formats/html/markup => html}/RawHtml.java | 8 +- .../formats/html/markup => html}/Script.java | 6 +- .../formats/html/markup => html}/Text.java | 4 +- .../html/markup => html}/TextBuilder.java | 4 +- .../jdk/javadoc/internal/package-info.java | 4 +- .../CheckStylesheetClasses.java | 12 +- .../testHtmlDocument/TestHtmlDocument.java | 36 +-- .../TestHtmlTableStyles.java | 2 +- .../TestVoidHtmlElements.java | 14 +- .../tools/doclint/CoverageExtras.java | 8 +- .../html/HtmlVersionTagsAttrsTest.java | 8 +- .../doclint/html/HtmlVersionTagsAttrsTest.out | 20 +- .../tools/doclint/html/OtherTagsTest.java | 2 +- .../tools/doclint/html/OtherTagsTest.out | 5 +- 107 files changed, 1377 insertions(+), 1395 deletions(-) delete mode 100644 src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlAttr.java rename src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/{HtmlStyle.java => HtmlStyles.java} (99%) delete mode 100644 src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/TagName.java rename src/jdk.javadoc/share/classes/jdk/javadoc/internal/{doclets/formats/html/markup => html}/Comment.java (94%) rename src/jdk.javadoc/share/classes/jdk/javadoc/internal/{doclets/formats => }/html/Content.java (99%) rename src/jdk.javadoc/share/classes/jdk/javadoc/internal/{doclets/formats/html/markup => html}/ContentBuilder.java (96%) rename src/jdk.javadoc/share/classes/jdk/javadoc/internal/{doclets/formats/html/markup => html}/DocType.java (96%) rename src/jdk.javadoc/share/classes/jdk/javadoc/internal/{doclets/formats/html/markup => html}/Entity.java (97%) create mode 100644 src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/HtmlAttr.java rename src/jdk.javadoc/share/classes/jdk/javadoc/internal/{doclets/formats/html/markup => html}/HtmlId.java (96%) create mode 100644 src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/HtmlStyle.java rename src/jdk.javadoc/share/classes/jdk/javadoc/internal/{doclint => html}/HtmlTag.java (72%) rename src/jdk.javadoc/share/classes/jdk/javadoc/internal/{doclets/formats/html/markup => html}/HtmlTree.java (90%) rename src/jdk.javadoc/share/classes/jdk/javadoc/internal/{doclets/formats/html/markup => html}/ListBuilder.java (97%) rename src/jdk.javadoc/share/classes/jdk/javadoc/internal/{doclets/formats/html/markup => html}/RawHtml.java (96%) rename src/jdk.javadoc/share/classes/jdk/javadoc/internal/{doclets/formats/html/markup => html}/Script.java (97%) rename src/jdk.javadoc/share/classes/jdk/javadoc/internal/{doclets/formats/html/markup => html}/Text.java (97%) rename src/jdk.javadoc/share/classes/jdk/javadoc/internal/{doclets/formats/html/markup => html}/TextBuilder.java (96%) diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractExecutableMemberWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractExecutableMemberWriter.java index f6ad4cf05dfab..84672926cf81a 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractExecutableMemberWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractExecutableMemberWriter.java @@ -38,13 +38,14 @@ import javax.lang.model.type.TypeMirror; import javax.lang.model.util.SimpleTypeVisitor14; -import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; -import jdk.javadoc.internal.doclets.formats.html.markup.Entity; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; -import jdk.javadoc.internal.doclets.formats.html.markup.TagName; -import jdk.javadoc.internal.doclets.formats.html.markup.Text; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyles; import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable; +import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.ContentBuilder; +import jdk.javadoc.internal.html.Entity; +import jdk.javadoc.internal.html.HtmlTag; +import jdk.javadoc.internal.html.HtmlTree; +import jdk.javadoc.internal.html.Text; import static jdk.javadoc.internal.doclets.formats.html.HtmlLinkInfo.Kind.LINK_TYPE_PARAMS; import static jdk.javadoc.internal.doclets.formats.html.HtmlLinkInfo.Kind.LINK_TYPE_PARAMS_AND_BOUNDS; @@ -108,7 +109,7 @@ protected Content getSummaryLink(Element member) { } String signature = utils.flatSignature((ExecutableElement) member, typeElement); if (signature.length() > 2) { - content.add(new HtmlTree(TagName.WBR)); + content.add(new HtmlTree(HtmlTag.WBR)); } content.add(signature); @@ -120,7 +121,7 @@ protected Content getSummaryLink(Element member) { protected void addSummaryLink(HtmlLinkInfo.Kind context, TypeElement te, Element member, Content target) { ExecutableElement ee = (ExecutableElement)member; - Content memberLink = writer.getDocLink(context, te, ee, name(ee), HtmlStyle.memberNameLink); + Content memberLink = writer.getDocLink(context, te, ee, name(ee), HtmlStyles.memberNameLink); var code = HtmlTree.CODE(memberLink); addParameters(ee, code); target.add(code); @@ -143,7 +144,7 @@ protected void addTypeParameters(ExecutableElement member, Content target) { // Add explicit line break between method type parameters and // return type in member summary table to avoid random wrapping. if (typeParameters.charCount() > 10) { - target.add(new HtmlTree(TagName.BR)); + target.add(new HtmlTree(HtmlTag.BR)); } else { target.add(Entity.NO_BREAK_SPACE); } @@ -232,7 +233,7 @@ protected void addParameters(ExecutableElement member, Content target) { Content params = getParameters(member, false); if (params.charCount() > 2) { // only add for non-empty parameters - target.add(new HtmlTree(TagName.WBR)); + target.add(new HtmlTree(HtmlTag.WBR)); } target.add(params); } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractMemberWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractMemberWriter.java index af1f7ef1fe6cb..e2b81bb39822d 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractMemberWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractMemberWriter.java @@ -44,15 +44,16 @@ import com.sun.source.doctree.DocTree; -import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; -import jdk.javadoc.internal.doclets.formats.html.markup.Entity; -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.markup.HtmlStyles; import jdk.javadoc.internal.doclets.toolkit.Resources; import jdk.javadoc.internal.doclets.toolkit.util.DocFinder; import jdk.javadoc.internal.doclets.toolkit.util.Utils; import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable; +import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.ContentBuilder; +import jdk.javadoc.internal.html.Entity; +import jdk.javadoc.internal.html.HtmlTag; +import jdk.javadoc.internal.html.HtmlTree; import static jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable.Kind.ANNOTATION_TYPE_MEMBER; import static jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable.Kind.ANNOTATION_TYPE_MEMBER_OPTIONAL; @@ -450,7 +451,7 @@ protected abstract void addInheritedSummaryLink(TypeElement typeElement, */ protected void addModifiersAndType(Element member, TypeMirror type, Content target) { - var code = new HtmlTree(TagName.CODE); + var code = new HtmlTree(HtmlTag.CODE); addModifiers(member, code); if (type == null) { code.add(switch (member.getKind()) { @@ -518,7 +519,7 @@ protected void addDeprecatedInfo(Element member, Content target) { var t = configuration.tagletManager.getTaglet(DocTree.Kind.DEPRECATED); Content output = t.getAllBlockTagOutput(member, writer.getTagletWriterInstance(false)); if (!output.isEmpty()) { - target.add(HtmlTree.DIV(HtmlStyle.deprecationBlock, output)); + target.add(HtmlTree.DIV(HtmlStyles.deprecationBlock, output)); } } @@ -570,9 +571,9 @@ protected void addUseInfo(List members, Content heading, Cont return; } boolean printedUseTableHeader = false; - var useTable = new Table(HtmlStyle.summaryTable) + var useTable = new Table(HtmlStyles.summaryTable) .setCaption(heading) - .setColumnStyles(HtmlStyle.colFirst, HtmlStyle.colSecond, HtmlStyle.colLast); + .setColumnStyles(HtmlStyles.colFirst, HtmlStyles.colSecond, HtmlStyles.colLast); for (Element element : members) { TypeElement te = (typeElement == null) ? utils.getEnclosingTypeElement(element) @@ -588,7 +589,7 @@ protected void addUseInfo(List members, Content heading, Cont && !utils.isConstructor(element) && !utils.isTypeElement(element)) { - var name = HtmlTree.SPAN(HtmlStyle.typeNameLabel); + var name = HtmlTree.SPAN(HtmlStyles.typeNameLabel); name.add(name(te) + "."); typeContent.add(name); } @@ -669,7 +670,7 @@ public Content getInheritedSummaryHeader(TypeElement tElement) { * @return the inherited summary links */ public Content getInheritedSummaryLinks() { - return new HtmlTree(TagName.CODE); + return new HtmlTree(HtmlTag.CODE); } /** diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractOverviewIndexWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractOverviewIndexWriter.java index 2d7fb6e9b11a9..c466a2fcb5aa7 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractOverviewIndexWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractOverviewIndexWriter.java @@ -25,14 +25,15 @@ package jdk.javadoc.internal.doclets.formats.html; -import jdk.javadoc.internal.doclets.formats.html.markup.BodyContents; -import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; -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.RawHtml; +import jdk.javadoc.internal.doclets.formats.html.markup.BodyContents; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyles; import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException; import jdk.javadoc.internal.doclets.toolkit.util.DocPath; +import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.ContentBuilder; +import jdk.javadoc.internal.html.HtmlTree; +import jdk.javadoc.internal.html.RawHtml; /** * Abstract class to generate the top-level "overview" files. @@ -135,8 +136,8 @@ protected void addConfigurationTitle(Content target) { if (!doctitle.isEmpty()) { var title = RawHtml.of(doctitle); var heading = HtmlTree.HEADING(Headings.PAGE_TITLE_HEADING, - HtmlStyle.title, title); - var div = HtmlTree.DIV(HtmlStyle.header, heading); + HtmlStyles.title, title); + var div = HtmlTree.DIV(HtmlStyles.header, heading); target.add(div); } } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractTreeWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractTreeWriter.java index d0483d5d33c16..594132743eb0f 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractTreeWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractTreeWriter.java @@ -25,18 +25,20 @@ package jdk.javadoc.internal.doclets.formats.html; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; -import jdk.javadoc.internal.doclets.formats.html.markup.TagName; -import jdk.javadoc.internal.doclets.toolkit.util.ClassTree; -import jdk.javadoc.internal.doclets.toolkit.util.ClassTree.Hierarchy; -import jdk.javadoc.internal.doclets.toolkit.util.DocPath; - -import javax.lang.model.element.TypeElement; import java.util.Collection; import java.util.SortedSet; import java.util.TreeSet; +import javax.lang.model.element.TypeElement; + +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyles; +import jdk.javadoc.internal.doclets.toolkit.util.ClassTree; +import jdk.javadoc.internal.doclets.toolkit.util.ClassTree.Hierarchy; +import jdk.javadoc.internal.doclets.toolkit.util.DocPath; +import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.HtmlTag; +import jdk.javadoc.internal.html.HtmlTree; + /** * Abstract class to print the class hierarchy page for all the Classes. This @@ -77,10 +79,10 @@ protected AbstractTreeWriter(HtmlConfiguration configuration, protected void addLevelInfo(TypeElement parent, Collection collection, Hierarchy hierarchy, Content content) { if (!collection.isEmpty()) { - var ul = new HtmlTree(TagName.UL); + var ul = new HtmlTree(HtmlTag.UL); for (TypeElement local : collection) { - var li = new HtmlTree(TagName.LI); - li.setStyle(HtmlStyle.circle); + var li = new HtmlTree(HtmlTag.LI); + li.setStyle(HtmlStyles.circle); addPartialInfo(local, li); addExtendsImplements(parent, local, li); addLevelInfo(local, hierarchy.subtypes(local), hierarchy, li); // Recurse @@ -104,7 +106,7 @@ protected void addTree(Hierarchy hierarchy, String heading, Content content) { Content headingContent = contents.getContent(heading); var sectionHeading = HtmlTree.HEADING_TITLE(Headings.CONTENT_HEADING, headingContent); - var section = HtmlTree.SECTION(HtmlStyle.hierarchy, sectionHeading); + var section = HtmlTree.SECTION(HtmlStyles.hierarchy, sectionHeading); addLevelInfo(!utils.isPlainInterface(firstTypeElement) ? firstTypeElement : null, roots, hierarchy, section); content.add(section); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AllClassesIndexWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AllClassesIndexWriter.java index 5aa9f349a5137..68ee6d98857e5 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AllClassesIndexWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AllClassesIndexWriter.java @@ -33,14 +33,16 @@ import javax.lang.model.element.TypeElement; import com.sun.source.doctree.DeprecatedTree; -import jdk.javadoc.internal.doclets.formats.html.markup.BodyContents; -import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; -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.BodyContents; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyles; import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException; import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; import jdk.javadoc.internal.doclets.toolkit.util.Utils.ElementFlag; +import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.ContentBuilder; +import jdk.javadoc.internal.html.HtmlTree; /** * Generate the file with list of all the classes in this run. @@ -79,9 +81,9 @@ public void buildPage() throws DocFileIOException { * @param target the content to which the links will be added */ protected void addContents(Content target) { - var table = new Table(HtmlStyle.summaryTable) + var table = new Table(HtmlStyles.summaryTable) .setHeader(new TableHeader(contents.classLabel, contents.descriptionLabel)) - .setColumnStyles(HtmlStyle.colFirst, HtmlStyle.colLast) + .setColumnStyles(HtmlStyles.colFirst, HtmlStyles.colLast) .setId(HtmlIds.ALL_CLASSES_TABLE) .setDefaultTab(contents.allClassesAndInterfacesLabel) .addTab(contents.interfaces, utils::isPlainInterface) @@ -96,8 +98,8 @@ protected void addContents(Content target) { } Content titleContent = contents.allClassesAndInterfacesLabel; var pHeading = HtmlTree.HEADING_TITLE(Headings.PAGE_TITLE_HEADING, - HtmlStyle.title, titleContent); - var headerDiv = HtmlTree.DIV(HtmlStyle.header, pHeading); + HtmlStyles.title, titleContent); + var headerDiv = HtmlTree.DIV(HtmlStyles.header, pHeading); target.add(headerDiv); if (!table.isEmpty()) { target.add(table); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AllPackagesIndexWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AllPackagesIndexWriter.java index 5581ec03e2a23..2c9539d3c30dc 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AllPackagesIndexWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AllPackagesIndexWriter.java @@ -29,12 +29,13 @@ import jdk.javadoc.internal.doclets.formats.html.Navigation.PageMode; import jdk.javadoc.internal.doclets.formats.html.markup.BodyContents; -import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; -import jdk.javadoc.internal.doclets.formats.html.markup.Text; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyles; import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException; import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; +import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.ContentBuilder; +import jdk.javadoc.internal.html.HtmlTree; +import jdk.javadoc.internal.html.Text; /** * Generate the file with list of all the packages in this run. @@ -60,8 +61,8 @@ public void buildPage() throws DocFileIOException { addPackages(mainContent); Content titleContent = contents.allPackagesLabel; var pHeading = HtmlTree.HEADING_TITLE(Headings.PAGE_TITLE_HEADING, - HtmlStyle.title, titleContent); - var headerDiv = HtmlTree.DIV(HtmlStyle.header, pHeading); + HtmlStyles.title, titleContent); + var headerDiv = HtmlTree.DIV(HtmlStyles.header, pHeading); HtmlTree body = getBody(getWindowTitle(label)); body.add(new BodyContents() .setHeader(getHeader(PageMode.ALL_PACKAGES)) @@ -77,10 +78,10 @@ public void buildPage() throws DocFileIOException { * @param target the content to which the links will be added */ protected void addPackages(Content target) { - var table = new Table(HtmlStyle.summaryTable) + var table = new Table(HtmlStyles.summaryTable) .setCaption(Text.of(contents.packageSummaryLabel.toString())) .setHeader(new TableHeader(contents.packageLabel, contents.descriptionLabel)) - .setColumnStyles(HtmlStyle.colFirst, HtmlStyle.colLast); + .setColumnStyles(HtmlStyles.colFirst, HtmlStyles.colLast); for (PackageElement pkg : configuration.packages) { if (!(options.noDeprecated() && utils.isDeprecated(pkg))) { Content packageLinkContent = getPackageLink(pkg, getLocalizedPackageName(pkg)); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AnnotationTypeMemberWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AnnotationTypeMemberWriter.java index 8f8585ecc6205..f1f6311023115 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AnnotationTypeMemberWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AnnotationTypeMemberWriter.java @@ -32,13 +32,14 @@ import javax.lang.model.element.TypeElement; import javax.lang.model.type.TypeMirror; -import jdk.javadoc.internal.doclets.formats.html.markup.Comment; -import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; -import jdk.javadoc.internal.doclets.formats.html.markup.Text; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyles; import jdk.javadoc.internal.doclets.toolkit.BaseOptions; import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable; +import jdk.javadoc.internal.html.Comment; +import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.ContentBuilder; +import jdk.javadoc.internal.html.HtmlTree; +import jdk.javadoc.internal.html.Text; /** @@ -96,7 +97,7 @@ protected void buildAnnotationTypeMember(Content target) { for (Element member : members) { currentMember = member; Content annotationContent = getAnnotationHeaderContent(currentMember); - Content div = HtmlTree.DIV(HtmlStyle.horizontalScroll); + Content div = HtmlTree.DIV(HtmlStyles.horizontalScroll); buildAnnotationTypeMemberChildren(div); annotationContent.add(div); memberList.add(writer.getMemberListItem(annotationContent)); @@ -181,7 +182,7 @@ public Content getMemberSummaryHeader(Content content) { @Override public void buildSummary(Content summariesList, Content content) { - writer.addSummary(HtmlStyle.memberSummary, + writer.addSummary(HtmlStyles.memberSummary, switch (kind) { case ANNOTATION_TYPE_MEMBER_REQUIRED -> HtmlIds.ANNOTATION_TYPE_REQUIRED_ELEMENT_SUMMARY; case ANNOTATION_TYPE_MEMBER_OPTIONAL -> HtmlIds.ANNOTATION_TYPE_OPTIONAL_ELEMENT_SUMMARY; @@ -209,7 +210,7 @@ protected Content getAnnotationHeaderContent(Element member) { var heading = HtmlTree.HEADING(Headings.TypeDeclaration.MEMBER_HEADING, Text.of(name(member))); content.add(heading); - return HtmlTree.SECTION(HtmlStyle.detail, content) + return HtmlTree.SECTION(HtmlStyles.detail, content) .setId(htmlIds.forMember((ExecutableElement) member).getFirst()); } @@ -238,7 +239,7 @@ protected void addTags(Element member, Content annotationContent) { protected Content getAnnotationDetails(Content annotationDetailsHeader, Content annotationDetails) { Content c = new ContentBuilder(annotationDetailsHeader, annotationDetails); - return getMember(HtmlTree.SECTION(HtmlStyle.memberDetails, c)); + return getMember(HtmlTree.SECTION(HtmlStyles.memberDetails, c)); } @Override @@ -278,10 +279,10 @@ public TableHeader getSummaryTableHeader(Element member) { @Override protected Table createSummaryTable() { - return new Table(HtmlStyle.summaryTable) + return new Table(HtmlStyles.summaryTable) .setCaption(getCaption()) .setHeader(getSummaryTableHeader(typeElement)) - .setColumnStyles(HtmlStyle.colFirst, HtmlStyle.colSecond, HtmlStyle.colLast); + .setColumnStyles(HtmlStyles.colFirst, HtmlStyles.colSecond, HtmlStyles.colLast); } @Override @@ -292,7 +293,7 @@ public void addInheritedSummaryLabel(TypeElement typeElement, Content content) { protected void addSummaryLink(HtmlLinkInfo.Kind context, TypeElement typeElement, Element member, Content content) { Content memberLink = writer.getDocLink(context, utils.getEnclosingTypeElement(member), member, - name(member), HtmlStyle.memberNameLink); + name(member), HtmlStyles.memberNameLink); var code = HtmlTree.CODE(memberLink); content.add(code); } @@ -331,7 +332,7 @@ protected void addDefaultValueInfo(Element member, Content annotationContent) { ExecutableElement ee = (ExecutableElement) member; AnnotationValue value = ee.getDefaultValue(); if (value != null) { - var dl = HtmlTree.DL(HtmlStyle.notes); + var dl = HtmlTree.DL(HtmlStyles.notes); dl.add(HtmlTree.DT(contents.default_)); dl.add(HtmlTree.DD(HtmlTree.CODE(Text.of(value.toString())))); annotationContent.add(dl); 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 94e66f1eed610..ac953dccb55df 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 @@ -38,11 +38,8 @@ import javax.lang.model.element.TypeElement; import javax.tools.Diagnostic; -import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; -import jdk.javadoc.internal.doclets.formats.html.markup.TagName; -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.HtmlStyles; import jdk.javadoc.internal.doclets.toolkit.DocletException; import jdk.javadoc.internal.doclets.toolkit.util.ClassTree; import jdk.javadoc.internal.doclets.toolkit.util.ClassUseMapper; @@ -50,6 +47,10 @@ import jdk.javadoc.internal.doclets.toolkit.util.DocPath; import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; import jdk.javadoc.internal.doclets.toolkit.util.Utils; +import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.ContentBuilder; +import jdk.javadoc.internal.html.HtmlTag; +import jdk.javadoc.internal.html.HtmlTree; /** @@ -244,10 +245,10 @@ protected void addPackageList(Content content) { "doclet.ClassUse_Packages.that.use.0", getLink(new HtmlLinkInfo(configuration, HtmlLinkInfo.Kind.PLAIN, typeElement))); - var table = new Table(HtmlStyle.summaryTable) + var table = new Table(HtmlStyles.summaryTable) .setCaption(caption) .setHeader(getPackageTableHeader()) - .setColumnStyles(HtmlStyle.colFirst, HtmlStyle.colLast); + .setColumnStyles(HtmlStyles.colFirst, HtmlStyles.colLast); for (PackageElement pkg : pkgSet) { addPackageUse(pkg, table); } @@ -270,10 +271,10 @@ protected void addPackageAnnotationList(Content content) { getLink(new HtmlLinkInfo(configuration, HtmlLinkInfo.Kind.PLAIN, typeElement))); - var table = new Table(HtmlStyle.summaryTable) + var table = new Table(HtmlStyles.summaryTable) .setCaption(caption) .setHeader(getPackageTableHeader()) - .setColumnStyles(HtmlStyle.colFirst, HtmlStyle.colLast); + .setColumnStyles(HtmlStyles.colFirst, HtmlStyles.colLast); for (PackageElement pkg : pkgToPackageAnnotations) { Content summary = new ContentBuilder(); addSummaryComment(pkg, summary); @@ -288,9 +289,9 @@ protected void addPackageAnnotationList(Content content) { * @param content the content to which the class elements will be added */ protected void addClassList(Content content) { - var ul = HtmlTree.UL(HtmlStyle.blockList); + var ul = HtmlTree.UL(HtmlStyles.blockList); for (PackageElement pkg : pkgSet) { - var section = HtmlTree.SECTION(HtmlStyle.detail) + var section = HtmlTree.SECTION(HtmlStyles.detail) .setId(htmlIds.forPackage(pkg)); Content link = contents.getContent("doclet.ClassUse_Uses.of.0.in.1", getLink(new HtmlLinkInfo(configuration, HtmlLinkInfo.Kind.PLAIN, @@ -301,7 +302,7 @@ protected void addClassList(Content content) { addClassUse(pkg, section); ul.add(HtmlTree.LI(section)); } - var li = HtmlTree.SECTION(HtmlStyle.classUses, ul); + var li = HtmlTree.SECTION(HtmlStyles.classUses, ul); content.add(li); } @@ -422,11 +423,11 @@ protected HtmlTree getClassUseHeader() { HtmlTree body = getBody(getWindowTitle(title)); ContentBuilder headingContent = new ContentBuilder(); headingContent.add(contents.getContent("doclet.ClassUse_Title", cltype)); - headingContent.add(new HtmlTree(TagName.BR)); + headingContent.add(new HtmlTree(HtmlTag.BR)); headingContent.add(clname); var heading = HtmlTree.HEADING_TITLE(Headings.PAGE_TITLE_HEADING, - HtmlStyle.title, headingContent); - var div = HtmlTree.DIV(HtmlStyle.header, heading); + HtmlStyles.title, headingContent); + var div = HtmlTree.DIV(HtmlStyles.header, heading); bodyContents.setHeader(getHeader(PageMode.USE, typeElement)).addMainContent(div); return body; } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriter.java index 7e0cf74c4f331..a1fd27fefdd58 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriter.java @@ -45,12 +45,7 @@ import com.sun.source.doctree.DocTree; import jdk.javadoc.internal.doclets.formats.html.Navigation.PageMode; -import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlAttr; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; -import jdk.javadoc.internal.doclets.formats.html.markup.TagName; -import jdk.javadoc.internal.doclets.formats.html.markup.Text; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyles; import jdk.javadoc.internal.doclets.toolkit.CommentUtils; import jdk.javadoc.internal.doclets.toolkit.DocletException; import jdk.javadoc.internal.doclets.toolkit.PropertyUtils; @@ -58,6 +53,12 @@ import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper; import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException; import jdk.javadoc.internal.doclets.toolkit.util.DocPath; +import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.ContentBuilder; +import jdk.javadoc.internal.html.HtmlAttr; +import jdk.javadoc.internal.html.HtmlTag; +import jdk.javadoc.internal.html.HtmlTree; +import jdk.javadoc.internal.html.Text; /** * Generate the Class Information Page. @@ -154,7 +155,7 @@ protected void buildClassTree(Content classContent) { * @param target the content to which the documentation will be added */ protected void buildClassInfo(Content target) { - Content c = HtmlTree.DIV(HtmlStyle.horizontalScroll); + Content c = HtmlTree.DIV(HtmlStyles.horizontalScroll); buildParamInfo(c); buildSuperInterfacesInfo(c); buildImplementedInterfacesInfo(c); @@ -430,12 +431,12 @@ private void setRecordDocumentation(TypeElement elem) { protected Content getHeader(String header) { HtmlTree body = getBody(getWindowTitle(utils.getSimpleName(typeElement))); - var div = HtmlTree.DIV(HtmlStyle.header); + var div = HtmlTree.DIV(HtmlStyles.header); HtmlLinkInfo linkInfo = new HtmlLinkInfo(configuration, HtmlLinkInfo.Kind.SHOW_TYPE_PARAMS_AND_BOUNDS, typeElement) .linkToSelf(false); // Let's not link to ourselves in the header var heading = HtmlTree.HEADING_TITLE(Headings.PAGE_TITLE_HEADING, - HtmlStyle.title, Text.of(header)); + HtmlStyles.title, Text.of(header)); heading.add(getTypeParameterLinks(linkInfo)); div.add(heading); bodyContents.setHeader(getHeader(PageMode.CLASS, typeElement)) @@ -463,7 +464,7 @@ protected void printDocument(Content content) throws DocFileIOException { } protected Content getClassInfo(Content classInfo) { - return getMember(HtmlIds.CLASS_DESCRIPTION, HtmlStyle.classDescription, classInfo); + return getMember(HtmlIds.CLASS_DESCRIPTION, HtmlStyles.classDescription, classInfo); } @Override @@ -472,7 +473,7 @@ public TypeElement getCurrentPageElement() { } protected void addClassSignature(Content classInfo) { - classInfo.add(new HtmlTree(TagName.HR)); + classInfo.add(new HtmlTree(HtmlTag.HR)); classInfo.add(new Signatures.TypeSignature(typeElement, this) .toContent()); } @@ -514,7 +515,7 @@ private Content getClassInheritanceTreeContent(TypeMirror type) { HtmlTree classTree = null; do { sup = utils.getFirstVisibleSuperClass(type); - var entry = HtmlTree.DIV(HtmlStyle.inheritance, getClassHelperContent(type)); + var entry = HtmlTree.DIV(HtmlStyles.inheritance, getClassHelperContent(type)); if (classTree != null) entry.add(classTree); classTree = entry; @@ -564,7 +565,7 @@ protected void addParamInfo(Content target) { var t = configuration.tagletManager.getTaglet(DocTree.Kind.PARAM); Content paramInfo = t.getAllBlockTagOutput(typeElement, getTagletWriterInstance(false)); if (!paramInfo.isEmpty()) { - target.add(HtmlTree.DL(HtmlStyle.notes, paramInfo)); + target.add(HtmlTree.DL(HtmlStyles.notes, paramInfo)); } } } @@ -578,7 +579,7 @@ protected void addSubClassInfo(Content target) { } Set subclasses = classTree.hierarchy(typeElement).subtypes(typeElement); if (!subclasses.isEmpty()) { - var dl = HtmlTree.DL(HtmlStyle.notes); + var dl = HtmlTree.DL(HtmlStyles.notes); dl.add(HtmlTree.DT(contents.subclassesLabel)); dl.add(HtmlTree.DD(getClassLinks(HtmlLinkInfo.Kind.PLAIN, subclasses))); target.add(dl); @@ -590,7 +591,7 @@ protected void addSubInterfacesInfo(Content target) { if (utils.isPlainInterface(typeElement)) { Set subInterfaces = classTree.hierarchy(typeElement).allSubtypes(typeElement); if (!subInterfaces.isEmpty()) { - var dl = HtmlTree.DL(HtmlStyle.notes); + var dl = HtmlTree.DL(HtmlStyles.notes); dl.add(HtmlTree.DT(contents.subinterfacesLabel)); dl.add(HtmlTree.DD(getClassLinks(HtmlLinkInfo.Kind.SHOW_TYPE_PARAMS, subInterfaces))); target.add(dl); @@ -609,7 +610,7 @@ protected void addInterfaceUsageInfo(Content target) { } Set implcl = classTree.implementingClasses(typeElement); if (!implcl.isEmpty()) { - var dl = HtmlTree.DL(HtmlStyle.notes); + var dl = HtmlTree.DL(HtmlStyles.notes); dl.add(HtmlTree.DT(contents.implementingClassesLabel)); dl.add(HtmlTree.DD(getClassLinks(HtmlLinkInfo.Kind.PLAIN, implcl))); target.add(dl); @@ -620,7 +621,7 @@ protected void addImplementedInterfacesInfo(Content target) { SortedSet interfaces = new TreeSet<>(comparators.typeMirrorClassUseComparator()); interfaces.addAll(utils.getAllInterfaces(typeElement)); if (utils.isClass(typeElement) && !interfaces.isEmpty()) { - var dl = HtmlTree.DL(HtmlStyle.notes); + var dl = HtmlTree.DL(HtmlStyles.notes); dl.add(HtmlTree.DT(contents.allImplementedInterfacesLabel)); dl.add(HtmlTree.DD(getClassLinks(HtmlLinkInfo.Kind.SHOW_TYPE_PARAMS, interfaces))); target.add(dl); @@ -633,7 +634,7 @@ protected void addSuperInterfacesInfo(Content target) { interfaces.addAll(utils.getAllInterfaces(typeElement)); if (utils.isPlainInterface(typeElement) && !interfaces.isEmpty()) { - var dl = HtmlTree.DL(HtmlStyle.notes); + var dl = HtmlTree.DL(HtmlStyles.notes); dl.add(HtmlTree.DT(contents.allSuperinterfacesLabel)); dl.add(HtmlTree.DD(getClassLinks(HtmlLinkInfo.Kind.SHOW_TYPE_PARAMS, interfaces))); target.add(dl); @@ -647,7 +648,7 @@ protected void addNestedClassInfo(final Content target) { new SimpleElementVisitor8() { @Override public Void visitType(TypeElement e, Void p) { - var dl = HtmlTree.DL(HtmlStyle.notes); + var dl = HtmlTree.DL(HtmlStyles.notes); dl.add(HtmlTree.DT(utils.isPlainInterface(e) ? contents.enclosingInterfaceLabel : contents.enclosingClassLabel)); @@ -660,9 +661,9 @@ public Void visitType(TypeElement e, Void p) { protected void addFunctionalInterfaceInfo (Content target) { if (utils.isFunctionalInterface(typeElement)) { - var dl = HtmlTree.DL(HtmlStyle.notes); + var dl = HtmlTree.DL(HtmlStyles.notes); dl.add(HtmlTree.DT(contents.functionalInterface)); - var dd = new HtmlTree(TagName.DD); + var dd = new HtmlTree(HtmlTag.DD); dd.add(contents.functionalInterfaceMessage); dl.add(dd); target.add(dl); @@ -672,8 +673,8 @@ protected void addFunctionalInterfaceInfo (Content target) { protected void addClassDeprecationInfo(Content classInfo) { List deprs = utils.getDeprecatedTrees(typeElement); if (utils.isDeprecated(typeElement)) { - var deprLabel = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(typeElement)); - var div = HtmlTree.DIV(HtmlStyle.deprecationBlock, deprLabel); + var deprLabel = HtmlTree.SPAN(HtmlStyles.deprecatedLabel, getDeprecatedPhrase(typeElement)); + var div = HtmlTree.DIV(HtmlStyles.deprecationBlock, deprLabel); if (!deprs.isEmpty()) { CommentHelper ch = utils.getCommentHelper(typeElement); DocTree dt = deprs.get(0); @@ -726,7 +727,7 @@ public TypeElement getTypeElement() { } protected Content getMemberDetails(Content content) { - var section = HtmlTree.SECTION(HtmlStyle.details, content); + var section = HtmlTree.SECTION(HtmlStyles.details, content); // The following id is required by the Navigation bar if (utils.isAnnotationInterface(typeElement)) { section.setId(HtmlIds.ANNOTATION_TYPE_ELEMENT_DETAIL); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstantsSummaryWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstantsSummaryWriter.java index 5bddac0622c4f..cdae0e8d9115e 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstantsSummaryWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstantsSummaryWriter.java @@ -39,20 +39,21 @@ import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; -import jdk.javadoc.internal.doclets.formats.html.markup.BodyContents; -import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; -import jdk.javadoc.internal.doclets.formats.html.markup.Entity; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlId; -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.formats.html.markup.BodyContents; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyles; import jdk.javadoc.internal.doclets.toolkit.DocletException; import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException; import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; import jdk.javadoc.internal.doclets.toolkit.util.IndexItem; import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable; +import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.ContentBuilder; +import jdk.javadoc.internal.html.Entity; +import jdk.javadoc.internal.html.HtmlId; +import jdk.javadoc.internal.html.HtmlTag; +import jdk.javadoc.internal.html.HtmlTree; +import jdk.javadoc.internal.html.Text; /** @@ -328,14 +329,14 @@ Content getHeader() { bodyContents.setHeader(getHeader(PageMode.CONSTANT_VALUES)); Content titleContent = contents.constantsSummaryTitle; var pHeading = HtmlTree.HEADING_TITLE(Headings.PAGE_TITLE_HEADING, - HtmlStyle.title, titleContent); - var div = HtmlTree.DIV(HtmlStyle.header, pHeading); + HtmlStyles.title, titleContent); + var div = HtmlTree.DIV(HtmlStyles.header, pHeading); bodyContents.addMainContent(div); return body; } Content getContentsHeader() { - return HtmlTree.UL(HtmlStyle.contentsList); + return HtmlTree.UL(HtmlStyles.contentsList); } void addLinkToTableOfContents(String abbrevPackageName) { @@ -361,14 +362,14 @@ void addPackageGroup(String abbrevPackageName, Content toContent) { var heading = HtmlTree.HEADING_TITLE( Headings.ConstantsSummary.PACKAGE_HEADING, headingContent); - summarySection = HtmlTree.SECTION(HtmlStyle.constantsSummary, heading) + summarySection = HtmlTree.SECTION(HtmlStyles.constantsSummary, heading) .setId(anchorName); toContent.add(summarySection); } Content getClassConstantHeader() { - return HtmlTree.UL(HtmlStyle.blockList); + return HtmlTree.UL(HtmlStyles.blockList); } void addClassConstant(Content fromClassConstant) { @@ -394,10 +395,10 @@ void addConstantMembers(TypeElement typeElement, Collection fie } caption.add(classLink); - var table = new Table(HtmlStyle.summaryTable) + var table = new Table(HtmlStyles.summaryTable) .setCaption(caption) .setHeader(constantsTableHeader) - .setColumnStyles(HtmlStyle.colFirst, HtmlStyle.colSecond, HtmlStyle.colLast); + .setColumnStyles(HtmlStyles.colFirst, HtmlStyles.colSecond, HtmlStyles.colLast); for (VariableElement field : fields) { table.addRow(getTypeColumn(field), getNameColumn(field), getValue(field)); @@ -413,7 +414,7 @@ void addConstantMembers(TypeElement typeElement, Collection fie */ private Content getTypeColumn(VariableElement member) { Content typeContent = new ContentBuilder(); - var code = new HtmlTree(TagName.CODE) + var code = new HtmlTree(HtmlTag.CODE) .setId(htmlIds.forMember(currentTypeElement, member)); for (Modifier mod : member.getModifiers()) { code.add(Text.of(mod.toString())) diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstructorWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstructorWriter.java index c5fb332a0087b..11975404a5564 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstructorWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstructorWriter.java @@ -33,15 +33,16 @@ import javax.lang.model.element.TypeElement; import javax.lang.model.element.TypeParameterElement; -import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; -import jdk.javadoc.internal.doclets.formats.html.markup.Entity; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlId; -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.markup.Text; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyles; import jdk.javadoc.internal.doclets.toolkit.BaseOptions; import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable; +import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.ContentBuilder; +import jdk.javadoc.internal.html.Entity; +import jdk.javadoc.internal.html.HtmlStyle; +import jdk.javadoc.internal.html.HtmlTag; +import jdk.javadoc.internal.html.HtmlTree; +import jdk.javadoc.internal.html.Text; /** @@ -111,7 +112,7 @@ protected void buildConstructorDoc(Content target) { for (Element constructor : constructors) { currentConstructor = (ExecutableElement)constructor; Content constructorContent = getConstructorHeaderContent(currentConstructor); - Content div = HtmlTree.DIV(HtmlStyle.horizontalScroll); + Content div = HtmlTree.DIV(HtmlStyles.horizontalScroll); buildSignature(div); buildDeprecationInfo(div); buildPreviewInfo(div); @@ -193,7 +194,7 @@ public Content getMemberSummaryHeader(Content content) { @Override public void buildSummary(Content summariesList, Content content) { - writer.addSummary(HtmlStyle.constructorSummary, + writer.addSummary(HtmlStyles.constructorSummary, HtmlIds.CONSTRUCTOR_SUMMARY, summariesList, content); } @@ -216,7 +217,7 @@ protected Content getConstructorHeaderContent(ExecutableElement constructor) { heading.setId(anchors.getLast()); } content.add(heading); - return HtmlTree.SECTION(HtmlStyle.detail, content) + return HtmlTree.SECTION(HtmlStyles.detail, content) .setId(anchors.getFirst()); } @@ -247,7 +248,7 @@ protected void addTags(ExecutableElement constructor, Content constructorContent protected Content getConstructorDetails(Content memberDetailsHeader, Content memberDetails) { return writer.getDetailsListItem( - HtmlTree.SECTION(HtmlStyle.constructorDetails) + HtmlTree.SECTION(HtmlStyles.constructorDetails) .setId(HtmlIds.CONSTRUCTOR_DETAIL) .add(memberDetailsHeader) .add(memberDetails)); @@ -279,14 +280,14 @@ protected Table createSummaryTable() { List bodyRowStyles; if (threeColumnSummary()) { - bodyRowStyles = Arrays.asList(HtmlStyle.colFirst, HtmlStyle.colConstructorName, - HtmlStyle.colLast); + bodyRowStyles = Arrays.asList(HtmlStyles.colFirst, HtmlStyles.colConstructorName, + HtmlStyles.colLast); } else { - bodyRowStyles = Arrays.asList(HtmlStyle.colConstructorName, HtmlStyle.colLast); + bodyRowStyles = Arrays.asList(HtmlStyles.colConstructorName, HtmlStyles.colLast); } return new Table( - HtmlStyle.summaryTable) + HtmlStyles.summaryTable) .setCaption(contents.constructors) .setHeader(getSummaryTableHeader(typeElement)) .setColumnStyles(bodyRowStyles); @@ -299,7 +300,7 @@ public void addInheritedSummaryLabel(TypeElement typeElement, Content content) { @Override protected void addSummaryType(Element member, Content content) { if (threeColumnSummary()) { - var code = new HtmlTree(TagName.CODE); + var code = new HtmlTree(HtmlTag.CODE); if (utils.isProtected(member)) { code.add("protected "); } else if (utils.isPrivate(member)) { 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 3afccd55ba1a4..f098a8dc8f3a2 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 @@ -31,11 +31,12 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; -import jdk.javadoc.internal.doclets.formats.html.markup.Entity; -import jdk.javadoc.internal.doclets.formats.html.markup.Text; import jdk.javadoc.internal.doclets.toolkit.Resources; import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable; +import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.ContentBuilder; +import jdk.javadoc.internal.html.Entity; +import jdk.javadoc.internal.html.Text; /** diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/DeprecatedListWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/DeprecatedListWriter.java index 684e198ef1b75..3f58ef90ad50a 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/DeprecatedListWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/DeprecatedListWriter.java @@ -32,11 +32,13 @@ import com.sun.source.doctree.DeprecatedTree; import jdk.javadoc.internal.doclets.formats.html.Navigation.PageMode; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; -import jdk.javadoc.internal.doclets.formats.html.markup.Text; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyles; import jdk.javadoc.internal.doclets.toolkit.util.DeprecatedAPIListBuilder; import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; +import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.HtmlStyle; +import jdk.javadoc.internal.html.HtmlTree; +import jdk.javadoc.internal.html.Text; /** * Generate File to list all the deprecated classes and class members with the @@ -79,7 +81,7 @@ protected String getTitleKey() { protected void addContentSelectors(Content target) { List releases = builder.releases; if (releases.size() > 1) { - Content tabs = HtmlTree.DIV(HtmlStyle.checkboxes, contents.getContent( + Content tabs = HtmlTree.DIV(HtmlStyles.checkboxes, contents.getContent( "doclet.Deprecated_API_Checkbox_Label")); // Table column ids are 1-based int index = 1; @@ -125,7 +127,7 @@ protected void addComments(Element e, Content desc) { protected void addTableTabs(Table table, String headingKey) { List releases = builder.releases; if (!releases.isEmpty()) { - table.setGridStyle(HtmlStyle.threeColumnReleaseSummary); + table.setGridStyle(HtmlStyles.threeColumnReleaseSummary); } if (releases.size() > 1) { table.setDefaultTab(getTableCaption(headingKey)) @@ -170,7 +172,7 @@ protected HtmlStyle[] getColumnStyles() { if (releases.isEmpty()) { return super.getColumnStyles(); } - return new HtmlStyle[]{ HtmlStyle.colSummaryItemName, HtmlStyle.colSecond, HtmlStyle.colLast }; + return new HtmlStyle[]{ HtmlStyles.colSummaryItemName, HtmlStyles.colSecond, HtmlStyles.colLast }; } @Override diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/DocFilesHandler.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/DocFilesHandler.java index cd2633d004d91..5b39b08c22b9f 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/DocFilesHandler.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/DocFilesHandler.java @@ -25,12 +25,23 @@ package jdk.javadoc.internal.doclets.formats.html; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.List; + +import javax.lang.model.element.Element; +import javax.lang.model.element.ModuleElement; +import javax.lang.model.element.PackageElement; +import javax.tools.JavaFileManager.Location; + import com.sun.source.doctree.DocTree; import com.sun.source.doctree.EndElementTree; import com.sun.source.doctree.StartElementTree; import com.sun.source.util.DocTreeFactory; + +import jdk.javadoc.internal.doclets.formats.html.Navigation.PageMode; import jdk.javadoc.internal.doclets.formats.html.markup.BodyContents; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; import jdk.javadoc.internal.doclets.toolkit.DocFileElement; import jdk.javadoc.internal.doclets.toolkit.DocletException; import jdk.javadoc.internal.doclets.toolkit.util.DocFile; @@ -38,19 +49,9 @@ import jdk.javadoc.internal.doclets.toolkit.util.DocPath; import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; import jdk.javadoc.internal.doclets.toolkit.util.Utils; -import jdk.javadoc.internal.doclint.HtmlTag; - -import javax.lang.model.element.Element; -import javax.lang.model.element.ModuleElement; -import javax.lang.model.element.PackageElement; -import javax.tools.JavaFileManager.Location; - -import java.net.URI; -import java.net.URISyntaxException; -import java.util.ArrayList; -import java.util.List; - -import jdk.javadoc.internal.doclets.formats.html.Navigation.PageMode; +import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.HtmlTag; +import jdk.javadoc.internal.html.HtmlTree; /** * A class to handle any files, including HTML files, found in the {@code doc-files} @@ -249,7 +250,7 @@ private List getLocalHeaderTags(List dtree switch (dt.getKind()) { case START_ELEMENT: StartElementTree startElem = (StartElementTree)dt; - switch (HtmlTag.get(startElem.getName())) { + switch (HtmlTag.of(startElem.getName())) { case HEAD: inHead = true; break; @@ -267,7 +268,7 @@ private List getLocalHeaderTags(List dtree break; case END_ELEMENT: EndElementTree endElem = (EndElementTree)dt; - switch (HtmlTag.get(endElem.getName())) { + switch (HtmlTag.of(endElem.getName())) { case HEAD: inHead = false; break loop; diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/EnumConstantWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/EnumConstantWriter.java index d60fd355027cb..ff82b95fe4d8a 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/EnumConstantWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/EnumConstantWriter.java @@ -29,12 +29,13 @@ import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; -import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; -import jdk.javadoc.internal.doclets.formats.html.markup.Text; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyles; import jdk.javadoc.internal.doclets.toolkit.BaseOptions; import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable; +import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.ContentBuilder; +import jdk.javadoc.internal.html.HtmlTree; +import jdk.javadoc.internal.html.Text; /** * Writes enum constant documentation in HTML format. @@ -75,7 +76,7 @@ protected void buildEnumConstant(Content target) { for (Element enumConstant : enumConstants) { currentElement = (VariableElement)enumConstant; Content enumConstantContent = getEnumConstantsHeader(currentElement); - Content div = HtmlTree.DIV(HtmlStyle.horizontalScroll); + Content div = HtmlTree.DIV(HtmlStyles.horizontalScroll); buildSignature(div); buildDeprecationInfo(div); buildPreviewInfo(div); @@ -138,7 +139,7 @@ public Content getMemberSummaryHeader(Content content) { @Override public void buildSummary(Content summariesList, Content content) { - writer.addSummary(HtmlStyle.constantsSummary, + writer.addSummary(HtmlStyles.constantsSummary, HtmlIds.ENUM_CONSTANT_SUMMARY, summariesList, content); } @@ -156,7 +157,7 @@ protected Content getEnumConstantsHeader(VariableElement enumConstant) { var heading = HtmlTree.HEADING(Headings.TypeDeclaration.MEMBER_HEADING, Text.of(name(enumConstant))); enumConstantsContent.add(heading); - return HtmlTree.SECTION(HtmlStyle.detail, enumConstantsContent) + return HtmlTree.SECTION(HtmlStyles.detail, enumConstantsContent) .setId(htmlIds.forMember(enumConstant)); } @@ -186,7 +187,7 @@ protected void addTags(VariableElement enumConstant, Content content) { protected Content getEnumConstantsDetails(Content memberDetailsHeader, Content content) { return writer.getDetailsListItem( - HtmlTree.SECTION(HtmlStyle.constantDetails) + HtmlTree.SECTION(HtmlStyles.constantDetails) .setId(HtmlIds.ENUM_CONSTANT_DETAIL) .add(memberDetailsHeader) .add(content)); @@ -206,10 +207,10 @@ public TableHeader getSummaryTableHeader(Element member) { @Override protected Table createSummaryTable() { - return new Table(HtmlStyle.summaryTable) + return new Table(HtmlStyles.summaryTable) .setCaption(contents.getContent("doclet.Enum_Constants")) .setHeader(getSummaryTableHeader(typeElement)) - .setColumnStyles(HtmlStyle.colFirst, HtmlStyle.colLast); + .setColumnStyles(HtmlStyles.colFirst, HtmlStyles.colLast); } @Override @@ -220,7 +221,7 @@ public void addInheritedSummaryLabel(TypeElement typeElement, Content content) { protected void addSummaryLink(HtmlLinkInfo.Kind context, TypeElement typeElement, Element member, Content content) { Content memberLink = writer.getDocLink(context, utils.getEnclosingTypeElement(member), member, - name(member), HtmlStyle.memberNameLink); + name(member), HtmlStyles.memberNameLink); var code = HtmlTree.CODE(memberLink); content.add(code); } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ExternalSpecsWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ExternalSpecsWriter.java index cd66876997cd9..0115de5558fba 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ExternalSpecsWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ExternalSpecsWriter.java @@ -49,15 +49,16 @@ import jdk.javadoc.internal.doclets.formats.html.Navigation.PageMode; import jdk.javadoc.internal.doclets.formats.html.markup.BodyContents; -import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; -import jdk.javadoc.internal.doclets.formats.html.markup.Text; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyles; import jdk.javadoc.internal.doclets.toolkit.DocFileElement; import jdk.javadoc.internal.doclets.toolkit.OverviewElement; import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException; import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; import jdk.javadoc.internal.doclets.toolkit.util.IndexItem; +import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.ContentBuilder; +import jdk.javadoc.internal.html.HtmlTree; +import jdk.javadoc.internal.html.Text; import static java.util.stream.Collectors.groupingBy; import static java.util.stream.Collectors.toList; @@ -103,7 +104,7 @@ public void buildPage() throws DocFileIOException { addExternalSpecs(mainContent); body.add(new BodyContents() .setHeader(getHeader(PageMode.EXTERNAL_SPECS)) - .addMainContent(HtmlTree.DIV(HtmlStyle.header, + .addMainContent(HtmlTree.DIV(HtmlStyles.header, HtmlTree.HEADING(Headings.PAGE_TITLE_HEADING, contents.getContent("doclet.External_Specifications")))) .addMainContent(mainContent) @@ -192,10 +193,10 @@ protected void addExternalSpecs(Content content) { } var hostNamesList = new ArrayList<>(hostNamesSet); - var table = new Table(HtmlStyle.summaryTable) + var table = new Table(HtmlStyles.summaryTable) .setCaption(contents.externalSpecifications) .setHeader(new TableHeader(contents.specificationLabel, contents.referencedIn)) - .setColumnStyles(HtmlStyle.colFirst, HtmlStyle.colLast) + .setColumnStyles(HtmlStyles.colFirst, HtmlStyles.colLast) .setId(HtmlIds.EXTERNAL_SPECS); if ((hostNamesList.size() + (noHost ? 1 : 0)) > 1) { for (var host : hostNamesList) { @@ -211,7 +212,7 @@ protected void addExternalSpecs(Content content) { for (List searchIndexItems : searchIndexMap.values()) { IndexItem ii = searchIndexItems.get(0); Content specName = createSpecLink(ii); - Content referencesList = HtmlTree.UL(HtmlStyle.refList, searchIndexItems, + Content referencesList = HtmlTree.UL(HtmlStyles.refList, searchIndexItems, item -> HtmlTree.LI(createLink(item))); Content references = searchIndexItems.size() < USE_DETAILS_THRESHHOLD ? referencesList diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/FieldWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/FieldWriter.java index c72521b73b288..213078712ebf0 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/FieldWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/FieldWriter.java @@ -32,13 +32,15 @@ import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; -import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; -import jdk.javadoc.internal.doclets.formats.html.markup.Entity; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; -import jdk.javadoc.internal.doclets.formats.html.markup.Text; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyles; import jdk.javadoc.internal.doclets.toolkit.BaseOptions; import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable; +import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.ContentBuilder; +import jdk.javadoc.internal.html.Entity; +import jdk.javadoc.internal.html.HtmlStyle; +import jdk.javadoc.internal.html.HtmlTree; +import jdk.javadoc.internal.html.Text; /** * Writes field documentation in HTML format. @@ -85,7 +87,7 @@ protected void buildFieldDoc(Content target) { for (Element element : fields) { currentElement = (VariableElement)element; Content fieldContent = getFieldHeaderContent(currentElement); - Content div = HtmlTree.DIV(HtmlStyle.horizontalScroll); + Content div = HtmlTree.DIV(HtmlStyles.horizontalScroll); buildSignature(div); buildDeprecationInfo(div); buildPreviewInfo(div); @@ -147,7 +149,7 @@ public Content getMemberSummaryHeader(Content content) { @Override public void buildSummary(Content summariesList, Content content) { - writer.addSummary(HtmlStyle.fieldSummary, + writer.addSummary(HtmlStyles.fieldSummary, HtmlIds.FIELD_SUMMARY, summariesList, content); } @@ -165,7 +167,7 @@ protected Content getFieldHeaderContent(VariableElement field) { var heading = HtmlTree.HEADING(Headings.TypeDeclaration.MEMBER_HEADING, Text.of(name(field))); content.add(heading); - return HtmlTree.SECTION(HtmlStyle.detail, content) + return HtmlTree.SECTION(HtmlStyles.detail, content) .setId(htmlIds.forMember(field)); } @@ -196,7 +198,7 @@ protected void addTags(VariableElement field, Content fieldContent) { protected Content getFieldDetails(Content memberDetailsHeaderContent, Content memberContent) { return writer.getDetailsListItem( - HtmlTree.SECTION(HtmlStyle.fieldDetails) + HtmlTree.SECTION(HtmlStyles.fieldDetails) .setId(HtmlIds.FIELD_DETAIL) .add(memberDetailsHeaderContent) .add(memberContent)); @@ -217,10 +219,10 @@ public TableHeader getSummaryTableHeader(Element member) { @Override protected Table createSummaryTable() { - List bodyRowStyles = Arrays.asList(HtmlStyle.colFirst, HtmlStyle.colSecond, - HtmlStyle.colLast); + List bodyRowStyles = Arrays.asList(HtmlStyles.colFirst, HtmlStyles.colSecond, + HtmlStyles.colLast); - return new Table(HtmlStyle.summaryTable) + return new Table(HtmlStyles.summaryTable) .setCaption(contents.fields) .setHeader(getSummaryTableHeader(typeElement)) .setColumnStyles(bodyRowStyles); @@ -252,7 +254,7 @@ public void addInheritedSummaryLabel(TypeElement typeElement, Content content) { protected void addSummaryLink(HtmlLinkInfo.Kind context, TypeElement typeElement, Element member, Content content) { Content memberLink = writer.getDocLink(context, typeElement , member, name(member), - HtmlStyle.memberNameLink); + HtmlStyles.memberNameLink); var code = HtmlTree.CODE(memberLink); content.add(code); } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Headings.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Headings.java index 84b2fda4da413..2dadfe3cfa67a 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Headings.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Headings.java @@ -25,7 +25,7 @@ package jdk.javadoc.internal.doclets.formats.html; -import jdk.javadoc.internal.doclets.formats.html.markup.TagName; +import jdk.javadoc.internal.html.HtmlTag; /** * Aliases for HTML heading tags (H1..H6) for different kinds of pages. @@ -34,25 +34,25 @@ class Headings { /** * Standard top-level heading for the page title for all pages. */ - static final TagName PAGE_TITLE_HEADING = TagName.H1; + static final HtmlTag PAGE_TITLE_HEADING = HtmlTag.H1; /** * Standard second-level heading for sundry pages that do * not have their own page group. */ - static final TagName CONTENT_HEADING = TagName.H2; + static final HtmlTag CONTENT_HEADING = HtmlTag.H2; /** * Standard third-level heading for sundry pages that do * not have their own page group. */ - static final TagName SUB_HEADING = TagName.H3; + static final HtmlTag SUB_HEADING = HtmlTag.H3; /** * Headings for the page for a module declaration. */ static class ModuleDeclaration { - static final TagName SUMMARY_HEADING = TagName.H2; + static final HtmlTag SUMMARY_HEADING = HtmlTag.H2; } /** @@ -64,31 +64,31 @@ static class TypeDeclaration { * Heading for the different summary lists: * Field Summary, Constructor Summary, Method Summary, etc. */ - static final TagName SUMMARY_HEADING = TagName.H2; + static final HtmlTag SUMMARY_HEADING = HtmlTag.H2; /** * Subheading within a summary for the inherited elements: * inherited methods, etc */ - static final TagName INHERITED_SUMMARY_HEADING = TagName.H3; + static final HtmlTag INHERITED_SUMMARY_HEADING = HtmlTag.H3; /** * Heading for the different detail lists: * Field Details, Constructor Details, Method Details, etc. */ - static final TagName DETAILS_HEADING = TagName.H2; + static final HtmlTag DETAILS_HEADING = HtmlTag.H2; /** * Subheading with a Details list for an individual element. */ - static final TagName MEMBER_HEADING = TagName.H3; + static final HtmlTag MEMBER_HEADING = HtmlTag.H3; } /** * Headings for the Constants Summary page. */ static class ConstantsSummary { - static final TagName PACKAGE_HEADING = TagName.H2; + static final HtmlTag PACKAGE_HEADING = HtmlTag.H2; } /** @@ -98,28 +98,28 @@ static class SerializedForm { /** * Heading for the package name, preceding a list of types. */ - static final TagName PACKAGE_HEADING = TagName.H2; + static final HtmlTag PACKAGE_HEADING = HtmlTag.H2; /** * Heading for a type name within a package. */ - static final TagName CLASS_HEADING = TagName.H3; + static final HtmlTag CLASS_HEADING = HtmlTag.H3; /** * Subheading for info within a type. */ - static final TagName CLASS_SUBHEADING = TagName.H4; + static final HtmlTag CLASS_SUBHEADING = HtmlTag.H4; /** * Heading for an individual member element within a type. */ - static final TagName MEMBER_HEADING = TagName.H5; + static final HtmlTag MEMBER_HEADING = HtmlTag.H5; } /** * Headings for a type Use page. */ static class TypeUse { - static final TagName SUMMARY_HEADING = TagName.H2; + static final HtmlTag SUMMARY_HEADING = HtmlTag.H2; } } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HelpWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HelpWriter.java index 1f396d49eeda0..22e778d39868f 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HelpWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HelpWriter.java @@ -27,17 +27,18 @@ import java.util.List; -import jdk.javadoc.internal.doclets.formats.html.markup.BodyContents; -import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlId; -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.formats.html.markup.BodyContents; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyles; import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException; import jdk.javadoc.internal.doclets.toolkit.util.DocPath; import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; +import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.ContentBuilder; +import jdk.javadoc.internal.html.HtmlId; +import jdk.javadoc.internal.html.HtmlTag; +import jdk.javadoc.internal.html.HtmlTree; +import jdk.javadoc.internal.html.Text; /** @@ -103,13 +104,13 @@ protected void addHelpFileContents(Content content) { var mainHeading = getContent("doclet.help.main_heading"); tableOfContents.addLink(HtmlIds.TOP_OF_PAGE, mainHeading); tableOfContents.pushNestedList(); - content.add(HtmlTree.HEADING(Headings.PAGE_TITLE_HEADING, HtmlStyle.title, mainHeading)) - .add(new HtmlTree(TagName.HR)) + content.add(HtmlTree.HEADING(Headings.PAGE_TITLE_HEADING, HtmlStyles.title, mainHeading)) + .add(new HtmlTree(HtmlTag.HR)) .add(getNavigationSection()) - .add(new HtmlTree(TagName.HR)) + .add(new HtmlTree(HtmlTag.HR)) .add(getPageKindSection()) - .add(new HtmlTree(TagName.HR)) - .add(HtmlTree.SPAN(HtmlStyle.helpFootnote, + .add(new HtmlTree(HtmlTag.HR)) + .add(HtmlTree.SPAN(HtmlStyles.helpFootnote, getContent("doclet.help.footnote"))); tableOfContents.popNestedList(); } @@ -129,7 +130,7 @@ private Content getNavigationSection() { Content content = new ContentBuilder(); Content navHeading = contents.getContent("doclet.help.navigation.head"); - var navSection = HtmlTree.DIV(HtmlStyle.subTitle) + var navSection = HtmlTree.DIV(HtmlStyles.subTitle) .add(HtmlTree.HEADING(Headings.CONTENT_HEADING, navHeading).setId(HtmlIds.HELP_NAVIGATION)) .add(contents.getContent("doclet.help.navigation.intro", overviewLink)); if (options.createIndex()) { @@ -153,7 +154,7 @@ private Content getNavigationSection() { if (options.createIndex()) { section = newHelpSection(getContent("doclet.help.search.head"), PageMode.SEARCH); var searchIntro = HtmlTree.P(getContent("doclet.help.search.intro")); - var searchExamples = HtmlTree.OL(HtmlStyle.tocList); + var searchExamples = HtmlTree.OL(HtmlStyles.tocList); for (String[] example : SEARCH_EXAMPLES) { searchExamples.add(HtmlTree.LI( getContent("doclet.help.search.example", @@ -190,7 +191,7 @@ private Content getNavigationSection() { */ private Content getPageKindSection() { Content pageKindsHeading = contents.getContent("doclet.help.page_kinds.head"); - var pageKindsSection = HtmlTree.DIV(HtmlStyle.subTitle) + var pageKindsSection = HtmlTree.DIV(HtmlStyles.subTitle) .add(HtmlTree.HEADING(Headings.CONTENT_HEADING, pageKindsHeading).setId(HtmlIds.HELP_PAGES)) .add(contents.getContent("doclet.help.page_kinds.intro")); @@ -235,7 +236,7 @@ private Content getPageKindSection() { // Class/interface Content notes = new ContentBuilder( - HtmlTree.SPAN(HtmlStyle.helpNote, getContent("doclet.help.class_interface.note")), + HtmlTree.SPAN(HtmlStyles.helpNote, getContent("doclet.help.class_interface.note")), Text.of(" "), getContent("doclet.help.class_interface.anno"), Text.of(" "), @@ -254,7 +255,7 @@ private Content getPageKindSection() { getContent("doclet.help.class_interface.implementations"), getContent("doclet.help.class_interface.declaration"), getContent("doclet.help.class_interface.description"))) - .add(new HtmlTree(TagName.BR)) + .add(new HtmlTree(HtmlTag.BR)) .add(newHelpSectionList( contents.nestedClassSummary, contents.enumConstantSummary, @@ -264,7 +265,7 @@ private Content getPageKindSection() { contents.methodSummary, contents.annotateTypeRequiredMemberSummaryLabel, contents.annotateTypeOptionalMemberSummaryLabel)) - .add(new HtmlTree(TagName.BR)) + .add(new HtmlTree(HtmlTag.BR)) .add(newHelpSectionList( contents.enumConstantDetailLabel, contents.fieldDetailsLabel, @@ -412,7 +413,7 @@ private Content getContent(String key, Object arg1, Object arg2) { private HtmlTree newHelpSection(Content headingContent, HtmlId id) { tableOfContents.addLink(id, headingContent); - return HtmlTree.SECTION(HtmlStyle.helpSection, + return HtmlTree.SECTION(HtmlStyles.helpSection, HtmlTree.HEADING(Headings.SUB_HEADING, headingContent)) .setId(id); } @@ -422,7 +423,7 @@ private HtmlTree newHelpSection(Content headingContent, Navigation.PageMode pm) } private HtmlTree newHelpSectionList(Content first, Content... rest) { - var list = HtmlTree.UL(HtmlStyle.helpSectionList, HtmlTree.LI(first)); + var list = HtmlTree.UL(HtmlStyles.helpSectionList, HtmlTree.LI(first)); List.of(rest).forEach(i -> list.add(HtmlTree.LI(i))); return list; } 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 2b8b6cfe058d4..235a0361b9233 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 @@ -94,20 +94,10 @@ import jdk.internal.org.commonmark.renderer.html.HtmlNodeRendererFactory; import jdk.internal.org.commonmark.renderer.html.HtmlRenderer; import jdk.internal.org.commonmark.renderer.html.HtmlWriter; - -import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; -import jdk.javadoc.internal.doclets.formats.html.markup.Entity; import jdk.javadoc.internal.doclets.formats.html.markup.Head; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlDocument; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlId; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyles; import jdk.javadoc.internal.doclets.formats.html.markup.Links; -import jdk.javadoc.internal.doclets.formats.html.markup.RawHtml; -import jdk.javadoc.internal.doclets.formats.html.markup.Script; -import jdk.javadoc.internal.doclets.formats.html.markup.TagName; -import jdk.javadoc.internal.doclets.formats.html.markup.Text; -import jdk.javadoc.internal.doclets.formats.html.markup.TextBuilder; import jdk.javadoc.internal.doclets.formats.html.taglets.Taglet; import jdk.javadoc.internal.doclets.formats.html.taglets.TagletWriter; import jdk.javadoc.internal.doclets.toolkit.DocFileElement; @@ -126,7 +116,17 @@ import jdk.javadoc.internal.doclets.toolkit.util.Utils.DeclarationPreviewLanguageFeatures; import jdk.javadoc.internal.doclets.toolkit.util.Utils.ElementFlag; import jdk.javadoc.internal.doclets.toolkit.util.Utils.PreviewSummary; -import jdk.javadoc.internal.doclint.HtmlTag; +import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.ContentBuilder; +import jdk.javadoc.internal.html.Entity; +import jdk.javadoc.internal.html.HtmlId; +import jdk.javadoc.internal.html.HtmlStyle; +import jdk.javadoc.internal.html.HtmlTag; +import jdk.javadoc.internal.html.HtmlTree; +import jdk.javadoc.internal.html.RawHtml; +import jdk.javadoc.internal.html.Script; +import jdk.javadoc.internal.html.Text; +import jdk.javadoc.internal.html.TextBuilder; import static com.sun.source.doctree.DocTree.Kind.COMMENT; import static com.sun.source.doctree.DocTree.Kind.START_ELEMENT; @@ -361,7 +361,7 @@ protected void addTagsInfo(Element e, Content content) { if (options.noComment()) { return; } - var dl = HtmlTree.DL(HtmlStyle.notes); + var dl = HtmlTree.DL(HtmlStyles.notes); if (utils.isMethod(e)) { addMethodInfo((ExecutableElement)e, dl); } @@ -610,7 +610,7 @@ private String getHeadingText(Content c) { var contents = cb.getContents(); if (!contents.isEmpty()) { var first = contents.get(0); - if (first instanceof HtmlTree htmlTree && htmlTree.tagName.equals(TagName.H1)) { + if (first instanceof HtmlTree htmlTree && htmlTree.tag.equals(HtmlTag.H1)) { for (var c2 : htmlTree.getContents()) { if (c2 instanceof Text t) { sb.append(t.toString()); @@ -685,8 +685,8 @@ public HtmlTree getFooter() { return (bottom == null || bottom.isEmpty()) ? null : HtmlTree.FOOTER() - .add(new HtmlTree(TagName.HR)) - .add(HtmlTree.P(HtmlStyle.legalCopy, + .add(new HtmlTree(HtmlTag.HR)) + .add(HtmlTree.P(HtmlStyles.legalCopy, HtmlTree.SMALL( RawHtml.of(replaceDocRootDir(bottom))))); } @@ -917,7 +917,7 @@ public Content getTypeParameterLinks(HtmlLinkInfo linkInfo) { * @return the link */ public Content getCrossClassLink(TypeElement classElement, String refMemName, - Content label, HtmlStyle style, boolean code) { + Content label, HtmlStyle style, boolean code) { if (classElement != null) { String className = utils.getSimpleName(classElement); PackageElement packageElement = utils.containingPackage(classElement); @@ -1047,7 +1047,7 @@ public TypeElement getCurrentPageElement() { * @param content the content to which the link with be added */ public void addPreQualifiedStrongClassLink(HtmlLinkInfo.Kind context, TypeElement typeElement, Content content) { - addPreQualifiedClassLink(context, typeElement, HtmlStyle.typeNameLink, content); + addPreQualifiedClassLink(context, typeElement, HtmlStyles.typeNameLink, content); } /** @@ -1255,10 +1255,10 @@ private void addCommentTags(Element element, List tags, boole Content result = commentTagsToContent(element, tags, first, inSummary); if (!result.isEmpty()) { if (depr) { - div = HtmlTree.DIV(HtmlStyle.deprecationComment, result); + div = HtmlTree.DIV(HtmlStyles.deprecationComment, result); target.add(div); } else { - div = HtmlTree.DIV(HtmlStyle.block, result); + div = HtmlTree.DIV(HtmlStyles.block, result); target.add(div); } } @@ -1277,7 +1277,7 @@ boolean ignoreNonInlineTag(DocTree dtree, List openTags) { } if (name != null) { - HtmlTag htmlTag = HtmlTag.get(name); + HtmlTag htmlTag = HtmlTag.of(name); if (htmlTag != null) { if (htmlTag.blockType != HtmlTag.BlockType.INLINE) { return true; @@ -1944,9 +1944,9 @@ private boolean shouldRedirectRelativeLinks(Element element) { public Content invalidTagOutput(String summary, Optional detail) { messages.setContainsDiagnosticMarkers(); if (detail.isEmpty() || detail.get().isEmpty()) { - return HtmlTree.SPAN(HtmlStyle.invalidTag, Text.of(summary)); + return HtmlTree.SPAN(HtmlStyles.invalidTag, Text.of(summary)); } - return HtmlTree.DETAILS(HtmlStyle.invalidTag) + return HtmlTree.DETAILS(HtmlStyles.invalidTag) .add(HtmlTree.SUMMARY(Text.of(summary))) .add(HtmlTree.PRE(detail.get())); } @@ -2405,7 +2405,7 @@ static String getGenerator(Class clazz) { * @return an HtmlTree for the BODY tag */ public HtmlTree getBody(String title) { - var body = new HtmlTree(TagName.BODY).setStyle(getBodyStyle()); + var body = new HtmlTree(HtmlTag.BODY).setStyle(getBodyStyle()); this.winTitle = title; // Don't print windowtitle script for overview-frame, allclasses-frame @@ -2423,7 +2423,7 @@ public HtmlStyle getBodyStyle() { .replaceAll("^(Module|Package|Class)$", "$1Declaration") .replace("API", "Api"); String page = kind.substring(0, 1).toLowerCase(Locale.US) + kind.substring(1) + "Page"; - return HtmlStyle.valueOf(page); + return HtmlStyles.valueOf(page); } /** @@ -2473,16 +2473,16 @@ private List getStylesheets(Element element) throws DocFileIOException public void addPreviewSummary(Element forWhat, Content target) { if (utils.isPreviewAPI(forWhat)) { - var div = HtmlTree.DIV(HtmlStyle.block); - div.add(HtmlTree.SPAN(HtmlStyle.previewLabel, contents.previewPhrase)); + var div = HtmlTree.DIV(HtmlStyles.block); + div.add(HtmlTree.SPAN(HtmlStyles.previewLabel, contents.previewPhrase)); target.add(div); } } public void addRestrictedSummary(Element forWhat, Content target) { if (utils.isRestrictedAPI(forWhat)) { - var div = HtmlTree.DIV(HtmlStyle.block); - div.add(HtmlTree.SPAN(HtmlStyle.restrictedLabel, contents.restrictedPhrase)); + var div = HtmlTree.DIV(HtmlStyles.block); + div.add(HtmlTree.SPAN(HtmlStyles.restrictedLabel, contents.restrictedPhrase)); target.add(div); } } @@ -2490,7 +2490,7 @@ public void addRestrictedSummary(Element forWhat, Content target) { public void addPreviewInfo(Element forWhat, Content target) { if (utils.isPreviewAPI(forWhat)) { //in Java platform: - var previewDiv = HtmlTree.DIV(HtmlStyle.previewBlock); + var previewDiv = HtmlTree.DIV(HtmlStyles.previewBlock); previewDiv.setId(htmlIds.forPreviewSection(forWhat)); String name = (switch (forWhat.getKind()) { case PACKAGE, MODULE -> @@ -2506,14 +2506,14 @@ public void addPreviewInfo(Element forWhat, Content target) { : "doclet.ReflectivePreviewPlatformLeadingNote"; Content leadingNote = contents.getContent(leadingNoteKey, nameCode); - previewDiv.add(HtmlTree.SPAN(HtmlStyle.previewLabel, + previewDiv.add(HtmlTree.SPAN(HtmlStyles.previewLabel, leadingNote)); if (!isReflectivePreview) { Content note1 = contents.getContent("doclet.PreviewTrailingNote1", nameCode); - previewDiv.add(HtmlTree.DIV(HtmlStyle.previewComment, note1)); + previewDiv.add(HtmlTree.DIV(HtmlStyles.previewComment, note1)); } Content note2 = contents.getContent("doclet.PreviewTrailingNote2", nameCode); - previewDiv.add(HtmlTree.DIV(HtmlStyle.previewComment, note2)); + previewDiv.add(HtmlTree.DIV(HtmlStyles.previewComment, note2)); target.add(previewDiv); } else if (forWhat.getKind().isClass() || forWhat.getKind().isInterface()) { //in custom code: @@ -2521,12 +2521,12 @@ public void addPreviewInfo(Element forWhat, Content target) { if (!previewNotes.isEmpty()) { Name name = forWhat.getSimpleName(); var nameCode = HtmlTree.CODE(Text.of(name)); - var previewDiv = HtmlTree.DIV(HtmlStyle.previewBlock); + var previewDiv = HtmlTree.DIV(HtmlStyles.previewBlock); previewDiv.setId(htmlIds.forPreviewSection(forWhat)); Content leadingNote = contents.getContent("doclet.PreviewLeadingNote", nameCode); - previewDiv.add(HtmlTree.SPAN(HtmlStyle.previewLabel, + previewDiv.add(HtmlTree.SPAN(HtmlStyles.previewLabel, leadingNote)); - var ul = HtmlTree.UL(HtmlStyle.previewComment); + var ul = HtmlTree.UL(HtmlStyles.previewComment); for (Content note : previewNotes) { ul.add(HtmlTree.LI(note)); } @@ -2534,11 +2534,11 @@ public void addPreviewInfo(Element forWhat, Content target) { Content note1 = contents.getContent("doclet.PreviewTrailingNote1", nameCode); - previewDiv.add(HtmlTree.DIV(HtmlStyle.previewComment, note1)); + previewDiv.add(HtmlTree.DIV(HtmlStyles.previewComment, note1)); Content note2 = contents.getContent("doclet.PreviewTrailingNote2", name); - previewDiv.add(HtmlTree.DIV(HtmlStyle.previewComment, note2)); + previewDiv.add(HtmlTree.DIV(HtmlStyles.previewComment, note2)); target.add(previewDiv); } } @@ -2601,7 +2601,7 @@ private Content withPreviewFeatures(String key, String className, String feature }); return contents.getContent(key, HtmlTree.CODE(Text.of(className)), - new HtmlTree(TagName.EM).add(featureName), + new HtmlTree(HtmlTag.EM).add(featureName), featureCodes); } @@ -2640,19 +2640,19 @@ public URI resolveExternalSpecURI(URI specURI) { public void addRestrictedInfo(ExecutableElement forWhat, Content target) { if (utils.isRestrictedAPI(forWhat)) { //in Java platform: - var restrictedDiv = HtmlTree.DIV(HtmlStyle.restrictedBlock); + var restrictedDiv = HtmlTree.DIV(HtmlStyles.restrictedBlock); restrictedDiv.setId(htmlIds.forRestrictedSection(forWhat)); String name = forWhat.getSimpleName().toString(); var nameCode = HtmlTree.CODE(Text.of(name)); String leadingNoteKey = "doclet.RestrictedLeadingNote"; Content leadingNote = contents.getContent(leadingNoteKey, nameCode); - restrictedDiv.add(HtmlTree.SPAN(HtmlStyle.restrictedLabel, + restrictedDiv.add(HtmlTree.SPAN(HtmlStyles.restrictedLabel, leadingNote)); Content note1 = contents.getContent("doclet.RestrictedTrailingNote1", nameCode); - restrictedDiv.add(HtmlTree.DIV(HtmlStyle.restrictedComment, note1)); + restrictedDiv.add(HtmlTree.DIV(HtmlStyles.restrictedComment, note1)); Content note2 = contents.getContent("doclet.RestrictedTrailingNote2", nameCode); - restrictedDiv.add(HtmlTree.DIV(HtmlStyle.restrictedComment, note2)); + restrictedDiv.add(HtmlTree.DIV(HtmlStyles.restrictedComment, note2)); target.add(restrictedDiv); } } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlIds.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlIds.java index 48edce573d3c7..1b9896fafa006 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlIds.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlIds.java @@ -33,6 +33,7 @@ import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; + import javax.lang.model.element.Element; import javax.lang.model.element.ElementKind; import javax.lang.model.element.ExecutableElement; @@ -46,10 +47,10 @@ import javax.lang.model.type.TypeVariable; import javax.lang.model.util.SimpleTypeVisitor9; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlId; import jdk.javadoc.internal.doclets.toolkit.util.SummaryAPIListBuilder; import jdk.javadoc.internal.doclets.toolkit.util.Utils; import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable; +import jdk.javadoc.internal.html.HtmlId; /** * Centralized constants and factory methods for HTML ids. diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlIndexBuilder.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlIndexBuilder.java index 51831b233361b..fcc9640126a57 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlIndexBuilder.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlIndexBuilder.java @@ -30,11 +30,11 @@ import java.util.HashMap; import java.util.Map; import java.util.SortedSet; + import javax.lang.model.element.Element; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.TypeElement; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; import jdk.javadoc.internal.doclets.toolkit.Resources; import jdk.javadoc.internal.doclets.toolkit.util.DocFile; import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException; @@ -42,6 +42,7 @@ import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; import jdk.javadoc.internal.doclets.toolkit.util.IndexBuilder; import jdk.javadoc.internal.doclets.toolkit.util.IndexItem; +import jdk.javadoc.internal.html.HtmlTree; /** * Extensions to {@code IndexBuilder} to fill in remaining fields diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlLinkFactory.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlLinkFactory.java index 87a842890a4e9..22af1e4a0244c 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlLinkFactory.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlLinkFactory.java @@ -43,17 +43,18 @@ import javax.lang.model.type.WildcardType; import javax.lang.model.util.SimpleTypeVisitor14; -import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; -import jdk.javadoc.internal.doclets.formats.html.markup.Entity; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; -import jdk.javadoc.internal.doclets.formats.html.markup.TagName; -import jdk.javadoc.internal.doclets.formats.html.markup.Text; import jdk.javadoc.internal.doclets.toolkit.BaseConfiguration; import jdk.javadoc.internal.doclets.toolkit.Resources; import jdk.javadoc.internal.doclets.toolkit.util.DocPath; import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; import jdk.javadoc.internal.doclets.toolkit.util.Utils; import jdk.javadoc.internal.doclets.toolkit.util.Utils.ElementFlag; +import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.ContentBuilder; +import jdk.javadoc.internal.html.Entity; +import jdk.javadoc.internal.html.HtmlTag; +import jdk.javadoc.internal.html.HtmlTree; +import jdk.javadoc.internal.html.Text; /** * A factory that returns a link given the information about it. @@ -377,14 +378,14 @@ protected Content getTypeParameterLinks(HtmlLinkInfo linkInfo) { } if (!vars.isEmpty()) { if (linkInfo.addLineBreakOpportunitiesInTypeParameters()) { - links.add(new HtmlTree(TagName.WBR)); + links.add(new HtmlTree(HtmlTag.WBR)); } links.add("<"); boolean many = false; for (TypeMirror t : vars) { if (many) { links.add(","); - links.add(new HtmlTree(TagName.WBR)); + links.add(new HtmlTree(HtmlTag.WBR)); if (linkInfo.addLineBreaksInTypeParameters()) { links.add(Text.NL); } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlLinkInfo.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlLinkInfo.java index c2c79e850b846..0b7be8fe6562a 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlLinkInfo.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlLinkInfo.java @@ -31,11 +31,13 @@ import javax.lang.model.type.DeclaredType; import javax.lang.model.type.TypeMirror; -import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; -import jdk.javadoc.internal.doclets.formats.html.markup.Text; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyles; import jdk.javadoc.internal.doclets.toolkit.BaseConfiguration; import jdk.javadoc.internal.doclets.toolkit.util.Utils; +import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.ContentBuilder; +import jdk.javadoc.internal.html.HtmlStyle; +import jdk.javadoc.internal.html.Text; /** diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/IndexRedirectWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/IndexRedirectWriter.java index e4543471a69bc..e449ecebf40a2 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/IndexRedirectWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/IndexRedirectWriter.java @@ -29,18 +29,18 @@ import java.util.Objects; import jdk.javadoc.internal.doclets.formats.html.markup.Head; -import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlAttr; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlDocument; -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.markup.Script; -import jdk.javadoc.internal.doclets.formats.html.markup.Text; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyles; import jdk.javadoc.internal.doclets.toolkit.util.DocFile; import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException; import jdk.javadoc.internal.doclets.toolkit.util.DocPath; import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; +import jdk.javadoc.internal.html.ContentBuilder; +import jdk.javadoc.internal.html.HtmlAttr; +import jdk.javadoc.internal.html.HtmlTag; +import jdk.javadoc.internal.html.HtmlTree; +import jdk.javadoc.internal.html.Script; +import jdk.javadoc.internal.html.Text; /** * Writes a file that tries to redirect to an alternate page. @@ -92,7 +92,7 @@ public void buildPage() throws DocFileIOException { Script script = new Script("window.location.replace(") .appendStringLiteral(targetPath, '\'') .append(")"); - var metaRefresh = new HtmlTree(TagName.META) + var metaRefresh = new HtmlTree(HtmlTag.META) .put(HtmlAttr.HTTP_EQUIV, "Refresh") .put(HtmlAttr.CONTENT, "0;" + targetPath); head.addContent(script.asContent(), HtmlTree.NOSCRIPT(metaRefresh)); @@ -103,7 +103,7 @@ public void buildPage() throws DocFileIOException { bodyContent.add(HtmlTree.P(HtmlTree.A(targetPath, Text.of(targetPath)))); - var body = new HtmlTree(TagName.BODY).setStyle(HtmlStyle.indexRedirectPage); + var body = new HtmlTree(HtmlTag.BODY).setStyle(HtmlStyles.indexRedirectPage); var main = HtmlTree.MAIN(bodyContent); body.add(main); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/IndexWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/IndexWriter.java index ff2761b8ecb9f..ecf1114364217 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/IndexWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/IndexWriter.java @@ -36,22 +36,21 @@ import javax.lang.model.element.PackageElement; import javax.lang.model.element.TypeElement; -import com.sun.source.doctree.DeprecatedTree; - -import jdk.javadoc.internal.doclets.formats.html.markup.BodyContents; -import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; -import jdk.javadoc.internal.doclets.formats.html.markup.Entity; -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.formats.html.markup.BodyContents; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyles; import jdk.javadoc.internal.doclets.toolkit.DocletException; import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException; import jdk.javadoc.internal.doclets.toolkit.util.DocPath; import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; import jdk.javadoc.internal.doclets.toolkit.util.IndexBuilder; import jdk.javadoc.internal.doclets.toolkit.util.IndexItem; +import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.ContentBuilder; +import jdk.javadoc.internal.html.Entity; +import jdk.javadoc.internal.html.HtmlTag; +import jdk.javadoc.internal.html.HtmlTree; +import jdk.javadoc.internal.html.Text; /** * Generator for either a single index or split index for all @@ -129,7 +128,7 @@ public void buildPage() throws DocFileIOException { addLinksForIndexes(allFirstCharacters, mainContent); body.add(new BodyContents() .setHeader(getHeader(PageMode.INDEX)) - .addMainContent(HtmlTree.DIV(HtmlStyle.header, + .addMainContent(HtmlTree.DIV(HtmlStyles.header, HtmlTree.HEADING(Headings.PAGE_TITLE_HEADING, contents.getContent("doclet.Index")))) .addMainContent(mainContent) @@ -149,7 +148,7 @@ public void buildPage() throws DocFileIOException { protected void addContents(char ch, SortedSet items, Content content) { addHeading(ch, content); - var dl = HtmlTree.DL(HtmlStyle.index); + var dl = HtmlTree.DL(HtmlStyles.index); for (IndexItem item : items) { addDescription(item, dl); } @@ -164,7 +163,7 @@ protected void addContents(char ch, SortedSet items, Content content) */ protected void addHeading(char ch, Content content) { Content headContent = Text.of(String.valueOf(ch)); - var heading = HtmlTree.HEADING(Headings.CONTENT_HEADING, HtmlStyle.title, headContent) + var heading = HtmlTree.HEADING(Headings.CONTENT_HEADING, HtmlStyles.title, headContent) .setId(HtmlIds.forIndexChar(ch)); content.add(heading); } @@ -209,7 +208,7 @@ protected void addElementDescription(IndexItem item, Content target) { case CLASS, ENUM, RECORD, ANNOTATION_TYPE, INTERFACE -> { dt = HtmlTree.DT(getLink(new HtmlLinkInfo(configuration, - HtmlLinkInfo.Kind.SHOW_TYPE_PARAMS_IN_LABEL, (TypeElement) element).style(HtmlStyle.typeNameLink))); + HtmlLinkInfo.Kind.SHOW_TYPE_PARAMS_IN_LABEL, (TypeElement) element).style(HtmlStyles.typeNameLink))); dt.add(" - "); addClassInfo((TypeElement) element, dt); } @@ -217,7 +216,7 @@ protected void addElementDescription(IndexItem item, Content target) { case CONSTRUCTOR, METHOD, FIELD, ENUM_CONSTANT -> { TypeElement containingType = item.getContainingTypeElement(); dt = HtmlTree.DT(getDocLink(HtmlLinkInfo.Kind.PLAIN, containingType, element, - label, HtmlStyle.memberNameLink)); + label, HtmlStyles.memberNameLink)); dt.add(" - "); addMemberDesc(element, containingType, dt); } @@ -225,7 +224,7 @@ protected void addElementDescription(IndexItem item, Content target) { default -> throw new Error(); } target.add(dt); - var dd = new HtmlTree(TagName.DD); + var dd = new HtmlTree(HtmlTag.DD); if (element.getKind() == ElementKind.MODULE || element.getKind() == ElementKind.PACKAGE) { addSummaryComment(element, dd); } else { @@ -258,11 +257,11 @@ protected void addTagDescription(IndexItem item, Content target) { String itemPath = pathToRoot.isEmpty() ? "" : pathToRoot.getPath() + "/"; itemPath += item.getUrl(); var labelLink = HtmlTree.A(itemPath, Text.of(item.getLabel())); - var dt = HtmlTree.DT(labelLink.setStyle(HtmlStyle.searchTagLink)); + var dt = HtmlTree.DT(labelLink.setStyle(HtmlStyles.searchTagLink)); dt.add(" - "); dt.add(contents.getContent("doclet.Search_tag_in", item.getHolder())); target.add(dt); - var dd = new HtmlTree(TagName.DD); + var dd = new HtmlTree(HtmlTag.DD); if (item.getDescription().isEmpty()) { dd.add(Entity.NO_BREAK_SPACE); } else { @@ -281,8 +280,8 @@ protected void addTagDescription(IndexItem item, Content target) { * @param content the content to which the comment will be added */ protected void addComment(Element element, Content content) { - var span = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(element)); - var div = HtmlTree.DIV(HtmlStyle.deprecationBlock); + var span = HtmlTree.SPAN(HtmlStyles.deprecatedLabel, getDeprecatedPhrase(element)); + var div = HtmlTree.DIV(HtmlStyles.deprecationBlock); if (utils.isDeprecated(element)) { div.add(span); var tags = utils.getDeprecatedTrees(element); @@ -349,7 +348,7 @@ protected void addLinksForIndexes(List allFirstCharacters, Content co content.add(Entity.NO_BREAK_SPACE); } - content.add(new HtmlTree(TagName.BR)); + content.add(new HtmlTree(HtmlTag.BR)); var pageLinks = Stream.of(IndexItem.Category.values()) .flatMap(c -> mainIndex.getItems(c).stream()) .filter(i -> !(i.isElementItem() || i.isTagItem())) @@ -361,6 +360,6 @@ protected void addLinksForIndexes(List allFirstCharacters, Content co } private Content getVerticalSeparator() { - return HtmlTree.SPAN(HtmlStyle.verticalSeparator, Text.of("|")); + return HtmlTree.SPAN(HtmlStyles.verticalSeparator, Text.of("|")); } } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/MarkerComments.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/MarkerComments.java index 04888d7cc2f0f..78696cc320ea2 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/MarkerComments.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/MarkerComments.java @@ -25,7 +25,7 @@ package jdk.javadoc.internal.doclets.formats.html; -import jdk.javadoc.internal.doclets.formats.html.markup.Comment; +import jdk.javadoc.internal.html.Comment; /** * Marker comments to identify regions in the generated files. diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/MethodWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/MethodWriter.java index 521616f982b52..9325bc07a6d99 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/MethodWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/MethodWriter.java @@ -35,16 +35,16 @@ import javax.lang.model.element.TypeElement; import javax.lang.model.type.TypeMirror; -import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; -import jdk.javadoc.internal.doclets.formats.html.markup.Entity; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlId; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; -import jdk.javadoc.internal.doclets.formats.html.markup.Text; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyles; import jdk.javadoc.internal.doclets.toolkit.BaseOptions; import jdk.javadoc.internal.doclets.toolkit.util.DocFinder; import jdk.javadoc.internal.doclets.toolkit.util.Utils; import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable; +import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.ContentBuilder; +import jdk.javadoc.internal.html.Entity; +import jdk.javadoc.internal.html.HtmlTree; +import jdk.javadoc.internal.html.Text; /** * Writes method documentation in HTML format. @@ -107,7 +107,7 @@ protected void buildMethodDoc(Content detailsList) { for (Element method : methods) { currentMethod = (ExecutableElement)method; Content methodContent = getMethodHeader(currentMethod); - Content div = HtmlTree.DIV(HtmlStyle.horizontalScroll); + Content div = HtmlTree.DIV(HtmlStyles.horizontalScroll); buildSignature(div); buildDeprecationInfo(div); buildPreviewInfo(div); @@ -187,7 +187,7 @@ public Content getMemberSummaryHeader(Content target) { @Override public void buildSummary(Content summariesList, Content content) { - writer.addSummary(HtmlStyle.methodSummary, + writer.addSummary(HtmlStyles.methodSummary, HtmlIds.METHOD_SUMMARY, summariesList, content); } @@ -209,7 +209,7 @@ protected Content getMethodHeader(ExecutableElement method) { heading.setId(anchors.getLast()); } content.add(heading); - return HtmlTree.SECTION(HtmlStyle.detail, content) + return HtmlTree.SECTION(HtmlStyles.detail, content) .setId(anchors.getFirst()); } @@ -251,13 +251,13 @@ protected void addComments(TypeMirror holderType, ExecutableElement method, Cont ? utils.getSimpleName(holder) : utils.getFullyQualifiedName(holder)); var codeLink = HtmlTree.CODE(link); - var descriptionFromTypeLabel = HtmlTree.SPAN(HtmlStyle.descriptionFromTypeLabel, + var descriptionFromTypeLabel = HtmlTree.SPAN(HtmlStyles.descriptionFromTypeLabel, utils.isClass(holder) ? contents.descriptionFromClassLabel : contents.descriptionFromInterfaceLabel); descriptionFromTypeLabel.add(Entity.NO_BREAK_SPACE); descriptionFromTypeLabel.add(codeLink); - methodContent.add(HtmlTree.DIV(HtmlStyle.block, descriptionFromTypeLabel)); + methodContent.add(HtmlTree.DIV(HtmlStyles.block, descriptionFromTypeLabel)); } writer.addInlineComment(method, methodContent); } @@ -270,7 +270,7 @@ protected void addTags(ExecutableElement method, Content methodContent) { protected Content getMethodDetails(Content methodDetailsHeader, Content methodDetails) { Content c = new ContentBuilder(methodDetailsHeader, methodDetails); - return getMember(HtmlTree.SECTION(HtmlStyle.methodDetails, c) + return getMember(HtmlTree.SECTION(HtmlStyles.methodDetails, c) .setId(HtmlIds.METHOD_DETAIL)); } @@ -289,9 +289,9 @@ public TableHeader getSummaryTableHeader(Element member) { @Override protected Table createSummaryTable() { - return new Table(HtmlStyle.summaryTable) + return new Table(HtmlStyles.summaryTable) .setHeader(getSummaryTableHeader(typeElement)) - .setColumnStyles(HtmlStyle.colFirst, HtmlStyle.colSecond, HtmlStyle.colLast) + .setColumnStyles(HtmlStyles.colFirst, HtmlStyles.colSecond, HtmlStyles.colLast) .setId(HtmlIds.METHOD_SUMMARY_TABLE) .setDefaultTab(contents.getContent("doclet.All_Methods")) .addTab(contents.getContent("doclet.Static_Methods"), utils::isStatic) diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModuleIndexWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModuleIndexWriter.java index abe6159d1af8e..86e81b77ddd76 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModuleIndexWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModuleIndexWriter.java @@ -31,10 +31,11 @@ import javax.lang.model.element.ModuleElement; -import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; -import jdk.javadoc.internal.doclets.formats.html.markup.Text; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyles; import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; +import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.ContentBuilder; +import jdk.javadoc.internal.html.Text; /** * Generate the module index page "index.html". @@ -78,9 +79,9 @@ protected void addIndex(Content target) { if (!groupModuleMap.keySet().isEmpty()) { TableHeader tableHeader = new TableHeader(contents.moduleLabel, contents.descriptionLabel); - var table = new Table(HtmlStyle.summaryTable) + var table = new Table(HtmlStyles.summaryTable) .setHeader(tableHeader) - .setColumnStyles(HtmlStyle.colFirst, HtmlStyle.colLast) + .setColumnStyles(HtmlStyles.colFirst, HtmlStyles.colLast) .setId(HtmlIds.ALL_MODULES_TABLE) .setDefaultTab(contents.getContent("doclet.All_Modules")); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModuleWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModuleWriter.java index d2f2206d27fd7..bd0ab2958d4e0 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModuleWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModuleWriter.java @@ -41,18 +41,21 @@ import com.sun.source.doctree.DeprecatedTree; import com.sun.source.doctree.DocTree; + import jdk.javadoc.doclet.DocletEnvironment.ModuleMode; -import jdk.javadoc.internal.doclets.formats.html.markup.BodyContents; -import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; -import jdk.javadoc.internal.doclets.formats.html.markup.Entity; -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.formats.html.markup.BodyContents; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyles; import jdk.javadoc.internal.doclets.toolkit.DocletException; import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper; import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException; +import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.ContentBuilder; +import jdk.javadoc.internal.html.Entity; +import jdk.javadoc.internal.html.HtmlStyle; +import jdk.javadoc.internal.html.HtmlTag; +import jdk.javadoc.internal.html.HtmlTree; +import jdk.javadoc.internal.html.Text; /** * Class to generate file for each module contents in the right-hand frame. This will list all the @@ -191,8 +194,8 @@ protected void buildModuleDoc() throws DocletException { */ protected void buildContent() { Content moduleContent = getContentHeader(); - moduleContent.add(new HtmlTree(TagName.HR)); - Content div = HtmlTree.DIV(HtmlStyle.horizontalScroll); + moduleContent.add(new HtmlTree(HtmlTag.HR)); + Content div = HtmlTree.DIV(HtmlStyles.horizontalScroll); addModuleSignature(div); buildModuleDescription(div); moduleContent.add(div); @@ -261,13 +264,13 @@ protected void buildModuleDescription(Content moduleContent) { protected Content getModuleHeader(String heading) { HtmlTree body = getBody(getWindowTitle(mdle.getQualifiedName().toString())); - var div = HtmlTree.DIV(HtmlStyle.header); + var div = HtmlTree.DIV(HtmlStyles.header); Content moduleHead = new ContentBuilder(); moduleHead.add(mdle.isOpen() && (configuration.docEnv.getModuleMode() == ModuleMode.ALL) ? contents.openModuleLabel : contents.moduleLabel); moduleHead.add(" ").add(heading); var tHeading = HtmlTree.HEADING_TITLE(Headings.PAGE_TITLE_HEADING, - HtmlStyle.title, moduleHead); + HtmlStyles.title, moduleHead); div.add(tHeading); bodyContents.setHeader(getHeader(PageMode.MODULE, mdle)) .addMainContent(div); @@ -279,11 +282,11 @@ protected Content getContentHeader() { } protected Content getSummariesList() { - return HtmlTree.UL(HtmlStyle.summaryList); + return HtmlTree.UL(HtmlStyles.summaryList); } protected Content getSummary(Content source) { - return HtmlTree.SECTION(HtmlStyle.summary, source); + return HtmlTree.SECTION(HtmlStyles.summary, source); } /** @@ -502,10 +505,10 @@ public void addSummaryHeader(Content startMarker, Content heading, * @return a content object */ private Table getTable2(Content caption, TableHeader tableHeader) { - return new Table(HtmlStyle.detailsTable) + return new Table(HtmlStyles.detailsTable) .setCaption(caption) .setHeader(tableHeader) - .setColumnStyles(HtmlStyle.colFirst, HtmlStyle.colLast); + .setColumnStyles(HtmlStyles.colFirst, HtmlStyles.colLast); } /** @@ -516,10 +519,10 @@ private Table getTable2(Content caption, TableHeader tableHeader) { * @return a content object */ private Table getTable3(Content caption, TableHeader tableHeader) { - return new Table(HtmlStyle.detailsTable) + return new Table(HtmlStyles.detailsTable) .setCaption(caption) .setHeader(tableHeader) - .setColumnStyles(HtmlStyle.colFirst, HtmlStyle.colSecond, HtmlStyle.colLast); + .setColumnStyles(HtmlStyles.colFirst, HtmlStyles.colSecond, HtmlStyles.colLast); } protected void addModulesSummary(Content summariesList) { @@ -528,7 +531,7 @@ protected void addModulesSummary(Content summariesList) { TableHeader requiresTableHeader = new TableHeader(contents.modifierLabel, contents.moduleLabel, contents.descriptionLabel); - var section = HtmlTree.SECTION(HtmlStyle.modulesSummary) + var section = HtmlTree.SECTION(HtmlStyles.modulesSummary) .setId(HtmlIds.MODULES); addSummaryHeader(MarkerComments.START_OF_MODULES_SUMMARY, contents.navModules, section); if (display(requires)) { @@ -570,7 +573,7 @@ protected void addPackagesSummary(Content summariesList) { if (display(packages) || display(indirectPackages) || display(indirectOpenPackages)) { tableOfContents.addLink(HtmlIds.PACKAGES, contents.navPackages); - var section = HtmlTree.SECTION(HtmlStyle.packagesSummary) + var section = HtmlTree.SECTION(HtmlStyles.packagesSummary) .setId(HtmlIds.PACKAGES); addSummaryHeader(MarkerComments.START_OF_PACKAGES_SUMMARY, contents.navPackages, section); if (display(packages)) { @@ -600,7 +603,7 @@ protected void addPackagesSummary(Content summariesList) { * @param li the tree to which the summary will be added */ public void addPackageSummary(HtmlTree li) { - var table = new Table(HtmlStyle.summaryTable) + var table = new Table(HtmlStyles.summaryTable) .setId(HtmlIds.PACKAGE_SUMMARY_TABLE) .setDefaultTab(contents.getContent("doclet.All_Packages")) .addTab(contents.getContent("doclet.Exported_Packages_Summary"), this::isExported) @@ -636,20 +639,20 @@ public void addPackageSummary(HtmlTree li) { List colHeaders = new ArrayList<>(); List colStyles = new ArrayList<>(); colHeaders.add(contents.packageLabel); - colStyles.add(HtmlStyle.colFirst); + colStyles.add(HtmlStyles.colFirst); if (showExportedTo) { colHeaders.add(contents.exportedTo); - colStyles.add(HtmlStyle.colSecond); + colStyles.add(HtmlStyles.colSecond); } if (showOpenedTo) { colHeaders.add(contents.openedTo); - colStyles.add(HtmlStyle.colSecond); + colStyles.add(HtmlStyles.colSecond); } colHeaders.add(contents.descriptionLabel); - colStyles.add(HtmlStyle.colLast); + colStyles.add(HtmlStyles.colLast); table.setHeader(new TableHeader(colHeaders).styles(colStyles)) .setColumnStyles(colStyles); @@ -741,7 +744,7 @@ protected void addServicesSummary(Content summariesList) { if (haveProvides || haveUses) { tableOfContents.addLink(HtmlIds.SERVICES, contents.navServices); - var section = HtmlTree.SECTION(HtmlStyle.servicesSummary) + var section = HtmlTree.SECTION(HtmlStyles.servicesSummary) .setId(HtmlIds.SERVICES); addSummaryHeader(MarkerComments.START_OF_SERVICES_SUMMARY, contents.navServices, section); TableHeader usesProvidesTableHeader = @@ -783,7 +786,7 @@ public void addUsesList(Table table) { if (display(usesTrees)) { description = usesTrees.get(t); if (description != null && !description.isEmpty()) { - summary.add(HtmlTree.DIV(HtmlStyle.block, description)); + summary.add(HtmlTree.DIV(HtmlStyles.block, description)); } else { addSummaryComment(t, summary); } @@ -813,7 +816,7 @@ public void addProvidesList(Table table) { if (display(providesTrees)) { description = providesTrees.get(srv); if (description != null && !description.isEmpty()) { - desc.add(HtmlTree.DIV(HtmlStyle.block, description)); + desc.add(HtmlTree.DIV(HtmlStyles.block, description)); } else { addSummaryComment(srv, desc); } @@ -822,9 +825,9 @@ public void addProvidesList(Table table) { } // Only display the implementation details in the "all" mode. if (moduleMode == ModuleMode.ALL && !implSet.isEmpty()) { - desc.add(new HtmlTree(TagName.BR)); + desc.add(new HtmlTree(HtmlTag.BR)); desc.add("("); - var implSpan = HtmlTree.SPAN(HtmlStyle.implementationLabel, contents.implementation); + var implSpan = HtmlTree.SPAN(HtmlStyles.implementationLabel, contents.implementation); desc.add(implSpan); desc.add(Entity.NO_BREAK_SPACE); String sep = ""; @@ -848,8 +851,8 @@ public void addDeprecationInfo(Content div) { List deprs = utils.getDeprecatedTrees(mdle); if (utils.isDeprecated(mdle)) { CommentHelper ch = utils.getCommentHelper(mdle); - var deprDiv = HtmlTree.DIV(HtmlStyle.deprecationBlock); - var deprPhrase = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(mdle)); + var deprDiv = HtmlTree.DIV(HtmlStyles.deprecationBlock); + var deprPhrase = HtmlTree.SPAN(HtmlStyles.deprecatedLabel, getDeprecatedPhrase(mdle)); deprDiv.add(deprPhrase); if (!deprs.isEmpty()) { List commentTags = ch.getDescription(deprs.get(0)); @@ -864,7 +867,7 @@ public void addDeprecationInfo(Content div) { protected void addModuleDescription(Content moduleContent) { addPreviewInfo(mdle, moduleContent); if (!utils.getFullBody(mdle).isEmpty()) { - var tree = HtmlTree.SECTION(HtmlStyle.moduleDescription) + var tree = HtmlTree.SECTION(HtmlStyles.moduleDescription) .setId(HtmlIds.MODULE_DESCRIPTION); addDeprecationInfo(tree); tree.add(MarkerComments.START_OF_MODULE_DESCRIPTION); @@ -902,8 +905,8 @@ protected void printDocument(Content content) throws DocFileIOException { public void addPackageDeprecationInfo(Content li, PackageElement pkg) { if (utils.isDeprecated(pkg)) { List deprs = utils.getDeprecatedTrees(pkg); - var deprDiv = HtmlTree.DIV(HtmlStyle.deprecationBlock); - var deprPhrase = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(pkg)); + var deprDiv = HtmlTree.DIV(HtmlStyles.deprecationBlock); + var deprPhrase = HtmlTree.SPAN(HtmlStyles.deprecatedLabel, getDeprecatedPhrase(pkg)); deprDiv.add(deprPhrase); if (!deprs.isEmpty()) { CommentHelper ch = utils.getCommentHelper(pkg); 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 63c18084c1077..293a6453925f6 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 @@ -35,19 +35,19 @@ import javax.lang.model.element.PackageElement; import javax.lang.model.element.TypeElement; -import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; -import jdk.javadoc.internal.doclets.formats.html.markup.Entity; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlAttr; -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.markup.HtmlStyles; import jdk.javadoc.internal.doclets.formats.html.markup.Links; -import jdk.javadoc.internal.doclets.formats.html.markup.Text; import jdk.javadoc.internal.doclets.toolkit.util.DocFile; import jdk.javadoc.internal.doclets.toolkit.util.DocLink; import jdk.javadoc.internal.doclets.toolkit.util.DocPath; import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; -import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable; +import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.ContentBuilder; +import jdk.javadoc.internal.html.Entity; +import jdk.javadoc.internal.html.HtmlAttr; +import jdk.javadoc.internal.html.HtmlTag; +import jdk.javadoc.internal.html.HtmlTree; +import jdk.javadoc.internal.html.Text; /** * Factory for navigation bar. @@ -326,7 +326,7 @@ private void addItemToList(Content list, Content item) { private void addActivePageLink(Content target, Content label, boolean display) { if (display) { - target.add(HtmlTree.LI(HtmlStyle.navBarCell1Rev, label)); + target.add(HtmlTree.LI(HtmlStyles.navBarCell1Rev, label)); } } @@ -409,7 +409,7 @@ protected void addBreadcrumbLinks(Element elem, List contents, boolean default -> throw new IllegalArgumentException(Objects.toString(elem)); }; if (selected) { - link.setStyle(HtmlStyle.currentSelection); + link.setStyle(HtmlStyles.currentSelection); } contents.add(link); } @@ -499,7 +499,7 @@ private void addSearch(Content target) { .put(HtmlAttr.AUTOCOMPLETE, "off"); var inputReset = HtmlTree.INPUT(HtmlAttr.InputType.RESET, HtmlIds.RESET_SEARCH) .put(HtmlAttr.VALUE, resources.getText("doclet.search_reset")); - var searchDiv = HtmlTree.DIV(HtmlStyle.navListSearch) + var searchDiv = HtmlTree.DIV(HtmlStyles.navListSearch) .add(inputText) .add(inputReset); target.add(searchDiv); @@ -516,36 +516,36 @@ public Content getContent() { } var navigationBar = HtmlTree.NAV(); - var navContent = new HtmlTree(TagName.DIV); + var navContent = new HtmlTree(HtmlTag.DIV); Content skipNavLinks = contents.getContent("doclet.Skip_navigation_links"); String toggleNavLinks = configuration.getDocResources().getText("doclet.Toggle_navigation_links"); navigationBar.add(MarkerComments.START_OF_TOP_NAVBAR); // The mobile menu button uses three empty spans to produce its animated icon - HtmlTree iconSpan = HtmlTree.SPAN(HtmlStyle.navBarToggleIcon).add(Entity.NO_BREAK_SPACE); - navContent.setStyle(HtmlStyle.navContent).add(HtmlTree.DIV(HtmlStyle.navMenuButton, - new HtmlTree(TagName.BUTTON).setId(HtmlIds.NAVBAR_TOGGLE_BUTTON) + HtmlTree iconSpan = HtmlTree.SPAN(HtmlStyles.navBarToggleIcon).add(Entity.NO_BREAK_SPACE); + navContent.setStyle(HtmlStyles.navContent).add(HtmlTree.DIV(HtmlStyles.navMenuButton, + new HtmlTree(HtmlTag.BUTTON).setId(HtmlIds.NAVBAR_TOGGLE_BUTTON) .put(HtmlAttr.ARIA_CONTROLS, HtmlIds.NAVBAR_TOP.name()) .put(HtmlAttr.ARIA_EXPANDED, String.valueOf(false)) .put(HtmlAttr.ARIA_LABEL, toggleNavLinks) .add(iconSpan) .add(iconSpan) .add(iconSpan))) - .add(HtmlTree.DIV(HtmlStyle.skipNav, + .add(HtmlTree.DIV(HtmlStyles.skipNav, links.createLink(HtmlIds.SKIP_NAVBAR_TOP, skipNavLinks, skipNavLinks.toString()))); Content aboutContent = userHeader; - var navList = new HtmlTree(TagName.UL) + var navList = new HtmlTree(HtmlTag.UL) .setId(HtmlIds.NAVBAR_TOP_FIRSTROW) - .setStyle(HtmlStyle.navList) + .setStyle(HtmlStyles.navList) .put(HtmlAttr.TITLE, rowListTitle); addMainNavLinks(navList); navContent.add(navList); - var aboutDiv = HtmlTree.DIV(HtmlStyle.aboutLanguage, aboutContent); + var aboutDiv = HtmlTree.DIV(HtmlStyles.aboutLanguage, aboutContent); navContent.add(aboutDiv); - navigationBar.add(HtmlTree.DIV(HtmlStyle.topNav, navContent).setId(HtmlIds.NAVBAR_TOP)); + navigationBar.add(HtmlTree.DIV(HtmlStyles.topNav, navContent).setId(HtmlIds.NAVBAR_TOP)); - var subNavContent = HtmlTree.DIV(HtmlStyle.navContent); + var subNavContent = HtmlTree.DIV(HtmlStyles.navContent); List subNavLinks = new ArrayList<>(); switch (documentedPage) { case MODULE, PACKAGE, CLASS, USE, DOC_FILE, TREE -> { @@ -553,17 +553,17 @@ public Content getContent() { } } // Add the breadcrumb navigation links if present. - var breadcrumbNav = HtmlTree.OL(HtmlStyle.subNavList); + var breadcrumbNav = HtmlTree.OL(HtmlStyles.subNavList); breadcrumbNav.addAll(subNavLinks, HtmlTree::LI); subNavContent.addUnchecked(breadcrumbNav); if (options.createIndex() && documentedPage != PageMode.SEARCH) { addSearch(subNavContent); } - navigationBar.add(HtmlTree.DIV(HtmlStyle.subNav, subNavContent)); + navigationBar.add(HtmlTree.DIV(HtmlStyles.subNav, subNavContent)); navigationBar.add(MarkerComments.END_OF_TOP_NAVBAR); - navigationBar.add(HtmlTree.SPAN(HtmlStyle.skipNav) + navigationBar.add(HtmlTree.SPAN(HtmlStyles.skipNav) .addUnchecked(Text.EMPTY) .setId(HtmlIds.SKIP_NAVBAR_TOP)); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/NestedClassWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/NestedClassWriter.java index 4534f707c38b7..12d4dcbd6638d 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/NestedClassWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/NestedClassWriter.java @@ -31,12 +31,14 @@ import javax.lang.model.element.Element; import javax.lang.model.element.TypeElement; -import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; -import jdk.javadoc.internal.doclets.formats.html.markup.Entity; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; -import jdk.javadoc.internal.doclets.formats.html.markup.Text; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyles; import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable; +import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.ContentBuilder; +import jdk.javadoc.internal.html.Entity; +import jdk.javadoc.internal.html.HtmlStyle; +import jdk.javadoc.internal.html.HtmlTree; +import jdk.javadoc.internal.html.Text; /** * Writes nested class documentation in HTML format. @@ -71,7 +73,7 @@ public Content getMemberSummaryHeader(Content content) { @Override public void buildSummary(Content summariesList, Content content) { - writer.addSummary(HtmlStyle.nestedClassSummary, + writer.addSummary(HtmlStyles.nestedClassSummary, HtmlIds.NESTED_CLASS_SUMMARY, summariesList, content); } @@ -92,10 +94,10 @@ public TableHeader getSummaryTableHeader(Element member) { @Override protected Table createSummaryTable() { - List bodyRowStyles = Arrays.asList(HtmlStyle.colFirst, HtmlStyle.colSecond, - HtmlStyle.colLast); + List bodyRowStyles = Arrays.asList(HtmlStyles.colFirst, HtmlStyles.colSecond, + HtmlStyles.colLast); - return new Table(HtmlStyle.summaryTable) + return new Table(HtmlStyles.summaryTable) .setCaption(contents.getContent("doclet.Nested_Classes")) .setHeader(getSummaryTableHeader(typeElement)) .setColumnStyles(bodyRowStyles); @@ -125,7 +127,7 @@ public void addInheritedSummaryLabel(TypeElement typeElement, Content content) { protected void addSummaryLink(HtmlLinkInfo.Kind context, TypeElement typeElement, Element member, Content content) { Content memberLink = writer.getLink(new HtmlLinkInfo(configuration, context, (TypeElement)member) - .style(HtmlStyle.typeNameLink)); + .style(HtmlStyles.typeNameLink)); var code = HtmlTree.CODE(memberLink); content.add(code); } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/NewAPIListWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/NewAPIListWriter.java index f46765933cfdb..68066b0c92be5 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/NewAPIListWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/NewAPIListWriter.java @@ -32,14 +32,14 @@ import com.sun.source.doctree.SinceTree; import jdk.javadoc.internal.doclets.formats.html.Navigation.PageMode; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlAttr; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlId; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; -import jdk.javadoc.internal.doclets.formats.html.markup.Text; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyles; import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper; import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; import jdk.javadoc.internal.doclets.toolkit.util.NewAPIBuilder; +import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.HtmlStyle; +import jdk.javadoc.internal.html.HtmlTree; +import jdk.javadoc.internal.html.Text; import static com.sun.source.doctree.DocTree.Kind.SINCE; @@ -81,7 +81,7 @@ protected String getTitleKey() { protected void addContentSelectors(Content content) { List releases = builder.releases; if (releases.size() > 1) { - Content tabs = HtmlTree.DIV(HtmlStyle.checkboxes, + Content tabs = HtmlTree.DIV(HtmlStyles.checkboxes, contents.getContent("doclet.New_API_Checkbox_Label")); // Table column ids are 1-based int index = 1; @@ -96,7 +96,7 @@ protected void addContentSelectors(Content content) { @Override protected void addTableTabs(Table table, String headingKey) { - table.setGridStyle(HtmlStyle.threeColumnReleaseSummary); + table.setGridStyle(HtmlStyles.threeColumnReleaseSummary); List releases = builder.releases; if (releases.size() > 1) { table.setDefaultTab(getTableCaption(headingKey)) @@ -149,7 +149,7 @@ protected TableHeader getTableHeader(String headerKey) { @Override protected HtmlStyle[] getColumnStyles() { - return new HtmlStyle[]{ HtmlStyle.colSummaryItemName, HtmlStyle.colSecond, HtmlStyle.colLast }; + return new HtmlStyle[]{ HtmlStyles.colSummaryItemName, HtmlStyles.colSecond, HtmlStyles.colLast }; } private static String getHeading(HtmlConfiguration configuration) { diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageIndexWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageIndexWriter.java index ef7f25e7388d4..fd257fc06f48e 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageIndexWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageIndexWriter.java @@ -31,11 +31,12 @@ import javax.lang.model.element.PackageElement; -import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; -import jdk.javadoc.internal.doclets.formats.html.markup.Text; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyles; import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; import jdk.javadoc.internal.doclets.toolkit.util.Group; +import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.ContentBuilder; +import jdk.javadoc.internal.html.Text; /** * Generate the package index page "index.html". @@ -81,9 +82,9 @@ protected void addIndex(Content target) { = configuration.group.groupPackages(packages); if (!groupPackageMap.keySet().isEmpty()) { - var table = new Table(HtmlStyle.summaryTable) + var table = new Table(HtmlStyles.summaryTable) .setHeader(getPackageTableHeader()) - .setColumnStyles(HtmlStyle.colFirst, HtmlStyle.colLast) + .setColumnStyles(HtmlStyles.colFirst, HtmlStyles.colLast) .setId(HtmlIds.ALL_PACKAGES_TABLE) .setDefaultTab(contents.getContent("doclet.All_Packages")); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageTreeWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageTreeWriter.java index cba27fd64faa3..8ff3cf9779717 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageTreeWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageTreeWriter.java @@ -25,21 +25,17 @@ package jdk.javadoc.internal.doclets.formats.html; -import javax.lang.model.element.Element; import javax.lang.model.element.PackageElement; import jdk.javadoc.internal.doclets.formats.html.Navigation.PageMode; import jdk.javadoc.internal.doclets.formats.html.markup.BodyContents; -import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; -import jdk.javadoc.internal.doclets.formats.html.markup.Text; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyles; import jdk.javadoc.internal.doclets.toolkit.util.ClassTree; import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException; import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; - -import java.util.ArrayList; -import java.util.List; +import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.ContentBuilder; +import jdk.javadoc.internal.html.HtmlTree; /** @@ -100,8 +96,8 @@ public void buildPage() throws DocFileIOException { : contents.getContent("doclet.Hierarchy_For_Package", getLocalizedPackageName(packageElement)); var heading = HtmlTree.HEADING(Headings.PAGE_TITLE_HEADING, - HtmlStyle.title, headContent); - var div = HtmlTree.DIV(HtmlStyle.header, heading); + HtmlStyles.title, headContent); + var div = HtmlTree.DIV(HtmlStyles.header, heading); mainContent.add(div); if (configuration.packages.size() > 1) { addLinkToAllPackages(mainContent); @@ -136,10 +132,10 @@ protected HtmlTree getPackageTreeHeader() { * @param target the content to which the link will be added */ protected void addLinkToAllPackages(Content target) { - var span = HtmlTree.SPAN(HtmlStyle.packageHierarchyLabel, + var span = HtmlTree.SPAN(HtmlStyles.packageHierarchyLabel, contents.packageHierarchies); target.add(span); - var ul = HtmlTree.UL(HtmlStyle.horizontal).addStyle(HtmlStyle.contentsList); + var ul = HtmlTree.UL(HtmlStyles.horizontal).addStyle(HtmlStyles.contentsList); // TODO the link should be more specific: // it should point to the "all packages" section of the overview tree ul.add(getNavLinkToOverviewTree(resources.getText("doclet.All_Packages"))); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageUseWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageUseWriter.java index 848e7069d66d7..b28b44d4cd3a6 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageUseWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageUseWriter.java @@ -25,28 +25,26 @@ package jdk.javadoc.internal.doclets.formats.html; -import java.util.ArrayList; -import java.util.List; import java.util.Set; import java.util.SortedMap; import java.util.TreeMap; import java.util.TreeSet; -import javax.lang.model.element.Element; import javax.lang.model.element.PackageElement; import javax.lang.model.element.TypeElement; -import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; -import jdk.javadoc.internal.doclets.formats.html.markup.Entity; -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.formats.html.markup.HtmlStyles; import jdk.javadoc.internal.doclets.toolkit.util.ClassUseMapper; import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException; import jdk.javadoc.internal.doclets.toolkit.util.DocPath; import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; +import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.ContentBuilder; +import jdk.javadoc.internal.html.Entity; +import jdk.javadoc.internal.html.HtmlTag; +import jdk.javadoc.internal.html.HtmlTree; +import jdk.javadoc.internal.html.Text; /** * Generate package usage information. @@ -138,10 +136,10 @@ protected void addPackageList(Content content) { Content caption = contents.getContent( "doclet.ClassUse_Packages.that.use.0", getPackageLink(packageElement, getLocalizedPackageName(packageElement))); - var table = new Table(HtmlStyle.summaryTable) + var table = new Table(HtmlStyles.summaryTable) .setCaption(caption) .setHeader(getPackageTableHeader()) - .setColumnStyles(HtmlStyle.colFirst, HtmlStyle.colLast); + .setColumnStyles(HtmlStyles.colFirst, HtmlStyles.colLast); for (String pkgname: usingPackageToUsedClasses.keySet()) { PackageElement pkg = utils.elementUtils.getPackageElement(pkgname); Content packageLink = links.createLink(htmlIds.forPackage(pkg), @@ -165,19 +163,19 @@ protected void addPackageList(Content content) { protected void addClassList(Content content) { TableHeader classTableHeader = new TableHeader( contents.classLabel, contents.descriptionLabel); - var ul = HtmlTree.UL(HtmlStyle.blockList); + var ul = HtmlTree.UL(HtmlStyles.blockList); for (String packageName : usingPackageToUsedClasses.keySet()) { PackageElement usingPackage = utils.elementUtils.getPackageElement(packageName); - var section = HtmlTree.SECTION(HtmlStyle.detail) + var section = HtmlTree.SECTION(HtmlStyles.detail) .setId(htmlIds.forPackage(usingPackage)); Content caption = contents.getContent( "doclet.ClassUse_Classes.in.0.used.by.1", getPackageLink(packageElement, getLocalizedPackageName(packageElement)), getPackageLink(usingPackage, getLocalizedPackageName(usingPackage))); - var table = new Table(HtmlStyle.summaryTable) + var table = new Table(HtmlStyles.summaryTable) .setCaption(caption) .setHeader(classTableHeader) - .setColumnStyles(HtmlStyle.colFirst, HtmlStyle.colLast); + .setColumnStyles(HtmlStyles.colFirst, HtmlStyles.colLast); for (TypeElement te : usingPackageToUsedClasses.get(packageName)) { DocPath dp = pathString(te, DocPaths.CLASS_USE.resolve(docPaths.forName(te))); @@ -192,7 +190,7 @@ protected void addClassList(Content content) { section.add(table); ul.add(HtmlTree.LI(section)); } - var li = HtmlTree.SECTION(HtmlStyle.packageUses, ul); + var li = HtmlTree.SECTION(HtmlStyles.packageUses, ul); content.add(li); } @@ -206,11 +204,11 @@ private HtmlTree getBody() { HtmlTree body = getBody(getWindowTitle(title)); ContentBuilder headingContent = new ContentBuilder(); headingContent.add(contents.getContent("doclet.ClassUse_Title", packageText)); - headingContent.add(new HtmlTree(TagName.BR)); + headingContent.add(new HtmlTree(HtmlTag.BR)); headingContent.add(name); var heading = HtmlTree.HEADING_TITLE(Headings.PAGE_TITLE_HEADING, - HtmlStyle.title, headingContent); - var div = HtmlTree.DIV(HtmlStyle.header, heading); + HtmlStyles.title, headingContent); + var div = HtmlTree.DIV(HtmlStyles.header, heading); bodyContents.setHeader(getHeader(PageMode.USE, packageElement)) .addMainContent(div); return body; diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageWriter.java index c70386c6b3666..ee022144fea57 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageWriter.java @@ -33,25 +33,26 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; -import javax.lang.model.element.Element; import javax.lang.model.element.ModuleElement; import javax.lang.model.element.PackageElement; import javax.lang.model.element.TypeElement; import com.sun.source.doctree.DeprecatedTree; import com.sun.source.doctree.DocTree; -import jdk.javadoc.internal.doclets.formats.html.markup.BodyContents; -import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; -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.formats.html.markup.BodyContents; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyles; import jdk.javadoc.internal.doclets.toolkit.DocletException; import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper; import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException; import jdk.javadoc.internal.doclets.toolkit.util.DocPath; import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; +import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.ContentBuilder; +import jdk.javadoc.internal.html.HtmlTag; +import jdk.javadoc.internal.html.HtmlTree; +import jdk.javadoc.internal.html.Text; /** * Class to generate file for each package contents in the right-hand @@ -71,7 +72,7 @@ public class PackageWriter extends HtmlDocletWriter { /** * The HTML element for the section tag being written. */ - private final HtmlTree section = HtmlTree.SECTION(HtmlStyle.packageDescription, new ContentBuilder()); + private final HtmlTree section = HtmlTree.SECTION(HtmlStyles.packageDescription, new ContentBuilder()); private final BodyContents bodyContents = new BodyContents(); @@ -127,8 +128,8 @@ protected void buildPackageDoc() throws DocletException { */ protected void buildContent() { Content packageContent = getContentHeader(); - packageContent.add(new HtmlTree(TagName.HR)); - Content div = HtmlTree.DIV(HtmlStyle.horizontalScroll); + packageContent.add(new HtmlTree(HtmlTag.HR)); + Content div = HtmlTree.DIV(HtmlStyles.horizontalScroll); addPackageSignature(div); buildPackageDescription(div); buildPackageTags(div); @@ -202,14 +203,14 @@ protected void buildPackageTags(Content packageContent) { protected Content getPackageHeader() { String packageName = getLocalizedPackageName(packageElement).toString(); HtmlTree body = getBody(getWindowTitle(packageName)); - var div = HtmlTree.DIV(HtmlStyle.header); + var div = HtmlTree.DIV(HtmlStyles.header); Content packageHead = new ContentBuilder(); if (!packageElement.isUnnamed()) { packageHead.add(contents.packageLabel).add(" "); } packageHead.add(packageName); var tHeading = HtmlTree.HEADING_TITLE(Headings.PAGE_TITLE_HEADING, - HtmlStyle.title, packageHead); + HtmlStyles.title, packageHead); div.add(tHeading); bodyContents.setHeader(getHeader(PageMode.PACKAGE, packageElement)) .addMainContent(div); @@ -277,8 +278,8 @@ public void addDeprecationInfo(Content div) { List deprs = utils.getDeprecatedTrees(packageElement); if (utils.isDeprecated(packageElement)) { CommentHelper ch = utils.getCommentHelper(packageElement); - var deprDiv = HtmlTree.DIV(HtmlStyle.deprecationBlock); - var deprPhrase = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(packageElement)); + var deprDiv = HtmlTree.DIV(HtmlStyles.deprecationBlock); + var deprPhrase = HtmlTree.SPAN(HtmlStyles.deprecatedLabel, getDeprecatedPhrase(packageElement)); deprDiv.add(deprPhrase); if (!deprs.isEmpty()) { List commentTags = ch.getDescription(deprs.get(0)); @@ -291,7 +292,7 @@ public void addDeprecationInfo(Content div) { } protected Content getSummariesList() { - return HtmlTree.UL(HtmlStyle.summaryList); + return HtmlTree.UL(HtmlStyles.summaryList); } protected void addRelatedPackagesSummary(Content summaryContent) { @@ -308,9 +309,9 @@ protected void addRelatedPackagesSummary(Content summaryContent) { * @param target the content to which the links will be added */ public void addAllClassesAndInterfacesSummary(Content target) { - var table = new Table(HtmlStyle.summaryTable) + var table = new Table(HtmlStyles.summaryTable) .setHeader(new TableHeader(contents.classLabel, contents.descriptionLabel)) - .setColumnStyles(HtmlStyle.colFirst, HtmlStyle.colLast) + .setColumnStyles(HtmlStyles.colFirst, HtmlStyles.colLast) .setId(HtmlIds.CLASS_SUMMARY) .setDefaultTab(contents.allClassesAndInterfacesLabel) .addTab(contents.interfaces, utils::isPlainInterface) @@ -347,14 +348,14 @@ protected void addRelatedPackageSummary(TableHeader tableHeader, Content summary boolean showModules) { if (!relatedPackages.isEmpty()) { tableOfContents.addLink(HtmlIds.RELATED_PACKAGE_SUMMARY, contents.relatedPackages); - var table = new Table(HtmlStyle.summaryTable) + var table = new Table(HtmlStyles.summaryTable) .setId(HtmlIds.RELATED_PACKAGE_SUMMARY) .setCaption(contents.relatedPackages) .setHeader(tableHeader); if (showModules) { - table.setColumnStyles(HtmlStyle.colPlain, HtmlStyle.colFirst, HtmlStyle.colLast); + table.setColumnStyles(HtmlStyles.colPlain, HtmlStyles.colFirst, HtmlStyles.colLast); } else { - table.setColumnStyles(HtmlStyle.colFirst, HtmlStyle.colLast); + table.setColumnStyles(HtmlStyles.colFirst, HtmlStyles.colLast); } for (PackageElement pkg : relatedPackages) { @@ -423,7 +424,7 @@ protected void printDocument(Content content) throws DocFileIOException { } protected Content getPackageSummary(Content summaryContent) { - return HtmlTree.SECTION(HtmlStyle.summary, summaryContent); + return HtmlTree.SECTION(HtmlStyles.summary, summaryContent); } private boolean hasRelatedPackagesInOtherModules(List relatedPackages) { diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PreviewListWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PreviewListWriter.java index 2141f1e7be734..4fb0d427ff965 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PreviewListWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PreviewListWriter.java @@ -33,12 +33,14 @@ import com.sun.source.doctree.DocTree; import jdk.javadoc.internal.doclets.formats.html.Navigation.PageMode; -import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; -import jdk.javadoc.internal.doclets.formats.html.markup.Text; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyles; import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; import jdk.javadoc.internal.doclets.toolkit.util.PreviewAPIListBuilder; +import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.ContentBuilder; +import jdk.javadoc.internal.html.HtmlStyle; +import jdk.javadoc.internal.html.HtmlTree; +import jdk.javadoc.internal.html.Text; /** * Generate File to list all the preview elements with the @@ -81,7 +83,7 @@ protected void addContentSelectors(Content target) { if (!jeps.isEmpty()) { int index = 1; target.add(HtmlTree.P(contents.getContent("doclet.Preview_API_Checkbox_Label"))); - Content list = HtmlTree.UL(HtmlStyle.previewFeatureList).addStyle(HtmlStyle.checkboxes); + Content list = HtmlTree.UL(HtmlStyles.previewFeatureList).addStyle(HtmlStyles.checkboxes); for (var jep : jeps) { String jepUrl = resources.getText("doclet.Preview_JEP_URL", String.valueOf(jep.number())); Content label = new ContentBuilder(Text.of(jep.number() + ": ")) @@ -106,7 +108,7 @@ protected void addComments(Element e, Content desc) { @Override protected void addTableTabs(Table table, String headingKey) { - table.setGridStyle(HtmlStyle.threeColumnSummary) + table.setGridStyle(HtmlStyles.threeColumnSummary) .setDefaultTab(getTableCaption(headingKey)) .setRenderTabs(false); for (PreviewAPIListBuilder.JEP jep : builder.getJEPs()) { @@ -131,6 +133,6 @@ protected TableHeader getTableHeader(String headerKey) { @Override protected HtmlStyle[] getColumnStyles() { - return new HtmlStyle[]{ HtmlStyle.colSummaryItemName, HtmlStyle.colSecond, HtmlStyle.colLast }; + return new HtmlStyle[]{ HtmlStyles.colSummaryItemName, HtmlStyles.colSecond, HtmlStyles.colLast }; } } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PropertyWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PropertyWriter.java index 41a59c8a30c5c..7365b9b3b8f9a 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PropertyWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PropertyWriter.java @@ -35,14 +35,15 @@ import com.sun.source.doctree.DocCommentTree; import com.sun.source.doctree.DocTree; -import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; -import jdk.javadoc.internal.doclets.formats.html.markup.Entity; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; -import jdk.javadoc.internal.doclets.formats.html.markup.Text; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyles; import jdk.javadoc.internal.doclets.toolkit.BaseOptions; import jdk.javadoc.internal.doclets.toolkit.CommentUtils; import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable; +import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.ContentBuilder; +import jdk.javadoc.internal.html.Entity; +import jdk.javadoc.internal.html.HtmlTree; +import jdk.javadoc.internal.html.Text; /** * Writes property documentation in HTML format. @@ -80,7 +81,7 @@ protected void buildPropertyDoc(Content detailsList) { for (Element property : properties) { currentProperty = (ExecutableElement)property; Content propertyContent = getPropertyHeaderContent(currentProperty); - Content div = HtmlTree.DIV(HtmlStyle.horizontalScroll); + Content div = HtmlTree.DIV(HtmlStyles.horizontalScroll); buildSignature(div); buildDeprecationInfo(div); buildPreviewInfo(div); @@ -161,7 +162,7 @@ public Content getMemberSummaryHeader(Content content) { @Override public void buildSummary(Content summariesList, Content content) { - writer.addSummary(HtmlStyle.propertySummary, + writer.addSummary(HtmlStyles.propertySummary, HtmlIds.PROPERTY_SUMMARY, summariesList, content); } @@ -179,7 +180,7 @@ protected Content getPropertyHeaderContent(ExecutableElement property) { var heading = HtmlTree.HEADING(Headings.TypeDeclaration.MEMBER_HEADING, Text.of(utils.getPropertyLabel(name(property)))); content.add(heading); - return HtmlTree.SECTION(HtmlStyle.detail, content) + return HtmlTree.SECTION(HtmlStyles.detail, content) .setId(htmlIds.forProperty(property)); } @@ -210,13 +211,13 @@ protected void addComments(ExecutableElement property, Content propertyContent) utils.isIncluded(holder) ? holder.getSimpleName() : holder.getQualifiedName()); var codeLink = HtmlTree.CODE(link); - var descriptionFromLabel = HtmlTree.SPAN(HtmlStyle.descriptionFromTypeLabel, + var descriptionFromLabel = HtmlTree.SPAN(HtmlStyles.descriptionFromTypeLabel, utils.isClass(holder) ? contents.descriptionFromClassLabel : contents.descriptionFromInterfaceLabel); descriptionFromLabel.add(Entity.NO_BREAK_SPACE); descriptionFromLabel.add(codeLink); - propertyContent.add(HtmlTree.DIV(HtmlStyle.block, descriptionFromLabel)); + propertyContent.add(HtmlTree.DIV(HtmlStyles.block, descriptionFromLabel)); } writer.addInlineComment(property, propertyContent); } @@ -229,7 +230,7 @@ protected void addTags(ExecutableElement property, Content propertyContent) { protected Content getPropertyDetails(Content memberDetailsHeader, Content memberDetails) { return writer.getDetailsListItem( - HtmlTree.SECTION(HtmlStyle.propertyDetails) + HtmlTree.SECTION(HtmlStyles.propertyDetails) .setId(HtmlIds.PROPERTY_DETAIL) .add(memberDetailsHeader) .add(memberDetails)); @@ -250,10 +251,10 @@ public TableHeader getSummaryTableHeader(Element member) { @Override protected Table createSummaryTable() { - return new Table(HtmlStyle.summaryTable) + return new Table(HtmlStyles.summaryTable) .setCaption(contents.properties) .setHeader(getSummaryTableHeader(typeElement)) - .setColumnStyles(HtmlStyle.colFirst, HtmlStyle.colSecond, HtmlStyle.colLast); + .setColumnStyles(HtmlStyles.colFirst, HtmlStyles.colSecond, HtmlStyles.colLast); } @Override @@ -284,7 +285,7 @@ protected void addSummaryLink(HtmlLinkInfo.Kind context, TypeElement typeElement Content memberLink = writer.getDocLink(context, typeElement, member, Text.of(utils.getPropertyLabel(name(member))), - HtmlStyle.memberNameLink, + HtmlStyles.memberNameLink, true); var code = HtmlTree.CODE(memberLink); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/RestrictedListWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/RestrictedListWriter.java index bfd062706a98f..ec629a227a328 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/RestrictedListWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/RestrictedListWriter.java @@ -31,6 +31,7 @@ import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; import jdk.javadoc.internal.doclets.toolkit.util.IndexItem; import jdk.javadoc.internal.doclets.toolkit.util.RestrictedAPIListBuilder; +import jdk.javadoc.internal.html.Content; /** * Generate File to list all the restricted methods with the diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SearchWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SearchWriter.java index 8a2f0e2910939..0bd173df3d5f0 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SearchWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SearchWriter.java @@ -27,15 +27,16 @@ import jdk.javadoc.internal.doclets.formats.html.Navigation.PageMode; import jdk.javadoc.internal.doclets.formats.html.markup.BodyContents; -import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlAttr; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlId; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; -import jdk.javadoc.internal.doclets.formats.html.markup.TagName; -import jdk.javadoc.internal.doclets.formats.html.markup.Text; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyles; import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException; import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; +import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.ContentBuilder; +import jdk.javadoc.internal.html.HtmlAttr; +import jdk.javadoc.internal.html.HtmlId; +import jdk.javadoc.internal.html.HtmlTag; +import jdk.javadoc.internal.html.HtmlTree; +import jdk.javadoc.internal.html.Text; /** * Generates the search landing page for the generated API documentation. @@ -79,7 +80,7 @@ protected void addSearchFileContents(Content contentTree) { helpSection = HtmlTree.P(contents.getContent("doclet.search.help_page_info", helpLink)); } - contentTree.add(HtmlTree.HEADING(Headings.PAGE_TITLE_HEADING, HtmlStyle.title, + contentTree.add(HtmlTree.HEADING(Headings.PAGE_TITLE_HEADING, HtmlStyles.title, contents.getContent("doclet.search.main_heading"))) .add(HtmlTree.DIV(HtmlTree.INPUT(HtmlAttr.InputType.TEXT, HtmlId.of("page-search-input")) .put(HtmlAttr.PLACEHOLDER, resources.getText("doclet.search_placeholder")) @@ -88,31 +89,31 @@ protected void addSearchFileContents(Content contentTree) { .add(HtmlTree.INPUT(HtmlAttr.InputType.RESET, HtmlId.of("page-search-reset")) .put(HtmlAttr.VALUE, resources.getText("doclet.search_reset")) .put(HtmlAttr.STYLE, "margin: 6px;")) - .add(HtmlTree.DETAILS(HtmlStyle.pageSearchDetails) + .add(HtmlTree.DETAILS(HtmlStyles.pageSearchDetails) .add(HtmlTree.SUMMARY(contents.getContent("doclet.search.show_more")) .setId(HtmlId.of("page-search-expand"))))) - .add(HtmlTree.DIV(HtmlStyle.pageSearchInfo, helpSection) + .add(HtmlTree.DIV(HtmlStyles.pageSearchInfo, helpSection) .add(HtmlTree.P(contents.getContent("doclet.search.keyboard_info"))) .add(HtmlTree.P(contents.getContent("doclet.search.browser_info"))) .add(HtmlTree.SPAN(Text.of("link")) .setId(HtmlId.of("page-search-link"))) - .add(new HtmlTree(TagName.BUTTON) - .add(new HtmlTree(TagName.IMG) + .add(new HtmlTree(HtmlTag.BUTTON) + .add(new HtmlTree(HtmlTag.IMG) .put(HtmlAttr.SRC, pathToRoot.resolve(DocPaths.RESOURCE_FILES) .resolve(DocPaths.CLIPBOARD_SVG).getPath()) .put(HtmlAttr.ALT, copyUrlText)) .add(HtmlTree.SPAN(Text.of(copyText)) .put(HtmlAttr.DATA_COPIED, copiedText)) - .addStyle(HtmlStyle.copy) + .addStyle(HtmlStyles.copy) .put(HtmlAttr.ARIA_LABEL, copyUrlText) .setId(HtmlId.of("page-search-copy"))) .add(HtmlTree.P(HtmlTree.INPUT(HtmlAttr.InputType.CHECKBOX, HtmlId.of("search-redirect"))) .add(HtmlTree.LABEL("search-redirect", contents.getContent("doclet.search.redirect"))))) - .add(new HtmlTree(TagName.P) + .add(new HtmlTree(HtmlTag.P) .setId(HtmlId.of("page-search-notify")) .add(contents.getContent("doclet.search.loading"))) - .add(HtmlTree.DIV(new HtmlTree(TagName.DIV) + .add(HtmlTree.DIV(new HtmlTree(HtmlTag.DIV) .setId(HtmlId.of("result-container")) .addUnchecked(Text.EMPTY)) .setId(HtmlId.of("result-section")) diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SerialFieldWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SerialFieldWriter.java index 758e0ee521491..c3d1cc582f36a 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SerialFieldWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SerialFieldWriter.java @@ -35,11 +35,12 @@ import com.sun.source.doctree.SerialFieldTree; import com.sun.source.doctree.SerialTree; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; -import jdk.javadoc.internal.doclets.formats.html.markup.TagName; -import jdk.javadoc.internal.doclets.formats.html.markup.Text; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyles; import jdk.javadoc.internal.doclets.formats.html.taglets.TagletWriter; +import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.HtmlTag; +import jdk.javadoc.internal.html.HtmlTree; +import jdk.javadoc.internal.html.Text; /** * Generate serialized form for serializable fields. @@ -53,15 +54,15 @@ public SerialFieldWriter(SubWriterHolderWriter writer, TypeElement typeElement) } protected Content getSerializableFieldsHeader() { - return HtmlTree.UL(HtmlStyle.blockList); + return HtmlTree.UL(HtmlStyles.blockList); } protected Content getFieldsContentHeader() { - return new HtmlTree(TagName.LI).setStyle(HtmlStyle.blockList); + return new HtmlTree(HtmlTag.LI).setStyle(HtmlStyles.blockList); } protected Content getSerializableFields(String heading, Content source) { - var section = HtmlTree.SECTION(HtmlStyle.detail); + var section = HtmlTree.SECTION(HtmlStyles.detail); if (!source.isEmpty()) { Content headingContent = Text.of(heading); var serialHeading = HtmlTree.HEADING(Headings.SerializedForm.CLASS_SUBHEADING, headingContent); @@ -75,7 +76,7 @@ protected void addMemberHeader(TypeMirror fieldType, String fieldName, Content c Content nameContent = Text.of(fieldName); var heading = HtmlTree.HEADING(Headings.SerializedForm.MEMBER_HEADING, nameContent); content.add(heading); - var pre = new HtmlTree(TagName.PRE); + var pre = new HtmlTree(HtmlTag.PRE); Content fieldContent = writer.getLink(new HtmlLinkInfo( configuration, HtmlLinkInfo.Kind.LINK_TYPE_PARAMS_AND_BOUNDS, fieldType)); pre.add(fieldContent); @@ -122,7 +123,7 @@ protected void addMemberDescription(VariableElement field, SerialFieldTree seria Content serialFieldContent = writer.commentTagsToContent(field, description, new TagletWriter.Context(false, false)); - var div = HtmlTree.DIV(HtmlStyle.block, serialFieldContent); + var div = HtmlTree.DIV(HtmlStyles.block, serialFieldContent); content.add(div); } } @@ -136,7 +137,7 @@ protected void addMemberDescription(VariableElement field, SerialFieldTree seria protected void addMemberTags(VariableElement field, Content content) { Content tagContent = writer.getBlockTagOutput(field); if (!tagContent.isEmpty()) { - var dl = HtmlTree.DL(HtmlStyle.notes); + var dl = HtmlTree.DL(HtmlStyles.notes); dl.add(tagContent); content.add(dl); } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SerialMethodWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SerialMethodWriter.java index 4af46f3ea0180..d9b888f2ee1b8 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SerialMethodWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SerialMethodWriter.java @@ -28,11 +28,12 @@ import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.TypeElement; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; -import jdk.javadoc.internal.doclets.formats.html.markup.TagName; -import jdk.javadoc.internal.doclets.formats.html.markup.Text; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyles; import jdk.javadoc.internal.doclets.formats.html.taglets.TagletManager; +import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.HtmlTag; +import jdk.javadoc.internal.html.HtmlTree; +import jdk.javadoc.internal.html.Text; /** @@ -46,11 +47,11 @@ public SerialMethodWriter(SubWriterHolderWriter writer, TypeElement typeElement) } protected Content getSerializableMethodsHeader() { - return HtmlTree.UL(HtmlStyle.blockList); + return HtmlTree.UL(HtmlStyles.blockList); } protected Content getMethodsContentHeader() { - return new HtmlTree(TagName.LI); + return new HtmlTree(HtmlTag.LI); } /** @@ -64,7 +65,7 @@ protected Content getMethodsContentHeader() { protected Content getSerializableMethods(String heading, Content source) { Content headingContent = Text.of(heading); var serialHeading = HtmlTree.HEADING(Headings.SerializedForm.CLASS_SUBHEADING, headingContent); - var section = HtmlTree.SECTION(HtmlStyle.detail, serialHeading); + var section = HtmlTree.SECTION(HtmlStyles.detail, serialHeading); section.add(source); return HtmlTree.LI(section); } @@ -121,7 +122,7 @@ protected void addMemberDescription(ExecutableElement member, Content methodsCon protected void addMemberTags(ExecutableElement member, Content methodsContent) { TagletManager tagletManager = configuration.tagletManager; Content tagContent = writer.getBlockTagOutput(member, tagletManager.getSerializedFormTaglets()); - var dl = HtmlTree.DL(HtmlStyle.notes); + var dl = HtmlTree.DL(HtmlStyles.notes); dl.add(tagContent); methodsContent.add(dl); if (name(member).equals("writeExternal") diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SerializedFormWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SerializedFormWriter.java index ffd654023d113..09fa5ed347c42 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SerializedFormWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SerializedFormWriter.java @@ -41,18 +41,19 @@ import com.sun.source.doctree.SerialFieldTree; import com.sun.source.doctree.SerialTree; -import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; -import jdk.javadoc.internal.doclets.formats.html.markup.Entity; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; -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.formats.html.markup.HtmlStyles; import jdk.javadoc.internal.doclets.toolkit.DocletException; import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper; import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException; import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; import jdk.javadoc.internal.doclets.toolkit.util.IndexItem; import jdk.javadoc.internal.doclets.toolkit.util.Utils; +import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.ContentBuilder; +import jdk.javadoc.internal.html.Entity; +import jdk.javadoc.internal.html.HtmlTree; +import jdk.javadoc.internal.html.Text; /** * Generates the Serialized Form Information Page, serialized-form.html. @@ -562,8 +563,8 @@ Content getHeader(String header) { HtmlTree body = getBody(getWindowTitle(header)); Content h1Content = Text.of(header); var heading = HtmlTree.HEADING_TITLE(Headings.PAGE_TITLE_HEADING, - HtmlStyle.title, h1Content); - var div = HtmlTree.DIV(HtmlStyle.header, heading); + HtmlStyles.title, h1Content); + var div = HtmlTree.DIV(HtmlStyles.header, heading); bodyContents.setHeader(getHeader(PageMode.SERIALIZED_FORM)) .addMainContent(div); return body; @@ -575,7 +576,7 @@ Content getHeader(String header) { * @return the serialized form summaries header */ Content getSerializedSummariesHeader() { - return HtmlTree.UL(HtmlStyle.blockList); + return HtmlTree.UL(HtmlStyles.blockList); } /** @@ -584,7 +585,7 @@ Content getSerializedSummariesHeader() { * @return the package serialized form header tree */ Content getPackageSerializedHeader() { - return HtmlTree.SECTION(HtmlStyle.serializedPackageContainer); + return HtmlTree.SECTION(HtmlStyles.serializedPackageContainer); } Content getPackageHeader(PackageElement packageElement) { @@ -596,7 +597,7 @@ Content getPackageHeader(PackageElement packageElement) { } Content getClassSerializedHeader() { - return HtmlTree.UL(HtmlStyle.blockList); + return HtmlTree.UL(HtmlStyles.blockList); } /** @@ -615,7 +616,7 @@ Content getClassHeader(TypeElement typeElement) { ? getLink(new HtmlLinkInfo(configuration, HtmlLinkInfo.Kind.PLAIN, typeElement) .label(configuration.getClassName(typeElement))) : Text.of(utils.getFullyQualifiedName(typeElement)); - var section = HtmlTree.SECTION(HtmlStyle.serializedClassDetails) + var section = HtmlTree.SECTION(HtmlStyles.serializedClassDetails) .setId(htmlIds.forClass(typeElement)); Content superClassLink = typeElement.getSuperclass() != null ? getLink(new HtmlLinkInfo(configuration, HtmlLinkInfo.Kind.LINK_TYPE_PARAMS_AND_BOUNDS, @@ -640,12 +641,12 @@ Content getClassHeader(TypeElement typeElement) { signature.add(superClassLink); signature.add(" implements "); signature.add(interfaceLink); - section.add(HtmlTree.DIV(HtmlStyle.typeSignature, signature)); + section.add(HtmlTree.DIV(HtmlStyles.typeSignature, signature)); return section; } Content getSerialUIDInfoHeader() { - return HtmlTree.DL(HtmlStyle.nameValue); + return HtmlTree.DL(HtmlStyles.nameValue); } /** @@ -667,7 +668,7 @@ void addSerialUIDInfo(String header, } Content getClassContentHeader() { - return HtmlTree.UL(HtmlStyle.blockList); + return HtmlTree.UL(HtmlStyles.blockList); } /** diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Signatures.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Signatures.java index afc0648fa79c2..9059efcf81438 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Signatures.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Signatures.java @@ -25,14 +25,12 @@ package jdk.javadoc.internal.doclets.formats.html; -import jdk.javadoc.doclet.DocletEnvironment; -import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; -import jdk.javadoc.internal.doclets.formats.html.markup.Entity; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; -import jdk.javadoc.internal.doclets.formats.html.markup.Text; -import jdk.javadoc.internal.doclets.formats.html.markup.TagName; -import jdk.javadoc.internal.doclets.toolkit.util.Utils; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; +import java.util.stream.Collectors; import javax.lang.model.element.Element; import javax.lang.model.element.ElementKind; @@ -43,12 +41,16 @@ import javax.lang.model.element.TypeElement; import javax.lang.model.type.TypeMirror; import javax.lang.model.util.ElementKindVisitor14; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; -import java.util.SortedSet; -import java.util.TreeSet; -import java.util.stream.Collectors; + +import jdk.javadoc.doclet.DocletEnvironment; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyles; +import jdk.javadoc.internal.doclets.toolkit.util.Utils; +import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.ContentBuilder; +import jdk.javadoc.internal.html.Entity; +import jdk.javadoc.internal.html.HtmlTag; +import jdk.javadoc.internal.html.HtmlTree; +import jdk.javadoc.internal.html.Text; import static javax.lang.model.element.Modifier.ABSTRACT; import static javax.lang.model.element.Modifier.FINAL; @@ -63,17 +65,17 @@ public class Signatures { public static Content getModuleSignature(ModuleElement mdle, ModuleWriter moduleWriter) { - var signature = HtmlTree.DIV(HtmlStyle.moduleSignature); + var signature = HtmlTree.DIV(HtmlStyles.moduleSignature); Content annotations = moduleWriter.getAnnotationInfo(mdle, true); if (!annotations.isEmpty()) { - signature.add(HtmlTree.SPAN(HtmlStyle.annotations, annotations)); + signature.add(HtmlTree.SPAN(HtmlStyles.annotations, annotations)); } DocletEnvironment docEnv = moduleWriter.configuration.docEnv; String label = mdle.isOpen() && (docEnv.getModuleMode() == DocletEnvironment.ModuleMode.ALL) ? "open module" : "module"; signature.add(label); signature.add(" "); - var nameSpan = HtmlTree.SPAN(HtmlStyle.elementName); + var nameSpan = HtmlTree.SPAN(HtmlStyles.elementName); nameSpan.add(mdle.getQualifiedName().toString()); signature.add(nameSpan); return signature; @@ -83,13 +85,13 @@ public static Content getPackageSignature(PackageElement pkg, PackageWriter pkgW if (pkg.isUnnamed()) { return Text.EMPTY; } - var signature = HtmlTree.DIV(HtmlStyle.packageSignature); + var signature = HtmlTree.DIV(HtmlStyles.packageSignature); Content annotations = pkgWriter.getAnnotationInfo(pkg, true); if (!annotations.isEmpty()) { - signature.add(HtmlTree.SPAN(HtmlStyle.annotations, annotations)); + signature.add(HtmlTree.SPAN(HtmlStyles.annotations, annotations)); } signature.add("package "); - var nameSpan = HtmlTree.SPAN(HtmlStyle.elementName); + var nameSpan = HtmlTree.SPAN(HtmlStyles.elementName); nameSpan.add(pkg.getQualifiedName().toString()); signature.add(nameSpan); return signature; @@ -122,16 +124,16 @@ public Content toContent() { Content content = new ContentBuilder(); Content annotationInfo = writer.getAnnotationInfo(typeElement, true); if (!annotationInfo.isEmpty()) { - content.add(HtmlTree.SPAN(HtmlStyle.annotations, annotationInfo)); + content.add(HtmlTree.SPAN(HtmlStyles.annotations, annotationInfo)); } - content.add(HtmlTree.SPAN(HtmlStyle.modifiers, modifiers)); + content.add(HtmlTree.SPAN(HtmlStyles.modifiers, modifiers)); - var nameSpan = HtmlTree.SPAN(HtmlStyle.elementName); + var nameSpan = HtmlTree.SPAN(HtmlStyles.elementName); Content className = Text.of(utils.getSimpleName(typeElement)); if (configuration.getOptions().linkSource()) { writer.addSrcLink(typeElement, className, nameSpan); } else { - nameSpan.addStyle(HtmlStyle.typeNameLabel).add(className); + nameSpan.addStyle(HtmlStyles.typeNameLabel).add(className); } HtmlLinkInfo linkInfo = new HtmlLinkInfo(configuration, HtmlLinkInfo.Kind.SHOW_TYPE_PARAMS_AND_BOUNDS, typeElement) @@ -144,7 +146,7 @@ public Content toContent() { content.add(getRecordComponents()); } if (!utils.isAnnotationInterface(typeElement)) { - var extendsImplements = HtmlTree.SPAN(HtmlStyle.extendsImplements); + var extendsImplements = HtmlTree.SPAN(HtmlStyles.extendsImplements); if (!utils.isPlainInterface(typeElement)) { TypeMirror superclass = utils.getFirstVisibleSuperClass(typeElement); if (superclass != null) { @@ -186,7 +188,7 @@ public Content toContent() { .filter(t -> utils.isLinkable(utils.asTypeElement(t))) .toList(); if (!linkablePermits.isEmpty()) { - var permitsSpan = HtmlTree.SPAN(HtmlStyle.permits); + var permitsSpan = HtmlTree.SPAN(HtmlStyles.permits); boolean isFirst = true; for (TypeMirror type : linkablePermits) { if (isFirst) { @@ -205,11 +207,11 @@ public Content toContent() { if (linkablePermits.size() < permits.size()) { Content c = Text.of(configuration.getDocResources().getText("doclet.not.exhaustive")); permitsSpan.add(" "); - permitsSpan.add(HtmlTree.SPAN(HtmlStyle.permitsNote, c)); + permitsSpan.add(HtmlTree.SPAN(HtmlStyles.permitsNote, c)); } content.add(permitsSpan); } - return HtmlTree.DIV(HtmlStyle.typeSignature, content); + return HtmlTree.DIV(HtmlStyles.typeSignature, content); } private Content getRecordComponents() { @@ -450,7 +452,7 @@ Content toContent() { // Annotations if (annotations != null && !annotations.isEmpty()) { - content.add(HtmlTree.SPAN(HtmlStyle.annotations, annotations)); + content.add(HtmlTree.SPAN(HtmlStyles.annotations, annotations)); lastLineSeparator = content.charCount(); } @@ -464,12 +466,12 @@ Content toContent() { // Return type if (returnType != null) { - content.add(HtmlTree.SPAN(HtmlStyle.returnType, returnType)); + content.add(HtmlTree.SPAN(HtmlStyles.returnType, returnType)); content.add(Entity.NO_BREAK_SPACE); } // Name - var nameSpan = HtmlTree.SPAN(HtmlStyle.elementName); + var nameSpan = HtmlTree.SPAN(HtmlStyles.elementName); if (memberWriter.options.linkSource()) { Content name = Text.of(memberWriter.name(element)); memberWriter.writer.addSrcLink(element, name, nameSpan); @@ -483,7 +485,7 @@ Content toContent() { appendParametersAndExceptions(content, lastLineSeparator); } - return HtmlTree.DIV(HtmlStyle.memberSignature, content); + return HtmlTree.DIV(HtmlStyles.memberSignature, content); } /** @@ -514,7 +516,7 @@ private void appendModifiers(Content target) { } if (!set.isEmpty()) { String mods = set.stream().map(Modifier::toString).collect(Collectors.joining(" ")); - target.add(HtmlTree.SPAN(HtmlStyle.modifiers, Text.of(mods))) + target.add(HtmlTree.SPAN(HtmlStyles.modifiers, Text.of(mods))) .add(Entity.NO_BREAK_SPACE); } } @@ -533,9 +535,9 @@ private int appendTypeParameters(Content target, int lastLineSeparator) { int typeParamLength = typeParameters.charCount(); if (typeParamLength >= TYPE_PARAMS_MAX_INLINE_LENGTH) { - target.add(HtmlTree.SPAN(HtmlStyle.typeParametersLong, typeParameters)); + target.add(HtmlTree.SPAN(HtmlStyles.typeParametersLong, typeParameters)); } else { - target.add(HtmlTree.SPAN(HtmlStyle.typeParameters, typeParameters)); + target.add(HtmlTree.SPAN(HtmlStyles.typeParameters, typeParameters)); } int lineLength = target.charCount() - lastLineSeparator; @@ -567,8 +569,8 @@ private void appendParametersAndExceptions(Content target, int lastLineSeparator // empty parameters are added without packing target.add(parameters); } else { - target.add(new HtmlTree(TagName.WBR)) - .add(HtmlTree.SPAN(HtmlStyle.parameters, parameters)); + target.add(new HtmlTree(HtmlTag.WBR)) + .add(HtmlTree.SPAN(HtmlStyles.parameters, parameters)); } // Exceptions @@ -577,7 +579,7 @@ private void appendParametersAndExceptions(Content target, int lastLineSeparator target.add(Text.NL) .add(indent) .add("throws ") - .add(HtmlTree.SPAN(HtmlStyle.exceptions, exceptions)); + .add(HtmlTree.SPAN(HtmlStyles.exceptions, exceptions)); } } } 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 6f1381a70ca4a..070b38421225b 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 @@ -25,8 +25,6 @@ package jdk.javadoc.internal.doclets.formats.html; -import jdk.javadoc.internal.doclets.formats.html.markup.Head; - import java.io.IOException; import java.io.LineNumberReader; import java.io.Reader; @@ -38,12 +36,9 @@ import javax.lang.model.element.TypeElement; import javax.tools.FileObject; +import jdk.javadoc.internal.doclets.formats.html.markup.Head; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlDocument; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlId; -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.markup.Text; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyles; import jdk.javadoc.internal.doclets.toolkit.Messages; import jdk.javadoc.internal.doclets.toolkit.Resources; import jdk.javadoc.internal.doclets.toolkit.util.DocFile; @@ -52,6 +47,11 @@ import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; import jdk.javadoc.internal.doclets.toolkit.util.SimpleDocletException; import jdk.javadoc.internal.doclets.toolkit.util.Utils; +import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.HtmlId; +import jdk.javadoc.internal.html.HtmlTag; +import jdk.javadoc.internal.html.HtmlTree; +import jdk.javadoc.internal.html.Text; /** * Converts Java Source Code to HTML. @@ -201,7 +201,7 @@ public void convertClass(TypeElement te, DocPath outputdir) .resolve(configuration.docPaths.forPackage(te)) .invert(); Content body = getHeader(); - var pre = new HtmlTree(TagName.PRE); + var pre = new HtmlTree(HtmlTag.PRE); try (var reader = new LineNumberReader(r)) { while ((line = reader.readLine()) != null) { addLineNo(pre, lineno); @@ -210,7 +210,7 @@ public void convertClass(TypeElement te, DocPath outputdir) } } addBlankLines(pre); - var div = HtmlTree.DIV(HtmlStyle.sourceContainer, pre); + var div = HtmlTree.DIV(HtmlStyles.sourceContainer, pre); body.add(HtmlTree.MAIN(div)); writeToFile(body, outputdir.resolve(configuration.docPaths.forClass(te)), te); } catch (IOException e) { @@ -246,7 +246,7 @@ private void writeToFile(Content body, DocPath path, TypeElement te) throws DocF * @return the header content for the HTML file */ private static Content getHeader() { - return new HtmlTree(TagName.BODY).setStyle(HtmlStyle.sourcePage); + return new HtmlTree(HtmlTag.BODY).setStyle(HtmlStyles.sourcePage); } /** @@ -256,7 +256,7 @@ private static Content getHeader() { * @param lineno The line number */ private static void addLineNo(Content pre, int lineno) { - var span = HtmlTree.SPAN(HtmlStyle.sourceLineNo); + var span = HtmlTree.SPAN(HtmlStyles.sourceLineNo); if (lineno < 10) { span.add("00" + lineno); } else if (lineno < 100) { diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SubWriterHolderWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SubWriterHolderWriter.java index 3926d4e9a4c13..0876a1611cdb6 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SubWriterHolderWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SubWriterHolderWriter.java @@ -25,20 +25,23 @@ package jdk.javadoc.internal.doclets.formats.html; -import java.util.*; +import java.util.List; import javax.lang.model.element.Element; import javax.lang.model.element.TypeElement; import com.sun.source.doctree.DeprecatedTree; import com.sun.source.doctree.DocTree; + import jdk.javadoc.internal.doclets.formats.html.markup.BodyContents; -import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlId; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyles; import jdk.javadoc.internal.doclets.toolkit.PropertyUtils; import jdk.javadoc.internal.doclets.toolkit.util.DocPath; +import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.ContentBuilder; +import jdk.javadoc.internal.html.HtmlId; +import jdk.javadoc.internal.html.HtmlStyle; +import jdk.javadoc.internal.html.HtmlTree; /** * This abstract class exists to provide functionality needed in the @@ -117,8 +120,8 @@ protected void addIndexComment(Element member, List firstSent List deprs = utils.getDeprecatedTrees(member); Content div; if (utils.isDeprecated(member)) { - var deprLabel = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(member)); - div = HtmlTree.DIV(HtmlStyle.block, deprLabel); + var deprLabel = HtmlTree.SPAN(HtmlStyles.deprecatedLabel, getDeprecatedPhrase(member)); + div = HtmlTree.DIV(HtmlStyles.block, deprLabel); if (!deprs.isEmpty()) { addSummaryDeprecatedComment(member, deprs.get(0), div); } @@ -127,8 +130,8 @@ protected void addIndexComment(Element member, List firstSent } else { Element te = member.getEnclosingElement(); if (te != null && utils.isTypeElement(te) && utils.isDeprecated(te)) { - var deprLabel = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(te)); - div = HtmlTree.DIV(HtmlStyle.block, deprLabel); + var deprLabel = HtmlTree.SPAN(HtmlStyles.deprecatedLabel, getDeprecatedPhrase(te)); + div = HtmlTree.DIV(HtmlStyles.block, deprLabel); tdSummaryContent.add(div); } } @@ -200,7 +203,7 @@ public void addClassContent(Content classContent) { * @return a list to be used for the list of summaries for members of a given kind */ public Content getSummariesList() { - return HtmlTree.UL(HtmlStyle.summaryList); + return HtmlTree.UL(HtmlStyles.summaryList); } /** @@ -219,7 +222,7 @@ public Content getSummariesListItem(Content content) { * @return a list to be used for the list of details for members of a given kind */ public Content getDetailsList() { - return HtmlTree.UL(HtmlStyle.detailsList); + return HtmlTree.UL(HtmlStyles.detailsList); } /** @@ -236,7 +239,7 @@ public Content getDetailsListItem(Content content) { * {@return a list to add member items to} */ public Content getMemberList() { - return HtmlTree.UL(HtmlStyle.memberList); + return HtmlTree.UL(HtmlStyles.memberList); } /** @@ -249,7 +252,7 @@ public Content getMemberListItem(Content member) { } public Content getMemberInherited() { - return HtmlTree.DIV(HtmlStyle.inheritedList); + return HtmlTree.DIV(HtmlStyles.inheritedList); } /** @@ -281,7 +284,7 @@ public Content getMember(Content content) { * @param memberContent the content used to generate the member summary */ public Content getMemberSummary(Content memberContent) { - return HtmlTree.SECTION(HtmlStyle.summary, memberContent); + return HtmlTree.SECTION(HtmlStyles.summary, memberContent); } /** diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SummaryListWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SummaryListWriter.java index ffe0350678de3..8d2f621e5d455 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SummaryListWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SummaryListWriter.java @@ -31,18 +31,20 @@ import javax.lang.model.element.ModuleElement; import javax.lang.model.element.PackageElement; -import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlAttr; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlId; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; -import jdk.javadoc.internal.doclets.formats.html.markup.Script; -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.formats.html.markup.HtmlStyles; import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException; import jdk.javadoc.internal.doclets.toolkit.util.DocPath; import jdk.javadoc.internal.doclets.toolkit.util.SummaryAPIListBuilder; import jdk.javadoc.internal.doclets.toolkit.util.SummaryAPIListBuilder.SummaryElementKind; +import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.ContentBuilder; +import jdk.javadoc.internal.html.HtmlAttr; +import jdk.javadoc.internal.html.HtmlId; +import jdk.javadoc.internal.html.HtmlStyle; +import jdk.javadoc.internal.html.HtmlTree; +import jdk.javadoc.internal.html.Script; +import jdk.javadoc.internal.html.Text; /** * Base class for generating a summary page that lists elements with a common characteristic, @@ -139,8 +141,8 @@ public void buildPage() throws DocFileIOException { HtmlTree body = getHeader(getPageMode(), getTitleKey()); Content content = new ContentBuilder(); var heading = HtmlTree.HEADING_TITLE(Headings.PAGE_TITLE_HEADING, - HtmlStyle.title, getHeadContent()); - content.add(HtmlTree.DIV(HtmlStyle.header, heading)); + HtmlStyles.title, getHeadContent()); + content.add(HtmlTree.DIV(HtmlStyles.header, heading)); addContentSelectors(content); if (showContentsList()) { content.add(HtmlTree.HEADING_TITLE(Headings.CONTENT_HEADING, contents.contentsHeading)); @@ -201,7 +203,7 @@ protected boolean showContentsList() { * @return the contents list */ public Content getContentsList() { - var ul= HtmlTree.UL(HtmlStyle.contentsList); + var ul= HtmlTree.UL(HtmlStyles.contentsList); addExtraIndexLink(ul); for (SummaryElementKind kind : SummaryElementKind.values()) { if (builder.hasDocumentation(kind)) { @@ -238,7 +240,7 @@ protected void addSummaryAPI(SortedSet apiList, HtmlId id, if (apiList.size() > 0) { TableHeader tableHeader = getTableHeader(headerKey); - var table = new Table(HtmlStyle.summaryTable) + var table = new Table(HtmlStyles.summaryTable) .setCaption(getTableCaption(headingKey)) .setHeader(tableHeader) .setId(id) @@ -267,7 +269,7 @@ protected void addSummaryAPI(SortedSet apiList, HtmlId id, } } // note: singleton list - content.add(HtmlTree.UL(HtmlStyle.blockList, HtmlTree.LI(table))); + content.add(HtmlTree.UL(HtmlStyles.blockList, HtmlTree.LI(table))); } } @@ -370,7 +372,7 @@ protected TableHeader getTableHeader(String headerKey) { * @return the styles to use for table columns */ protected HtmlStyle[] getColumnStyles() { - return new HtmlStyle[]{ HtmlStyle.colSummaryItemName, HtmlStyle.colLast }; + return new HtmlStyle[]{ HtmlStyles.colSummaryItemName, HtmlStyles.colLast }; } /** diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SystemPropertiesWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SystemPropertiesWriter.java index 45985532ad6fb..d7aacd3ab0ff5 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SystemPropertiesWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SystemPropertiesWriter.java @@ -38,15 +38,16 @@ import jdk.javadoc.internal.doclets.formats.html.Navigation.PageMode; import jdk.javadoc.internal.doclets.formats.html.markup.BodyContents; -import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; -import jdk.javadoc.internal.doclets.formats.html.markup.Text; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyles; import jdk.javadoc.internal.doclets.toolkit.DocFileElement; import jdk.javadoc.internal.doclets.toolkit.OverviewElement; import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException; import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; import jdk.javadoc.internal.doclets.toolkit.util.IndexItem; +import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.ContentBuilder; +import jdk.javadoc.internal.html.HtmlTree; +import jdk.javadoc.internal.html.Text; import static java.util.stream.Collectors.groupingBy; @@ -86,7 +87,7 @@ public void buildPage() throws DocFileIOException { addSystemProperties(mainContent); body.add(new BodyContents() .setHeader(getHeader(PageMode.SYSTEM_PROPERTIES)) - .addMainContent(HtmlTree.DIV(HtmlStyle.header, + .addMainContent(HtmlTree.DIV(HtmlStyles.header, HtmlTree.HEADING(Headings.PAGE_TITLE_HEADING, contents.getContent("doclet.systemProperties")))) .addMainContent(mainContent) @@ -106,10 +107,10 @@ public void buildPage() throws DocFileIOException { protected void addSystemProperties(Content target) { Map> searchIndexMap = groupSystemProperties(); Content separator = Text.of(", "); - var table = new Table(HtmlStyle.summaryTable) + var table = new Table(HtmlStyles.summaryTable) .setCaption(contents.systemPropertiesSummaryLabel) .setHeader(new TableHeader(contents.propertyLabel, contents.referencedIn)) - .setColumnStyles(HtmlStyle.colFirst, HtmlStyle.colLast); + .setColumnStyles(HtmlStyles.colFirst, HtmlStyles.colLast); for (Entry> entry : searchIndexMap.entrySet()) { Content propertyName = Text.of(entry.getKey()); List searchIndexItems = entry.getValue(); @@ -119,7 +120,7 @@ protected void addSystemProperties(Content target) { separatedReferenceLinks.add(separator); separatedReferenceLinks.add(createLink(searchIndexItems.get(i))); } - table.addRow(propertyName, HtmlTree.DIV(HtmlStyle.block, separatedReferenceLinks)); + table.addRow(propertyName, HtmlTree.DIV(HtmlStyles.block, separatedReferenceLinks)); } target.add(table); } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Table.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Table.java index 339cfbf6f727f..5d09682d4920b 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Table.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Table.java @@ -34,13 +34,15 @@ import java.util.Set; import java.util.function.Predicate; -import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlAttr; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlId; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; -import jdk.javadoc.internal.doclets.formats.html.markup.TagName; -import jdk.javadoc.internal.doclets.formats.html.markup.Text; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyles; +import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.ContentBuilder; +import jdk.javadoc.internal.html.HtmlAttr; +import jdk.javadoc.internal.html.HtmlId; +import jdk.javadoc.internal.html.HtmlStyle; +import jdk.javadoc.internal.html.HtmlTag; +import jdk.javadoc.internal.html.HtmlTree; +import jdk.javadoc.internal.html.Text; /** * An HTML container used to display summary tables for various kinds of elements @@ -303,7 +305,7 @@ public void addRow(T item, List contents) { Content row = new ContentBuilder(); int rowIndex = bodyRows.size(); - HtmlStyle rowStyle = rowIndex % 2 == 0 ? HtmlStyle.evenRowColor : HtmlStyle.oddRowColor; + HtmlStyle rowStyle = rowIndex % 2 == 0 ? HtmlStyles.evenRowColor : HtmlStyles.oddRowColor; List tabClasses = new ArrayList<>(); if (tabs != null) { @@ -359,16 +361,16 @@ public boolean write(Writer out, String newline, boolean atNewline) throws IOExc private Content toContent() { Content main; if (id != null) { - main = new HtmlTree(TagName.DIV).setId(id); + main = new HtmlTree(HtmlTag.DIV).setId(id); } else { main = new ContentBuilder(); } // If no grid style is set use on of the default styles if (gridStyle == null) { gridStyle = switch (columnStyles.size()) { - case 2 -> HtmlStyle.twoColumnSummary; - case 3 -> HtmlStyle.threeColumnSummary; - case 4 -> HtmlStyle.fourColumnSummary; + case 2 -> HtmlStyles.twoColumnSummary; + case 3 -> HtmlStyles.threeColumnSummary; + case 4 -> HtmlStyles.fourColumnSummary; default -> throw new IllegalStateException(); }; } @@ -383,16 +385,16 @@ private Content toContent() { table.add(getTableBody()); main.add(table); } else { - var tablist = HtmlTree.DIV(HtmlStyle.tableTabs) + var tablist = HtmlTree.DIV(HtmlStyles.tableTabs) .put(HtmlAttr.ROLE, "tablist") .put(HtmlAttr.ARIA_ORIENTATION, "horizontal"); HtmlId defaultTabId = HtmlIds.forTab(id, 0); if (renderTabs) { - tablist.add(createTab(defaultTabId, HtmlStyle.activeTableTab, true, defaultTab)); + tablist.add(createTab(defaultTabId, HtmlStyles.activeTableTab, true, defaultTab)); for (var tab : tabs) { if (occurringTabs.contains(tab)) { - tablist.add(createTab(HtmlIds.forTab(id, tab.index()), HtmlStyle.tableTab, false, tab.label())); + tablist.add(createTab(HtmlIds.forTab(id, tab.index()), HtmlStyles.tableTab, false, tab.label())); } } } else { @@ -401,7 +403,7 @@ private Content toContent() { if (id == null) { throw new IllegalStateException("no id set for table"); } - var tabpanel = new HtmlTree(TagName.DIV) + var tabpanel = new HtmlTree(HtmlTag.DIV) .setId(HtmlIds.forTabPanel(id)) .put(HtmlAttr.ROLE, "tabpanel") .put(HtmlAttr.ARIA_LABELLEDBY, defaultTabId.name()); @@ -414,7 +416,7 @@ private Content toContent() { } private HtmlTree createTab(HtmlId tabId, HtmlStyle style, boolean defaultTab, Content tabLabel) { - var tab = new HtmlTree(TagName.BUTTON) + var tab = new HtmlTree(HtmlTag.BUTTON) .setId(tabId) .put(HtmlAttr.ROLE, "tab") .put(HtmlAttr.ARIA_SELECTED, defaultTab ? "true" : "false") @@ -436,6 +438,6 @@ private Content getTableBody() { } private HtmlTree getCaption(Content title) { - return HtmlTree.DIV(HtmlStyle.caption, HtmlTree.SPAN(title)); + return HtmlTree.DIV(HtmlStyles.caption, HtmlTree.SPAN(title)); } } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TableHeader.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TableHeader.java index a505797764e33..e1c42062c2190 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TableHeader.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TableHeader.java @@ -30,10 +30,12 @@ import java.util.Arrays; import java.util.List; -import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlAttr; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyles; +import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.ContentBuilder; +import jdk.javadoc.internal.html.HtmlAttr; +import jdk.javadoc.internal.html.HtmlStyle; +import jdk.javadoc.internal.html.HtmlTree; /** * A row of header cells for an HTML table. @@ -152,10 +154,10 @@ private Content toContent() { int i = 0; for (Content cellContent : cellContents) { HtmlStyle style = (styles != null) ? styles.get(i) - : (i == 0) ? HtmlStyle.colFirst - : (i == (cellContents.size() - 1)) ? HtmlStyle.colLast - : (i == 1) ? HtmlStyle.colSecond : null; - var cell = HtmlTree.DIV(HtmlStyle.tableHeader, cellContent); + : (i == 0) ? HtmlStyles.colFirst + : (i == (cellContents.size() - 1)) ? HtmlStyles.colLast + : (i == 1) ? HtmlStyles.colSecond : null; + var cell = HtmlTree.DIV(HtmlStyles.tableHeader, cellContent); if (style != null) { cell.addStyle(style); } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TableOfContents.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TableOfContents.java index 7cfbffb6cee02..a9036d7dcd856 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TableOfContents.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TableOfContents.java @@ -24,14 +24,15 @@ */ package jdk.javadoc.internal.doclets.formats.html; -import jdk.javadoc.internal.doclets.formats.html.markup.Entity; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlAttr; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlId; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; -import jdk.javadoc.internal.doclets.formats.html.markup.ListBuilder; -import jdk.javadoc.internal.doclets.formats.html.markup.TagName; -import jdk.javadoc.internal.doclets.formats.html.markup.Text; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyles; +import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.Entity; +import jdk.javadoc.internal.html.HtmlAttr; +import jdk.javadoc.internal.html.HtmlId; +import jdk.javadoc.internal.html.HtmlTag; +import jdk.javadoc.internal.html.HtmlTree; +import jdk.javadoc.internal.html.ListBuilder; +import jdk.javadoc.internal.html.Text; /** * A class used by various {@link HtmlDocletWriter} subclasses to build tables of contents. @@ -46,7 +47,7 @@ public class TableOfContents { */ public TableOfContents(HtmlDocletWriter writer) { this.writer = writer; - listBuilder = new ListBuilder(HtmlTree.OL(HtmlStyle.tocList)); + listBuilder = new ListBuilder(HtmlTree.OL(HtmlStyles.tocList)); } /** @@ -64,7 +65,7 @@ public TableOfContents addLink(HtmlId id, Content label) { * Adds a new nested list to add new items to. */ public void pushNestedList() { - listBuilder.pushNestedList(HtmlTree.OL(HtmlStyle.tocList)); + listBuilder.pushNestedList(HtmlTree.OL(HtmlStyles.tocList)); } /** @@ -87,23 +88,23 @@ protected Content toContent(boolean hasFilterInput) { return Text.EMPTY; } var content = HtmlTree.NAV() - .setStyle(HtmlStyle.toc) + .setStyle(HtmlStyles.toc) .put(HtmlAttr.ARIA_LABEL, writer.resources.getText("doclet.table_of_contents")); - var header = HtmlTree.DIV(HtmlStyle.tocHeader, writer.contents.contentsHeading); + var header = HtmlTree.DIV(HtmlStyles.tocHeader, writer.contents.contentsHeading); if (hasFilterInput) { header.add(Entity.NO_BREAK_SPACE) - .add(HtmlTree.INPUT(HtmlAttr.InputType.TEXT, HtmlStyle.filterInput) + .add(HtmlTree.INPUT(HtmlAttr.InputType.TEXT, HtmlStyles.filterInput) .put(HtmlAttr.PLACEHOLDER, writer.resources.getText("doclet.filter_label")) .put(HtmlAttr.ARIA_LABEL, writer.resources.getText("doclet.filter_table_of_contents")) .put(HtmlAttr.AUTOCOMPLETE, "off")) - .add(HtmlTree.INPUT(HtmlAttr.InputType.RESET, HtmlStyle.resetFilter) + .add(HtmlTree.INPUT(HtmlAttr.InputType.RESET, HtmlStyles.resetFilter) .put(HtmlAttr.VALUE, writer.resources.getText("doclet.filter_reset"))); } content.add(header); - content.add(new HtmlTree(TagName.BUTTON).addStyle(HtmlStyle.hideSidebar) + content.add(new HtmlTree(HtmlTag.BUTTON).addStyle(HtmlStyles.hideSidebar) .add(HtmlTree.SPAN(writer.contents.hideSidebar).add(Entity.NO_BREAK_SPACE)) .add(Entity.LEFT_POINTING_ANGLE)); - content.add(new HtmlTree(TagName.BUTTON).addStyle(HtmlStyle.showSidebar) + content.add(new HtmlTree(HtmlTag.BUTTON).addStyle(HtmlStyles.showSidebar) .add(Entity.RIGHT_POINTING_ANGLE) .add(HtmlTree.SPAN(Entity.NO_BREAK_SPACE).add(writer.contents.showSidebar))); return content.add(listBuilder); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TreeWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TreeWriter.java index c5e0329e9e684..8af3b7016cecb 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TreeWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TreeWriter.java @@ -29,15 +29,16 @@ import javax.lang.model.element.PackageElement; -import jdk.javadoc.internal.doclets.formats.html.markup.BodyContents; -import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; -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.BodyContents; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyles; import jdk.javadoc.internal.doclets.toolkit.util.ClassTree; import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException; import jdk.javadoc.internal.doclets.toolkit.util.DocPath; import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; +import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.ContentBuilder; +import jdk.javadoc.internal.html.HtmlTree; /** * Generate Class Hierarchy page for all the Classes in this run. Use @@ -78,8 +79,8 @@ public void buildPage() throws DocFileIOException { HtmlTree body = getBody(); Content headContent = contents.hierarchyForAllPackages; var heading = HtmlTree.HEADING(Headings.PAGE_TITLE_HEADING, - HtmlStyle.title, headContent); - var div = HtmlTree.DIV(HtmlStyle.header, heading); + HtmlStyles.title, headContent); + var div = HtmlTree.DIV(HtmlStyles.header, heading); Content mainContent = new ContentBuilder(); mainContent.add(div); addPackageTreeLinks(mainContent); @@ -105,10 +106,10 @@ protected void addPackageTreeLinks(Content content) { return; } if (!classesOnly) { - var span = HtmlTree.SPAN(HtmlStyle.packageHierarchyLabel, + var span = HtmlTree.SPAN(HtmlStyles.packageHierarchyLabel, contents.packageHierarchies); content.add(span); - var ul = HtmlTree.UL(HtmlStyle.horizontal).addStyle(HtmlStyle.contentsList); + var ul = HtmlTree.UL(HtmlStyles.horizontal).addStyle(HtmlStyles.contentsList); int i = 0; for (PackageElement pkg : packages) { // If the package name length is 0 or if -nodeprecated option diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/BodyContents.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/BodyContents.java index 71bf1f265cfb2..d7c865b8350fd 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/BodyContents.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/BodyContents.java @@ -25,14 +25,17 @@ package jdk.javadoc.internal.doclets.formats.html.markup; -import jdk.javadoc.internal.doclets.formats.html.Content; - import java.io.IOException; import java.io.Writer; import java.util.ArrayList; import java.util.List; import java.util.Objects; +import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.ContentBuilder; +import jdk.javadoc.internal.html.HtmlTree; +import jdk.javadoc.internal.html.Text; + /** * Content for the {@code } element. * @@ -96,7 +99,7 @@ private Content toContent() { return new ContentBuilder() .add(header) - .add(HtmlTree.DIV(HtmlStyle.mainGrid) + .add(HtmlTree.DIV(HtmlStyles.mainGrid) .add(side == null ? Text.EMPTY : side) .add(HtmlTree.MAIN() .add(mainContents) diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Head.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Head.java index c4a223a94c73b..3d5b1a494ba2c 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Head.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Head.java @@ -34,10 +34,15 @@ import java.util.List; import java.util.Locale; -import jdk.javadoc.internal.doclets.formats.html.Content; import jdk.javadoc.internal.doclets.formats.html.HtmlConfiguration; import jdk.javadoc.internal.doclets.toolkit.util.DocPath; import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; +import jdk.javadoc.internal.html.Comment; +import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.HtmlAttr; +import jdk.javadoc.internal.html.HtmlTag; +import jdk.javadoc.internal.html.HtmlTree; +import jdk.javadoc.internal.html.Script; /** * An HTML {@code } element. @@ -267,7 +272,7 @@ public boolean write(Writer out, String newline, boolean atNewline) throws IOExc * @return the HTML */ private Content toContent() { - var head = new HtmlTree(TagName.HEAD); + var head = new HtmlTree(HtmlTag.HEAD); head.add(getGeneratedBy(showTimestamp, generatedDate)); head.add(HtmlTree.TITLE(title)); @@ -295,7 +300,7 @@ private Content toContent() { } if (canonicalLink != null) { - var link = new HtmlTree(TagName.LINK); + var link = new HtmlTree(HtmlTag.LINK); link.put(HtmlAttr.REL, "canonical"); link.put(HtmlAttr.HREF, canonicalLink.getPath()); head.add(link); 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 deleted file mode 100644 index 1d0d54a05252c..0000000000000 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlAttr.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (c) 2010, 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.javadoc.internal.doclets.formats.html.markup; - -import jdk.javadoc.internal.doclets.toolkit.util.Utils; - -/** - * Enum representing HTML tag attributes. - */ -public enum HtmlAttr { - ALT, - ARIA_CONTROLS("aria-controls"), - ARIA_EXPANDED("aria-expanded"), - ARIA_LABEL("aria-label"), - ARIA_LABELLEDBY("aria-labelledby"), - ARIA_ORIENTATION("aria-orientation"), - ARIA_SELECTED("aria-selected"), - AUTOCOMPLETE, - CHECKED, - CLASS, - CLEAR, - COLS, - CONTENT, - DATA_COPIED("data-copied"), // custom HTML5 data attribute - DISABLED, - FOR, - HREF, - HTTP_EQUIV("http-equiv"), - ID, - LANG, - NAME, - ONCLICK, - ONKEYDOWN, - ONLOAD, - PLACEHOLDER, - REL, - ROLE, - ROWS, - SCOPE, - SCROLLING, - SRC, - STYLE, - SUMMARY, - TABINDEX, - TARGET, - TITLE, - TYPE, - VALUE, - WIDTH; - - private final String value; - - public enum Role { - - BANNER, - CONTENTINFO, - MAIN, - NAVIGATION, - REGION; - - private final String role; - - Role() { - role = Utils.toLowerCase(name()); - } - - public String toString() { - return role; - } - } - - public enum InputType { - - CHECKBOX, - RESET, - TEXT; - - private final String type; - - InputType() { - type = Utils.toLowerCase(name()); - } - - public String toString() { - return type; - } - } - - HtmlAttr() { - this.value = Utils.toLowerCase(name()); - } - - HtmlAttr(String name) { - this.value = name; - } - - public String toString() { - return value; - } -} diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlDocument.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlDocument.java index dcfed8707dd17..051cbfd00423b 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlDocument.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlDocument.java @@ -29,9 +29,11 @@ import java.io.StringWriter; import java.io.Writer; -import jdk.javadoc.internal.doclets.formats.html.Content; import jdk.javadoc.internal.doclets.toolkit.util.DocFile; import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException; +import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.DocType; +import jdk.javadoc.internal.html.HtmlTag; /** * Class for generating an HTML document for javadoc output. @@ -43,7 +45,7 @@ public class HtmlDocument { /** * Constructs an HTML document. * - * @param html the {@link TagName#HTML HTML} element of the document + * @param html the {@link HtmlTag#HTML HTML} element of the document */ public HtmlDocument(Content html) { docContent = html; 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/HtmlStyles.java similarity index 99% rename from src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlStyle.java rename to src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlStyles.java index 35a52b0c05dd1..35240fa69dabc 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/HtmlStyles.java @@ -28,6 +28,8 @@ import java.util.Locale; import java.util.regex.Pattern; +import jdk.javadoc.internal.html.HtmlStyle; + /** * Enum representing HTML styles, with associated entries in the stylesheet files. * @@ -49,7 +51,7 @@ * * @see WhatWG: {@code class} attribute */ -public enum HtmlStyle { +public enum HtmlStyles implements HtmlStyle { // // @@ -1098,13 +1100,13 @@ public enum HtmlStyle { private final String cssName; - HtmlStyle() { + HtmlStyles() { cssName = Pattern.compile("\\p{Upper}") .matcher(toString()) .replaceAll(mr -> "-" + mr.group().toLowerCase(Locale.US)); } - HtmlStyle(String cssName) { + HtmlStyles(String cssName) { this.cssName = cssName; } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Links.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Links.java index a0bd0b3dd044a..0af2913565465 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Links.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Links.java @@ -25,9 +25,14 @@ package jdk.javadoc.internal.doclets.formats.html.markup; -import jdk.javadoc.internal.doclets.formats.html.Content; import jdk.javadoc.internal.doclets.toolkit.util.DocLink; import jdk.javadoc.internal.doclets.toolkit.util.DocPath; +import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.HtmlAttr; +import jdk.javadoc.internal.html.HtmlId; +import jdk.javadoc.internal.html.HtmlStyle; +import jdk.javadoc.internal.html.HtmlTree; +import jdk.javadoc.internal.html.Text; /** * Factory for HTML A elements: links (with a {@code href} attribute). @@ -197,7 +202,7 @@ public HtmlTree createLink(DocLink link, Content label, HtmlStyle style, } if (isExternal) { // Use addStyle as external links might have an explicit style set above as well. - l.addStyle(HtmlStyle.externalLink); + l.addStyle(HtmlStyles.externalLink); } return l; } @@ -211,6 +216,6 @@ public HtmlTree createLink(DocLink link, Content label, HtmlStyle style, */ public HtmlTree createExternalLink(DocLink link, Content label) { return HtmlTree.A(link.relativizeAgainst(file).toString(), label) - .setStyle(HtmlStyle.externalLink); + .setStyle(HtmlStyles.externalLink); } } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/TagName.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/TagName.java deleted file mode 100644 index d849c2f1798ba..0000000000000 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/TagName.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (c) 2010, 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.javadoc.internal.doclets.formats.html.markup; - -import java.util.Locale; - -import jdk.javadoc.internal.doclets.toolkit.util.Utils; - -/** - * Enum representing the names for HTML elements. - * - * @see WhatWG: Tag Name - * @see HTML 5.1: Tag Name - */ -public enum TagName { - A(true), - ASIDE, - BUTTON(true), - BLOCKQUOTE, - BODY, - BR(true), - CAPTION, - CODE(true), - DD, - DETAILS, - DIV, - DL, - DT, - EM(true), - FOOTER, - FORM, - H1, - H2, - H3, - H4, - H5, - H6, - HEAD, - HEADER, - HR, - HTML, - I(true), - IMG(true), - INPUT(true), - LABEL(true), - LI, - LISTING, - LINK(true), - MAIN, - MENU, - META, - NAV, - NOSCRIPT(true), - OL, - P, - PRE, - SCRIPT(true), - SECTION, - SMALL(true), - SPAN(true), - STRONG(true), - SUB(true), - SUMMARY, - SUP(true), - TABLE, - TBODY, - THEAD, - TD, - TH, - TITLE, - TR, - UL, - WBR(true); - - public final String value; - public final boolean phrasingContent; - - static TagName of(String s) { - return valueOf(s.toUpperCase(Locale.ROOT)); - } - - TagName() { - this(false); - } - - TagName(boolean phrasingContent) { - this.value = Utils.toLowerCase(name()); - this.phrasingContent = phrasingContent; - } - - public String toString() { - return value; - } - -} diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/package-info.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/package-info.java index aa279972f8c6a..efad5fc0fe925 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/package-info.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/package-info.java @@ -27,7 +27,7 @@ * This package contains classes that create and write HTML markup tags. * *

The primary low level classes are - * {@link jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree HtmlTree} + * {@link jdk.javadoc.internal.html.HtmlTree HtmlTree} * and other subtypes of {@code Content}. In addition, there are mid-level builders * like {@link jdk.javadoc.internal.doclets.formats.html.TableHeader TableHeader} * and {@link jdk.javadoc.internal.doclets.formats.html.Table Table} diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/BaseTaglet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/BaseTaglet.java index bda31883f35de..7b0a4329ee1c7 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/BaseTaglet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/BaseTaglet.java @@ -33,10 +33,10 @@ import jdk.javadoc.doclet.Taglet.Location; import jdk.javadoc.internal.doclets.formats.html.HtmlConfiguration; -import jdk.javadoc.internal.doclets.formats.html.Content; import jdk.javadoc.internal.doclets.toolkit.Messages; import jdk.javadoc.internal.doclets.toolkit.Resources; import jdk.javadoc.internal.doclets.toolkit.util.Utils; +import jdk.javadoc.internal.html.Content; /** * A base class that implements the {@link Taglet} interface. diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/DeprecatedTaglet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/DeprecatedTaglet.java index d586b697bd771..fa30589e59d3d 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/DeprecatedTaglet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/DeprecatedTaglet.java @@ -35,11 +35,11 @@ import jdk.javadoc.doclet.Taglet; import jdk.javadoc.internal.doclets.formats.html.HtmlConfiguration; -import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; -import jdk.javadoc.internal.doclets.formats.html.Content; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyles; import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper; +import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.ContentBuilder; +import jdk.javadoc.internal.html.HtmlTree; /** * A taglet that represents the {@code @deprecated} tag. @@ -61,7 +61,7 @@ public Content getAllBlockTagOutput(Element element, TagletWriter tagletWriter) List deprs = utils.getDeprecatedTrees(element); if (utils.isTypeElement(element)) { if (utils.isDeprecated(element)) { - result.add(HtmlTree.SPAN(HtmlStyle.deprecatedLabel, + result.add(HtmlTree.SPAN(HtmlStyles.deprecatedLabel, htmlWriter.getDeprecatedPhrase(element))); if (!deprs.isEmpty()) { List commentTrees = ch.getDescription(deprs.get(0)); @@ -72,18 +72,18 @@ public Content getAllBlockTagOutput(Element element, TagletWriter tagletWriter) } } else { if (utils.isDeprecated(element)) { - result.add(HtmlTree.SPAN(HtmlStyle.deprecatedLabel, + result.add(HtmlTree.SPAN(HtmlStyles.deprecatedLabel, htmlWriter.getDeprecatedPhrase(element))); if (!deprs.isEmpty()) { List bodyTrees = ch.getBody(deprs.get(0)); Content body = tagletWriter.commentTagsToOutput(element, null, bodyTrees, false); if (!body.isEmpty()) - result.add(HtmlTree.DIV(HtmlStyle.deprecationComment, body)); + result.add(HtmlTree.DIV(HtmlStyles.deprecationComment, body)); } } else { Element ee = utils.getEnclosingTypeElement(element); if (utils.isDeprecated(ee)) { - result.add(HtmlTree.SPAN(HtmlStyle.deprecatedLabel, + result.add(HtmlTree.SPAN(HtmlStyles.deprecatedLabel, htmlWriter.getDeprecatedPhrase(ee))); } } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/DocRootTaglet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/DocRootTaglet.java index 94d701f7441e5..d4050f6e0ec26 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/DocRootTaglet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/DocRootTaglet.java @@ -33,8 +33,8 @@ import jdk.javadoc.doclet.Taglet; import jdk.javadoc.internal.doclets.formats.html.HtmlConfiguration; -import jdk.javadoc.internal.doclets.formats.html.markup.Text; -import jdk.javadoc.internal.doclets.formats.html.Content; +import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.Text; /** * An inline taglet representing {@code {@docRoot}}. This taglet is diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/IndexTaglet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/IndexTaglet.java index 4361dd5c1ef0c..6f5077bb32c1f 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/IndexTaglet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/IndexTaglet.java @@ -35,7 +35,7 @@ import jdk.javadoc.doclet.Taglet; import jdk.javadoc.internal.doclets.formats.html.HtmlConfiguration; -import jdk.javadoc.internal.doclets.formats.html.Content; +import jdk.javadoc.internal.html.Content; /** * An inline taglet used to index a word or a phrase. diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/InheritDocTaglet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/InheritDocTaglet.java index b7b937a5fc6bd..b05bb144f1b0b 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/InheritDocTaglet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/InheritDocTaglet.java @@ -39,12 +39,12 @@ import jdk.javadoc.doclet.Taglet.Location; import jdk.javadoc.internal.doclets.formats.html.HtmlConfiguration; -import jdk.javadoc.internal.doclets.formats.html.Content; import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper; import jdk.javadoc.internal.doclets.toolkit.util.DocFinder; import jdk.javadoc.internal.doclets.toolkit.util.DocFinder.Result; import jdk.javadoc.internal.doclets.toolkit.util.Utils; import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable; +import jdk.javadoc.internal.html.Content; /** * A taglet that represents the {@code {@inheritDoc}} tag. diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/LinkTaglet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/LinkTaglet.java index 1b02c9ea05e07..e16acd0315ad7 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/LinkTaglet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/LinkTaglet.java @@ -46,12 +46,12 @@ import jdk.javadoc.internal.doclets.formats.html.ClassWriter; import jdk.javadoc.internal.doclets.formats.html.HtmlConfiguration; import jdk.javadoc.internal.doclets.formats.html.HtmlLinkInfo; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; -import jdk.javadoc.internal.doclets.formats.html.markup.Text; -import jdk.javadoc.internal.doclets.formats.html.Content; import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper; import jdk.javadoc.internal.doclets.toolkit.util.DocLink; import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable; +import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.HtmlTree; +import jdk.javadoc.internal.html.Text; import static com.sun.source.doctree.DocTree.Kind.LINK; import static com.sun.source.doctree.DocTree.Kind.LINK_PLAIN; diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/LiteralTaglet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/LiteralTaglet.java index 1d209427c214d..c0543026f23dd 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/LiteralTaglet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/LiteralTaglet.java @@ -34,9 +34,9 @@ import jdk.javadoc.doclet.Taglet; import jdk.javadoc.internal.doclets.formats.html.HtmlConfiguration; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; -import jdk.javadoc.internal.doclets.formats.html.markup.Text; -import jdk.javadoc.internal.doclets.formats.html.Content; +import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.HtmlTree; +import jdk.javadoc.internal.html.Text; /** * An inline taglet used to denote literal text, possibly in monospace font. diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/ParamTaglet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/ParamTaglet.java index 9963547acf3e7..ed46e6c5c864f 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/ParamTaglet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/ParamTaglet.java @@ -43,13 +43,13 @@ import jdk.javadoc.internal.doclets.formats.html.Contents; import jdk.javadoc.internal.doclets.formats.html.HtmlConfiguration; import jdk.javadoc.internal.doclets.formats.html.HtmlIds; -import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; -import jdk.javadoc.internal.doclets.formats.html.markup.Text; -import jdk.javadoc.internal.doclets.formats.html.Content; import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper; import jdk.javadoc.internal.doclets.toolkit.util.DocFinder; import jdk.javadoc.internal.doclets.toolkit.util.Utils; +import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.ContentBuilder; +import jdk.javadoc.internal.html.HtmlTree; +import jdk.javadoc.internal.html.Text; /** * A taglet that represents the {@code @param} tag. diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/ReturnTaglet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/ReturnTaglet.java index 6ba5d897c463a..b9572afb9bc4f 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/ReturnTaglet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/ReturnTaglet.java @@ -41,11 +41,11 @@ import jdk.javadoc.doclet.Taglet; import jdk.javadoc.internal.doclets.formats.html.Contents; import jdk.javadoc.internal.doclets.formats.html.HtmlConfiguration; -import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; -import jdk.javadoc.internal.doclets.formats.html.Content; import jdk.javadoc.internal.doclets.toolkit.util.DocFinder; import jdk.javadoc.internal.doclets.toolkit.util.Utils; +import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.ContentBuilder; +import jdk.javadoc.internal.html.HtmlTree; /** * A taglet that represents the {@code @return} and {@code {@return }} tags. diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SeeTaglet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SeeTaglet.java index 9052b1a49aa9d..abfb3b526ec08 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SeeTaglet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SeeTaglet.java @@ -45,16 +45,16 @@ import jdk.javadoc.internal.doclets.formats.html.HtmlConfiguration; import jdk.javadoc.internal.doclets.formats.html.HtmlDocletWriter; import jdk.javadoc.internal.doclets.formats.html.SerializedFormWriter; -import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; -import jdk.javadoc.internal.doclets.formats.html.markup.Text; -import jdk.javadoc.internal.doclets.formats.html.Content; import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper; import jdk.javadoc.internal.doclets.toolkit.util.DocFinder; import jdk.javadoc.internal.doclets.toolkit.util.DocLink; import jdk.javadoc.internal.doclets.toolkit.util.DocPath; import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; import jdk.javadoc.internal.doclets.toolkit.util.Utils; +import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.ContentBuilder; +import jdk.javadoc.internal.html.HtmlTree; +import jdk.javadoc.internal.html.Text; public class SeeTaglet extends BaseTaglet implements InheritableTaglet { SeeTaglet(HtmlConfiguration config) { diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SimpleTaglet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SimpleTaglet.java index 110a3e1246eb3..6ce38b3b515ab 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SimpleTaglet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SimpleTaglet.java @@ -42,11 +42,11 @@ import jdk.javadoc.doclet.Taglet; import jdk.javadoc.internal.doclets.formats.html.HtmlConfiguration; -import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; -import jdk.javadoc.internal.doclets.formats.html.markup.RawHtml; -import jdk.javadoc.internal.doclets.formats.html.Content; import jdk.javadoc.internal.doclets.toolkit.util.DocFinder; +import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.ContentBuilder; +import jdk.javadoc.internal.html.HtmlTree; +import jdk.javadoc.internal.html.RawHtml; /** * A custom single-argument block tag. diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SnippetTaglet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SnippetTaglet.java index 0642b37406420..af2378c0351d1 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SnippetTaglet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SnippetTaglet.java @@ -51,21 +51,21 @@ import jdk.javadoc.doclet.Taglet; import jdk.javadoc.internal.doclets.formats.html.HtmlConfiguration; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlAttr; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; -import jdk.javadoc.internal.doclets.formats.html.markup.TagName; -import jdk.javadoc.internal.doclets.formats.html.markup.Text; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyles; import jdk.javadoc.internal.doclets.formats.html.taglets.snippet.Action; import jdk.javadoc.internal.doclets.formats.html.taglets.snippet.ParseException; import jdk.javadoc.internal.doclets.formats.html.taglets.snippet.Parser; import jdk.javadoc.internal.doclets.formats.html.taglets.snippet.Style; import jdk.javadoc.internal.doclets.formats.html.taglets.snippet.StyledText; -import jdk.javadoc.internal.doclets.formats.html.Content; import jdk.javadoc.internal.doclets.toolkit.DocletElement; import jdk.javadoc.internal.doclets.toolkit.Resources; import jdk.javadoc.internal.doclets.toolkit.util.DocPaths; import jdk.javadoc.internal.doclets.toolkit.util.Utils; +import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.HtmlAttr; +import jdk.javadoc.internal.html.HtmlTag; +import jdk.javadoc.internal.html.HtmlTree; +import jdk.javadoc.internal.html.Text; import static jdk.javadoc.internal.doclets.formats.html.taglets.SnippetTaglet.Language.*; @@ -122,13 +122,13 @@ public Content getInlineTagOutput(Element holder, DocTree tag, TagletWriter tagl private Content snippetTagOutput(Element element, SnippetTree tag, StyledText content, String id, String lang) { var pathToRoot = tagletWriter.htmlWriter.pathToRoot; - var pre = new HtmlTree(TagName.PRE).setStyle(HtmlStyle.snippet); + var pre = new HtmlTree(HtmlTag.PRE).setStyle(HtmlStyles.snippet); if (id != null && !id.isBlank()) { pre.put(HtmlAttr.ID, id); } else { pre.put(HtmlAttr.ID, config.htmlIds.forSnippet(element, ids).name()); } - var code = new HtmlTree(TagName.CODE) + var code = new HtmlTree(HtmlTag.CODE) .addUnchecked(Text.EMPTY); // Make sure the element is always rendered if (lang != null && !lang.isBlank()) { code.addStyle("language-" + lang); @@ -196,16 +196,16 @@ private Content snippetTagOutput(Element element, SnippetTree tag, StyledText co String copyText = resources.getText("doclet.Copy_to_clipboard"); String copiedText = resources.getText("doclet.Copied_to_clipboard"); String copySnippetText = resources.getText("doclet.Copy_snippet_to_clipboard"); - var snippetContainer = HtmlTree.DIV(HtmlStyle.snippetContainer, - new HtmlTree(TagName.BUTTON) + var snippetContainer = HtmlTree.DIV(HtmlStyles.snippetContainer, + new HtmlTree(HtmlTag.BUTTON) .add(HtmlTree.SPAN(Text.of(copyText)) .put(HtmlAttr.DATA_COPIED, copiedText)) - .add(new HtmlTree(TagName.IMG) + .add(new HtmlTree(HtmlTag.IMG) .put(HtmlAttr.SRC, pathToRoot.resolve(DocPaths.RESOURCE_FILES) .resolve(DocPaths.CLIPBOARD_SVG).getPath()) .put(HtmlAttr.ALT, copySnippetText)) - .addStyle(HtmlStyle.copy) - .addStyle(HtmlStyle.snippetCopy) + .addStyle(HtmlStyles.copy) + .addStyle(HtmlStyles.snippetCopy) .put(HtmlAttr.ARIA_LABEL, copySnippetText) .put(HtmlAttr.ONCLICK, "copySnippet(this)")); return snippetContainer.add(pre.add(code)); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SpecTaglet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SpecTaglet.java index e55ede7a7e1cf..b408d30b16835 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SpecTaglet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SpecTaglet.java @@ -30,7 +30,6 @@ import java.util.EnumSet; import java.util.List; import java.util.Optional; -import java.util.stream.Collectors; import javax.lang.model.element.Element; import javax.lang.model.element.ExecutableElement; @@ -42,16 +41,16 @@ import jdk.javadoc.doclet.Taglet; import jdk.javadoc.internal.doclets.formats.html.Contents; import jdk.javadoc.internal.doclets.formats.html.HtmlConfiguration; -import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; -import jdk.javadoc.internal.doclets.formats.html.markup.Entity; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; -import jdk.javadoc.internal.doclets.formats.html.markup.RawHtml; -import jdk.javadoc.internal.doclets.formats.html.markup.Text; -import jdk.javadoc.internal.doclets.formats.html.Content; -import jdk.javadoc.internal.doclets.formats.html.markup.TextBuilder; import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper; import jdk.javadoc.internal.doclets.toolkit.util.DocFinder; import jdk.javadoc.internal.doclets.toolkit.util.Utils; +import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.ContentBuilder; +import jdk.javadoc.internal.html.Entity; +import jdk.javadoc.internal.html.HtmlTree; +import jdk.javadoc.internal.html.RawHtml; +import jdk.javadoc.internal.html.Text; +import jdk.javadoc.internal.html.TextBuilder; /** * A taglet that represents the {@code @spec} tag. diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SummaryTaglet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SummaryTaglet.java index 0961c7312d563..7912abef0c6ec 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SummaryTaglet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SummaryTaglet.java @@ -34,7 +34,7 @@ import jdk.javadoc.doclet.Taglet.Location; import jdk.javadoc.internal.doclets.formats.html.HtmlConfiguration; -import jdk.javadoc.internal.doclets.formats.html.Content; +import jdk.javadoc.internal.html.Content; /** * A taglet that represents the {@code {@summary}} tag. diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SystemPropertyTaglet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SystemPropertyTaglet.java index 3dc72e561a131..4cab9d90ce0d0 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SystemPropertyTaglet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/SystemPropertyTaglet.java @@ -34,8 +34,8 @@ import jdk.javadoc.doclet.Taglet; import jdk.javadoc.internal.doclets.formats.html.HtmlConfiguration; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; -import jdk.javadoc.internal.doclets.formats.html.Content; +import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.HtmlTree; /** * A taglet that represents the {@code @systemProperty} tag. diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/Taglet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/Taglet.java index 0236287468cb2..c1c6a56e5cbb3 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/Taglet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/Taglet.java @@ -26,12 +26,14 @@ package jdk.javadoc.internal.doclets.formats.html.taglets; import java.util.Set; + import javax.lang.model.element.Element; import com.sun.source.doctree.DocTree; + import jdk.javadoc.doclet.Taglet.Location; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; -import jdk.javadoc.internal.doclets.formats.html.Content; +import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.HtmlTree; /** * This is the taglet interface used internally within the doclet. diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/TagletWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/TagletWriter.java index b977951f2fa73..79b4433a58bc0 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/TagletWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/TagletWriter.java @@ -43,20 +43,13 @@ import javax.lang.model.util.SimpleElementVisitor14; import com.sun.source.doctree.DocTree; - import com.sun.source.doctree.InlineTagTree; + import jdk.javadoc.internal.doclets.formats.html.HtmlConfiguration; import jdk.javadoc.internal.doclets.formats.html.HtmlDocletWriter; import jdk.javadoc.internal.doclets.formats.html.HtmlIds; import jdk.javadoc.internal.doclets.formats.html.HtmlOptions; -import jdk.javadoc.internal.doclets.formats.html.IndexWriter; -import jdk.javadoc.internal.doclets.formats.html.SummaryListWriter; -import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlId; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; -import jdk.javadoc.internal.doclets.formats.html.markup.Text; -import jdk.javadoc.internal.doclets.formats.html.Content; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyles; import jdk.javadoc.internal.doclets.formats.html.taglets.Taglet.UnsupportedTagletOperationException; import jdk.javadoc.internal.doclets.toolkit.DocletElement; import jdk.javadoc.internal.doclets.toolkit.Resources; @@ -64,6 +57,11 @@ import jdk.javadoc.internal.doclets.toolkit.util.DocLink; import jdk.javadoc.internal.doclets.toolkit.util.IndexItem; import jdk.javadoc.internal.doclets.toolkit.util.Utils; +import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.ContentBuilder; +import jdk.javadoc.internal.html.HtmlId; +import jdk.javadoc.internal.html.HtmlTree; +import jdk.javadoc.internal.html.Text; /** * Context and utility methods for taglet classes. @@ -377,7 +375,7 @@ Content createAnchorAndSearchIndex(Element element, String tagText, Content tagC result = tagContent; } else { HtmlId id = HtmlIds.forText(tagText, htmlWriter.indexAnchorTable); - result = HtmlTree.SPAN(id, HtmlStyle.searchTagResult, tagContent); + result = HtmlTree.SPAN(id, HtmlStyles.searchTagResult, tagContent); if (options.createIndex() && !tagText.isEmpty()) { String holder = getHolderName(element); IndexItem item = IndexItem.of(element, tree, tagText, holder, desc, @@ -457,7 +455,7 @@ private String getHolderName(DocletElement de) { Content tagList(List items) { // Use a different style if any list item is longer than 30 chars or contains commas. boolean hasLongLabels = items.stream().anyMatch(this::isLongOrHasComma); - var list = HtmlTree.UL(hasLongLabels ? HtmlStyle.tagListLong : HtmlStyle.tagList); + var list = HtmlTree.UL(hasLongLabels ? HtmlStyles.tagListLong : HtmlStyles.tagList); items.stream() .filter(Predicate.not(Content::isEmpty)) .forEach(item -> list.add(HtmlTree.LI(item))); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/ThrowsTaglet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/ThrowsTaglet.java index 131f0350e5e13..ca4a8c939abba 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/ThrowsTaglet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/ThrowsTaglet.java @@ -57,12 +57,12 @@ import jdk.javadoc.internal.doclets.formats.html.Contents; import jdk.javadoc.internal.doclets.formats.html.HtmlConfiguration; import jdk.javadoc.internal.doclets.formats.html.HtmlLinkInfo; -import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; -import jdk.javadoc.internal.doclets.formats.html.Content; import jdk.javadoc.internal.doclets.toolkit.util.DocFinder; import jdk.javadoc.internal.doclets.toolkit.util.Utils; import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable; +import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.ContentBuilder; +import jdk.javadoc.internal.html.HtmlTree; /** * A taglet that processes {@link ThrowsTree}, which represents {@code @throws} diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/UserTaglet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/UserTaglet.java index bcfdd6682ed29..cc5ae21ba2965 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/UserTaglet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/UserTaglet.java @@ -32,8 +32,8 @@ import com.sun.source.doctree.DocTree; -import jdk.javadoc.internal.doclets.formats.html.markup.RawHtml; -import jdk.javadoc.internal.doclets.formats.html.Content; +import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.RawHtml; /** * A taglet wrapper, allows the public taglet {@link jdk.javadoc.doclet.Taglet} diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/ValueTaglet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/ValueTaglet.java index 006277eeeb006..a4fddef0f117a 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/ValueTaglet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/ValueTaglet.java @@ -39,10 +39,10 @@ import jdk.javadoc.doclet.Taglet; import jdk.javadoc.internal.doclets.formats.html.HtmlConfiguration; import jdk.javadoc.internal.doclets.formats.html.HtmlLinkInfo; -import jdk.javadoc.internal.doclets.formats.html.markup.Text; import jdk.javadoc.internal.doclets.toolkit.BaseConfiguration; -import jdk.javadoc.internal.doclets.formats.html.Content; import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper; +import jdk.javadoc.internal.html.Content; +import jdk.javadoc.internal.html.Text; /** * An inline taglet representing the value tag. This tag should only be used with diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Checker.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Checker.java index d33e4874c008a..7bc5563950186 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Checker.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Checker.java @@ -101,9 +101,16 @@ import com.sun.tools.javac.util.DefinedBy; import com.sun.tools.javac.util.DefinedBy.Api; -import jdk.javadoc.internal.doclint.HtmlTag.AttrKind; -import jdk.javadoc.internal.doclint.HtmlTag.ElemKind; -import static jdk.javadoc.internal.doclint.Messages.Group.*; +import jdk.javadoc.internal.html.HtmlAttr; +import jdk.javadoc.internal.html.HtmlAttr.AttrKind; +import jdk.javadoc.internal.html.HtmlTag; +import jdk.javadoc.internal.html.HtmlTag.ElemKind; + +import static jdk.javadoc.internal.doclint.Messages.Group.ACCESSIBILITY; +import static jdk.javadoc.internal.doclint.Messages.Group.HTML; +import static jdk.javadoc.internal.doclint.Messages.Group.MISSING; +import static jdk.javadoc.internal.doclint.Messages.Group.REFERENCE; +import static jdk.javadoc.internal.doclint.Messages.Group.SYNTAX; /** @@ -132,12 +139,12 @@ public enum Flag { static class TagStackItem { final DocTree tree; // typically, but not always, StartElementTree final HtmlTag tag; - final Set attrs; + final Set attrs; final Set flags; TagStackItem(DocTree tree, HtmlTag tag) { this.tree = tree; this.tag = tag; - attrs = EnumSet.noneOf(HtmlTag.Attr.class); + attrs = EnumSet.noneOf(HtmlAttr.class); flags = EnumSet.noneOf(Flag.class); } @Override @@ -399,7 +406,7 @@ void checkAllowsText(DocTree tree) { @Override @DefinedBy(Api.COMPILER_TREE) public Void visitStartElement(StartElementTree tree, Void ignore) { final Name treeName = tree.getName(); - final HtmlTag t = HtmlTag.get(treeName); + final HtmlTag t = HtmlTag.of(treeName); if (t == null) { env.messages.error(HTML, tree, "dc.tag.unknown", treeName); } else if (t.elemKind == ElemKind.HTML4) { @@ -472,7 +479,7 @@ public Void visitStartElement(StartElementTree tree, Void ignore) { } case IMG -> { - if (!top.attrs.contains(HtmlTag.Attr.ALT)) + if (!top.attrs.contains(HtmlAttr.ALT)) env.messages.error(ACCESSIBILITY, tree, "dc.no.alt.attr.for.image"); } } @@ -592,7 +599,7 @@ private int getHeadingRank(HtmlTag tag) { @Override @DefinedBy(Api.COMPILER_TREE) public Void visitEndElement(EndElementTree tree, Void ignore) { final Name treeName = tree.getName(); - final HtmlTag t = HtmlTag.get(treeName); + final HtmlTag t = HtmlTag.of(treeName); if (t == null) { env.messages.error(HTML, tree, "dc.tag.unknown", treeName); } else if (t.endKind == HtmlTag.EndKind.NONE) { @@ -605,7 +612,7 @@ public Void visitEndElement(EndElementTree tree, Void ignore) { switch (t) { case TABLE -> { if (!top.flags.contains(Flag.TABLE_IS_PRESENTATION) - && !top.attrs.contains(HtmlTag.Attr.SUMMARY) + && !top.attrs.contains(HtmlAttr.SUMMARY) && !top.flags.contains(Flag.TABLE_HAS_CAPTION)) { env.messages.error(ACCESSIBILITY, tree, "dc.no.summary.or.caption.for.table"); @@ -682,7 +689,7 @@ public Void visitAttribute(AttributeTree tree, Void ignore) { HtmlTag currTag = tagStack.peek().tag; if (currTag != null && currTag.elemKind != ElemKind.HTML4) { Name name = tree.getName(); - HtmlTag.Attr attr = currTag.getAttr(name); + HtmlAttr attr = currTag.getAttr(name); if (attr != null) { boolean first = tagStack.peek().attrs.add(attr); if (!first) @@ -758,19 +765,21 @@ public Void visitAttribute(AttributeTree tree, Void ignore) { String v = getAttrValue(tree); try { if (v == null || (!v.isEmpty() && Integer.parseInt(v) != 1)) { - env.messages.error(HTML, tree, "dc.attr.table.border.not.valid", attr); + env.messages.error(HTML, tree, "dc.attr.table.border.not.valid", + (v == null ? tree : v)); } } catch (NumberFormatException ex) { - env.messages.error(HTML, tree, "dc.attr.table.border.not.number", attr); + env.messages.error(HTML, tree, "dc.attr.table.border.not.number", v); } } else if (currTag == HtmlTag.IMG) { String v = getAttrValue(tree); try { if (v == null || (!v.isEmpty() && Integer.parseInt(v) != 0)) { - env.messages.error(HTML, tree, "dc.attr.img.border.not.valid", attr); + env.messages.error(HTML, tree, "dc.attr.img.border.not.valid", + (v == null ? tree : v)); } } catch (NumberFormatException ex) { - env.messages.error(HTML, tree, "dc.attr.img.border.not.number", attr); + env.messages.error(HTML, tree, "dc.attr.img.border.not.number", v); } } } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Comment.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/Comment.java similarity index 94% rename from src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Comment.java rename to src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/Comment.java index aa563eeded768..77b456cc7ffe8 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Comment.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/Comment.java @@ -23,14 +23,12 @@ * questions. */ -package jdk.javadoc.internal.doclets.formats.html.markup; +package jdk.javadoc.internal.html; import java.io.IOException; import java.io.Writer; import java.util.Objects; -import jdk.javadoc.internal.doclets.formats.html.Content; - /** * Class for generating a comment for HTML pages of javadoc output. */ diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Content.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/Content.java similarity index 99% rename from src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Content.java rename to src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/Content.java index 13a2bb4c1bf8b..63142f8301138 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Content.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/Content.java @@ -23,7 +23,7 @@ * questions. */ -package jdk.javadoc.internal.doclets.formats.html; +package jdk.javadoc.internal.html; import java.io.IOException; import java.io.StringWriter; diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/ContentBuilder.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/ContentBuilder.java similarity index 96% rename from src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/ContentBuilder.java rename to src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/ContentBuilder.java index b059b0fdb3660..358b1591dfc66 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/ContentBuilder.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/ContentBuilder.java @@ -23,7 +23,7 @@ * questions. */ -package jdk.javadoc.internal.doclets.formats.html.markup; +package jdk.javadoc.internal.html; import java.io.IOException; import java.io.Writer; @@ -31,8 +31,6 @@ import java.util.List; import java.util.Objects; -import jdk.javadoc.internal.doclets.formats.html.Content; - /** * A sequence of Content nodes. */ diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/DocType.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/DocType.java similarity index 96% rename from src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/DocType.java rename to src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/DocType.java index dd4b50eb76089..5e6bf502fe111 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/DocType.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/DocType.java @@ -23,7 +23,7 @@ * questions. */ -package jdk.javadoc.internal.doclets.formats.html.markup; +package jdk.javadoc.internal.html; /** * Supported DOCTYPE declarations. diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Entity.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/Entity.java similarity index 97% rename from src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Entity.java rename to src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/Entity.java index 542e081a58385..fbc7e08761626 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Entity.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/Entity.java @@ -23,9 +23,7 @@ * questions. */ -package jdk.javadoc.internal.doclets.formats.html.markup; - -import jdk.javadoc.internal.doclets.formats.html.Content; +package jdk.javadoc.internal.html; import java.io.IOException; import java.io.Writer; diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/HtmlAttr.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/HtmlAttr.java new file mode 100644 index 0000000000000..ccb193d6ab9ad --- /dev/null +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/HtmlAttr.java @@ -0,0 +1,275 @@ +/* + * Copyright (c) 2010, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.internal.html; + +import java.util.HashMap; +import java.util.Map; +import java.util.Locale; + + +/** + * An abstraction for the type-safe representation and use of HTML attributes. + * + * @apiNote + * Attributes are used when performing simple validity checks on HTML in + * documentation comments, and when generating HTML for output. + * + * @see HtmlTree#put(HtmlAttr, String) + */ +public enum HtmlAttr { + ABBR, + ACCESSKEY(true), + ALIGN, + ALINK, + ALT, + ARIA_ACTIVEDESCENDANT(true), + ARIA_CONTROLS(true), + ARIA_DESCRIBEDBY(true), + ARIA_EXPANDED(true), + ARIA_LABEL(true), + ARIA_LABELLEDBY(true), + ARIA_LEVEL(true), + ARIA_MULTISELECTABLE(true), + ARIA_ORIENTATION(true), + ARIA_OWNS(true), + ARIA_POSINSET(true), + ARIA_READONLY(true), + ARIA_REQUIRED(true), + ARIA_SELECTED(true), + ARIA_SETSIZE(true), + ARIA_SORT(true), + AUTOCAPITALIZE(true), + AUTOCOMPLETE, + AUTOFOCUS(true), + AXIS, + BACKGROUND, + BGCOLOR, + BORDER, + CELLPADDING, + CELLSPACING, + CHAR, + CHAROFF, + CHARSET, + CHECKED, + CITE, + CLASS(true), + CLEAR, + COLOR, + COLS, + COLSPAN, + COMPACT, + CONTENT, + CONTENTEDITABLE(true), + COORDS, + CROSSORIGIN, + DATA_COPIED, // custom HTML5 data attribute + DATETIME, + DIR(true), + DISABLED, + DRAGGABLE(true), + ENTERKEYHINT(true), + FACE, + FOR, + FORM, + FRAME, + FRAMEBORDER, + HEADERS, + HEIGHT, + HIDDEN(true), + HREF, + HSPACE, + HTTP_EQUIV, + ID(true), + INERT(true), + INPUTMODE(true), + IS(true), + ITEMID(true), + ITEMPROP(true), + ITEMREF(true), + ITEMSCOPE(true), + ITEMTYPE(true), + LANG(true), + LINK, + LONGDESC, + MARGINHEIGHT, + MARGINWIDTH, + NAME, + NONCE(true), + NOSHADE, + NOWRAP, + ONCLICK, + ONKEYDOWN, + ONLOAD, + PLACEHOLDER, + POPOVER(true), + PROFILE, + REL, + REV, + REVERSED, + ROLE(true), + ROWS, + ROWSPAN, + RULES, + SCHEME, + SCOPE, + SCROLLING, + SHAPE, + SIZE, + SPACE, + SPELLCHECK(true), + SRC, + START, + STYLE(true), + SUMMARY, + TABINDEX(true), + TARGET, + TEXT, + TITLE(true), + TRANSLATE(true), + TYPE, + VALIGN, + VALUE, + VERSION, + VLINK, + VSPACE, + WIDTH, + WRITINGSUGGESTIONS(true); + + /** + * The "external" name of this attribute. + */ + private final String name; + + /** + * Whether this is a global attribute, that can be used with all HTML tags. + */ + private final boolean isGlobal; + + /** + * An abstraction for the type-safe representation and use of ARIA roles. + * + * @see HtmlTree#setRole(Role) + */ + public enum Role { + + BANNER, + CONTENTINFO, + MAIN, + NAVIGATION, + REGION; + + private final String role; + + Role() { + role = name().toLowerCase(Locale.ROOT); + } + + public String toString() { + return role; + } + } + + /** + * An abstraction for the type-safe representation and use of "input" types. + * + * @see HtmlTree#INPUT(InputType, HtmlId) + * @see HtmlTree#INPUT(InputType, HtmlStyle) + */ + public enum InputType { + + CHECKBOX, + RESET, + TEXT; + + private final String type; + + InputType() { + type = name().toLowerCase(Locale.ROOT); + } + + public String toString() { + return type; + } + } + + /** + * An abstraction for the kind of an attribute in the context of an HTML tag. + * + * @see HtmlTag#attrs(AttrKind,HtmlAttr...) + */ + public enum AttrKind { + OK, + INVALID, + OBSOLETE, + HTML4 + } + + HtmlAttr() { + this(false); + } + + HtmlAttr(boolean flag) { + name = name().toLowerCase(Locale.ROOT).replace("_", "-"); + isGlobal = flag; + } + + /** + * {@return the "external" name of this attribute} + * The external name is the name of the enum member in lower case with {@code _} replaced by {@code -}. + */ + public String getName() { + return name; + } + + /** + * {@return whether this attribute is a global attribute, that may appear on all tags} + */ + public boolean isGlobal() { + return isGlobal; + } + + // FIXME: this is used in doclint Checker, when generating messages + @Override + public String toString() { + return name; + } + + private static final Map index = new HashMap<>(); + static { + for (HtmlAttr t : values()) { + index.put(t.getName(), t); + } + } + + /** + * {@return the attribute with the given name, or {@code null} if there is no known attribute} + * + * @param name the name + */ + public static HtmlAttr of(CharSequence name) { + return index.get(name.toString().toLowerCase(Locale.ROOT)); + } +} diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlId.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/HtmlId.java similarity index 96% rename from src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlId.java rename to src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/HtmlId.java index 1e0db271ef544..a6af14382848b 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlId.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/HtmlId.java @@ -23,7 +23,7 @@ * questions. */ -package jdk.javadoc.internal.doclets.formats.html.markup; +package jdk.javadoc.internal.html; /** * A type-safe wrapper around a {@code String}, for use as an "id" diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/HtmlStyle.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/HtmlStyle.java new file mode 100644 index 0000000000000..9b77d5de8b49f --- /dev/null +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/HtmlStyle.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.javadoc.internal.html; + +/** + * An abstraction for the type-safe representation and use of CSS class names. + * + * @apiNote + * Despite the name, implementations of this interface provide values for the HTML + * {@code class} attribute, and not the HTML {@code style} attribute. + * This is to avoid confusion with the widespread use of the word "class" in the Java ecosystem, + * and the potential for clashes with methods called {@code setClass} instead of {@code setStyle}. + * + * @see HtmlTree#addStyle(HtmlStyle) + * @see HtmlTree#setStyle(HtmlStyle) + */ +public interface HtmlStyle { + String cssName(); +} diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/HtmlTag.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/HtmlTag.java similarity index 72% rename from src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/HtmlTag.java rename to src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/HtmlTag.java index fa9d3ea578dd4..7b198a066315a 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/HtmlTag.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/HtmlTag.java @@ -23,18 +23,18 @@ * questions. */ -package jdk.javadoc.internal.doclint; +package jdk.javadoc.internal.html; +import java.io.Serial; import java.util.EnumMap; import java.util.EnumSet; import java.util.HashMap; +import java.util.Locale; import java.util.Map; import java.util.Set; import javax.lang.model.element.Name; -import com.sun.tools.javac.util.StringUtils; - -import static jdk.javadoc.internal.doclint.HtmlTag.Attr.*; +import static jdk.javadoc.internal.html.HtmlAttr.*; /** * Enum representing HTML tags. @@ -42,10 +42,6 @@ * The intent of this class is to embody the semantics of the current HTML standard, * to the extent supported/used by javadoc. * - * This class is derivative of {@link jdk.javadoc.internal.doclets.formats.html.markup.TagName}. - * Eventually, these two should be merged back together, and possibly made - * public. - * * @see HTML Living Standard * @see HTML 5 Specification * @see HTML 4.01 Specification @@ -88,6 +84,9 @@ public enum HtmlTag { BR(BlockType.INLINE, EndKind.NONE, attrs(AttrKind.HTML4, CLEAR)), + BUTTON(BlockType.INLINE, EndKind.REQUIRED, + attrs(AttrKind.OK, FORM, NAME, TYPE, VALUE)), + CAPTION(BlockType.TABLE_ITEM, EndKind.REQUIRED, EnumSet.of(Flag.ACCEPTS_INLINE, Flag.EXPECT_CONTENT), attrs(AttrKind.HTML4, ALIGN)), @@ -117,7 +116,10 @@ public boolean accepts(HtmlTag t) { DEL(BlockType.INLINE, EndKind.REQUIRED, EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST), - attrs(AttrKind.OK, Attr.CITE, Attr.DATETIME)), + attrs(AttrKind.OK, HtmlAttr.CITE, HtmlAttr.DATETIME)), + + DETAILS(BlockType.BLOCK, EndKind.REQUIRED, + EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE)), DFN(BlockType.INLINE, EndKind.REQUIRED, EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)), @@ -149,12 +151,10 @@ public boolean accepts(HtmlTag t) { EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE)) { @Override public boolean accepts(HtmlTag t) { - switch (t) { - case HEADER: case FOOTER: case MAIN: - return false; - default: - return (t.blockType == BlockType.BLOCK) || (t.blockType == BlockType.INLINE); - } + return switch (t) { + case HEADER, FOOTER, MAIN -> false; + default -> (t.blockType == BlockType.BLOCK) || (t.blockType == BlockType.INLINE); + }; } }, @@ -186,12 +186,10 @@ public boolean accepts(HtmlTag t) { EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE)) { @Override public boolean accepts(HtmlTag t) { - switch (t) { - case HEADER: case FOOTER: case MAIN: - return false; - default: - return (t.blockType == BlockType.BLOCK) || (t.blockType == BlockType.INLINE); - } + return switch (t) { + case HEADER, FOOTER, MAIN -> false; + default -> (t.blockType == BlockType.BLOCK) || (t.blockType == BlockType.INLINE); + }; } }, @@ -209,19 +207,25 @@ public boolean accepts(HtmlTag t) { attrs(AttrKind.OK, SRC, ALT, HEIGHT, WIDTH, CROSSORIGIN), attrs(AttrKind.HTML4, NAME, ALIGN, HSPACE, VSPACE, BORDER)), + INPUT(BlockType.INLINE, EndKind.NONE, + attrs(AttrKind.OK, NAME, TYPE, VALUE)), + INS(BlockType.INLINE, EndKind.REQUIRED, EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST), - attrs(AttrKind.OK, Attr.CITE, Attr.DATETIME)), + attrs(AttrKind.OK, HtmlAttr.CITE, HtmlAttr.DATETIME)), KBD(BlockType.INLINE, EndKind.REQUIRED, EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)), + LABEL(BlockType.INLINE, EndKind.REQUIRED), + LI(BlockType.LIST_ITEM, EndKind.OPTIONAL, EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE), attrs(AttrKind.OK, VALUE), attrs(AttrKind.HTML4, TYPE)), - LINK(BlockType.OTHER, EndKind.NONE), + LINK(BlockType.INLINE, EndKind.NONE, + attrs(AttrKind.OK, REL)), MAIN(BlockType.OTHER, EndKind.REQUIRED), @@ -262,12 +266,10 @@ public boolean accepts(HtmlTag t) { attrs(AttrKind.HTML4, WIDTH)) { @Override public boolean accepts(HtmlTag t) { - switch (t) { - case IMG: case BIG: case SMALL: case SUB: case SUP: - return false; - default: - return (t.blockType == BlockType.INLINE); - } + return switch (t) { + case IMG, BIG, SMALL, SUB, SUP -> false; + default -> (t.blockType == BlockType.INLINE); + }; } }, @@ -280,8 +282,8 @@ public boolean accepts(HtmlTag t) { SAMP(BlockType.INLINE, EndKind.REQUIRED, EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)), - SCRIPT(BlockType.OTHER, EndKind.REQUIRED, - attrs(AttrKind.OK, SRC)), + SCRIPT(BlockType.INLINE, EndKind.REQUIRED, + attrs(AttrKind.OK, SRC, TYPE)), SECTION(BlockType.BLOCK, EndKind.REQUIRED, EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE)), @@ -303,25 +305,22 @@ public boolean accepts(HtmlTag t) { SUB(BlockType.INLINE, EndKind.REQUIRED, EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)), + SUMMARY(BlockType.BLOCK, EndKind.REQUIRED), + SUP(BlockType.INLINE, EndKind.REQUIRED, EnumSet.of(Flag.EXPECT_CONTENT, Flag.NO_NEST)), TABLE(BlockType.BLOCK, EndKind.REQUIRED, EnumSet.of(Flag.EXPECT_CONTENT), attrs(AttrKind.OK, BORDER), - attrs(AttrKind.HTML4, SUMMARY, CELLPADDING, CELLSPACING, - Attr.FRAME, RULES, WIDTH, ALIGN, BGCOLOR)) { + attrs(AttrKind.HTML4, HtmlAttr.SUMMARY, CELLPADDING, CELLSPACING, + HtmlAttr.FRAME, RULES, WIDTH, ALIGN, BGCOLOR)) { @Override public boolean accepts(HtmlTag t) { - switch (t) { - case CAPTION: - case COLGROUP: - case THEAD: case TBODY: case TFOOT: - case TR: // HTML 3.2 - return true; - default: - return false; - } + return switch (t) { + case CAPTION, COLGROUP, THEAD, TBODY, TFOOT, TR -> true; + default -> false; + }; } }, @@ -337,7 +336,7 @@ public boolean accepts(HtmlTag t) { TD(BlockType.TABLE_ITEM, EndKind.OPTIONAL, EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE), attrs(AttrKind.OK, COLSPAN, ROWSPAN, HEADERS), - attrs(AttrKind.HTML4, AXIS, Attr.ABBR, SCOPE, ALIGN, VALIGN, CHAR, CHAROFF, + attrs(AttrKind.HTML4, AXIS, HtmlAttr.ABBR, SCOPE, ALIGN, VALIGN, CHAR, CHAROFF, WIDTH, BGCOLOR, HEIGHT, NOWRAP)), TEMPLATE(BlockType.BLOCK, EndKind.REQUIRED, @@ -353,7 +352,7 @@ public boolean accepts(HtmlTag t) { TH(BlockType.TABLE_ITEM, EndKind.OPTIONAL, EnumSet.of(Flag.ACCEPTS_BLOCK, Flag.ACCEPTS_INLINE), - attrs(AttrKind.OK, COLSPAN, ROWSPAN, HEADERS, SCOPE, Attr.ABBR), + attrs(AttrKind.OK, COLSPAN, ROWSPAN, HEADERS, SCOPE, HtmlAttr.ABBR), attrs(AttrKind.HTML4, WIDTH, BGCOLOR, HEIGHT, NOWRAP, AXIS, ALIGN, CHAR, CHAROFF, VALIGN)), THEAD(BlockType.TABLE_ITEM, EndKind.REQUIRED, @@ -408,6 +407,7 @@ public enum ElemKind { /** * Enum representing the type of HTML element. */ + // See JDK-8337586 for suggestions public enum BlockType { BLOCK, INLINE, @@ -432,150 +432,13 @@ public enum Flag { NO_NEST } - public enum Attr { - ABBR, - ACCESSKEY(true), - ALIGN, - ALINK, - ALT, - ARIA_ACTIVEDESCENDANT(true), - ARIA_CONTROLS(true), - ARIA_DESCRIBEDBY(true), - ARIA_EXPANDED(true), - ARIA_LABEL(true), - ARIA_LABELLEDBY(true), - ARIA_LEVEL(true), - ARIA_MULTISELECTABLE(true), - ARIA_OWNS(true), - ARIA_POSINSET(true), - ARIA_READONLY(true), - ARIA_REQUIRED(true), - ARIA_SELECTED(true), - ARIA_SETSIZE(true), - ARIA_SORT(true), - AUTOCAPITALIZE(true), - AUTOFOCUS(true), - AXIS, - BACKGROUND, - BGCOLOR, - BORDER, - CELLPADDING, - CELLSPACING, - CHAR, - CHAROFF, - CHARSET, - CITE, - CLASS(true), - CLEAR, - COLOR, - COLSPAN, - COMPACT, - CONTENTEDITABLE(true), - COORDS, - CROSSORIGIN, - DATETIME, - DIR(true), - DRAGGABLE(true), - ENTERKEYHINT(true), - FACE, - FRAME, - FRAMEBORDER, - HEADERS, - HEIGHT, - HIDDEN(true), - HREF, - HSPACE, - ID(true), - INERT(true), - INPUTMODE(true), - IS(true), - ITEMID(true), - ITEMPROP(true), - ITEMREF(true), - ITEMSCOPE(true), - ITEMTYPE(true), - LANG(true), - LINK, - LONGDESC, - MARGINHEIGHT, - MARGINWIDTH, - NAME, - NONCE(true), - NOSHADE, - NOWRAP, - POPOVER(true), - PROFILE, - REV, - REVERSED, - ROLE(true), - ROWSPAN, - RULES, - SCHEME, - SCOPE, - SCROLLING, - SHAPE, - SIZE, - SPACE, - SPELLCHECK(true), - SRC, - START, - STYLE(true), - SUMMARY, - TABINDEX(true), - TARGET, - TEXT, - TITLE(true), - TRANSLATE(true), - TYPE, - VALIGN, - VALUE, - VERSION, - VLINK, - VSPACE, - WIDTH, - WRITINGSUGGESTIONS(true); - - private final String name; - private final boolean isGlobal; - - Attr() { - this(false); - } - - Attr(boolean flag) { - name = StringUtils.toLowerCase(name().replace("_", "-")); - isGlobal = flag; - } - - public boolean isGlobal() { - return isGlobal; - } - - public String getText() { - return name; - } - - static final Map index = new HashMap<>(); - static { - for (Attr t: values()) { - index.put(t.getText(), t); - } - } - } - - public enum AttrKind { - OK, - INVALID, - OBSOLETE, - HTML4 - } - // This class exists to avoid warnings from using parameterized vararg type // Map in signature of HtmlTag constructor. - private static class AttrMap extends EnumMap { + private static class AttrMap extends EnumMap { + @Serial private static final long serialVersionUID = 0; AttrMap() { - super(Attr.class); + super(HtmlAttr.class); } } @@ -584,7 +447,7 @@ private static class AttrMap extends EnumMap { public final BlockType blockType; public final EndKind endKind; public final Set flags; - private final Map attrs; + private final Map attrs; HtmlTag(BlockType blockType, EndKind endKind, AttrMap... attrMaps) { this(ElemKind.OK, blockType, endKind, Set.of(), attrMaps); @@ -603,8 +466,8 @@ private static class AttrMap extends EnumMap { this.blockType = blockType; this.endKind = endKind; this.flags = flags; - this.attrs = new EnumMap<>(Attr.class); - for (Map m: attrMaps) + this.attrs = new EnumMap<>(HtmlAttr.class); + for (Map m: attrMaps) this.attrs.putAll(m); } @@ -615,20 +478,18 @@ public boolean accepts(HtmlTag t) { return (t.blockType == BlockType.BLOCK); } else if (flags.contains(Flag.ACCEPTS_INLINE)) { return (t.blockType == BlockType.INLINE); - } else - switch (blockType) { - case BLOCK: - case INLINE: - return (t.blockType == BlockType.INLINE); - case OTHER: + } else { + // any combination which could otherwise arrive here + // ought to have been handled in an overriding method + return switch (blockType) { + case BLOCK, INLINE -> (t.blockType == BlockType.INLINE); + case OTHER -> // OTHER tags are invalid in doc comments, and will be // reported separately, so silently accept/ignore any content - return true; - default: - // any combination which could otherwise arrive here - // ought to have been handled in an overriding method - throw new AssertionError(this + ":" + t); - } + true; + default -> throw new AssertionError(this + ":" + t); + }; + } } public boolean acceptsText() { @@ -637,16 +498,16 @@ public boolean acceptsText() { return accepts(B); } - public String getText() { - return StringUtils.toLowerCase(name()); + public String getName() { + return name().toLowerCase(Locale.ROOT).replace("_", "-"); } - public Attr getAttr(Name attrName) { - return Attr.index.get(StringUtils.toLowerCase(attrName.toString())); + public HtmlAttr getAttr(Name attrName) { + return HtmlAttr.of(attrName); } public AttrKind getAttrKind(Name attrName) { - Attr attr = getAttr(attrName); + HtmlAttr attr = getAttr(attrName); if (attr == null) { return AttrKind.INVALID; } @@ -655,20 +516,20 @@ public AttrKind getAttrKind(Name attrName) { attrs.getOrDefault(attr, AttrKind.INVALID); } - private static AttrMap attrs(AttrKind k, Attr... attrs) { + private static AttrMap attrs(AttrKind k, HtmlAttr... attrs) { AttrMap map = new AttrMap(); - for (Attr a: attrs) map.put(a, k); + for (HtmlAttr a : attrs) map.put(a, k); return map; } private static final Map index = new HashMap<>(); static { for (HtmlTag t: values()) { - index.put(t.getText(), t); + index.put(t.getName(), t); } } - public static HtmlTag get(Name tagName) { - return index.get(StringUtils.toLowerCase(tagName.toString())); + public static HtmlTag of(CharSequence tagName) { + return index.get(tagName.toString().toLowerCase(Locale.ROOT)); } } 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/html/HtmlTree.java similarity index 90% rename from src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlTree.java rename to src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/HtmlTree.java index 57adb96632612..f60537511746d 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/html/HtmlTree.java @@ -23,7 +23,7 @@ * questions. */ -package jdk.javadoc.internal.doclets.formats.html.markup; +package jdk.javadoc.internal.html; import java.io.IOException; import java.io.Writer; @@ -38,9 +38,6 @@ import java.util.Objects; import java.util.function.Function; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlAttr.Role; -import jdk.javadoc.internal.doclets.formats.html.Content; - /** * A tree node representing an HTML element, containing the name of the element, * a collection of attributes, and content. @@ -63,10 +60,10 @@ public class HtmlTree extends Content { /** - * The name of the HTML element. + * The tag for the HTML element. * This value is never {@code null}. */ - public final TagName tagName; + public final HtmlTag tag; /** * The attributes for the HTML element. @@ -84,10 +81,10 @@ public class HtmlTree extends Content { * Creates an {@code HTMLTree} object representing an HTML element * with the given name. * - * @param tagName the name + * @param tag the name */ - public HtmlTree(TagName tagName) { - this.tagName = Objects.requireNonNull(tagName); + public HtmlTree(HtmlTag tag) { + this.tag = Objects.requireNonNull(tag); } /** @@ -131,7 +128,7 @@ public HtmlTree setTitle(Content body) { * @param role the role * @return this object */ - public HtmlTree setRole(Role role) { + public HtmlTree setRole(HtmlAttr.Role role) { return put(HtmlAttr.ROLE, role.toString()); } @@ -347,7 +344,7 @@ public static String encodeURL(String url) { * @return the element */ public static HtmlTree A(String ref, Content body) { - return new HtmlTree(TagName.A) + return new HtmlTree(HtmlTag.A) .put(HtmlAttr.HREF, encodeURL(ref)) .add(body); } @@ -363,7 +360,7 @@ public static HtmlTree A(String ref, Content body) { * @return the element */ public static HtmlTree A(URI ref, Content body) { - return new HtmlTree(TagName.A) + return new HtmlTree(HtmlTag.A) .put(HtmlAttr.HREF, ref.toASCIIString()) .add(body); } @@ -375,7 +372,7 @@ public static HtmlTree A(URI ref, Content body) { * @return the element */ public static HtmlTree CAPTION(Content body) { - return new HtmlTree(TagName.CAPTION) + return new HtmlTree(HtmlTag.CAPTION) .add(body); } @@ -386,7 +383,7 @@ public static HtmlTree CAPTION(Content body) { * @return the element */ public static HtmlTree CODE(Content body) { - return new HtmlTree(TagName.CODE) + return new HtmlTree(HtmlTag.CODE) .add(body); } @@ -397,7 +394,7 @@ public static HtmlTree CODE(Content body) { * @return the element */ public static HtmlTree DD(Content body) { - return new HtmlTree(TagName.DD) + return new HtmlTree(HtmlTag.DD) .add(body); } @@ -407,7 +404,7 @@ public static HtmlTree DD(Content body) { * @return the element */ public static HtmlTree DETAILS() { - return new HtmlTree(TagName.DETAILS); + return new HtmlTree(HtmlTag.DETAILS); } /** @@ -416,7 +413,7 @@ public static HtmlTree DETAILS() { * @return the element */ public static HtmlTree DETAILS(HtmlStyle style) { - return new HtmlTree(TagName.DETAILS) + return new HtmlTree(HtmlTag.DETAILS) .setStyle(style); } @@ -427,7 +424,7 @@ public static HtmlTree DETAILS(HtmlStyle style) { * @return the element */ public static HtmlTree DL(HtmlStyle style) { - return new HtmlTree(TagName.DL) + return new HtmlTree(HtmlTag.DL) .setStyle(style); } @@ -439,7 +436,7 @@ public static HtmlTree DL(HtmlStyle style) { * @return the element */ public static HtmlTree DL(HtmlStyle style, Content body) { - return new HtmlTree(TagName.DL) + return new HtmlTree(HtmlTag.DL) .setStyle(style) .add(body); } @@ -451,7 +448,7 @@ public static HtmlTree DL(HtmlStyle style, Content body) { * @return the element */ public static HtmlTree DIV(HtmlStyle style) { - return new HtmlTree(TagName.DIV) + return new HtmlTree(HtmlTag.DIV) .setStyle(style); } @@ -463,7 +460,7 @@ public static HtmlTree DIV(HtmlStyle style) { * @return the element */ public static HtmlTree DIV(HtmlStyle style, Content body) { - return new HtmlTree(TagName.DIV) + return new HtmlTree(HtmlTag.DIV) .setStyle(style) .add(body); } @@ -475,7 +472,7 @@ public static HtmlTree DIV(HtmlStyle style, Content body) { * @return the element */ public static HtmlTree DIV(Content body) { - return new HtmlTree(TagName.DIV) + return new HtmlTree(HtmlTag.DIV) .add(body); } @@ -486,7 +483,7 @@ public static HtmlTree DIV(Content body) { * @return the element */ public static HtmlTree DT(Content body) { - return new HtmlTree(TagName.DT) + return new HtmlTree(HtmlTag.DT) .add(body); } @@ -497,8 +494,8 @@ public static HtmlTree DT(Content body) { * @return the element */ public static HtmlTree FOOTER() { - return new HtmlTree(TagName.FOOTER) - .setRole(Role.CONTENTINFO); + return new HtmlTree(HtmlTag.FOOTER) + .setRole(HtmlAttr.Role.CONTENTINFO); } /** @@ -508,8 +505,8 @@ public static HtmlTree FOOTER() { * @return the element */ public static HtmlTree HEADER() { - return new HtmlTree(TagName.HEADER) - .setRole(Role.BANNER); + return new HtmlTree(HtmlTag.HEADER) + .setRole(HtmlAttr.Role.BANNER); } /** @@ -519,7 +516,7 @@ public static HtmlTree HEADER() { * @param body the content * @return the element */ - public static HtmlTree HEADING(TagName headingTag, Content body) { + public static HtmlTree HEADING(HtmlTag headingTag, Content body) { return new HtmlTree(checkHeading(headingTag)) .add(body); } @@ -532,7 +529,7 @@ public static HtmlTree HEADING(TagName headingTag, Content body) { * @param body the content * @return the element */ - public static HtmlTree HEADING(TagName headingTag, HtmlStyle style, Content body) { + public static HtmlTree HEADING(HtmlTag headingTag, HtmlStyle style, Content body) { return new HtmlTree(checkHeading(headingTag)) .setStyle(style) .add(body); @@ -547,7 +544,7 @@ public static HtmlTree HEADING(TagName headingTag, HtmlStyle style, Content body * @param body the content * @return the element */ - public static HtmlTree HEADING_TITLE(TagName headingTag, + public static HtmlTree HEADING_TITLE(HtmlTag headingTag, HtmlStyle style, Content body) { return new HtmlTree(checkHeading(headingTag)) .setTitle(body) @@ -563,13 +560,13 @@ public static HtmlTree HEADING_TITLE(TagName headingTag, * @param body the content * @return the element */ - public static HtmlTree HEADING_TITLE(TagName headingTag, Content body) { + public static HtmlTree HEADING_TITLE(HtmlTag headingTag, Content body) { return new HtmlTree(checkHeading(headingTag)) .setTitle(body) .add(body); } - private static TagName checkHeading(TagName headingTag) { + private static HtmlTag checkHeading(HtmlTag headingTag) { return switch (headingTag) { case H1, H2, H3, H4, H5, H6 -> headingTag; default -> throw new IllegalArgumentException(headingTag.toString()); @@ -586,7 +583,7 @@ private static TagName checkHeading(TagName headingTag) { * @return the {@code HTML} element */ public static HtmlTree HTML(String lang, Content head, Content body) { - return new HtmlTree(TagName.HTML) + return new HtmlTree(HtmlTag.HTML) .put(HtmlAttr.LANG, lang) .add(head) .add(body); @@ -601,7 +598,7 @@ public static HtmlTree HTML(String lang, Content head, Content body) { * @return the element */ public static HtmlTree INPUT(HtmlAttr.InputType type, HtmlId id) { - return new HtmlTree(TagName.INPUT) + return new HtmlTree(HtmlTag.INPUT) .put(HtmlAttr.TYPE, type.toString()) .setId(id) .put(HtmlAttr.DISABLED, ""); @@ -615,7 +612,7 @@ public static HtmlTree INPUT(HtmlAttr.InputType type, HtmlId id) { * @return the element */ public static HtmlTree INPUT(HtmlAttr.InputType type, HtmlStyle style) { - return new HtmlTree(TagName.INPUT) + return new HtmlTree(HtmlTag.INPUT) .put(HtmlAttr.TYPE, type.toString()) .setStyle(style) .put(HtmlAttr.DISABLED, ""); @@ -628,7 +625,7 @@ public static HtmlTree INPUT(HtmlAttr.InputType type, HtmlStyle style) { * @return the element */ public static HtmlTree LABEL(String forLabel, Content body) { - return new HtmlTree(TagName.LABEL) + return new HtmlTree(HtmlTag.LABEL) .put(HtmlAttr.FOR, forLabel) .add(body); } @@ -640,7 +637,7 @@ public static HtmlTree LABEL(String forLabel, Content body) { * @return the element */ public static HtmlTree LI(Content body) { - return new HtmlTree(TagName.LI) + return new HtmlTree(HtmlTag.LI) .add(body); } @@ -666,7 +663,7 @@ public static HtmlTree LI(HtmlStyle style, Content body) { * @return the element */ public static HtmlTree LINK(String rel, String type, String href, String title) { - return new HtmlTree(TagName.LINK) + return new HtmlTree(HtmlTag.LINK) .put(HtmlAttr.REL, rel) .put(HtmlAttr.TYPE, type) .put(HtmlAttr.HREF, href) @@ -680,8 +677,8 @@ public static HtmlTree LINK(String rel, String type, String href, String title) * @return the element */ public static HtmlTree MAIN() { - return new HtmlTree(TagName.MAIN) - .setRole(Role.MAIN); + return new HtmlTree(HtmlTag.MAIN) + .setRole(HtmlAttr.Role.MAIN); } /** @@ -691,8 +688,8 @@ public static HtmlTree MAIN() { * @return the element */ public static HtmlTree MAIN(Content body) { - return new HtmlTree(TagName.MAIN) - .setRole(Role.MAIN) + return new HtmlTree(HtmlTag.MAIN) + .setRole(HtmlAttr.Role.MAIN) .add(body); } @@ -705,7 +702,7 @@ public static HtmlTree MAIN(Content body) { * @return the element */ public static HtmlTree META(String httpEquiv, String content, String charset) { - return new HtmlTree(TagName.META) + return new HtmlTree(HtmlTag.META) .put(HtmlAttr.HTTP_EQUIV, httpEquiv) .put(HtmlAttr.CONTENT, content + "; charset=" + charset); } @@ -718,7 +715,7 @@ public static HtmlTree META(String httpEquiv, String content, String charset) { * @return the element */ public static HtmlTree META(String name, String content) { - return new HtmlTree(TagName.META) + return new HtmlTree(HtmlTag.META) .put(HtmlAttr.NAME, name) .put(HtmlAttr.CONTENT, content); } @@ -730,8 +727,8 @@ public static HtmlTree META(String name, String content) { * @return the element */ public static HtmlTree NAV() { - return new HtmlTree(TagName.NAV) - .setRole(Role.NAVIGATION); + return new HtmlTree(HtmlTag.NAV) + .setRole(HtmlAttr.Role.NAVIGATION); } /** @@ -741,7 +738,7 @@ public static HtmlTree NAV() { * @return the element */ public static HtmlTree NOSCRIPT(Content body) { - return new HtmlTree(TagName.NOSCRIPT) + return new HtmlTree(HtmlTag.NOSCRIPT) .add(body); } @@ -752,7 +749,7 @@ public static HtmlTree NOSCRIPT(Content body) { * @return the element */ public static HtmlTree OL(HtmlStyle style) { - return new HtmlTree(TagName.OL) + return new HtmlTree(HtmlTag.OL) .setStyle(style); } @@ -763,7 +760,7 @@ public static HtmlTree OL(HtmlStyle style) { * @return the element */ public static HtmlTree P(Content body) { - return new HtmlTree(TagName.P) + return new HtmlTree(HtmlTag.P) .add(body); } @@ -786,7 +783,7 @@ public static HtmlTree P(HtmlStyle style, Content body) { * @return the element */ public static HtmlTree PRE(Content body) { - return new HtmlTree(TagName.PRE).add(body); + return new HtmlTree(HtmlTag.PRE).add(body); } /** @@ -797,7 +794,7 @@ public static HtmlTree PRE(Content body) { * @return the element */ public static HtmlTree SCRIPT(String src) { - return new HtmlTree(TagName.SCRIPT) + return new HtmlTree(HtmlTag.SCRIPT) .put(HtmlAttr.TYPE, "text/javascript") .put(HtmlAttr.SRC, src); @@ -810,7 +807,7 @@ public static HtmlTree SCRIPT(String src) { * @return the element */ public static HtmlTree SECTION(HtmlStyle style) { - return new HtmlTree(TagName.SECTION) + return new HtmlTree(HtmlTag.SECTION) .setStyle(style); } @@ -822,7 +819,7 @@ public static HtmlTree SECTION(HtmlStyle style) { * @return the element */ public static HtmlTree SECTION(HtmlStyle style, Content body) { - return new HtmlTree(TagName.SECTION) + return new HtmlTree(HtmlTag.SECTION) .setStyle(style) .add(body); } @@ -834,7 +831,7 @@ public static HtmlTree SECTION(HtmlStyle style, Content body) { * @return the element */ public static HtmlTree SMALL(Content body) { - return new HtmlTree(TagName.SMALL) + return new HtmlTree(HtmlTag.SMALL) .add(body); } @@ -845,7 +842,7 @@ public static HtmlTree SMALL(Content body) { * @return the element */ public static HtmlTree SPAN(Content body) { - return new HtmlTree(TagName.SPAN) + return new HtmlTree(HtmlTag.SPAN) .add(body); } @@ -856,7 +853,7 @@ public static HtmlTree SPAN(Content body) { * @return the element */ public static HtmlTree SPAN(HtmlStyle styleClass) { - return new HtmlTree(TagName.SPAN) + return new HtmlTree(HtmlTag.SPAN) .setStyle(styleClass); } @@ -880,7 +877,7 @@ public static HtmlTree SPAN(HtmlStyle styleClass, Content body) { * @return the element */ public static HtmlTree SPAN_ID(HtmlId id, Content body) { - return new HtmlTree(TagName.SPAN) + return new HtmlTree(HtmlTag.SPAN) .setId(id) .add(body); } @@ -894,7 +891,7 @@ public static HtmlTree SPAN_ID(HtmlId id, Content body) { * @return the element */ public static HtmlTree SPAN(HtmlId id, HtmlStyle style, Content body) { - return new HtmlTree(TagName.SPAN) + return new HtmlTree(HtmlTag.SPAN) .setId(id) .setStyle(style) .add(body); @@ -907,7 +904,7 @@ public static HtmlTree SPAN(HtmlId id, HtmlStyle style, Content body) { * @return the element */ public static HtmlTree SUMMARY(Content body) { - return new HtmlTree(TagName.SUMMARY) + return new HtmlTree(HtmlTag.SUMMARY) .add(body); } @@ -918,7 +915,7 @@ public static HtmlTree SUMMARY(Content body) { * @return the element */ public static HtmlTree SUP(Content body) { - return new HtmlTree(TagName.SUP) + return new HtmlTree(HtmlTag.SUP) .add(body); } @@ -930,7 +927,7 @@ public static HtmlTree SUP(Content body) { * @return the element */ public static HtmlTree TD(HtmlStyle style, Content body) { - return new HtmlTree(TagName.TD) + return new HtmlTree(HtmlTag.TD) .setStyle(style) .add(body); } @@ -944,7 +941,7 @@ public static HtmlTree TD(HtmlStyle style, Content body) { * @return the element */ public static HtmlTree TH(HtmlStyle style, String scope, Content body) { - return new HtmlTree(TagName.TH) + return new HtmlTree(HtmlTag.TH) .setStyle(style) .put(HtmlAttr.SCOPE, scope) .add(body); @@ -958,7 +955,7 @@ public static HtmlTree TH(HtmlStyle style, String scope, Content body) { * @return the element */ public static HtmlTree TH(String scope, Content body) { - return new HtmlTree(TagName.TH) + return new HtmlTree(HtmlTag.TH) .put(HtmlAttr.SCOPE, scope) .add(body); } @@ -970,7 +967,7 @@ public static HtmlTree TH(String scope, Content body) { * @return the element */ public static HtmlTree TITLE(String body) { - return new HtmlTree(TagName.TITLE) + return new HtmlTree(HtmlTag.TITLE) .add(body); } @@ -981,7 +978,7 @@ public static HtmlTree TITLE(String body) { * @return the element */ public static HtmlTree UL(HtmlStyle style) { - return new HtmlTree(TagName.UL) + return new HtmlTree(HtmlTag.UL) .setStyle(style); } @@ -994,7 +991,7 @@ public static HtmlTree UL(HtmlStyle style) { * @return the element */ public static HtmlTree UL(HtmlStyle style, Content first, Content... more) { - var ul = new HtmlTree(TagName.UL) + var ul = new HtmlTree(HtmlTag.UL) .setStyle(style); ul.add(first); for (Content c : more) { @@ -1013,7 +1010,7 @@ public static HtmlTree UL(HtmlStyle style, Content first, Content... more) { * @return the element */ public static HtmlTree UL(HtmlStyle style, Collection items, Function mapper) { - return new HtmlTree(TagName.UL) + return new HtmlTree(HtmlTag.UL) .setStyle(style) .addAll(items, mapper); } @@ -1025,7 +1022,7 @@ public boolean isEmpty() { @Override public boolean isPhrasingContent() { - return tagName.phrasingContent; + return tag.blockType == HtmlTag.BlockType.INLINE; } /** @@ -1069,7 +1066,7 @@ public boolean isDiscardable() { return !isVoid() && !hasContent() && !hasAttr(HtmlAttr.ID) - && tagName != TagName.SCRIPT; + && tag != HtmlTag.SCRIPT; } /** @@ -1080,22 +1077,22 @@ public boolean isDiscardable() { * @see Phrasing Content */ public boolean isInline() { - return switch (tagName) { + return switch (tag) { case A, BUTTON, BR, CODE, EM, I, IMG, LABEL, SMALL, SPAN, STRONG, SUB, SUP, WBR -> true; default -> false; }; } /** - * Returns whether or not this is a void element. + * Returns whether this is a void element. * - * @return whether or not this is a void element + * @return whether this is a void element * * @see Void Elements */ public boolean isVoid() { - return switch (tagName) { - case BR, HR, IMG, INPUT, LINK, META, WBR -> true; + return switch (tag) { + case BR, COL, FRAME, HR, IMG, INPUT, LINK, META, WBR -> true; default -> false; }; } @@ -1106,14 +1103,14 @@ public boolean write(Writer out, String newline, boolean atNewline) throws IOExc if (!isInline && !atNewline) { out.write(newline); } - String tagString = tagName.toString(); + String tagString = tag.getName(); out.write("<"); out.write(tagString); for (var attr : attrs.entrySet()) { var key = attr.getKey(); var value = attr.getValue(); out.write(" "); - out.write(key.toString()); + out.write(key.getName()); if (!value.isEmpty()) { out.write("=\""); out.write(value.replace("\"", """)); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/ListBuilder.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/ListBuilder.java similarity index 97% rename from src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/ListBuilder.java rename to src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/ListBuilder.java index 603e571789564..05c9f8388dbc6 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/ListBuilder.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/ListBuilder.java @@ -23,7 +23,7 @@ * questions. */ -package jdk.javadoc.internal.doclets.formats.html.markup; +package jdk.javadoc.internal.html; import java.io.IOException; import java.io.Writer; @@ -32,8 +32,6 @@ import java.util.NoSuchElementException; import java.util.Objects; -import jdk.javadoc.internal.doclets.formats.html.Content; - /** * A utility class for building nested HTML lists. This class is implemented as a * stack of nested list/item pairs where list items are added to the inner-most diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/RawHtml.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/RawHtml.java similarity index 96% rename from src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/RawHtml.java rename to src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/RawHtml.java index a71ea7831da4a..1c9f60f69e866 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/RawHtml.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/RawHtml.java @@ -23,15 +23,13 @@ * questions. */ -package jdk.javadoc.internal.doclets.formats.html.markup; +package jdk.javadoc.internal.html; import java.io.IOException; import java.io.Writer; import java.util.regex.Matcher; import java.util.regex.Pattern; -import jdk.javadoc.internal.doclets.formats.html.Content; - /** * Class for generating raw HTML content to be added to HTML pages of javadoc output. */ @@ -147,8 +145,8 @@ public boolean isPhrasingContent() { Matcher m = tag.matcher(rawHtmlContent); while (m.find()) { try { - var tn = TagName.of(m.group("tag")); - if (!tn.phrasingContent) { + var tn = HtmlTag.of(m.group("tag")); + if (tn.blockType != HtmlTag.BlockType.INLINE) { return false; } } catch (IllegalArgumentException e) { diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Script.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/Script.java similarity index 97% rename from src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Script.java rename to src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/Script.java index f194aa5527a53..a5fc15215092c 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Script.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/Script.java @@ -23,13 +23,11 @@ * questions. */ -package jdk.javadoc.internal.doclets.formats.html.markup; +package jdk.javadoc.internal.html; import java.io.IOException; import java.io.Writer; -import jdk.javadoc.internal.doclets.formats.html.Content; - /** * A builder for HTML script elements. */ @@ -100,7 +98,7 @@ public Script appendStringLiteral(CharSequence text, char quoteChar) { */ public Content asContent() { ScriptContent scriptContent = new ScriptContent(sb); - var script = new HtmlTree(TagName.SCRIPT) { + var script = new HtmlTree(HtmlTag.SCRIPT) { @Override public HtmlTree add(Content c) { if (c != scriptContent) { diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Text.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/Text.java similarity index 97% rename from src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Text.java rename to src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/Text.java index e05ca73001af7..78bb5cb89e66c 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Text.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/Text.java @@ -23,13 +23,11 @@ * questions. */ -package jdk.javadoc.internal.doclets.formats.html.markup; +package jdk.javadoc.internal.html; import java.io.IOException; import java.io.Writer; -import jdk.javadoc.internal.doclets.formats.html.Content; - /** * Class for containing immutable string content for HTML tags of javadoc output. * Newlines are always represented by {@code \n}. diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/TextBuilder.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/TextBuilder.java similarity index 96% rename from src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/TextBuilder.java rename to src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/TextBuilder.java index 6c4d66024c58a..f27e5922043f6 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/TextBuilder.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/html/TextBuilder.java @@ -23,13 +23,11 @@ * questions. */ -package jdk.javadoc.internal.doclets.formats.html.markup; +package jdk.javadoc.internal.html; import java.io.IOException; import java.io.Writer; -import jdk.javadoc.internal.doclets.formats.html.Content; - /** * Class for generating string content for HTML tags of javadoc output. * The content is mutable to the extent that additional content may be added. diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/package-info.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/package-info.java index 4f5601b96003d..dffb34f1e9306 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/package-info.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/package-info.java @@ -68,9 +68,9 @@ * library in the * {@link jdk.javadoc.internal.doclets.formats.html.markup formats.html.markup} package, * to create trees (or acyclic graphs) of - * {@linkplain jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree HTML tree nodes}. + * {@linkplain jdk.javadoc.internal.html.HtmlTree HTML tree nodes}. * Apart from using a common format-neutral supertype, - * {@link jdk.javadoc.internal.doclets.formats.html.Content}, the {@code markup} library + * {@link jdk.javadoc.internal.html.Content}, the {@code markup} library * is mostly independent of the rest of the javadoc software stack. * *

Toolkit diff --git a/test/langtools/jdk/javadoc/doclet/checkStylesheetClasses/CheckStylesheetClasses.java b/test/langtools/jdk/javadoc/doclet/checkStylesheetClasses/CheckStylesheetClasses.java index b26f2afe96be1..f103ef4e608f0 100644 --- a/test/langtools/jdk/javadoc/doclet/checkStylesheetClasses/CheckStylesheetClasses.java +++ b/test/langtools/jdk/javadoc/doclet/checkStylesheetClasses/CheckStylesheetClasses.java @@ -26,7 +26,8 @@ * @test * @bug 8267574 * @summary check stylesheet names against HtmlStyle - * @modules jdk.javadoc/jdk.javadoc.internal.doclets.formats.html.markup + * @modules jdk.javadoc/jdk.javadoc.internal.html + * jdk.javadoc/jdk.javadoc.internal.doclets.formats.html.markup * jdk.javadoc/jdk.javadoc.internal.doclets.formats.html.resources:open */ @@ -44,10 +45,11 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; +import jdk.javadoc.internal.html.HtmlStyle; +import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyles; /** - * This test compares the set of CSS class names defined in HtmlStyle + * This test compares the set of CSS class names defined in HtmlStyles * and other files (such as search.js) against the set of CSS class names * defined in the main stylesheet.css provided by the doclet. * @@ -185,7 +187,7 @@ void error(String message) { } Set getHtmlStyleNames() { - return Arrays.stream(HtmlStyle.values()) + return Arrays.stream(HtmlStyles.values()) .map(HtmlStyle::cssName) .collect(Collectors.toCollection(TreeSet::new)); } @@ -193,7 +195,7 @@ Set getHtmlStyleNames() { Set getStylesheetNames() throws IOException { Set names = new TreeSet<>(); String stylesheet = "/jdk/javadoc/internal/doclets/formats/html/resources/stylesheet.css"; - URL url = HtmlStyle.class.getResource(stylesheet); + URL url = HtmlStyles.class.getResource(stylesheet); readStylesheet(url, names); return names; } diff --git a/test/langtools/jdk/javadoc/doclet/testHtmlDocument/TestHtmlDocument.java b/test/langtools/jdk/javadoc/doclet/testHtmlDocument/TestHtmlDocument.java index 7472a2c397e88..9a9b20541c8b6 100644 --- a/test/langtools/jdk/javadoc/doclet/testHtmlDocument/TestHtmlDocument.java +++ b/test/langtools/jdk/javadoc/doclet/testHtmlDocument/TestHtmlDocument.java @@ -28,6 +28,7 @@ * @library ../../lib * @modules jdk.javadoc/jdk.javadoc.internal.doclets.formats.html.markup * jdk.javadoc/jdk.javadoc.internal.doclets.toolkit.util + * jdk.javadoc/jdk.javadoc.internal.html * jdk.javadoc/jdk.javadoc.internal.tool * @build javadoc.tester.* * @run main TestHtmlDocument @@ -35,6 +36,7 @@ import jdk.javadoc.internal.doclets.formats.html.markup.*; +import jdk.javadoc.internal.html.*; /** * The class reads each file, complete with newlines, into a string to easily @@ -68,19 +70,19 @@ public void test() { // Generate the HTML output using the HTML document generation within doclet. public static String generateHtmlTree() { // Document type for the HTML document - HtmlTree html = new HtmlTree(TagName.HTML); - HtmlTree head = new HtmlTree(TagName.HEAD); - HtmlTree title = new HtmlTree(TagName.TITLE); + HtmlTree html = new HtmlTree(HtmlTag.HTML); + HtmlTree head = new HtmlTree(HtmlTag.HEAD); + HtmlTree title = new HtmlTree(HtmlTag.TITLE); // String content within the document TextBuilder titleContent = new TextBuilder("Markup test"); title.add(titleContent); head.add(title); // Test META tag - HtmlTree meta = new HtmlTree(TagName.META); + HtmlTree meta = new HtmlTree(HtmlTag.META); meta.put(HtmlAttr.NAME, "keywords"); meta.put(HtmlAttr.CONTENT, "testContent"); head.add(meta); - HtmlTree link = new HtmlTree(TagName.LINK); + HtmlTree link = new HtmlTree(HtmlTag.LINK); link.put(HtmlAttr.REL, "testRel"); link.put(HtmlAttr.HREF, "testLink.html"); head.add(link); @@ -88,10 +90,10 @@ public static String generateHtmlTree() { // Comment within the document Comment bodyMarker = new Comment("======== START OF BODY ========"); html.add(bodyMarker); - HtmlTree body = new HtmlTree(TagName.BODY); + HtmlTree body = new HtmlTree(HtmlTag.BODY); Comment pMarker = new Comment("======== START OF PARAGRAPH ========"); body.add(pMarker); - HtmlTree p = new HtmlTree(TagName.P); + HtmlTree p = new HtmlTree(HtmlTag.P); TextBuilder bodyContent = new TextBuilder( "This document is generated from sample source code and HTML " + "files with examples of a wide variety of Java language constructs: packages, " + @@ -104,24 +106,24 @@ public static String generateHtmlTree() { TextBuilder pContent = new TextBuilder(" to out a link."); p.add(pContent); body.add(p); - HtmlTree p1 = new HtmlTree(TagName.P); + HtmlTree p1 = new HtmlTree(HtmlTag.P); // Test another version of A tag. - HtmlTree anchor = new HtmlTree(TagName.A); + HtmlTree anchor = new HtmlTree(HtmlTag.A); anchor.put(HtmlAttr.HREF, "testLink.html"); anchor.put(HtmlAttr.ID, "Another version of a tag"); p1.add(anchor); body.add(p1); // Test for empty tags. - HtmlTree dl = new HtmlTree(TagName.DL); + HtmlTree dl = new HtmlTree(HtmlTag.DL); html.add(dl); // Test for empty nested tags. - HtmlTree dlTree = new HtmlTree(TagName.DL); - dlTree.add(new HtmlTree(TagName.DT)); - dlTree.add(new HtmlTree (TagName.DD)); + HtmlTree dlTree = new HtmlTree(HtmlTag.DL); + dlTree.add(new HtmlTree(HtmlTag.DT)); + dlTree.add(new HtmlTree (HtmlTag.DD)); html.add(dlTree); - HtmlTree dlDisplay = new HtmlTree(TagName.DL); - dlDisplay.add(new HtmlTree(TagName.DT)); - HtmlTree dd = new HtmlTree (TagName.DD); + HtmlTree dlDisplay = new HtmlTree(HtmlTag.DL); + dlDisplay.add(new HtmlTree(HtmlTag.DT)); + HtmlTree dd = new HtmlTree (HtmlTag.DD); TextBuilder ddContent = new TextBuilder("Test DD"); dd.add(ddContent); dlDisplay.add(dd); @@ -130,7 +132,7 @@ public static String generateHtmlTree() { body.add(emptyString); Comment emptyComment = new Comment(""); body.add(emptyComment); - HtmlTree hr = new HtmlTree(TagName.HR); + HtmlTree hr = new HtmlTree(HtmlTag.HR); body.add(hr); html.add(body); HtmlDocument htmlDoc = new HtmlDocument(html); diff --git a/test/langtools/jdk/javadoc/doclet/testHtmlTableStyles/TestHtmlTableStyles.java b/test/langtools/jdk/javadoc/doclet/testHtmlTableStyles/TestHtmlTableStyles.java index 2225de2f9c5d4..c11e6d5f720fa 100644 --- a/test/langtools/jdk/javadoc/doclet/testHtmlTableStyles/TestHtmlTableStyles.java +++ b/test/langtools/jdk/javadoc/doclet/testHtmlTableStyles/TestHtmlTableStyles.java @@ -50,7 +50,7 @@ public void test() { checkOutput(Output.OUT, true, "attribute not supported in HTML5: summary", """ - attribute "border" for table only accepts "" or "1": BORDER""", + attribute "border" for table only accepts "" or "1": border""", "attribute not supported in HTML5: cellpadding", "attribute not supported in HTML5: cellspacing", "attribute not supported in HTML5: align"); diff --git a/test/langtools/jdk/javadoc/doclet/testVoidHtmlElements/TestVoidHtmlElements.java b/test/langtools/jdk/javadoc/doclet/testVoidHtmlElements/TestVoidHtmlElements.java index 6229533af4a55..bd44fe8814119 100644 --- a/test/langtools/jdk/javadoc/doclet/testVoidHtmlElements/TestVoidHtmlElements.java +++ b/test/langtools/jdk/javadoc/doclet/testVoidHtmlElements/TestVoidHtmlElements.java @@ -25,13 +25,12 @@ * @test * @bug 8266856 * @modules jdk.javadoc/jdk.javadoc.internal.doclint - * jdk.javadoc/jdk.javadoc.internal.doclets.formats.html.markup + * jdk.javadoc/jdk.javadoc.internal.html * @run main TestVoidHtmlElements */ -import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; -import jdk.javadoc.internal.doclets.formats.html.markup.TagName; -import jdk.javadoc.internal.doclint.HtmlTag; +import jdk.javadoc.internal.html.HtmlTree; +import jdk.javadoc.internal.html.HtmlTag; public class TestVoidHtmlElements { @@ -42,9 +41,8 @@ public static void main(String[] args) { // check that the definition of void-ness is the same. for (HtmlTag htmlTag : HtmlTag.values()) { try { - TagName tagName = TagName.valueOf(htmlTag.name()); checks++; - check(htmlTag, tagName); + check(htmlTag); } catch (IllegalArgumentException e) { // no matching TagName } @@ -56,8 +54,8 @@ public static void main(String[] args) { System.out.println(checks + " checks passed"); } - private static void check(HtmlTag htmlTag, TagName tagName) { - boolean elementIsVoid = new HtmlTree(tagName).isVoid(); + private static void check(HtmlTag htmlTag) { + boolean elementIsVoid = new HtmlTree(htmlTag).isVoid(); boolean elementHasNoEndTag = htmlTag.endKind == HtmlTag.EndKind.NONE; if (elementIsVoid != elementHasNoEndTag) { throw new AssertionError(htmlTag + ", " + elementIsVoid + ", " + elementHasNoEndTag); diff --git a/test/langtools/tools/doclint/CoverageExtras.java b/test/langtools/tools/doclint/CoverageExtras.java index 5a6c90c4b7462..55ac63d6ab3d4 100644 --- a/test/langtools/tools/doclint/CoverageExtras.java +++ b/test/langtools/tools/doclint/CoverageExtras.java @@ -26,13 +26,15 @@ * @bug 8006263 * @summary Supplementary test cases needed for doclint * @modules jdk.javadoc/jdk.javadoc.internal.doclint + * jdk.javadoc/jdk.javadoc.internal.html */ import java.util.Objects; import jdk.javadoc.internal.doclint.Checker; -import jdk.javadoc.internal.doclint.HtmlTag; import jdk.javadoc.internal.doclint.Messages; +import jdk.javadoc.internal.html.HtmlAttr; +import jdk.javadoc.internal.html.HtmlTag; public class CoverageExtras { public static void main(String... args) { @@ -41,8 +43,8 @@ public static void main(String... args) { void run() { check(HtmlTag.A, HtmlTag.valueOf("A"), HtmlTag.values()); - check(HtmlTag.Attr.ABBR, HtmlTag.Attr.valueOf("ABBR"), HtmlTag.Attr.values()); - check(HtmlTag.AttrKind.INVALID, HtmlTag.AttrKind.valueOf("INVALID"), HtmlTag.AttrKind.values()); + check(HtmlAttr.ABBR, HtmlAttr.valueOf("ABBR"), HtmlAttr.values()); + check(HtmlAttr.AttrKind.INVALID, HtmlAttr.AttrKind.valueOf("INVALID"), HtmlAttr.AttrKind.values()); check(HtmlTag.BlockType.BLOCK, HtmlTag.BlockType.valueOf("BLOCK"), HtmlTag.BlockType.values()); check(HtmlTag.EndKind.NONE, HtmlTag.EndKind.valueOf("NONE"), HtmlTag.EndKind.values()); check(HtmlTag.Flag.EXPECT_CONTENT, HtmlTag.Flag.valueOf("EXPECT_CONTENT"), HtmlTag.Flag.values()); diff --git a/test/langtools/tools/doclint/html/HtmlVersionTagsAttrsTest.java b/test/langtools/tools/doclint/html/HtmlVersionTagsAttrsTest.java index 3b8f29d2d62af..6ef32c881bb78 100644 --- a/test/langtools/tools/doclint/html/HtmlVersionTagsAttrsTest.java +++ b/test/langtools/tools/doclint/html/HtmlVersionTagsAttrsTest.java @@ -100,10 +100,6 @@ public void SupportedAttrs_html5() { } * * hgroup no longer supported in HTML5. * - *
- * Summary - *

Details and Summary no longer supported in HTML5

- *
*/ public void notSupportedTags_html5() { } @@ -152,6 +148,10 @@ public void notSupportedTags_html5() { } * *

Test current time is at night

*

Testtext

+ *
+ * Summary + *

Details

+ *
*/ public void SupportedTags_html5() { } diff --git a/test/langtools/tools/doclint/html/HtmlVersionTagsAttrsTest.out b/test/langtools/tools/doclint/html/HtmlVersionTagsAttrsTest.out index 69b31d53831f4..badd9ea998273 100644 --- a/test/langtools/tools/doclint/html/HtmlVersionTagsAttrsTest.out +++ b/test/langtools/tools/doclint/html/HtmlVersionTagsAttrsTest.out @@ -226,7 +226,7 @@ HtmlVersionTagsAttrsTest.java:67: error: attribute not supported in HTML5: width HtmlVersionTagsAttrsTest.java:68: error: attribute not supported in HTML5: name * Anchor Test ^ -HtmlVersionTagsAttrsTest.java:69: error: attribute "border" for table only accepts "" or "1": BORDER +HtmlVersionTagsAttrsTest.java:69: error: attribute "border" for table only accepts "" or "1": 0 * ^ HtmlVersionTagsAttrsTest.java:71: error: no caption for table @@ -259,19 +259,7 @@ HtmlVersionTagsAttrsTest.java:97: error: unknown tag: hgroup HtmlVersionTagsAttrsTest.java:100: error: unknown tag: hgroup * ^ -HtmlVersionTagsAttrsTest.java:103: error: unknown tag: details - *
- ^ -HtmlVersionTagsAttrsTest.java:104: error: unknown tag: summary - * Summary - ^ -HtmlVersionTagsAttrsTest.java:104: error: unknown tag: summary - * Summary - ^ -HtmlVersionTagsAttrsTest.java:106: error: unknown tag: details - *
- ^ -HtmlVersionTagsAttrsTest.java:129: error: element not allowed in documentation comments:
+HtmlVersionTagsAttrsTest.java:125: error: element not allowed in documentation comments:
*
^ HtmlVersionTagsAttrsTest.java:161: error: heading not found for @@ -298,7 +286,7 @@ HtmlVersionTagsAttrsTest.java:181: error: tag not allowed here:
HtmlVersionTagsAttrsTest.java:184: error: element not allowed in documentation comments:
*
^ -HtmlVersionTagsAttrsTest.java:189: error: attribute "border" for table only accepts "" or "1": BORDER +HtmlVersionTagsAttrsTest.java:189: error: attribute "border" for table only accepts "" or "1": 2 *
^ HtmlVersionTagsAttrsTest.java:191: error: no caption for table @@ -310,5 +298,5 @@ HtmlVersionTagsAttrsTest.java:202: error: no caption for table HtmlVersionTagsAttrsTest.java:205: error: no caption for table *
^ -102 errors +98 errors 2 warnings diff --git a/test/langtools/tools/doclint/html/OtherTagsTest.java b/test/langtools/tools/doclint/html/OtherTagsTest.java index e64b12a71a8b2..6da198b3cef4c 100644 --- a/test/langtools/tools/doclint/html/OtherTagsTest.java +++ b/test/langtools/tools/doclint/html/OtherTagsTest.java @@ -16,7 +16,7 @@ public class OtherTagsTest { * * *
- * + * * * * diff --git a/test/langtools/tools/doclint/html/OtherTagsTest.out b/test/langtools/tools/doclint/html/OtherTagsTest.out index 571df0f20a3df..f8e06bb6bb6c0 100644 --- a/test/langtools/tools/doclint/html/OtherTagsTest.out +++ b/test/langtools/tools/doclint/html/OtherTagsTest.out @@ -13,9 +13,6 @@ OtherTagsTest.java:17: error: element not allowed in documentation comments: ^ -OtherTagsTest.java:19: error: element not allowed in documentation comments: - * - ^ OtherTagsTest.java:20: error: element not allowed in documentation comments: * ^ @@ -25,4 +22,4 @@ OtherTagsTest.java:21: error: tag not supported in HTML5: noframes OtherTagsTest.java:23: error: element not allowed in documentation comments: * <title> ^ -9 errors +8 errors From 34edc7358f733cdf433d0ff50921bcb5a94c5e35 Mon Sep 17 00:00:00 2001 From: Vladimir Kozlov Date: Sat, 3 Aug 2024 06:21:28 +0000 Subject: [PATCH 179/353] 8337396: Cleanup usage of ExternalAddess Co-authored-by: Fei Yang Reviewed-by: vlivanov, adinn --- .../cpu/aarch64/macroAssembler_aarch64.cpp | 8 +- .../cpu/aarch64/stubGenerator_aarch64.cpp | 2 +- .../templateInterpreterGenerator_aarch64.cpp | 12 +-- .../cpu/riscv/macroAssembler_riscv.cpp | 4 +- src/hotspot/cpu/riscv/stubGenerator_riscv.cpp | 2 +- .../templateInterpreterGenerator_riscv.cpp | 6 +- src/hotspot/cpu/x86/stubGenerator_x86_64.cpp | 2 +- .../x86/templateInterpreterGenerator_x86.cpp | 6 +- src/hotspot/cpu/x86/templateTable_x86.cpp | 18 ++-- src/hotspot/share/code/oopRecorder.cpp | 92 ++++++++++++++++++- 10 files changed, 117 insertions(+), 35 deletions(-) diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp index f90aefc8fd3e6..e210c8b3de05a 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp @@ -736,7 +736,7 @@ void MacroAssembler::reserved_stack_check() { br(Assembler::LO, no_reserved_zone_enabling); enter(); // LR and FP are live. - lea(rscratch1, CAST_FROM_FN_PTR(address, SharedRuntime::enable_stack_reserved_zone)); + lea(rscratch1, RuntimeAddress(CAST_FROM_FN_PTR(address, SharedRuntime::enable_stack_reserved_zone))); mov(c_rarg0, rthread); blr(rscratch1); leave(); @@ -1879,7 +1879,7 @@ void MacroAssembler::_verify_oop(Register reg, const char* s, const char* file, movptr(rscratch1, (uintptr_t)(address)b); // call indirectly to solve generation ordering problem - lea(rscratch2, ExternalAddress(StubRoutines::verify_oop_subroutine_entry_address())); + lea(rscratch2, RuntimeAddress(StubRoutines::verify_oop_subroutine_entry_address())); ldr(rscratch2, Address(rscratch2)); blr(rscratch2); @@ -1918,7 +1918,7 @@ void MacroAssembler::_verify_oop_addr(Address addr, const char* s, const char* f movptr(rscratch1, (uintptr_t)(address)b); // call indirectly to solve generation ordering problem - lea(rscratch2, ExternalAddress(StubRoutines::verify_oop_subroutine_entry_address())); + lea(rscratch2, RuntimeAddress(StubRoutines::verify_oop_subroutine_entry_address())); ldr(rscratch2, Address(rscratch2)); blr(rscratch2); @@ -6454,7 +6454,7 @@ void MacroAssembler::verify_cross_modify_fence_not_required() { Label fence_not_required; cbz(rscratch1, fence_not_required); // If it does then fail. - lea(rscratch1, CAST_FROM_FN_PTR(address, JavaThread::verify_cross_modify_fence_failure)); + lea(rscratch1, RuntimeAddress(CAST_FROM_FN_PTR(address, JavaThread::verify_cross_modify_fence_failure))); mov(c_rarg0, rthread); blr(rscratch1); bind(fence_not_required); diff --git a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp index 3f1a4423b5efe..5e2ef97e4a3ad 100644 --- a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp @@ -7045,7 +7045,7 @@ class StubGenerator: public StubCodeGenerator { Label thaw_success; // rscratch2 contains the size of the frames to thaw, 0 if overflow or no more frames __ cbnz(rscratch2, thaw_success); - __ lea(rscratch1, ExternalAddress(StubRoutines::throw_StackOverflowError_entry())); + __ lea(rscratch1, RuntimeAddress(StubRoutines::throw_StackOverflowError_entry())); __ br(rscratch1); __ bind(thaw_success); diff --git a/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp index 89f5fbd281b79..d639d9cf17ee5 100644 --- a/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -1337,8 +1337,8 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { { Label L; __ ldr(r10, Address(rmethod, Method::native_function_offset())); - address unsatisfied = (SharedRuntime::native_method_throw_unsatisfied_link_error_entry()); - __ mov(rscratch2, unsatisfied); + ExternalAddress unsatisfied(SharedRuntime::native_method_throw_unsatisfied_link_error_entry()); + __ lea(rscratch2, unsatisfied); __ ldr(rscratch2, rscratch2); __ cmp(r10, rscratch2); __ br(Assembler::NE, L); @@ -1432,7 +1432,7 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { // hand. // __ mov(c_rarg0, rthread); - __ mov(rscratch2, CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans)); + __ lea(rscratch2, RuntimeAddress(CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans))); __ blr(rscratch2); __ get_method(rmethod); __ reinit_heapbase(); @@ -1482,7 +1482,7 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { __ push_call_clobbered_registers(); __ mov(c_rarg0, rthread); - __ mov(rscratch2, CAST_FROM_FN_PTR(address, SharedRuntime::reguard_yellow_pages)); + __ lea(rscratch2, RuntimeAddress(CAST_FROM_FN_PTR(address, SharedRuntime::reguard_yellow_pages))); __ blr(rscratch2); __ pop_call_clobbered_registers(); @@ -2085,7 +2085,7 @@ void TemplateInterpreterGenerator::trace_bytecode(Template* t) { assert(Interpreter::trace_code(t->tos_in()) != nullptr, "entry must have been generated"); - __ bl(Interpreter::trace_code(t->tos_in())); + __ bl(RuntimeAddress(Interpreter::trace_code(t->tos_in()))); __ reinit_heapbase(); } diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index e349eab317760..cd7a4ecf22803 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -547,7 +547,7 @@ void MacroAssembler::_verify_oop(Register reg, const char* s, const char* file, } // call indirectly to solve generation ordering problem - ExternalAddress target(StubRoutines::verify_oop_subroutine_entry_address()); + RuntimeAddress target(StubRoutines::verify_oop_subroutine_entry_address()); relocate(target.rspec(), [&] { int32_t offset; la(t1, target.target(), offset); @@ -592,7 +592,7 @@ void MacroAssembler::_verify_oop_addr(Address addr, const char* s, const char* f } // call indirectly to solve generation ordering problem - ExternalAddress target(StubRoutines::verify_oop_subroutine_entry_address()); + RuntimeAddress target(StubRoutines::verify_oop_subroutine_entry_address()); relocate(target.rspec(), [&] { int32_t offset; la(t1, target.target(), offset); diff --git a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp index f78d7261e40a5..198835d733f79 100644 --- a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp +++ b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp @@ -3774,7 +3774,7 @@ class StubGenerator: public StubCodeGenerator { Label thaw_success; // t1 contains the size of the frames to thaw, 0 if overflow or no more frames __ bnez(t1, thaw_success); - __ la(t0, ExternalAddress(StubRoutines::throw_StackOverflowError_entry())); + __ la(t0, RuntimeAddress(StubRoutines::throw_StackOverflowError_entry())); __ jr(t0); __ bind(thaw_success); diff --git a/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp b/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp index 769e4dc5ccc78..f01945bc6a3d1 100644 --- a/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp +++ b/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp @@ -1111,8 +1111,8 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { { Label L; __ ld(x28, Address(xmethod, Method::native_function_offset())); - address unsatisfied = (SharedRuntime::native_method_throw_unsatisfied_link_error_entry()); - __ mv(t, unsatisfied); + ExternalAddress unsatisfied(SharedRuntime::native_method_throw_unsatisfied_link_error_entry()); + __ la(t, unsatisfied); __ load_long_misaligned(t1, Address(t, 0), t0, 2); // 2 bytes aligned, but not 4 or 8 __ bne(x28, t1, L); @@ -1815,7 +1815,7 @@ void TemplateInterpreterGenerator::trace_bytecode(Template* t) { // the tosca in-state for the given template. assert(Interpreter::trace_code(t->tos_in()) != nullptr, "entry must have been generated"); - __ call(Interpreter::trace_code(t->tos_in())); + __ rt_call(Interpreter::trace_code(t->tos_in())); __ reinit_heapbase(); } diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp index c9c4b056eb59d..a7404b298f673 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp @@ -3702,7 +3702,7 @@ address StubGenerator::generate_cont_thaw(const char* label, Continuation::thaw_ Label L_thaw_success; __ testptr(rbx, rbx); __ jccb(Assembler::notZero, L_thaw_success); - __ jump(ExternalAddress(StubRoutines::throw_StackOverflowError_entry())); + __ jump(RuntimeAddress(StubRoutines::throw_StackOverflowError_entry())); __ bind(L_thaw_success); // Make room for the thawed frames and align the stack. diff --git a/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp b/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp index fe2bf67afc96e..3b32d577d4470 100644 --- a/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp +++ b/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -178,7 +178,7 @@ address TemplateInterpreterGenerator::generate_exception_handler_common( rarg, rarg2); } // throw exception - __ jump(ExternalAddress(Interpreter::throw_exception_entry())); + __ jump(RuntimeAddress(Interpreter::throw_exception_entry())); return entry; } @@ -546,7 +546,7 @@ void TemplateInterpreterGenerator::generate_stack_overflow_check(void) { // Note: the restored frame is not necessarily interpreted. // Use the shared runtime version of the StackOverflowError. assert(StubRoutines::throw_StackOverflowError_entry() != nullptr, "stub not yet generated"); - __ jump(ExternalAddress(StubRoutines::throw_StackOverflowError_entry())); + __ jump(RuntimeAddress(StubRoutines::throw_StackOverflowError_entry())); // all done with frame size check __ bind(after_frame_check_pop); NOT_LP64(__ pop(rsi)); diff --git a/src/hotspot/cpu/x86/templateTable_x86.cpp b/src/hotspot/cpu/x86/templateTable_x86.cpp index 6446ec6598791..fc6844aedd6b2 100644 --- a/src/hotspot/cpu/x86/templateTable_x86.cpp +++ b/src/hotspot/cpu/x86/templateTable_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -774,7 +774,7 @@ void TemplateTable::index_check_without_pop(Register array, Register index) { __ jccb(Assembler::below, skip); // Pass array to create more detailed exceptions. __ mov(NOT_LP64(rax) LP64_ONLY(c_rarg1), array); - __ jump(ExternalAddress(Interpreter::_throw_ArrayIndexOutOfBoundsException_entry)); + __ jump(RuntimeAddress(Interpreter::_throw_ArrayIndexOutOfBoundsException_entry)); __ bind(skip); } @@ -1152,7 +1152,7 @@ void TemplateTable::aastore() { // Come here on failure // object is at TOS - __ jump(ExternalAddress(Interpreter::_throw_ArrayStoreException_entry)); + __ jump(RuntimeAddress(Interpreter::_throw_ArrayStoreException_entry)); // Come here on success __ bind(ok_is_subtype); @@ -1432,7 +1432,7 @@ void TemplateTable::ldiv() { // generate explicit div0 check __ testq(rcx, rcx); __ jump_cc(Assembler::zero, - ExternalAddress(Interpreter::_throw_ArithmeticException_entry)); + RuntimeAddress(Interpreter::_throw_ArithmeticException_entry)); // Note: could xor rax and rcx and compare with (-1 ^ min_int). If // they are not equal, one could do a normal division (no correction // needed), which may speed up this implementation for the common case. @@ -1445,7 +1445,7 @@ void TemplateTable::ldiv() { // check if y = 0 __ orl(rax, rdx); __ jump_cc(Assembler::zero, - ExternalAddress(Interpreter::_throw_ArithmeticException_entry)); + RuntimeAddress(Interpreter::_throw_ArithmeticException_entry)); __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::ldiv)); __ addptr(rsp, 4 * wordSize); // take off temporaries #endif @@ -1458,7 +1458,7 @@ void TemplateTable::lrem() { __ pop_l(rax); __ testq(rcx, rcx); __ jump_cc(Assembler::zero, - ExternalAddress(Interpreter::_throw_ArithmeticException_entry)); + RuntimeAddress(Interpreter::_throw_ArithmeticException_entry)); // Note: could xor rax and rcx and compare with (-1 ^ min_int). If // they are not equal, one could do a normal division (no correction // needed), which may speed up this implementation for the common case. @@ -1472,7 +1472,7 @@ void TemplateTable::lrem() { // check if y = 0 __ orl(rax, rdx); __ jump_cc(Assembler::zero, - ExternalAddress(Interpreter::_throw_ArithmeticException_entry)); + RuntimeAddress(Interpreter::_throw_ArithmeticException_entry)); __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::lrem)); __ addptr(rsp, 4 * wordSize); #endif @@ -4222,7 +4222,7 @@ void TemplateTable::checkcast() { // Come here on failure __ push_ptr(rdx); // object is at TOS - __ jump(ExternalAddress(Interpreter::_throw_ClassCastException_entry)); + __ jump(RuntimeAddress(Interpreter::_throw_ClassCastException_entry)); // Come here on success __ bind(ok_is_subtype); @@ -4340,7 +4340,7 @@ void TemplateTable::_breakpoint() { void TemplateTable::athrow() { transition(atos, vtos); __ null_check(rax); - __ jump(ExternalAddress(Interpreter::throw_exception_entry())); + __ jump(RuntimeAddress(Interpreter::throw_exception_entry())); } //----------------------------------------------------------------------------- diff --git a/src/hotspot/share/code/oopRecorder.cpp b/src/hotspot/share/code/oopRecorder.cpp index fd13b1050410e..1849493974ca4 100644 --- a/src/hotspot/share/code/oopRecorder.cpp +++ b/src/hotspot/share/code/oopRecorder.cpp @@ -32,6 +32,7 @@ #include "oops/oop.inline.hpp" #include "runtime/jniHandles.inline.hpp" #include "runtime/mutexLocker.hpp" +#include "runtime/os.hpp" #include "utilities/copy.hpp" #ifdef ASSERT @@ -220,6 +221,11 @@ ExternalsRecorder* ExternalsRecorder::_recorder = nullptr; ExternalsRecorder::ExternalsRecorder(): _arena(mtCode), _externals(&_arena) {} +#ifndef PRODUCT +static int total_access_count = 0; +static GrowableArray* extern_hist = nullptr; +#endif + void ExternalsRecorder_init() { ExternalsRecorder::initialize(); } @@ -228,30 +234,106 @@ void ExternalsRecorder::initialize() { // After Mutex and before CodeCache are initialized assert(_recorder == nullptr, "should initialize only once"); _recorder = new ExternalsRecorder(); +#ifndef PRODUCT + if (PrintNMethodStatistics) { + Arena* arena = &_recorder->_arena; + extern_hist = new(arena) GrowableArray(arena, 512, 512, 0); + } +#endif } int ExternalsRecorder::find_index(address adr) { - MutexLocker ml(ExternalsRecorder_lock, Mutex::_no_safepoint_check_flag); assert(_recorder != nullptr, "sanity"); - return _recorder->_externals.find_index(adr); + MutexLocker ml(ExternalsRecorder_lock, Mutex::_no_safepoint_check_flag); + int index = _recorder->_externals.find_index(adr); +#ifndef PRODUCT + if (PrintNMethodStatistics) { + total_access_count++; + int n = extern_hist->at_grow(index, 0); + extern_hist->at_put(index, (n + 1)); + } +#endif + return index; } address ExternalsRecorder::at(int index) { + assert(_recorder != nullptr, "sanity"); // find_index() may resize array by reallocating it and freeing old, // we need loock here to make sure we not accessing to old freed array. MutexLocker ml(ExternalsRecorder_lock, Mutex::_no_safepoint_check_flag); - assert(_recorder != nullptr, "sanity"); return _recorder->_externals.at(index); } int ExternalsRecorder::count() { - MutexLocker ml(ExternalsRecorder_lock, Mutex::_no_safepoint_check_flag); assert(_recorder != nullptr, "sanity"); + MutexLocker ml(ExternalsRecorder_lock, Mutex::_no_safepoint_check_flag); return _recorder->_externals.count(); } #ifndef PRODUCT +extern "C" { + // Order from large to small values + static int count_cmp(const void *i, const void *j) { + int a = *(int*)i; + int b = *(int*)j; + return a < b ? 1 : a > b ? -1 : 0; + } +} + void ExternalsRecorder::print_statistics() { - tty->print_cr("External addresses table: %d entries", count()); + int cnt = count(); + tty->print_cr("External addresses table: %d entries, %d accesses", cnt, total_access_count); + { // Print most accessed entries in the table. + int* array = NEW_C_HEAP_ARRAY(int, (2 * cnt), mtCode); + for (int i = 0; i < cnt; i++) { + array[(2 * i) + 0] = extern_hist->at(i); + array[(2 * i) + 1] = i; + } + // Reverse sort to have "hottest" addresses first. + qsort(array, cnt, 2*sizeof(int), count_cmp); + // Print all entries with Verbose flag otherwise only top 5. + int limit = (Verbose || cnt <= 5) ? cnt : 5; + int j = 0; + for (int i = 0; i < limit; i++) { + int index = array[(2 * i) + 1]; + int n = extern_hist->at(index); + if (n > 0) { + address addr = at(index); + tty->print("%d: %8d " INTPTR_FORMAT " :", j++, n, p2i(addr)); + if (addr != nullptr) { + if (StubRoutines::contains(addr)) { + StubCodeDesc* desc = StubCodeDesc::desc_for(addr); + if (desc == nullptr) { + desc = StubCodeDesc::desc_for(addr + frame::pc_return_offset); + } + const char* stub_name = (desc != nullptr) ? desc->name() : ""; + tty->print(" stub: %s", stub_name); + } else { + ResourceMark rm; + const int buflen = 1024; + char* buf = NEW_RESOURCE_ARRAY(char, buflen); + int offset = 0; + if (os::dll_address_to_function_name(addr, buf, buflen, &offset)) { + tty->print(" extn: %s", buf); + if (offset != 0) { + tty->print("+%d", offset); + } + } else { + if (CodeCache::contains((void*)addr)) { + // Something in CodeCache + tty->print(" in CodeCache"); + } else { + // It could be string + memcpy(buf, (char*)addr, 80); + buf[80] = '\0'; + tty->print(" '%s'", buf); + } + } + } + } + tty->cr(); + } + } + } } #endif From 367e0a65561f95aad61b40930d5f46843fee3444 Mon Sep 17 00:00:00 2001 From: fabioromano1 <51378941+fabioromano1@users.noreply.github.com> Date: Sat, 3 Aug 2024 13:08:54 +0000 Subject: [PATCH 180/353] 8334755: Asymptotically faster implementation of square root algorithm Reviewed-by: rgiulietti --- .../share/classes/java/math/BigInteger.java | 12 +- .../classes/java/math/MutableBigInteger.java | 307 +++++++++++++----- .../java/math/BigInteger/BigIntegerTest.java | 24 +- .../bench/java/math/BigIntegerSquareRoot.java | 132 ++++++++ 4 files changed, 390 insertions(+), 85 deletions(-) create mode 100644 test/micro/org/openjdk/bench/java/math/BigIntegerSquareRoot.java diff --git a/src/java.base/share/classes/java/math/BigInteger.java b/src/java.base/share/classes/java/math/BigInteger.java index c69e291d0e2be..3a5fd1439373c 100644 --- a/src/java.base/share/classes/java/math/BigInteger.java +++ b/src/java.base/share/classes/java/math/BigInteger.java @@ -2723,7 +2723,7 @@ public BigInteger sqrt() { throw new ArithmeticException("Negative BigInteger"); } - return new MutableBigInteger(this.mag).sqrt().toBigInteger(); + return new MutableBigInteger(this.mag).sqrtRem(false)[0].toBigInteger(); } /** @@ -2742,10 +2742,12 @@ public BigInteger sqrt() { * @since 9 */ public BigInteger[] sqrtAndRemainder() { - BigInteger s = sqrt(); - BigInteger r = this.subtract(s.square()); - assert r.compareTo(BigInteger.ZERO) >= 0; - return new BigInteger[] {s, r}; + if (this.signum < 0) { + throw new ArithmeticException("Negative BigInteger"); + } + + MutableBigInteger[] sqrtRem = new MutableBigInteger(this.mag).sqrtRem(true); + return new BigInteger[] { sqrtRem[0].toBigInteger(), sqrtRem[1].toBigInteger() }; } /** diff --git a/src/java.base/share/classes/java/math/MutableBigInteger.java b/src/java.base/share/classes/java/math/MutableBigInteger.java index 30ea8e130fcca..b84e50f567eb7 100644 --- a/src/java.base/share/classes/java/math/MutableBigInteger.java +++ b/src/java.base/share/classes/java/math/MutableBigInteger.java @@ -109,9 +109,26 @@ class MutableBigInteger { * the int val. */ MutableBigInteger(int val) { - value = new int[1]; - intLen = 1; - value[0] = val; + init(val); + } + + /** + * Construct a new MutableBigInteger with a magnitude specified by + * the long val. + */ + MutableBigInteger(long val) { + int hi = (int) (val >>> 32); + if (hi == 0) { + init((int) val); + } else { + value = new int[] { hi, (int) val }; + intLen = 2; + } + } + + private void init(int val) { + value = new int[] { val }; + intLen = val != 0 ? 1 : 0; } /** @@ -260,6 +277,7 @@ void reset() { * Compare the magnitude of two MutableBigIntegers. Returns -1, 0 or 1 * as this MutableBigInteger is numerically less than, equal to, or * greater than {@code b}. + * Assumes no leading unnecessary zeros. */ final int compare(MutableBigInteger b) { int blen = b.intLen; @@ -285,6 +303,7 @@ final int compare(MutableBigInteger b) { /** * Returns a value equal to what {@code b.leftShift(32*ints); return compare(b);} * would return, but doesn't change the value of {@code b}. + * Assumes no leading unnecessary zeros. */ private int compareShifted(MutableBigInteger b, int ints) { int blen = b.intLen; @@ -538,6 +557,7 @@ void safeRightShift(int n) { /** * Right shift this MutableBigInteger n bits. The MutableBigInteger is left * in normal form. + * Assumes {@code Math.ceilDiv(n, 32) <= intLen || intLen == 0} */ void rightShift(int n) { if (intLen == 0) @@ -911,6 +931,58 @@ void addLower(MutableBigInteger addend, int n) { add(a); } + /** + * Shifts {@code this} of {@code n} ints to the left and adds {@code addend}. + * Assumes {@code n > 0} for speed. + */ + void shiftAdd(MutableBigInteger addend, int n) { + // Fast cases + if (addend.intLen <= n) { + shiftAddDisjoint(addend, n); + } else if (intLen == 0) { + copyValue(addend); + } else { + leftShift(n << 5); + add(addend); + } + } + + /** + * Shifts {@code this} of {@code n} ints to the left and adds {@code addend}. + * Assumes {@code addend.intLen <= n}. + */ + void shiftAddDisjoint(MutableBigInteger addend, int n) { + if (intLen == 0) { // Avoid unnormal values + copyValue(addend); + return; + } + + int[] res; + final int resLen = intLen + n, resOffset; + if (resLen > value.length) { + res = new int[resLen]; + System.arraycopy(value, offset, res, 0, intLen); + resOffset = 0; + } else { + res = value; + if (offset + resLen > value.length) { + System.arraycopy(value, offset, res, 0, intLen); + resOffset = 0; + } else { + resOffset = offset; + } + // Clear words where necessary + if (addend.intLen < n) + Arrays.fill(res, resOffset + intLen, resOffset + resLen - addend.intLen, 0); + } + + System.arraycopy(addend.value, addend.offset, res, resOffset + resLen - addend.intLen, addend.intLen); + + value = res; + offset = resOffset; + intLen = resLen; + } + /** * Subtracts the smaller of this and b from the larger and places the * result into this MutableBigInteger. @@ -1003,6 +1075,7 @@ private int difference(MutableBigInteger b) { /** * Multiply the contents of two MutableBigInteger objects. The result is * placed into MutableBigInteger z. The contents of y are not changed. + * Assume {@code intLen > 0} */ void multiply(MutableBigInteger y, MutableBigInteger z) { int xLen = intLen; @@ -1793,93 +1866,169 @@ private boolean unsignedLongCompare(long one, long two) { } /** - * Calculate the integer square root {@code floor(sqrt(this))} where - * {@code sqrt(.)} denotes the mathematical square root. The contents of - * {@code this} are not changed. The value of {@code this} is assumed - * to be non-negative. + * Calculate the integer square root {@code floor(sqrt(this))} and the remainder + * if needed, where {@code sqrt(.)} denotes the mathematical square root. + * The contents of {@code this} are not changed. + * The value of {@code this} is assumed to be non-negative. * - * @implNote The implementation is based on the material in Henry S. Warren, - * Jr., Hacker's Delight (2nd ed.) (Addison Wesley, 2013), 279-282. - * - * @throws ArithmeticException if the value returned by {@code bitLength()} - * overflows the range of {@code int}. - * @return the integer square root of {@code this} - * @since 9 + * @return the integer square root of {@code this} and the remainder if needed */ - MutableBigInteger sqrt() { + MutableBigInteger[] sqrtRem(boolean needRemainder) { // Special cases. - if (this.isZero()) { - return new MutableBigInteger(0); - } else if (this.value.length == 1 - && (this.value[0] & LONG_MASK) < 4) { // result is unity - return ONE; - } - - if (bitLength() <= 63) { - // Initial estimate is the square root of the positive long value. - long v = new BigInteger(this.value, 1).longValueExact(); - long xk = (long)Math.floor(Math.sqrt(v)); - - // Refine the estimate. - do { - long xk1 = (xk + v/xk)/2; - - // Terminate when non-decreasing. - if (xk1 >= xk) { - return new MutableBigInteger(new int[] { - (int)(xk >>> 32), (int)(xk & LONG_MASK) - }); + if (this.intLen <= 2) { + final long x = this.toLong(); // unsigned + long s = unsignedLongSqrt(x); + + return new MutableBigInteger[] { + new MutableBigInteger((int) s), + needRemainder ? new MutableBigInteger(x - s * s) : null + }; + } + + // Normalize + MutableBigInteger x = this; + final int shift = (Integer.numberOfLeadingZeros(x.value[x.offset]) & ~1) // shift must be even + + ((x.intLen & 1) << 5); // x.intLen must be even + + if (shift != 0) { + x = new MutableBigInteger(x); + x.leftShift(shift); + } + + // Compute sqrt and remainder + MutableBigInteger[] sqrtRem = x.sqrtRemKaratsuba(x.intLen, needRemainder); + + // Unnormalize + if (shift != 0) { + final int halfShift = shift >> 1; + if (needRemainder) { + // shift <= 62, so s0 is at most 31 bit long + final long s0 = sqrtRem[0].value[sqrtRem[0].offset + sqrtRem[0].intLen - 1] + & (-1 >>> -halfShift); // Remove excess bits + if (s0 != 0L) { // An optimization + MutableBigInteger doubleProd = new MutableBigInteger(); + sqrtRem[0].mul((int) (s0 << 1), doubleProd); + + sqrtRem[1].add(doubleProd); + sqrtRem[1].subtract(new MutableBigInteger(s0 * s0)); } + sqrtRem[1].rightShift(shift); + } + sqrtRem[0].primitiveRightShift(halfShift); + } + return sqrtRem; + } - xk = xk1; - } while (true); - } else { - // Set up the initial estimate of the iteration. + private static long unsignedLongSqrt(long x) { + /* For every long value s in [0, 2^32) such that x == s * s, + * it is true that s - 1 <= (long) Math.sqrt(x >= 0 ? x : x + 0x1p64) <= s, + * and if x == 2^64 - 1, then (long) Math.sqrt(x >= 0 ? x : x + 0x1p64) == 2^32. + * Since both cast to long and `Math.sqrt()` are (weakly) increasing, + * this means that the value returned by Math.sqrt() + * for a long value in the range [0, 2^64) is either correct, + * or rounded up/down by one if the value is too high + * and too close to a perfect square. + */ + long s = (long) Math.sqrt(x >= 0 ? x : x + 0x1p64); + long s2 = s * s; // overflows iff s == 2^32 + return Long.compareUnsigned(x, s2) < 0 || s > LONG_MASK + ? s - 1 + : (Long.compareUnsigned(x, s2 + (s << 1)) <= 0 // x <= (s + 1)^2 - 1, does not overflow + ? s + : s + 1); + } - // Obtain the bitLength > 63. - int bitLength = (int) this.bitLength(); - if (bitLength != this.bitLength()) { - throw new ArithmeticException("bitLength() integer overflow"); - } + /** + * Assumes {@code 2 <= len <= intLen && len % 2 == 0 + * && Integer.numberOfLeadingZeros(value[offset]) <= 1} + * @implNote The implementation is based on Zimmermann's works available + * here and + * here + */ + private MutableBigInteger[] sqrtRemKaratsuba(int len, boolean needRemainder) { + if (len == 2) { // Base case + long x = ((value[offset] & LONG_MASK) << 32) | (value[offset + 1] & LONG_MASK); + long s = unsignedLongSqrt(x); - // Determine an even valued right shift into positive long range. - int shift = bitLength - 63; - if (shift % 2 == 1) { - shift++; - } + // Allocate sufficient space to hold the final square root, assuming intLen % 2 == 0 + MutableBigInteger sqrt = new MutableBigInteger(new int[intLen >> 1]); - // Shift the value into positive long range. - MutableBigInteger xk = new MutableBigInteger(this); - xk.rightShift(shift); - xk.normalize(); - - // Use the square root of the shifted value as an approximation. - double d = new BigInteger(xk.value, 1).doubleValue(); - BigInteger bi = BigInteger.valueOf((long)Math.ceil(Math.sqrt(d))); - xk = new MutableBigInteger(bi.mag); - - // Shift the approximate square root back into the original range. - xk.leftShift(shift / 2); - - // Refine the estimate. - MutableBigInteger xk1 = new MutableBigInteger(); - do { - // xk1 = (xk + n/xk)/2 - this.divide(xk, xk1, false); - xk1.add(xk); - xk1.rightShift(1); - - // Terminate when non-decreasing. - if (xk1.compare(xk) >= 0) { - return xk; - } + // Place the partial square root + sqrt.intLen = 1; + sqrt.value[0] = (int) s; + + return new MutableBigInteger[] { sqrt, new MutableBigInteger(x - s * s) }; + } - // xk = xk1 - xk.copyValue(xk1); + // Recursive step (len >= 4) - xk1.reset(); - } while (true); + final int halfLen = len >> 1; + // Recursive invocation + MutableBigInteger[] sr = sqrtRemKaratsuba(halfLen + (halfLen & 1), true); + + final int blockLen = halfLen >> 1; + MutableBigInteger dividend = sr[1]; + dividend.shiftAddDisjoint(getBlockForSqrt(1, len, blockLen), blockLen); + + // Compute dividend / (2*sqrt) + MutableBigInteger sqrt = sr[0]; + MutableBigInteger q = new MutableBigInteger(); + MutableBigInteger u = dividend.divide(sqrt, q); + if (q.isOdd()) + u.add(sqrt); + q.rightShift(1); + + sqrt.shiftAdd(q, blockLen); + // Corresponds to ub + a_0 in the paper + u.shiftAddDisjoint(getBlockForSqrt(0, len, blockLen), blockLen); + BigInteger qBig = q.toBigInteger(); // Cast to BigInteger to use fast multiplication + MutableBigInteger qSqr = new MutableBigInteger(qBig.multiply(qBig).mag); + + MutableBigInteger rem; + if (needRemainder) { + rem = u; + if (rem.subtract(qSqr) < 0) { + MutableBigInteger twiceSqrt = new MutableBigInteger(sqrt); + twiceSqrt.leftShift(1); + + // Since subtract() performs an absolute difference, to get the correct algebraic sum + // we must first add the sum of absolute values of addends concordant with the sign of rem + // and then subtract the sum of absolute values of addends that are discordant + rem.add(ONE); + rem.subtract(twiceSqrt); + sqrt.subtract(ONE); + } + } else { + rem = null; + if (u.compare(qSqr) < 0) + sqrt.subtract(ONE); } + + sr[1] = rem; + return sr; + } + + /** + * Returns a {@code MutableBigInteger} obtained by taking {@code blockLen} ints from + * {@code this} number, ending at {@code blockIndex*blockLen} (exclusive).
+ * Used in Karatsuba square root. + * @param blockIndex the block index, starting from the lowest + * @param len the logical length of the input value in units of 32 bits + * @param blockLen the length of the block in units of 32 bits + * + * @return a {@code MutableBigInteger} obtained by taking {@code blockLen} ints from + * {@code this} number, ending at {@code blockIndex*blockLen} (exclusive). + */ + private MutableBigInteger getBlockForSqrt(int blockIndex, int len, int blockLen) { + final int to = offset + len - blockIndex * blockLen; + + // Skip leading zeros + int from; + for (from = to - blockLen; from < to && value[from] == 0; from++); + + return from == to + ? new MutableBigInteger() + : new MutableBigInteger(Arrays.copyOfRange(value, from, to)); } /** diff --git a/test/jdk/java/math/BigInteger/BigIntegerTest.java b/test/jdk/java/math/BigInteger/BigIntegerTest.java index 2ac4750e43fa0..7da3fdac61813 100644 --- a/test/jdk/java/math/BigInteger/BigIntegerTest.java +++ b/test/jdk/java/math/BigInteger/BigIntegerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -293,8 +293,30 @@ private static void squareRootSmall() { report("squareRootSmall", failCount); } + private static void perfectSquaresLong() { + /* For every long value n in [0, 2^32) such that x == n * n, + * n - 1 <= (long) Math.sqrt(x >= 0 ? x : x + 0x1p64) <= n + * must be true. + * This property is used to implement MutableBigInteger.unsignedLongSqrt(). + */ + int failCount = 0; + + long limit = 1L << 32; + for (long n = 0; n < limit; n++) { + long x = n * n; + long s = (long) Math.sqrt(x >= 0 ? x : x + 0x1p64); + if (!(s == n || s == n - 1)) { + failCount++; + System.err.println(s + "^2 != " + x + " && (" + s + "+1)^2 != " + x); + } + } + + report("perfectSquaresLong", failCount); + } + public static void squareRoot() { squareRootSmall(); + perfectSquaresLong(); ToIntFunction f = (n) -> { int failCount = 0; diff --git a/test/micro/org/openjdk/bench/java/math/BigIntegerSquareRoot.java b/test/micro/org/openjdk/bench/java/math/BigIntegerSquareRoot.java new file mode 100644 index 0000000000000..4b78b4cd8fa7f --- /dev/null +++ b/test/micro/org/openjdk/bench/java/math/BigIntegerSquareRoot.java @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.bench.java.math; + +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.OperationsPerInvocation; +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.Param; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; + +import java.math.BigInteger; +import java.util.Random; +import java.util.concurrent.TimeUnit; + +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Thread) +@Warmup(iterations = 5, time = 1) +@Measurement(iterations = 5, time = 1) +@Fork(value = 3) +public class BigIntegerSquareRoot { + + private BigInteger[] xsArray, sArray, mArray, lArray, xlArray; + private static final int TESTSIZE = 1000; + + @Setup + public void setup() { + Random r = new Random(1123); + + xsArray = new BigInteger[TESTSIZE]; /* + * Each array entry is atmost 64 bits + * in size + */ + sArray = new BigInteger[TESTSIZE]; /* + * Each array entry is atmost 256 bits + * in size + */ + mArray = new BigInteger[TESTSIZE]; /* + * Each array entry is atmost 1024 bits + * in size + */ + lArray = new BigInteger[TESTSIZE]; /* + * Each array entry is atmost 4096 bits + * in size + */ + xlArray = new BigInteger[TESTSIZE]; /* + * Each array entry is atmost 16384 bits + * in size + */ + + for (int i = 0; i < TESTSIZE; i++) { + xsArray[i] = new BigInteger(r.nextInt(64), r); + sArray[i] = new BigInteger(r.nextInt(256), r); + mArray[i] = new BigInteger(r.nextInt(1024), r); + lArray[i] = new BigInteger(r.nextInt(4096), r); + xlArray[i] = new BigInteger(r.nextInt(16384), r); + } + } + + /** Test BigInteger.sqrt() with numbers long at most 64 bits */ + @Benchmark + @OperationsPerInvocation(TESTSIZE) + public void testSqrtXS(Blackhole bh) { + for (BigInteger s : xsArray) { + bh.consume(s.sqrt()); + } + } + + /** Test BigInteger.sqrt() with numbers long at most 256 bits */ + @Benchmark + @OperationsPerInvocation(TESTSIZE) + public void testSqrtS(Blackhole bh) { + for (BigInteger s : sArray) { + bh.consume(s.sqrt()); + } + } + + /** Test BigInteger.sqrt() with numbers long at most 1024 bits */ + @Benchmark + @OperationsPerInvocation(TESTSIZE) + public void testSqrtM(Blackhole bh) { + for (BigInteger s : mArray) { + bh.consume(s.sqrt()); + } + } + + /** Test BigInteger.sqrt() with numbers long at most 4096 bits */ + @Benchmark + @OperationsPerInvocation(TESTSIZE) + public void testSqrtL(Blackhole bh) { + for (BigInteger s : lArray) { + bh.consume(s.sqrt()); + } + } + + /** Test BigInteger.sqrt() with numbers long at most 16384 bits */ + @Benchmark + @OperationsPerInvocation(TESTSIZE) + public void testSqrtXL(Blackhole bh) { + for (BigInteger s : xlArray) { + bh.consume(s.sqrt()); + } + } +} From 8bd3cd51562ff9e76fa0e3d49d38e6e19210f878 Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Sun, 4 Aug 2024 15:42:51 +0000 Subject: [PATCH 181/353] 8337716: ByteBuffer hashCode implementations are inconsistent Reviewed-by: alanb, liach --- .../java/nio/Heap-X-Buffer.java.template | 7 ------ .../java/nio/Buffer/EqualsCompareTest.java | 24 ++++++++++++++++++- .../openjdk/bench/java/nio/ByteBuffers.java | 7 +----- 3 files changed, 24 insertions(+), 14 deletions(-) diff --git a/src/java.base/share/classes/java/nio/Heap-X-Buffer.java.template b/src/java.base/share/classes/java/nio/Heap-X-Buffer.java.template index 8fbc1a3b69dfa..4820725d6c4ea 100644 --- a/src/java.base/share/classes/java/nio/Heap-X-Buffer.java.template +++ b/src/java.base/share/classes/java/nio/Heap-X-Buffer.java.template @@ -29,7 +29,6 @@ package java.nio; import java.lang.foreign.MemorySegment; import java.util.Objects; -import jdk.internal.util.ArraysSupport; /** #if[rw] @@ -706,9 +705,6 @@ class Heap$Type$Buffer$RW$ addr, segment))); } - public int hashCode() { - return ArraysSupport.hashCode(hb, ix(position()), remaining(), 1); - } #end[byte] @@ -737,9 +733,6 @@ class Heap$Type$Buffer$RW$ offset, segment); } - public int hashCode() { - return ArraysSupport.hashCode(hb, ix(position()), remaining(), 1); - } #end[char] diff --git a/test/jdk/java/nio/Buffer/EqualsCompareTest.java b/test/jdk/java/nio/Buffer/EqualsCompareTest.java index baee641208411..03bd7c26a584a 100644 --- a/test/jdk/java/nio/Buffer/EqualsCompareTest.java +++ b/test/jdk/java/nio/Buffer/EqualsCompareTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ import org.testng.annotations.DataProvider; import org.testng.annotations.Test; +import java.io.IOException; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; @@ -36,13 +37,21 @@ import java.nio.FloatBuffer; import java.nio.IntBuffer; import java.nio.LongBuffer; +import java.nio.MappedByteBuffer; import java.nio.ShortBuffer; +import java.nio.channels.FileChannel; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.HashMap; import java.util.Map; +import java.util.Set; import java.util.function.BiFunction; import java.util.function.LongFunction; import java.util.stream.IntStream; +import static java.nio.charset.StandardCharsets.UTF_8; +import static java.nio.file.StandardOpenOption.*; + /* * @test * @bug 8193085 8199773 @@ -713,4 +722,17 @@ static int[] ranges(int from, int to) { .distinct().toArray(); } } + + @Test + void testHashCode() throws IOException { + byte[] bytes = "hello world".getBytes(UTF_8); + Path path = Files.createTempFile("", ""); + Files.write(path, bytes); + try (FileChannel fc = FileChannel.open(path, READ, DELETE_ON_CLOSE)) { + MappedByteBuffer one = fc.map(FileChannel.MapMode.READ_ONLY, 0, bytes.length); + ByteBuffer two = ByteBuffer.wrap(bytes); + Assert.assertEquals(one, two); + Assert.assertEquals(one.hashCode(), two.hashCode()); + } + } } diff --git a/test/micro/org/openjdk/bench/java/nio/ByteBuffers.java b/test/micro/org/openjdk/bench/java/nio/ByteBuffers.java index c2f4e93313c91..48f75a3ec8117 100644 --- a/test/micro/org/openjdk/bench/java/nio/ByteBuffers.java +++ b/test/micro/org/openjdk/bench/java/nio/ByteBuffers.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -923,9 +923,4 @@ public double testDirectLoopGetDouble() { } return r; } - - @Benchmark - public int testHeapHashCode() { - return heapByteBuffer.hashCode(); - } } From dabdae6b355b3e7a2795f6b01ba475652d483288 Mon Sep 17 00:00:00 2001 From: Julian Waters Date: Mon, 5 Aug 2024 05:13:08 +0000 Subject: [PATCH 182/353] 8334599: Improve code from JDK-8302671 Reviewed-by: aivanov, stuefe, prr --- .../windows/native/libawt/windows/awt_Component.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/java.desktop/windows/native/libawt/windows/awt_Component.cpp b/src/java.desktop/windows/native/libawt/windows/awt_Component.cpp index 4f87e8ef4c113..640b06d0521a9 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_Component.cpp +++ b/src/java.desktop/windows/native/libawt/windows/awt_Component.cpp @@ -3362,10 +3362,10 @@ BOOL AwtComponent::IsNumPadKey(UINT vkey, BOOL extended) return FALSE; } static void -resetKbdState( BYTE kstate[256]) { - BYTE tmpState[256]; +resetKbdState( BYTE (&kstate)[AwtToolkit::KB_STATE_SIZE]) { + BYTE tmpState[AwtToolkit::KB_STATE_SIZE]; WCHAR wc[2]; - memmove(tmpState, kstate, 256 * sizeof(BYTE)); + memmove(tmpState, kstate, sizeof(kstate)); tmpState[VK_SHIFT] = 0; tmpState[VK_CONTROL] = 0; tmpState[VK_MENU] = 0; From fbe8a81d1900d0de1920ad1df6ad574f3da4bd51 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Mon, 5 Aug 2024 05:57:41 +0000 Subject: [PATCH 183/353] 8333144: docker tests do not work when ubsan is configured Reviewed-by: clanger, stuefe --- test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java | 1 + 1 file changed, 1 insertion(+) diff --git a/test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java b/test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java index 2404394690ebd..c87796da47e7e 100644 --- a/test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java +++ b/test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java @@ -323,6 +323,7 @@ private static void generateDockerFile(Path dockerfile, String baseImage, String baseImageVersion) throws Exception { String template = "FROM %s:%s\n" + + "RUN apt-get install libubsan1\n" + "COPY /jdk /jdk\n" + "ENV JAVA_HOME=/jdk\n" + "CMD [\"/bin/bash\"]\n"; From be34730fb4e6818ac13c46b34b735c967351e5cd Mon Sep 17 00:00:00 2001 From: Christian Hagedorn Date: Mon, 5 Aug 2024 09:52:07 +0000 Subject: [PATCH 184/353] 8335257: Refactor code to create Initialized Assertion Predicates into separate class Reviewed-by: kvn, epeter --- src/hotspot/share/opto/cfgnode.hpp | 4 + src/hotspot/share/opto/ifnode.cpp | 4 +- src/hotspot/share/opto/loopPredicate.cpp | 12 +-- src/hotspot/share/opto/loopTransform.cpp | 82 +++++++--------- src/hotspot/share/opto/loopnode.hpp | 9 +- src/hotspot/share/opto/predicates.cpp | 118 +++++++++++++++++++---- src/hotspot/share/opto/predicates.hpp | 61 ++++++++---- src/hotspot/share/opto/split_if.cpp | 24 ++--- 8 files changed, 206 insertions(+), 108 deletions(-) diff --git a/src/hotspot/share/opto/cfgnode.hpp b/src/hotspot/share/opto/cfgnode.hpp index 18d7577d9e621..5edd31fa71695 100644 --- a/src/hotspot/share/opto/cfgnode.hpp +++ b/src/hotspot/share/opto/cfgnode.hpp @@ -449,6 +449,10 @@ class IfNode : public MultiBranchNode { static const TypeInt* filtered_int_type(PhaseGVN* phase, Node* val, Node* if_proj); #ifndef PRODUCT + AssertionPredicateType assertion_predicate_type() const { + return _assertion_predicate_type; + } + virtual void dump_spec(outputStream *st) const; #endif diff --git a/src/hotspot/share/opto/ifnode.cpp b/src/hotspot/share/opto/ifnode.cpp index cedbc66bbb444..8e5cd2702137a 100644 --- a/src/hotspot/share/opto/ifnode.cpp +++ b/src/hotspot/share/opto/ifnode.cpp @@ -1843,10 +1843,10 @@ void IfProjNode::pin_array_access_nodes(PhaseIterGVN* igvn) { #ifndef PRODUCT void IfNode::dump_spec(outputStream* st) const { switch (_assertion_predicate_type) { - case AssertionPredicateType::Init_value: + case AssertionPredicateType::InitValue: st->print("#Init Value Assertion Predicate "); break; - case AssertionPredicateType::Last_value: + case AssertionPredicateType::LastValue: st->print("#Last Value Assertion Predicate "); break; case AssertionPredicateType::None: diff --git a/src/hotspot/share/opto/loopPredicate.cpp b/src/hotspot/share/opto/loopPredicate.cpp index b22931e56630e..5e585a406f20c 100644 --- a/src/hotspot/share/opto/loopPredicate.cpp +++ b/src/hotspot/share/opto/loopPredicate.cpp @@ -374,10 +374,10 @@ IfProjNode* PhaseIdealLoop::clone_assertion_predicate_for_unswitched_loops(IfNod IfProjNode* predicate, Deoptimization::DeoptReason reason, ParsePredicateSuccessProj* parse_predicate_proj) { - TemplateAssertionPredicateExpression template_assertion_predicate_expression( - template_assertion_predicate->in(1)->as_Opaque4()); - Opaque4Node* cloned_opaque4_node = template_assertion_predicate_expression.clone(parse_predicate_proj->in(0)->in(0), this); - IfProjNode* if_proj = create_new_if_for_predicate(parse_predicate_proj, nullptr, reason, template_assertion_predicate->Opcode(), false); + TemplateAssertionExpression template_assertion_expression(template_assertion_predicate->in(1)->as_Opaque4()); + Opaque4Node* cloned_opaque4_node = template_assertion_expression.clone(parse_predicate_proj->in(0)->in(0), this); + IfProjNode* if_proj = create_new_if_for_predicate(parse_predicate_proj, nullptr, reason, + template_assertion_predicate->Opcode(), false); _igvn.replace_input_of(if_proj->in(0), 1, cloned_opaque4_node); _igvn.replace_input_of(parse_predicate_proj->in(0), 0, if_proj); set_idom(parse_predicate_proj->in(0), if_proj, dom_depth(if_proj)); @@ -1324,7 +1324,7 @@ IfTrueNode* PhaseIdealLoop::add_template_assertion_predicate(IfNode* iff, IdealL C->add_template_assertion_predicate_opaq(opaque_bol); register_new_node(opaque_bol, upper_bound_proj); IfTrueNode* new_proj = create_new_if_for_predicate(parse_predicate_proj, nullptr, reason, overflow ? Op_If : iff->Opcode(), - false NOT_PRODUCT(COMMA AssertionPredicateType::Init_value)); + false NOT_PRODUCT(COMMA AssertionPredicateType::InitValue)); _igvn.replace_input_of(new_proj->in(0), 1, opaque_bol); assert(opaque_init->outcnt() > 0, "should be used"); @@ -1350,7 +1350,7 @@ IfTrueNode* PhaseIdealLoop::add_template_assertion_predicate(IfNode* iff, IdealL C->add_template_assertion_predicate_opaq(opaque_bol); register_new_node(opaque_bol, new_proj); new_proj = create_new_if_for_predicate(parse_predicate_proj, nullptr, reason, overflow ? Op_If : iff->Opcode(), - false NOT_PRODUCT(COMMA AssertionPredicateType::Last_value)); + false NOT_PRODUCT(COMMA AssertionPredicateType::LastValue)); _igvn.replace_input_of(new_proj->in(0), 1, opaque_bol); assert(max_value->outcnt() > 0, "should be used"); assert(assertion_predicate_has_loop_opaque_node(new_proj->in(0)->as_If()), "unexpected"); diff --git a/src/hotspot/share/opto/loopTransform.cpp b/src/hotspot/share/opto/loopTransform.cpp index 6ca7bb51fb458..99742a598e858 100644 --- a/src/hotspot/share/opto/loopTransform.cpp +++ b/src/hotspot/share/opto/loopTransform.cpp @@ -1373,17 +1373,12 @@ void PhaseIdealLoop::copy_assertion_predicates_to_main_loop_helper(const Predica Node* bol = iff->in(1); assert(!bol->is_OpaqueInitializedAssertionPredicate(), "should not find an Initialized Assertion Predicate"); if (bol->is_Opaque4()) { - assert(assertion_predicate_has_loop_opaque_node(iff), "must find OpaqueLoop* nodes"); // Clone the Assertion Predicate twice and initialize one with the initial // value of the loop induction variable. Leave the other predicate // to be initialized when increasing the stride during loop unrolling. - prev_proj = clone_assertion_predicate_and_initialize(iff, opaque_init, nullptr, predicate_proj, uncommon_proj, - current_proj, outer_loop, prev_proj); - assert(assertion_predicate_has_loop_opaque_node(prev_proj->in(0)->as_If()), ""); - - prev_proj = clone_assertion_predicate_and_initialize(iff, init, stride, predicate_proj, uncommon_proj, - current_proj, outer_loop, prev_proj); - assert(!assertion_predicate_has_loop_opaque_node(prev_proj->in(0)->as_If()), ""); + prev_proj = clone_template_assertion_predicate(iff, opaque_init, predicate_proj, uncommon_proj, + current_proj, outer_loop, prev_proj); + prev_proj = create_initialized_assertion_predicate(iff, init, stride, prev_proj); // Rewire any control inputs from the cloned Assertion Predicates down to the main and post loop for data nodes // that are part of the main loop (and were cloned to the pre and post loop). @@ -1460,7 +1455,7 @@ void PhaseIdealLoop::count_opaque_loop_nodes(Node* n, uint& init, uint& stride) wq.push(n); for (uint i = 0; i < wq.size(); i++) { Node* n = wq.at(i); - if (TemplateAssertionPredicateExpressionNode::is_maybe_in_expression(n)) { + if (TemplateAssertionExpressionNode::is_maybe_in_expression(n)) { if (n->is_OpaqueLoopInit()) { init++; } else if (n->is_OpaqueLoopStride()) { @@ -1477,27 +1472,28 @@ void PhaseIdealLoop::count_opaque_loop_nodes(Node* n, uint& init, uint& stride) } } -// Clone an Assertion Predicate for the main loop. new_init and new_stride are set as new inputs. Since the predicates -// cannot fail at runtime, Halt nodes are inserted instead of uncommon traps. -Node* PhaseIdealLoop::clone_assertion_predicate_and_initialize(Node* iff, Node* new_init, Node* new_stride, Node* predicate, - Node* uncommon_proj, Node* control, IdealLoopTree* outer_loop, - Node* input_proj) { - TemplateAssertionPredicateExpression template_assertion_predicate_expression(iff->in(1)->as_Opaque4()); - Node* new_opaque_node; - if (new_stride == nullptr) { - // Clone the Template Assertion Predicate and set a new OpaqueLoopInitNode to create a new Template Assertion Predicate. - // This is done when creating a new Template Assertion Predicate for the main loop which requires a new init node. - // We keep the Opaque4 node since it's still a template. - assert(new_init->is_OpaqueLoopInit(), "only for creating new Template Assertion Predicates"); - new_opaque_node = template_assertion_predicate_expression.clone_and_replace_init(new_init, control, this); - } else { - // Create an Initialized Assertion Predicate from the Template Assertion Predicate. - new_opaque_node = template_assertion_predicate_expression.clone_and_replace_init_and_stride(new_init, new_stride, - control, this); - // Since this is an Initialized Assertion Predicate, we use the dedicated opaque node. - new_opaque_node = new OpaqueInitializedAssertionPredicateNode(new_opaque_node->in(1)->as_Bool(), C); - register_new_node(new_opaque_node, control); - } +// Create an Initialized Assertion Predicate from the template_assertion_predicate +IfTrueNode* PhaseIdealLoop::create_initialized_assertion_predicate(IfNode* template_assertion_predicate, Node* new_init, + Node* new_stride, Node* control) { + assert(assertion_predicate_has_loop_opaque_node(template_assertion_predicate), + "must find OpaqueLoop* nodes for Template Assertion Predicate"); + InitializedAssertionPredicate initialized_assertion_predicate(template_assertion_predicate, new_init, new_stride, this); + IfTrueNode* success_proj = initialized_assertion_predicate.create(control); + assert(!assertion_predicate_has_loop_opaque_node(success_proj->in(0)->as_If()), + "Initialized Assertion Predicates do not have OpaqueLoop* nodes in the bool expression anymore"); + return success_proj; +} + +// Clone the Template Assertion Predicate and set a new OpaqueLoopInitNode to create a new Template Assertion Predicate. +// This is done when creating a new Template Assertion Predicate for the main loop which requires a new init node. +// We keep the Opaque4 node since it's still a template. Since the templates are eventually removed after loop opts, +// these are never executed. We therefore insert a Halt node instead of an uncommon trap. +Node* PhaseIdealLoop::clone_template_assertion_predicate(IfNode* iff, Node* new_init, Node* predicate, Node* uncommon_proj, + Node* control, IdealLoopTree* outer_loop, Node* input_proj) { + assert(assertion_predicate_has_loop_opaque_node(iff), "must find OpaqueLoop* nodes for Template Assertion Predicate"); + TemplateAssertionExpression template_assertion_expression(iff->in(1)->as_Opaque4()); + assert(new_init->is_OpaqueLoopInit(), "only for creating new Template Assertion Predicates"); + Opaque4Node* new_opaque_node = template_assertion_expression.clone_and_replace_init(new_init, control, this); Node* proj = predicate->clone(); Node* other_proj = uncommon_proj->clone(); Node* new_iff = iff->clone(); @@ -1506,8 +1502,7 @@ Node* PhaseIdealLoop::clone_assertion_predicate_and_initialize(Node* iff, Node* other_proj->set_req(0, new_iff); Node* frame = new ParmNode(C->start(), TypeFunc::FramePtr); register_new_node(frame, C->start()); - // It's impossible for the predicate to fail at runtime. Use a Halt node. - Node* halt = new HaltNode(other_proj, frame, "duplicated predicate failed which is impossible"); + Node* halt = new HaltNode(other_proj, frame, "Template Assertion Predicates are always removed before code generation"); _igvn.add_input_to(C->root(), halt); new_iff->set_req(0, input_proj); @@ -1515,6 +1510,8 @@ Node* PhaseIdealLoop::clone_assertion_predicate_and_initialize(Node* iff, Node* register_control(proj, outer_loop == _ltree_root ? _ltree_root : outer_loop->_parent, new_iff); register_control(other_proj, _ltree_root, new_iff); register_control(halt, _ltree_root, other_proj); + assert(assertion_predicate_has_loop_opaque_node(proj->in(0)->as_If()), + "Template Assertion Predicates must have OpaqueLoop* nodes in the bool expression"); return proj; } @@ -1967,9 +1964,7 @@ void PhaseIdealLoop::update_main_loop_assertion_predicates(Node* ctrl, CountedLo // Create an Initialized Assertion Predicates for it accordingly: // - For the initial access a[init] (same as before) // - For the last access a[init+new_stride-orig_stride] (with the new unroll stride) - prev_proj = clone_assertion_predicate_and_initialize(iff, init, max_value, entry, proj, ctrl, outer_loop, - prev_proj); - assert(!assertion_predicate_has_loop_opaque_node(prev_proj->in(0)->as_If()), "unexpected"); + prev_proj = create_initialized_assertion_predicate(iff, init, max_value, prev_proj); } else { // Ignore Opaque4 from a non-null-check for an intrinsic or unsafe access. This could happen when we maximally // unroll a non-main loop with such an If with an Opaque4 node directly above the loop entry. @@ -2008,10 +2003,7 @@ void PhaseIdealLoop::copy_assertion_predicates_to_post_loop(LoopNode* main_loop_ } if (iff->in(1)->is_Opaque4()) { // Initialize from Template Assertion Predicate. - assert(assertion_predicate_has_loop_opaque_node(iff), "must find OpaqueLoop* nodes"); - prev_proj = clone_assertion_predicate_and_initialize(iff, init, stride, ctrl, proj, post_loop_entry, - post_loop, prev_proj); - assert(!assertion_predicate_has_loop_opaque_node(prev_proj->in(0)->as_If()), "must not find OpaqueLoop* nodes"); + prev_proj = create_initialized_assertion_predicate(iff, init, stride, prev_proj); } ctrl = ctrl->in(0)->in(0); } @@ -2030,9 +2022,7 @@ void PhaseIdealLoop::initialize_assertion_predicates_for_peeled_loop(const Predi if (!predicate_block->has_parse_predicate()) { return; } - Node* control = outer_loop_head->in(LoopNode::EntryControl); - Node* input_proj = control; - + Node* input_proj = outer_loop_head->in(LoopNode::EntryControl); const Node* parse_predicate_uncommon_trap = predicate_block->parse_predicate()->uncommon_trap(); Node* next_regular_predicate_proj = predicate_block->skip_parse_predicate(); while (next_regular_predicate_proj->is_IfProj()) { @@ -2046,9 +2036,7 @@ void PhaseIdealLoop::initialize_assertion_predicates_for_peeled_loop(const Predi assert(!bol->is_OpaqueInitializedAssertionPredicate(), "should not find an Initialized Assertion Predicate"); if (bol->is_Opaque4()) { // Initialize from Template Assertion Predicate. - assert(assertion_predicate_has_loop_opaque_node(iff), "must find OpaqueLoop* nodes"); - input_proj = clone_assertion_predicate_and_initialize(iff, init, stride, next_regular_predicate_proj, uncommon_proj, control, - outer_loop, input_proj); + input_proj = create_initialized_assertion_predicate(iff, init, stride, input_proj); // Rewire any control inputs from the old Assertion Predicates above the peeled iteration down to the initialized // Assertion Predicates above the peeled loop. @@ -3018,7 +3006,7 @@ void PhaseIdealLoop::do_range_check(IdealLoopTree *loop, Node_List &old_new) { // unrolling or splitting this main-loop further. loop_entry = add_range_check_elimination_assertion_predicate( loop, loop_entry, scale_con, int_offset, int_limit, stride_con, opaque_init, true - NOT_PRODUCT(COMMA AssertionPredicateType::Init_value)); + NOT_PRODUCT(COMMA AssertionPredicateType::InitValue)); assert(assertion_predicate_has_loop_opaque_node(loop_entry->in(0)->as_If()), "unexpected"); Node* opaque_stride = new OpaqueLoopStrideNode(C, cl->stride()); @@ -3032,7 +3020,7 @@ void PhaseIdealLoop::do_range_check(IdealLoopTree *loop, Node_List &old_new) { register_new_node(max_value, loop_entry); loop_entry = add_range_check_elimination_assertion_predicate( loop, loop_entry, scale_con, int_offset, int_limit, stride_con, max_value, true - NOT_PRODUCT(COMMA AssertionPredicateType::Last_value)); + NOT_PRODUCT(COMMA AssertionPredicateType::LastValue)); assert(assertion_predicate_has_loop_opaque_node(loop_entry->in(0)->as_If()), "unexpected"); } else { diff --git a/src/hotspot/share/opto/loopnode.hpp b/src/hotspot/share/opto/loopnode.hpp index 24101ea07a002..94632be268d58 100644 --- a/src/hotspot/share/opto/loopnode.hpp +++ b/src/hotspot/share/opto/loopnode.hpp @@ -952,9 +952,10 @@ class PhaseIdealLoop : public PhaseTransform { LoopNode* outer_main_head, uint dd_main_head, uint idx_before_pre_post, uint idx_after_post_before_pre, Node* zero_trip_guard_proj_main, Node* zero_trip_guard_proj_post, const Node_List& old_new); - Node* clone_assertion_predicate_and_initialize(Node* iff, Node* new_init, Node* new_stride, Node* predicate, - Node* uncommon_proj, Node* control, IdealLoopTree* outer_loop, - Node* input_proj); + Node* clone_template_assertion_predicate(IfNode* iff, Node* new_init, Node* predicate, Node* uncommon_proj, Node* control, + IdealLoopTree* outer_loop, Node* input_proj); + IfTrueNode* create_initialized_assertion_predicate(IfNode* template_assertion_predicate, Node* new_init, + Node* new_stride, Node* control); static void count_opaque_loop_nodes(Node* n, uint& init, uint& stride); static bool assertion_predicate_has_loop_opaque_node(IfNode* iff); static void get_assertion_predicates(Node* predicate, Unique_Node_List& list, bool get_opaque = false); @@ -1774,7 +1775,7 @@ class PhaseIdealLoop : public PhaseTransform { bool clone_cmp_loadklass_down(Node* n, const Node* blk1, const Node* blk2); void clone_loadklass_nodes_at_cmp_index(const Node* n, Node* cmp, int i); bool clone_cmp_down(Node* n, const Node* blk1, const Node* blk2); - void clone_template_assertion_predicate_expression_down(Node* node); + void clone_template_assertion_expression_down(Node* node); Node* similar_subtype_check(const Node* x, Node* r_in); diff --git a/src/hotspot/share/opto/predicates.cpp b/src/hotspot/share/opto/predicates.cpp index 5b0de2e02d5f0..3887e8a5f6cdf 100644 --- a/src/hotspot/share/opto/predicates.cpp +++ b/src/hotspot/share/opto/predicates.cpp @@ -27,6 +27,7 @@ #include "opto/loopnode.hpp" #include "opto/node.hpp" #include "opto/predicates.hpp" +#include "opto/rootnode.hpp" // Walk over all Initialized Assertion Predicates and return the entry into the first Initialized Assertion Predicate // (i.e. not belonging to an Initialized Assertion Predicate anymore) @@ -239,27 +240,27 @@ class ReplaceInitAndStrideStrategy : public TransformStrategyForOpaqueLoopNodes } }; -// Creates an identical clone of this Template Assertion Predicate Expression (i.e.cloning all nodes from the Opaque4Node -// to and including the OpaqueLoop* nodes). The cloned nodes are rewired to reflect the same graph structure as found for -// this Template Assertion Predicate Expression. The cloned nodes get 'new_ctrl' as ctrl. There is no other update done -// for the cloned nodes. Return the newly cloned Opaque4Node. -Opaque4Node* TemplateAssertionPredicateExpression::clone(Node* new_ctrl, PhaseIdealLoop* phase) { +// Creates an identical clone of this Template Assertion Expression (i.e.cloning all nodes from the Opaque4Node to and +// including the OpaqueLoop* nodes). The cloned nodes are rewired to reflect the same graph structure as found for this +// Template Assertion Expression. The cloned nodes get 'new_ctrl' as ctrl. There is no other update done for the cloned +// nodes. Return the newly cloned Opaque4Node. +Opaque4Node* TemplateAssertionExpression::clone(Node* new_ctrl, PhaseIdealLoop* phase) { CloneStrategy clone_init_and_stride_strategy(phase, new_ctrl); return clone(clone_init_and_stride_strategy, new_ctrl, phase); } // Same as clone() but instead of cloning the OpaqueLoopInitNode, we replace it with the provided 'new_init' node. -Opaque4Node* TemplateAssertionPredicateExpression::clone_and_replace_init(Node* new_init, Node* new_ctrl, - PhaseIdealLoop* phase) { +Opaque4Node* TemplateAssertionExpression::clone_and_replace_init(Node* new_init, Node* new_ctrl, + PhaseIdealLoop* phase) { ReplaceInitAndCloneStrideStrategy replace_init_and_clone_stride_strategy(new_init, new_ctrl, phase); return clone(replace_init_and_clone_stride_strategy, new_ctrl, phase); } // Same as clone() but instead of cloning the OpaqueLoopInit and OpaqueLoopStride node, we replace them with the provided // 'new_init' and 'new_stride' nodes, respectively. -Opaque4Node* TemplateAssertionPredicateExpression::clone_and_replace_init_and_stride(Node* new_init, Node* new_stride, - Node* new_ctrl, - PhaseIdealLoop* phase) { +Opaque4Node* TemplateAssertionExpression::clone_and_replace_init_and_stride(Node* new_init, Node* new_stride, + Node* new_ctrl, + PhaseIdealLoop* phase) { ReplaceInitAndStrideStrategy replace_init_and_stride_strategy(new_init, new_stride); return clone(replace_init_and_stride_strategy, new_ctrl, phase); } @@ -307,8 +308,7 @@ class DataNodesOnPathsToTargets : public StackObj { // Do a BFS from the start_node to collect all target nodes. We can then do another BFS from the target nodes to // find all nodes on the paths from start->target(s). // Note: We could do a single DFS pass to search targets and backtrack in one walk. But this is much more complex. - // Given that the typical Template Assertion Predicate Expression only consists of a few nodes, we aim for - // simplicity here. + // Given that the typical Template Assertion Expression only consists of a few nodes, we aim for simplicity here. void collect_target_nodes(Node* start_node) { _nodes_to_visit.push(start_node); for (uint i = 0; i < _nodes_to_visit.size(); i++) { @@ -342,14 +342,14 @@ class DataNodesOnPathsToTargets : public StackObj { } }; -// Clones this Template Assertion Predicate Expression and applies the given strategy to transform the OpaqueLoop* nodes. -Opaque4Node* TemplateAssertionPredicateExpression::clone(const TransformStrategyForOpaqueLoopNodes& transform_strategy, - Node* new_ctrl, PhaseIdealLoop* phase) { +// Clones this Template Assertion Expression and applies the given strategy to transform the OpaqueLoop* nodes. +Opaque4Node* TemplateAssertionExpression::clone(const TransformStrategyForOpaqueLoopNodes& transform_strategy, + Node* new_ctrl, PhaseIdealLoop* phase) { ResourceMark rm; auto is_opaque_loop_node = [](const Node* node) { return node->is_Opaque1(); }; - DataNodesOnPathsToTargets data_nodes_on_path_to_targets(TemplateAssertionPredicateExpressionNode::is_maybe_in_expression, + DataNodesOnPathsToTargets data_nodes_on_path_to_targets(TemplateAssertionExpressionNode::is_maybe_in_expression, is_opaque_loop_node); const Unique_Node_List& collected_nodes = data_nodes_on_path_to_targets.collect(_opaque4_node); DataNodeGraph data_node_graph(collected_nodes, phase); @@ -359,8 +359,8 @@ Opaque4Node* TemplateAssertionPredicateExpression::clone(const TransformStrategy return opaque4_clone->as_Opaque4(); } -// Check if this node belongs a Template Assertion Predicate Expression (including OpaqueLoop* nodes). -bool TemplateAssertionPredicateExpressionNode::is_in_expression(Node* node) { +// Check if this node belongs a Template Assertion Expression (including OpaqueLoop* nodes). +bool TemplateAssertionExpressionNode::is_in_expression(Node* node) { if (is_maybe_in_expression(node)) { ResourceMark rm; Unique_Node_List list; @@ -377,10 +377,90 @@ bool TemplateAssertionPredicateExpressionNode::is_in_expression(Node* node) { return false; } -bool TemplateAssertionPredicateExpressionNode::is_template_assertion_predicate(Node* node) { +bool TemplateAssertionExpressionNode::is_template_assertion_predicate(Node* node) { return node->is_If() && node->in(1)->is_Opaque4(); } +InitializedAssertionPredicate::InitializedAssertionPredicate(IfNode* template_assertion_predicate, Node* new_init, + Node* new_stride, PhaseIdealLoop* phase) + : _template_assertion_predicate(template_assertion_predicate), + _new_init(new_init), + _new_stride(new_stride), + _phase(phase) {} + +// Create an Initialized Assertion Predicate at the provided control from the _template_assertion_predicate. +// We clone the Template Assertion Expression and replace: +// - Opaque4 with OpaqueInitializedAssertionPredicate +// - OpaqueLoop*Nodes with _new_init and _new_stride, respectively. +// +// / init stride +// | | | +// | OpaqueLoopInitNode OpaqueLoopStrideNode / _new_init _new_stride +// Template | \ / | \ / +// Assertion | ... Assertion | ... +// Expression | | Expression | | +// | Bool | new Bool +// | | | | +// \ Opaque4 ======> control \ OpaqueInitializedAssertionPredicate +// | \ / +// If new If +// / \ / \ +// success fail path new success new Halt +// proj (Halt or UCT) proj +// +IfTrueNode* InitializedAssertionPredicate::create(Node* control) { + IdealLoopTree* loop = _phase->get_loop(control); + OpaqueInitializedAssertionPredicateNode* assertion_expression = create_assertion_expression(control); + IfNode* if_node = create_if_node(control, assertion_expression, loop); + create_fail_path(if_node, loop); + return create_success_path(if_node, loop); +} + +// Create a new Assertion Expression to be used as bool input for the Initialized Assertion Predicate IfNode. +OpaqueInitializedAssertionPredicateNode* InitializedAssertionPredicate::create_assertion_expression(Node* control) { + Opaque4Node* template_opaque = _template_assertion_predicate->in(1)->as_Opaque4(); + TemplateAssertionExpression template_assertion_expression(template_opaque); + Opaque4Node* tmp_opaque = template_assertion_expression.clone_and_replace_init_and_stride(_new_init, _new_stride, + control, _phase); + OpaqueInitializedAssertionPredicateNode* assertion_expression = + new OpaqueInitializedAssertionPredicateNode(tmp_opaque->in(1)->as_Bool(), _phase->C); + _phase->register_new_node(assertion_expression, control); + return assertion_expression; +} + +IfNode* InitializedAssertionPredicate::create_if_node(Node* control, + OpaqueInitializedAssertionPredicateNode* assertion_expression, + IdealLoopTree* loop) { + const int if_opcode = _template_assertion_predicate->Opcode(); + NOT_PRODUCT(const AssertionPredicateType assertion_predicate_type = _template_assertion_predicate->assertion_predicate_type();) + IfNode* if_node = if_opcode == Op_If ? + new IfNode(control, assertion_expression, PROB_MAX, COUNT_UNKNOWN NOT_PRODUCT(COMMA assertion_predicate_type)) : + new RangeCheckNode(control, assertion_expression, PROB_MAX, COUNT_UNKNOWN NOT_PRODUCT(COMMA assertion_predicate_type)); + _phase->register_control(if_node, loop, control); + return if_node; +} + +IfTrueNode* InitializedAssertionPredicate::create_success_path(IfNode* if_node, IdealLoopTree* loop) { + IfTrueNode* success_proj = new IfTrueNode(if_node); + _phase->register_control(success_proj, loop, if_node); + return success_proj; +} + +void InitializedAssertionPredicate::create_fail_path(IfNode* if_node, IdealLoopTree* loop) { + IfFalseNode* fail_proj = new IfFalseNode(if_node); + _phase->register_control(fail_proj, loop, if_node); + create_halt_node(fail_proj, loop); +} + +void InitializedAssertionPredicate::create_halt_node(IfFalseNode* fail_proj, IdealLoopTree* loop) { + StartNode* start_node = _phase->C->start(); + Node* frame = new ParmNode(start_node, TypeFunc::FramePtr); + _phase->register_new_node(frame, start_node); + Node* halt = new HaltNode(fail_proj, frame, "Initialized Assertion Predicate cannot fail"); + _phase->igvn().add_input_to(_phase->C->root(), halt); + _phase->register_control(halt, loop, fail_proj); +} + // Is current node pointed to by iterator a predicate? bool PredicateEntryIterator::has_next() const { return ParsePredicate::is_predicate(_current) || diff --git a/src/hotspot/share/opto/predicates.hpp b/src/hotspot/share/opto/predicates.hpp index 08aa64f03e583..96f5c438b802f 100644 --- a/src/hotspot/share/opto/predicates.hpp +++ b/src/hotspot/share/opto/predicates.hpp @@ -29,6 +29,8 @@ #include "opto/connode.hpp" #include "opto/opaquenode.hpp" +class IdealLoopTree; + /* * There are different kinds of predicates throughout the code. We differentiate between the following predicates: * @@ -198,8 +200,8 @@ // value of a range check in the last iteration of a loop. enum class AssertionPredicateType { None, // Not an Assertion Predicate - Init_value, - Last_value + InitValue, + LastValue }; #endif // NOT PRODUCT @@ -294,20 +296,20 @@ class RuntimePredicate : public StackObj { static bool is_success_proj(Node* node, Deoptimization::DeoptReason deopt_reason); }; -// Interface to transform OpaqueLoopInit and OpaqueLoopStride nodes of a Template Assertion Predicate Expression. +// Interface to transform OpaqueLoopInit and OpaqueLoopStride nodes of a Template Assertion Expression. class TransformStrategyForOpaqueLoopNodes : public StackObj { public: virtual Node* transform_opaque_init(OpaqueLoopInitNode* opaque_init) const = 0; virtual Node* transform_opaque_stride(OpaqueLoopStrideNode* opaque_stride) const = 0; }; -// A Template Assertion Predicate Expression represents the Opaque4Node for the initial value or the last value of a +// A Template Assertion Predicate represents the Opaque4Node for the initial value or the last value of a // Template Assertion Predicate and all the nodes up to and including the OpaqueLoop* nodes. -class TemplateAssertionPredicateExpression : public StackObj { +class TemplateAssertionExpression : public StackObj { Opaque4Node* _opaque4_node; public: - explicit TemplateAssertionPredicateExpression(Opaque4Node* opaque4_node) : _opaque4_node(opaque4_node) {} + explicit TemplateAssertionExpression(Opaque4Node* opaque4_node) : _opaque4_node(opaque4_node) {} private: Opaque4Node* clone(const TransformStrategyForOpaqueLoopNodes& transform_strategy, Node* new_ctrl, PhaseIdealLoop* phase); @@ -318,29 +320,29 @@ class TemplateAssertionPredicateExpression : public StackObj { Opaque4Node* clone_and_replace_init_and_stride(Node* new_init, Node* new_stride, Node* new_ctrl, PhaseIdealLoop* phase); }; -// Class to represent a node being part of a Template Assertion Predicate Expression. +// Class to represent a node being part of a Template Assertion Expression. Note that this is not an IR node. // // The expression itself can belong to no, one, or two Template Assertion Predicates: // - None: This node is already dead (i.e. we replaced the Bool condition of the Template Assertion Predicate). // - Two: A OpaqueLoopInitNode could be part of two Template Assertion Predicates. // - One: In all other cases. -class TemplateAssertionPredicateExpressionNode : public StackObj { +class TemplateAssertionExpressionNode : public StackObj { Node* const _node; public: - explicit TemplateAssertionPredicateExpressionNode(Node* node) : _node(node) { + explicit TemplateAssertionExpressionNode(Node* node) : _node(node) { assert(is_in_expression(node), "must be valid"); } - NONCOPYABLE(TemplateAssertionPredicateExpressionNode); + NONCOPYABLE(TemplateAssertionExpressionNode); private: static bool is_template_assertion_predicate(Node* node); public: - // Check whether the provided node is part of a Template Assertion Predicate Expression or not. + // Check whether the provided node is part of a Template Assertion Expression or not. static bool is_in_expression(Node* node); - // Check if the opcode of node could be found in a Template Assertion Predicate Expression. + // Check if the opcode of node could be found in a Template Assertion Expression. // This also provides a fast check whether a node is unrelated. static bool is_maybe_in_expression(const Node* node) { const int opcode = node->Opcode(); @@ -377,21 +379,44 @@ class TemplateAssertionPredicateExpressionNode : public StackObj { callback(next->as_If()); DEBUG_ONLY(template_counter++;) } else { - assert(!next->is_CFG(), "no CFG expected in Template Assertion Predicate Expression"); + assert(!next->is_CFG(), "no CFG expected in Template Assertion Expression"); list.push_outputs_of(next); } } - // Each node inside a Template Assertion Predicate Expression is in between a Template Assertion Predicate and - // its OpaqueLoop* nodes (or an OpaqueLoop* node itself). The OpaqueLoop* nodes do not common up. Therefore, each - // Template Assertion Predicate Expression node belongs to a single expression - except for OpaqueLoopInitNodes. - // An OpaqueLoopInitNode is shared between the init and last value Template Assertion Predicate at creation. - // Later, when cloning the expressions, they are no longer shared. + // Each node inside a Template Assertion Expression is in between a Template Assertion Predicate and its OpaqueLoop* + // nodes (or an OpaqueLoop* node itself). The OpaqueLoop* nodes do not common up. Therefore, each Template Assertion + // Expression node belongs to a single expression - except for OpaqueLoopInitNodes. An OpaqueLoopInitNode is shared + // between the init and last value Template Assertion Predicate at creation. Later, when cloning the expressions, + // they are no longer shared. assert(template_counter <= 2, "a node cannot be part of more than two templates"); assert(template_counter <= 1 || _node->is_OpaqueLoopInit(), "only OpaqueLoopInit nodes can be part of two templates"); } }; +// This class creates a new Initialized Assertion Predicate. +class InitializedAssertionPredicate : public StackObj { + IfNode* const _template_assertion_predicate; + Node* const _new_init; + Node* const _new_stride; + PhaseIdealLoop* const _phase; + + public: + InitializedAssertionPredicate(IfNode* template_assertion_predicate, Node* new_init, Node* new_stride, + PhaseIdealLoop* phase); + NONCOPYABLE(InitializedAssertionPredicate); + + IfTrueNode* create(Node* control); + + private: + OpaqueInitializedAssertionPredicateNode* create_assertion_expression(Node* control); + IfNode* create_if_node(Node* control, OpaqueInitializedAssertionPredicateNode* assertion_expression, IdealLoopTree* loop); + void create_fail_path(IfNode* if_node, IdealLoopTree* loop); + void create_halt_node(IfFalseNode* fail_proj, IdealLoopTree* loop); + IfTrueNode* create_success_path(IfNode* if_node, IdealLoopTree* loop); +}; + + // This class represents a Predicate Block (i.e. either a Loop Predicate Block, a Profiled Loop Predicate Block, // or a Loop Limit Check Predicate Block). It contains zero or more Regular Predicates followed by a Parse Predicate // which, however, does not need to exist (we could already have decided to remove Parse Predicates for this loop). diff --git a/src/hotspot/share/opto/split_if.cpp b/src/hotspot/share/opto/split_if.cpp index ad4053e2c98c4..1eff44ab7834f 100644 --- a/src/hotspot/share/opto/split_if.cpp +++ b/src/hotspot/share/opto/split_if.cpp @@ -95,7 +95,7 @@ bool PhaseIdealLoop::split_up( Node *n, Node *blk1, Node *blk2 ) { return true; } - clone_template_assertion_predicate_expression_down(n); + clone_template_assertion_expression_down(n); if (n->Opcode() == Op_OpaqueZeroTripGuard) { // If this Opaque1 is part of the zero trip guard for a loop: @@ -409,25 +409,25 @@ bool PhaseIdealLoop::clone_cmp_down(Node* n, const Node* blk1, const Node* blk2) return false; } -// 'n' could be a node belonging to a Template Assertion Predicate Expression (i.e. any node between a Template -// Assertion Predicate and its OpaqueLoop* nodes (included)). We cannot simply split this node up since this would -// create a phi node inside the Template Assertion Predicate Expression - making it unrecognizable as such. Therefore, -// we completely clone the entire Template Assertion Predicate Expression "down". This ensures that we have an -// untouched copy that is still recognized by the Template Assertion Predicate matching code. -void PhaseIdealLoop::clone_template_assertion_predicate_expression_down(Node* node) { - if (!TemplateAssertionPredicateExpressionNode::is_in_expression(node)) { +// 'n' could be a node belonging to a Template Assertion Expression (i.e. any node between a Template Assertion Predicate +// and its OpaqueLoop* nodes (included)). We cannot simply split this node up since this would create a phi node inside +// the Template Assertion Expression - making it unrecognizable as such. Therefore, we completely clone the entire +// Template Assertion Expression "down". This ensures that we have an untouched copy that is still recognized by the +// Template Assertion Predicate matching code. +void PhaseIdealLoop::clone_template_assertion_expression_down(Node* node) { + if (!TemplateAssertionExpressionNode::is_in_expression(node)) { return; } - TemplateAssertionPredicateExpressionNode template_assertion_predicate_expression_node(node); + TemplateAssertionExpressionNode template_assertion_expression_node(node); auto clone_expression = [&](IfNode* template_assertion_predicate) { Opaque4Node* opaque4_node = template_assertion_predicate->in(1)->as_Opaque4(); - TemplateAssertionPredicateExpression template_assertion_predicate_expression(opaque4_node); + TemplateAssertionExpression template_assertion_expression(opaque4_node); Node* new_ctrl = template_assertion_predicate->in(0); - Opaque4Node* cloned_opaque4_node = template_assertion_predicate_expression.clone(new_ctrl, this); + Opaque4Node* cloned_opaque4_node = template_assertion_expression.clone(new_ctrl, this); igvn().replace_input_of(template_assertion_predicate, 1, cloned_opaque4_node); }; - template_assertion_predicate_expression_node.for_each_template_assertion_predicate(clone_expression); + template_assertion_expression_node.for_each_template_assertion_predicate(clone_expression); } //------------------------------register_new_node------------------------------ From d3e7b0c12afde03985f1b06e6e7d789928971090 Mon Sep 17 00:00:00 2001 From: Viktor Klang Date: Mon, 5 Aug 2024 10:56:21 +0000 Subject: [PATCH 185/353] 8336462: ConcurrentSkipListSet Javadoc incorrectly warns about size method complexity Reviewed-by: jpai --- .../java/util/concurrent/ConcurrentSkipListSet.java | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListSet.java b/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListSet.java index 3a72c4f4189a4..2a2fbc54d8618 100644 --- a/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListSet.java +++ b/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListSet.java @@ -189,14 +189,9 @@ public ConcurrentSkipListSet clone() { * contains more than {@code Integer.MAX_VALUE} elements, it * returns {@code Integer.MAX_VALUE}. * - *

Beware that, unlike in most collections, this method is - * NOT a constant-time operation. Because of the - * asynchronous nature of these sets, determining the current - * number of elements requires traversing them all to count them. - * Additionally, it is possible for the size to change during - * execution of this method, in which case the returned result - * will be inaccurate. Thus, this method is typically not very - * useful in concurrent applications. + *

It is possible for the size to change during execution of this method, + * in which case the returned result will be inaccurate. + * Thus, this method is typically not very useful in concurrent applications. * * @return the number of elements in this set */ From 2e093b06916b72b4feae5635aa8c5aa90679172b Mon Sep 17 00:00:00 2001 From: Erik Gahlin Date: Mon, 5 Aug 2024 13:17:32 +0000 Subject: [PATCH 186/353] 8337779: test/jdk/jdk/jfr/jvm/TestHiddenWait.java is a bit fragile Reviewed-by: mgronlun --- test/jdk/jdk/jfr/jvm/TestHiddenWait.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/jdk/jdk/jfr/jvm/TestHiddenWait.java b/test/jdk/jdk/jfr/jvm/TestHiddenWait.java index f4b810f192e48..b064285329c0f 100644 --- a/test/jdk/jdk/jfr/jvm/TestHiddenWait.java +++ b/test/jdk/jdk/jfr/jvm/TestHiddenWait.java @@ -77,6 +77,15 @@ public static void main(String... args) throws Exception { s.start(); } List events = Events.fromRecording(r); + // Only keep events from the test thread and the JFR threads + String testThread = Thread.currentThread().getName(); + events.removeIf(event -> { + String threadName = event.getThread().getJavaName(); + if (threadName.equals(testThread) || threadName.contains("JFR")) { + return false; + } + return true; + }); for (RecordedEvent event : events) { if (!event.getEventType().getName().equals(PERIODIC_EVENT_NAME)) { System.out.println(event); From 7e925d727f716e5c366b0d85b9c0de24efe43103 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Mon, 5 Aug 2024 14:05:00 +0000 Subject: [PATCH 187/353] 8337283: configure.log is truncated when build dir is on different filesystem Reviewed-by: phh, stuefe, clanger, ihse --- make/autoconf/configure.ac | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/make/autoconf/configure.ac b/make/autoconf/configure.ac index 6afa36ac18d33..f7e9844a64301 100644 --- a/make/autoconf/configure.ac +++ b/make/autoconf/configure.ac @@ -313,9 +313,11 @@ AC_OUTPUT # After AC_OUTPUT, we need to do final work CUSTOM_CONFIG_OUTPUT_GENERATED_HOOK -BASIC_POST_CONFIG_OUTPUT # Finally output some useful information to the user HELP_PRINT_SUMMARY_AND_WARNINGS CUSTOM_SUMMARY_AND_WARNINGS_HOOK HELP_REPEAT_WARNINGS + +# All output is done. Do the post-config output management. +BASIC_POST_CONFIG_OUTPUT From c095c0e6a58b1665d51ff19381e32f168e99e8f5 Mon Sep 17 00:00:00 2001 From: Carlo Refice Date: Mon, 5 Aug 2024 14:09:54 +0000 Subject: [PATCH 188/353] 8336489: Track scoped accesses in JVMCI compiled code Reviewed-by: dnsimon, never --- .../share/jvmci/jvmciCodeInstaller.cpp | 3 +++ src/hotspot/share/jvmci/jvmciRuntime.cpp | 3 ++- src/hotspot/share/jvmci/jvmciRuntime.hpp | 3 ++- src/hotspot/share/jvmci/vmStructs_jvmci.cpp | 1 + .../ci/hotspot/HotSpotCompiledCodeStream.java | 1 + .../vm/ci/hotspot/HotSpotCompiledNmethod.java | 20 ++++++++++++++++++- .../HotSpotResolvedJavaMethodImpl.java | 15 ++++++++++++-- .../jdk/vm/ci/hotspot/HotSpotVMConfig.java | 1 + .../jdk/vm/ci/meta/ResolvedJavaMethod.java | 10 ++++++++++ .../runtime/test/TestResolvedJavaMethod.java | 18 +++++++++++++++++ .../jdk/vm/ci/runtime/test/TypeUniverse.java | 3 ++- 11 files changed, 72 insertions(+), 6 deletions(-) diff --git a/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp b/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp index 79bc97f53ac6b..6bca2aa644e55 100644 --- a/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp +++ b/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp @@ -722,6 +722,7 @@ JVMCI::CodeInstallResult CodeInstaller::install(JVMCICompiler* compiler, jint entry_bci = -1; JVMCICompileState* compile_state = nullptr; bool has_unsafe_access = false; + bool has_scoped_access = false; jint id = -1; if (is_nmethod) { @@ -729,6 +730,7 @@ JVMCI::CodeInstallResult CodeInstaller::install(JVMCICompiler* compiler, entry_bci = is_nmethod ? stream->read_s4("entryBCI") : -1; compile_state = (JVMCICompileState*) stream->read_u8("compileState"); has_unsafe_access = stream->read_bool("hasUnsafeAccess"); + has_scoped_access = stream->read_bool("hasScopedAccess"); id = stream->read_s4("id"); } stream->set_code_desc(name, method); @@ -795,6 +797,7 @@ JVMCI::CodeInstallResult CodeInstaller::install(JVMCICompiler* compiler, id, _has_monitors, has_unsafe_access, + has_scoped_access, _has_wide_vector, compiled_code, mirror, diff --git a/src/hotspot/share/jvmci/jvmciRuntime.cpp b/src/hotspot/share/jvmci/jvmciRuntime.cpp index ad0430787aa13..8241fc2498c39 100644 --- a/src/hotspot/share/jvmci/jvmciRuntime.cpp +++ b/src/hotspot/share/jvmci/jvmciRuntime.cpp @@ -2078,6 +2078,7 @@ JVMCI::CodeInstallResult JVMCIRuntime::register_method(JVMCIEnv* JVMCIENV, int compile_id, bool has_monitors, bool has_unsafe_access, + bool has_scoped_access, bool has_wide_vector, JVMCIObject compiled_code, JVMCIObject nmethod_mirror, @@ -2183,7 +2184,7 @@ JVMCI::CodeInstallResult JVMCIRuntime::register_method(JVMCIEnv* JVMCIENV, nm->set_has_unsafe_access(has_unsafe_access); nm->set_has_wide_vectors(has_wide_vector); nm->set_has_monitors(has_monitors); - nm->set_has_scoped_access(true); // conservative + nm->set_has_scoped_access(has_scoped_access); JVMCINMethodData* data = nm->jvmci_nmethod_data(); assert(data != nullptr, "must be"); diff --git a/src/hotspot/share/jvmci/jvmciRuntime.hpp b/src/hotspot/share/jvmci/jvmciRuntime.hpp index bc5bee4edebee..99738393b5b0d 100644 --- a/src/hotspot/share/jvmci/jvmciRuntime.hpp +++ b/src/hotspot/share/jvmci/jvmciRuntime.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -452,6 +452,7 @@ class JVMCIRuntime: public CHeapObj { int compile_id, bool has_monitors, bool has_unsafe_access, + bool has_scoped_access, bool has_wide_vector, JVMCIObject compiled_code, JVMCIObject nmethod_mirror, diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp index 1e2ca0e990edb..ac895cc93f2f7 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -655,6 +655,7 @@ declare_constant(ConstMethodFlags::_misc_intrinsic_candidate) \ declare_constant(ConstMethodFlags::_misc_reserved_stack_access) \ declare_constant(ConstMethodFlags::_misc_changes_current_thread) \ + declare_constant(ConstMethodFlags::_misc_is_scoped) \ \ declare_constant(CounterData::count_off) \ \ diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotCompiledCodeStream.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotCompiledCodeStream.java index 87c6ecde07b6e..ab7a57f2759d4 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotCompiledCodeStream.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotCompiledCodeStream.java @@ -563,6 +563,7 @@ private String codeDesc() { writeInt("entryBCI", nmethod.entryBCI); writeLong("compileState", nmethod.compileState); writeBoolean("hasUnsafeAccess", nmethod.hasUnsafeAccess); + writeBoolean("hasScopedAccess", nmethod.hasScopedAccess()); writeInt("id", nmethod.id); } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotCompiledNmethod.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotCompiledNmethod.java index c364af7ad410c..b1be3dee25cd8 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotCompiledNmethod.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotCompiledNmethod.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -100,4 +100,22 @@ public String toString() { public String getInstallationFailureMessage() { return installationFailureMessage; } + + /** + * Determines if {@code methods} contains at least one entry for which {@code HotSpotResolvedJavaMethod.isScoped()} returns true. + */ + public boolean hasScopedAccess() { + if (methods == null) { + return false; + } + for (ResolvedJavaMethod method : methods) { + if (method instanceof HotSpotResolvedJavaMethod hotSpotMethod) { + if (hotSpotMethod.isScoped()) { + return true; + } + } + } + return false; + } + } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java index 4c9dc509ce1dc..4fbd479602437 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java @@ -170,7 +170,7 @@ public int hashCode() { * @return flags of this method */ private int getFlags() { - return UNSAFE.getShort(getMethodPointer() + config().methodFlagsOffset); + return UNSAFE.getInt(getMethodPointer() + config().methodFlagsOffset); } /** @@ -179,7 +179,7 @@ private int getFlags() { * @return flags of this method's ConstMethod */ private int getConstMethodFlags() { - return UNSAFE.getChar(getConstMethod() + config().constMethodFlagsOffset); + return UNSAFE.getInt(getConstMethod() + config().constMethodFlagsOffset); } @Override @@ -324,6 +324,17 @@ public boolean hasReservedStackAccess() { return (getConstMethodFlags() & config().constMethodFlagsReservedStackAccess) != 0; } + /** + * Returns true if this method has a + * {@code jdk.internal.misc.ScopedMemoryAccess.Scoped} annotation. + * + * @return true if Scoped annotation present, false otherwise + */ + @Override + public boolean isScoped() { + return (getConstMethodFlags() & config().constMethodFlagsIsScoped) != 0; + } + /** * Sets flags on {@code method} indicating that it should never be inlined or compiled by the * VM. diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java index 57f9473c90209..954e1f6b20173 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java @@ -194,6 +194,7 @@ long prototypeMarkWord() { final int constMethodFlagsReservedStackAccess = getConstant("ConstMethodFlags::_misc_reserved_stack_access", Integer.class); final int constMethodFlagsCallerSensitive = getConstant("ConstMethodFlags::_misc_caller_sensitive", Integer.class); final int constMethodFlagsIntrinsicCandidate = getConstant("ConstMethodFlags::_misc_intrinsic_candidate", Integer.class); + final int constMethodFlagsIsScoped = getConstant("ConstMethodFlags::_misc_is_scoped", Integer.class); final int constMethodHasLineNumberTable = getConstant("ConstMethodFlags::_misc_has_linenumber_table", Integer.class); final int constMethodHasLocalVariableTable = getConstant("ConstMethodFlags::_misc_has_localvariable_table", Integer.class); final int constMethodHasMethodAnnotations = getConstant("ConstMethodFlags::_misc_has_method_annotations", Integer.class); diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaMethod.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaMethod.java index 41eccc9d1c65d..fa42dc26ac8da 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaMethod.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaMethod.java @@ -463,6 +463,16 @@ default boolean isJavaLangObjectInit() { return getDeclaringClass().isJavaLangObject() && getName().equals(""); } + /** + * Returns true if this method has a + * {@code jdk.internal.misc.ScopedMemoryAccess.Scoped} annotation. + * + * @return true if Scoped annotation present, false otherwise. + */ + default boolean isScoped() { + throw new UnsupportedOperationException(); + } + /** * Gets a speculation log that can be used when compiling this method to make new speculations * and query previously failed speculations. The implementation may return a new diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java index 00973fd78c29d..98d7d168ba718 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java @@ -475,6 +475,24 @@ public void isJavaLangObjectInitTest() throws NoSuchMethodException { } } + @Test + public void isScopedTest() throws NoSuchMethodException, ClassNotFoundException { + // Must use reflection as ScopedMemoryAccess$Scoped is package-private + Class scopedAnnotationClass = Class.forName("jdk.internal.misc.ScopedMemoryAccess$Scoped").asSubclass(Annotation.class); + boolean scopedMethodFound = false; + for (Map.Entry e : methods.entrySet()) { + ResolvedJavaMethod m = e.getValue(); + Method key = e.getKey(); + boolean expect = key.isAnnotationPresent(scopedAnnotationClass); + boolean actual = m.isScoped(); + assertEquals(m.toString(), expect, actual); + if (expect) { + scopedMethodFound = true; + } + } + assertTrue("At least one scoped method must be present", scopedMethodFound); + } + abstract static class UnlinkedType { abstract void abstractMethod(); diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TypeUniverse.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TypeUniverse.java index 2420a133b63f9..13003095ee6a2 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TypeUniverse.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TypeUniverse.java @@ -51,6 +51,7 @@ import org.junit.Test; import jdk.internal.misc.Unsafe; +import jdk.internal.misc.ScopedMemoryAccess; import jdk.vm.ci.meta.ConstantReflectionProvider; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.MetaAccessProvider; @@ -115,7 +116,7 @@ protected class ProtectedInnerClass { byte[][].class, short[][].class, char[][].class, int[][].class, float[][].class, long[][].class, double[][].class, Object[][].class, Class[][].class, List[][].class, ClassLoader.class, String.class, Serializable.class, Cloneable.class, Test.class, TestMetaAccessProvider.class, List.class, Collection.class, Map.class, Queue.class, HashMap.class, LinkedHashMap.class, IdentityHashMap.class, AbstractCollection.class, AbstractList.class, ArrayList.class, InnerClass.class, InnerStaticClass.class, - InnerStaticFinalClass.class, PrivateInnerClass.class, ProtectedInnerClass.class}; + InnerStaticFinalClass.class, PrivateInnerClass.class, ProtectedInnerClass.class, ScopedMemoryAccess.class}; for (Class c : initialClasses) { addClass(c); } From 97afbd9603ba8ec1956c4cedf542667d33988661 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johan=20Sj=C3=B6len?= Date: Mon, 5 Aug 2024 14:49:38 +0000 Subject: [PATCH 189/353] 8336410: runtime/NMT/TotalMallocMmapDiffTest.java Total malloc diff is incorrect. Expected malloc diff range Reviewed-by: gziemski, stuefe --- .../jtreg/runtime/NMT/TotalMallocMmapDiffTest.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/test/hotspot/jtreg/runtime/NMT/TotalMallocMmapDiffTest.java b/test/hotspot/jtreg/runtime/NMT/TotalMallocMmapDiffTest.java index 3ba94c6a31a86..cd89bded57827 100644 --- a/test/hotspot/jtreg/runtime/NMT/TotalMallocMmapDiffTest.java +++ b/test/hotspot/jtreg/runtime/NMT/TotalMallocMmapDiffTest.java @@ -32,7 +32,7 @@ * java.management * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:NativeMemoryTracking=summary -Xms32m -Xmx32m TotalMallocMmapDiffTest + * @run main/othervm -Xbootclasspath/a:. -XX:TieredStopAtLevel=1 -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:NativeMemoryTracking=summary -Xms32m -Xmx32m TotalMallocMmapDiffTest * */ @@ -43,9 +43,10 @@ public class TotalMallocMmapDiffTest { private static final WhiteBox wb = WhiteBox.getWhiteBox(); private static final long ALLOCATE_SIZE = 250 * 1024 * 1024; // 250MB - private static final double FUDGE_FACTOR = 0.2; - private static final double UPPER_BOUND = ALLOCATE_SIZE * (1 + FUDGE_FACTOR); - private static final double LOWER_BOUND = ALLOCATE_SIZE * (1 - FUDGE_FACTOR); + private static final double FUDGE_FACTOR_UPPER = 0.3; + private static final double FUDGE_FACTOR_LOWER = 0.2; + private static final double UPPER_BOUND = ALLOCATE_SIZE * (1 + FUDGE_FACTOR_UPPER); + private static final double LOWER_BOUND = ALLOCATE_SIZE * (1 - FUDGE_FACTOR_LOWER); public static void main(String[] args) throws Exception { From 219e1eb13a688532705e603e276799c0157f5f28 Mon Sep 17 00:00:00 2001 From: Per Minborg Date: Mon, 5 Aug 2024 15:06:38 +0000 Subject: [PATCH 190/353] 8337712: Wrong javadoc in java.util.Date#toString(): "61" and right parenthesis Reviewed-by: rgiulietti --- src/java.base/share/classes/java/util/Date.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/java.base/share/classes/java/util/Date.java b/src/java.base/share/classes/java/util/Date.java index 1850564d8b290..aa16f2a75ee60 100644 --- a/src/java.base/share/classes/java/util/Date.java +++ b/src/java.base/share/classes/java/util/Date.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1012,7 +1012,7 @@ public int hashCode() { *

  • {@code mm} is the minute within the hour ({@code 00} through * {@code 59}), as two decimal digits. *
  • {@code ss} is the second within the minute ({@code 00} through - * {@code 61}, as two decimal digits. + * {@code 61}), as two decimal digits. *
  • {@code zzz} is the time zone (and may reflect daylight saving * time). Standard time zone abbreviations include those * recognized by the method {@code parse}. If time zone From 98562166e4a4c8921709014423c6cbc993aa0d97 Mon Sep 17 00:00:00 2001 From: Zdenek Zambersky Date: Mon, 5 Aug 2024 15:09:45 +0000 Subject: [PATCH 191/353] 8336928: GHA: Bundle artifacts removal broken Reviewed-by: ihse --- .github/workflows/main.yml | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 067548b9768e3..b16335b7091c2 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -363,26 +363,23 @@ jobs: - test-windows-x64 steps: - # Hack to get hold of the api environment variables that are only defined for actions - - name: 'Get API configuration' - id: api - uses: actions/github-script@v7 - with: - script: 'return { url: process.env["ACTIONS_RUNTIME_URL"], token: process.env["ACTIONS_RUNTIME_TOKEN"] }' - - name: 'Remove bundle artifacts' run: | # Find and remove all bundle artifacts - ALL_ARTIFACT_URLS="$(curl -s \ - -H 'Accept: application/json;api-version=6.0-preview' \ - -H 'Authorization: Bearer ${{ fromJson(steps.api.outputs.result).token }}' \ - '${{ fromJson(steps.api.outputs.result).url }}_apis/pipelines/workflows/${{ github.run_id }}/artifacts?api-version=6.0-preview')" - BUNDLE_ARTIFACT_URLS="$(echo "$ALL_ARTIFACT_URLS" | jq -r -c '.value | map(select(.name|startswith("bundles-"))) | .[].url')" - for url in $BUNDLE_ARTIFACT_URLS; do - echo "Removing $url" - curl -s \ - -H 'Accept: application/json;api-version=6.0-preview' \ - -H 'Authorization: Bearer ${{ fromJson(steps.api.outputs.result).token }}' \ - -X DELETE "$url" \ + # See: https://docs.github.com/en/rest/actions/artifacts?apiVersion=2022-11-28 + ALL_ARTIFACT_IDS="$(curl -sL \ + -H 'Accept: application/vnd.github+json' \ + -H 'Authorization: Bearer ${{ github.token }}' \ + -H 'X-GitHub-Api-Version: 2022-11-28' \ + '${{ github.api_url }}/repos/${{ github.repository }}/actions/runs/${{ github.run_id }}/artifacts')" + BUNDLE_ARTIFACT_IDS="$(echo "$ALL_ARTIFACT_IDS" | jq -r -c '.artifacts | map(select(.name|startswith("bundles-"))) | .[].id')" + for id in $BUNDLE_ARTIFACT_IDS; do + echo "Removing $id" + curl -sL \ + -X DELETE \ + -H 'Accept: application/vnd.github+json' \ + -H 'Authorization: Bearer ${{ github.token }}' \ + -H 'X-GitHub-Api-Version: 2022-11-28' \ + "${{ github.api_url }}/repos/${{ github.repository }}/actions/artifacts/$id" \ || echo "Failed to remove bundle" done From e68df528f80cff3a5564a12b7ec71a920800ce28 Mon Sep 17 00:00:00 2001 From: Damon Nguyen Date: Mon, 5 Aug 2024 16:48:18 +0000 Subject: [PATCH 192/353] 8337054: JDK 23 RDP2 L10n resource files update Reviewed-by: naoto, jlu --- .../tools/javac/resources/compiler_de.properties | 9 +++++---- .../tools/javac/resources/compiler_ja.properties | 9 +++++---- .../javac/resources/compiler_zh_CN.properties | 15 ++++++++------- .../javac/resources/launcher_zh_CN.properties | 2 +- .../toolkit/resources/doclets_de.properties | 4 ++-- .../toolkit/resources/doclets_ja.properties | 4 ++-- .../toolkit/resources/doclets_zh_CN.properties | 4 ++-- 7 files changed, 25 insertions(+), 22 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler_de.properties b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler_de.properties index dfbeb0fd0b715..33063b6558d3a 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler_de.properties +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler_de.properties @@ -2305,13 +2305,14 @@ compiler.err.this.as.identifier=Ab Release 8 ist "this" nur als Parametername f compiler.err.receiver.parameter.not.applicable.constructor.toplevel.class=receiver-Parameter nicht für Konstruktor der obersten Klasse anwendbar -# TODO 308: make a better error message +# 0: fragment, 1: symbol, 2: annotated-type +compiler.err.type.annotation.inadmissible={0} wurde hier nicht erwartet\n(Um einen qualifizierten Typ zu annotieren, schreiben Sie {1}.{2}) + # 0: annotation -compiler.err.cant.type.annotate.scoping.1=Scoping-Konstrukt kann nicht mit type-use-Annotation versehen werden: {0} +compiler.misc.type.annotation.1=Typannotation {0} ist -# TODO 308: make a better error message # 0: list of annotation -compiler.err.cant.type.annotate.scoping=Scoping-Konstrukt kann nicht mit type-use-Annotationen versehen werden: {0} +compiler.misc.type.annotation=Typannotationen {0} sind # 0: type, 1: type compiler.err.incorrect.receiver.name=Der Empfängername stimmt nicht mit dem einschließenden Klassentyp überein\nErforderlich: {0}\nErmittelt: {1} diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler_ja.properties b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler_ja.properties index 4d98e4cabccba..818b5fb70668b 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler_ja.properties +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler_ja.properties @@ -2305,13 +2305,14 @@ compiler.err.this.as.identifier=リリース8から''this''は受信タイプの compiler.err.receiver.parameter.not.applicable.constructor.toplevel.class=受取り側パラメータは最上位レベル・クラスのコンストラクタに適用できません -# TODO 308: make a better error message +# 0: fragment, 1: symbol, 2: annotated-type +compiler.err.type.annotation.inadmissible=ここでは{0}は予期されていません\n(修飾されたタイプに注釈を付けるには、{1}.{2}と記述します) + # 0: annotation -compiler.err.cant.type.annotate.scoping.1=スコープ・コンストラクトを型使用注釈で注釈付けすることはできません: {0} +compiler.misc.type.annotation.1=タイプ注釈{0}は -# TODO 308: make a better error message # 0: list of annotation -compiler.err.cant.type.annotate.scoping=スコープ・コンストラクトを型使用注釈で注釈付けすることはできません: {0} +compiler.misc.type.annotation=タイプ注釈{0}は # 0: type, 1: type compiler.err.incorrect.receiver.name=受取り側の名前が、包含するクラス・タイプと一致しません\n必須: {0}\n検出: {1} diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler_zh_CN.properties b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler_zh_CN.properties index 81452f23a0d55..54298cb23b912 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler_zh_CN.properties +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler_zh_CN.properties @@ -93,7 +93,7 @@ compiler.err.abstract.cant.be.instantiated={0}是抽象的; 无法实例化 compiler.err.abstract.meth.cant.have.body=抽象方法不能有主体 # 0: kind name, 1: symbol -compiler.err.already.annotated={0} {1}已进行注释 +compiler.err.already.annotated={0} {1} 已进行批注 # 0: kind name, 1: symbol, 2: kind name, 3: symbol compiler.err.already.defined=已在{2} {3}中定义了{0} {1} @@ -642,7 +642,7 @@ compiler.err.malformed.fp.lit=浮点文字的格式错误 compiler.err.method.does.not.override.superclass=方法不会覆盖或实现超类型的方法 -compiler.err.static.methods.cannot.be.annotated.with.override=不能使用 @Override 注释静态方法 +compiler.err.static.methods.cannot.be.annotated.with.override=不能使用 @Override 对静态方法进行批注 compiler.err.missing.meth.body.or.decl.abstract=缺少方法主体, 或声明抽象 @@ -1638,7 +1638,7 @@ compiler.warn.unchecked.varargs.non.reifiable.type=参数化 vararg 类型{0}的 # 0: symbol compiler.warn.varargs.unsafe.use.varargs.param=Varargs 方法可能导致来自不可具体化 varargs 参数 {0} 的堆污染 -compiler.warn.missing.deprecated.annotation=未使用 @Deprecated 对已过时的项目进行注释 +compiler.warn.missing.deprecated.annotation=未使用 @Deprecated 对已过时的项目进行批注 # 0: kind name compiler.warn.deprecated.annotation.has.no.effect=@Deprecated 批注对此 {0} 声明没有任何效果 @@ -2305,13 +2305,14 @@ compiler.err.this.as.identifier=从发行版 8 开始,''this'' 只能作为接 compiler.err.receiver.parameter.not.applicable.constructor.toplevel.class=接收方参数不适用于顶层类的构造器 -# TODO 308: make a better error message +# 0: fragment, 1: symbol, 2: annotated-type +compiler.err.type.annotation.inadmissible={0} 不应出现在此处\n(要对限定类型进行批注,请编写 {1}.{2}) + # 0: annotation -compiler.err.cant.type.annotate.scoping.1=无法使用 type-use 批注 {0} 来批注确定作用域结构 +compiler.misc.type.annotation.1=类型批注 {0} 为 -# TODO 308: make a better error message # 0: list of annotation -compiler.err.cant.type.annotate.scoping=无法使用 type-use 批注 {0} 来批注确定作用域结构 +compiler.misc.type.annotation=类型批注 {0} 为 # 0: type, 1: type compiler.err.incorrect.receiver.name=接收方名称与封闭类类型不匹配\n需要: {0}\n找到: {1} diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/launcher_zh_CN.properties b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/launcher_zh_CN.properties index ee666cc02c11d..9382ac9e348e4 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/launcher_zh_CN.properties +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/launcher_zh_CN.properties @@ -120,7 +120,7 @@ launcher.err.cant.read.file=读取源文件 {0} 时出错:{1} launcher.err.no.value.for.option=没有为选项 {0} 指定值 # 0: string -launcher.err.invalid.value.for.source=--source 选项的值无效:{0}\n +launcher.err.invalid.value.for.source=--source 选项的值无效:{0} launcher.err.unnamed.pkg.not.allowed.named.modules=命名模块中不允许未命名程序包 diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets_de.properties b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets_de.properties index 4e84cdc52c77f..7ab2d3fc1dcaf 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets_de.properties +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets_de.properties @@ -278,9 +278,9 @@ doclet.record_constructor_doc.param_name=Wert für die Datensatzkomponente {0} doclet.record_equals_doc.fullbody.head=Gibt an, ob ein anderes Objekt diesem gleich ("equal to") ist. Die Objekte sind gleich, wenn das andere Objekt der gleichen Klasse angehört und alle Datensatzkomponenten gleich sind. -doclet.record_equals_doc.fullbody.tail.both=Referenzkomponenten werden verglichen mit {@link java.util.Objects#equals(Object,Object) Objects::equals(Object,Object)}; primitive Komponenten werden verglichen mit "==". +doclet.record_equals_doc.fullbody.tail.both=Referenzkomponenten werden verglichen mit {@link java.util.Objects#equals(Object,Object) Objects::equals(Object,Object)}. Primitive Komponenten werden mit der compare-Methode aus den entsprechenden Wrapper-Klassen verglichen. -doclet.record_equals_doc.fullbody.tail.primitive=Alle Komponenten in dieser Datensatzklasse werden verglichen mit "==". +doclet.record_equals_doc.fullbody.tail.primitive=Alle Komponenten dieser Datensatzklasse werden mit der compare-Methode aus den entsprechenden Wrapper-Klassen verglichen. doclet.record_equals_doc.fullbody.tail.reference=Alle Komponenten in dieser Datensatzklasse werden verglichen mit {@link java.util.Objects#equals(Object,Object) Objects::equals(Object,Object)}. diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets_ja.properties b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets_ja.properties index 515df706272d8..1b00ea9fbc02c 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets_ja.properties +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets_ja.properties @@ -278,9 +278,9 @@ doclet.record_constructor_doc.param_name={0}レコード・コンポーネント doclet.record_equals_doc.fullbody.head=他のオブジェクトがこれと"等しい"かどうかを示します。他のオブジェクトが同じクラスであり、すべてのレコード・コンポーネントが等しい場合、オブジェクトは等しくなります。 -doclet.record_equals_doc.fullbody.tail.both=参照コンポーネントは{@link java.util.Objects#equals(Object,Object) Objects::equals(Object,Object)}と比較され、プリミティブ・コンポーネントは'=='と比較されます。 +doclet.record_equals_doc.fullbody.tail.both=参照コンポーネントは{@link java.util.Objects#equals(Object,Object) Objects::equals(Object,Object)}と比較され、プリミティブ・コンポーネントは対応するラッパー・クラスのcompareメソッドで比較されます。 -doclet.record_equals_doc.fullbody.tail.primitive=このレコード・クラスのすべてのコンポーネントは'=='と比較されます。 +doclet.record_equals_doc.fullbody.tail.primitive=このレコード・クラスのすべてのコンポーネントは対応するラッパー・クラスのcompareメソッドで比較されます。 doclet.record_equals_doc.fullbody.tail.reference=このレコード・クラスのすべてのコンポーネントは{@link java.util.Objects#equals(Object,Object) Objects::equals(Object,Object)}と比較されます。 diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets_zh_CN.properties b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets_zh_CN.properties index d01d42faa56a4..e9786173c5f1d 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets_zh_CN.properties +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets_zh_CN.properties @@ -278,9 +278,9 @@ doclet.record_constructor_doc.param_name={0} 记录组件的值 doclet.record_equals_doc.fullbody.head=指示某个其他对象是否“等于”此对象。如果两个对象属于同一个类,而且所有记录组件都相等,则这两个对象相等。 -doclet.record_equals_doc.fullbody.tail.both=使用 {@link java.util.Objects#equals(Object,Object) Objects::equals(Object,Object)} 对参考组件进行比较;使用 '==' 对基元组件进行比较 +doclet.record_equals_doc.fullbody.tail.both=使用 {@link java.util.Objects#equals(Object,Object) Objects::equals(Object,Object)} 对参考组件进行比较;使用 compare 方法从对应的包装类对基元组件进行比较。 -doclet.record_equals_doc.fullbody.tail.primitive=此记录类中的所有组件都使用 '==' 进行比较。 +doclet.record_equals_doc.fullbody.tail.primitive=此记录类中的所有组件都使用 compare 方法从对应的包装类进行比较。 doclet.record_equals_doc.fullbody.tail.reference=此记录类中的所有组件都使用 {@link java.util.Objects#equals(Object,Object) Objects::equals(Object,Object)} 进行比较。 From 807186ffc6a0a9f2515a66329c2a98a43385463c Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Mon, 5 Aug 2024 16:53:30 +0000 Subject: [PATCH 193/353] 8337784: Fix simple -Wzero-as-null-pointer-constant warnings in linux/posix code Reviewed-by: stefank, shade --- src/hotspot/os/linux/os_linux.cpp | 4 ++-- src/hotspot/os/posix/perfMemory_posix.cpp | 4 ++-- src/hotspot/os/posix/signals_posix.cpp | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index 1c735f1b3c9d8..d4699567733b2 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -864,7 +864,7 @@ static void *thread_native_entry(Thread *thread) { log_info(os, thread)("Thread finished (tid: " UINTX_FORMAT ", pthread id: " UINTX_FORMAT ").", os::current_thread_id(), (uintx) pthread_self()); - return 0; + return nullptr; } // On Linux, glibc places static TLS blocks (for __thread variables) on @@ -4449,7 +4449,7 @@ void os::init(void) { check_pax(); // Check the availability of MADV_POPULATE_WRITE. - FLAG_SET_DEFAULT(UseMadvPopulateWrite, (::madvise(0, 0, MADV_POPULATE_WRITE) == 0)); + FLAG_SET_DEFAULT(UseMadvPopulateWrite, (::madvise(nullptr, 0, MADV_POPULATE_WRITE) == 0)); os::Posix::init(); } diff --git a/src/hotspot/os/posix/perfMemory_posix.cpp b/src/hotspot/os/posix/perfMemory_posix.cpp index 4339a21ae4e92..56bc8a1ef6b81 100644 --- a/src/hotspot/os/posix/perfMemory_posix.cpp +++ b/src/hotspot/os/posix/perfMemory_posix.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2021 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -1329,7 +1329,7 @@ void PerfMemory::attach(int vmid, char** addrp, size_t* sizep, TRAPS) { // void PerfMemory::detach(char* addr, size_t bytes) { - assert(addr != 0, "address sanity check"); + assert(addr != nullptr, "address sanity check"); assert(bytes > 0, "capacity sanity check"); if (PerfMemory::contains(addr) || PerfMemory::contains(addr + bytes - 1)) { diff --git a/src/hotspot/os/posix/signals_posix.cpp b/src/hotspot/os/posix/signals_posix.cpp index a9d3bb9284c49..6a14d0a485643 100644 --- a/src/hotspot/os/posix/signals_posix.cpp +++ b/src/hotspot/os/posix/signals_posix.cpp @@ -1719,7 +1719,7 @@ static int SR_initialize() { struct sigaction act; char *s; // Get signal number to use for suspend/resume - if ((s = ::getenv("_JAVA_SR_SIGNUM")) != 0) { + if ((s = ::getenv("_JAVA_SR_SIGNUM")) != nullptr) { int sig; bool result = parse_integer(s, &sig); if (result && sig > MAX2(SIGSEGV, SIGBUS) && // See 4355769. @@ -1742,7 +1742,7 @@ static int SR_initialize() { pthread_sigmask(SIG_BLOCK, nullptr, &act.sa_mask); remove_error_signals_from_set(&(act.sa_mask)); - if (sigaction(PosixSignals::SR_signum, &act, 0) == -1) { + if (sigaction(PosixSignals::SR_signum, &act, nullptr) == -1) { return -1; } From 42652b2e5350bcab6fceb0148be8bf3d65a0e173 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Mon, 5 Aug 2024 16:57:11 +0000 Subject: [PATCH 194/353] 8337787: Fix -Wzero-as-null-pointer-constant warnings when JVMTI feature is disabled Reviewed-by: ayang, sspitsyn --- src/hotspot/share/prims/jvmtiExport.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/prims/jvmtiExport.hpp b/src/hotspot/share/prims/jvmtiExport.hpp index 36df28f271677..e98020aef1d3b 100644 --- a/src/hotspot/share/prims/jvmtiExport.hpp +++ b/src/hotspot/share/prims/jvmtiExport.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -287,10 +287,10 @@ class JvmtiExport : public AllStatic { } // field access management - static address get_field_access_count_addr() NOT_JVMTI_RETURN_(0); + static address get_field_access_count_addr() NOT_JVMTI_RETURN_(nullptr); // field modification management - static address get_field_modification_count_addr() NOT_JVMTI_RETURN_(0); + static address get_field_modification_count_addr() NOT_JVMTI_RETURN_(nullptr); // ----------------- From 08f697f4fcbcdd912c3aa5f331fbf8212906465f Mon Sep 17 00:00:00 2001 From: Christoph Langer Date: Mon, 5 Aug 2024 17:58:12 +0000 Subject: [PATCH 195/353] 8337819: Update GHA JDKs to 22.0.2 Reviewed-by: mbaesken, ihse, shade --- make/conf/github-actions.conf | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/make/conf/github-actions.conf b/make/conf/github-actions.conf index deb5e36f60572..3cb56b47b50b8 100644 --- a/make/conf/github-actions.conf +++ b/make/conf/github-actions.conf @@ -29,17 +29,17 @@ GTEST_VERSION=1.14.0 JTREG_VERSION=7.4+1 LINUX_X64_BOOT_JDK_EXT=tar.gz -LINUX_X64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk22/830ec9fcccef480bb3e73fb7ecafe059/36/GPL/openjdk-22_linux-x64_bin.tar.gz -LINUX_X64_BOOT_JDK_SHA256=4d65cc6ed28711768fd72c2043a7925f7c83f5f51bb64970bd9d52f7791fc6ac - -MACOS_X64_BOOT_JDK_EXT=tar.gz -MACOS_X64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk22/830ec9fcccef480bb3e73fb7ecafe059/36/GPL/openjdk-22_macos-x64_bin.tar.gz -MACOS_X64_BOOT_JDK_SHA256=ae31fe10916429e3fe284266095067a5ce9fecbdc03ff1a079d20459f731ca36 +LINUX_X64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk22.0.2/c9ecb94cd31b495da20a27d4581645e8/9/GPL/openjdk-22.0.2_linux-x64_bin.tar.gz +LINUX_X64_BOOT_JDK_SHA256=41536f115668308ecf4eba92aaf6acaeb0936225828b741efd83b6173ba82963 MACOS_AARCH64_BOOT_JDK_EXT=tar.gz -MACOS_AARCH64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk22/830ec9fcccef480bb3e73fb7ecafe059/36/GPL/openjdk-22_macos-aarch64_bin.tar.gz -MACOS_AARCH64_BOOT_JDK_SHA256=d10f82429d01047968c52c7975c326388cb5d212791e14c1de21c987463a4b53 +MACOS_AARCH64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk22.0.2/c9ecb94cd31b495da20a27d4581645e8/9/GPL/openjdk-22.0.2_macos-aarch64_bin.tar.gz +MACOS_AARCH64_BOOT_JDK_SHA256=3dab98730234e1a87aec14bcb8171d2cae101e96ff4eed1dab96abbb08e843fd + +MACOS_X64_BOOT_JDK_EXT=tar.gz +MACOS_X64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk22.0.2/c9ecb94cd31b495da20a27d4581645e8/9/GPL/openjdk-22.0.2_macos-x64_bin.tar.gz +MACOS_X64_BOOT_JDK_SHA256=e8b3ec7a7077711223d31156e771f11723cd7af31c2017f1bd2eda20855940fb WINDOWS_X64_BOOT_JDK_EXT=zip -WINDOWS_X64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk22/830ec9fcccef480bb3e73fb7ecafe059/36/GPL/openjdk-22_windows-x64_bin.zip -WINDOWS_X64_BOOT_JDK_SHA256=8f5138fecb53c08c20abd4fa6812f9400051f3852582a2142ffda0dff73a5824 +WINDOWS_X64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk22.0.2/c9ecb94cd31b495da20a27d4581645e8/9/GPL/openjdk-22.0.2_windows-x64_bin.zip +WINDOWS_X64_BOOT_JDK_SHA256=f2a9b9ab944e71a64637fcdc6b13a1188cf02d4eb9ecf71dc927e98b3e45f5dc From e2c07d5044587476fc0fff14260e2b73816d2062 Mon Sep 17 00:00:00 2001 From: Chris Plummer Date: Mon, 5 Aug 2024 18:42:27 +0000 Subject: [PATCH 196/353] 8337299: vmTestbase/nsk/jdb/stop_at/stop_at002/stop_at002.java failure goes undetected Reviewed-by: amenkov, sspitsyn --- .../jdb/stop_at/stop_at002/stop_at002.java | 64 ++++++++++++++----- .../jdb/stop_at/stop_at002/stop_at002a.java | 8 ++- 2 files changed, 52 insertions(+), 20 deletions(-) diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/stop_at/stop_at002/stop_at002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/stop_at/stop_at002/stop_at002.java index 620c50fa2ae22..9dae8c17cfc36 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/stop_at/stop_at002/stop_at002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/stop_at/stop_at002/stop_at002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -82,17 +82,10 @@ public static int run(String argv[], PrintStream out) { static final String DEBUGGEE_CLASS = TEST_CLASS + "a"; static final String FIRST_BREAK = DEBUGGEE_CLASS + ".main"; static final String LAST_BREAK = DEBUGGEE_CLASS + ".lastBreak"; - static final String DEBUGGEE_LOCATION1 = DEBUGGEE_CLASS + "$Nested$DeeperNested$DeepestNested:43"; - static final String DEBUGGEE_LOCATION2 = DEBUGGEE_CLASS + "$Inner$MoreInner:57"; - static final String FAILURE_PATTERN = "Unable to set"; + static final String DEBUGGEE_LOCATION1 = DEBUGGEE_CLASS + "$Nested$DeeperNested$DeepestNested:64"; + static final String DEBUGGEE_LOCATION2 = DEBUGGEE_CLASS + "$Inner$MoreInner:78"; protected void runCases() { - String[] reply; - Paragrep grep; - int count; - Vector v; - String found; - if (!checkStop(DEBUGGEE_LOCATION1)) { success = false; } @@ -101,25 +94,62 @@ protected void runCases() { success = false; } - jdb.contToExit(3); + if (!checkBreakpointHit(DEBUGGEE_LOCATION1)) { + success = false; + } + + if (!checkBreakpointHit(DEBUGGEE_LOCATION2)) { + success = false; + } + + jdb.contToExit(1); } - private boolean checkStop (String location) { + private boolean checkStop(String location) { Paragrep grep; String[] reply; String found; - boolean result = true; log.display("Trying to set breakpoint at line: " + location); reply = jdb.receiveReplyFor(JdbCommand.stop_at + location); grep = new Paragrep(reply); - found = grep.findFirst(FAILURE_PATTERN); + found = grep.findFirst("Deferring breakpoint " + location); + if (found.length() == 0) { + log.complain("jdb failed to setup deferred breakpoint at line: " + location); + return false; + } + + return true; + } + + private boolean checkBreakpointHit(String location) { + Paragrep grep; + String[] reply; + String found; + + log.display("continuing to breakpoint at line: " + location); + reply = jdb.receiveReplyFor(JdbCommand.cont); + grep = new Paragrep(reply); + + found = grep.findFirst("Unable to set deferred breakpoint"); if (found.length() > 0) { - log.complain("jdb failed to set line breakpoint at line: " + found); - result = false; + log.complain("jdb failed to set deferred breakpoint at line: " + location); + return false; + } + + found = grep.findFirst("Set deferred breakpoint " + location); + if (found.length() == 0) { + log.complain("jdb failed to set deferred breakpoint at line: " + location); + return false; + } + + found = grep.findFirst("Breakpoint hit: \"thread=main\", "); + if (found.length() == 0) { + log.complain("jdb failed to hit breakpoint at line: " + location); + return false; } - return result; + return true; } } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/stop_at/stop_at002/stop_at002a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/stop_at/stop_at002/stop_at002a.java index 9195dd2698612..d4a40689372d4 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/stop_at/stop_at002/stop_at002a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/stop_at/stop_at002/stop_at002a.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,6 +21,8 @@ * questions. */ +// THIS TEST IS LINE NUMBER SENSITIVE + package nsk.jdb.stop_at.stop_at002; import nsk.share.*; @@ -59,7 +61,7 @@ class Nested { class DeeperNested { class DeepestNested { public void foo(boolean input) { - flag = input; /* <-------- This is line number 43 */ + flag = input; /* <-------- This is line number 64 */ } } } @@ -73,7 +75,7 @@ public MoreInner() { content = ""; } public void foo(String input) { - content += input; /* <-------- This is line number 57 */ + content += input; /* <-------- This is line number 78 */ } } } From 431d4f7e18369466eedd00926a5162a1461d0b25 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Mon, 5 Aug 2024 19:53:49 +0000 Subject: [PATCH 197/353] 8337785: Fix simple -Wzero-as-null-pointer-constant warnings in x86 code Reviewed-by: jwaters, ayang, shade --- src/hotspot/cpu/x86/frame_x86.cpp | 6 +++--- src/hotspot/cpu/x86/macroAssembler_x86_sha.cpp | 6 +++--- src/hotspot/cpu/x86/methodHandles_x86.cpp | 4 ++-- src/hotspot/cpu/x86/vm_version_x86.cpp | 8 ++++---- src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp | 2 +- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/hotspot/cpu/x86/frame_x86.cpp b/src/hotspot/cpu/x86/frame_x86.cpp index 2366d31992d6e..aeb77763e7fff 100644 --- a/src/hotspot/cpu/x86/frame_x86.cpp +++ b/src/hotspot/cpu/x86/frame_x86.cpp @@ -279,7 +279,7 @@ void frame::patch_pc(Thread* thread, address pc) { assert(!Continuation::is_return_barrier_entry(*pc_addr), "return barrier"); - assert(_pc == *pc_addr || pc == *pc_addr || *pc_addr == 0, ""); + assert(_pc == *pc_addr || pc == *pc_addr || *pc_addr == nullptr, ""); DEBUG_ONLY(address old_pc = _pc;) *pc_addr = pc; _pc = pc; // must be set before call to get_deopt_original_pc @@ -483,10 +483,10 @@ frame frame::sender_for_interpreter_frame(RegisterMap* map) const { bool frame::is_interpreted_frame_valid(JavaThread* thread) const { assert(is_interpreted_frame(), "Not an interpreted frame"); // These are reasonable sanity checks - if (fp() == 0 || (intptr_t(fp()) & (wordSize-1)) != 0) { + if (fp() == nullptr || (intptr_t(fp()) & (wordSize-1)) != 0) { return false; } - if (sp() == 0 || (intptr_t(sp()) & (wordSize-1)) != 0) { + if (sp() == nullptr || (intptr_t(sp()) & (wordSize-1)) != 0) { return false; } if (fp() + interpreter_frame_initial_sp_offset < sp()) { diff --git a/src/hotspot/cpu/x86/macroAssembler_x86_sha.cpp b/src/hotspot/cpu/x86/macroAssembler_x86_sha.cpp index c4e9e836fd312..090de71425f17 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86_sha.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86_sha.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2016, 2021, Intel Corporation. All rights reserved. +* Copyright (c) 2016, 2024, Intel Corporation. All rights reserved. * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -689,7 +689,7 @@ void MacroAssembler::sha256_AVX2(XMMRegister msg, XMMRegister state0, XMMRegiste address K256_W = StubRoutines::x86::k256_W_addr(); address pshuffle_byte_flip_mask = StubRoutines::x86::pshuffle_byte_flip_mask_addr(); - address pshuffle_byte_flip_mask_addr = 0; + address pshuffle_byte_flip_mask_addr = nullptr; const XMMRegister& SHUF_00BA = xmm10; // ymm10: shuffle xBxA -> 00BA const XMMRegister& SHUF_DC00 = xmm12; // ymm12: shuffle xDxC -> DC00 @@ -1247,7 +1247,7 @@ void MacroAssembler::sha512_AVX2(XMMRegister msg, XMMRegister state0, XMMRegiste address K512_W = StubRoutines::x86::k512_W_addr(); address pshuffle_byte_flip_mask_sha512 = StubRoutines::x86::pshuffle_byte_flip_mask_addr_sha512(); - address pshuffle_byte_flip_mask_addr = 0; + address pshuffle_byte_flip_mask_addr = nullptr; const XMMRegister& XFER = xmm0; // YTMP0 const XMMRegister& BYTE_FLIP_MASK = xmm9; // ymm9 diff --git a/src/hotspot/cpu/x86/methodHandles_x86.cpp b/src/hotspot/cpu/x86/methodHandles_x86.cpp index de897d71facef..3a8c104876677 100644 --- a/src/hotspot/cpu/x86/methodHandles_x86.cpp +++ b/src/hotspot/cpu/x86/methodHandles_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -572,7 +572,7 @@ void trace_method_handle_stub(const char* adaptername, frame cur_frame = os::current_frame(); - if (cur_frame.fp() != 0) { // not walkable + if (cur_frame.fp() != nullptr) { // not walkable // Robust search of trace_calling_frame (independent of inlining). // Assumes saved_regs comes from a pusha in the trace_calling_frame. diff --git a/src/hotspot/cpu/x86/vm_version_x86.cpp b/src/hotspot/cpu/x86/vm_version_x86.cpp index 02e147743cb1d..6216cf44b887a 100644 --- a/src/hotspot/cpu/x86/vm_version_x86.cpp +++ b/src/hotspot/cpu/x86/vm_version_x86.cpp @@ -53,13 +53,13 @@ const char* VM_Version::_features_names[] = { CPU_FEATURE_FLAGS(DECLARE_CPU_FEAT #undef DECLARE_CPU_FEATURE_FLAG // Address of instruction which causes SEGV -address VM_Version::_cpuinfo_segv_addr = 0; +address VM_Version::_cpuinfo_segv_addr = nullptr; // Address of instruction after the one which causes SEGV -address VM_Version::_cpuinfo_cont_addr = 0; +address VM_Version::_cpuinfo_cont_addr = nullptr; // Address of instruction which causes APX specific SEGV -address VM_Version::_cpuinfo_segv_addr_apx = 0; +address VM_Version::_cpuinfo_segv_addr_apx = nullptr; // Address of instruction after the one which causes APX specific SEGV -address VM_Version::_cpuinfo_cont_addr_apx = 0; +address VM_Version::_cpuinfo_cont_addr_apx = nullptr; static BufferBlob* stub_blob; static const int stub_size = 2000; diff --git a/src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp b/src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp index 78988dd4fd005..0d5d07fc8a804 100644 --- a/src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp +++ b/src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp @@ -224,7 +224,7 @@ bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info, if (info != nullptr && uc != nullptr && thread != nullptr) { pc = (address) os::Posix::ucontext_get_pc(uc); - if (sig == SIGSEGV && info->si_addr == 0 && info->si_code == SI_KERNEL) { + if (sig == SIGSEGV && info->si_addr == nullptr && info->si_code == SI_KERNEL) { // An irrecoverable SI_KERNEL SIGSEGV has occurred. // It's likely caused by dereferencing an address larger than TASK_SIZE. return false; From 7146daee68788bf9a33d6eed6fb0614a82644cbc Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Mon, 5 Aug 2024 20:05:07 +0000 Subject: [PATCH 198/353] 8337783: Use THROW_NULL instead of THROW_0 in pointer contexts in misc runtime code Reviewed-by: stefank, shade --- src/hotspot/os/posix/perfMemory_posix.cpp | 6 +-- src/hotspot/share/classfile/javaClasses.cpp | 2 +- .../share/classfile/systemDictionary.cpp | 2 +- src/hotspot/share/oops/objArrayKlass.cpp | 2 +- src/hotspot/share/runtime/perfData.cpp | 16 ++++---- src/hotspot/share/runtime/reflection.cpp | 38 +++++++++---------- 6 files changed, 33 insertions(+), 33 deletions(-) diff --git a/src/hotspot/os/posix/perfMemory_posix.cpp b/src/hotspot/os/posix/perfMemory_posix.cpp index 56bc8a1ef6b81..4eb46169878cd 100644 --- a/src/hotspot/os/posix/perfMemory_posix.cpp +++ b/src/hotspot/os/posix/perfMemory_posix.cpp @@ -499,11 +499,11 @@ static char* get_user_name_slow(int vmid, int nspid, TRAPS) { // short circuit the directory search if the process doesn't even exist. if (kill(vmid, 0) == OS_ERR) { if (errno == ESRCH) { - THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), - "Process not found"); + THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), + "Process not found"); } else /* EPERM */ { - THROW_MSG_0(vmSymbols::java_io_IOException(), os::strerror(errno)); + THROW_MSG_NULL(vmSymbols::java_io_IOException(), os::strerror(errno)); } } diff --git a/src/hotspot/share/classfile/javaClasses.cpp b/src/hotspot/share/classfile/javaClasses.cpp index b1b74bbba05cf..ab9460e2b9b01 100644 --- a/src/hotspot/share/classfile/javaClasses.cpp +++ b/src/hotspot/share/classfile/javaClasses.cpp @@ -475,7 +475,7 @@ Handle java_lang_String::externalize_classname(Symbol* java_name, TRAPS) { jchar* java_lang_String::as_unicode_string(oop java_string, int& length, TRAPS) { jchar* result = as_unicode_string_or_null(java_string, length); if (result == nullptr) { - THROW_MSG_0(vmSymbols::java_lang_OutOfMemoryError(), "could not allocate Unicode string"); + THROW_MSG_NULL(vmSymbols::java_lang_OutOfMemoryError(), "could not allocate Unicode string"); } return result; } diff --git a/src/hotspot/share/classfile/systemDictionary.cpp b/src/hotspot/share/classfile/systemDictionary.cpp index 3016d41b28923..7f9e6430cc651 100644 --- a/src/hotspot/share/classfile/systemDictionary.cpp +++ b/src/hotspot/share/classfile/systemDictionary.cpp @@ -259,7 +259,7 @@ Handle SystemDictionary::get_loader_lock_or_null(Handle class_loader) { Symbol* SystemDictionary::class_name_symbol(const char* name, Symbol* exception, TRAPS) { if (name == nullptr) { - THROW_MSG_0(exception, "No class name given"); + THROW_MSG_NULL(exception, "No class name given"); } if ((int)strlen(name) > Symbol::max_length()) { // It's impossible to create this class; the name cannot fit diff --git a/src/hotspot/share/oops/objArrayKlass.cpp b/src/hotspot/share/oops/objArrayKlass.cpp index 94d3c6b6b358e..bee010b6d7244 100644 --- a/src/hotspot/share/oops/objArrayKlass.cpp +++ b/src/hotspot/share/oops/objArrayKlass.cpp @@ -173,7 +173,7 @@ oop ObjArrayKlass::multi_allocate(int rank, jint* sizes, TRAPS) { for (int i = 0; i < rank - 1; ++i) { sizes += 1; if (*sizes < 0) { - THROW_MSG_0(vmSymbols::java_lang_NegativeArraySizeException(), err_msg("%d", *sizes)); + THROW_MSG_NULL(vmSymbols::java_lang_NegativeArraySizeException(), err_msg("%d", *sizes)); } } } diff --git a/src/hotspot/share/runtime/perfData.cpp b/src/hotspot/share/runtime/perfData.cpp index 5e78baad3ab2a..657427943aa2f 100644 --- a/src/hotspot/share/runtime/perfData.cpp +++ b/src/hotspot/share/runtime/perfData.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -361,7 +361,7 @@ PerfStringConstant* PerfDataManager::create_string_constant(CounterNS ns, if (!p->is_valid()) { // allocation of native resources failed. delete p; - THROW_0(vmSymbols::java_lang_OutOfMemoryError()); + THROW_NULL(vmSymbols::java_lang_OutOfMemoryError()); } add_item(p, false); @@ -379,7 +379,7 @@ PerfLongConstant* PerfDataManager::create_long_constant(CounterNS ns, if (!p->is_valid()) { // allocation of native resources failed. delete p; - THROW_0(vmSymbols::java_lang_OutOfMemoryError()); + THROW_NULL(vmSymbols::java_lang_OutOfMemoryError()); } add_item(p, false); @@ -402,7 +402,7 @@ PerfStringVariable* PerfDataManager::create_string_variable(CounterNS ns, if (!p->is_valid()) { // allocation of native resources failed. delete p; - THROW_0(vmSymbols::java_lang_OutOfMemoryError()); + THROW_NULL(vmSymbols::java_lang_OutOfMemoryError()); } add_item(p, false); @@ -420,7 +420,7 @@ PerfLongVariable* PerfDataManager::create_long_variable(CounterNS ns, if (!p->is_valid()) { // allocation of native resources failed. delete p; - THROW_0(vmSymbols::java_lang_OutOfMemoryError()); + THROW_NULL(vmSymbols::java_lang_OutOfMemoryError()); } add_item(p, false); @@ -442,7 +442,7 @@ PerfLongVariable* PerfDataManager::create_long_variable(CounterNS ns, if (!p->is_valid()) { // allocation of native resources failed. delete p; - THROW_0(vmSymbols::java_lang_OutOfMemoryError()); + THROW_NULL(vmSymbols::java_lang_OutOfMemoryError()); } add_item(p, true); @@ -460,7 +460,7 @@ PerfLongCounter* PerfDataManager::create_long_counter(CounterNS ns, if (!p->is_valid()) { // allocation of native resources failed. delete p; - THROW_0(vmSymbols::java_lang_OutOfMemoryError()); + THROW_NULL(vmSymbols::java_lang_OutOfMemoryError()); } add_item(p, false); @@ -482,7 +482,7 @@ PerfLongCounter* PerfDataManager::create_long_counter(CounterNS ns, if (!p->is_valid()) { // allocation of native resources failed. delete p; - THROW_0(vmSymbols::java_lang_OutOfMemoryError()); + THROW_NULL(vmSymbols::java_lang_OutOfMemoryError()); } add_item(p, true); diff --git a/src/hotspot/share/runtime/reflection.cpp b/src/hotspot/share/runtime/reflection.cpp index bc8779158d31d..865d25fa06b8a 100644 --- a/src/hotspot/share/runtime/reflection.cpp +++ b/src/hotspot/share/runtime/reflection.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -325,7 +325,7 @@ static Klass* basic_type_mirror_to_arrayklass(oop basic_type_mirror, TRAPS) { assert(java_lang_Class::is_primitive(basic_type_mirror), "just checking"); BasicType type = java_lang_Class::primitive_type(basic_type_mirror); if (type == T_VOID) { - THROW_0(vmSymbols::java_lang_IllegalArgumentException()); + THROW_NULL(vmSymbols::java_lang_IllegalArgumentException()); } else { return Universe::typeArrayKlass(type); @@ -334,10 +334,10 @@ static Klass* basic_type_mirror_to_arrayklass(oop basic_type_mirror, TRAPS) { arrayOop Reflection::reflect_new_array(oop element_mirror, jint length, TRAPS) { if (element_mirror == nullptr) { - THROW_0(vmSymbols::java_lang_NullPointerException()); + THROW_NULL(vmSymbols::java_lang_NullPointerException()); } if (length < 0) { - THROW_MSG_0(vmSymbols::java_lang_NegativeArraySizeException(), err_msg("%d", length)); + THROW_MSG_NULL(vmSymbols::java_lang_NegativeArraySizeException(), err_msg("%d", length)); } if (java_lang_Class::is_primitive(element_mirror)) { Klass* tak = basic_type_mirror_to_arrayklass(element_mirror, CHECK_NULL); @@ -345,7 +345,7 @@ arrayOop Reflection::reflect_new_array(oop element_mirror, jint length, TRAPS) { } else { Klass* k = java_lang_Class::as_Klass(element_mirror); if (k->is_array_klass() && ArrayKlass::cast(k)->dimension() >= MAX_DIM) { - THROW_0(vmSymbols::java_lang_IllegalArgumentException()); + THROW_NULL(vmSymbols::java_lang_IllegalArgumentException()); } return oopFactory::new_objArray(k, length, THREAD); } @@ -357,19 +357,19 @@ arrayOop Reflection::reflect_new_multi_array(oop element_mirror, typeArrayOop di assert(TypeArrayKlass::cast(dim_array->klass())->element_type() == T_INT, "just checking"); if (element_mirror == nullptr) { - THROW_0(vmSymbols::java_lang_NullPointerException()); + THROW_NULL(vmSymbols::java_lang_NullPointerException()); } int len = dim_array->length(); if (len <= 0 || len > MAX_DIM) { - THROW_0(vmSymbols::java_lang_IllegalArgumentException()); + THROW_NULL(vmSymbols::java_lang_IllegalArgumentException()); } jint dimensions[MAX_DIM]; // C array copy of intArrayOop for (int i = 0; i < len; i++) { int d = dim_array->int_at(i); if (d < 0) { - THROW_MSG_0(vmSymbols::java_lang_NegativeArraySizeException(), err_msg("%d", d)); + THROW_MSG_NULL(vmSymbols::java_lang_NegativeArraySizeException(), err_msg("%d", d)); } dimensions[i] = d; } @@ -383,7 +383,7 @@ arrayOop Reflection::reflect_new_multi_array(oop element_mirror, typeArrayOop di if (klass->is_array_klass()) { int k_dim = ArrayKlass::cast(klass)->dimension(); if (k_dim + len > MAX_DIM) { - THROW_0(vmSymbols::java_lang_IllegalArgumentException()); + THROW_NULL(vmSymbols::java_lang_IllegalArgumentException()); } dim += k_dim; } @@ -977,11 +977,11 @@ static oop invoke(InstanceKlass* klass, } else { // check for null receiver if (receiver.is_null()) { - THROW_0(vmSymbols::java_lang_NullPointerException()); + THROW_NULL(vmSymbols::java_lang_NullPointerException()); } // Check class of receiver against class declaring method if (!receiver->is_a(klass)) { - THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "object is not an instance of declaring class"); + THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), "object is not an instance of declaring class"); } // target klass is receiver's klass target_klass = receiver->klass(); @@ -1047,15 +1047,15 @@ static oop invoke(InstanceKlass* klass, reflected_method->name(), reflected_method->signature()); ss.print("'"); - THROW_MSG_0(vmSymbols::java_lang_NoSuchMethodError(), ss.as_string()); + THROW_MSG_NULL(vmSymbols::java_lang_NoSuchMethodError(), ss.as_string()); } assert(ptypes->is_objArray(), "just checking"); int args_len = args.is_null() ? 0 : args->length(); // Check number of arguments if (ptypes->length() != args_len) { - THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), - "wrong number of arguments"); + THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), + "wrong number of arguments"); } // Create object to contain parameters for the JavaCall @@ -1085,14 +1085,14 @@ static oop invoke(InstanceKlass* klass, case T_FLOAT: java_args.push_float(value.f); break; case T_DOUBLE: java_args.push_double(value.d); break; default: - THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "argument type mismatch"); + THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), "argument type mismatch"); } } else { if (arg != nullptr) { Klass* k = java_lang_Class::as_Klass(type_mirror); if (!arg->is_a(k)) { - THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), - "argument type mismatch"); + THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), + "argument type mismatch"); } } Handle arg_handle(THREAD, arg); // Create handle for argument @@ -1148,7 +1148,7 @@ oop Reflection::invoke_method(oop method_mirror, Handle receiver, objArrayHandle InstanceKlass* klass = InstanceKlass::cast(java_lang_Class::as_Klass(mirror)); Method* m = klass->method_with_idnum(slot); if (m == nullptr) { - THROW_MSG_0(vmSymbols::java_lang_InternalError(), "invoke"); + THROW_MSG_NULL(vmSymbols::java_lang_InternalError(), "invoke"); } methodHandle method(THREAD, m); @@ -1165,7 +1165,7 @@ oop Reflection::invoke_constructor(oop constructor_mirror, objArrayHandle args, InstanceKlass* klass = InstanceKlass::cast(java_lang_Class::as_Klass(mirror)); Method* m = klass->method_with_idnum(slot); if (m == nullptr) { - THROW_MSG_0(vmSymbols::java_lang_InternalError(), "invoke"); + THROW_MSG_NULL(vmSymbols::java_lang_InternalError(), "invoke"); } methodHandle method(THREAD, m); assert(method->name() == vmSymbols::object_initializer_name(), "invalid constructor"); From 965d6b9cbe2dd882fe3c3c955dfa08685af7d6c2 Mon Sep 17 00:00:00 2001 From: Serguei Spitsyn Date: Mon, 5 Aug 2024 23:29:17 +0000 Subject: [PATCH 199/353] 8335836: serviceability/jvmti/StartPhase/AllowedFunctions/AllowedFunctions.java fails with unexpected exit code: 112 Reviewed-by: cjplummer, amenkov --- .../AllowedFunctions/libAllowedFunctions.c | 45 +++++++++++++++++-- 1 file changed, 41 insertions(+), 4 deletions(-) diff --git a/test/hotspot/jtreg/serviceability/jvmti/StartPhase/AllowedFunctions/libAllowedFunctions.c b/test/hotspot/jtreg/serviceability/jvmti/StartPhase/AllowedFunctions/libAllowedFunctions.c index 4299a98d7e63b..97b5cab341eb2 100644 --- a/test/hotspot/jtreg/serviceability/jvmti/StartPhase/AllowedFunctions/libAllowedFunctions.c +++ b/test/hotspot/jtreg/serviceability/jvmti/StartPhase/AllowedFunctions/libAllowedFunctions.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,6 +47,8 @@ extern "C" { #define FAILED 2 static jint result = PASSED; +static jrawMonitorID event_mon = NULL; +static jboolean is_vm_dead = JNI_FALSE; static jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved); @@ -68,7 +70,7 @@ jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) { static void check_jvmti_error(jvmtiEnv *jvmti, char* fname, jvmtiError err) { if (err != JVMTI_ERROR_NONE) { printf(" ## %s error: %d\n", fname, err); - exit(err); + abort(); } } @@ -317,7 +319,7 @@ VMStart(jvmtiEnv *jvmti, JNIEnv* jni) { } static void JNICALL -VMInit(jvmtiEnv *jvmti, JNIEnv* jnii, jthread thread) { +VMInit(jvmtiEnv *jvmti, JNIEnv* jni, jthread thread) { jvmtiPhase phase; printf("VMInit event\n"); @@ -329,22 +331,52 @@ VMInit(jvmtiEnv *jvmti, JNIEnv* jnii, jthread thread) { } } +static void JNICALL +VMDeath(jvmtiEnv *jvmti, JNIEnv* jni) { + jvmtiError err; + + // Block ClassPrepare events while this callback is executed. + err = (*jvmti)->RawMonitorEnter(jvmti, event_mon); + check_jvmti_error(jvmti, "VMDeath event: Failed in RawMonitorEnter", err); + + is_vm_dead = JNI_TRUE; + printf("VMDeath event\n"); + + err = (*jvmti)->RawMonitorExit(jvmti, event_mon); + check_jvmti_error(jvmti, "VMDeath event: Failed in RawMonitorExit", err); +} + static void JNICALL ClassPrepare(jvmtiEnv *jvmti, JNIEnv *env, jthread thread, jclass klass) { static const jint EVENTS_LIMIT = 2; static jint event_no = 0; - jthread cur_thread = get_cur_thread(jvmti); jvmtiPhase phase; intptr_t exp_val = 777; intptr_t act_val; + jvmtiError err; + + // Block VMDeath event and other ClassPrepare events while this callback is executed. + // Sync with VMDeath event and check for is_vm_dead guard against JVMTI_ERROR WRONG_PHASE. + err = (*jvmti)->RawMonitorEnter(jvmti, event_mon); + check_jvmti_error(jvmti, "ClassPrepare event: Failed in RawMonitorEnter", err); + if (is_vm_dead) { + printf("\nIgnoring ClassPrepare event during the dead phase\n"); + err = (*jvmti)->RawMonitorExit(jvmti, event_mon); + check_jvmti_error(jvmti, "ClassPrepare event: Failed in RawMonitorExit", err); + return; + } get_phase(jvmti, &phase); if (phase != JVMTI_PHASE_START && phase != JVMTI_PHASE_LIVE) { printf(" ## Error: unexpected phase: %d, expected: %d or %d\n", phase, JVMTI_PHASE_START, JVMTI_PHASE_LIVE); + result = FAILED; + err = (*jvmti)->RawMonitorExit(jvmti, event_mon); + check_jvmti_error(jvmti, "ClassPrepare event: Failed in RawMonitorExit", err); return; } if (phase == JVMTI_PHASE_START && event_no < EVENTS_LIMIT) { + jthread cur_thread = get_cur_thread(jvmti); printf("\nClassPrepare event during the start phase: #%d\n", event_no); // Test the JVMTI class functions during the start phase test_class_functions(jvmti, env, thread, klass); @@ -360,6 +392,8 @@ ClassPrepare(jvmtiEnv *jvmti, JNIEnv *env, jthread thread, jclass klass) { } event_no++; } + err = (*jvmti)->RawMonitorExit(jvmti, event_mon); + check_jvmti_error(jvmti, "ClassPrepare event: Failed in RawMonitorExit", err); } static @@ -400,6 +434,9 @@ jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { callbacks.VMInit = VMInit; callbacks.ClassPrepare = ClassPrepare; + err = (*jvmti)->CreateRawMonitor(jvmti, "Events Monitor", &event_mon); + check_jvmti_error(jvmti, "## Agent_Initialize: CreateRawMonitor", err); + err = (*jvmti)->SetEventCallbacks(jvmti, &callbacks, size); check_jvmti_error(jvmti, "## Agent_Initialize: SetEventCallbacks", err); From 73718fb8a3570023e7855137eb008f78b8a1e8ce Mon Sep 17 00:00:00 2001 From: Gui Cao Date: Tue, 6 Aug 2024 02:16:19 +0000 Subject: [PATCH 200/353] 8337788: RISC-V: Cleanup code in MacroAssembler::reserved_stack_check Reviewed-by: fyang, rehn, fjiang --- .../cpu/riscv/macroAssembler_riscv.cpp | 34 ++++++++----------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index cd7a4ecf22803..e0b24b7fd66ca 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -4130,29 +4130,25 @@ void MacroAssembler::remove_frame(int framesize) { } void MacroAssembler::reserved_stack_check() { - // testing if reserved zone needs to be enabled - Label no_reserved_zone_enabling; + // testing if reserved zone needs to be enabled + Label no_reserved_zone_enabling; - ld(t0, Address(xthread, JavaThread::reserved_stack_activation_offset())); - bltu(sp, t0, no_reserved_zone_enabling); + ld(t0, Address(xthread, JavaThread::reserved_stack_activation_offset())); + bltu(sp, t0, no_reserved_zone_enabling); - enter(); // RA and FP are live. - mv(c_rarg0, xthread); - rt_call(CAST_FROM_FN_PTR(address, SharedRuntime::enable_stack_reserved_zone)); - leave(); + enter(); // RA and FP are live. + mv(c_rarg0, xthread); + rt_call(CAST_FROM_FN_PTR(address, SharedRuntime::enable_stack_reserved_zone)); + leave(); - // We have already removed our own frame. - // throw_delayed_StackOverflowError will think that it's been - // called by our caller. - RuntimeAddress target(StubRoutines::throw_delayed_StackOverflowError_entry()); - relocate(target.rspec(), [&] { - int32_t offset; - movptr(t0, target.target(), offset); - jr(t0, offset); - }); - should_not_reach_here(); + // We have already removed our own frame. + // throw_delayed_StackOverflowError will think that it's been + // called by our caller. + la(t0, RuntimeAddress(StubRoutines::throw_delayed_StackOverflowError_entry())); + jr(t0); + should_not_reach_here(); - bind(no_reserved_zone_enabling); + bind(no_reserved_zone_enabling); } // Move the address of the polling page into dest. From 20575949612a750a428316635715737183a2d58c Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Tue, 6 Aug 2024 05:34:33 +0000 Subject: [PATCH 201/353] 8337782: Use THROW_NULL instead of THROW_0 in pointer contexts in prims code Reviewed-by: shade, dholmes --- src/hotspot/share/prims/jni.cpp | 16 +++---- src/hotspot/share/prims/jvm.cpp | 54 ++++++++++++------------ src/hotspot/share/prims/nativeLookup.cpp | 4 +- src/hotspot/share/prims/perf.cpp | 16 +++---- src/hotspot/share/prims/unsafe.cpp | 2 +- src/hotspot/share/prims/whitebox.cpp | 2 +- 6 files changed, 47 insertions(+), 47 deletions(-) diff --git a/src/hotspot/share/prims/jni.cpp b/src/hotspot/share/prims/jni.cpp index a91d7375761e2..12eba0ff623be 100644 --- a/src/hotspot/share/prims/jni.cpp +++ b/src/hotspot/share/prims/jni.cpp @@ -1074,7 +1074,7 @@ static jmethodID get_method_id(JNIEnv *env, jclass clazz, const char *name_str, TempNewSymbol signature = SymbolTable::probe(sig, (int)strlen(sig)); if (name == nullptr || signature == nullptr) { - THROW_MSG_0(vmSymbols::java_lang_NoSuchMethodError(), name_str); + THROW_MSG_NULL(vmSymbols::java_lang_NoSuchMethodError(), name_str); } oop mirror = JNIHandles::resolve_non_null(clazz); @@ -1084,7 +1084,7 @@ static jmethodID get_method_id(JNIEnv *env, jclass clazz, const char *name_str, // primitive java.lang.Class if (java_lang_Class::is_primitive(mirror)) { ResourceMark rm(THREAD); - THROW_MSG_0(vmSymbols::java_lang_NoSuchMethodError(), err_msg("%s%s.%s%s", is_static ? "static " : "", klass->signature_name(), name_str, sig)); + THROW_MSG_NULL(vmSymbols::java_lang_NoSuchMethodError(), err_msg("%s%s.%s%s", is_static ? "static " : "", klass->signature_name(), name_str, sig)); } // Make sure class is linked and initialized before handing id's out to @@ -1108,7 +1108,7 @@ static jmethodID get_method_id(JNIEnv *env, jclass clazz, const char *name_str, } if (m == nullptr || (m->is_static() != is_static)) { ResourceMark rm(THREAD); - THROW_MSG_0(vmSymbols::java_lang_NoSuchMethodError(), err_msg("%s%s.%s%s", is_static ? "static " : "", klass->signature_name(), name_str, sig)); + THROW_MSG_NULL(vmSymbols::java_lang_NoSuchMethodError(), err_msg("%s%s.%s%s", is_static ? "static " : "", klass->signature_name(), name_str, sig)); } return m->jmethod_id(); } @@ -1762,7 +1762,7 @@ JNI_ENTRY(jfieldID, jni_GetFieldID(JNIEnv *env, jclass clazz, TempNewSymbol signame = SymbolTable::probe(sig, (int)strlen(sig)); if (fieldname == nullptr || signame == nullptr) { ResourceMark rm; - THROW_MSG_0(vmSymbols::java_lang_NoSuchFieldError(), err_msg("%s.%s %s", k->external_name(), name, sig)); + THROW_MSG_NULL(vmSymbols::java_lang_NoSuchFieldError(), err_msg("%s.%s %s", k->external_name(), name, sig)); } // Make sure class is initialized before handing id's out to fields @@ -1772,7 +1772,7 @@ JNI_ENTRY(jfieldID, jni_GetFieldID(JNIEnv *env, jclass clazz, if (!k->is_instance_klass() || !InstanceKlass::cast(k)->find_field(fieldname, signame, false, &fd)) { ResourceMark rm; - THROW_MSG_0(vmSymbols::java_lang_NoSuchFieldError(), err_msg("%s.%s %s", k->external_name(), name, sig)); + THROW_MSG_NULL(vmSymbols::java_lang_NoSuchFieldError(), err_msg("%s.%s %s", k->external_name(), name, sig)); } // A jfieldID for a non-static field is simply the offset of the field within the instanceOop @@ -1986,7 +1986,7 @@ JNI_ENTRY(jfieldID, jni_GetStaticFieldID(JNIEnv *env, jclass clazz, TempNewSymbol fieldname = SymbolTable::probe(name, (int)strlen(name)); TempNewSymbol signame = SymbolTable::probe(sig, (int)strlen(sig)); if (fieldname == nullptr || signame == nullptr) { - THROW_MSG_0(vmSymbols::java_lang_NoSuchFieldError(), (char*) name); + THROW_MSG_NULL(vmSymbols::java_lang_NoSuchFieldError(), (char*) name); } Klass* k = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(clazz)); // Make sure class is initialized before handing id's out to static fields @@ -1995,7 +1995,7 @@ JNI_ENTRY(jfieldID, jni_GetStaticFieldID(JNIEnv *env, jclass clazz, fieldDescriptor fd; if (!k->is_instance_klass() || !InstanceKlass::cast(k)->find_field(fieldname, signame, true, &fd)) { - THROW_MSG_0(vmSymbols::java_lang_NoSuchFieldError(), (char*) name); + THROW_MSG_NULL(vmSymbols::java_lang_NoSuchFieldError(), (char*) name); } // A jfieldID for a static field is a JNIid specifying the field holder and the offset within the Klass* @@ -2309,7 +2309,7 @@ JNI_ENTRY(jobject, jni_GetObjectArrayElement(JNIEnv *env, jobjectArray array, js ResourceMark rm(THREAD); stringStream ss; ss.print("Index %d out of bounds for length %d", index, a->length()); - THROW_MSG_0(vmSymbols::java_lang_ArrayIndexOutOfBoundsException(), ss.as_string()); + THROW_MSG_NULL(vmSymbols::java_lang_ArrayIndexOutOfBoundsException(), ss.as_string()); } JNI_END diff --git a/src/hotspot/share/prims/jvm.cpp b/src/hotspot/share/prims/jvm.cpp index 1e3806474b540..e40c11289661e 100644 --- a/src/hotspot/share/prims/jvm.cpp +++ b/src/hotspot/share/prims/jvm.cpp @@ -691,7 +691,7 @@ JVM_ENTRY(jobject, JVM_Clone(JNIEnv* env, jobject handle)) (klass->is_instance_klass() && InstanceKlass::cast(klass)->reference_type() != REF_NONE)) { ResourceMark rm(THREAD); - THROW_MSG_0(vmSymbols::java_lang_CloneNotSupportedException(), klass->external_name()); + THROW_MSG_NULL(vmSymbols::java_lang_CloneNotSupportedException(), klass->external_name()); } // Make shallow object copy @@ -791,7 +791,7 @@ JVM_ENTRY(jclass, JVM_FindPrimitiveClass(JNIEnv* env, const char* utf)) mirror = Universe::java_mirror(t); } if (mirror == nullptr) { - THROW_MSG_0(vmSymbols::java_lang_ClassNotFoundException(), (char*) utf); + THROW_MSG_NULL(vmSymbols::java_lang_ClassNotFoundException(), (char*) utf); } else { return (jclass) JNIHandles::make_local(THREAD, mirror); } @@ -952,7 +952,7 @@ static jclass jvm_lookup_define_class(jclass lookup, const char *name, Klass* lookup_k = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(lookup)); // Lookup class must be a non-null instance if (lookup_k == nullptr) { - THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "Lookup class is null"); + THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), "Lookup class is null"); } assert(lookup_k->is_instance_klass(), "Lookup class must be an instance klass"); @@ -979,20 +979,20 @@ static jclass jvm_lookup_define_class(jclass lookup, const char *name, if (!is_hidden) { // classData is only applicable for hidden classes if (classData != nullptr) { - THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "classData is only applicable for hidden classes"); + THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), "classData is only applicable for hidden classes"); } if (is_nestmate) { - THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "dynamic nestmate is only applicable for hidden classes"); + THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), "dynamic nestmate is only applicable for hidden classes"); } if (!is_strong) { - THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "an ordinary class must be strongly referenced by its defining loader"); + THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), "an ordinary class must be strongly referenced by its defining loader"); } if (vm_annotations) { - THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "vm annotations only allowed for hidden classes"); + THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), "vm annotations only allowed for hidden classes"); } if (flags != STRONG_LOADER_LINK) { - THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), - err_msg("invalid flag 0x%x", flags)); + THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), + err_msg("invalid flag 0x%x", flags)); } } @@ -1047,7 +1047,7 @@ static jclass jvm_lookup_define_class(jclass lookup, const char *name, if ((!is_hidden || is_nestmate) && !Reflection::is_same_class_package(lookup_k, ik)) { // non-hidden class or nestmate class must be in the same package as the Lookup class - THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "Lookup class and defined class are in different packages"); + THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), "Lookup class and defined class are in different packages"); } if (init) { @@ -1078,7 +1078,7 @@ JVM_ENTRY(jclass, JVM_LookupDefineClass(JNIEnv *env, jclass lookup, const char * jsize len, jobject pd, jboolean initialize, int flags, jobject classData)) if (lookup == nullptr) { - THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "Lookup class is null"); + THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), "Lookup class is null"); } assert(buf != nullptr, "buf must not be null"); @@ -1703,8 +1703,8 @@ JVM_ENTRY(jobjectArray, JVM_GetMethodParameters(JNIEnv *env, jobject method)) bounds_check(cp, index, CHECK_NULL); if (0 != index && !mh->constants()->tag_at(index).is_utf8()) { - THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), - "Wrong type at constant pool index"); + THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), + "Wrong type at constant pool index"); } } @@ -2133,7 +2133,7 @@ JVM_ENTRY(jclass, JVM_ConstantPoolGetClassAt(JNIEnv *env, jobject obj, jobject u bounds_check(cp, index, CHECK_NULL); constantTag tag = cp->tag_at(index); if (!tag.is_klass() && !tag.is_unresolved_klass()) { - THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "Wrong type at constant pool index"); + THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), "Wrong type at constant pool index"); } Klass* k = cp->klass_at(index, CHECK_NULL); return (jclass) JNIHandles::make_local(THREAD, k->java_mirror()); @@ -2146,7 +2146,7 @@ JVM_ENTRY(jclass, JVM_ConstantPoolGetClassAtIfLoaded(JNIEnv *env, jobject obj, j bounds_check(cp, index, CHECK_NULL); constantTag tag = cp->tag_at(index); if (!tag.is_klass() && !tag.is_unresolved_klass()) { - THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "Wrong type at constant pool index"); + THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), "Wrong type at constant pool index"); } Klass* k = ConstantPool::klass_at_if_loaded(cp, index); if (k == nullptr) return nullptr; @@ -2157,7 +2157,7 @@ JVM_END static jobject get_method_at_helper(const constantPoolHandle& cp, jint index, bool force_resolution, TRAPS) { constantTag tag = cp->tag_at(index); if (!tag.is_method() && !tag.is_interface_method()) { - THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "Wrong type at constant pool index"); + THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), "Wrong type at constant pool index"); } int klass_ref = cp->uncached_klass_ref_index_at(index); Klass* k_o; @@ -2172,7 +2172,7 @@ static jobject get_method_at_helper(const constantPoolHandle& cp, jint index, bo Symbol* sig = cp->uncached_signature_ref_at(index); methodHandle m (THREAD, k->find_method(name, sig)); if (m.is_null()) { - THROW_MSG_0(vmSymbols::java_lang_RuntimeException(), "Unable to look up method in target class"); + THROW_MSG_NULL(vmSymbols::java_lang_RuntimeException(), "Unable to look up method in target class"); } oop method; if (!m->is_initializer() || m->is_static()) { @@ -2206,7 +2206,7 @@ JVM_END static jobject get_field_at_helper(constantPoolHandle cp, jint index, bool force_resolution, TRAPS) { constantTag tag = cp->tag_at(index); if (!tag.is_field()) { - THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "Wrong type at constant pool index"); + THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), "Wrong type at constant pool index"); } int klass_ref = cp->uncached_klass_ref_index_at(index); Klass* k_o; @@ -2222,7 +2222,7 @@ static jobject get_field_at_helper(constantPoolHandle cp, jint index, bool force fieldDescriptor fd; Klass* target_klass = k->find_field(name, sig, &fd); if (target_klass == nullptr) { - THROW_MSG_0(vmSymbols::java_lang_RuntimeException(), "Unable to look up field in target class"); + THROW_MSG_NULL(vmSymbols::java_lang_RuntimeException(), "Unable to look up field in target class"); } oop field = Reflection::new_field(&fd, CHECK_NULL); return JNIHandles::make_local(THREAD, field); @@ -2255,7 +2255,7 @@ JVM_ENTRY(jobjectArray, JVM_ConstantPoolGetMemberRefInfoAt(JNIEnv *env, jobject bounds_check(cp, index, CHECK_NULL); constantTag tag = cp->tag_at(index); if (!tag.is_field_or_method()) { - THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "Wrong type at constant pool index"); + THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), "Wrong type at constant pool index"); } int klass_ref = cp->uncached_klass_ref_index_at(index); Symbol* klass_name = cp->klass_name_at(klass_ref); @@ -2306,7 +2306,7 @@ JVM_ENTRY(jobjectArray, JVM_ConstantPoolGetNameAndTypeRefInfoAt(JNIEnv *env, job bounds_check(cp, index, CHECK_NULL); constantTag tag = cp->tag_at(index); if (!tag.is_name_and_type()) { - THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "Wrong type at constant pool index"); + THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), "Wrong type at constant pool index"); } Symbol* member_name = cp->symbol_at(cp->name_ref_index_at(index)); Symbol* member_sig = cp->symbol_at(cp->signature_ref_index_at(index)); @@ -2374,7 +2374,7 @@ JVM_ENTRY(jstring, JVM_ConstantPoolGetStringAt(JNIEnv *env, jobject obj, jobject bounds_check(cp, index, CHECK_NULL); constantTag tag = cp->tag_at(index); if (!tag.is_string()) { - THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "Wrong type at constant pool index"); + THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), "Wrong type at constant pool index"); } oop str = cp->string_at(index, CHECK_NULL); return (jstring) JNIHandles::make_local(THREAD, str); @@ -2388,7 +2388,7 @@ JVM_ENTRY(jstring, JVM_ConstantPoolGetUTF8At(JNIEnv *env, jobject obj, jobject u bounds_check(cp, index, CHECK_NULL); constantTag tag = cp->tag_at(index); if (!tag.is_symbol()) { - THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "Wrong type at constant pool index"); + THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), "Wrong type at constant pool index"); } Symbol* sym = cp->symbol_at(index); Handle str = java_lang_String::create_from_symbol(sym, CHECK_NULL); @@ -3292,13 +3292,13 @@ JVM_END // resolve array handle and check arguments static inline arrayOop check_array(JNIEnv *env, jobject arr, bool type_array_only, TRAPS) { if (arr == nullptr) { - THROW_0(vmSymbols::java_lang_NullPointerException()); + THROW_NULL(vmSymbols::java_lang_NullPointerException()); } oop a = JNIHandles::resolve_non_null(arr); if (!a->is_array()) { - THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "Argument is not an array"); + THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), "Argument is not an array"); } else if (type_array_only && !a->is_typeArray()) { - THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "Argument is not an array of primitive type"); + THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), "Argument is not an array of primitive type"); } return arrayOop(a); } @@ -3535,7 +3535,7 @@ JVM_ENTRY(jobject, JVM_InvokeMethod(JNIEnv *env, jobject method, jobject obj, jo } return res; } else { - THROW_0(vmSymbols::java_lang_StackOverflowError()); + THROW_NULL(vmSymbols::java_lang_StackOverflowError()); } JVM_END diff --git a/src/hotspot/share/prims/nativeLookup.cpp b/src/hotspot/share/prims/nativeLookup.cpp index e838c831ff1ab..78cf7481abfd0 100644 --- a/src/hotspot/share/prims/nativeLookup.cpp +++ b/src/hotspot/share/prims/nativeLookup.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -414,7 +414,7 @@ address NativeLookup::lookup_base(const methodHandle& method, TRAPS) { ss.print("'"); method->print_external_name(&ss); ss.print("'"); - THROW_MSG_0(vmSymbols::java_lang_UnsatisfiedLinkError(), ss.as_string()); + THROW_MSG_NULL(vmSymbols::java_lang_UnsatisfiedLinkError(), ss.as_string()); } diff --git a/src/hotspot/share/prims/perf.cpp b/src/hotspot/share/prims/perf.cpp index 9ff831dded9fa..feef9760d8fdf 100644 --- a/src/hotspot/share/prims/perf.cpp +++ b/src/hotspot/share/prims/perf.cpp @@ -50,7 +50,7 @@ static char* jstr_to_utf(JNIEnv *env, jstring str, TRAPS) { char* utfstr = nullptr; if (str == nullptr) { - THROW_0(vmSymbols::java_lang_NullPointerException()); + THROW_NULL(vmSymbols::java_lang_NullPointerException()); //throw_new(env,"NullPointerException"); } @@ -113,7 +113,7 @@ PERF_ENTRY(jobject, Perf_CreateLong(JNIEnv *env, jobject perf, jstring name, if (units <= 0 || units > PerfData::U_Last) { debug_only(warning("unexpected units argument, units = %d", units)); - THROW_0(vmSymbols::java_lang_IllegalArgumentException()); + THROW_NULL(vmSymbols::java_lang_IllegalArgumentException()); } ResourceMark rm; @@ -128,7 +128,7 @@ PERF_ENTRY(jobject, Perf_CreateLong(JNIEnv *env, jobject perf, jstring name, // check that the PerfData name doesn't already exist if (PerfDataManager::exists(name_utf)) { - THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "PerfLong name already exists"); + THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), "PerfLong name already exists"); } switch(variability) { @@ -152,7 +152,7 @@ PERF_ENTRY(jobject, Perf_CreateLong(JNIEnv *env, jobject perf, jstring name, default: /* Illegal Argument */ debug_only(warning("unexpected variability value: %d", variability)); - THROW_0(vmSymbols::java_lang_IllegalArgumentException()); + THROW_NULL(vmSymbols::java_lang_IllegalArgumentException()); break; } @@ -174,21 +174,21 @@ PERF_ENTRY(jobject, Perf_CreateByteArray(JNIEnv *env, jobject perf, // check for valid byte array objects if (name == nullptr || value == nullptr) { - THROW_0(vmSymbols::java_lang_NullPointerException()); + THROW_NULL(vmSymbols::java_lang_NullPointerException()); } // check for valid variability classification if (variability != PerfData::V_Constant && variability != PerfData::V_Variable) { debug_only(warning("unexpected variability value: %d", variability)); - THROW_0(vmSymbols::java_lang_IllegalArgumentException()); + THROW_NULL(vmSymbols::java_lang_IllegalArgumentException()); } // check for valid units if (units != PerfData::U_String) { // only String based ByteArray objects are currently supported debug_only(warning("unexpected units value: %d", variability)); - THROW_0(vmSymbols::java_lang_IllegalArgumentException()); + THROW_NULL(vmSymbols::java_lang_IllegalArgumentException()); } int value_length; @@ -211,7 +211,7 @@ PERF_ENTRY(jobject, Perf_CreateByteArray(JNIEnv *env, jobject perf, // check that the counter name doesn't already exist if (PerfDataManager::exists((char*)name_utf)) { - THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "PerfByteArray name already exists"); + THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), "PerfByteArray name already exists"); } PerfByteArray* pbv = nullptr; diff --git a/src/hotspot/share/prims/unsafe.cpp b/src/hotspot/share/prims/unsafe.cpp index 1be157b2e44eb..239ae480030f5 100644 --- a/src/hotspot/share/prims/unsafe.cpp +++ b/src/hotspot/share/prims/unsafe.cpp @@ -552,7 +552,7 @@ UNSAFE_ENTRY(jobject, Unsafe_StaticFieldBase0(JNIEnv *env, jobject unsafe, jobje int modifiers = java_lang_reflect_Field::modifiers(reflected); if ((modifiers & JVM_ACC_STATIC) == 0) { - THROW_0(vmSymbols::java_lang_IllegalArgumentException()); + THROW_NULL(vmSymbols::java_lang_IllegalArgumentException()); } return JNIHandles::make_local(THREAD, mirror); diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index 43e47409c4cb6..6ee33a6107998 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -590,7 +590,7 @@ WB_ENTRY(jobject, WB_G1AuxiliaryMemoryUsage(JNIEnv* env)) Handle h = MemoryService::create_MemoryUsage_obj(usage, CHECK_NULL); return JNIHandles::make_local(THREAD, h()); } - THROW_MSG_0(vmSymbols::java_lang_UnsupportedOperationException(), "WB_G1AuxiliaryMemoryUsage: G1 GC is not enabled"); + THROW_MSG_NULL(vmSymbols::java_lang_UnsupportedOperationException(), "WB_G1AuxiliaryMemoryUsage: G1 GC is not enabled"); WB_END WB_ENTRY(jint, WB_G1ActiveMemoryNodeCount(JNIEnv* env, jobject o)) From 0d8ec42969fb60c140aaed7795ea1b9591915b8d Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Tue, 6 Aug 2024 06:59:11 +0000 Subject: [PATCH 202/353] 8337642: Remove unused APIs of GCPolicyCounters Reviewed-by: tschatzl --- .../share/gc/parallel/gcAdaptivePolicyCounters.hpp | 4 ---- .../gc/parallel/psGCAdaptivePolicyCounters.hpp | 4 ---- src/hotspot/share/gc/serial/defNewGeneration.cpp | 1 - src/hotspot/share/gc/shared/gcPolicyCounters.hpp | 13 ------------- 4 files changed, 22 deletions(-) diff --git a/src/hotspot/share/gc/parallel/gcAdaptivePolicyCounters.hpp b/src/hotspot/share/gc/parallel/gcAdaptivePolicyCounters.hpp index e83813c78f48f..e21d568955a38 100644 --- a/src/hotspot/share/gc/parallel/gcAdaptivePolicyCounters.hpp +++ b/src/hotspot/share/gc/parallel/gcAdaptivePolicyCounters.hpp @@ -223,10 +223,6 @@ class GCAdaptivePolicyCounters : public GCPolicyCounters { } void set_size_policy(AdaptiveSizePolicy* v) { _size_policy = v; } - - virtual GCPolicyCounters::Name kind() const { - return GCPolicyCounters::GCAdaptivePolicyCountersKind; - } }; #endif // SHARE_GC_PARALLEL_GCADAPTIVEPOLICYCOUNTERS_HPP diff --git a/src/hotspot/share/gc/parallel/psGCAdaptivePolicyCounters.hpp b/src/hotspot/share/gc/parallel/psGCAdaptivePolicyCounters.hpp index ad84eb4368b80..217cd7b9c5c36 100644 --- a/src/hotspot/share/gc/parallel/psGCAdaptivePolicyCounters.hpp +++ b/src/hotspot/share/gc/parallel/psGCAdaptivePolicyCounters.hpp @@ -180,10 +180,6 @@ class PSGCAdaptivePolicyCounters : public GCAdaptivePolicyCounters { // counter or from globals. This is distinguished from counters // that are updated via input parameters. void update_counters(); - - virtual GCPolicyCounters::Name kind() const { - return GCPolicyCounters::PSGCAdaptivePolicyCountersKind; - } }; #endif // SHARE_GC_PARALLEL_PSGCADAPTIVEPOLICYCOUNTERS_HPP diff --git a/src/hotspot/share/gc/serial/defNewGeneration.cpp b/src/hotspot/share/gc/serial/defNewGeneration.cpp index 715b82fd38d32..e93b97c85eb12 100644 --- a/src/hotspot/share/gc/serial/defNewGeneration.cpp +++ b/src/hotspot/share/gc/serial/defNewGeneration.cpp @@ -833,7 +833,6 @@ void DefNewGeneration::gc_epilogue(bool full) { assert(!GCLocker::is_active(), "We should not be executing here"); // update the generation and space performance counters update_counters(); - SerialHeap::heap()->counters()->update_counters(); } void DefNewGeneration::update_counters() { diff --git a/src/hotspot/share/gc/shared/gcPolicyCounters.hpp b/src/hotspot/share/gc/shared/gcPolicyCounters.hpp index a631664fcab93..9c7e5788a7eec 100644 --- a/src/hotspot/share/gc/shared/gcPolicyCounters.hpp +++ b/src/hotspot/share/gc/shared/gcPolicyCounters.hpp @@ -46,13 +46,6 @@ class GCPolicyCounters: public CHeapObj { const char* _name_space; public: - enum Name { - NONE, - GCPolicyCountersKind, - GCAdaptivePolicyCountersKind, - PSGCAdaptivePolicyCountersKind - }; - GCPolicyCounters(const char* name, int collectors, int generations); inline PerfVariable* tenuring_threshold() const { @@ -68,12 +61,6 @@ class GCPolicyCounters: public CHeapObj { } const char* name_space() const { return _name_space; } - - virtual void update_counters() {} - - virtual GCPolicyCounters::Name kind() const { - return GCPolicyCounters::GCPolicyCountersKind; - } }; #endif // SHARE_GC_SHARED_GCPOLICYCOUNTERS_HPP From f92c60e1a9968620cbc92b52aa546b57c09da487 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Tue, 6 Aug 2024 07:06:43 +0000 Subject: [PATCH 203/353] 8337810: ProblemList BasicDirectoryModel/LoaderThreadCount.java on Windows Reviewed-by: clanger --- test/jdk/ProblemList.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index f8bdfd26e8f79..bd29d64addf04 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -640,6 +640,7 @@ javax/sound/sampled/Clip/ClipFlushCrash.java 8308395 linux-x64 # jdk_swing javax/swing/plaf/basic/BasicTextUI/8001470/bug8001470.java 8233177 linux-all,windows-all +javax/swing/plaf/basic/BasicDirectoryModel/LoaderThreadCount.java 8333880 windows-all javax/swing/JFrame/MaximizeWindowTest.java 8321289 linux-all javax/swing/JWindow/ShapedAndTranslucentWindows/ShapedTranslucentPerPixelTranslucentGradient.java 8233582 linux-all From 958786b28ffb532b38746640b6fc11242f056ad9 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Tue, 6 Aug 2024 09:07:44 +0000 Subject: [PATCH 204/353] 8332522: SwitchBootstraps::mappedEnumLookup constructs unused array Reviewed-by: liach, redestad --- .../java/lang/runtime/SwitchBootstraps.java | 112 ++++++++++++------ .../bench/java/lang/runtime/SwitchEnum.java | 105 ++++++++++++++++ 2 files changed, 178 insertions(+), 39 deletions(-) create mode 100644 test/micro/org/openjdk/bench/java/lang/runtime/SwitchEnum.java diff --git a/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java b/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java index ccb33a0e4dbd1..43f7339c75a96 100644 --- a/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java +++ b/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java @@ -56,6 +56,7 @@ import static java.lang.invoke.MethodHandles.Lookup.ClassOption.NESTMATE; import static java.lang.invoke.MethodHandles.Lookup.ClassOption.STRONG; +import java.util.Arrays; import java.util.HashMap; import java.util.Map; import static java.util.Objects.requireNonNull; @@ -95,19 +96,13 @@ private SwitchBootstraps() {} private static final ClassDesc CD_Objects = ReferenceClassDescImpl.ofValidated("Ljava/util/Objects;"); private static class StaticHolders { - private static final MethodHandle NULL_CHECK; - private static final MethodHandle IS_ZERO; - private static final MethodHandle MAPPED_ENUM_LOOKUP; + private static final MethodHandle MAPPED_ENUM_SWITCH; static { try { - NULL_CHECK = LOOKUP.findStatic(Objects.class, "isNull", - MethodType.methodType(boolean.class, Object.class)); - IS_ZERO = LOOKUP.findStatic(SwitchBootstraps.class, "isZero", - MethodType.methodType(boolean.class, int.class)); - MAPPED_ENUM_LOOKUP = LOOKUP.findStatic(SwitchBootstraps.class, "mappedEnumLookup", - MethodType.methodType(int.class, Enum.class, MethodHandles.Lookup.class, - Class.class, EnumDesc[].class, EnumMap.class)); + MAPPED_ENUM_SWITCH = LOOKUP.findStatic(SwitchBootstraps.class, "mappedEnumSwitch", + MethodType.methodType(int.class, Enum.class, int.class, MethodHandles.Lookup.class, + Class.class, EnumDesc[].class, MappedEnumCache.class)); } catch (ReflectiveOperationException e) { throw new ExceptionInInitializerError(e); @@ -211,10 +206,6 @@ private static void verifyLabel(Object label, Class selectorType) { } } - private static boolean isZero(int value) { - return value == 0; - } - /** * Bootstrap method for linking an {@code invokedynamic} call site that * implements a {@code switch} on a target of an enum type. The static @@ -286,23 +277,27 @@ public static CallSite enumSwitch(MethodHandles.Lookup lookup, labels = labels.clone(); Class enumClass = invocationType.parameterType(0); - labels = Stream.of(labels).map(l -> convertEnumConstants(lookup, enumClass, l)).toArray(); + boolean constantsOnly = true; + int len = labels.length; + + for (int i = 0; i < len; i++) { + Object convertedLabel = + convertEnumConstants(lookup, enumClass, labels[i]); + labels[i] = convertedLabel; + if (constantsOnly) + constantsOnly = convertedLabel instanceof EnumDesc; + } MethodHandle target; - boolean constantsOnly = Stream.of(labels).allMatch(l -> enumClass.isAssignableFrom(EnumDesc.class)); if (labels.length > 0 && constantsOnly) { //If all labels are enum constants, construct an optimized handle for repeat index 0: //if (selector == null) return -1 //else if (idx == 0) return mappingArray[selector.ordinal()]; //mapping array created lazily //else return "typeSwitch(labels)" - MethodHandle body = - MethodHandles.guardWithTest(MethodHandles.dropArguments(StaticHolders.NULL_CHECK, 0, int.class), - MethodHandles.dropArguments(MethodHandles.constant(int.class, -1), 0, int.class, Object.class), - MethodHandles.guardWithTest(MethodHandles.dropArguments(StaticHolders.IS_ZERO, 1, Object.class), - generateTypeSwitch(lookup, invocationType.parameterType(0), labels), - MethodHandles.insertArguments(StaticHolders.MAPPED_ENUM_LOOKUP, 1, lookup, enumClass, labels, new EnumMap()))); - target = MethodHandles.permuteArguments(body, MethodType.methodType(int.class, Object.class, int.class), 1, 0); + EnumDesc[] enumDescLabels = + Arrays.copyOf(labels, labels.length, EnumDesc[].class); + target = MethodHandles.insertArguments(StaticHolders.MAPPED_ENUM_SWITCH, 2, lookup, enumClass, enumDescLabels, new MappedEnumCache()); } else { target = generateTypeSwitch(lookup, invocationType.parameterType(0), labels); } @@ -331,26 +326,63 @@ private static > Object convertEnumConstants(MethodHandles.Loo } } - private static > int mappedEnumLookup(T value, MethodHandles.Lookup lookup, Class enumClass, EnumDesc[] labels, EnumMap enumMap) { - if (enumMap.map == null) { - T[] constants = SharedSecrets.getJavaLangAccess().getEnumConstantsShared(enumClass); - int[] map = new int[constants.length]; - int ordinal = 0; - - for (T constant : constants) { - map[ordinal] = labels.length; + private static > int mappedEnumSwitch(T value, int restartIndex, MethodHandles.Lookup lookup, Class enumClass, EnumDesc[] labels, MappedEnumCache enumCache) throws Throwable { + if (value == null) { + return -1; + } - for (int i = 0; i < labels.length; i++) { - if (Objects.equals(labels[i].constantName(), constant.name())) { - map[ordinal] = i; - break; + if (restartIndex != 0) { + MethodHandle generatedSwitch = enumCache.generatedSwitch; + if (generatedSwitch == null) { + synchronized (enumCache) { + generatedSwitch = enumCache.generatedSwitch; + + if (generatedSwitch == null) { + generatedSwitch = + generateTypeSwitch(lookup, enumClass, labels) + .asType(MethodType.methodType(int.class, + Enum.class, + int.class)); + enumCache.generatedSwitch = generatedSwitch; } } + } + + return (int) generatedSwitch.invokeExact(value, restartIndex); + } + + int[] constantsMap = enumCache.constantsMap; + + if (constantsMap == null) { + synchronized (enumCache) { + constantsMap = enumCache.constantsMap; - ordinal++; + if (constantsMap == null) { + T[] constants = SharedSecrets.getJavaLangAccess() + .getEnumConstantsShared(enumClass); + constantsMap = new int[constants.length]; + int ordinal = 0; + + for (T constant : constants) { + constantsMap[ordinal] = labels.length; + + for (int i = 0; i < labels.length; i++) { + if (Objects.equals(labels[i].constantName(), + constant.name())) { + constantsMap[ordinal] = i; + break; + } + } + + ordinal++; + } + + enumCache.constantsMap = constantsMap; + } } } - return enumMap.map[value.ordinal()]; + + return constantsMap[value.ordinal()]; } private static final class ResolvedEnumLabels implements BiPredicate { @@ -395,9 +427,11 @@ public boolean test(Integer labelIndex, Object value) { } } - private static final class EnumMap { + private static final class MappedEnumCache { + @Stable + public int[] constantsMap; @Stable - public int[] map; + public MethodHandle generatedSwitch; } /* diff --git a/test/micro/org/openjdk/bench/java/lang/runtime/SwitchEnum.java b/test/micro/org/openjdk/bench/java/lang/runtime/SwitchEnum.java new file mode 100644 index 0000000000000..bfec0d321b29d --- /dev/null +++ b/test/micro/org/openjdk/bench/java/lang/runtime/SwitchEnum.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.bench.java.lang.runtime; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; + +import java.util.concurrent.TimeUnit; + +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Thread) +@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS) +@Measurement(iterations = 5, time = 2, timeUnit = TimeUnit.SECONDS) +@Fork(3) +public class SwitchEnum { + + public E[] inputs; + @Setup + public void setup() { + inputs = E.values(); + } + + @Benchmark + public int enumSwitchWithBootstrap() { + int sum = 0; + for (E e : inputs) { + sum += switch (e) { + case null -> -1; + case E0 -> 10; + case E1 -> 11; + case E2 -> 12; + case E3 -> 13; + case E4 -> 14; + case E5 -> 15; + case E6 -> 16; + case E7 -> 17; + case E8 -> 18; + case E9 -> 19; + default -> 17; + }; + } + return sum; + } + + @Benchmark + public int enumSwitchTraditional() { + int sum = 0; + for (E e : inputs) { + sum += switch (e) { + case E0 -> 10; + case E1 -> 11; + case E2 -> 12; + case E3 -> 13; + case E4 -> 14; + case E5 -> 15; + case E6 -> 16; + case E7 -> 17; + case E8 -> 18; + case E9 -> 19; + default -> 17; + }; + } + return sum; + } + + public static void main(String[] args) { + SwitchEnum s = new SwitchEnum(); + s.setup(); + System.out.println(s.enumSwitchWithBootstrap()); + System.out.println(s.enumSwitchTraditional()); + } + + enum E { + E0, E1, E2, E3, E4, E5, E6, E7, E8, E9; + } +} From f9b8a22062c7ad7ffb150394da6b3ab069785535 Mon Sep 17 00:00:00 2001 From: Erik Gahlin Date: Tue, 6 Aug 2024 09:28:12 +0000 Subject: [PATCH 205/353] 8337798: JFR: Remove jdk/jfr/api/consumer/recordingstream/TestOnEvent.java from ProblemList.txt Reviewed-by: mgronlun --- test/jdk/ProblemList.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index bd29d64addf04..3211f27b5c1e4 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -744,7 +744,6 @@ jdk/jfr/event/runtime/TestResidentSetSizeEvent.java 8309846 aix-ppc6 jdk/jfr/startupargs/TestStartName.java 8214685 windows-x64 jdk/jfr/startupargs/TestStartDuration.java 8214685 windows-x64 jdk/jfr/jvm/TestWaste.java 8282427 generic-all -jdk/jfr/api/consumer/recordingstream/TestOnEvent.java 8255404 linux-x64,linux-aarch64 ############################################################################ From a117945d5a704781944ae15c852c31d090f03adb Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Tue, 6 Aug 2024 09:37:21 +0000 Subject: [PATCH 206/353] 8337344: Redundant javadoc at RasterPrinterJob.isCancelled Reviewed-by: aivanov, prr --- .../share/classes/sun/print/RasterPrinterJob.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java b/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java index 0dfa5e42d9a89..82f47824bfae7 100644 --- a/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java +++ b/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java @@ -2474,11 +2474,7 @@ public void cancel() { } } - /** - * Returns true is a print job is ongoing but will - * be cancelled and the next opportunity. false is - * returned otherwise. - */ + @Override public boolean isCancelled() { boolean cancelled = false; From ef909bdf7f08dfd67bac2665aa85f86c0e303db9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20Gr=C3=B6nlund?= Date: Tue, 6 Aug 2024 11:32:24 +0000 Subject: [PATCH 207/353] 8335121: Native memory leak when not recording any events Reviewed-by: egahlin, shade --- .../share/jfr/recorder/service/jfrRecorderService.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp b/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp index fc2043a4d921d..418b774996e4c 100644 --- a/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp +++ b/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp @@ -639,11 +639,7 @@ static void write_thread_local_buffer(JfrChunkWriter& chunkwriter, Thread* t) { size_t JfrRecorderService::flush() { size_t total_elements = flush_metadata(_chunkwriter); - const size_t storage_elements = flush_storage(_storage, _chunkwriter); - if (0 == storage_elements) { - return total_elements; - } - total_elements += storage_elements; + total_elements += flush_storage(_storage, _chunkwriter); if (_string_pool.is_modified()) { total_elements += flush_stringpool(_string_pool, _chunkwriter); } From 1348ece6df7b460501931533c238e819995a2086 Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Tue, 6 Aug 2024 11:34:57 +0000 Subject: [PATCH 208/353] 8332120: Potential compilation failure in istream.cpp:205 - loss of data on conversion Reviewed-by: dholmes, iklam --- src/hotspot/share/utilities/istream.cpp | 8 +------- src/hotspot/share/utilities/istream.hpp | 2 -- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/src/hotspot/share/utilities/istream.cpp b/src/hotspot/share/utilities/istream.cpp index cb082128c62ca..55fa443af69e9 100644 --- a/src/hotspot/share/utilities/istream.cpp +++ b/src/hotspot/share/utilities/istream.cpp @@ -78,7 +78,6 @@ bool inputStream::next() { void inputStream::set_done() { size_t end = _beg = _end = _content_end; _next = end + NEXT_PHANTOM; - _line_ending = 0; assert(definitely_done(), ""); } @@ -94,7 +93,6 @@ void inputStream::set_error(bool error_condition) { void inputStream::clear_buffer() { _content_end = _beg = _end = _next = 0; - _line_ending = 0; } const char* inputStream::next_content(size_t& next_content_length) const { @@ -146,7 +144,6 @@ bool inputStream::fill_buffer() { else { COV(FIB_L); } if (last_partial) { assert(have_current_line(), ""); - _line_ending = 0; _content_end -= 1; // reverse insertion of phantom newline assert(_next == _content_end + NEXT_PHANTOM, ""); assert(have_current_line(), ""); @@ -224,7 +221,6 @@ void inputStream::set_buffer_content(size_t content_start, if (nl == nullptr) { COV(SBC_N); _next = _end = content_end; - _line_ending = 0; assert(need_to_read(), ""); } else { COV(SBC_L); @@ -247,7 +243,6 @@ void inputStream::set_buffer_content(size_t content_start, // accept '\r' before '\n'. } _end = end; // now this->current_line() points to buf[beg..end] - _line_ending = (int)(_next - end); assert(have_current_line(), ""); assert(current_line() == &_buffer[_beg], ""); assert(current_line_length() == _end - _beg, ""); @@ -299,7 +294,7 @@ void inputStream::dump(const char* what) { bool ntr = (_next == _end), hcl = (_beg < _content_end && _end < _next), ddn = (_beg == _content_end && _next > _content_end); - tty->print_cr("%s%sistream %s%s%s%s%s [%d<%.*s>%d/%d..%d] LE=%d," + tty->print_cr("%s%sistream %s%s%s%s%s [%d<%.*s>%d/%d..%d] " " B=%llx%s[%d], LN=%d, CH=%d", what ? what : "", what ? ": " : "", _buffer == nullptr ? "U" : "", @@ -312,7 +307,6 @@ void inputStream::dump(const char* what) { diff < 0 ? 0 : diff > 10 ? 10 : diff, _buffer ? &_buffer[_beg] : "", (int)_end, (int)_next, (int)_content_end, - _line_ending, (unsigned long long)(intptr_t)_buffer, _buffer == _small_buffer ? "(SB)" : "", (int)_buffer_size, diff --git a/src/hotspot/share/utilities/istream.hpp b/src/hotspot/share/utilities/istream.hpp index b6a58055b937c..dd12028185956 100644 --- a/src/hotspot/share/utilities/istream.hpp +++ b/src/hotspot/share/utilities/istream.hpp @@ -96,7 +96,6 @@ class inputStream : public CHeapObjBase { Input* _input; // where the input comes from or else nullptr IState _input_state; // one of {NTR,EOF,ERR}_STATE - char _line_ending; // one of {0,1,2} for "", "\n", "\r\n" char* _buffer; // scratch buffer holding at least the current line size_t _buffer_size; // allocated size of buffer size_t _content_end; // offset to end of valid contents of buffer @@ -225,7 +224,6 @@ class inputStream : public CHeapObjBase { inputStream() : _input(nullptr), _input_state(IState::NTR_STATE), - _line_ending(0), _buffer(&_small_buffer[0]), _buffer_size(sizeof(_small_buffer)), _content_end(0), From ab509f1b98329b1624a3111e226b640ee76f5969 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Tue, 6 Aug 2024 13:22:55 +0000 Subject: [PATCH 209/353] 8337654: Relocate uncommon trap stub from SharedRuntime to OptoRuntime Reviewed-by: kvn, vlivanov, fyang --- src/hotspot/cpu/aarch64/runtime_aarch64.cpp | 343 ++++++++++++++++ .../cpu/aarch64/sharedRuntime_aarch64.cpp | 349 ---------------- src/hotspot/cpu/arm/runtime_arm.cpp | 141 ++++++- src/hotspot/cpu/arm/sharedRuntime_arm.cpp | 141 ------- src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp | 4 +- src/hotspot/cpu/riscv/runtime_riscv.cpp | 382 ++++++++++++++++++ src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp | 343 ---------------- src/hotspot/cpu/s390/sharedRuntime_s390.cpp | 4 +- src/hotspot/cpu/x86/runtime_x86_32.cpp | 174 ++++++++ src/hotspot/cpu/x86/runtime_x86_64.cpp | 327 ++++++++++++++- src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp | 177 -------- src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp | 327 --------------- src/hotspot/share/opto/graphKit.cpp | 2 +- src/hotspot/share/opto/lcm.cpp | 2 +- src/hotspot/share/opto/library_call.cpp | 2 +- src/hotspot/share/opto/loopnode.cpp | 2 +- src/hotspot/share/opto/matcher.cpp | 2 +- src/hotspot/share/opto/runtime.cpp | 4 +- src/hotspot/share/opto/runtime.hpp | 4 + src/hotspot/share/opto/stringopts.cpp | 2 +- src/hotspot/share/runtime/sharedRuntime.cpp | 8 - src/hotspot/share/runtime/sharedRuntime.hpp | 9 - 22 files changed, 1378 insertions(+), 1371 deletions(-) create mode 100644 src/hotspot/cpu/riscv/runtime_riscv.cpp diff --git a/src/hotspot/cpu/aarch64/runtime_aarch64.cpp b/src/hotspot/cpu/aarch64/runtime_aarch64.cpp index 61d27e3224248..09bb370f210f7 100644 --- a/src/hotspot/cpu/aarch64/runtime_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/runtime_aarch64.cpp @@ -36,6 +36,349 @@ #include "runtime/vframeArray.hpp" #include "utilities/globalDefinitions.hpp" #include "vmreg_aarch64.inline.hpp" + +class SimpleRuntimeFrame { + + public: + + // Most of the runtime stubs have this simple frame layout. + // This class exists to make the layout shared in one place. + // Offsets are for compiler stack slots, which are jints. + enum layout { + // The frame sender code expects that rbp will be in the "natural" place and + // will override any oopMap setting for it. We must therefore force the layout + // so that it agrees with the frame sender code. + // we don't expect any arg reg save area so aarch64 asserts that + // frame::arg_reg_save_area_bytes == 0 + rfp_off = 0, + rfp_off2, + return_off, return_off2, + framesize + }; +}; + +#define __ masm-> + +//------------------------------generate_uncommon_trap_blob-------------------- +void OptoRuntime::generate_uncommon_trap_blob() { + // Allocate space for the code + ResourceMark rm; + // Setup code generation tools + CodeBuffer buffer("uncommon_trap_blob", 2048, 1024); + MacroAssembler* masm = new MacroAssembler(&buffer); + + assert(SimpleRuntimeFrame::framesize % 4 == 0, "sp not 16-byte aligned"); + + address start = __ pc(); + + // Push self-frame. We get here with a return address in LR + // and sp should be 16 byte aligned + // push rfp and retaddr by hand + __ protect_return_address(); + __ stp(rfp, lr, Address(__ pre(sp, -2 * wordSize))); + // we don't expect an arg reg save area +#ifndef PRODUCT + assert(frame::arg_reg_save_area_bytes == 0, "not expecting frame reg save area"); +#endif + // compiler left unloaded_class_index in j_rarg0 move to where the + // runtime expects it. + if (c_rarg1 != j_rarg0) { + __ movw(c_rarg1, j_rarg0); + } + + // we need to set the past SP to the stack pointer of the stub frame + // and the pc to the address where this runtime call will return + // although actually any pc in this code blob will do). + Label retaddr; + __ set_last_Java_frame(sp, noreg, retaddr, rscratch1); + + // Call C code. Need thread but NOT official VM entry + // crud. We cannot block on this call, no GC can happen. Call should + // capture callee-saved registers as well as return values. + // + // UnrollBlock* uncommon_trap(JavaThread* thread, jint unloaded_class_index); + // + // n.b. 2 gp args, 0 fp args, integral return type + + __ mov(c_rarg0, rthread); + __ movw(c_rarg2, (unsigned)Deoptimization::Unpack_uncommon_trap); + __ lea(rscratch1, + RuntimeAddress(CAST_FROM_FN_PTR(address, + Deoptimization::uncommon_trap))); + __ blr(rscratch1); + __ bind(retaddr); + + // Set an oopmap for the call site + OopMapSet* oop_maps = new OopMapSet(); + OopMap* map = new OopMap(SimpleRuntimeFrame::framesize, 0); + + // location of rfp is known implicitly by the frame sender code + + oop_maps->add_gc_map(__ pc() - start, map); + + __ reset_last_Java_frame(false); + + // move UnrollBlock* into r4 + __ mov(r4, r0); + +#ifdef ASSERT + { Label L; + __ ldrw(rscratch1, Address(r4, Deoptimization::UnrollBlock::unpack_kind_offset())); + __ cmpw(rscratch1, (unsigned)Deoptimization::Unpack_uncommon_trap); + __ br(Assembler::EQ, L); + __ stop("OptoRuntime::generate_uncommon_trap_blob: expected Unpack_uncommon_trap"); + __ bind(L); + } +#endif + + // Pop all the frames we must move/replace. + // + // Frame picture (youngest to oldest) + // 1: self-frame (no frame link) + // 2: deopting frame (no frame link) + // 3: caller of deopting frame (could be compiled/interpreted). + + // Pop self-frame. We have no frame, and must rely only on r0 and sp. + __ add(sp, sp, (SimpleRuntimeFrame::framesize) << LogBytesPerInt); // Epilog! + + // Pop deoptimized frame (int) + __ ldrw(r2, Address(r4, + Deoptimization::UnrollBlock:: + size_of_deoptimized_frame_offset())); + __ sub(r2, r2, 2 * wordSize); + __ add(sp, sp, r2); + __ ldp(rfp, zr, __ post(sp, 2 * wordSize)); + +#ifdef ASSERT + // Compilers generate code that bang the stack by as much as the + // interpreter would need. So this stack banging should never + // trigger a fault. Verify that it does not on non product builds. + __ ldrw(r1, Address(r4, + Deoptimization::UnrollBlock:: + total_frame_sizes_offset())); + __ bang_stack_size(r1, r2); +#endif + + // Load address of array of frame pcs into r2 (address*) + __ ldr(r2, Address(r4, + Deoptimization::UnrollBlock::frame_pcs_offset())); + + // Load address of array of frame sizes into r5 (intptr_t*) + __ ldr(r5, Address(r4, + Deoptimization::UnrollBlock:: + frame_sizes_offset())); + + // Counter + __ ldrw(r3, Address(r4, + Deoptimization::UnrollBlock:: + number_of_frames_offset())); // (int) + + // Now adjust the caller's stack to make up for the extra locals but + // record the original sp so that we can save it in the skeletal + // interpreter frame and the stack walking of interpreter_sender + // will get the unextended sp value and not the "real" sp value. + + const Register sender_sp = r8; + + __ mov(sender_sp, sp); + __ ldrw(r1, Address(r4, + Deoptimization::UnrollBlock:: + caller_adjustment_offset())); // (int) + __ sub(sp, sp, r1); + + // Push interpreter frames in a loop + Label loop; + __ bind(loop); + __ ldr(r1, Address(r5, 0)); // Load frame size + __ sub(r1, r1, 2 * wordSize); // We'll push pc and rfp by hand + __ ldr(lr, Address(r2, 0)); // Save return address + __ enter(); // and old rfp & set new rfp + __ sub(sp, sp, r1); // Prolog + __ str(sender_sp, Address(rfp, frame::interpreter_frame_sender_sp_offset * wordSize)); // Make it walkable + // This value is corrected by layout_activation_impl + __ str(zr, Address(rfp, frame::interpreter_frame_last_sp_offset * wordSize)); + __ mov(sender_sp, sp); // Pass sender_sp to next frame + __ add(r5, r5, wordSize); // Bump array pointer (sizes) + __ add(r2, r2, wordSize); // Bump array pointer (pcs) + __ subsw(r3, r3, 1); // Decrement counter + __ br(Assembler::GT, loop); + __ ldr(lr, Address(r2, 0)); // save final return address + // Re-push self-frame + __ enter(); // & old rfp & set new rfp + + // Use rfp because the frames look interpreted now + // Save "the_pc" since it cannot easily be retrieved using the last_java_SP after we aligned SP. + // Don't need the precise return PC here, just precise enough to point into this code blob. + address the_pc = __ pc(); + __ set_last_Java_frame(sp, rfp, the_pc, rscratch1); + + // Call C code. Need thread but NOT official VM entry + // crud. We cannot block on this call, no GC can happen. Call should + // restore return values to their stack-slots with the new SP. + // Thread is in rdi already. + // + // BasicType unpack_frames(JavaThread* thread, int exec_mode); + // + // n.b. 2 gp args, 0 fp args, integral return type + + // sp should already be aligned + __ mov(c_rarg0, rthread); + __ movw(c_rarg1, (unsigned)Deoptimization::Unpack_uncommon_trap); + __ lea(rscratch1, RuntimeAddress(CAST_FROM_FN_PTR(address, Deoptimization::unpack_frames))); + __ blr(rscratch1); + + // Set an oopmap for the call site + // Use the same PC we used for the last java frame + oop_maps->add_gc_map(the_pc - start, new OopMap(SimpleRuntimeFrame::framesize, 0)); + + // Clear fp AND pc + __ reset_last_Java_frame(true); + + // Pop self-frame. + __ leave(); // Epilog + + // Jump to interpreter + __ ret(lr); + + // Make sure all code is generated + masm->flush(); + + _uncommon_trap_blob = UncommonTrapBlob::create(&buffer, oop_maps, + SimpleRuntimeFrame::framesize >> 1); +} + +//------------------------------generate_exception_blob--------------------------- +// creates exception blob at the end +// Using exception blob, this code is jumped from a compiled method. +// (see emit_exception_handler in aarch64.ad file) +// +// Given an exception pc at a call we call into the runtime for the +// handler in this method. This handler might merely restore state +// (i.e. callee save registers) unwind the frame and jump to the +// exception handler for the nmethod if there is no Java level handler +// for the nmethod. +// +// This code is entered with a jmp. +// +// Arguments: +// r0: exception oop +// r3: exception pc +// +// Results: +// r0: exception oop +// r3: exception pc in caller or ??? +// destination: exception handler of caller +// +// Note: the exception pc MUST be at a call (precise debug information) +// Registers r0, r3, r2, r4, r5, r8-r11 are not callee saved. +// + +void OptoRuntime::generate_exception_blob() { + assert(!OptoRuntime::is_callee_saved_register(R3_num), ""); + assert(!OptoRuntime::is_callee_saved_register(R0_num), ""); + assert(!OptoRuntime::is_callee_saved_register(R2_num), ""); + + assert(SimpleRuntimeFrame::framesize % 4 == 0, "sp not 16-byte aligned"); + + // Allocate space for the code + ResourceMark rm; + // Setup code generation tools + CodeBuffer buffer("exception_blob", 2048, 1024); + MacroAssembler* masm = new MacroAssembler(&buffer); + + // TODO check various assumptions made here + // + // make sure we do so before running this + + address start = __ pc(); + + // push rfp and retaddr by hand + // Exception pc is 'return address' for stack walker + __ protect_return_address(); + __ stp(rfp, lr, Address(__ pre(sp, -2 * wordSize))); + // there are no callee save registers and we don't expect an + // arg reg save area +#ifndef PRODUCT + assert(frame::arg_reg_save_area_bytes == 0, "not expecting frame reg save area"); +#endif + // Store exception in Thread object. We cannot pass any arguments to the + // handle_exception call, since we do not want to make any assumption + // about the size of the frame where the exception happened in. + __ str(r0, Address(rthread, JavaThread::exception_oop_offset())); + __ str(r3, Address(rthread, JavaThread::exception_pc_offset())); + + // This call does all the hard work. It checks if an exception handler + // exists in the method. + // If so, it returns the handler address. + // If not, it prepares for stack-unwinding, restoring the callee-save + // registers of the frame being removed. + // + // address OptoRuntime::handle_exception_C(JavaThread* thread) + // + // n.b. 1 gp arg, 0 fp args, integral return type + + // the stack should always be aligned + address the_pc = __ pc(); + __ set_last_Java_frame(sp, noreg, the_pc, rscratch1); + __ mov(c_rarg0, rthread); + __ lea(rscratch1, RuntimeAddress(CAST_FROM_FN_PTR(address, OptoRuntime::handle_exception_C))); + __ blr(rscratch1); + // handle_exception_C is a special VM call which does not require an explicit + // instruction sync afterwards. + + // May jump to SVE compiled code + __ reinitialize_ptrue(); + + // Set an oopmap for the call site. This oopmap will only be used if we + // are unwinding the stack. Hence, all locations will be dead. + // Callee-saved registers will be the same as the frame above (i.e., + // handle_exception_stub), since they were restored when we got the + // exception. + + OopMapSet* oop_maps = new OopMapSet(); + + oop_maps->add_gc_map(the_pc - start, new OopMap(SimpleRuntimeFrame::framesize, 0)); + + __ reset_last_Java_frame(false); + + // Restore callee-saved registers + + // rfp is an implicitly saved callee saved register (i.e. the calling + // convention will save restore it in prolog/epilog) Other than that + // there are no callee save registers now that adapter frames are gone. + // and we dont' expect an arg reg save area + __ ldp(rfp, r3, Address(__ post(sp, 2 * wordSize))); + __ authenticate_return_address(r3); + + // r0: exception handler + + // We have a handler in r0 (could be deopt blob). + __ mov(r8, r0); + + // Get the exception oop + __ ldr(r0, Address(rthread, JavaThread::exception_oop_offset())); + // Get the exception pc in case we are deoptimized + __ ldr(r4, Address(rthread, JavaThread::exception_pc_offset())); +#ifdef ASSERT + __ str(zr, Address(rthread, JavaThread::exception_handler_pc_offset())); + __ str(zr, Address(rthread, JavaThread::exception_pc_offset())); #endif + // Clear the exception oop so GC no longer processes it as a root. + __ str(zr, Address(rthread, JavaThread::exception_oop_offset())); + + // r0: exception oop + // r8: exception handler + // r4: exception pc + // Jump to handler + + __ br(r8); + + // Make sure all code is generated + masm->flush(); + + // Set exception blob + _exception_blob = ExceptionBlob::create(&buffer, oop_maps, SimpleRuntimeFrame::framesize >> 1); +} +#endif // COMPILER2 diff --git a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp index bb2554e65ce83..65c026b95abbd 100644 --- a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp @@ -68,26 +68,6 @@ const int StackAlignmentInSlots = StackAlignmentInBytes / VMRegImpl::stack_slot_size; -class SimpleRuntimeFrame { - - public: - - // Most of the runtime stubs have this simple frame layout. - // This class exists to make the layout shared in one place. - // Offsets are for compiler stack slots, which are jints. - enum layout { - // The frame sender code expects that rbp will be in the "natural" place and - // will override any oopMap setting for it. We must therefore force the layout - // so that it agrees with the frame sender code. - // we don't expect any arg reg save area so aarch64 asserts that - // frame::arg_reg_save_area_bytes == 0 - rfp_off = 0, - rfp_off2, - return_off, return_off2, - framesize - }; -}; - // FIXME -- this is used by C1 class RegisterSaver { const bool _save_vectors; @@ -2581,197 +2561,6 @@ uint SharedRuntime::out_preserve_stack_slots() { return 0; } -#ifdef COMPILER2 -//------------------------------generate_uncommon_trap_blob-------------------- -void SharedRuntime::generate_uncommon_trap_blob() { - // Allocate space for the code - ResourceMark rm; - // Setup code generation tools - CodeBuffer buffer("uncommon_trap_blob", 2048, 1024); - MacroAssembler* masm = new MacroAssembler(&buffer); - - assert(SimpleRuntimeFrame::framesize % 4 == 0, "sp not 16-byte aligned"); - - address start = __ pc(); - - // Push self-frame. We get here with a return address in LR - // and sp should be 16 byte aligned - // push rfp and retaddr by hand - __ protect_return_address(); - __ stp(rfp, lr, Address(__ pre(sp, -2 * wordSize))); - // we don't expect an arg reg save area -#ifndef PRODUCT - assert(frame::arg_reg_save_area_bytes == 0, "not expecting frame reg save area"); -#endif - // compiler left unloaded_class_index in j_rarg0 move to where the - // runtime expects it. - if (c_rarg1 != j_rarg0) { - __ movw(c_rarg1, j_rarg0); - } - - // we need to set the past SP to the stack pointer of the stub frame - // and the pc to the address where this runtime call will return - // although actually any pc in this code blob will do). - Label retaddr; - __ set_last_Java_frame(sp, noreg, retaddr, rscratch1); - - // Call C code. Need thread but NOT official VM entry - // crud. We cannot block on this call, no GC can happen. Call should - // capture callee-saved registers as well as return values. - // Thread is in rdi already. - // - // UnrollBlock* uncommon_trap(JavaThread* thread, jint unloaded_class_index); - // - // n.b. 2 gp args, 0 fp args, integral return type - - __ mov(c_rarg0, rthread); - __ movw(c_rarg2, (unsigned)Deoptimization::Unpack_uncommon_trap); - __ lea(rscratch1, - RuntimeAddress(CAST_FROM_FN_PTR(address, - Deoptimization::uncommon_trap))); - __ blr(rscratch1); - __ bind(retaddr); - - // Set an oopmap for the call site - OopMapSet* oop_maps = new OopMapSet(); - OopMap* map = new OopMap(SimpleRuntimeFrame::framesize, 0); - - // location of rfp is known implicitly by the frame sender code - - oop_maps->add_gc_map(__ pc() - start, map); - - __ reset_last_Java_frame(false); - - // move UnrollBlock* into r4 - __ mov(r4, r0); - -#ifdef ASSERT - { Label L; - __ ldrw(rscratch1, Address(r4, Deoptimization::UnrollBlock::unpack_kind_offset())); - __ cmpw(rscratch1, (unsigned)Deoptimization::Unpack_uncommon_trap); - __ br(Assembler::EQ, L); - __ stop("SharedRuntime::generate_uncommon_trap_blob: expected Unpack_uncommon_trap"); - __ bind(L); - } -#endif - - // Pop all the frames we must move/replace. - // - // Frame picture (youngest to oldest) - // 1: self-frame (no frame link) - // 2: deopting frame (no frame link) - // 3: caller of deopting frame (could be compiled/interpreted). - - // Pop self-frame. We have no frame, and must rely only on r0 and sp. - __ add(sp, sp, (SimpleRuntimeFrame::framesize) << LogBytesPerInt); // Epilog! - - // Pop deoptimized frame (int) - __ ldrw(r2, Address(r4, - Deoptimization::UnrollBlock:: - size_of_deoptimized_frame_offset())); - __ sub(r2, r2, 2 * wordSize); - __ add(sp, sp, r2); - __ ldp(rfp, zr, __ post(sp, 2 * wordSize)); - -#ifdef ASSERT - // Compilers generate code that bang the stack by as much as the - // interpreter would need. So this stack banging should never - // trigger a fault. Verify that it does not on non product builds. - __ ldrw(r1, Address(r4, - Deoptimization::UnrollBlock:: - total_frame_sizes_offset())); - __ bang_stack_size(r1, r2); -#endif - - // Load address of array of frame pcs into r2 (address*) - __ ldr(r2, Address(r4, - Deoptimization::UnrollBlock::frame_pcs_offset())); - - // Load address of array of frame sizes into r5 (intptr_t*) - __ ldr(r5, Address(r4, - Deoptimization::UnrollBlock:: - frame_sizes_offset())); - - // Counter - __ ldrw(r3, Address(r4, - Deoptimization::UnrollBlock:: - number_of_frames_offset())); // (int) - - // Now adjust the caller's stack to make up for the extra locals but - // record the original sp so that we can save it in the skeletal - // interpreter frame and the stack walking of interpreter_sender - // will get the unextended sp value and not the "real" sp value. - - const Register sender_sp = r8; - - __ mov(sender_sp, sp); - __ ldrw(r1, Address(r4, - Deoptimization::UnrollBlock:: - caller_adjustment_offset())); // (int) - __ sub(sp, sp, r1); - - // Push interpreter frames in a loop - Label loop; - __ bind(loop); - __ ldr(r1, Address(r5, 0)); // Load frame size - __ sub(r1, r1, 2 * wordSize); // We'll push pc and rfp by hand - __ ldr(lr, Address(r2, 0)); // Save return address - __ enter(); // and old rfp & set new rfp - __ sub(sp, sp, r1); // Prolog - __ str(sender_sp, Address(rfp, frame::interpreter_frame_sender_sp_offset * wordSize)); // Make it walkable - // This value is corrected by layout_activation_impl - __ str(zr, Address(rfp, frame::interpreter_frame_last_sp_offset * wordSize)); - __ mov(sender_sp, sp); // Pass sender_sp to next frame - __ add(r5, r5, wordSize); // Bump array pointer (sizes) - __ add(r2, r2, wordSize); // Bump array pointer (pcs) - __ subsw(r3, r3, 1); // Decrement counter - __ br(Assembler::GT, loop); - __ ldr(lr, Address(r2, 0)); // save final return address - // Re-push self-frame - __ enter(); // & old rfp & set new rfp - - // Use rfp because the frames look interpreted now - // Save "the_pc" since it cannot easily be retrieved using the last_java_SP after we aligned SP. - // Don't need the precise return PC here, just precise enough to point into this code blob. - address the_pc = __ pc(); - __ set_last_Java_frame(sp, rfp, the_pc, rscratch1); - - // Call C code. Need thread but NOT official VM entry - // crud. We cannot block on this call, no GC can happen. Call should - // restore return values to their stack-slots with the new SP. - // Thread is in rdi already. - // - // BasicType unpack_frames(JavaThread* thread, int exec_mode); - // - // n.b. 2 gp args, 0 fp args, integral return type - - // sp should already be aligned - __ mov(c_rarg0, rthread); - __ movw(c_rarg1, (unsigned)Deoptimization::Unpack_uncommon_trap); - __ lea(rscratch1, RuntimeAddress(CAST_FROM_FN_PTR(address, Deoptimization::unpack_frames))); - __ blr(rscratch1); - - // Set an oopmap for the call site - // Use the same PC we used for the last java frame - oop_maps->add_gc_map(the_pc - start, new OopMap(SimpleRuntimeFrame::framesize, 0)); - - // Clear fp AND pc - __ reset_last_Java_frame(true); - - // Pop self-frame. - __ leave(); // Epilog - - // Jump to interpreter - __ ret(lr); - - // Make sure all code is generated - masm->flush(); - - _uncommon_trap_blob = UncommonTrapBlob::create(&buffer, oop_maps, - SimpleRuntimeFrame::framesize >> 1); -} -#endif // COMPILER2 - //------------------------------generate_handler_blob------ // @@ -2983,141 +2772,3 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const cha // frame_size_words or bytes?? return RuntimeStub::new_runtime_stub(name, &buffer, frame_complete, frame_size_in_words, oop_maps, true); } - -#ifdef COMPILER2 -// This is here instead of runtime_aarch64_64.cpp because it uses SimpleRuntimeFrame -// -//------------------------------generate_exception_blob--------------------------- -// creates exception blob at the end -// Using exception blob, this code is jumped from a compiled method. -// (see emit_exception_handler in x86_64.ad file) -// -// Given an exception pc at a call we call into the runtime for the -// handler in this method. This handler might merely restore state -// (i.e. callee save registers) unwind the frame and jump to the -// exception handler for the nmethod if there is no Java level handler -// for the nmethod. -// -// This code is entered with a jmp. -// -// Arguments: -// r0: exception oop -// r3: exception pc -// -// Results: -// r0: exception oop -// r3: exception pc in caller or ??? -// destination: exception handler of caller -// -// Note: the exception pc MUST be at a call (precise debug information) -// Registers r0, r3, r2, r4, r5, r8-r11 are not callee saved. -// - -void OptoRuntime::generate_exception_blob() { - assert(!OptoRuntime::is_callee_saved_register(R3_num), ""); - assert(!OptoRuntime::is_callee_saved_register(R0_num), ""); - assert(!OptoRuntime::is_callee_saved_register(R2_num), ""); - - assert(SimpleRuntimeFrame::framesize % 4 == 0, "sp not 16-byte aligned"); - - // Allocate space for the code - ResourceMark rm; - // Setup code generation tools - CodeBuffer buffer("exception_blob", 2048, 1024); - MacroAssembler* masm = new MacroAssembler(&buffer); - - // TODO check various assumptions made here - // - // make sure we do so before running this - - address start = __ pc(); - - // push rfp and retaddr by hand - // Exception pc is 'return address' for stack walker - __ protect_return_address(); - __ stp(rfp, lr, Address(__ pre(sp, -2 * wordSize))); - // there are no callee save registers and we don't expect an - // arg reg save area -#ifndef PRODUCT - assert(frame::arg_reg_save_area_bytes == 0, "not expecting frame reg save area"); -#endif - // Store exception in Thread object. We cannot pass any arguments to the - // handle_exception call, since we do not want to make any assumption - // about the size of the frame where the exception happened in. - __ str(r0, Address(rthread, JavaThread::exception_oop_offset())); - __ str(r3, Address(rthread, JavaThread::exception_pc_offset())); - - // This call does all the hard work. It checks if an exception handler - // exists in the method. - // If so, it returns the handler address. - // If not, it prepares for stack-unwinding, restoring the callee-save - // registers of the frame being removed. - // - // address OptoRuntime::handle_exception_C(JavaThread* thread) - // - // n.b. 1 gp arg, 0 fp args, integral return type - - // the stack should always be aligned - address the_pc = __ pc(); - __ set_last_Java_frame(sp, noreg, the_pc, rscratch1); - __ mov(c_rarg0, rthread); - __ lea(rscratch1, RuntimeAddress(CAST_FROM_FN_PTR(address, OptoRuntime::handle_exception_C))); - __ blr(rscratch1); - // handle_exception_C is a special VM call which does not require an explicit - // instruction sync afterwards. - - // May jump to SVE compiled code - __ reinitialize_ptrue(); - - // Set an oopmap for the call site. This oopmap will only be used if we - // are unwinding the stack. Hence, all locations will be dead. - // Callee-saved registers will be the same as the frame above (i.e., - // handle_exception_stub), since they were restored when we got the - // exception. - - OopMapSet* oop_maps = new OopMapSet(); - - oop_maps->add_gc_map(the_pc - start, new OopMap(SimpleRuntimeFrame::framesize, 0)); - - __ reset_last_Java_frame(false); - - // Restore callee-saved registers - - // rfp is an implicitly saved callee saved register (i.e. the calling - // convention will save restore it in prolog/epilog) Other than that - // there are no callee save registers now that adapter frames are gone. - // and we dont' expect an arg reg save area - __ ldp(rfp, r3, Address(__ post(sp, 2 * wordSize))); - __ authenticate_return_address(r3); - - // r0: exception handler - - // We have a handler in r0 (could be deopt blob). - __ mov(r8, r0); - - // Get the exception oop - __ ldr(r0, Address(rthread, JavaThread::exception_oop_offset())); - // Get the exception pc in case we are deoptimized - __ ldr(r4, Address(rthread, JavaThread::exception_pc_offset())); -#ifdef ASSERT - __ str(zr, Address(rthread, JavaThread::exception_handler_pc_offset())); - __ str(zr, Address(rthread, JavaThread::exception_pc_offset())); -#endif - // Clear the exception oop so GC no longer processes it as a root. - __ str(zr, Address(rthread, JavaThread::exception_oop_offset())); - - // r0: exception oop - // r8: exception handler - // r4: exception pc - // Jump to handler - - __ br(r8); - - // Make sure all code is generated - masm->flush(); - - // Set exception blob - _exception_blob = ExceptionBlob::create(&buffer, oop_maps, SimpleRuntimeFrame::framesize >> 1); -} - -#endif // COMPILER2 diff --git a/src/hotspot/cpu/arm/runtime_arm.cpp b/src/hotspot/cpu/arm/runtime_arm.cpp index 94a9ef553c75e..6f6c0c17e000d 100644 --- a/src/hotspot/cpu/arm/runtime_arm.cpp +++ b/src/hotspot/cpu/arm/runtime_arm.cpp @@ -37,10 +37,146 @@ #include "runtime/vframeArray.hpp" #include "utilities/globalDefinitions.hpp" #include "vmreg_arm.inline.hpp" -#endif #define __ masm-> +//------------------------------generate_uncommon_trap_blob-------------------- +// Ought to generate an ideal graph & compile, but here's some ASM +// instead. +void OptoRuntime::generate_uncommon_trap_blob() { + // allocate space for the code + ResourceMark rm; + + // setup code generation tools +#ifdef _LP64 + CodeBuffer buffer("uncommon_trap_blob", 2700, 512); +#else + // Measured 8/7/03 at 660 in 32bit debug build + CodeBuffer buffer("uncommon_trap_blob", 2000, 512); +#endif + // bypassed when code generation useless + MacroAssembler* masm = new MacroAssembler(&buffer); + const Register Rublock = R6; + const Register Rsender = altFP_7_11; + assert_different_registers(Rublock, Rsender, Rexception_obj, R0, R1, R2, R3, R8, Rtemp); + + // + // This is the entry point for all traps the compiler takes when it thinks + // it cannot handle further execution of compilation code. The frame is + // deoptimized in these cases and converted into interpreter frames for + // execution + // The steps taken by this frame are as follows: + // - push a fake "unpack_frame" + // - call the C routine Deoptimization::uncommon_trap (this function + // packs the current compiled frame into vframe arrays and returns + // information about the number and size of interpreter frames which + // are equivalent to the frame which is being deoptimized) + // - deallocate the "unpack_frame" + // - deallocate the deoptimization frame + // - in a loop using the information returned in the previous step + // push interpreter frames; + // - create a dummy "unpack_frame" + // - call the C routine: Deoptimization::unpack_frames (this function + // lays out values on the interpreter frame which was just created) + // - deallocate the dummy unpack_frame + // - return to the interpreter entry point + // + // Refer to the following methods for more information: + // - Deoptimization::uncommon_trap + // - Deoptimization::unpack_frame + + // the unloaded class index is in R0 (first parameter to this blob) + + __ raw_push(FP, LR); + __ set_last_Java_frame(SP, FP, false, Rtemp); + __ mov(R2, Deoptimization::Unpack_uncommon_trap); + __ mov(R1, R0); + __ mov(R0, Rthread); + __ call(CAST_FROM_FN_PTR(address, Deoptimization::uncommon_trap)); + __ mov(Rublock, R0); + __ reset_last_Java_frame(Rtemp); + __ raw_pop(FP, LR); + +#ifdef ASSERT + { Label L; + __ ldr_s32(Rtemp, Address(Rublock, Deoptimization::UnrollBlock::unpack_kind_offset())); + __ cmp_32(Rtemp, Deoptimization::Unpack_uncommon_trap); + __ b(L, eq); + __ stop("OptoRuntime::generate_uncommon_trap_blob: expected Unpack_uncommon_trap"); + __ bind(L); + } +#endif + + + // Set initial stack state before pushing interpreter frames + __ ldr_s32(Rtemp, Address(Rublock, Deoptimization::UnrollBlock::size_of_deoptimized_frame_offset())); + __ ldr(R2, Address(Rublock, Deoptimization::UnrollBlock::frame_pcs_offset())); + __ ldr(R3, Address(Rublock, Deoptimization::UnrollBlock::frame_sizes_offset())); + + __ add(SP, SP, Rtemp); + + // See if it is enough stack to push deoptimized frames. +#ifdef ASSERT + // Compilers generate code that bang the stack by as much as the + // interpreter would need. So this stack banging should never + // trigger a fault. Verify that it does not on non product builds. + // + // The compiled method that we are deoptimizing was popped from the stack. + // If the stack bang results in a stack overflow, we don't return to the + // method that is being deoptimized. The stack overflow exception is + // propagated to the caller of the deoptimized method. Need to get the pc + // from the caller in LR and restore FP. + __ ldr(LR, Address(R2, 0)); + __ ldr(FP, Address(Rublock, Deoptimization::UnrollBlock::initial_info_offset())); + __ ldr_s32(R8, Address(Rublock, Deoptimization::UnrollBlock::total_frame_sizes_offset())); + __ arm_stack_overflow_check(R8, Rtemp); +#endif + __ ldr_s32(R8, Address(Rublock, Deoptimization::UnrollBlock::number_of_frames_offset())); + __ ldr_s32(Rtemp, Address(Rublock, Deoptimization::UnrollBlock::caller_adjustment_offset())); + __ mov(Rsender, SP); + __ sub(SP, SP, Rtemp); + // __ ldr(FP, Address(FP)); + __ ldr(FP, Address(Rublock, Deoptimization::UnrollBlock::initial_info_offset())); + + // Push interpreter frames in a loop + Label loop; + __ bind(loop); + __ ldr(LR, Address(R2, wordSize, post_indexed)); // load frame pc + __ ldr(Rtemp, Address(R3, wordSize, post_indexed)); // load frame size + + __ raw_push(FP, LR); // create new frame + __ mov(FP, SP); + __ sub(Rtemp, Rtemp, 2*wordSize); + + __ sub(SP, SP, Rtemp); + + __ str(Rsender, Address(FP, frame::interpreter_frame_sender_sp_offset * wordSize)); + __ mov(LR, 0); + __ str(LR, Address(FP, frame::interpreter_frame_last_sp_offset * wordSize)); + __ subs(R8, R8, 1); // decrement counter + __ mov(Rsender, SP); + __ b(loop, ne); + + // Re-push self-frame + __ ldr(LR, Address(R2)); + __ raw_push(FP, LR); + __ mov(FP, SP); + + // Call unpack_frames with proper arguments + __ mov(R0, Rthread); + __ mov(R1, Deoptimization::Unpack_uncommon_trap); + __ set_last_Java_frame(SP, FP, true, Rtemp); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, Deoptimization::unpack_frames)); + // oop_maps->add_gc_map(__ pc() - start, new OopMap(frame_size_in_words, 0)); + __ reset_last_Java_frame(Rtemp); + + __ mov(SP, FP); + __ pop(RegisterSet(FP) | RegisterSet(PC)); + + masm->flush(); + _uncommon_trap_blob = UncommonTrapBlob::create(&buffer, nullptr, 2 /* LR+FP */); +} + //------------------------------ generate_exception_blob --------------------------- // creates exception blob at the end // Using exception blob, this code is jumped from a compiled method. @@ -148,3 +284,6 @@ void OptoRuntime::generate_exception_blob() { _exception_blob = ExceptionBlob::create(&buffer, oop_maps, framesize_in_words); } + +#endif // COMPILER2 + diff --git a/src/hotspot/cpu/arm/sharedRuntime_arm.cpp b/src/hotspot/cpu/arm/sharedRuntime_arm.cpp index 3792fab082ba6..1305283aeaeba 100644 --- a/src/hotspot/cpu/arm/sharedRuntime_arm.cpp +++ b/src/hotspot/cpu/arm/sharedRuntime_arm.cpp @@ -1595,147 +1595,6 @@ void SharedRuntime::generate_deopt_blob() { _deopt_blob->set_unpack_with_exception_in_tls_offset(exception_in_tls_offset); } -#ifdef COMPILER2 - -//------------------------------generate_uncommon_trap_blob-------------------- -// Ought to generate an ideal graph & compile, but here's some ASM -// instead. -void SharedRuntime::generate_uncommon_trap_blob() { - // allocate space for the code - ResourceMark rm; - - // setup code generation tools -#ifdef _LP64 - CodeBuffer buffer("uncommon_trap_blob", 2700, 512); -#else - // Measured 8/7/03 at 660 in 32bit debug build - CodeBuffer buffer("uncommon_trap_blob", 2000, 512); -#endif - // bypassed when code generation useless - MacroAssembler* masm = new MacroAssembler(&buffer); - const Register Rublock = R6; - const Register Rsender = altFP_7_11; - assert_different_registers(Rublock, Rsender, Rexception_obj, R0, R1, R2, R3, R8, Rtemp); - - // - // This is the entry point for all traps the compiler takes when it thinks - // it cannot handle further execution of compilation code. The frame is - // deoptimized in these cases and converted into interpreter frames for - // execution - // The steps taken by this frame are as follows: - // - push a fake "unpack_frame" - // - call the C routine Deoptimization::uncommon_trap (this function - // packs the current compiled frame into vframe arrays and returns - // information about the number and size of interpreter frames which - // are equivalent to the frame which is being deoptimized) - // - deallocate the "unpack_frame" - // - deallocate the deoptimization frame - // - in a loop using the information returned in the previous step - // push interpreter frames; - // - create a dummy "unpack_frame" - // - call the C routine: Deoptimization::unpack_frames (this function - // lays out values on the interpreter frame which was just created) - // - deallocate the dummy unpack_frame - // - return to the interpreter entry point - // - // Refer to the following methods for more information: - // - Deoptimization::uncommon_trap - // - Deoptimization::unpack_frame - - // the unloaded class index is in R0 (first parameter to this blob) - - __ raw_push(FP, LR); - __ set_last_Java_frame(SP, FP, false, Rtemp); - __ mov(R2, Deoptimization::Unpack_uncommon_trap); - __ mov(R1, R0); - __ mov(R0, Rthread); - __ call(CAST_FROM_FN_PTR(address, Deoptimization::uncommon_trap)); - __ mov(Rublock, R0); - __ reset_last_Java_frame(Rtemp); - __ raw_pop(FP, LR); - -#ifdef ASSERT - { Label L; - __ ldr_s32(Rtemp, Address(Rublock, Deoptimization::UnrollBlock::unpack_kind_offset())); - __ cmp_32(Rtemp, Deoptimization::Unpack_uncommon_trap); - __ b(L, eq); - __ stop("SharedRuntime::generate_uncommon_trap_blob: expected Unpack_uncommon_trap"); - __ bind(L); - } -#endif - - - // Set initial stack state before pushing interpreter frames - __ ldr_s32(Rtemp, Address(Rublock, Deoptimization::UnrollBlock::size_of_deoptimized_frame_offset())); - __ ldr(R2, Address(Rublock, Deoptimization::UnrollBlock::frame_pcs_offset())); - __ ldr(R3, Address(Rublock, Deoptimization::UnrollBlock::frame_sizes_offset())); - - __ add(SP, SP, Rtemp); - - // See if it is enough stack to push deoptimized frames. -#ifdef ASSERT - // Compilers generate code that bang the stack by as much as the - // interpreter would need. So this stack banging should never - // trigger a fault. Verify that it does not on non product builds. - // - // The compiled method that we are deoptimizing was popped from the stack. - // If the stack bang results in a stack overflow, we don't return to the - // method that is being deoptimized. The stack overflow exception is - // propagated to the caller of the deoptimized method. Need to get the pc - // from the caller in LR and restore FP. - __ ldr(LR, Address(R2, 0)); - __ ldr(FP, Address(Rublock, Deoptimization::UnrollBlock::initial_info_offset())); - __ ldr_s32(R8, Address(Rublock, Deoptimization::UnrollBlock::total_frame_sizes_offset())); - __ arm_stack_overflow_check(R8, Rtemp); -#endif - __ ldr_s32(R8, Address(Rublock, Deoptimization::UnrollBlock::number_of_frames_offset())); - __ ldr_s32(Rtemp, Address(Rublock, Deoptimization::UnrollBlock::caller_adjustment_offset())); - __ mov(Rsender, SP); - __ sub(SP, SP, Rtemp); - // __ ldr(FP, Address(FP)); - __ ldr(FP, Address(Rublock, Deoptimization::UnrollBlock::initial_info_offset())); - - // Push interpreter frames in a loop - Label loop; - __ bind(loop); - __ ldr(LR, Address(R2, wordSize, post_indexed)); // load frame pc - __ ldr(Rtemp, Address(R3, wordSize, post_indexed)); // load frame size - - __ raw_push(FP, LR); // create new frame - __ mov(FP, SP); - __ sub(Rtemp, Rtemp, 2*wordSize); - - __ sub(SP, SP, Rtemp); - - __ str(Rsender, Address(FP, frame::interpreter_frame_sender_sp_offset * wordSize)); - __ mov(LR, 0); - __ str(LR, Address(FP, frame::interpreter_frame_last_sp_offset * wordSize)); - __ subs(R8, R8, 1); // decrement counter - __ mov(Rsender, SP); - __ b(loop, ne); - - // Re-push self-frame - __ ldr(LR, Address(R2)); - __ raw_push(FP, LR); - __ mov(FP, SP); - - // Call unpack_frames with proper arguments - __ mov(R0, Rthread); - __ mov(R1, Deoptimization::Unpack_uncommon_trap); - __ set_last_Java_frame(SP, FP, true, Rtemp); - __ call_VM_leaf(CAST_FROM_FN_PTR(address, Deoptimization::unpack_frames)); - // oop_maps->add_gc_map(__ pc() - start, new OopMap(frame_size_in_words, 0)); - __ reset_last_Java_frame(Rtemp); - - __ mov(SP, FP); - __ pop(RegisterSet(FP) | RegisterSet(PC)); - - masm->flush(); - _uncommon_trap_blob = UncommonTrapBlob::create(&buffer, nullptr, 2 /* LR+FP */); -} - -#endif // COMPILER2 - //------------------------------generate_handler_blob------ // // Generate a special Compile2Runtime blob that saves all registers, diff --git a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp index 9b5a86bc45bfd..505f67ab6f952 100644 --- a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp +++ b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp @@ -3078,7 +3078,7 @@ void SharedRuntime::generate_deopt_blob() { } #ifdef COMPILER2 -void SharedRuntime::generate_uncommon_trap_blob() { +void OptoRuntime::generate_uncommon_trap_blob() { // Allocate space for the code. ResourceMark rm; // Setup code generation tools. @@ -3144,7 +3144,7 @@ void SharedRuntime::generate_uncommon_trap_blob() { #ifdef ASSERT __ lwz(R22_tmp2, in_bytes(Deoptimization::UnrollBlock::unpack_kind_offset()), unroll_block_reg); __ cmpdi(CCR0, R22_tmp2, (unsigned)Deoptimization::Unpack_uncommon_trap); - __ asm_assert_eq("SharedRuntime::generate_deopt_blob: expected Unpack_uncommon_trap"); + __ asm_assert_eq("OptoRuntime::generate_uncommon_trap_blob: expected Unpack_uncommon_trap"); #endif // Freezing continuation frames requires that the caller is trimmed to unextended sp if compiled. diff --git a/src/hotspot/cpu/riscv/runtime_riscv.cpp b/src/hotspot/cpu/riscv/runtime_riscv.cpp new file mode 100644 index 0000000000000..9e16278c3b547 --- /dev/null +++ b/src/hotspot/cpu/riscv/runtime_riscv.cpp @@ -0,0 +1,382 @@ +/* + * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, Red Hat Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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" +#ifdef COMPILER2 +#include "asm/macroAssembler.hpp" +#include "asm/macroAssembler.inline.hpp" +#include "code/vmreg.hpp" +#include "interpreter/interpreter.hpp" +#include "opto/runtime.hpp" +#include "runtime/interfaceSupport.inline.hpp" +#include "runtime/sharedRuntime.hpp" +#include "runtime/stubRoutines.hpp" +#include "runtime/vframeArray.hpp" +#include "utilities/globalDefinitions.hpp" +#include "vmreg_riscv.inline.hpp" + +class SimpleRuntimeFrame { +public: + + // Most of the runtime stubs have this simple frame layout. + // This class exists to make the layout shared in one place. + // Offsets are for compiler stack slots, which are jints. + enum layout { + // The frame sender code expects that fp will be in the "natural" place and + // will override any oopMap setting for it. We must therefore force the layout + // so that it agrees with the frame sender code. + // we don't expect any arg reg save area so riscv asserts that + // frame::arg_reg_save_area_bytes == 0 + fp_off = 0, fp_off2, + return_off, return_off2, + framesize + }; +}; + +#define __ masm-> + +//------------------------------generate_uncommon_trap_blob-------------------- +void OptoRuntime::generate_uncommon_trap_blob() { + // Allocate space for the code + ResourceMark rm; + // Setup code generation tools + CodeBuffer buffer("uncommon_trap_blob", 2048, 1024); + MacroAssembler* masm = new MacroAssembler(&buffer); + assert_cond(masm != nullptr); + + assert(SimpleRuntimeFrame::framesize % 4 == 0, "sp not 16-byte aligned"); + + address start = __ pc(); + + // Push self-frame. We get here with a return address in RA + // and sp should be 16 byte aligned + // push fp and retaddr by hand + __ addi(sp, sp, -2 * wordSize); + __ sd(ra, Address(sp, wordSize)); + __ sd(fp, Address(sp, 0)); + // we don't expect an arg reg save area +#ifndef PRODUCT + assert(frame::arg_reg_save_area_bytes == 0, "not expecting frame reg save area"); +#endif + // compiler left unloaded_class_index in j_rarg0 move to where the + // runtime expects it. + __ sign_extend(c_rarg1, j_rarg0, 32); + + // we need to set the past SP to the stack pointer of the stub frame + // and the pc to the address where this runtime call will return + // although actually any pc in this code blob will do). + Label retaddr; + __ set_last_Java_frame(sp, noreg, retaddr, t0); + + // Call C code. Need thread but NOT official VM entry + // crud. We cannot block on this call, no GC can happen. Call should + // capture callee-saved registers as well as return values. + // + // UnrollBlock* uncommon_trap(JavaThread* thread, jint unloaded_class_index, jint exec_mode) + // + // n.b. 3 gp args, 0 fp args, integral return type + + __ mv(c_rarg0, xthread); + __ mv(c_rarg2, Deoptimization::Unpack_uncommon_trap); + __ rt_call(CAST_FROM_FN_PTR(address, Deoptimization::uncommon_trap)); + __ bind(retaddr); + + // Set an oopmap for the call site + OopMapSet* oop_maps = new OopMapSet(); + OopMap* map = new OopMap(SimpleRuntimeFrame::framesize, 0); + assert_cond(oop_maps != nullptr && map != nullptr); + + // location of fp is known implicitly by the frame sender code + + oop_maps->add_gc_map(__ pc() - start, map); + + __ reset_last_Java_frame(false); + + // move UnrollBlock* into x14 + __ mv(x14, x10); + +#ifdef ASSERT + { Label L; + __ lwu(t0, Address(x14, Deoptimization::UnrollBlock::unpack_kind_offset())); + __ mv(t1, Deoptimization::Unpack_uncommon_trap); + __ beq(t0, t1, L); + __ stop("OptoRuntime::generate_uncommon_trap_blob: expected Unpack_uncommon_trap"); + __ bind(L); + } +#endif + + // Pop all the frames we must move/replace. + // + // Frame picture (youngest to oldest) + // 1: self-frame (no frame link) + // 2: deopting frame (no frame link) + // 3: caller of deopting frame (could be compiled/interpreted). + + __ add(sp, sp, (SimpleRuntimeFrame::framesize) << LogBytesPerInt); // Epilog! + + // Pop deoptimized frame (int) + __ lwu(x12, Address(x14, + Deoptimization::UnrollBlock:: + size_of_deoptimized_frame_offset())); + __ sub(x12, x12, 2 * wordSize); + __ add(sp, sp, x12); + __ ld(fp, Address(sp, 0)); + __ ld(ra, Address(sp, wordSize)); + __ addi(sp, sp, 2 * wordSize); + // RA should now be the return address to the caller (3) frame + +#ifdef ASSERT + // Compilers generate code that bang the stack by as much as the + // interpreter would need. So this stack banging should never + // trigger a fault. Verify that it does not on non product builds. + __ lwu(x11, Address(x14, + Deoptimization::UnrollBlock:: + total_frame_sizes_offset())); + __ bang_stack_size(x11, x12); +#endif + + // Load address of array of frame pcs into x12 (address*) + __ ld(x12, Address(x14, + Deoptimization::UnrollBlock::frame_pcs_offset())); + + // Load address of array of frame sizes into x15 (intptr_t*) + __ ld(x15, Address(x14, + Deoptimization::UnrollBlock:: + frame_sizes_offset())); + + // Counter + __ lwu(x13, Address(x14, + Deoptimization::UnrollBlock:: + number_of_frames_offset())); // (int) + + // Now adjust the caller's stack to make up for the extra locals but + // record the original sp so that we can save it in the skeletal + // interpreter frame and the stack walking of interpreter_sender + // will get the unextended sp value and not the "real" sp value. + + const Register sender_sp = t1; // temporary register + + __ lwu(x11, Address(x14, + Deoptimization::UnrollBlock:: + caller_adjustment_offset())); // (int) + __ mv(sender_sp, sp); + __ sub(sp, sp, x11); + + // Push interpreter frames in a loop + Label loop; + __ bind(loop); + __ ld(x11, Address(x15, 0)); // Load frame size + __ sub(x11, x11, 2 * wordSize); // We'll push pc and fp by hand + __ ld(ra, Address(x12, 0)); // Save return address + __ enter(); // and old fp & set new fp + __ sub(sp, sp, x11); // Prolog + __ sd(sender_sp, Address(fp, frame::interpreter_frame_sender_sp_offset * wordSize)); // Make it walkable + // This value is corrected by layout_activation_impl + __ sd(zr, Address(fp, frame::interpreter_frame_last_sp_offset * wordSize)); + __ mv(sender_sp, sp); // Pass sender_sp to next frame + __ add(x15, x15, wordSize); // Bump array pointer (sizes) + __ add(x12, x12, wordSize); // Bump array pointer (pcs) + __ subw(x13, x13, 1); // Decrement counter + __ bgtz(x13, loop); + __ ld(ra, Address(x12, 0)); // save final return address + // Re-push self-frame + __ enter(); // & old fp & set new fp + + // Use fp because the frames look interpreted now + // Save "the_pc" since it cannot easily be retrieved using the last_java_SP after we aligned SP. + // Don't need the precise return PC here, just precise enough to point into this code blob. + address the_pc = __ pc(); + __ set_last_Java_frame(sp, fp, the_pc, t0); + + // Call C code. Need thread but NOT official VM entry + // crud. We cannot block on this call, no GC can happen. Call should + // restore return values to their stack-slots with the new SP. + // + // BasicType unpack_frames(JavaThread* thread, int exec_mode) + // + + // n.b. 2 gp args, 0 fp args, integral return type + + // sp should already be aligned + __ mv(c_rarg0, xthread); + __ mv(c_rarg1, Deoptimization::Unpack_uncommon_trap); + __ rt_call(CAST_FROM_FN_PTR(address, Deoptimization::unpack_frames)); + + // Set an oopmap for the call site + // Use the same PC we used for the last java frame + oop_maps->add_gc_map(the_pc - start, new OopMap(SimpleRuntimeFrame::framesize, 0)); + + // Clear fp AND pc + __ reset_last_Java_frame(true); + + // Pop self-frame. + __ leave(); // Epilog + + // Jump to interpreter + __ ret(); + + // Make sure all code is generated + masm->flush(); + + _uncommon_trap_blob = UncommonTrapBlob::create(&buffer, oop_maps, + SimpleRuntimeFrame::framesize >> 1); +} + +//------------------------------generate_exception_blob--------------------------- +// creates exception blob at the end +// Using exception blob, this code is jumped from a compiled method. +// (see emit_exception_handler in riscv.ad file) +// +// Given an exception pc at a call we call into the runtime for the +// handler in this method. This handler might merely restore state +// (i.e. callee save registers) unwind the frame and jump to the +// exception handler for the nmethod if there is no Java level handler +// for the nmethod. +// +// This code is entered with a jmp. +// +// Arguments: +// x10: exception oop +// x13: exception pc +// +// Results: +// x10: exception oop +// x13: exception pc in caller +// destination: exception handler of caller +// +// Note: the exception pc MUST be at a call (precise debug information) +// Registers x10, x13, x12, x14, x15, t0 are not callee saved. +// + +void OptoRuntime::generate_exception_blob() { + assert(!OptoRuntime::is_callee_saved_register(R13_num), ""); + assert(!OptoRuntime::is_callee_saved_register(R10_num), ""); + assert(!OptoRuntime::is_callee_saved_register(R12_num), ""); + + assert(SimpleRuntimeFrame::framesize % 4 == 0, "sp not 16-byte aligned"); + + // Allocate space for the code + ResourceMark rm; + // Setup code generation tools + CodeBuffer buffer("exception_blob", 2048, 1024); + MacroAssembler* masm = new MacroAssembler(&buffer); + assert_cond(masm != nullptr); + + // TODO check various assumptions made here + // + // make sure we do so before running this + + address start = __ pc(); + + // push fp and retaddr by hand + // Exception pc is 'return address' for stack walker + __ addi(sp, sp, -2 * wordSize); + __ sd(ra, Address(sp, wordSize)); + __ sd(fp, Address(sp)); + // there are no callee save registers and we don't expect an + // arg reg save area +#ifndef PRODUCT + assert(frame::arg_reg_save_area_bytes == 0, "not expecting frame reg save area"); +#endif + // Store exception in Thread object. We cannot pass any arguments to the + // handle_exception call, since we do not want to make any assumption + // about the size of the frame where the exception happened in. + __ sd(x10, Address(xthread, JavaThread::exception_oop_offset())); + __ sd(x13, Address(xthread, JavaThread::exception_pc_offset())); + + // This call does all the hard work. It checks if an exception handler + // exists in the method. + // If so, it returns the handler address. + // If not, it prepares for stack-unwinding, restoring the callee-save + // registers of the frame being removed. + // + // address OptoRuntime::handle_exception_C(JavaThread* thread) + // + // n.b. 1 gp arg, 0 fp args, integral return type + + // the stack should always be aligned + address the_pc = __ pc(); + __ set_last_Java_frame(sp, noreg, the_pc, t0); + __ mv(c_rarg0, xthread); + __ rt_call(CAST_FROM_FN_PTR(address, OptoRuntime::handle_exception_C)); + + // handle_exception_C is a special VM call which does not require an explicit + // instruction sync afterwards. + + // Set an oopmap for the call site. This oopmap will only be used if we + // are unwinding the stack. Hence, all locations will be dead. + // Callee-saved registers will be the same as the frame above (i.e., + // handle_exception_stub), since they were restored when we got the + // exception. + + OopMapSet* oop_maps = new OopMapSet(); + assert_cond(oop_maps != nullptr); + + oop_maps->add_gc_map(the_pc - start, new OopMap(SimpleRuntimeFrame::framesize, 0)); + + __ reset_last_Java_frame(false); + + // Restore callee-saved registers + + // fp is an implicitly saved callee saved register (i.e. the calling + // convention will save restore it in prolog/epilog) Other than that + // there are no callee save registers now that adapter frames are gone. + // and we dont' expect an arg reg save area + __ ld(fp, Address(sp)); + __ ld(x13, Address(sp, wordSize)); + __ addi(sp, sp , 2 * wordSize); + + // x10: exception handler + + // We have a handler in x10 (could be deopt blob). + __ mv(t0, x10); + + // Get the exception oop + __ ld(x10, Address(xthread, JavaThread::exception_oop_offset())); + // Get the exception pc in case we are deoptimized + __ ld(x14, Address(xthread, JavaThread::exception_pc_offset())); +#ifdef ASSERT + __ sd(zr, Address(xthread, JavaThread::exception_handler_pc_offset())); + __ sd(zr, Address(xthread, JavaThread::exception_pc_offset())); +#endif + // Clear the exception oop so GC no longer processes it as a root. + __ sd(zr, Address(xthread, JavaThread::exception_oop_offset())); + + // x10: exception oop + // t0: exception handler + // x14: exception pc + // Jump to handler + + __ jr(t0); + + // Make sure all code is generated + masm->flush(); + + // Set exception blob + _exception_blob = ExceptionBlob::create(&buffer, oop_maps, SimpleRuntimeFrame::framesize >> 1); +} +#endif // COMPILER2 + + diff --git a/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp b/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp index 01ab3d5c27403..ad06f688d6a36 100644 --- a/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp +++ b/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp @@ -67,24 +67,6 @@ const int StackAlignmentInSlots = StackAlignmentInBytes / VMRegImpl::stack_slot_size; -class SimpleRuntimeFrame { -public: - - // Most of the runtime stubs have this simple frame layout. - // This class exists to make the layout shared in one place. - // Offsets are for compiler stack slots, which are jints. - enum layout { - // The frame sender code expects that fp will be in the "natural" place and - // will override any oopMap setting for it. We must therefore force the layout - // so that it agrees with the frame sender code. - // we don't expect any arg reg save area so riscv asserts that - // frame::arg_reg_save_area_bytes == 0 - fp_off = 0, fp_off2, - return_off, return_off2, - framesize - }; -}; - class RegisterSaver { const bool _save_vectors; public: @@ -2441,195 +2423,6 @@ uint SharedRuntime::out_preserve_stack_slots() { return 0; } -#ifdef COMPILER2 -//------------------------------generate_uncommon_trap_blob-------------------- -void SharedRuntime::generate_uncommon_trap_blob() { - // Allocate space for the code - ResourceMark rm; - // Setup code generation tools - CodeBuffer buffer("uncommon_trap_blob", 2048, 1024); - MacroAssembler* masm = new MacroAssembler(&buffer); - assert_cond(masm != nullptr); - - assert(SimpleRuntimeFrame::framesize % 4 == 0, "sp not 16-byte aligned"); - - address start = __ pc(); - - // Push self-frame. We get here with a return address in RA - // and sp should be 16 byte aligned - // push fp and retaddr by hand - __ addi(sp, sp, -2 * wordSize); - __ sd(ra, Address(sp, wordSize)); - __ sd(fp, Address(sp, 0)); - // we don't expect an arg reg save area -#ifndef PRODUCT - assert(frame::arg_reg_save_area_bytes == 0, "not expecting frame reg save area"); -#endif - // compiler left unloaded_class_index in j_rarg0 move to where the - // runtime expects it. - __ sign_extend(c_rarg1, j_rarg0, 32); - - // we need to set the past SP to the stack pointer of the stub frame - // and the pc to the address where this runtime call will return - // although actually any pc in this code blob will do). - Label retaddr; - __ set_last_Java_frame(sp, noreg, retaddr, t0); - - // Call C code. Need thread but NOT official VM entry - // crud. We cannot block on this call, no GC can happen. Call should - // capture callee-saved registers as well as return values. - // - // UnrollBlock* uncommon_trap(JavaThread* thread, jint unloaded_class_index, jint exec_mode) - // - // n.b. 3 gp args, 0 fp args, integral return type - - __ mv(c_rarg0, xthread); - __ mv(c_rarg2, Deoptimization::Unpack_uncommon_trap); - __ rt_call(CAST_FROM_FN_PTR(address, Deoptimization::uncommon_trap)); - __ bind(retaddr); - - // Set an oopmap for the call site - OopMapSet* oop_maps = new OopMapSet(); - OopMap* map = new OopMap(SimpleRuntimeFrame::framesize, 0); - assert_cond(oop_maps != nullptr && map != nullptr); - - // location of fp is known implicitly by the frame sender code - - oop_maps->add_gc_map(__ pc() - start, map); - - __ reset_last_Java_frame(false); - - // move UnrollBlock* into x14 - __ mv(x14, x10); - -#ifdef ASSERT - { Label L; - __ lwu(t0, Address(x14, Deoptimization::UnrollBlock::unpack_kind_offset())); - __ mv(t1, Deoptimization::Unpack_uncommon_trap); - __ beq(t0, t1, L); - __ stop("SharedRuntime::generate_uncommon_trap_blob: expected Unpack_uncommon_trap"); - __ bind(L); - } -#endif - - // Pop all the frames we must move/replace. - // - // Frame picture (youngest to oldest) - // 1: self-frame (no frame link) - // 2: deopting frame (no frame link) - // 3: caller of deopting frame (could be compiled/interpreted). - - __ add(sp, sp, (SimpleRuntimeFrame::framesize) << LogBytesPerInt); // Epilog! - - // Pop deoptimized frame (int) - __ lwu(x12, Address(x14, - Deoptimization::UnrollBlock:: - size_of_deoptimized_frame_offset())); - __ sub(x12, x12, 2 * wordSize); - __ add(sp, sp, x12); - __ ld(fp, Address(sp, 0)); - __ ld(ra, Address(sp, wordSize)); - __ addi(sp, sp, 2 * wordSize); - // RA should now be the return address to the caller (3) frame - -#ifdef ASSERT - // Compilers generate code that bang the stack by as much as the - // interpreter would need. So this stack banging should never - // trigger a fault. Verify that it does not on non product builds. - __ lwu(x11, Address(x14, - Deoptimization::UnrollBlock:: - total_frame_sizes_offset())); - __ bang_stack_size(x11, x12); -#endif - - // Load address of array of frame pcs into x12 (address*) - __ ld(x12, Address(x14, - Deoptimization::UnrollBlock::frame_pcs_offset())); - - // Load address of array of frame sizes into x15 (intptr_t*) - __ ld(x15, Address(x14, - Deoptimization::UnrollBlock:: - frame_sizes_offset())); - - // Counter - __ lwu(x13, Address(x14, - Deoptimization::UnrollBlock:: - number_of_frames_offset())); // (int) - - // Now adjust the caller's stack to make up for the extra locals but - // record the original sp so that we can save it in the skeletal - // interpreter frame and the stack walking of interpreter_sender - // will get the unextended sp value and not the "real" sp value. - - const Register sender_sp = t1; // temporary register - - __ lwu(x11, Address(x14, - Deoptimization::UnrollBlock:: - caller_adjustment_offset())); // (int) - __ mv(sender_sp, sp); - __ sub(sp, sp, x11); - - // Push interpreter frames in a loop - Label loop; - __ bind(loop); - __ ld(x11, Address(x15, 0)); // Load frame size - __ sub(x11, x11, 2 * wordSize); // We'll push pc and fp by hand - __ ld(ra, Address(x12, 0)); // Save return address - __ enter(); // and old fp & set new fp - __ sub(sp, sp, x11); // Prolog - __ sd(sender_sp, Address(fp, frame::interpreter_frame_sender_sp_offset * wordSize)); // Make it walkable - // This value is corrected by layout_activation_impl - __ sd(zr, Address(fp, frame::interpreter_frame_last_sp_offset * wordSize)); - __ mv(sender_sp, sp); // Pass sender_sp to next frame - __ add(x15, x15, wordSize); // Bump array pointer (sizes) - __ add(x12, x12, wordSize); // Bump array pointer (pcs) - __ subw(x13, x13, 1); // Decrement counter - __ bgtz(x13, loop); - __ ld(ra, Address(x12, 0)); // save final return address - // Re-push self-frame - __ enter(); // & old fp & set new fp - - // Use fp because the frames look interpreted now - // Save "the_pc" since it cannot easily be retrieved using the last_java_SP after we aligned SP. - // Don't need the precise return PC here, just precise enough to point into this code blob. - address the_pc = __ pc(); - __ set_last_Java_frame(sp, fp, the_pc, t0); - - // Call C code. Need thread but NOT official VM entry - // crud. We cannot block on this call, no GC can happen. Call should - // restore return values to their stack-slots with the new SP. - // - // BasicType unpack_frames(JavaThread* thread, int exec_mode) - // - - // n.b. 2 gp args, 0 fp args, integral return type - - // sp should already be aligned - __ mv(c_rarg0, xthread); - __ mv(c_rarg1, Deoptimization::Unpack_uncommon_trap); - __ rt_call(CAST_FROM_FN_PTR(address, Deoptimization::unpack_frames)); - - // Set an oopmap for the call site - // Use the same PC we used for the last java frame - oop_maps->add_gc_map(the_pc - start, new OopMap(SimpleRuntimeFrame::framesize, 0)); - - // Clear fp AND pc - __ reset_last_Java_frame(true); - - // Pop self-frame. - __ leave(); // Epilog - - // Jump to interpreter - __ ret(); - - // Make sure all code is generated - masm->flush(); - - _uncommon_trap_blob = UncommonTrapBlob::create(&buffer, oop_maps, - SimpleRuntimeFrame::framesize >> 1); -} -#endif // COMPILER2 - //------------------------------generate_handler_blob------ // // Generate a special Compile2Runtime blob that saves all registers, @@ -2835,139 +2628,3 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const cha // return the blob return RuntimeStub::new_runtime_stub(name, &buffer, frame_complete, frame_size_in_words, oop_maps, true); } - -#ifdef COMPILER2 -//------------------------------generate_exception_blob--------------------------- -// creates exception blob at the end -// Using exception blob, this code is jumped from a compiled method. -// (see emit_exception_handler in riscv.ad file) -// -// Given an exception pc at a call we call into the runtime for the -// handler in this method. This handler might merely restore state -// (i.e. callee save registers) unwind the frame and jump to the -// exception handler for the nmethod if there is no Java level handler -// for the nmethod. -// -// This code is entered with a jmp. -// -// Arguments: -// x10: exception oop -// x13: exception pc -// -// Results: -// x10: exception oop -// x13: exception pc in caller -// destination: exception handler of caller -// -// Note: the exception pc MUST be at a call (precise debug information) -// Registers x10, x13, x12, x14, x15, t0 are not callee saved. -// - -void OptoRuntime::generate_exception_blob() { - assert(!OptoRuntime::is_callee_saved_register(R13_num), ""); - assert(!OptoRuntime::is_callee_saved_register(R10_num), ""); - assert(!OptoRuntime::is_callee_saved_register(R12_num), ""); - - assert(SimpleRuntimeFrame::framesize % 4 == 0, "sp not 16-byte aligned"); - - // Allocate space for the code - ResourceMark rm; - // Setup code generation tools - CodeBuffer buffer("exception_blob", 2048, 1024); - MacroAssembler* masm = new MacroAssembler(&buffer); - assert_cond(masm != nullptr); - - // TODO check various assumptions made here - // - // make sure we do so before running this - - address start = __ pc(); - - // push fp and retaddr by hand - // Exception pc is 'return address' for stack walker - __ addi(sp, sp, -2 * wordSize); - __ sd(ra, Address(sp, wordSize)); - __ sd(fp, Address(sp)); - // there are no callee save registers and we don't expect an - // arg reg save area -#ifndef PRODUCT - assert(frame::arg_reg_save_area_bytes == 0, "not expecting frame reg save area"); -#endif - // Store exception in Thread object. We cannot pass any arguments to the - // handle_exception call, since we do not want to make any assumption - // about the size of the frame where the exception happened in. - __ sd(x10, Address(xthread, JavaThread::exception_oop_offset())); - __ sd(x13, Address(xthread, JavaThread::exception_pc_offset())); - - // This call does all the hard work. It checks if an exception handler - // exists in the method. - // If so, it returns the handler address. - // If not, it prepares for stack-unwinding, restoring the callee-save - // registers of the frame being removed. - // - // address OptoRuntime::handle_exception_C(JavaThread* thread) - // - // n.b. 1 gp arg, 0 fp args, integral return type - - // the stack should always be aligned - address the_pc = __ pc(); - __ set_last_Java_frame(sp, noreg, the_pc, t0); - __ mv(c_rarg0, xthread); - __ rt_call(CAST_FROM_FN_PTR(address, OptoRuntime::handle_exception_C)); - - // handle_exception_C is a special VM call which does not require an explicit - // instruction sync afterwards. - - // Set an oopmap for the call site. This oopmap will only be used if we - // are unwinding the stack. Hence, all locations will be dead. - // Callee-saved registers will be the same as the frame above (i.e., - // handle_exception_stub), since they were restored when we got the - // exception. - - OopMapSet* oop_maps = new OopMapSet(); - assert_cond(oop_maps != nullptr); - - oop_maps->add_gc_map(the_pc - start, new OopMap(SimpleRuntimeFrame::framesize, 0)); - - __ reset_last_Java_frame(false); - - // Restore callee-saved registers - - // fp is an implicitly saved callee saved register (i.e. the calling - // convention will save restore it in prolog/epilog) Other than that - // there are no callee save registers now that adapter frames are gone. - // and we dont' expect an arg reg save area - __ ld(fp, Address(sp)); - __ ld(x13, Address(sp, wordSize)); - __ addi(sp, sp , 2 * wordSize); - - // x10: exception handler - - // We have a handler in x10 (could be deopt blob). - __ mv(t0, x10); - - // Get the exception oop - __ ld(x10, Address(xthread, JavaThread::exception_oop_offset())); - // Get the exception pc in case we are deoptimized - __ ld(x14, Address(xthread, JavaThread::exception_pc_offset())); -#ifdef ASSERT - __ sd(zr, Address(xthread, JavaThread::exception_handler_pc_offset())); - __ sd(zr, Address(xthread, JavaThread::exception_pc_offset())); -#endif - // Clear the exception oop so GC no longer processes it as a root. - __ sd(zr, Address(xthread, JavaThread::exception_oop_offset())); - - // x10: exception oop - // t0: exception handler - // x14: exception pc - // Jump to handler - - __ jr(t0); - - // Make sure all code is generated - masm->flush(); - - // Set exception blob - _exception_blob = ExceptionBlob::create(&buffer, oop_maps, SimpleRuntimeFrame::framesize >> 1); -} -#endif // COMPILER2 diff --git a/src/hotspot/cpu/s390/sharedRuntime_s390.cpp b/src/hotspot/cpu/s390/sharedRuntime_s390.cpp index 0ee88345282b7..641b3712a175b 100644 --- a/src/hotspot/cpu/s390/sharedRuntime_s390.cpp +++ b/src/hotspot/cpu/s390/sharedRuntime_s390.cpp @@ -2706,7 +2706,7 @@ void SharedRuntime::generate_deopt_blob() { #ifdef COMPILER2 //------------------------------generate_uncommon_trap_blob-------------------- -void SharedRuntime::generate_uncommon_trap_blob() { +void OptoRuntime::generate_uncommon_trap_blob() { // Allocate space for the code ResourceMark rm; // Setup code generation tools @@ -2769,7 +2769,7 @@ void SharedRuntime::generate_uncommon_trap_blob() { } else { __ z_cliy(unpack_kind_byte_offset, unroll_block_reg, Deoptimization::Unpack_uncommon_trap); } - __ asm_assert(Assembler::bcondEqual, "SharedRuntime::generate_deopt_blob: expected Unpack_uncommon_trap", 0); + __ asm_assert(Assembler::bcondEqual, "OptoRuntime::generate_deopt_blob: expected Unpack_uncommon_trap", 0); #endif __ zap_from_to(Z_SP, Z_SP, Z_R0_scratch, Z_R1, 500, -1); diff --git a/src/hotspot/cpu/x86/runtime_x86_32.cpp b/src/hotspot/cpu/x86/runtime_x86_32.cpp index d38fa3c60bdd1..2a21c42a5e606 100644 --- a/src/hotspot/cpu/x86/runtime_x86_32.cpp +++ b/src/hotspot/cpu/x86/runtime_x86_32.cpp @@ -41,6 +41,180 @@ #define __ masm-> +//------------------------------generate_uncommon_trap_blob-------------------- +void OptoRuntime::generate_uncommon_trap_blob() { + // allocate space for the code + ResourceMark rm; + // setup code generation tools + CodeBuffer buffer("uncommon_trap_blob", 512, 512); + MacroAssembler* masm = new MacroAssembler(&buffer); + + enum frame_layout { + arg0_off, // thread sp + 0 // Arg location for + arg1_off, // unloaded_class_index sp + 1 // calling C + arg2_off, // exec_mode sp + 2 + // The frame sender code expects that rbp will be in the "natural" place and + // will override any oopMap setting for it. We must therefore force the layout + // so that it agrees with the frame sender code. + rbp_off, // callee saved register sp + 3 + return_off, // slot for return address sp + 4 + framesize + }; + + address start = __ pc(); + + // Push self-frame. + __ subptr(rsp, return_off*wordSize); // Epilog! + + // rbp, is an implicitly saved callee saved register (i.e. the calling + // convention will save restore it in prolog/epilog) Other than that + // there are no callee save registers no that adapter frames are gone. + __ movptr(Address(rsp, rbp_off*wordSize), rbp); + + // Clear the floating point exception stack + __ empty_FPU_stack(); + + // set last_Java_sp + __ get_thread(rdx); + __ set_last_Java_frame(rdx, noreg, noreg, nullptr, noreg); + + // Call C code. Need thread but NOT official VM entry + // crud. We cannot block on this call, no GC can happen. Call should + // capture callee-saved registers as well as return values. + __ movptr(Address(rsp, arg0_off*wordSize), rdx); + // argument already in ECX + __ movl(Address(rsp, arg1_off*wordSize),rcx); + __ movl(Address(rsp, arg2_off*wordSize), Deoptimization::Unpack_uncommon_trap); + __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, Deoptimization::uncommon_trap))); + + // Set an oopmap for the call site + OopMapSet *oop_maps = new OopMapSet(); + OopMap* map = new OopMap( framesize, 0 ); + // No oopMap for rbp, it is known implicitly + + oop_maps->add_gc_map( __ pc()-start, map); + + __ get_thread(rcx); + + __ reset_last_Java_frame(rcx, false); + + // Load UnrollBlock into EDI + __ movptr(rdi, rax); + +#ifdef ASSERT + { Label L; + __ cmpptr(Address(rdi, Deoptimization::UnrollBlock::unpack_kind_offset()), + (int32_t)Deoptimization::Unpack_uncommon_trap); + __ jcc(Assembler::equal, L); + __ stop("OptoRuntime::generate_uncommon_trap_blob: expected Unpack_uncommon_trap"); + __ bind(L); + } +#endif + + // Pop all the frames we must move/replace. + // + // Frame picture (youngest to oldest) + // 1: self-frame (no frame link) + // 2: deopting frame (no frame link) + // 3: caller of deopting frame (could be compiled/interpreted). + + // Pop self-frame. We have no frame, and must rely only on EAX and ESP. + __ addptr(rsp,(framesize-1)*wordSize); // Epilog! + + // Pop deoptimized frame + __ movl2ptr(rcx, Address(rdi,Deoptimization::UnrollBlock::size_of_deoptimized_frame_offset())); + __ addptr(rsp, rcx); + + // sp should be pointing at the return address to the caller (3) + + // Pick up the initial fp we should save + // restore rbp before stack bang because if stack overflow is thrown it needs to be pushed (and preserved) + __ movptr(rbp, Address(rdi, Deoptimization::UnrollBlock::initial_info_offset())); + +#ifdef ASSERT + // Compilers generate code that bang the stack by as much as the + // interpreter would need. So this stack banging should never + // trigger a fault. Verify that it does not on non product builds. + __ movl(rbx, Address(rdi ,Deoptimization::UnrollBlock::total_frame_sizes_offset())); + __ bang_stack_size(rbx, rcx); +#endif + + // Load array of frame pcs into ECX + __ movl(rcx,Address(rdi,Deoptimization::UnrollBlock::frame_pcs_offset())); + + __ pop(rsi); // trash the pc + + // Load array of frame sizes into ESI + __ movptr(rsi,Address(rdi,Deoptimization::UnrollBlock::frame_sizes_offset())); + + Address counter(rdi, Deoptimization::UnrollBlock::counter_temp_offset()); + + __ movl(rbx, Address(rdi, Deoptimization::UnrollBlock::number_of_frames_offset())); + __ movl(counter, rbx); + + // Now adjust the caller's stack to make up for the extra locals + // but record the original sp so that we can save it in the skeletal interpreter + // frame and the stack walking of interpreter_sender will get the unextended sp + // value and not the "real" sp value. + + Address sp_temp(rdi, Deoptimization::UnrollBlock::sender_sp_temp_offset()); + __ movptr(sp_temp, rsp); + __ movl(rbx, Address(rdi, Deoptimization::UnrollBlock::caller_adjustment_offset())); + __ subptr(rsp, rbx); + + // Push interpreter frames in a loop + Label loop; + __ bind(loop); + __ movptr(rbx, Address(rsi, 0)); // Load frame size + __ subptr(rbx, 2*wordSize); // we'll push pc and rbp, by hand + __ pushptr(Address(rcx, 0)); // save return address + __ enter(); // save old & set new rbp, + __ subptr(rsp, rbx); // Prolog! + __ movptr(rbx, sp_temp); // sender's sp + // This value is corrected by layout_activation_impl + __ movptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), NULL_WORD ); + __ movptr(Address(rbp, frame::interpreter_frame_sender_sp_offset * wordSize), rbx); // Make it walkable + __ movptr(sp_temp, rsp); // pass to next frame + __ addptr(rsi, wordSize); // Bump array pointer (sizes) + __ addptr(rcx, wordSize); // Bump array pointer (pcs) + __ decrementl(counter); // decrement counter + __ jcc(Assembler::notZero, loop); + __ pushptr(Address(rcx, 0)); // save final return address + + // Re-push self-frame + __ enter(); // save old & set new rbp, + __ subptr(rsp, (framesize-2) * wordSize); // Prolog! + + + // set last_Java_sp, last_Java_fp + __ get_thread(rdi); + __ set_last_Java_frame(rdi, noreg, rbp, nullptr, noreg); + + // Call C code. Need thread but NOT official VM entry + // crud. We cannot block on this call, no GC can happen. Call should + // restore return values to their stack-slots with the new SP. + __ movptr(Address(rsp,arg0_off*wordSize),rdi); + __ movl(Address(rsp,arg1_off*wordSize), Deoptimization::Unpack_uncommon_trap); + __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, Deoptimization::unpack_frames))); + // Set an oopmap for the call site + oop_maps->add_gc_map( __ pc()-start, new OopMap( framesize, 0 ) ); + + __ get_thread(rdi); + __ reset_last_Java_frame(rdi, true); + + // Pop self-frame. + __ leave(); // Epilog! + + // Jump to interpreter + __ ret(0); + + // ------------- + // make sure all code is generated + masm->flush(); + + _uncommon_trap_blob = UncommonTrapBlob::create(&buffer, oop_maps, framesize); +} + //------------------------------generate_exception_blob--------------------------- // creates exception blob at the end // Using exception blob, this code is jumped from a compiled method. diff --git a/src/hotspot/cpu/x86/runtime_x86_64.cpp b/src/hotspot/cpu/x86/runtime_x86_64.cpp index e08550715b495..eb3bab36b88cb 100644 --- a/src/hotspot/cpu/x86/runtime_x86_64.cpp +++ b/src/hotspot/cpu/x86/runtime_x86_64.cpp @@ -34,11 +34,328 @@ #include "runtime/vframeArray.hpp" #include "utilities/globalDefinitions.hpp" #include "vmreg_x86.inline.hpp" + +class SimpleRuntimeFrame { + + public: + + // Most of the runtime stubs have this simple frame layout. + // This class exists to make the layout shared in one place. + // Offsets are for compiler stack slots, which are jints. + enum layout { + // The frame sender code expects that rbp will be in the "natural" place and + // will override any oopMap setting for it. We must therefore force the layout + // so that it agrees with the frame sender code. + rbp_off = frame::arg_reg_save_area_bytes/BytesPerInt, + rbp_off2, + return_off, return_off2, + framesize + }; +}; + +#define __ masm-> + +//------------------------------generate_uncommon_trap_blob-------------------- +void OptoRuntime::generate_uncommon_trap_blob() { + // Allocate space for the code + ResourceMark rm; + // Setup code generation tools + CodeBuffer buffer("uncommon_trap_blob", 2048, 1024); + MacroAssembler* masm = new MacroAssembler(&buffer); + + assert(SimpleRuntimeFrame::framesize % 4 == 0, "sp not 16-byte aligned"); + + address start = __ pc(); + + // Push self-frame. We get here with a return address on the + // stack, so rsp is 8-byte aligned until we allocate our frame. + __ subptr(rsp, SimpleRuntimeFrame::return_off << LogBytesPerInt); // Epilog! + + // No callee saved registers. rbp is assumed implicitly saved + __ movptr(Address(rsp, SimpleRuntimeFrame::rbp_off << LogBytesPerInt), rbp); + + // compiler left unloaded_class_index in j_rarg0 move to where the + // runtime expects it. + __ movl(c_rarg1, j_rarg0); + + __ set_last_Java_frame(noreg, noreg, nullptr, rscratch1); + + // Call C code. Need thread but NOT official VM entry + // crud. We cannot block on this call, no GC can happen. Call should + // capture callee-saved registers as well as return values. + // Thread is in rdi already. + // + // UnrollBlock* uncommon_trap(JavaThread* thread, jint unloaded_class_index); + + __ mov(c_rarg0, r15_thread); + __ movl(c_rarg2, Deoptimization::Unpack_uncommon_trap); + __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, Deoptimization::uncommon_trap))); + + // Set an oopmap for the call site + OopMapSet* oop_maps = new OopMapSet(); + OopMap* map = new OopMap(SimpleRuntimeFrame::framesize, 0); + + // location of rbp is known implicitly by the frame sender code + + oop_maps->add_gc_map(__ pc() - start, map); + + __ reset_last_Java_frame(false); + + // Load UnrollBlock* into rdi + __ mov(rdi, rax); + +#ifdef ASSERT + { Label L; + __ cmpptr(Address(rdi, Deoptimization::UnrollBlock::unpack_kind_offset()), + Deoptimization::Unpack_uncommon_trap); + __ jcc(Assembler::equal, L); + __ stop("OptoRuntime::generate_uncommon_trap_blob: expected Unpack_uncommon_trap"); + __ bind(L); + } #endif + // Pop all the frames we must move/replace. + // + // Frame picture (youngest to oldest) + // 1: self-frame (no frame link) + // 2: deopting frame (no frame link) + // 3: caller of deopting frame (could be compiled/interpreted). + + // Pop self-frame. We have no frame, and must rely only on rax and rsp. + __ addptr(rsp, (SimpleRuntimeFrame::framesize - 2) << LogBytesPerInt); // Epilog! + + // Pop deoptimized frame (int) + __ movl(rcx, Address(rdi, + Deoptimization::UnrollBlock:: + size_of_deoptimized_frame_offset())); + __ addptr(rsp, rcx); + + // rsp should be pointing at the return address to the caller (3) + + // Pick up the initial fp we should save + // restore rbp before stack bang because if stack overflow is thrown it needs to be pushed (and preserved) + __ movptr(rbp, Address(rdi, Deoptimization::UnrollBlock::initial_info_offset())); + +#ifdef ASSERT + // Compilers generate code that bang the stack by as much as the + // interpreter would need. So this stack banging should never + // trigger a fault. Verify that it does not on non product builds. + __ movl(rbx, Address(rdi ,Deoptimization::UnrollBlock::total_frame_sizes_offset())); + __ bang_stack_size(rbx, rcx); +#endif + + // Load address of array of frame pcs into rcx (address*) + __ movptr(rcx, Address(rdi, Deoptimization::UnrollBlock::frame_pcs_offset())); + + // Trash the return pc + __ addptr(rsp, wordSize); + + // Load address of array of frame sizes into rsi (intptr_t*) + __ movptr(rsi, Address(rdi, Deoptimization::UnrollBlock:: frame_sizes_offset())); + + // Counter + __ movl(rdx, Address(rdi, Deoptimization::UnrollBlock:: number_of_frames_offset())); // (int) + + // Now adjust the caller's stack to make up for the extra locals but + // record the original sp so that we can save it in the skeletal + // interpreter frame and the stack walking of interpreter_sender + // will get the unextended sp value and not the "real" sp value. + + const Register sender_sp = r8; + + __ mov(sender_sp, rsp); + __ movl(rbx, Address(rdi, Deoptimization::UnrollBlock:: caller_adjustment_offset())); // (int) + __ subptr(rsp, rbx); + + // Push interpreter frames in a loop + Label loop; + __ bind(loop); + __ movptr(rbx, Address(rsi, 0)); // Load frame size + __ subptr(rbx, 2 * wordSize); // We'll push pc and rbp by hand + __ pushptr(Address(rcx, 0)); // Save return address + __ enter(); // Save old & set new rbp + __ subptr(rsp, rbx); // Prolog + __ movptr(Address(rbp, frame::interpreter_frame_sender_sp_offset * wordSize), + sender_sp); // Make it walkable + // This value is corrected by layout_activation_impl + __ movptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), NULL_WORD); + __ mov(sender_sp, rsp); // Pass sender_sp to next frame + __ addptr(rsi, wordSize); // Bump array pointer (sizes) + __ addptr(rcx, wordSize); // Bump array pointer (pcs) + __ decrementl(rdx); // Decrement counter + __ jcc(Assembler::notZero, loop); + __ pushptr(Address(rcx, 0)); // Save final return address + + // Re-push self-frame + __ enter(); // Save old & set new rbp + __ subptr(rsp, (SimpleRuntimeFrame::framesize - 4) << LogBytesPerInt); + // Prolog + + // Use rbp because the frames look interpreted now + // Save "the_pc" since it cannot easily be retrieved using the last_java_SP after we aligned SP. + // Don't need the precise return PC here, just precise enough to point into this code blob. + address the_pc = __ pc(); + __ set_last_Java_frame(noreg, rbp, the_pc, rscratch1); + + // Call C code. Need thread but NOT official VM entry + // crud. We cannot block on this call, no GC can happen. Call should + // restore return values to their stack-slots with the new SP. + // Thread is in rdi already. + // + // BasicType unpack_frames(JavaThread* thread, int exec_mode); + + __ andptr(rsp, -(StackAlignmentInBytes)); // Align SP as required by ABI + __ mov(c_rarg0, r15_thread); + __ movl(c_rarg1, Deoptimization::Unpack_uncommon_trap); + __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, Deoptimization::unpack_frames))); + + // Set an oopmap for the call site + // Use the same PC we used for the last java frame + oop_maps->add_gc_map(the_pc - start, new OopMap(SimpleRuntimeFrame::framesize, 0)); + + // Clear fp AND pc + __ reset_last_Java_frame(true); + + // Pop self-frame. + __ leave(); // Epilog + + // Jump to interpreter + __ ret(0); + + // Make sure all code is generated + masm->flush(); + + _uncommon_trap_blob = UncommonTrapBlob::create(&buffer, oop_maps, + SimpleRuntimeFrame::framesize >> 1); +} + +//------------------------------generate_exception_blob--------------------------- +// creates exception blob at the end +// Using exception blob, this code is jumped from a compiled method. +// (see emit_exception_handler in x86_64.ad file) +// +// Given an exception pc at a call we call into the runtime for the +// handler in this method. This handler might merely restore state +// (i.e. callee save registers) unwind the frame and jump to the +// exception handler for the nmethod if there is no Java level handler +// for the nmethod. +// +// This code is entered with a jmp. +// +// Arguments: +// rax: exception oop +// rdx: exception pc +// +// Results: +// rax: exception oop +// rdx: exception pc in caller or ??? +// destination: exception handler of caller +// +// Note: the exception pc MUST be at a call (precise debug information) +// Registers rax, rdx, rcx, rsi, rdi, r8-r11 are not callee saved. +// + +void OptoRuntime::generate_exception_blob() { + assert(!OptoRuntime::is_callee_saved_register(RDX_num), ""); + assert(!OptoRuntime::is_callee_saved_register(RAX_num), ""); + assert(!OptoRuntime::is_callee_saved_register(RCX_num), ""); + + assert(SimpleRuntimeFrame::framesize % 4 == 0, "sp not 16-byte aligned"); + + // Allocate space for the code + ResourceMark rm; + // Setup code generation tools + CodeBuffer buffer("exception_blob", 2048, 1024); + MacroAssembler* masm = new MacroAssembler(&buffer); + + + address start = __ pc(); + + // Exception pc is 'return address' for stack walker + __ push(rdx); + __ subptr(rsp, SimpleRuntimeFrame::return_off << LogBytesPerInt); // Prolog + + // Save callee-saved registers. See x86_64.ad. + + // rbp is an implicitly saved callee saved register (i.e., the calling + // convention will save/restore it in the prolog/epilog). Other than that + // there are no callee save registers now that adapter frames are gone. + + __ movptr(Address(rsp, SimpleRuntimeFrame::rbp_off << LogBytesPerInt), rbp); + + // Store exception in Thread object. We cannot pass any arguments to the + // handle_exception call, since we do not want to make any assumption + // about the size of the frame where the exception happened in. + // c_rarg0 is either rdi (Linux) or rcx (Windows). + __ movptr(Address(r15_thread, JavaThread::exception_oop_offset()),rax); + __ movptr(Address(r15_thread, JavaThread::exception_pc_offset()), rdx); + + // This call does all the hard work. It checks if an exception handler + // exists in the method. + // If so, it returns the handler address. + // If not, it prepares for stack-unwinding, restoring the callee-save + // registers of the frame being removed. + // + // address OptoRuntime::handle_exception_C(JavaThread* thread) + + // At a method handle call, the stack may not be properly aligned + // when returning with an exception. + address the_pc = __ pc(); + __ set_last_Java_frame(noreg, noreg, the_pc, rscratch1); + __ mov(c_rarg0, r15_thread); + __ andptr(rsp, -(StackAlignmentInBytes)); // Align stack + __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, OptoRuntime::handle_exception_C))); + + // Set an oopmap for the call site. This oopmap will only be used if we + // are unwinding the stack. Hence, all locations will be dead. + // Callee-saved registers will be the same as the frame above (i.e., + // handle_exception_stub), since they were restored when we got the + // exception. + + OopMapSet* oop_maps = new OopMapSet(); + + oop_maps->add_gc_map(the_pc - start, new OopMap(SimpleRuntimeFrame::framesize, 0)); + + __ reset_last_Java_frame(false); + + // Restore callee-saved registers + + // rbp is an implicitly saved callee-saved register (i.e., the calling + // convention will save restore it in prolog/epilog) Other than that + // there are no callee save registers now that adapter frames are gone. + + __ movptr(rbp, Address(rsp, SimpleRuntimeFrame::rbp_off << LogBytesPerInt)); + + __ addptr(rsp, SimpleRuntimeFrame::return_off << LogBytesPerInt); // Epilog + __ pop(rdx); // No need for exception pc anymore + + // rax: exception handler + + // We have a handler in rax (could be deopt blob). + __ mov(r8, rax); + + // Get the exception oop + __ movptr(rax, Address(r15_thread, JavaThread::exception_oop_offset())); + // Get the exception pc in case we are deoptimized + __ movptr(rdx, Address(r15_thread, JavaThread::exception_pc_offset())); +#ifdef ASSERT + __ movptr(Address(r15_thread, JavaThread::exception_handler_pc_offset()), NULL_WORD); + __ movptr(Address(r15_thread, JavaThread::exception_pc_offset()), NULL_WORD); +#endif + // Clear the exception oop so GC no longer processes it as a root. + __ movptr(Address(r15_thread, JavaThread::exception_oop_offset()), NULL_WORD); + + // rax: exception oop + // r8: exception handler + // rdx: exception pc + // Jump to handler + + __ jmp(r8); + + // Make sure all code is generated + masm->flush(); -// This file should really contain the code for generating the OptoRuntime -// exception_blob. However that code uses SimpleRuntimeFrame which only -// exists in sharedRuntime_x86_64.cpp. When there is a sharedRuntime_.hpp -// file and SimpleRuntimeFrame is able to move there then the exception_blob -// code will move here where it belongs. + // Set exception blob + _exception_blob = ExceptionBlob::create(&buffer, oop_maps, SimpleRuntimeFrame::framesize >> 1); +} +#endif // COMPILER2 diff --git a/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp b/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp index 6303c279195ca..80be7c7d5b642 100644 --- a/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp +++ b/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp @@ -2389,183 +2389,6 @@ void SharedRuntime::generate_deopt_blob() { _deopt_blob->set_unpack_with_exception_in_tls_offset(exception_in_tls_offset); } - -#ifdef COMPILER2 -//------------------------------generate_uncommon_trap_blob-------------------- -void SharedRuntime::generate_uncommon_trap_blob() { - // allocate space for the code - ResourceMark rm; - // setup code generation tools - CodeBuffer buffer("uncommon_trap_blob", 512, 512); - MacroAssembler* masm = new MacroAssembler(&buffer); - - enum frame_layout { - arg0_off, // thread sp + 0 // Arg location for - arg1_off, // unloaded_class_index sp + 1 // calling C - arg2_off, // exec_mode sp + 2 - // The frame sender code expects that rbp will be in the "natural" place and - // will override any oopMap setting for it. We must therefore force the layout - // so that it agrees with the frame sender code. - rbp_off, // callee saved register sp + 3 - return_off, // slot for return address sp + 4 - framesize - }; - - address start = __ pc(); - - // Push self-frame. - __ subptr(rsp, return_off*wordSize); // Epilog! - - // rbp, is an implicitly saved callee saved register (i.e. the calling - // convention will save restore it in prolog/epilog) Other than that - // there are no callee save registers no that adapter frames are gone. - __ movptr(Address(rsp, rbp_off*wordSize), rbp); - - // Clear the floating point exception stack - __ empty_FPU_stack(); - - // set last_Java_sp - __ get_thread(rdx); - __ set_last_Java_frame(rdx, noreg, noreg, nullptr, noreg); - - // Call C code. Need thread but NOT official VM entry - // crud. We cannot block on this call, no GC can happen. Call should - // capture callee-saved registers as well as return values. - __ movptr(Address(rsp, arg0_off*wordSize), rdx); - // argument already in ECX - __ movl(Address(rsp, arg1_off*wordSize),rcx); - __ movl(Address(rsp, arg2_off*wordSize), Deoptimization::Unpack_uncommon_trap); - __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, Deoptimization::uncommon_trap))); - - // Set an oopmap for the call site - OopMapSet *oop_maps = new OopMapSet(); - OopMap* map = new OopMap( framesize, 0 ); - // No oopMap for rbp, it is known implicitly - - oop_maps->add_gc_map( __ pc()-start, map); - - __ get_thread(rcx); - - __ reset_last_Java_frame(rcx, false); - - // Load UnrollBlock into EDI - __ movptr(rdi, rax); - -#ifdef ASSERT - { Label L; - __ cmpptr(Address(rdi, Deoptimization::UnrollBlock::unpack_kind_offset()), - (int32_t)Deoptimization::Unpack_uncommon_trap); - __ jcc(Assembler::equal, L); - __ stop("SharedRuntime::generate_uncommon_trap_blob: expected Unpack_uncommon_trap"); - __ bind(L); - } -#endif - - // Pop all the frames we must move/replace. - // - // Frame picture (youngest to oldest) - // 1: self-frame (no frame link) - // 2: deopting frame (no frame link) - // 3: caller of deopting frame (could be compiled/interpreted). - - // Pop self-frame. We have no frame, and must rely only on EAX and ESP. - __ addptr(rsp,(framesize-1)*wordSize); // Epilog! - - // Pop deoptimized frame - __ movl2ptr(rcx, Address(rdi,Deoptimization::UnrollBlock::size_of_deoptimized_frame_offset())); - __ addptr(rsp, rcx); - - // sp should be pointing at the return address to the caller (3) - - // Pick up the initial fp we should save - // restore rbp before stack bang because if stack overflow is thrown it needs to be pushed (and preserved) - __ movptr(rbp, Address(rdi, Deoptimization::UnrollBlock::initial_info_offset())); - -#ifdef ASSERT - // Compilers generate code that bang the stack by as much as the - // interpreter would need. So this stack banging should never - // trigger a fault. Verify that it does not on non product builds. - __ movl(rbx, Address(rdi ,Deoptimization::UnrollBlock::total_frame_sizes_offset())); - __ bang_stack_size(rbx, rcx); -#endif - - // Load array of frame pcs into ECX - __ movl(rcx,Address(rdi,Deoptimization::UnrollBlock::frame_pcs_offset())); - - __ pop(rsi); // trash the pc - - // Load array of frame sizes into ESI - __ movptr(rsi,Address(rdi,Deoptimization::UnrollBlock::frame_sizes_offset())); - - Address counter(rdi, Deoptimization::UnrollBlock::counter_temp_offset()); - - __ movl(rbx, Address(rdi, Deoptimization::UnrollBlock::number_of_frames_offset())); - __ movl(counter, rbx); - - // Now adjust the caller's stack to make up for the extra locals - // but record the original sp so that we can save it in the skeletal interpreter - // frame and the stack walking of interpreter_sender will get the unextended sp - // value and not the "real" sp value. - - Address sp_temp(rdi, Deoptimization::UnrollBlock::sender_sp_temp_offset()); - __ movptr(sp_temp, rsp); - __ movl(rbx, Address(rdi, Deoptimization::UnrollBlock::caller_adjustment_offset())); - __ subptr(rsp, rbx); - - // Push interpreter frames in a loop - Label loop; - __ bind(loop); - __ movptr(rbx, Address(rsi, 0)); // Load frame size - __ subptr(rbx, 2*wordSize); // we'll push pc and rbp, by hand - __ pushptr(Address(rcx, 0)); // save return address - __ enter(); // save old & set new rbp, - __ subptr(rsp, rbx); // Prolog! - __ movptr(rbx, sp_temp); // sender's sp - // This value is corrected by layout_activation_impl - __ movptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), NULL_WORD ); - __ movptr(Address(rbp, frame::interpreter_frame_sender_sp_offset * wordSize), rbx); // Make it walkable - __ movptr(sp_temp, rsp); // pass to next frame - __ addptr(rsi, wordSize); // Bump array pointer (sizes) - __ addptr(rcx, wordSize); // Bump array pointer (pcs) - __ decrementl(counter); // decrement counter - __ jcc(Assembler::notZero, loop); - __ pushptr(Address(rcx, 0)); // save final return address - - // Re-push self-frame - __ enter(); // save old & set new rbp, - __ subptr(rsp, (framesize-2) * wordSize); // Prolog! - - - // set last_Java_sp, last_Java_fp - __ get_thread(rdi); - __ set_last_Java_frame(rdi, noreg, rbp, nullptr, noreg); - - // Call C code. Need thread but NOT official VM entry - // crud. We cannot block on this call, no GC can happen. Call should - // restore return values to their stack-slots with the new SP. - __ movptr(Address(rsp,arg0_off*wordSize),rdi); - __ movl(Address(rsp,arg1_off*wordSize), Deoptimization::Unpack_uncommon_trap); - __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, Deoptimization::unpack_frames))); - // Set an oopmap for the call site - oop_maps->add_gc_map( __ pc()-start, new OopMap( framesize, 0 ) ); - - __ get_thread(rdi); - __ reset_last_Java_frame(rdi, true); - - // Pop self-frame. - __ leave(); // Epilog! - - // Jump to interpreter - __ ret(0); - - // ------------- - // make sure all code is generated - masm->flush(); - - _uncommon_trap_blob = UncommonTrapBlob::create(&buffer, oop_maps, framesize); -} -#endif // COMPILER2 - //------------------------------generate_handler_blob------ // // Generate a special Compile2Runtime blob that saves all registers, diff --git a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp index decaa9d1ee914..f2488ef4e7445 100644 --- a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp +++ b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp @@ -72,24 +72,6 @@ const int StackAlignmentInSlots = StackAlignmentInBytes / VMRegImpl::stack_slot_size; -class SimpleRuntimeFrame { - - public: - - // Most of the runtime stubs have this simple frame layout. - // This class exists to make the layout shared in one place. - // Offsets are for compiler stack slots, which are jints. - enum layout { - // The frame sender code expects that rbp will be in the "natural" place and - // will override any oopMap setting for it. We must therefore force the layout - // so that it agrees with the frame sender code. - rbp_off = frame::arg_reg_save_area_bytes/BytesPerInt, - rbp_off2, - return_off, return_off2, - framesize - }; -}; - class RegisterSaver { // Capture info about frame layout. Layout offsets are in jint // units because compiler frame slots are jints. @@ -2987,182 +2969,6 @@ void SharedRuntime::generate_deopt_blob() { #endif } -#ifdef COMPILER2 -//------------------------------generate_uncommon_trap_blob-------------------- -void SharedRuntime::generate_uncommon_trap_blob() { - // Allocate space for the code - ResourceMark rm; - // Setup code generation tools - CodeBuffer buffer("uncommon_trap_blob", 2048, 1024); - MacroAssembler* masm = new MacroAssembler(&buffer); - - assert(SimpleRuntimeFrame::framesize % 4 == 0, "sp not 16-byte aligned"); - - address start = __ pc(); - - // Push self-frame. We get here with a return address on the - // stack, so rsp is 8-byte aligned until we allocate our frame. - __ subptr(rsp, SimpleRuntimeFrame::return_off << LogBytesPerInt); // Epilog! - - // No callee saved registers. rbp is assumed implicitly saved - __ movptr(Address(rsp, SimpleRuntimeFrame::rbp_off << LogBytesPerInt), rbp); - - // compiler left unloaded_class_index in j_rarg0 move to where the - // runtime expects it. - __ movl(c_rarg1, j_rarg0); - - __ set_last_Java_frame(noreg, noreg, nullptr, rscratch1); - - // Call C code. Need thread but NOT official VM entry - // crud. We cannot block on this call, no GC can happen. Call should - // capture callee-saved registers as well as return values. - // Thread is in rdi already. - // - // UnrollBlock* uncommon_trap(JavaThread* thread, jint unloaded_class_index); - - __ mov(c_rarg0, r15_thread); - __ movl(c_rarg2, Deoptimization::Unpack_uncommon_trap); - __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, Deoptimization::uncommon_trap))); - - // Set an oopmap for the call site - OopMapSet* oop_maps = new OopMapSet(); - OopMap* map = new OopMap(SimpleRuntimeFrame::framesize, 0); - - // location of rbp is known implicitly by the frame sender code - - oop_maps->add_gc_map(__ pc() - start, map); - - __ reset_last_Java_frame(false); - - // Load UnrollBlock* into rdi - __ mov(rdi, rax); - -#ifdef ASSERT - { Label L; - __ cmpptr(Address(rdi, Deoptimization::UnrollBlock::unpack_kind_offset()), - Deoptimization::Unpack_uncommon_trap); - __ jcc(Assembler::equal, L); - __ stop("SharedRuntime::generate_uncommon_trap_blob: expected Unpack_uncommon_trap"); - __ bind(L); - } -#endif - - // Pop all the frames we must move/replace. - // - // Frame picture (youngest to oldest) - // 1: self-frame (no frame link) - // 2: deopting frame (no frame link) - // 3: caller of deopting frame (could be compiled/interpreted). - - // Pop self-frame. We have no frame, and must rely only on rax and rsp. - __ addptr(rsp, (SimpleRuntimeFrame::framesize - 2) << LogBytesPerInt); // Epilog! - - // Pop deoptimized frame (int) - __ movl(rcx, Address(rdi, - Deoptimization::UnrollBlock:: - size_of_deoptimized_frame_offset())); - __ addptr(rsp, rcx); - - // rsp should be pointing at the return address to the caller (3) - - // Pick up the initial fp we should save - // restore rbp before stack bang because if stack overflow is thrown it needs to be pushed (and preserved) - __ movptr(rbp, Address(rdi, Deoptimization::UnrollBlock::initial_info_offset())); - -#ifdef ASSERT - // Compilers generate code that bang the stack by as much as the - // interpreter would need. So this stack banging should never - // trigger a fault. Verify that it does not on non product builds. - __ movl(rbx, Address(rdi ,Deoptimization::UnrollBlock::total_frame_sizes_offset())); - __ bang_stack_size(rbx, rcx); -#endif - - // Load address of array of frame pcs into rcx (address*) - __ movptr(rcx, Address(rdi, Deoptimization::UnrollBlock::frame_pcs_offset())); - - // Trash the return pc - __ addptr(rsp, wordSize); - - // Load address of array of frame sizes into rsi (intptr_t*) - __ movptr(rsi, Address(rdi, Deoptimization::UnrollBlock:: frame_sizes_offset())); - - // Counter - __ movl(rdx, Address(rdi, Deoptimization::UnrollBlock:: number_of_frames_offset())); // (int) - - // Now adjust the caller's stack to make up for the extra locals but - // record the original sp so that we can save it in the skeletal - // interpreter frame and the stack walking of interpreter_sender - // will get the unextended sp value and not the "real" sp value. - - const Register sender_sp = r8; - - __ mov(sender_sp, rsp); - __ movl(rbx, Address(rdi, Deoptimization::UnrollBlock:: caller_adjustment_offset())); // (int) - __ subptr(rsp, rbx); - - // Push interpreter frames in a loop - Label loop; - __ bind(loop); - __ movptr(rbx, Address(rsi, 0)); // Load frame size - __ subptr(rbx, 2 * wordSize); // We'll push pc and rbp by hand - __ pushptr(Address(rcx, 0)); // Save return address - __ enter(); // Save old & set new rbp - __ subptr(rsp, rbx); // Prolog - __ movptr(Address(rbp, frame::interpreter_frame_sender_sp_offset * wordSize), - sender_sp); // Make it walkable - // This value is corrected by layout_activation_impl - __ movptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), NULL_WORD); - __ mov(sender_sp, rsp); // Pass sender_sp to next frame - __ addptr(rsi, wordSize); // Bump array pointer (sizes) - __ addptr(rcx, wordSize); // Bump array pointer (pcs) - __ decrementl(rdx); // Decrement counter - __ jcc(Assembler::notZero, loop); - __ pushptr(Address(rcx, 0)); // Save final return address - - // Re-push self-frame - __ enter(); // Save old & set new rbp - __ subptr(rsp, (SimpleRuntimeFrame::framesize - 4) << LogBytesPerInt); - // Prolog - - // Use rbp because the frames look interpreted now - // Save "the_pc" since it cannot easily be retrieved using the last_java_SP after we aligned SP. - // Don't need the precise return PC here, just precise enough to point into this code blob. - address the_pc = __ pc(); - __ set_last_Java_frame(noreg, rbp, the_pc, rscratch1); - - // Call C code. Need thread but NOT official VM entry - // crud. We cannot block on this call, no GC can happen. Call should - // restore return values to their stack-slots with the new SP. - // Thread is in rdi already. - // - // BasicType unpack_frames(JavaThread* thread, int exec_mode); - - __ andptr(rsp, -(StackAlignmentInBytes)); // Align SP as required by ABI - __ mov(c_rarg0, r15_thread); - __ movl(c_rarg1, Deoptimization::Unpack_uncommon_trap); - __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, Deoptimization::unpack_frames))); - - // Set an oopmap for the call site - // Use the same PC we used for the last java frame - oop_maps->add_gc_map(the_pc - start, new OopMap(SimpleRuntimeFrame::framesize, 0)); - - // Clear fp AND pc - __ reset_last_Java_frame(true); - - // Pop self-frame. - __ leave(); // Epilog - - // Jump to interpreter - __ ret(0); - - // Make sure all code is generated - masm->flush(); - - _uncommon_trap_blob = UncommonTrapBlob::create(&buffer, oop_maps, - SimpleRuntimeFrame::framesize >> 1); -} -#endif // COMPILER2 - //------------------------------generate_handler_blob------ // // Generate a special Compile2Runtime blob that saves all registers, @@ -3669,136 +3475,3 @@ void SharedRuntime::montgomery_square(jint *a_ints, jint *n_ints, reverse_words(m, (julong *)m_ints, longwords); } -#ifdef COMPILER2 -// This is here instead of runtime_x86_64.cpp because it uses SimpleRuntimeFrame -// -//------------------------------generate_exception_blob--------------------------- -// creates exception blob at the end -// Using exception blob, this code is jumped from a compiled method. -// (see emit_exception_handler in x86_64.ad file) -// -// Given an exception pc at a call we call into the runtime for the -// handler in this method. This handler might merely restore state -// (i.e. callee save registers) unwind the frame and jump to the -// exception handler for the nmethod if there is no Java level handler -// for the nmethod. -// -// This code is entered with a jmp. -// -// Arguments: -// rax: exception oop -// rdx: exception pc -// -// Results: -// rax: exception oop -// rdx: exception pc in caller or ??? -// destination: exception handler of caller -// -// Note: the exception pc MUST be at a call (precise debug information) -// Registers rax, rdx, rcx, rsi, rdi, r8-r11 are not callee saved. -// - -void OptoRuntime::generate_exception_blob() { - assert(!OptoRuntime::is_callee_saved_register(RDX_num), ""); - assert(!OptoRuntime::is_callee_saved_register(RAX_num), ""); - assert(!OptoRuntime::is_callee_saved_register(RCX_num), ""); - - assert(SimpleRuntimeFrame::framesize % 4 == 0, "sp not 16-byte aligned"); - - // Allocate space for the code - ResourceMark rm; - // Setup code generation tools - CodeBuffer buffer("exception_blob", 2048, 1024); - MacroAssembler* masm = new MacroAssembler(&buffer); - - - address start = __ pc(); - - // Exception pc is 'return address' for stack walker - __ push(rdx); - __ subptr(rsp, SimpleRuntimeFrame::return_off << LogBytesPerInt); // Prolog - - // Save callee-saved registers. See x86_64.ad. - - // rbp is an implicitly saved callee saved register (i.e., the calling - // convention will save/restore it in the prolog/epilog). Other than that - // there are no callee save registers now that adapter frames are gone. - - __ movptr(Address(rsp, SimpleRuntimeFrame::rbp_off << LogBytesPerInt), rbp); - - // Store exception in Thread object. We cannot pass any arguments to the - // handle_exception call, since we do not want to make any assumption - // about the size of the frame where the exception happened in. - // c_rarg0 is either rdi (Linux) or rcx (Windows). - __ movptr(Address(r15_thread, JavaThread::exception_oop_offset()),rax); - __ movptr(Address(r15_thread, JavaThread::exception_pc_offset()), rdx); - - // This call does all the hard work. It checks if an exception handler - // exists in the method. - // If so, it returns the handler address. - // If not, it prepares for stack-unwinding, restoring the callee-save - // registers of the frame being removed. - // - // address OptoRuntime::handle_exception_C(JavaThread* thread) - - // At a method handle call, the stack may not be properly aligned - // when returning with an exception. - address the_pc = __ pc(); - __ set_last_Java_frame(noreg, noreg, the_pc, rscratch1); - __ mov(c_rarg0, r15_thread); - __ andptr(rsp, -(StackAlignmentInBytes)); // Align stack - __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, OptoRuntime::handle_exception_C))); - - // Set an oopmap for the call site. This oopmap will only be used if we - // are unwinding the stack. Hence, all locations will be dead. - // Callee-saved registers will be the same as the frame above (i.e., - // handle_exception_stub), since they were restored when we got the - // exception. - - OopMapSet* oop_maps = new OopMapSet(); - - oop_maps->add_gc_map(the_pc - start, new OopMap(SimpleRuntimeFrame::framesize, 0)); - - __ reset_last_Java_frame(false); - - // Restore callee-saved registers - - // rbp is an implicitly saved callee-saved register (i.e., the calling - // convention will save restore it in prolog/epilog) Other than that - // there are no callee save registers now that adapter frames are gone. - - __ movptr(rbp, Address(rsp, SimpleRuntimeFrame::rbp_off << LogBytesPerInt)); - - __ addptr(rsp, SimpleRuntimeFrame::return_off << LogBytesPerInt); // Epilog - __ pop(rdx); // No need for exception pc anymore - - // rax: exception handler - - // We have a handler in rax (could be deopt blob). - __ mov(r8, rax); - - // Get the exception oop - __ movptr(rax, Address(r15_thread, JavaThread::exception_oop_offset())); - // Get the exception pc in case we are deoptimized - __ movptr(rdx, Address(r15_thread, JavaThread::exception_pc_offset())); -#ifdef ASSERT - __ movptr(Address(r15_thread, JavaThread::exception_handler_pc_offset()), NULL_WORD); - __ movptr(Address(r15_thread, JavaThread::exception_pc_offset()), NULL_WORD); -#endif - // Clear the exception oop so GC no longer processes it as a root. - __ movptr(Address(r15_thread, JavaThread::exception_oop_offset()), NULL_WORD); - - // rax: exception oop - // r8: exception handler - // rdx: exception pc - // Jump to handler - - __ jmp(r8); - - // Make sure all code is generated - masm->flush(); - - // Set exception blob - _exception_blob = ExceptionBlob::create(&buffer, oop_maps, SimpleRuntimeFrame::framesize >> 1); -} -#endif // COMPILER2 diff --git a/src/hotspot/share/opto/graphKit.cpp b/src/hotspot/share/opto/graphKit.cpp index 569d6bc35cd16..3bc5b9a8b2a7d 100644 --- a/src/hotspot/share/opto/graphKit.cpp +++ b/src/hotspot/share/opto/graphKit.cpp @@ -2151,7 +2151,7 @@ Node* GraphKit::uncommon_trap(int trap_request, kill_dead_locals(); // Now insert the uncommon trap subroutine call - address call_addr = SharedRuntime::uncommon_trap_blob()->entry_point(); + address call_addr = OptoRuntime::uncommon_trap_blob()->entry_point(); const TypePtr* no_memory_effects = nullptr; // Pass the index of the class to be loaded Node* call = make_runtime_call(RC_NO_LEAF | RC_UNCOMMON | diff --git a/src/hotspot/share/opto/lcm.cpp b/src/hotspot/share/opto/lcm.cpp index 549290397e3b7..9db94748ca27c 100644 --- a/src/hotspot/share/opto/lcm.cpp +++ b/src/hotspot/share/opto/lcm.cpp @@ -122,7 +122,7 @@ void PhaseCFG::implicit_null_check(Block* block, Node *proj, Node *val, int allo for (uint i1 = 0; i1 < null_block->number_of_nodes(); i1++) { Node* nn = null_block->get_node(i1); if (nn->is_MachCall() && - nn->as_MachCall()->entry_point() == SharedRuntime::uncommon_trap_blob()->entry_point()) { + nn->as_MachCall()->entry_point() == OptoRuntime::uncommon_trap_blob()->entry_point()) { const Type* trtype = nn->in(TypeFunc::Parms)->bottom_type(); if (trtype->isa_int() && trtype->is_int()->is_con()) { jint tr_con = trtype->is_int()->get_con(); diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index f1c3e592fff53..9660413dd190f 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -5949,7 +5949,7 @@ CallStaticJavaNode* LibraryCallKit::get_uncommon_trap_from_success_proj(Node* no for (DUIterator_Fast jmax, j = other_proj->fast_outs(jmax); j < jmax; j++) { Node* obs = other_proj->fast_out(j); if (obs->in(0) == other_proj && obs->is_CallStaticJava() && - (obs->as_CallStaticJava()->entry_point() == SharedRuntime::uncommon_trap_blob()->entry_point())) { + (obs->as_CallStaticJava()->entry_point() == OptoRuntime::uncommon_trap_blob()->entry_point())) { return obs->as_CallStaticJava(); } } diff --git a/src/hotspot/share/opto/loopnode.cpp b/src/hotspot/share/opto/loopnode.cpp index 45e59f4e21680..b4c134570e63f 100644 --- a/src/hotspot/share/opto/loopnode.cpp +++ b/src/hotspot/share/opto/loopnode.cpp @@ -567,7 +567,7 @@ void PhaseIdealLoop::add_parse_predicate(Deoptimization::DeoptReason reason, Nod register_control(if_true, loop, parse_predicate); int trap_request = Deoptimization::make_trap_request(reason, Deoptimization::Action_maybe_recompile); - address call_addr = SharedRuntime::uncommon_trap_blob()->entry_point(); + address call_addr = OptoRuntime::uncommon_trap_blob()->entry_point(); const TypePtr* no_memory_effects = nullptr; JVMState* jvms = sfpt->jvms(); CallNode* unc = new CallStaticJavaNode(OptoRuntime::uncommon_trap_Type(), call_addr, "uncommon_trap", diff --git a/src/hotspot/share/opto/matcher.cpp b/src/hotspot/share/opto/matcher.cpp index 4c2f208e445c1..4e2306602e6f7 100644 --- a/src/hotspot/share/opto/matcher.cpp +++ b/src/hotspot/share/opto/matcher.cpp @@ -2960,7 +2960,7 @@ bool Matcher::branches_to_uncommon_trap(const Node *n) { } if (call && - call->entry_point() == SharedRuntime::uncommon_trap_blob()->entry_point()) { + call->entry_point() == OptoRuntime::uncommon_trap_blob()->entry_point()) { const Type* trtype = call->in(TypeFunc::Parms)->bottom_type(); if (trtype->isa_int() && trtype->is_int()->is_con()) { jint tr_con = trtype->is_int()->get_con(); diff --git a/src/hotspot/share/opto/runtime.cpp b/src/hotspot/share/opto/runtime.cpp index 465404bb4693f..54408146d0c26 100644 --- a/src/hotspot/share/opto/runtime.cpp +++ b/src/hotspot/share/opto/runtime.cpp @@ -114,7 +114,8 @@ address OptoRuntime::_notify_jvmti_vthread_mount = nullptr; address OptoRuntime::_notify_jvmti_vthread_unmount = nullptr; #endif -ExceptionBlob* OptoRuntime::_exception_blob; +UncommonTrapBlob* OptoRuntime::_uncommon_trap_blob; +ExceptionBlob* OptoRuntime::_exception_blob; // This should be called in an assertion at the start of OptoRuntime routines // which are entered from compiled code (all of them) @@ -138,6 +139,7 @@ static bool check_compiled_frame(JavaThread* thread) { bool OptoRuntime::generate(ciEnv* env) { + generate_uncommon_trap_blob(); generate_exception_blob(); // Note: tls: Means fetching the return oop out of the thread-local storage diff --git a/src/hotspot/share/opto/runtime.hpp b/src/hotspot/share/opto/runtime.hpp index 6aadab9712243..34c2780a2f8d7 100644 --- a/src/hotspot/share/opto/runtime.hpp +++ b/src/hotspot/share/opto/runtime.hpp @@ -168,7 +168,10 @@ class OptoRuntime : public AllStatic { // CodeBlob support // =================================================================== + static UncommonTrapBlob* _uncommon_trap_blob; static ExceptionBlob* _exception_blob; + + static void generate_uncommon_trap_blob(void); static void generate_exception_blob(); static void register_finalizer(oopDesc* obj, JavaThread* current); @@ -208,6 +211,7 @@ class OptoRuntime : public AllStatic { static address notify_jvmti_vthread_unmount() { return _notify_jvmti_vthread_unmount; } #endif + static UncommonTrapBlob* uncommon_trap_blob() { return _uncommon_trap_blob; } static ExceptionBlob* exception_blob() { return _exception_blob; } // Implicit exception support diff --git a/src/hotspot/share/opto/stringopts.cpp b/src/hotspot/share/opto/stringopts.cpp index 2e227be765cfa..7bf75c93055a5 100644 --- a/src/hotspot/share/opto/stringopts.cpp +++ b/src/hotspot/share/opto/stringopts.cpp @@ -203,7 +203,7 @@ class StringConcat : public ResourceObj { Node* uct = _uncommon_traps.at(u); // Build a new call using the jvms state of the allocate - address call_addr = SharedRuntime::uncommon_trap_blob()->entry_point(); + address call_addr = OptoRuntime::uncommon_trap_blob()->entry_point(); const TypeFunc* call_type = OptoRuntime::uncommon_trap_Type(); const TypePtr* no_memory_effects = nullptr; Compile* C = _stringopts->C; diff --git a/src/hotspot/share/runtime/sharedRuntime.cpp b/src/hotspot/share/runtime/sharedRuntime.cpp index 0e6d367586b9d..0eec7e4c34cae 100644 --- a/src/hotspot/share/runtime/sharedRuntime.cpp +++ b/src/hotspot/share/runtime/sharedRuntime.cpp @@ -100,10 +100,6 @@ SafepointBlob* SharedRuntime::_polling_page_vectors_safepoint_handler_blob; SafepointBlob* SharedRuntime::_polling_page_safepoint_handler_blob; SafepointBlob* SharedRuntime::_polling_page_return_handler_blob; -#ifdef COMPILER2 -UncommonTrapBlob* SharedRuntime::_uncommon_trap_blob; -#endif // COMPILER2 - nmethod* SharedRuntime::_cont_doYield_stub; //----------------------------generate_stubs----------------------------------- @@ -129,10 +125,6 @@ void SharedRuntime::generate_stubs() { _polling_page_return_handler_blob = generate_handler_blob(CAST_FROM_FN_PTR(address, SafepointSynchronize::handle_polling_page_exception), POLL_AT_RETURN); generate_deopt_blob(); - -#ifdef COMPILER2 - generate_uncommon_trap_blob(); -#endif // COMPILER2 } #include diff --git a/src/hotspot/share/runtime/sharedRuntime.hpp b/src/hotspot/share/runtime/sharedRuntime.hpp index da61883b2fe64..9eec8e079ec34 100644 --- a/src/hotspot/share/runtime/sharedRuntime.hpp +++ b/src/hotspot/share/runtime/sharedRuntime.hpp @@ -62,10 +62,6 @@ class SharedRuntime: AllStatic { static SafepointBlob* _polling_page_safepoint_handler_blob; static SafepointBlob* _polling_page_return_handler_blob; -#ifdef COMPILER2 - static UncommonTrapBlob* _uncommon_trap_blob; -#endif // COMPILER2 - static nmethod* _cont_doYield_stub; #ifndef PRODUCT @@ -223,11 +219,6 @@ class SharedRuntime: AllStatic { return _wrong_method_abstract_blob->entry_point(); } -#ifdef COMPILER2 - static void generate_uncommon_trap_blob(void); - static UncommonTrapBlob* uncommon_trap_blob() { return _uncommon_trap_blob; } -#endif // COMPILER2 - static address get_resolve_opt_virtual_call_stub() { assert(_resolve_opt_virtual_call_blob != nullptr, "oops"); return _resolve_opt_virtual_call_blob->entry_point(); From 53db937dd0766695906dc20c1dbbd3228c02fe1e Mon Sep 17 00:00:00 2001 From: Feilong Jiang Date: Tue, 6 Aug 2024 14:01:23 +0000 Subject: [PATCH 210/353] 8337780: RISC-V: C2: Change C calling convention for sp to NS Reviewed-by: fyang, rehn --- src/hotspot/cpu/riscv/riscv.ad | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/cpu/riscv/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad index b176c6e9cb7c2..1e26c2bf14202 100644 --- a/src/hotspot/cpu/riscv/riscv.ad +++ b/src/hotspot/cpu/riscv/riscv.ad @@ -84,8 +84,8 @@ reg_def R0 ( NS, NS, Op_RegI, 0, x0->as_VMReg() ); // zr reg_def R0_H ( NS, NS, Op_RegI, 0, x0->as_VMReg()->next() ); reg_def R1 ( NS, SOC, Op_RegI, 1, x1->as_VMReg() ); // ra reg_def R1_H ( NS, SOC, Op_RegI, 1, x1->as_VMReg()->next() ); -reg_def R2 ( NS, SOE, Op_RegI, 2, x2->as_VMReg() ); // sp -reg_def R2_H ( NS, SOE, Op_RegI, 2, x2->as_VMReg()->next() ); +reg_def R2 ( NS, NS, Op_RegI, 2, x2->as_VMReg() ); // sp +reg_def R2_H ( NS, NS, Op_RegI, 2, x2->as_VMReg()->next() ); reg_def R3 ( NS, NS, Op_RegI, 3, x3->as_VMReg() ); // gp reg_def R3_H ( NS, NS, Op_RegI, 3, x3->as_VMReg()->next() ); reg_def R4 ( NS, NS, Op_RegI, 4, x4->as_VMReg() ); // tp From 3f8b3e55276336cbb814d3b746d4337678389969 Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Tue, 6 Aug 2024 16:37:59 +0000 Subject: [PATCH 211/353] 8337887: [JVMCI] Clarify jdk.vm.ci.code.Architecture.getName javadoc Reviewed-by: never --- .../share/classes/jdk/vm/ci/aarch64/AArch64.java | 2 ++ .../share/classes/jdk/vm/ci/amd64/AMD64.java | 2 ++ .../share/classes/jdk/vm/ci/code/Architecture.java | 13 +++++++++---- .../share/classes/jdk/vm/ci/riscv64/RISCV64.java | 2 ++ 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/aarch64/AArch64.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/aarch64/AArch64.java index 609e01a8db154..c0d6c4cdb84ee 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/aarch64/AArch64.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/aarch64/AArch64.java @@ -35,6 +35,8 @@ /** * Represents the AArch64 architecture. + * + * The value returned by {@code Architecture#getName} for an instance of this class is {@code "aarch64"}. */ public class AArch64 extends Architecture { diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/amd64/AMD64.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/amd64/AMD64.java index 83401fed62033..f0ca7a2fc2359 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/amd64/AMD64.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/amd64/AMD64.java @@ -40,6 +40,8 @@ /** * Represents the AMD64 architecture. + * + * The value returned by {@code Architecture#getName} for an instance of this class is {@code "AMD64"}. */ public class AMD64 extends Architecture { diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/Architecture.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/Architecture.java index f14855cd6b995..64b0600674fd6 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/Architecture.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/Architecture.java @@ -107,7 +107,7 @@ protected Architecture(String name, PlatformKind wordKind, ByteOrder byteOrder, /** * Converts this architecture to a string. * - * @return the string representation of this architecture + * @return a lowercase version of {@linkplain #getName name} */ @Override public final String toString() { @@ -126,9 +126,14 @@ public PlatformKind getWordKind() { return wordKind; } - /** - * Gets the name of this architecture. - */ + /// Gets the name of this architecture. The value returned for + /// each architecture is shown in the table below. + /// + /// | Name | Receiver type | + /// |-----------|-----------------------------| + /// | "aarch64" | [jdk.vm.ci.aarch64.AArch64] | + /// | "AMD64" | [jdk.vm.ci.amd64.AMD64] | + /// | "riscv64" | [jdk.vm.ci.riscv64.RISCV64] | public String getName() { return name; } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/riscv64/RISCV64.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/riscv64/RISCV64.java index c06ba315a149c..0a28703001503 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/riscv64/RISCV64.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/riscv64/RISCV64.java @@ -35,6 +35,8 @@ /** * Represents the RISCV64 architecture. + * + * The value returned by {@code Architecture#getName} for an instance of this class is {@code "riscv64"}. */ public class RISCV64 extends Architecture { From ff634a967027cfa56b666d31c45db9a4acc09ea4 Mon Sep 17 00:00:00 2001 From: Naoto Sato Date: Tue, 6 Aug 2024 20:11:21 +0000 Subject: [PATCH 212/353] 8337506: Disable "best-fit" mapping on Windows command line Reviewed-by: alanb --- src/java.base/share/native/launcher/main.c | 22 ++++- .../launcher/DisableBestFitMappingTest.java | 83 +++++++++++++++++++ 2 files changed, 103 insertions(+), 2 deletions(-) create mode 100644 test/jdk/tools/launcher/DisableBestFitMappingTest.java diff --git a/src/java.base/share/native/launcher/main.c b/src/java.base/share/native/launcher/main.c index d3898d7adc634..c504c13154f5b 100644 --- a/src/java.base/share/native/launcher/main.c +++ b/src/java.base/share/native/launcher/main.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -110,7 +110,25 @@ main(int argc, char **argv) } } } - JLI_CmdToArgs(GetCommandLine()); + + // Obtain the command line in UTF-16, then convert it to ANSI code page + // without the "best-fit" option + LPWSTR wcCmdline = GetCommandLineW(); + int mbSize = WideCharToMultiByte(CP_ACP, + WC_NO_BEST_FIT_CHARS | WC_COMPOSITECHECK | WC_DEFAULTCHAR, + wcCmdline, -1, NULL, 0, NULL, NULL); + // If the call to WideCharToMultiByte() fails, it returns 0, which + // will then make the following JLI_MemAlloc() to issue exit(1) + LPSTR mbCmdline = JLI_MemAlloc(mbSize); + if (WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS | WC_COMPOSITECHECK | WC_DEFAULTCHAR, + wcCmdline, -1, mbCmdline, mbSize, NULL, NULL) == 0) { + perror("command line encoding conversion failure"); + exit(1); + } + + JLI_CmdToArgs(mbCmdline); + JLI_MemFree(mbCmdline); + margc = JLI_GetStdArgc(); // add one more to mark the end margv = (char **)JLI_MemAlloc((margc + 1) * (sizeof(char *))); diff --git a/test/jdk/tools/launcher/DisableBestFitMappingTest.java b/test/jdk/tools/launcher/DisableBestFitMappingTest.java new file mode 100644 index 0000000000000..6602aae60a9fe --- /dev/null +++ b/test/jdk/tools/launcher/DisableBestFitMappingTest.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8337506 + * @summary Verify Command Line arguments are not mapped with + * "best-fit" mappings on Windows + * @requires (os.family == "windows") + * @library /test/lib + * @run junit DisableBestFitMappingTest + */ +import java.nio.ByteBuffer; +import java.nio.charset.Charset; +import java.nio.charset.CharsetEncoder; +import java.util.stream.Stream; +import jdk.test.lib.process.ProcessTools; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assumptions.*; + +public class DisableBestFitMappingTest { + private static final CharsetEncoder NATIVE_ENC = + Charset.forName(System.getProperty("native.encoding")).newEncoder(); + private static final String REPLACEMENT = + NATIVE_ENC.charset().decode(ByteBuffer.wrap(NATIVE_ENC.replacement())).toString(); + private static final int EXIT_SUCCESS = 0; + private static final int EXIT_FAILURE = -1; + + static Stream CMD_ARGS() { + return Stream.of( + Arguments.of("aa\uff02 \uff02bb", "aa" + REPLACEMENT + " " + REPLACEMENT + "bb"), + Arguments.of("aa\uff01bb", "aa" + REPLACEMENT + "bb"), + Arguments.of("aa\u221ebb", "aa" + REPLACEMENT + "bb") + ); + } + + @ParameterizedTest + @MethodSource("CMD_ARGS") + void testDisableBestFitMapping(String arg, String expected) throws Exception { + // Only execute if the arg cannot be encoded + assumeFalse(NATIVE_ENC.canEncode(arg), + "native.encoding (%s) can encode the argument '%s'. Test ignored." + .formatted(NATIVE_ENC.charset(), arg)); + + var result= ProcessTools.executeTestJava( + DisableBestFitMappingTest.class.getSimpleName(), arg, expected); + result.asLines().forEach(System.out::println); + assertEquals(EXIT_SUCCESS, result.getExitValue(), + "Disabling best-fit mapping failed"); + } + + public static void main(String... args) { + System.out.println(args[0]); + System.out.println(args[1]); + System.exit(args[0].equals(args[1]) ? EXIT_SUCCESS : EXIT_FAILURE); + } +} From 22a3421379162bb302fb8e5ccc315e53d95b6245 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Tue, 6 Aug 2024 20:15:47 +0000 Subject: [PATCH 213/353] 8337786: Fix simple -Wzero-as-null-pointer-constant warnings in aarch64 code Reviewed-by: shade, tschatzl --- src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp | 2 +- src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp | 4 ++-- src/hotspot/cpu/aarch64/frame_aarch64.cpp | 6 +++--- src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp | 2 +- src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp | 4 ++-- src/hotspot/cpu/aarch64/vm_version_aarch64.cpp | 4 ++-- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp index 615c8e19ac863..91430be5835b5 100644 --- a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp @@ -647,7 +647,7 @@ void LIR_Assembler::const2mem(LIR_Opr src, LIR_Opr dest, BasicType type, CodeEmi break; case T_OBJECT: case T_ARRAY: - assert(c->as_jobject() == 0, "should be"); + assert(c->as_jobject() == nullptr, "should be"); if (UseCompressedOops && !wide) { insn = &Assembler::strw; } else { diff --git a/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp index 63a32e714e365..780055a611f3b 100644 --- a/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2021, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -1029,4 +1029,4 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { #undef __ -const char *Runtime1::pd_name_for_address(address entry) { Unimplemented(); return 0; } +const char *Runtime1::pd_name_for_address(address entry) { Unimplemented(); } diff --git a/src/hotspot/cpu/aarch64/frame_aarch64.cpp b/src/hotspot/cpu/aarch64/frame_aarch64.cpp index 0387f763bbdd7..c2b127f31bb6d 100644 --- a/src/hotspot/cpu/aarch64/frame_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/frame_aarch64.cpp @@ -293,7 +293,7 @@ void frame::patch_pc(Thread* thread, address pc) { // Either the return address is the original one or we are going to // patch in the same address that's already there. - assert(_pc == pc_old || pc == pc_old || pc_old == 0, ""); + assert(_pc == pc_old || pc == pc_old || pc_old == nullptr, ""); DEBUG_ONLY(address old_pc = _pc;) *pc_addr = signed_pc; _pc = pc; // must be set before call to get_deopt_original_pc @@ -497,10 +497,10 @@ frame frame::sender_for_interpreter_frame(RegisterMap* map) const { bool frame::is_interpreted_frame_valid(JavaThread* thread) const { assert(is_interpreted_frame(), "Not an interpreted frame"); // These are reasonable sanity checks - if (fp() == 0 || (intptr_t(fp()) & (wordSize-1)) != 0) { + if (fp() == nullptr || (intptr_t(fp()) & (wordSize-1)) != 0) { return false; } - if (sp() == 0 || (intptr_t(sp()) & (wordSize-1)) != 0) { + if (sp() == nullptr || (intptr_t(sp()) & (wordSize-1)) != 0) { return false; } if (fp() + interpreter_frame_initial_sp_offset < sp()) { diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp index e210c8b3de05a..25dfaca6dca20 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp @@ -215,7 +215,7 @@ class RelocActions { break; } else { // nothing to do - assert(target == 0, "did not expect to relocate target for polling page load"); + assert(target == nullptr, "did not expect to relocate target for polling page load"); } break; } diff --git a/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp b/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp index 5a3f9d228ca89..770ed2f6c3868 100644 --- a/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp @@ -228,7 +228,7 @@ address NativeJump::jump_destination() const { // load // return -1 if jump to self or to 0 - if ((dest == (address)this) || dest == 0) { + if ((dest == (address)this) || dest == nullptr) { dest = (address) -1; } return dest; @@ -256,7 +256,7 @@ address NativeGeneralJump::jump_destination() const { // a general jump // return -1 if jump to self or to 0 - if ((dest == (address)this) || dest == 0) { + if ((dest == (address)this) || dest == nullptr) { dest = (address) -1; } return dest; diff --git a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp index aa64f411dbfb9..c0f10adc85df9 100644 --- a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp @@ -606,12 +606,12 @@ static bool check_info_file(const char* fpath, return false; } while (fgets(line, sizeof(line), fp) != nullptr) { - if (strcasestr(line, virt1) != 0) { + if (strcasestr(line, virt1) != nullptr) { Abstract_VM_Version::_detected_virtualization = vt1; fclose(fp); return true; } - if (virt2 != nullptr && strcasestr(line, virt2) != 0) { + if (virt2 != nullptr && strcasestr(line, virt2) != nullptr) { Abstract_VM_Version::_detected_virtualization = vt2; fclose(fp); return true; From fc652d2a58bfd99b05011c051e5710d1dac049ab Mon Sep 17 00:00:00 2001 From: Alisen Chung Date: Tue, 6 Aug 2024 21:10:06 +0000 Subject: [PATCH 214/353] 8235404: [macos] JOptionPane blocks drawing string on another component Reviewed-by: honkar, dnguyen --- .../classes/javax/swing/JOptionPane.java | 7 +- .../swing/JOptionPane/OptionPaneInput.java | 80 +++++++++++++++++++ 2 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 test/jdk/javax/swing/JOptionPane/OptionPaneInput.java diff --git a/src/java.desktop/share/classes/javax/swing/JOptionPane.java b/src/java.desktop/share/classes/javax/swing/JOptionPane.java index 930acc90b35c3..1c1f3ee9ba355 100644 --- a/src/java.desktop/share/classes/javax/swing/JOptionPane.java +++ b/src/java.desktop/share/classes/javax/swing/JOptionPane.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -883,6 +883,11 @@ public static int showOptionDialog(Component parentComponent, Object selectedValue = pane.getValue(); + if (parentComponent != null) { + parentComponent.revalidate(); + parentComponent.repaint(); + } + if(selectedValue == null) return CLOSED_OPTION; if(options == null) { diff --git a/test/jdk/javax/swing/JOptionPane/OptionPaneInput.java b/test/jdk/javax/swing/JOptionPane/OptionPaneInput.java new file mode 100644 index 0000000000000..998efccf1f3ce --- /dev/null +++ b/test/jdk/javax/swing/JOptionPane/OptionPaneInput.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Canvas; +import java.awt.Color; +import java.awt.Graphics2D; +import javax.swing.JFrame; +import javax.swing.JOptionPane; +import javax.swing.JTextField; +import javax.swing.SwingUtilities; + +/* + * @test + * @bug 8235404 + * @summary Checks that JOptionPane doesn't block drawing strings on another component + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual OptionPaneInput + */ +public class OptionPaneInput { + private static JFrame f; + private static Canvas c; + private static JTextField t; + private static final String instructions = """ + 1. Type "test" into the message dialog. + 2. Press enter key. + 3. Press OK button. + 4. If the OptionPaneInput frame has test drawn on it, pass. Otherwise fail. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame testFrame = new PassFailJFrame(instructions); + + SwingUtilities.invokeAndWait(() -> createGUI()); + testFrame.awaitAndCheck(); + } + + public static void createGUI() { + f = new JFrame("OptionPaneInput"); + c = new Canvas(); + t = new JTextField(); + f.add(c); + + t.addActionListener(e -> { + String text = t.getText(); + Graphics2D g2 = (Graphics2D)(c.getGraphics()); + g2.setColor(Color.BLACK); + g2.drawString(text, 10, 10); + System.out.println("drawing "+text); + g2.dispose(); + }); + + f.setSize(300, 100); + PassFailJFrame.addTestWindow(f); + PassFailJFrame.positionTestWindow(f, PassFailJFrame.Position.HORIZONTAL); + f.setVisible(true); + + JOptionPane.showMessageDialog(f, t); + } +} From 6733b89de1ed9ebcc1e8a8271970048ad0f0aac3 Mon Sep 17 00:00:00 2001 From: Chris Plummer Date: Tue, 6 Aug 2024 21:44:30 +0000 Subject: [PATCH 215/353] 8337667: sun/tools/jcmd/TestJcmdPIDSubstitution.java is failing on mac and windows Reviewed-by: stuefe, kevinw --- test/jdk/sun/tools/jcmd/TestJcmdPIDSubstitution.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/test/jdk/sun/tools/jcmd/TestJcmdPIDSubstitution.java b/test/jdk/sun/tools/jcmd/TestJcmdPIDSubstitution.java index f462ea1a52b0d..4af5bf1ff6755 100644 --- a/test/jdk/sun/tools/jcmd/TestJcmdPIDSubstitution.java +++ b/test/jdk/sun/tools/jcmd/TestJcmdPIDSubstitution.java @@ -40,6 +40,8 @@ import java.nio.file.Path; import java.nio.file.Paths; +import jdk.test.lib.Platform; + public class TestJcmdPIDSubstitution { private static final String FILENAME = "myfile%p"; @@ -47,8 +49,10 @@ public class TestJcmdPIDSubstitution { public static void main(String[] args) throws Exception { verifyOutputFilenames("Thread.dump_to_file", FILENAME); verifyOutputFilenames("GC.heap_dump", FILENAME); - verifyOutputFilenames("Compiler.perfmap", FILENAME); - verifyOutputFilenames("System.dump_map", "-F=%s".formatted(FILENAME)); + if (Platform.isLinux()) { + verifyOutputFilenames("Compiler.perfmap", FILENAME); + verifyOutputFilenames("System.dump_map", "-F=%s".formatted(FILENAME)); + } } private static void verifyOutputFilenames(String... args) throws Exception { From 920751e5d5838dab90438117a77f43876902eb72 Mon Sep 17 00:00:00 2001 From: Alex Menkov Date: Tue, 6 Aug 2024 21:56:48 +0000 Subject: [PATCH 216/353] 8311990: Two JDI tests may interfere with each other Reviewed-by: dholmes, sspitsyn --- test/jdk/com/sun/jdi/JdwpListenTest.java | 5 +++-- test/jdk/com/sun/jdi/JdwpNetProps.java | 15 ++++++++++++++- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/test/jdk/com/sun/jdi/JdwpListenTest.java b/test/jdk/com/sun/jdi/JdwpListenTest.java index a55eefb58689c..53f5b404de5e4 100644 --- a/test/jdk/com/sun/jdi/JdwpListenTest.java +++ b/test/jdk/com/sun/jdi/JdwpListenTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,7 +50,8 @@ public class JdwpListenTest { // Set to true to allow testing of attach from wrong address (expected to fail). // It's off by default as it causes test time increase and test interference (see JDK-8231915). - private static boolean allowNegativeTesting = false; + private static boolean allowNegativeTesting = + "true".equalsIgnoreCase(System.getProperty("jdk.jdi.allowNegativeTesting")); public static void main(String[] args) throws Exception { List addresses = Utils.getAddressesWithSymbolicAndNumericScopes(); diff --git a/test/jdk/com/sun/jdi/JdwpNetProps.java b/test/jdk/com/sun/jdi/JdwpNetProps.java index af69c9ca3adf2..0247e4551a3da 100644 --- a/test/jdk/com/sun/jdi/JdwpNetProps.java +++ b/test/jdk/com/sun/jdi/JdwpNetProps.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -49,6 +49,11 @@ */ public class JdwpNetProps { + // Set to true to allow testing of attach from wrong address (expected to fail). + // It's off by default as it causes test interference (see JDK-8311990). + private static boolean allowNegativeAttachTesting = + "true".equalsIgnoreCase(System.getProperty("jdk.jdi.allowNegativeTesting")); + public static void main(String[] args) throws Exception { InetAddress addrs[] = InetAddress.getAllByName("localhost"); InetAddress ipv4Address = null; @@ -171,6 +176,14 @@ public ListenTest preferIPv6Addresses(String value) { } public void run(TestResult expectedResult) throws Exception { + log("\nTest: listen at " + listenAddress + ", attaching to " + connectAddress + + ", preferIPv4Stack = " + preferIPv4Stack + + ", preferIPv6Addresses = " + preferIPv6Addresses + + ", expectedResult = " + expectedResult); + if (expectedResult == TestResult.AttachFailed && !allowNegativeAttachTesting) { + log("SKIPPED: negative attach testing is disabled"); + return; + } List options = new LinkedList<>(); if (preferIPv4Stack != null) { options.add("-Djava.net.preferIPv4Stack=" + preferIPv4Stack.toString()); From 66286b25a183de2ffd0689da9c2bd1978b881aa7 Mon Sep 17 00:00:00 2001 From: Tobias Hartmann Date: Wed, 7 Aug 2024 05:32:28 +0000 Subject: [PATCH 217/353] 8337968: Problem list compiler/vectorapi/VectorRebracket128Test.java Reviewed-by: chagedorn --- 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 7e7970a4c6caf..f5b14e87607e3 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -59,6 +59,8 @@ compiler/codecache/CheckLargePages.java 8332654 linux-x64 compiler/vectorapi/reshape/TestVectorReinterpret.java 8320897 aix-ppc64,linux-ppc64le compiler/vectorapi/VectorLogicalOpIdentityTest.java 8302459 linux-x64,windows-x64 +compiler/vectorapi/VectorRebracket128Test.java#ZSinglegen 8330538 generic-all +compiler/vectorapi/VectorRebracket128Test.java#ZGenerational 8330538 generic-all compiler/jvmci/TestUncaughtErrorInCompileMethod.java 8309073 generic-all From 41f784fe63f8e06a25e1fe00dc96e398874adf81 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Wed, 7 Aug 2024 07:48:05 +0000 Subject: [PATCH 218/353] 8335925: Serial: Move allocation API from Generation to subclasses Reviewed-by: gli, kbarrett, iwalulya --- src/hotspot/share/gc/serial/defNewGeneration.cpp | 10 ++-------- src/hotspot/share/gc/serial/defNewGeneration.hpp | 8 +++----- src/hotspot/share/gc/serial/generation.hpp | 14 -------------- src/hotspot/share/gc/serial/serialHeap.cpp | 13 +++++++------ src/hotspot/share/gc/serial/tenuredGeneration.cpp | 9 ++++----- src/hotspot/share/gc/serial/tenuredGeneration.hpp | 8 +++++--- .../share/gc/serial/tenuredGeneration.inline.hpp | 14 +------------- 7 files changed, 22 insertions(+), 54 deletions(-) diff --git a/src/hotspot/share/gc/serial/defNewGeneration.cpp b/src/hotspot/share/gc/serial/defNewGeneration.cpp index e93b97c85eb12..047171a5eb364 100644 --- a/src/hotspot/share/gc/serial/defNewGeneration.cpp +++ b/src/hotspot/share/gc/serial/defNewGeneration.cpp @@ -572,11 +572,6 @@ HeapWord* DefNewGeneration::block_start(const void* p) const { return block_start_const(to(), p); } -HeapWord* DefNewGeneration::expand_and_allocate(size_t size, bool is_tlab) { - // We don't attempt to expand the young generation (but perhaps we should.) - return allocate(size, is_tlab); -} - void DefNewGeneration::adjust_desired_tenuring_threshold() { // Set the desired survivor size to half the real survivor space size_t const survivor_capacity = to()->capacity() / HeapWordSize; @@ -865,7 +860,7 @@ const char* DefNewGeneration::name() const { return "def new generation"; } -HeapWord* DefNewGeneration::allocate(size_t word_size, bool is_tlab) { +HeapWord* DefNewGeneration::allocate(size_t word_size) { // This is the slow-path allocation for the DefNewGeneration. // Most allocations are fast-path in compiled code. // We try to allocate from the eden. If that works, we are happy. @@ -875,8 +870,7 @@ HeapWord* DefNewGeneration::allocate(size_t word_size, bool is_tlab) { return result; } -HeapWord* DefNewGeneration::par_allocate(size_t word_size, - bool is_tlab) { +HeapWord* DefNewGeneration::par_allocate(size_t word_size) { return eden()->par_allocate(word_size); } diff --git a/src/hotspot/share/gc/serial/defNewGeneration.hpp b/src/hotspot/share/gc/serial/defNewGeneration.hpp index 011b79fdabd6b..c5b7c095ac4e6 100644 --- a/src/hotspot/share/gc/serial/defNewGeneration.hpp +++ b/src/hotspot/share/gc/serial/defNewGeneration.hpp @@ -209,9 +209,9 @@ class DefNewGeneration: public Generation { return result; } - HeapWord* allocate(size_t word_size, bool is_tlab); - - HeapWord* par_allocate(size_t word_size, bool is_tlab); + // Allocate requested size or return null; single-threaded and lock-free versions. + HeapWord* allocate(size_t word_size); + HeapWord* par_allocate(size_t word_size); void gc_epilogue(bool full); @@ -227,8 +227,6 @@ class DefNewGeneration: public Generation { bool collect(bool clear_all_soft_refs); - HeapWord* expand_and_allocate(size_t size, bool is_tlab); - oop copy_to_survivor_space(oop old); uint tenuring_threshold() { return _tenuring_threshold; } diff --git a/src/hotspot/share/gc/serial/generation.hpp b/src/hotspot/share/gc/serial/generation.hpp index a757c97c5cb15..beb29928f4826 100644 --- a/src/hotspot/share/gc/serial/generation.hpp +++ b/src/hotspot/share/gc/serial/generation.hpp @@ -103,20 +103,6 @@ class Generation: public CHeapObj { return _reserved.contains(p); } - // Allocate and returns a block of the requested size, or returns "null". - // Assumes the caller has done any necessary locking. - virtual HeapWord* allocate(size_t word_size, bool is_tlab) = 0; - - // Like "allocate", but performs any necessary locking internally. - virtual HeapWord* par_allocate(size_t word_size, bool is_tlab) = 0; - - // Perform a heap collection, attempting to create (at least) enough - // space to support an allocation of the given "word_size". If - // successful, perform the allocation and return the resulting - // "oop" (initializing the allocated block). If the allocation is - // still unsuccessful, return "null". - virtual HeapWord* expand_and_allocate(size_t word_size, bool is_tlab) = 0; - // Printing virtual const char* name() const = 0; virtual const char* short_name() const = 0; diff --git a/src/hotspot/share/gc/serial/serialHeap.cpp b/src/hotspot/share/gc/serial/serialHeap.cpp index c1fdc1eba1a32..3c48177554121 100644 --- a/src/hotspot/share/gc/serial/serialHeap.cpp +++ b/src/hotspot/share/gc/serial/serialHeap.cpp @@ -156,7 +156,7 @@ void SerialHeap::safepoint_synchronize_end() { HeapWord* SerialHeap::allocate_loaded_archive_space(size_t word_size) { MutexLocker ml(Heap_lock); - return old_gen()->allocate(word_size, false /* is_tlab */); + return old_gen()->allocate(word_size); } void SerialHeap::complete_loaded_archive_space(MemRegion archive_space) { @@ -292,11 +292,12 @@ bool SerialHeap::should_try_older_generation_allocation(size_t word_size) const HeapWord* SerialHeap::expand_heap_and_allocate(size_t size, bool is_tlab) { HeapWord* result = nullptr; if (_old_gen->should_allocate(size, is_tlab)) { - result = _old_gen->expand_and_allocate(size, is_tlab); + result = _old_gen->expand_and_allocate(size); } if (result == nullptr) { if (_young_gen->should_allocate(size, is_tlab)) { - result = _young_gen->expand_and_allocate(size, is_tlab); + // Young-gen is not expanded. + result = _young_gen->allocate(size); } } assert(result == nullptr || is_in_reserved(result), "result not in heap"); @@ -314,7 +315,7 @@ HeapWord* SerialHeap::mem_allocate_work(size_t size, // First allocation attempt is lock-free. DefNewGeneration *young = _young_gen; if (young->should_allocate(size, is_tlab)) { - result = young->par_allocate(size, is_tlab); + result = young->par_allocate(size); if (result != nullptr) { assert(is_in_reserved(result), "result not in heap"); return result; @@ -406,14 +407,14 @@ HeapWord* SerialHeap::attempt_allocation(size_t size, HeapWord* res = nullptr; if (_young_gen->should_allocate(size, is_tlab)) { - res = _young_gen->allocate(size, is_tlab); + res = _young_gen->allocate(size); if (res != nullptr || first_only) { return res; } } if (_old_gen->should_allocate(size, is_tlab)) { - res = _old_gen->allocate(size, is_tlab); + res = _old_gen->allocate(size); } return res; diff --git a/src/hotspot/share/gc/serial/tenuredGeneration.cpp b/src/hotspot/share/gc/serial/tenuredGeneration.cpp index b1b7507094771..febc4713d0372 100644 --- a/src/hotspot/share/gc/serial/tenuredGeneration.cpp +++ b/src/hotspot/share/gc/serial/tenuredGeneration.cpp @@ -397,20 +397,19 @@ oop TenuredGeneration::allocate_for_promotion(oop obj, size_t obj_size) { #endif // #ifndef PRODUCT // Allocate new object. - HeapWord* result = allocate(obj_size, false); + HeapWord* result = allocate(obj_size); if (result == nullptr) { // Promotion of obj into gen failed. Try to expand and allocate. - result = expand_and_allocate(obj_size, false); + result = expand_and_allocate(obj_size); } return cast_to_oop(result); } HeapWord* -TenuredGeneration::expand_and_allocate(size_t word_size, bool is_tlab) { - assert(!is_tlab, "TenuredGeneration does not support TLAB allocation"); +TenuredGeneration::expand_and_allocate(size_t word_size) { expand(word_size*HeapWordSize, _min_heap_delta_bytes); - return allocate(word_size, is_tlab); + return allocate(word_size); } void TenuredGeneration::assert_correct_size_change_locking() { diff --git a/src/hotspot/share/gc/serial/tenuredGeneration.hpp b/src/hotspot/share/gc/serial/tenuredGeneration.hpp index dcec912d4887f..fc0578d4e4fe4 100644 --- a/src/hotspot/share/gc/serial/tenuredGeneration.hpp +++ b/src/hotspot/share/gc/serial/tenuredGeneration.hpp @@ -130,10 +130,12 @@ class TenuredGeneration: public Generation { void complete_loaded_archive_space(MemRegion archive_space); inline void update_for_block(HeapWord* start, HeapWord* end); - virtual inline HeapWord* allocate(size_t word_size, bool is_tlab); - virtual inline HeapWord* par_allocate(size_t word_size, bool is_tlab); + // Allocate and returns a block of the requested size, or returns "null". + // Assumes the caller has done any necessary locking. + inline HeapWord* allocate(size_t word_size); - HeapWord* expand_and_allocate(size_t size, bool is_tlab); + // Expand the old-gen then invoke allocate above. + HeapWord* expand_and_allocate(size_t size); void gc_prologue(); void gc_epilogue(); diff --git a/src/hotspot/share/gc/serial/tenuredGeneration.inline.hpp b/src/hotspot/share/gc/serial/tenuredGeneration.inline.hpp index ba0dbcdc02d57..c6a6a0ae71634 100644 --- a/src/hotspot/share/gc/serial/tenuredGeneration.inline.hpp +++ b/src/hotspot/share/gc/serial/tenuredGeneration.inline.hpp @@ -48,9 +48,7 @@ inline void TenuredGeneration::update_for_block(HeapWord* start, HeapWord* end) _bts->update_for_block(start, end); } -HeapWord* TenuredGeneration::allocate(size_t word_size, - bool is_tlab) { - assert(!is_tlab, "TenuredGeneration does not support TLAB allocation"); +HeapWord* TenuredGeneration::allocate(size_t word_size) { HeapWord* res = _the_space->allocate(word_size); if (res != nullptr) { _bts->update_for_block(res, res + word_size); @@ -58,14 +56,4 @@ HeapWord* TenuredGeneration::allocate(size_t word_size, return res; } -HeapWord* TenuredGeneration::par_allocate(size_t word_size, - bool is_tlab) { - assert(!is_tlab, "TenuredGeneration does not support TLAB allocation"); - HeapWord* res = _the_space->par_allocate(word_size); - if (res != nullptr) { - _bts->update_for_block(res, res + word_size); - } - return res; -} - #endif // SHARE_GC_SERIAL_TENUREDGENERATION_INLINE_HPP From 88a05a853ed9e0425ba3315b751a5015bed62675 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20Gr=C3=B6nlund?= Date: Wed, 7 Aug 2024 10:24:34 +0000 Subject: [PATCH 219/353] 8337975: [BACKOUT] Native memory leak when not recording any events Reviewed-by: jpai, egahlin --- .../share/jfr/recorder/service/jfrRecorderService.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp b/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp index 418b774996e4c..fc2043a4d921d 100644 --- a/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp +++ b/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp @@ -639,7 +639,11 @@ static void write_thread_local_buffer(JfrChunkWriter& chunkwriter, Thread* t) { size_t JfrRecorderService::flush() { size_t total_elements = flush_metadata(_chunkwriter); - total_elements += flush_storage(_storage, _chunkwriter); + const size_t storage_elements = flush_storage(_storage, _chunkwriter); + if (0 == storage_elements) { + return total_elements; + } + total_elements += storage_elements; if (_string_pool.is_modified()) { total_elements += flush_stringpool(_string_pool, _chunkwriter); } From 21f710e7f6698b12b06cc3685cefa31f5fcff2a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20Sikstr=C3=B6m?= Date: Wed, 7 Aug 2024 14:16:01 +0000 Subject: [PATCH 220/353] 8310675: Fix -Wconversion warnings in ZGC code Reviewed-by: stefank, ayang --- src/hotspot/share/gc/z/c2/zBarrierSetC2.cpp | 2 +- src/hotspot/share/gc/z/zArguments.cpp | 2 +- src/hotspot/share/gc/z/zArray.inline.hpp | 4 +- src/hotspot/share/gc/z/zBarrier.cpp | 4 +- src/hotspot/share/gc/z/zBarrierSetNMethod.cpp | 4 +- src/hotspot/share/gc/z/zCPU.inline.hpp | 4 +- src/hotspot/share/gc/z/zDirector.cpp | 10 ++--- .../gc/z/zForwardingAllocator.inline.hpp | 4 +- src/hotspot/share/gc/z/zGeneration.cpp | 6 +-- src/hotspot/share/gc/z/zGeneration.hpp | 4 +- src/hotspot/share/gc/z/zHeapIterator.cpp | 6 +-- src/hotspot/share/gc/z/zHeuristics.cpp | 14 +++---- .../share/gc/z/zIndexDistributor.inline.hpp | 6 +-- src/hotspot/share/gc/z/zLiveMap.cpp | 6 +-- src/hotspot/share/gc/z/zLiveMap.hpp | 4 +- src/hotspot/share/gc/z/zMarkCache.cpp | 4 +- src/hotspot/share/gc/z/zMarkStack.cpp | 4 +- src/hotspot/share/gc/z/zMetronome.cpp | 10 ++--- src/hotspot/share/gc/z/zNMethod.cpp | 6 +-- src/hotspot/share/gc/z/zNMethodTable.cpp | 8 ++-- src/hotspot/share/gc/z/zObjArrayAllocator.cpp | 4 +- src/hotspot/share/gc/z/zPage.inline.hpp | 12 +++--- src/hotspot/share/gc/z/zPageCache.cpp | 6 +-- src/hotspot/share/gc/z/zPageTable.inline.hpp | 4 +- src/hotspot/share/gc/z/zRelocationSet.cpp | 6 +-- .../share/gc/z/zRelocationSetSelector.cpp | 8 ++-- src/hotspot/share/gc/z/zStat.cpp | 38 ++++++++++--------- src/hotspot/share/gc/z/zStat.hpp | 3 +- .../share/gc/z/zStoreBarrierBuffer.cpp | 20 +++++----- .../share/gc/z/zStoreBarrierBuffer.hpp | 10 ++--- .../share/gc/z/zStoreBarrierBuffer.inline.hpp | 4 +- src/hotspot/share/gc/z/zUnmapper.cpp | 4 +- src/hotspot/share/gc/z/zVerify.cpp | 4 +- 33 files changed, 120 insertions(+), 115 deletions(-) diff --git a/src/hotspot/share/gc/z/c2/zBarrierSetC2.cpp b/src/hotspot/share/gc/z/c2/zBarrierSetC2.cpp index dbec45fd96ea9..f72e84eaf5935 100644 --- a/src/hotspot/share/gc/z/c2/zBarrierSetC2.cpp +++ b/src/hotspot/share/gc/z/c2/zBarrierSetC2.cpp @@ -327,7 +327,7 @@ int ZBarrierSetC2::estimate_stub_size() const { int size = 0; for (int i = 0; i < stubs->length(); i++) { - CodeBuffer cb(blob->content_begin(), (address)C->output()->scratch_locs_memory() - blob->content_begin()); + CodeBuffer cb(blob->content_begin(), checked_cast((address)C->output()->scratch_locs_memory() - blob->content_begin())); MacroAssembler masm(&cb); stubs->at(i)->emit_code(masm); size += cb.insts_size(); diff --git a/src/hotspot/share/gc/z/zArguments.cpp b/src/hotspot/share/gc/z/zArguments.cpp index c71e59944f095..f3ff568c64d14 100644 --- a/src/hotspot/share/gc/z/zArguments.cpp +++ b/src/hotspot/share/gc/z/zArguments.cpp @@ -146,7 +146,7 @@ void ZArguments::initialize() { ZHeuristics::set_medium_page_size(); if (!FLAG_IS_DEFAULT(ZTenuringThreshold) && ZTenuringThreshold != -1) { - FLAG_SET_ERGO_IF_DEFAULT(MaxTenuringThreshold, ZTenuringThreshold); + FLAG_SET_ERGO_IF_DEFAULT(MaxTenuringThreshold, (uint)ZTenuringThreshold); if (MaxTenuringThreshold == 0) { FLAG_SET_ERGO_IF_DEFAULT(AlwaysTenure, true); } diff --git a/src/hotspot/share/gc/z/zArray.inline.hpp b/src/hotspot/share/gc/z/zArray.inline.hpp index 2ec87a761564e..ec7feda8d6398 100644 --- a/src/hotspot/share/gc/z/zArray.inline.hpp +++ b/src/hotspot/share/gc/z/zArray.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -61,7 +61,7 @@ inline ZArrayIteratorImpl::ZArrayIteratorImpl(const T* array, size_ template inline ZArrayIteratorImpl::ZArrayIteratorImpl(const ZArray* array) - : ZArrayIteratorImpl(array->is_empty() ? nullptr : array->adr_at(0), array->length()) {} + : ZArrayIteratorImpl(array->is_empty() ? nullptr : array->adr_at(0), (size_t)array->length()) {} template inline bool ZArrayIteratorImpl::next(T* elem) { diff --git a/src/hotspot/share/gc/z/zBarrier.cpp b/src/hotspot/share/gc/z/zBarrier.cpp index c4b6e0f8239e1..7d7f1284bdfdc 100644 --- a/src/hotspot/share/gc/z/zBarrier.cpp +++ b/src/hotspot/share/gc/z/zBarrier.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -291,7 +291,7 @@ zaddress ZBarrier::keep_alive_slow_path(zaddress addr) { // ON_WEAK barriers should only ever be applied to j.l.r.Reference.referents. void ZBarrier::verify_on_weak(volatile zpointer* referent_addr) { if (referent_addr != nullptr) { - const uintptr_t base = (uintptr_t)referent_addr - java_lang_ref_Reference::referent_offset(); + const uintptr_t base = (uintptr_t)referent_addr - (size_t)java_lang_ref_Reference::referent_offset(); const oop obj = cast_to_oop(base); assert(oopDesc::is_oop(obj), "Verification failed for: ref " PTR_FORMAT " obj: " PTR_FORMAT, (uintptr_t)referent_addr, base); assert(java_lang_ref_Reference::is_referent_field(obj, java_lang_ref_Reference::referent_offset()), "Sanity"); diff --git a/src/hotspot/share/gc/z/zBarrierSetNMethod.cpp b/src/hotspot/share/gc/z/zBarrierSetNMethod.cpp index b8ecc3eddd3cd..33894f166a3e9 100644 --- a/src/hotspot/share/gc/z/zBarrierSetNMethod.cpp +++ b/src/hotspot/share/gc/z/zBarrierSetNMethod.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -79,7 +79,7 @@ bool ZBarrierSetNMethod::nmethod_entry_barrier(nmethod* nm) { ZNMethod::nmethod_oops_do_inner(nm, &cl); const uintptr_t prev_color = ZNMethod::color(nm); - const uintptr_t new_color = *(int*)ZPointerStoreGoodMaskLowOrderBitsAddr; + const uintptr_t new_color = *ZPointerStoreGoodMaskLowOrderBitsAddr; log_develop_trace(gc, nmethod)("nmethod: " PTR_FORMAT " visited by entry (complete) [" PTR_FORMAT " -> " PTR_FORMAT "]", p2i(nm), prev_color, new_color); // CodeCache unloading support diff --git a/src/hotspot/share/gc/z/zCPU.inline.hpp b/src/hotspot/share/gc/z/zCPU.inline.hpp index 67d26f4c2e17c..b3712dc5ac98b 100644 --- a/src/hotspot/share/gc/z/zCPU.inline.hpp +++ b/src/hotspot/share/gc/z/zCPU.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,7 @@ #include "utilities/debug.hpp" inline uint32_t ZCPU::count() { - return os::processor_count(); + return (uint32_t)os::processor_count(); } inline uint32_t ZCPU::id() { diff --git a/src/hotspot/share/gc/z/zDirector.cpp b/src/hotspot/share/gc/z/zDirector.cpp index 162e05f2c0763..3ba8698bd8e22 100644 --- a/src/hotspot/share/gc/z/zDirector.cpp +++ b/src/hotspot/share/gc/z/zDirector.cpp @@ -102,7 +102,7 @@ static double estimated_gc_workers(double serial_gc_time, double parallelizable_ } static uint discrete_young_gc_workers(double gc_workers) { - return clamp(ceil(gc_workers), 1, ZYoungGCThreads); + return clamp((uint)ceil(gc_workers), 1, ZYoungGCThreads); } static double select_young_gc_workers(const ZDirectorStats& stats, double serial_gc_time, double parallelizable_gc_time, double alloc_rate_sd_percent, double time_until_oom) { @@ -426,7 +426,7 @@ static bool rule_major_warmup(const ZDirectorStats& stats) { const size_t soft_max_capacity = stats._heap._soft_max_heap_size; const size_t used = stats._heap._used; const double used_threshold_percent = (stats._old_stats._cycle._nwarmup_cycles + 1) * 0.1; - const size_t used_threshold = soft_max_capacity * used_threshold_percent; + const size_t used_threshold = (size_t)(soft_max_capacity * used_threshold_percent); log_debug(gc, director)("Rule Major: Warmup %.0f%%, Used: " SIZE_FORMAT "MB, UsedThreshold: " SIZE_FORMAT "MB", used_threshold_percent * 100, used / M, used_threshold / M); @@ -497,13 +497,13 @@ static bool rule_major_allocation_rate(const ZDirectorStats& stats) { // Doing an old collection makes subsequent young collections more efficient. // Calculate the number of young collections ahead that we will try to amortize // the cost of doing an old collection for. - const int lookahead = stats._heap._total_collections - stats._old_stats._general._total_collections_at_start; + const uint lookahead = stats._heap._total_collections - stats._old_stats._general._total_collections_at_start; // Calculate extra young collection overhead predicted for a number of future // young collections, due to not freeing up memory in the old generation. const double extra_young_gc_time_for_lookahead = extra_young_gc_time * lookahead; - log_debug(gc, director)("Rule Major: Allocation Rate, ExtraYoungGCTime: %.3fs, OldGCTime: %.3fs, Lookahead: %d, ExtraYoungGCTimeForLookahead: %.3fs", + log_debug(gc, director)("Rule Major: Allocation Rate, ExtraYoungGCTime: %.3fs, OldGCTime: %.3fs, Lookahead: %u, ExtraYoungGCTimeForLookahead: %.3fs", extra_young_gc_time, old_gc_time, lookahead, extra_young_gc_time_for_lookahead); // If we continue doing as many minor collections as we already did since the @@ -565,7 +565,7 @@ static bool rule_major_proactive(const ZDirectorStats& stats) { // passed since the previous GC. This helps avoid superfluous GCs when running // applications with very low allocation rate. const size_t used_after_last_gc = stats._old_stats._stat_heap._used_at_relocate_end; - const size_t used_increase_threshold = stats._heap._soft_max_heap_size * 0.10; // 10% + const size_t used_increase_threshold = (size_t)(stats._heap._soft_max_heap_size * 0.10); // 10% const size_t used_threshold = used_after_last_gc + used_increase_threshold; const size_t used = stats._heap._used; const double time_since_last_gc = stats._old_stats._cycle._time_since_last; diff --git a/src/hotspot/share/gc/z/zForwardingAllocator.inline.hpp b/src/hotspot/share/gc/z/zForwardingAllocator.inline.hpp index 41d9106843450..42d006a5b3734 100644 --- a/src/hotspot/share/gc/z/zForwardingAllocator.inline.hpp +++ b/src/hotspot/share/gc/z/zForwardingAllocator.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,7 @@ #include "utilities/debug.hpp" inline size_t ZForwardingAllocator::size() const { - return _end - _start; + return (size_t)(_end - _start); } inline bool ZForwardingAllocator::is_full() const { diff --git a/src/hotspot/share/gc/z/zGeneration.cpp b/src/hotspot/share/gc/z/zGeneration.cpp index be86550d32171..8a7d38e299166 100644 --- a/src/hotspot/share/gc/z/zGeneration.cpp +++ b/src/hotspot/share/gc/z/zGeneration.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -299,7 +299,7 @@ void ZGeneration::reset_statistics() { _page_allocator->reset_statistics(_id); } -ssize_t ZGeneration::freed() const { +size_t ZGeneration::freed() const { return _freed; } @@ -448,7 +448,7 @@ class VM_ZOperation : public VM_Operation { _success = do_operation(); // Update statistics - ZStatSample(ZSamplerJavaThreads, Threads::number_of_threads()); + ZStatSample(ZSamplerJavaThreads, (uint64_t)Threads::number_of_threads()); } virtual void doit_epilogue() { diff --git a/src/hotspot/share/gc/z/zGeneration.hpp b/src/hotspot/share/gc/z/zGeneration.hpp index 32762a50b6278..aec48a0a07236 100644 --- a/src/hotspot/share/gc/z/zGeneration.hpp +++ b/src/hotspot/share/gc/z/zGeneration.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -122,7 +122,7 @@ class ZGeneration { // Statistics void reset_statistics(); virtual bool should_record_stats() = 0; - ssize_t freed() const; + size_t freed() const; void increase_freed(size_t size); size_t promoted() const; void increase_promoted(size_t size); diff --git a/src/hotspot/share/gc/z/zHeapIterator.cpp b/src/hotspot/share/gc/z/zHeapIterator.cpp index cbcac39a11bbc..50fc921131fe7 100644 --- a/src/hotspot/share/gc/z/zHeapIterator.cpp +++ b/src/hotspot/share/gc/z/zHeapIterator.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -204,7 +204,7 @@ class ZHeapIteratorOopClosure : public OopIterateClosure { assert(ZCollectedHeap::heap()->is_in(p), "Should be in heap"); if (VisitReferents) { - return HeapAccess::oop_load_at(_base, _base->field_offset(p)); + return HeapAccess::oop_load_at(_base, (ptrdiff_t)_base->field_offset(p)); } return HeapAccess::oop_load(p); @@ -447,7 +447,7 @@ void ZHeapIterator::follow_array_chunk(const ZHeapIteratorContext& context, cons const objArrayOop obj = objArrayOop(array.obj()); const int length = obj->length(); const int start = array.index(); - const int stride = MIN2(length - start, ObjArrayMarkingStride); + const int stride = MIN2(length - start, (int)ObjArrayMarkingStride); const int end = start + stride; // Push remaining array chunk first diff --git a/src/hotspot/share/gc/z/zHeuristics.cpp b/src/hotspot/share/gc/z/zHeuristics.cpp index c764227061e88..ebf979af79518 100644 --- a/src/hotspot/share/gc/z/zHeuristics.cpp +++ b/src/hotspot/share/gc/z/zHeuristics.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,14 +39,14 @@ void ZHeuristics::set_medium_page_size() { // becomes larger than ZPageSizeSmall. const size_t min = ZGranuleSize; const size_t max = ZGranuleSize * 16; - const size_t unclamped = MaxHeapSize * 0.03125; + const size_t unclamped = (size_t)(MaxHeapSize * 0.03125); const size_t clamped = clamp(unclamped, min, max); const size_t size = round_down_power_of_2(clamped); if (size > ZPageSizeSmall) { // Enable medium pages ZPageSizeMedium = size; - ZPageSizeMediumShift = log2i_exact(ZPageSizeMedium); + ZPageSizeMediumShift = (size_t)log2i_exact(ZPageSizeMedium); ZObjectSizeLimitMedium = ZPageSizeMedium / 8; ZObjectAlignmentMediumShift = (int)ZPageSizeMediumShift - 13; ZObjectAlignmentMedium = 1 << ZObjectAlignmentMediumShift; @@ -68,11 +68,11 @@ bool ZHeuristics::use_per_cpu_shared_small_pages() { } static uint nworkers_based_on_ncpus(double cpu_share_in_percent) { - return ceil(os::initial_active_processor_count() * cpu_share_in_percent / 100.0); + return (uint)ceil(os::initial_active_processor_count() * cpu_share_in_percent / 100.0); } static uint nworkers_based_on_heap_size(double heap_share_in_percent) { - return (MaxHeapSize * (heap_share_in_percent / 100.0)) / ZPageSizeSmall; + return (uint)(MaxHeapSize * (heap_share_in_percent / 100.0) / ZPageSizeSmall); } static uint nworkers(double cpu_share_in_percent) { @@ -101,9 +101,9 @@ uint ZHeuristics::nconcurrent_workers() { } size_t ZHeuristics::significant_heap_overhead() { - return MaxHeapSize * (ZFragmentationLimit / 100); + return (size_t)(MaxHeapSize * (ZFragmentationLimit / 100)); } size_t ZHeuristics::significant_young_overhead() { - return MaxHeapSize * (ZYoungCompactionLimit / 100); + return (size_t)(MaxHeapSize * (ZYoungCompactionLimit / 100)); } diff --git a/src/hotspot/share/gc/z/zIndexDistributor.inline.hpp b/src/hotspot/share/gc/z/zIndexDistributor.inline.hpp index 172ba2505759d..26afdef9d052d 100644 --- a/src/hotspot/share/gc/z/zIndexDistributor.inline.hpp +++ b/src/hotspot/share/gc/z/zIndexDistributor.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,7 +47,7 @@ class ZIndexDistributorStriped : public CHeapObj { } volatile int* claim_addr(int index) { - return (volatile int*)(align_up(_mem, ZCacheLineSize) + index * ZCacheLineSize); + return (volatile int*)(align_up(_mem, ZCacheLineSize) + (size_t)index * ZCacheLineSize); } public: @@ -136,7 +136,7 @@ class ZIndexDistributorClaimTree : public CHeapObj { // Total size used to hold all claim variables static size_t claim_variables_size() { - return sizeof(int) * claim_level_end_index(ClaimLevels); + return sizeof(int) * (size_t)claim_level_end_index(ClaimLevels); } // Returns the index of the start of the current segment of the current level diff --git a/src/hotspot/share/gc/z/zLiveMap.cpp b/src/hotspot/share/gc/z/zLiveMap.cpp index 2e4a8edd356cc..4123620f8b7e0 100644 --- a/src/hotspot/share/gc/z/zLiveMap.cpp +++ b/src/hotspot/share/gc/z/zLiveMap.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,7 +47,7 @@ ZLiveMap::ZLiveMap(uint32_t size) _segment_live_bits(0), _segment_claim_bits(0), _bitmap(bitmap_size(size, nsegments)), - _segment_shift(exact_log2(segment_size())) {} + _segment_shift(log2i_exact(segment_size())) {} void ZLiveMap::reset(ZGenerationId id) { ZGeneration* const generation = ZGeneration::generation(id); @@ -130,6 +130,6 @@ void ZLiveMap::resize(uint32_t size) { const size_t new_bitmap_size = bitmap_size(size, nsegments); if (_bitmap.size() != new_bitmap_size) { _bitmap.reinitialize(new_bitmap_size, false /* clear */); - _segment_shift = exact_log2(segment_size()); + _segment_shift = log2i_exact(segment_size()); } } diff --git a/src/hotspot/share/gc/z/zLiveMap.hpp b/src/hotspot/share/gc/z/zLiveMap.hpp index e3bcd2e267ddb..f8b16d06dc52c 100644 --- a/src/hotspot/share/gc/z/zLiveMap.hpp +++ b/src/hotspot/share/gc/z/zLiveMap.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,7 +43,7 @@ class ZLiveMap { BitMap::bm_word_t _segment_live_bits; BitMap::bm_word_t _segment_claim_bits; ZBitMap _bitmap; - size_t _segment_shift; + int _segment_shift; const BitMapView segment_live_bits() const; const BitMapView segment_claim_bits() const; diff --git a/src/hotspot/share/gc/z/zMarkCache.cpp b/src/hotspot/share/gc/z/zMarkCache.cpp index 7fbb5a8be4e61..0eecfbfaa6773 100644 --- a/src/hotspot/share/gc/z/zMarkCache.cpp +++ b/src/hotspot/share/gc/z/zMarkCache.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,7 +27,7 @@ #include "utilities/powerOfTwo.hpp" static size_t shift_for_stripes(size_t nstripes) { - return ZMarkStripeShift + exact_log2(nstripes); + return ZMarkStripeShift + (size_t)log2i_exact(nstripes); } ZMarkCacheEntry::ZMarkCacheEntry() diff --git a/src/hotspot/share/gc/z/zMarkStack.cpp b/src/hotspot/share/gc/z/zMarkStack.cpp index 1e10c41eb41dd..c4938af0a5f6d 100644 --- a/src/hotspot/share/gc/z/zMarkStack.cpp +++ b/src/hotspot/share/gc/z/zMarkStack.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -86,7 +86,7 @@ ZMarkStripe* ZMarkStripeSet::stripe_for_worker(uint nworkers, uint worker_id) { const size_t spillover_nworkers = nworkers - spillover_limit; const size_t spillover_worker_id = worker_id - spillover_limit; const double spillover_chunk = (double)nstripes / (double)spillover_nworkers; - index = spillover_worker_id * spillover_chunk; + index = (size_t)(spillover_worker_id * spillover_chunk); } assert(index < nstripes, "Invalid index"); diff --git a/src/hotspot/share/gc/z/zMetronome.cpp b/src/hotspot/share/gc/z/zMetronome.cpp index 0cc209cd7c843..876b1f6922799 100644 --- a/src/hotspot/share/gc/z/zMetronome.cpp +++ b/src/hotspot/share/gc/z/zMetronome.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,7 +38,7 @@ bool ZMetronome::wait_for_tick() { if (_nticks++ == 0) { // First tick, set start time const Ticks now = Ticks::now(); - _start_ms = TimeHelper::counter_to_millis(now.value()); + _start_ms = (uint64_t)TimeHelper::counter_to_millis(now.value()); } MonitorLocker ml(&_monitor, Monitor::_no_safepoint_check_flag); @@ -47,9 +47,9 @@ bool ZMetronome::wait_for_tick() { // We might wake up spuriously from wait, so always recalculate // the timeout after a wakeup to see if we need to wait again. const Ticks now = Ticks::now(); - const uint64_t now_ms = TimeHelper::counter_to_millis(now.value()); + const uint64_t now_ms = (uint64_t)TimeHelper::counter_to_millis(now.value()); const uint64_t next_ms = _start_ms + (_interval_ms * _nticks); - const int64_t timeout_ms = next_ms - now_ms; + const int64_t timeout_ms = (int64_t)(next_ms - now_ms); if (timeout_ms > 0) { // Wait @@ -57,7 +57,7 @@ bool ZMetronome::wait_for_tick() { } else { // Tick if (timeout_ms < 0) { - const uint64_t overslept = -timeout_ms; + const uint64_t overslept = (uint64_t)-timeout_ms; if (overslept > _interval_ms) { // Missed one or more ticks. Bump _nticks accordingly to // avoid firing a string of immediate ticks to make up diff --git a/src/hotspot/share/gc/z/zNMethod.cpp b/src/hotspot/share/gc/z/zNMethod.cpp index 7ae7b204d08c9..7c5b1e06edbb0 100644 --- a/src/hotspot/share/gc/z/zNMethod.cpp +++ b/src/hotspot/share/gc/z/zNMethod.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -302,8 +302,8 @@ void ZNMethod::nmethods_do(bool secondary, NMethodClosure* cl) { uintptr_t ZNMethod::color(nmethod* nm) { BarrierSetNMethod* bs_nm = BarrierSet::barrier_set()->barrier_set_nmethod(); - // color is stored at low order bits of int; implicit conversion to uintptr_t is fine - return bs_nm->guard_value(nm); + // color is stored at low order bits of int; conversion to uintptr_t is fine + return (uintptr_t)bs_nm->guard_value(nm); } oop ZNMethod::load_oop(oop* p, DecoratorSet decorators) { diff --git a/src/hotspot/share/gc/z/zNMethodTable.cpp b/src/hotspot/share/gc/z/zNMethodTable.cpp index a4b56292c522b..9714bee4bd88f 100644 --- a/src/hotspot/share/gc/z/zNMethodTable.cpp +++ b/src/hotspot/share/gc/z/zNMethodTable.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -144,9 +144,9 @@ void ZNMethodTable::rebuild_if_needed() { // grows/shrinks by doubling/halving its size. Pruning of unregistered // entries is done by rebuilding the table with or without resizing it. const size_t min_size = 1024; - const size_t shrink_threshold = _size * 0.30; - const size_t prune_threshold = _size * 0.65; - const size_t grow_threshold = _size * 0.70; + const size_t shrink_threshold = (size_t)(_size * 0.30); + const size_t prune_threshold = (size_t)(_size * 0.65); + const size_t grow_threshold = (size_t)(_size * 0.70); if (_size == 0) { // Initialize table diff --git a/src/hotspot/share/gc/z/zObjArrayAllocator.cpp b/src/hotspot/share/gc/z/zObjArrayAllocator.cpp index ad19f273dcf0f..ada8351a9f65f 100644 --- a/src/hotspot/share/gc/z/zObjArrayAllocator.cpp +++ b/src/hotspot/share/gc/z/zObjArrayAllocator.cpp @@ -76,8 +76,8 @@ oop ZObjArrayAllocator::initialize(HeapWord* mem) const { ZThreadLocalData::set_invisible_root(_thread, (zaddress_unsafe*)&mem); const BasicType element_type = ArrayKlass::cast(_klass)->element_type(); - const size_t base_offset_in_bytes = arrayOopDesc::base_offset_in_bytes(element_type); - const size_t process_start_offset_in_bytes = align_up(base_offset_in_bytes, BytesPerWord); + const size_t base_offset_in_bytes = (size_t)arrayOopDesc::base_offset_in_bytes(element_type); + const size_t process_start_offset_in_bytes = align_up(base_offset_in_bytes, (size_t)BytesPerWord); if (process_start_offset_in_bytes != base_offset_in_bytes) { // initialize_memory can only fill word aligned memory, diff --git a/src/hotspot/share/gc/z/zPage.inline.hpp b/src/hotspot/share/gc/z/zPage.inline.hpp index 0b4ee28ba7d0a..fcf69c685f7b6 100644 --- a/src/hotspot/share/gc/z/zPage.inline.hpp +++ b/src/hotspot/share/gc/z/zPage.inline.hpp @@ -83,13 +83,13 @@ inline uint32_t ZPage::object_max_count() const { inline size_t ZPage::object_alignment_shift() const { switch (type()) { case ZPageType::small: - return ZObjectAlignmentSmallShift; + return (size_t)ZObjectAlignmentSmallShift; case ZPageType::medium: - return ZObjectAlignmentMediumShift; + return (size_t)ZObjectAlignmentMediumShift; case ZPageType::large: - return ZObjectAlignmentLargeShift; + return (size_t)ZObjectAlignmentLargeShift; default: fatal("Unexpected page type"); @@ -100,13 +100,13 @@ inline size_t ZPage::object_alignment_shift() const { inline size_t ZPage::object_alignment() const { switch (type()) { case ZPageType::small: - return ZObjectAlignmentSmall; + return (size_t)ZObjectAlignmentSmall; case ZPageType::medium: - return ZObjectAlignmentMedium; + return (size_t)ZObjectAlignmentMedium; case ZPageType::large: - return ZObjectAlignmentLarge; + return (size_t)ZObjectAlignmentLarge; default: fatal("Unexpected page type"); diff --git a/src/hotspot/share/gc/z/zPageCache.cpp b/src/hotspot/share/gc/z/zPageCache.cpp index 96fd2eafe0f66..163bb395560de 100644 --- a/src/hotspot/share/gc/z/zPageCache.cpp +++ b/src/hotspot/share/gc/z/zPageCache.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -308,7 +308,7 @@ class ZPageCacheFlushForUncommitClosure : public ZPageCacheFlushClosure { }; size_t ZPageCache::flush_for_uncommit(size_t requested, ZList* to, uint64_t* timeout) { - const uint64_t now = os::elapsedTime(); + const uint64_t now = (uint64_t)os::elapsedTime(); const uint64_t expires = _last_commit + ZUncommitDelay; if (expires > now) { // Delay uncommit, set next timeout @@ -329,5 +329,5 @@ size_t ZPageCache::flush_for_uncommit(size_t requested, ZList* to, uint64 } void ZPageCache::set_last_commit() { - _last_commit = ceil(os::elapsedTime()); + _last_commit = (uint64_t)ceil(os::elapsedTime()); } diff --git a/src/hotspot/share/gc/z/zPageTable.inline.hpp b/src/hotspot/share/gc/z/zPageTable.inline.hpp index 3b4cbe9220cfb..79a2d297df889 100644 --- a/src/hotspot/share/gc/z/zPageTable.inline.hpp +++ b/src/hotspot/share/gc/z/zPageTable.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -69,7 +69,7 @@ inline ZPageTableParallelIterator::ZPageTableParallelIterator(const ZPageTable* template inline void ZPageTableParallelIterator::do_pages(Function function) { _index_distributor.do_indices([&](int index) { - ZPage* const page = _table->at(index); + ZPage* const page = _table->at(size_t(index)); if (page != nullptr) { const size_t start_index = untype(page->start()) >> ZGranuleSizeShift; if (size_t(index) == start_index) { diff --git a/src/hotspot/share/gc/z/zRelocationSet.cpp b/src/hotspot/share/gc/z/zRelocationSet.cpp index 92f245777b4e9..5c82f55bbbfe7 100644 --- a/src/hotspot/share/gc/z/zRelocationSet.cpp +++ b/src/hotspot/share/gc/z/zRelocationSet.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -84,7 +84,7 @@ class ZRelocationSetInstallTask : public ZTask { : ZTask("ZRelocationSetInstallTask"), _allocator(allocator), _forwardings(nullptr), - _nforwardings(selector->selected_small()->length() + selector->selected_medium()->length()), + _nforwardings((size_t)selector->selected_small()->length() + (size_t)selector->selected_medium()->length()), _small(selector->selected_small()), _medium(selector->selected_medium()), _small_iter(selector->selected_small()), @@ -113,7 +113,7 @@ class ZRelocationSetInstallTask : public ZTask { for (size_t page_index; _small_iter.next_index(&page_index);) { ZPage* page = _small->at(int(page_index)); ZForwarding* const forwarding = ZForwarding::alloc(_allocator, page, to_age(page)); - install_small(forwarding, _medium->length() + page_index); + install_small(forwarding, (size_t)_medium->length() + page_index); SuspendibleThreadSet::yield(); } diff --git a/src/hotspot/share/gc/z/zRelocationSetSelector.cpp b/src/hotspot/share/gc/z/zRelocationSetSelector.cpp index ab1df68fe5110..ec904b914fb0b 100644 --- a/src/hotspot/share/gc/z/zRelocationSetSelector.cpp +++ b/src/hotspot/share/gc/z/zRelocationSetSelector.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -51,7 +51,7 @@ ZRelocationSetSelectorGroup::ZRelocationSetSelectorGroup(const char* name, _page_size(page_size), _object_size_limit(object_size_limit), _fragmentation_limit(fragmentation_limit), - _page_fragmentation_limit(page_size * (fragmentation_limit / 100)), + _page_fragmentation_limit((size_t)(page_size * (fragmentation_limit / 100))), _live_pages(), _not_selected_pages(), _forwarding_entries(0), @@ -72,7 +72,7 @@ void ZRelocationSetSelectorGroup::semi_sort() { const size_t npartitions_shift = 11; const size_t npartitions = (size_t)1 << npartitions_shift; const size_t partition_size = _page_size >> npartitions_shift; - const size_t partition_size_shift = exact_log2(partition_size); + const int partition_size_shift = log2i_exact(partition_size); // Partition slots/fingers int partitions[npartitions] = { /* zero initialize */ }; @@ -135,7 +135,7 @@ void ZRelocationSetSelectorGroup::select_inner() { // By subtracting the object size limit from the pages size we get the maximum // number of pages that the relocation set is guaranteed to fit in, regardless // of in which order the objects are relocated. - const int to = ceil((double)(from_live_bytes) / (double)(_page_size - _object_size_limit)); + const int to = (int)ceil(from_live_bytes / (double)(_page_size - _object_size_limit)); // Calculate the relative difference in reclaimable space compared to our // currently selected final relocation set. If this number is larger than the diff --git a/src/hotspot/share/gc/z/zStat.cpp b/src/hotspot/share/gc/z/zStat.cpp index d838cb0b8138a..613f7b2740b43 100644 --- a/src/hotspot/share/gc/z/zStat.cpp +++ b/src/hotspot/share/gc/z/zStat.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -250,14 +250,14 @@ void ZStatUnitTime(LogTargetHandle log, const ZStatSampler& sampler, const ZStat "%9.3f / %-9.3f ms", sampler.group(), sampler.name(), - TimeHelper::counter_to_millis(history.avg_10_seconds()), - TimeHelper::counter_to_millis(history.max_10_seconds()), - TimeHelper::counter_to_millis(history.avg_10_minutes()), - TimeHelper::counter_to_millis(history.max_10_minutes()), - TimeHelper::counter_to_millis(history.avg_10_hours()), - TimeHelper::counter_to_millis(history.max_10_hours()), - TimeHelper::counter_to_millis(history.avg_total()), - TimeHelper::counter_to_millis(history.max_total())); + TimeHelper::counter_to_millis((jlong)history.avg_10_seconds()), + TimeHelper::counter_to_millis((jlong)history.max_10_seconds()), + TimeHelper::counter_to_millis((jlong)history.avg_10_minutes()), + TimeHelper::counter_to_millis((jlong)history.max_10_minutes()), + TimeHelper::counter_to_millis((jlong)history.avg_10_hours()), + TimeHelper::counter_to_millis((jlong)history.max_10_hours()), + TimeHelper::counter_to_millis((jlong)history.avg_total()), + TimeHelper::counter_to_millis((jlong)history.max_total())); } void ZStatUnitBytes(LogTargetHandle log, const ZStatSampler& sampler, const ZStatSamplerHistory& history) { @@ -677,7 +677,7 @@ void ZStatPhaseCollection::register_end(ConcurrentGCTimer* timer, const Ticks& s ZCollectedHeap::heap()->trace_heap_after_gc(jfr_tracer()); const Tickspan duration = end - start; - ZStatSample(_sampler, duration.value()); + ZStatDurationSample(_sampler, duration); const size_t used_at_end = ZHeap::heap()->used(); @@ -718,7 +718,7 @@ void ZStatPhaseGeneration::register_end(ConcurrentGCTimer* timer, const Ticks& s ZCollectedHeap::heap()->print_heap_after_gc(); const Tickspan duration = end - start; - ZStatSample(_sampler, duration.value()); + ZStatDurationSample(_sampler, duration); ZGeneration* const generation = ZGeneration::generation(_id); @@ -766,7 +766,7 @@ void ZStatPhasePause::register_end(ConcurrentGCTimer* timer, const Ticks& start, timer->register_gc_pause_end(end); const Tickspan duration = end - start; - ZStatSample(_sampler, duration.value()); + ZStatDurationSample(_sampler, duration); // Track max pause time if (_max < duration) { @@ -798,7 +798,7 @@ void ZStatPhaseConcurrent::register_end(ConcurrentGCTimer* timer, const Ticks& s timer->register_gc_concurrent_end(end); const Tickspan duration = end - start; - ZStatSample(_sampler, duration.value()); + ZStatDurationSample(_sampler, duration); LogTarget(Info, gc, phases) log; log_end(log, duration); @@ -835,7 +835,7 @@ void ZStatSubPhase::register_end(ConcurrentGCTimer* timer, const Ticks& start, c ZTracer::report_thread_phase(name(), start, end); const Tickspan duration = end - start; - ZStatSample(_sampler, duration.value()); + ZStatDurationSample(_sampler, duration); if (Thread::current()->is_Worker_thread()) { LogTarget(Trace, gc, phases) log; @@ -862,7 +862,7 @@ void ZStatCriticalPhase::register_end(ConcurrentGCTimer* timer, const Ticks& sta ZTracer::report_thread_phase(name(), start, end); const Tickspan duration = end - start; - ZStatSample(_sampler, duration.value()); + ZStatDurationSample(_sampler, duration); ZStatInc(_counter); if (_verbose) { @@ -914,6 +914,10 @@ void ZStatSample(const ZStatSampler& sampler, uint64_t value) { ZTracer::report_stat_sampler(sampler, value); } +void ZStatDurationSample(const ZStatSampler& sampler, const Tickspan& duration) { + ZStatSample(sampler, (uint64_t)duration.value()); +} + void ZStatInc(const ZStatCounter& counter, uint64_t increment) { ZStatCounterData* const cpu_data = counter.get(); const uint64_t value = Atomic::add(&cpu_data->_counter, increment); @@ -1036,7 +1040,7 @@ void ZStat::sample_and_collect(ZStatSamplerHistory* history) const { bool ZStat::should_print(LogTargetHandle log) const { static uint64_t print_at = ZStatisticsInterval; - const uint64_t now = os::elapsedTime(); + const uint64_t now = (uint64_t)os::elapsedTime(); if (now < print_at) { return false; @@ -1846,7 +1850,7 @@ void ZStatHeap::at_relocate_end(const ZPageAllocatorStats& stats, bool record_st } size_t ZStatHeap::reclaimed_avg() { - return _reclaimed_bytes.davg(); + return (size_t)_reclaimed_bytes.davg(); } size_t ZStatHeap::max_capacity() { diff --git a/src/hotspot/share/gc/z/zStat.hpp b/src/hotspot/share/gc/z/zStat.hpp index 346773c3b7e2a..d7482dbe6aaaf 100644 --- a/src/hotspot/share/gc/z/zStat.hpp +++ b/src/hotspot/share/gc/z/zStat.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -345,6 +345,7 @@ class ZStatTimerWorker : public ZStatTimer { // Stat sample/increment // void ZStatSample(const ZStatSampler& sampler, uint64_t value); +void ZStatDurationSample(const ZStatSampler& sampler, const Tickspan& duration); void ZStatInc(const ZStatCounter& counter, uint64_t increment = 1); void ZStatInc(const ZStatUnsampledCounter& counter, uint64_t increment = 1); diff --git a/src/hotspot/share/gc/z/zStoreBarrierBuffer.cpp b/src/hotspot/share/gc/z/zStoreBarrierBuffer.cpp index 537609e723bbb..c94551dc62d20 100644 --- a/src/hotspot/share/gc/z/zStoreBarrierBuffer.cpp +++ b/src/hotspot/share/gc/z/zStoreBarrierBuffer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -79,7 +79,7 @@ void ZStoreBarrierBuffer::install_base_pointers_inner() { (ZPointer::remap_bits(_last_processed_color) & ZPointerRemappedOldMask) == 0, "Should not have double bit errors"); - for (int i = current(); i < (int)_buffer_length; ++i) { + for (size_t i = current(); i < _buffer_length; ++i) { const ZStoreBarrierEntry& entry = _buffer[i]; volatile zpointer* const p = entry._p; const zaddress_unsafe p_unsafe = to_zaddress_unsafe((uintptr_t)p); @@ -141,7 +141,7 @@ static volatile zpointer* make_load_good(volatile zpointer* p, zaddress_unsafe p return (volatile zpointer*)p_remapped; } -void ZStoreBarrierBuffer::on_new_phase_relocate(int i) { +void ZStoreBarrierBuffer::on_new_phase_relocate(size_t i) { const uintptr_t last_remap_bits = ZPointer::remap_bits(_last_processed_color); if (last_remap_bits == ZPointerRemapped) { // All pointers are already remapped @@ -160,7 +160,7 @@ void ZStoreBarrierBuffer::on_new_phase_relocate(int i) { entry._p = make_load_good(entry._p, p_base, _last_processed_color); } -void ZStoreBarrierBuffer::on_new_phase_remember(int i) { +void ZStoreBarrierBuffer::on_new_phase_remember(size_t i) { volatile zpointer* const p = _buffer[i]._p; if (ZHeap::heap()->is_young(p)) { @@ -197,7 +197,7 @@ bool ZStoreBarrierBuffer::stored_during_old_mark() const { return last_mark_old_bits == ZPointerMarkedOld; } -void ZStoreBarrierBuffer::on_new_phase_mark(int i) { +void ZStoreBarrierBuffer::on_new_phase_mark(size_t i) { const ZStoreBarrierEntry& entry = _buffer[i]; const zpointer prev = entry._prev; @@ -229,7 +229,7 @@ void ZStoreBarrierBuffer::on_new_phase() { // Install all base pointers for relocation install_base_pointers(); - for (int i = current(); i < (int)_buffer_length; ++i) { + for (size_t i = current(); i < _buffer_length; ++i) { on_new_phase_relocate(i); on_new_phase_remember(i); on_new_phase_mark(i); @@ -259,8 +259,8 @@ void ZStoreBarrierBuffer::on_error(outputStream* st) { st->print_cr(" _last_processed_color: " PTR_FORMAT, _last_processed_color); st->print_cr(" _last_installed_color: " PTR_FORMAT, _last_installed_color); - for (int i = current(); i < (int)_buffer_length; ++i) { - st->print_cr(" [%2d]: base: " PTR_FORMAT " p: " PTR_FORMAT " prev: " PTR_FORMAT, + for (size_t i = current(); i < _buffer_length; ++i) { + st->print_cr(" [%2zu]: base: " PTR_FORMAT " p: " PTR_FORMAT " prev: " PTR_FORMAT, i, untype(_base_pointers[i]), p2i(_buffer[i]._p), @@ -276,7 +276,7 @@ void ZStoreBarrierBuffer::flush() { OnError on_error(this); VMErrorCallbackMark mark(&on_error); - for (int i = current(); i < (int)_buffer_length; ++i) { + for (size_t i = current(); i < _buffer_length; ++i) { const ZStoreBarrierEntry& entry = _buffer[i]; const zaddress addr = ZBarrier::make_load_good(entry._prev); ZBarrier::mark_and_remember(entry._p, addr); @@ -296,7 +296,7 @@ bool ZStoreBarrierBuffer::is_in(volatile zpointer* p) { const uintptr_t last_remap_bits = ZPointer::remap_bits(buffer->_last_processed_color) & ZPointerRemappedMask; const bool needs_remap = last_remap_bits != ZPointerRemapped; - for (int i = buffer->current(); i < (int)_buffer_length; ++i) { + for (size_t i = buffer->current(); i < _buffer_length; ++i) { const ZStoreBarrierEntry& entry = buffer->_buffer[i]; volatile zpointer* entry_p = entry._p; diff --git a/src/hotspot/share/gc/z/zStoreBarrierBuffer.hpp b/src/hotspot/share/gc/z/zStoreBarrierBuffer.hpp index f917a6c3e7b58..5903edb6ad409 100644 --- a/src/hotspot/share/gc/z/zStoreBarrierBuffer.hpp +++ b/src/hotspot/share/gc/z/zStoreBarrierBuffer.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -59,16 +59,16 @@ class ZStoreBarrierBuffer : public CHeapObj { // sizeof(ZStoreBarrierEntry) scaled index growing downwards size_t _current; - void on_new_phase_relocate(int i); - void on_new_phase_remember(int i); - void on_new_phase_mark(int i); + void on_new_phase_relocate(size_t i); + void on_new_phase_remember(size_t i); + void on_new_phase_mark(size_t i); void clear(); bool is_old_mark() const; bool stored_during_old_mark() const; bool is_empty() const; - intptr_t current() const; + size_t current() const; void install_base_pointers_inner(); diff --git a/src/hotspot/share/gc/z/zStoreBarrierBuffer.inline.hpp b/src/hotspot/share/gc/z/zStoreBarrierBuffer.inline.hpp index 762aac3ccd5bf..72327fe83466b 100644 --- a/src/hotspot/share/gc/z/zStoreBarrierBuffer.inline.hpp +++ b/src/hotspot/share/gc/z/zStoreBarrierBuffer.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,7 @@ #include "gc/z/zThreadLocalData.hpp" #include "runtime/thread.hpp" -inline intptr_t ZStoreBarrierBuffer::current() const { +inline size_t ZStoreBarrierBuffer::current() const { return _current / sizeof(ZStoreBarrierEntry); } diff --git a/src/hotspot/share/gc/z/zUnmapper.cpp b/src/hotspot/share/gc/z/zUnmapper.cpp index 3b2bac7eb00a7..b6ef40b6b059f 100644 --- a/src/hotspot/share/gc/z/zUnmapper.cpp +++ b/src/hotspot/share/gc/z/zUnmapper.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -85,7 +85,7 @@ bool ZUnmapper::try_enqueue(ZPage* page) { } size_t ZUnmapper::queue_capacity() const { - return align_up(_page_allocator->max_capacity() * ZAsyncUnmappingLimit / 100.0, ZGranuleSize); + return align_up((size_t)(_page_allocator->max_capacity() * ZAsyncUnmappingLimit / 100.0), ZGranuleSize); } bool ZUnmapper::is_saturated() const { diff --git a/src/hotspot/share/gc/z/zVerify.cpp b/src/hotspot/share/gc/z/zVerify.cpp index fba8adfb3c16f..d47886ec7c2fc 100644 --- a/src/hotspot/share/gc/z/zVerify.cpp +++ b/src/hotspot/share/gc/z/zVerify.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -583,7 +583,7 @@ void ZVerify::on_color_flip() { for (JavaThreadIteratorWithHandle jtiwh; JavaThread* const jt = jtiwh.next(); ) { const ZStoreBarrierBuffer* const buffer = ZThreadLocalData::store_barrier_buffer(jt); - for (int i = buffer->current(); i < (int)ZStoreBarrierBuffer::_buffer_length; ++i) { + for (size_t i = buffer->current(); i < ZStoreBarrierBuffer::_buffer_length; ++i) { volatile zpointer* const p = buffer->_buffer[i]._p; bool created = false; z_verify_store_barrier_buffer_table->put_if_absent(p, true, &created); From d19ba81ce12a99de1114c1bfe67392f5aee2104e Mon Sep 17 00:00:00 2001 From: Naoto Sato Date: Wed, 7 Aug 2024 15:58:03 +0000 Subject: [PATCH 221/353] 8337603: Change in behavior with -Djava.locale.useOldISOCodes=true Reviewed-by: iris, bpb --- .../util/locale/provider/LocaleResources.java | 13 ++++++- test/jdk/java/util/Locale/LocaleTest.java | 35 +++++++++++++++++-- 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java b/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java index e83f2896304af..ee6ec0f72baa8 100644 --- a/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java +++ b/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -62,6 +62,7 @@ import java.util.regex.Pattern; import java.util.stream.Stream; +import jdk.internal.util.StaticProperty; import sun.security.action.GetPropertyAction; import sun.util.resources.LocaleData; import sun.util.resources.OpenListResourceBundle; @@ -289,6 +290,16 @@ public String getCurrencyName(String key) { } public String getLocaleName(String key) { + // Get names for old ISO codes with new ISO code resources + if (StaticProperty.javaLocaleUseOldISOCodes().equalsIgnoreCase("true")) { + key = switch (key) { + case "iw" -> "he"; + case "in" -> "id"; + case "ji" -> "yi"; + default -> key; + }; + } + Object localeName = null; String cacheKey = LOCALE_NAMES + key; diff --git a/test/jdk/java/util/Locale/LocaleTest.java b/test/jdk/java/util/Locale/LocaleTest.java index c6afbc099ae75..0cf272f20a0d2 100644 --- a/test/jdk/java/util/Locale/LocaleTest.java +++ b/test/jdk/java/util/Locale/LocaleTest.java @@ -20,12 +20,13 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -/** +/* * @test * @bug 4052404 4052440 4084688 4092475 4101316 4105828 4107014 4107953 4110613 * 4118587 4118595 4122371 4126371 4126880 4135316 4135752 4139504 4139940 4143951 * 4147315 4147317 4147552 4335196 4778440 4940539 5010672 6475525 6544471 6627549 * 6786276 7066203 7085757 8008577 8030696 8170840 8174269 8255086 8263202 8287868 + * 8337603 * @summary test Locales * @modules jdk.localedata * @run junit LocaleTest @@ -84,9 +85,13 @@ import java.util.List; import java.util.Locale; import java.util.MissingResourceException; +import java.util.stream.Stream; import org.junit.jupiter.api.Test; - +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.fail; public class LocaleTest { @@ -734,6 +739,32 @@ public void TestChangedISO639Codes() { } + /** + * @bug 8337603 + */ + static Stream changedISOCodes() { + var hebrew = "\u05e2\u05d1\u05e8\u05d9\u05ea"; + var yiddish = "\u05d9\u05d9\u05b4\u05d3\u05d9\u05e9"; + var indonesian = "Indonesia"; + + return Stream.of( + Arguments.of("he", hebrew), + Arguments.of("iw", hebrew), + Arguments.of("yi", yiddish), + Arguments.of("ji", yiddish), + Arguments.of("id", indonesian), + Arguments.of("in", indonesian) + ); + } + @ParameterizedTest + @MethodSource("changedISOCodes") + public void TestOldISOCodeLanguageName(String code, String expected) { + var loc = Locale.of(code); + assertEquals(expected, + loc.getDisplayName(loc), + "java.locale.useOldISOCodes=" + System.getProperty("java.locale.useOldISOCodes")); + } + /** * @bug 4092475 * I could not reproduce this bug. I'm pretty convinced it was fixed with the From 36d08c213d03deddf69ecb9770a3afef73a15444 Mon Sep 17 00:00:00 2001 From: Serguei Spitsyn Date: Wed, 7 Aug 2024 17:41:23 +0000 Subject: [PATCH 222/353] 8336846: assert(state->get_thread() == jt) failed: handshake unsafe conditions Reviewed-by: amenkov, dholmes, cjplummer, pchilanomate, lmesnik --- src/hotspot/share/prims/jvmtiEventController.cpp | 4 +++- src/hotspot/share/runtime/mutexLocker.cpp | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/prims/jvmtiEventController.cpp b/src/hotspot/share/prims/jvmtiEventController.cpp index d5c5d53ba8104..c9867ff164350 100644 --- a/src/hotspot/share/prims/jvmtiEventController.cpp +++ b/src/hotspot/share/prims/jvmtiEventController.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -982,6 +982,8 @@ JvmtiEventControllerPrivate::change_field_watch(jvmtiEvent event_type, bool adde added? "add" : "remove", *count_addr)); + JvmtiVTMSTransitionDisabler disabler; + if (added) { (*count_addr)++; if (*count_addr == 1) { diff --git a/src/hotspot/share/runtime/mutexLocker.cpp b/src/hotspot/share/runtime/mutexLocker.cpp index a63014d78a171..8c1dff38051d9 100644 --- a/src/hotspot/share/runtime/mutexLocker.cpp +++ b/src/hotspot/share/runtime/mutexLocker.cpp @@ -269,7 +269,6 @@ void mutex_init() { MUTEX_DEFN(JvmtiThreadState_lock , PaddedMutex , safepoint); // Used by JvmtiThreadState/JvmtiEventController MUTEX_DEFN(EscapeBarrier_lock , PaddedMonitor, nosafepoint); // Used to synchronize object reallocation/relocking triggered by JVMTI - MUTEX_DEFN(JvmtiVTMSTransition_lock , PaddedMonitor, safepoint); // used for Virtual Thread Mount State transition management MUTEX_DEFN(Management_lock , PaddedMutex , safepoint); // used for JVM management MUTEX_DEFN(ConcurrentGCBreakpoints_lock , PaddedMonitor, safepoint, true); @@ -355,6 +354,7 @@ void mutex_init() { // JVMCIRuntime_lock must be acquired before JVMCI_lock to avoid deadlock MUTEX_DEFL(JVMCI_lock , PaddedMonitor, JVMCIRuntime_lock); #endif + MUTEX_DEFL(JvmtiVTMSTransition_lock , PaddedMonitor, JvmtiThreadState_lock); // used for Virtual Thread Mount State transition management // Allocate RecursiveMutex MultiArray_lock = new RecursiveMutex(); From a5c2d7b305407974b3f67c48b8dcb1f8e77abde3 Mon Sep 17 00:00:00 2001 From: Fernando Guallini Date: Wed, 7 Aug 2024 18:24:08 +0000 Subject: [PATCH 223/353] 8335172: Add manual steps to run security/auth/callback/TextCallbackHandler/Password.java test Reviewed-by: rhalade --- test/jdk/ProblemList.txt | 1 - test/jdk/TEST.groups | 2 +- .../callback/TextCallbackHandler/Password.java | 16 ++++++++++++++-- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 3211f27b5c1e4..84c7a7d855f73 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -606,7 +606,6 @@ sun/security/smartcardio/TestExclusive.java 8039280 generic- sun/security/smartcardio/TestMultiplePresent.java 8039280 generic-all sun/security/smartcardio/TestPresent.java 8039280 generic-all sun/security/smartcardio/TestTransmit.java 8039280 generic-all -com/sun/security/auth/callback/TextCallbackHandler/Password.java 8039280 generic-all com/sun/security/sasl/gsskerb/AuthOnly.java 8039280 generic-all com/sun/security/sasl/gsskerb/ConfSecurityLayer.java 8039280 generic-all com/sun/security/sasl/gsskerb/NoSecurityLayer.java 8039280 generic-all diff --git a/test/jdk/TEST.groups b/test/jdk/TEST.groups index 55ae0e9c67b14..97b355fbea6c5 100644 --- a/test/jdk/TEST.groups +++ b/test/jdk/TEST.groups @@ -623,7 +623,6 @@ jdk_security_manual_no_input = \ :jdk_security_infra \ com/sun/crypto/provider/Cipher/AEAD/GCMIncrementByte4.java \ com/sun/crypto/provider/Cipher/AEAD/GCMIncrementDirect4.java \ - com/sun/security/auth/callback/TextCallbackHandler/Password.java \ com/sun/security/sasl/gsskerb/AuthOnly.java \ com/sun/security/sasl/gsskerb/ConfSecurityLayer.java \ com/sun/security/sasl/gsskerb/NoSecurityLayer.java \ @@ -652,6 +651,7 @@ jdk_core_manual_interactive = \ jdk_security_manual_interactive = \ sun/security/tools/keytool/i18n.java \ java/security/Policy/Root/Root.java \ + com/sun/security/auth/callback/TextCallbackHandler/Password.java \ sun/security/krb5/config/native/TestDynamicStore.java # Test sets for running inside container environment diff --git a/test/jdk/com/sun/security/auth/callback/TextCallbackHandler/Password.java b/test/jdk/com/sun/security/auth/callback/TextCallbackHandler/Password.java index b34ef04355867..f9231a0b36edc 100644 --- a/test/jdk/com/sun/security/auth/callback/TextCallbackHandler/Password.java +++ b/test/jdk/com/sun/security/auth/callback/TextCallbackHandler/Password.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,11 +23,23 @@ /* * @test - * @bug 6825240 + * @bug 6825240 6829785 * @summary Password.readPassword() echos the input when System.Console is null * @run main/manual Password */ +/* + * This scenario cannot be automated because util/Password.java verifies the given input stream is + * equal to the initialSystemIn. This prevents the test from providing a custom input stream. + * + * Steps to run the test: + * 1) Compile the class using the JDK version being tested: '/javac Password.java' + * 2) Run the test using the JDK version being tested: '/java -cp . Password' + * 3) Type in the first password, it should not be visible in the console + * 4) Type in the second password, it should be visible in the console + * 5) The final output line displays the entered passwords, both should be visible + */ + import com.sun.security.auth.callback.TextCallbackHandler; import javax.security.auth.callback.*; From 5e021cbcc7a6cb30a27380950e115ff12846239c Mon Sep 17 00:00:00 2001 From: Leonid Mesnik Date: Wed, 7 Aug 2024 20:25:51 +0000 Subject: [PATCH 224/353] 8337410: The makefiles should set problemlist and adjust timeout basing on the given VM flags Reviewed-by: ihse --- make/RunTests.gmk | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/make/RunTests.gmk b/make/RunTests.gmk index b0291e4eff4e7..8cfee45892339 100644 --- a/make/RunTests.gmk +++ b/make/RunTests.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -748,8 +748,6 @@ define SetupRunJtregTestBody # we may end up with a lot of JVM's $1_JTREG_MAX_RAM_PERCENTAGE := $$(shell $(AWK) 'BEGIN { print 25 / $$($1_JTREG_JOBS); }') - JTREG_TIMEOUT_FACTOR ?= 4 - JTREG_VERBOSE ?= fail,error,summary JTREG_RETAIN ?= fail,error JTREG_TEST_THREAD_FACTORY ?= @@ -837,6 +835,24 @@ define SetupRunJtregTestBody $1_JTREG_BASIC_OPTIONS += $$(addprefix $$(JTREG_PROBLEM_LIST_PREFIX), $$($1_JTREG_PROBLEM_LIST)) endif + JTREG_ALL_OPTIONS := $$(JTREG_JAVA_OPTIONS) $$(JTREG_VM_OPTIONS) + + JTREG_AUTO_PROBLEM_LISTS := + JTREG_AUTO_TIMEOUT_FACTOR := 4 + + ifneq ($$(findstring -Xcomp, $$(JTREG_ALL_OPTIONS)), ) + JTREG_AUTO_PROBLEM_LISTS += ProblemList-Xcomp.txt + JTREG_AUTO_TIMEOUT_FACTOR := 10 + endif + + ifneq ($$(findstring -XX:+UseZGC, $$(JTREG_ALL_OPTIONS)), ) + ifneq ($$(findstring -XX:-ZGenerational, $$(JTREG_ALL_OPTIONS)), ) + JTREG_AUTO_PROBLEM_LISTS += ProblemList-zgc.txt + else + JTREG_AUTO_PROBLEM_LISTS += ProblemList-generational-zgc.txt + endif + endif + ifneq ($$(JTREG_EXTRA_PROBLEM_LISTS), ) # Accept both absolute paths as well as relative to the current test root. $1_JTREG_BASIC_OPTIONS += $$(addprefix $$(JTREG_PROBLEM_LIST_PREFIX), $$(wildcard \ @@ -868,6 +884,18 @@ define SetupRunJtregTestBody $$(eval $$(call SetupRunJtregTestCustom, $1)) + # SetupRunJtregTestCustom might also adjust JTREG_AUTO_ variables + # so set the final results after setting values from custom setup + ifneq ($$(JTREG_AUTO_PROBLEM_LISTS), ) + # Accept both absolute paths as well as relative to the current test root. + $1_JTREG_BASIC_OPTIONS += $$(addprefix $$(JTREG_PROBLEM_LIST_PREFIX), $$(wildcard \ + $$(JTREG_AUTO_PROBLEM_LISTS) \ + $$(addprefix $$($1_TEST_ROOT)/, $$(JTREG_AUTO_PROBLEM_LISTS)) \ + )) + endif + + JTREG_TIMEOUT_FACTOR ?= $$(JTREG_AUTO_TIMEOUT_FACTOR) + clean-outputdirs-$1: $$(RM) -r $$($1_TEST_SUPPORT_DIR) $$(RM) -r $$($1_TEST_RESULTS_DIR) From 9b11bd7f4a511ddadf9f02e82aab6ba78beb6763 Mon Sep 17 00:00:00 2001 From: Jamil Nimeh Date: Wed, 7 Aug 2024 21:06:47 +0000 Subject: [PATCH 225/353] 8337826: Improve logging in OCSPTimeout and SimpleOCSPResponder to help diagnose JDK-8309754 Reviewed-by: mullan --- .../CertPathValidator/OCSP/OCSPTimeout.java | 124 ++++++++++-------- .../testlibrary/SimpleOCSPServer.java | 16 ++- 2 files changed, 81 insertions(+), 59 deletions(-) diff --git a/test/jdk/java/security/cert/CertPathValidator/OCSP/OCSPTimeout.java b/test/jdk/java/security/cert/CertPathValidator/OCSP/OCSPTimeout.java index 3e2648af7cb5f..dfd7dcdc81efe 100644 --- a/test/jdk/java/security/cert/CertPathValidator/OCSP/OCSPTimeout.java +++ b/test/jdk/java/security/cert/CertPathValidator/OCSP/OCSPTimeout.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,17 +36,17 @@ * java.base/sun.security.util * @library ../../../../../java/security/testlibrary * @build CertificateBuilder SimpleOCSPServer - * @run main/othervm OCSPTimeout 1000 true - * @run main/othervm -Dcom.sun.security.ocsp.readtimeout=5 - * OCSPTimeout 1000 true - * @run main/othervm -Dcom.sun.security.ocsp.readtimeout=1 - * OCSPTimeout 5000 false - * @run main/othervm -Dcom.sun.security.ocsp.readtimeout=1s - * OCSPTimeout 5000 false - * @run main/othervm -Dcom.sun.security.ocsp.readtimeout=1500ms - * OCSPTimeout 5000 false - * @run main/othervm -Dcom.sun.security.ocsp.readtimeout=4500ms - * OCSPTimeout 1000 true + * @run main/othervm -Djava.security.debug=certpath OCSPTimeout 1000 true + * @run main/othervm -Djava.security.debug=certpath + * -Dcom.sun.security.ocsp.readtimeout=5 OCSPTimeout 1000 true + * @run main/othervm -Djava.security.debug=certpath + * -Dcom.sun.security.ocsp.readtimeout=1 OCSPTimeout 5000 false + * @run main/othervm -Djava.security.debug=certpath + * -Dcom.sun.security.ocsp.readtimeout=1s OCSPTimeout 5000 false + * @run main/othervm -Djava.security.debug=certpath + * -Dcom.sun.security.ocsp.readtimeout=1500ms OCSPTimeout 5000 false + * @run main/othervm -Djava.security.debug=certpath + * -Dcom.sun.security.ocsp.readtimeout=4500ms OCSPTimeout 1000 true */ import java.io.*; @@ -82,62 +82,72 @@ public class OCSPTimeout { static SimpleOCSPServer rootOcsp; // Root CA OCSP Responder static int rootOcspPort; // Port number for root OCSP - public static void main(String args[]) throws Exception { + public static void main(String[] args) throws Exception { int ocspTimeout = 15000; boolean expected = false; createPKI(); - if (args[0] != null) { - ocspTimeout = Integer.parseInt(args[0]); - } - rootOcsp.setDelay(ocspTimeout); - - expected = (args[1] != null && Boolean.parseBoolean(args[1])); - log("Test case expects to " + (expected ? "pass" : "fail")); - - // validate chain - CertPathValidator cpv = CertPathValidator.getInstance("PKIX"); - PKIXRevocationChecker prc = - (PKIXRevocationChecker) cpv.getRevocationChecker(); - prc.setOptions(EnumSet.of(NO_FALLBACK, SOFT_FAIL)); - PKIXParameters params = - new PKIXParameters(Set.of(new TrustAnchor(rootCert, null))); - params.addCertPathChecker(prc); - CertificateFactory cf = CertificateFactory.getInstance("X.509"); - CertPath cp = cf.generateCertPath(List.of(eeCert)); - cpv.validate(cp, params); - - // unwrap soft fail exceptions and check for SocketTimeoutException - List softExc = prc.getSoftFailExceptions(); - if (expected) { - if (softExc.size() > 0) { - throw new RuntimeException("Expected to pass, found " + - softExc.size() + " soft fail exceptions"); + try { + if (args[0] != null) { + ocspTimeout = Integer.parseInt(args[0]); } - } else { - // If we expect to fail the validation then there should be a - // SocketTimeoutException - boolean found = false; - for (CertPathValidatorException softFail : softExc) { - log("CPVE: " + softFail); - Throwable cause = softFail.getCause(); - log("Cause: " + cause); - while (cause != null) { - if (cause instanceof SocketTimeoutException) { - found = true; - break; + rootOcsp.setDelay(ocspTimeout); + + expected = (args[1] != null && Boolean.parseBoolean(args[1])); + log("Test case expects to " + (expected ? "pass" : "fail")); + + // validate chain + CertPathValidator cpv = CertPathValidator.getInstance("PKIX"); + PKIXRevocationChecker prc = + (PKIXRevocationChecker) cpv.getRevocationChecker(); + prc.setOptions(EnumSet.of(NO_FALLBACK, SOFT_FAIL)); + PKIXParameters params = + new PKIXParameters(Set.of(new TrustAnchor(rootCert, null))); + params.addCertPathChecker(prc); + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + CertPath cp = cf.generateCertPath(List.of(eeCert)); + cpv.validate(cp, params); + + // unwrap soft fail exceptions and check for SocketTimeoutException + List softExc = prc.getSoftFailExceptions(); + if (expected) { + if (!softExc.isEmpty()) { + log("Expected to pass, found " + softExc.size() + + " soft fail exceptions"); + for (CertPathValidatorException cpve : softExc) { + log("Exception: " + cpve); } - cause = cause.getCause(); + throw new RuntimeException("Expected to pass, found " + + softExc.size() + " soft fail exceptions"); } - if (found) { - break; + } else { + // If we expect to fail the validation then there should be a + // SocketTimeoutException + boolean found = false; + for (CertPathValidatorException softFail : softExc) { + log("CPVE: " + softFail); + Throwable cause = softFail.getCause(); + log("Cause: " + cause); + while (cause != null) { + if (cause instanceof SocketTimeoutException) { + found = true; + break; + } + cause = cause.getCause(); + } + if (found) { + break; + } } - } - if (!found) { - throw new RuntimeException("SocketTimeoutException not thrown"); + if (!found) { + throw new RuntimeException("SocketTimeoutException not thrown"); + } } + } finally { + rootOcsp.stop(); + rootOcsp.shutdownNow(); } } diff --git a/test/jdk/java/security/testlibrary/SimpleOCSPServer.java b/test/jdk/java/security/testlibrary/SimpleOCSPServer.java index e1883edeec51f..5b9fb23c4ef90 100644 --- a/test/jdk/java/security/testlibrary/SimpleOCSPServer.java +++ b/test/jdk/java/security/testlibrary/SimpleOCSPServer.java @@ -572,8 +572,8 @@ public void setDisableContentLength(boolean isDisabled) { */ private synchronized void log(String message) { if (logEnabled || debug != null) { - System.out.println("[" + Thread.currentThread().getName() + "]: " + - message); + System.out.println("[" + Thread.currentThread().getName() + "][" + + System.currentTimeMillis() + "]: " + message); } } @@ -727,6 +727,7 @@ public void run() { // wait out the delay here before any other processing. try { if (delayMsec > 0) { + log("Delaying response for " + delayMsec + " milliseconds."); Thread.sleep(delayMsec); } } catch (InterruptedException ie) { @@ -908,6 +909,13 @@ private LocalOcspRequest parseHttpOcspPost(InputStream inStream) */ private LocalOcspRequest parseHttpOcspGet(String[] headerTokens, InputStream inStream) throws IOException, CertificateException { + // Display the whole request + StringBuilder sb = new StringBuilder("OCSP GET REQUEST\n"); + for (String hTok : headerTokens) { + sb.append(hTok).append("\n"); + } + log(sb.toString()); + // Before we process the remainder of the GET URL, we should drain // the InputStream of any other header data. We (for now) won't // use it, but will display the contents if logging is enabled. @@ -1000,6 +1008,10 @@ private LocalOcspRequest(byte[] requestBytes) throws IOException, CertificateException { Objects.requireNonNull(requestBytes, "Received null input"); + // Display the DER encoding before parsing + log("Local OCSP Request Constructor, parsing bytes:\n" + + dumpHexBytes(requestBytes)); + DerInputStream dis = new DerInputStream(requestBytes); // Parse the top-level structure, it should have no more than From 16df9c33e9bbc9329ae60ba14332c09aadaba3f0 Mon Sep 17 00:00:00 2001 From: Gui Cao Date: Thu, 8 Aug 2024 05:22:20 +0000 Subject: [PATCH 226/353] 8337971: Problem list several jvmci tests on linux-riscv64 until JDK-8331704 is fixed Reviewed-by: fyang, shade --- test/hotspot/jtreg/ProblemList.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index f5b14e87607e3..d40a8c2d5f431 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -63,6 +63,12 @@ compiler/vectorapi/VectorRebracket128Test.java#ZSinglegen 8330538 generic-all compiler/vectorapi/VectorRebracket128Test.java#ZGenerational 8330538 generic-all compiler/jvmci/TestUncaughtErrorInCompileMethod.java 8309073 generic-all +compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/DataPatchTest.java 8331704 linux-riscv64 +compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/MaxOopMapStackOffsetTest.java 8331704 linux-riscv64 +compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/NativeCallTest.java 8331704 linux-riscv64 +compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/SimpleDebugInfoTest.java 8331704 linux-riscv64 +compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/SimpleCodeInstallationTest.java 8331704 linux-riscv64 +compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/VirtualObjectDebugInfoTest.java 8331704 linux-riscv64 compiler/floatingpoint/TestSubnormalFloat.java 8317810 generic-i586 compiler/floatingpoint/TestSubnormalDouble.java 8317810 generic-i586 From 1846a65e32624f6da691c1072f44fcb762b43233 Mon Sep 17 00:00:00 2001 From: Turkhan Badalov Date: Thu, 8 Aug 2024 05:34:32 +0000 Subject: [PATCH 227/353] 8337205: Typo in Stack vs Deque Method table in Deque specification Reviewed-by: liach --- src/java.base/share/classes/java/util/Deque.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/java.base/share/classes/java/util/Deque.java b/src/java.base/share/classes/java/util/Deque.java index ce40687989434..79e4187a586d8 100644 --- a/src/java.base/share/classes/java/util/Deque.java +++ b/src/java.base/share/classes/java/util/Deque.java @@ -163,7 +163,7 @@ * * * {@link #peek() peek()} - * {@link #getFirst() getFirst()} + * {@link #peekFirst() peekFirst()} * * * From fa18359007bd80d2e74c07a5a1ea6170e1bd474d Mon Sep 17 00:00:00 2001 From: Afshin Zafari Date: Thu, 8 Aug 2024 08:55:05 +0000 Subject: [PATCH 228/353] 8335981: ProblemList runtime/Thread/TestAlwaysPreTouchStacks.java for MacOS Reviewed-by: tschatzl --- 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 d40a8c2d5f431..2414f3d090a18 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -117,8 +117,10 @@ runtime/ErrorHandling/CreateCoredumpOnCrash.java 8267433 macosx-x64 runtime/StackGuardPages/TestStackGuardPagesNative.java 8303612 linux-all runtime/ErrorHandling/TestDwarf.java#checkDecoder 8305489 linux-all runtime/ErrorHandling/MachCodeFramesInErrorFile.java 8313315 linux-ppc64le +runtime/Thread/TestAlwaysPreTouchStacks.java 8335167 macosx-aarch64 runtime/cds/appcds/customLoader/HelloCustom_JFR.java 8241075 linux-all,windows-x64 + applications/jcstress/copy.java 8229852 linux-all containers/docker/TestJcmd.java 8278102 linux-all From a9460a69e74f876274ec64394ac6504580041b21 Mon Sep 17 00:00:00 2001 From: Casper Norrbin Date: Thu, 8 Aug 2024 10:38:02 +0000 Subject: [PATCH 229/353] 8337982: Remove dead undef assrt0n Reviewed-by: stefank, dholmes --- src/hotspot/share/memory/metaspace/blockTree.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/hotspot/share/memory/metaspace/blockTree.cpp b/src/hotspot/share/memory/metaspace/blockTree.cpp index 934f25d84ccb3..1f1e54f4a4612 100644 --- a/src/hotspot/share/memory/metaspace/blockTree.cpp +++ b/src/hotspot/share/memory/metaspace/blockTree.cpp @@ -178,8 +178,6 @@ void BlockTree::verify() const { // (which also verifies that we visited every node, or at least // as many nodes as are in this tree) _counter.check(counter); - - #undef assrt0n } void BlockTree::zap_range(MetaWord* p, size_t word_size) { From 3bc4a1acc4bb1885ddba69283b99bbe02f8e43b7 Mon Sep 17 00:00:00 2001 From: Tejesh R Date: Thu, 8 Aug 2024 10:40:56 +0000 Subject: [PATCH 230/353] 8233068: HIDPI: Linux: AWT Checkbox check mark is unscaled Reviewed-by: jdv, abhiscxk, honkar --- .../classes/sun/awt/X11/XCheckboxPeer.java | 9 +- .../Checkbox/CheckboxCheckerScalingTest.java | 92 +++++++++++++++++++ 2 files changed, 98 insertions(+), 3 deletions(-) create mode 100644 test/jdk/java/awt/Checkbox/CheckboxCheckerScalingTest.java diff --git a/src/java.desktop/unix/classes/sun/awt/X11/XCheckboxPeer.java b/src/java.desktop/unix/classes/sun/awt/X11/XCheckboxPeer.java index 88f1784889e73..c66cda1644372 100644 --- a/src/java.desktop/unix/classes/sun/awt/X11/XCheckboxPeer.java +++ b/src/java.desktop/unix/classes/sun/awt/X11/XCheckboxPeer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -362,12 +362,15 @@ public void paintCheckbox(Graphics g, if (armed | selected) { //Paint the check + AffineTransform af = g2.getTransform(); + double scaleX = af.getScaleX(); + double scaleY = af.getScaleY(); // FIXME: is this the right color? g2.setColor(getPeerForeground()); - AffineTransform af = g2.getTransform(); - g2.setTransform(AffineTransform.getTranslateInstance(rx,ry)); + g2.setTransform(AffineTransform.getTranslateInstance(rx * scaleX, ry * scaleY)); + g2.scale(scaleX, scaleY); g2.fill(myCheckMark); g2.setTransform(af); } diff --git a/test/jdk/java/awt/Checkbox/CheckboxCheckerScalingTest.java b/test/jdk/java/awt/Checkbox/CheckboxCheckerScalingTest.java new file mode 100644 index 0000000000000..5e531e84801cd --- /dev/null +++ b/test/jdk/java/awt/Checkbox/CheckboxCheckerScalingTest.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Checkbox; +import java.awt.Color; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.image.BufferedImage; + +/* + * @test + * @key headful + * @bug 8233068 + * @summary Tests checkbox checker on scaling + * @requires (os.family == "linux") + * @run main CheckboxCheckerScalingTest + */ + +public class CheckboxCheckerScalingTest { + private static Frame frame; + private static Checkbox checkbox; + private static BufferedImage imageAfterChecked; + private static volatile boolean checkmarkFound = false; + + public static void main(String[] args) throws Exception { + System.setProperty("sun.java2d.uiScale", "2"); + Robot robot = new Robot(); + try { + EventQueue.invokeAndWait(() -> { + frame = new Frame("ComboBox checker scaling test"); + checkbox = new Checkbox("one"); + checkbox.setState(true); + frame.add(checkbox); + frame.pack(); + frame.setVisible(true); + }); + + robot.waitForIdle(); + robot.delay(100); + EventQueue.invokeAndWait(() -> { + Point point = checkbox.getLocationOnScreen(); + Rectangle rect = new Rectangle(point.x + 5, point.y + 7, 8, 8); + imageAfterChecked = robot.createScreenCapture(rect); + + check: { + for (int i = 0; i < imageAfterChecked.getHeight(); i++) { + for (int j = 0; j < imageAfterChecked.getWidth(); j++) { + if (Color.black.getRGB() == imageAfterChecked.getRGB(i, j)) { + checkmarkFound = true; + break check; + } + } + } + } + }); + + if (!checkmarkFound) { + throw new RuntimeException("Checkmark not scaled"); + } + System.out.println("Test Passed"); + } finally { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } +} From 088871ce36f85fb30b24c49146f547bc8e2b0dcb Mon Sep 17 00:00:00 2001 From: Alexander Zvegintsev Date: Thu, 8 Aug 2024 10:51:47 +0000 Subject: [PATCH 231/353] 8335267: [XWayland] move screencast tokens from .awt to .java folder Reviewed-by: prr, avu --- .../sun/awt/screencast/TokenStorage.java | 91 +++++++++++-------- 1 file changed, 53 insertions(+), 38 deletions(-) diff --git a/src/java.desktop/unix/classes/sun/awt/screencast/TokenStorage.java b/src/java.desktop/unix/classes/sun/awt/screencast/TokenStorage.java index 3daf9b2a8b8e8..b05ff7f8c4add 100644 --- a/src/java.desktop/unix/classes/sun/awt/screencast/TokenStorage.java +++ b/src/java.desktop/unix/classes/sun/awt/screencast/TokenStorage.java @@ -60,35 +60,33 @@ * The restore token allows the ScreenCast session to be restored * with previously granted screen access permissions. */ -@SuppressWarnings("removal") final class TokenStorage { private TokenStorage() {} private static final String REL_NAME = + ".java/robot/screencast-tokens.properties"; + private static final String REL_NAME_SECONDARY = ".awt/robot/screencast-tokens.properties"; private static final Properties PROPS = new Properties(); private static final Path PROPS_PATH; private static final Path PROP_FILENAME; + @SuppressWarnings("removal") private static void doPrivilegedRunnable(Runnable runnable) { - AccessController.doPrivileged(new PrivilegedAction() { - @Override - public Void run() { - runnable.run(); - return null; - } + AccessController.doPrivileged((PrivilegedAction) () -> { + runnable.run(); + return null; }); } static { - PROPS_PATH = AccessController.doPrivileged(new PrivilegedAction() { - @Override - public Path run() { - return setupPath(); - } - }); + @SuppressWarnings("removal") + Path propsPath = AccessController + .doPrivileged((PrivilegedAction) () -> setupPath()); + + PROPS_PATH = propsPath; if (PROPS_PATH != null) { PROP_FILENAME = PROPS_PATH.getFileName(); @@ -110,25 +108,32 @@ private static Path setupPath() { } Path path = Path.of(userHome, REL_NAME); + Path secondaryPath = Path.of(userHome, REL_NAME_SECONDARY); + + boolean copyFromSecondary = !Files.isWritable(path) + && Files.isWritable(secondaryPath); + Path workdir = path.getParent(); - if (!Files.exists(workdir)) { - try { - Files.createDirectories(workdir); - } catch (Exception e) { - if (SCREENCAST_DEBUG) { - System.err.printf("Token storage: cannot create" + - " directory %s %s\n", workdir, e); + if (!Files.isWritable(path)) { + if (!Files.exists(workdir)) { + try { + Files.createDirectories(workdir); + } catch (Exception e) { + if (SCREENCAST_DEBUG) { + System.err.printf("Token storage: cannot create" + + " directory %s %s\n", workdir, e); + } + return null; } - return null; } - } - if (!Files.isWritable(workdir)) { - if (SCREENCAST_DEBUG) { - System.err.printf("Token storage: %s is not writable\n", workdir); + if (!Files.isWritable(workdir)) { + if (SCREENCAST_DEBUG) { + System.err.printf("Token storage: %s is not writable\n", workdir); + } + return null; } - return null; } try { @@ -145,7 +150,17 @@ private static Path setupPath() { } } - if (Files.exists(path)) { + if (copyFromSecondary) { + if (SCREENCAST_DEBUG) { + System.out.println("Token storage: copying from the secondary location " + + secondaryPath); + } + synchronized (PROPS) { + if (readTokens(secondaryPath)) { + store(path, "copy from the secondary location"); + } + } + } else if (Files.exists(path)) { if (!setFilePermission(path)) { return null; } @@ -302,7 +317,7 @@ private static void storeTokenFromNative(String oldToken, } if (changed) { - doPrivilegedRunnable(() -> store("save tokens")); + doPrivilegedRunnable(() -> store(PROPS_PATH, "save tokens")); } } } @@ -315,7 +330,7 @@ private static boolean readTokens(Path path) { PROPS.clear(); PROPS.load(reader); } - } catch (IOException e) { + } catch (IOException | IllegalArgumentException e) { if (SCREENCAST_DEBUG) { System.err.printf(""" Token storage: failed to load property file %s @@ -410,7 +425,7 @@ static Set getTokens(List affectedScreenBounds) { } private static void removeMalformedRecords(Set malformedRecords) { - if (!isWritable() + if (!isWritable(PROPS_PATH) || malformedRecords == null || malformedRecords.isEmpty()) { return; @@ -424,17 +439,17 @@ private static void removeMalformedRecords(Set malformedRecords) { } } - store("remove malformed records"); + store(PROPS_PATH, "remove malformed records"); } } - private static void store(String failMsg) { - if (!isWritable()) { + private static void store(Path path, String failMsg) { + if (!isWritable(path)) { return; } synchronized (PROPS) { - try (BufferedWriter writer = Files.newBufferedWriter(PROPS_PATH)) { + try (BufferedWriter writer = Files.newBufferedWriter(path)) { PROPS.store(writer, null); } catch (IOException e) { if (SCREENCAST_DEBUG) { @@ -445,13 +460,13 @@ private static void store(String failMsg) { } } - private static boolean isWritable() { - if (PROPS_PATH == null - || (Files.exists(PROPS_PATH) && !Files.isWritable(PROPS_PATH))) { + private static boolean isWritable(Path path) { + if (path == null + || (Files.exists(path) && !Files.isWritable(path))) { if (SCREENCAST_DEBUG) { System.err.printf( - "Token storage: %s is not writable\n", PROPS_PATH); + "Token storage: %s is not writable\n", path); } return false; } else { From 12c553f12876b4095685676f800119c0e275bf44 Mon Sep 17 00:00:00 2001 From: Alexander Zvegintsev Date: Thu, 8 Aug 2024 10:51:58 +0000 Subject: [PATCH 232/353] 8329471: Remove GTK2 Reviewed-by: abhiscxk, prr, ihse --- .../modules/java.desktop/lib/AwtLibraries.gmk | 4 - .../sun/java/swing/plaf/gtk/GTKEngine.java | 16 +- .../java/swing/plaf/gtk/GTKIconFactory.java | 6 +- .../java/swing/plaf/gtk/GTKLookAndFeel.java | 24 +- .../sun/java/swing/plaf/gtk/GTKPainter.java | 98 +- .../com/sun/java/swing/plaf/gtk/GTKStyle.java | 11 +- .../unix/classes/sun/awt/UNIXToolkit.java | 19 +- .../native/libawt_xawt/awt/gtk2_interface.c | 2603 ----------------- .../native/libawt_xawt/awt/gtk2_interface.h | 448 --- .../native/libawt_xawt/awt/gtk_interface.c | 11 +- .../libawt_xawt/awt/screencast_pipewire.c | 3 +- .../Gtk/GtkVersionTest/GtkVersionTest.java | 7 +- .../ScreenCaptureGtkTest.java | 11 +- .../swing/LookAndFeel/8145547/DemandGTK.java | 3 +- .../swing/LookAndFeel/8145547/DemandGTK2.sh | 91 - .../swing/LookAndFeel/8145547/DemandGTK2.txt | 36 - .../swing/LookAndFeel/8145547/DemandGTK3.sh | 11 +- 17 files changed, 54 insertions(+), 3348 deletions(-) delete mode 100644 src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.c delete mode 100644 src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.h delete mode 100644 test/jdk/javax/swing/LookAndFeel/8145547/DemandGTK2.sh delete mode 100644 test/jdk/javax/swing/LookAndFeel/8145547/DemandGTK2.txt diff --git a/make/modules/java.desktop/lib/AwtLibraries.gmk b/make/modules/java.desktop/lib/AwtLibraries.gmk index 11f92585bd919..be29805f35271 100644 --- a/make/modules/java.desktop/lib/AwtLibraries.gmk +++ b/make/modules/java.desktop/lib/AwtLibraries.gmk @@ -237,7 +237,6 @@ ifeq ($(call isTargetOs, windows macosx)+$(ENABLE_HEADLESS_ONLY), false+false) DISABLED_WARNINGS_gcc := int-to-pointer-cast, \ DISABLED_WARNINGS_gcc_awt_Taskbar.c := parentheses, \ DISABLED_WARNINGS_gcc_GLXSurfaceData.c := unused-function, \ - DISABLED_WARNINGS_gcc_gtk2_interface.c := parentheses type-limits, \ DISABLED_WARNINGS_gcc_gtk3_interface.c := parentheses type-limits \ unused-function, \ DISABLED_WARNINGS_gcc_OGLBufImgOps.c := format-nonliteral, \ @@ -252,7 +251,6 @@ ifeq ($(call isTargetOs, windows macosx)+$(ENABLE_HEADLESS_ONLY), false+false) DISABLED_WARNINGS_gcc_XToolkit.c := unused-result, \ DISABLED_WARNINGS_gcc_XWindow.c := unused-function, \ DISABLED_WARNINGS_clang_awt_Taskbar.c := parentheses, \ - DISABLED_WARNINGS_clang_gtk2_interface.c := parentheses, \ DISABLED_WARNINGS_clang_gtk3_interface.c := parentheses, \ DISABLED_WARNINGS_clang_OGLBufImgOps.c := format-nonliteral, \ DISABLED_WARNINGS_clang_OGLPaints.c := format-nonliteral, \ @@ -262,8 +260,6 @@ ifeq ($(call isTargetOs, windows macosx)+$(ENABLE_HEADLESS_ONLY), false+false) DISABLED_WARNINGS_clang_aix_awt_Taskbar.c := parentheses, \ DISABLED_WARNINGS_clang_aix_OGLPaints.c := format-nonliteral, \ DISABLED_WARNINGS_clang_aix_OGLBufImgOps.c := format-nonliteral, \ - DISABLED_WARNINGS_clang_aix_gtk2_interface.c := parentheses \ - logical-op-parentheses, \ DISABLED_WARNINGS_clang_aix_gtk3_interface.c := parentheses \ logical-op-parentheses, \ DISABLED_WARNINGS_clang_aix_sun_awt_X11_GtkFileDialogPeer.c := \ diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKEngine.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKEngine.java index 1326cee140371..f9f6307678108 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKEngine.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKEngine.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -61,7 +61,7 @@ class GTKEngine { /** Size of the image cache */ private static final int CACHE_SIZE = 50; - /** This enum mirrors that in gtk2_interface.h */ + /** This enum mirrors that in gtk_interface.h */ static enum WidgetType { BUTTON, CHECK_BOX, CHECK_BOX_MENU_ITEM, COLOR_CHOOSER, COMBO_BOX, COMBO_BOX_ARROW_BUTTON, COMBO_BOX_TEXT_FIELD, @@ -493,13 +493,13 @@ public void paintShadow(Graphics g, SynthContext context, GTKLookAndFeel.synthStateToGTKStateType(state).ordinal(); int synthState = context.getComponentState(); Container parent = context.getComponent().getParent(); - if(GTKLookAndFeel.is3()) { - if (parent != null && parent.getParent() instanceof JComboBox) { - if (parent.getParent().hasFocus()) { - synthState |= SynthConstants.FOCUSED; - } + + if (parent != null && parent.getParent() instanceof JComboBox) { + if (parent.getParent().hasFocus()) { + synthState |= SynthConstants.FOCUSED; } } + int dir = getTextDirection(context); int widget = getWidgetType(context.getComponent(), id).ordinal(); native_paint_shadow(widget, gtkState, shadowType.ordinal(), detail, @@ -628,7 +628,7 @@ public void themeChanged() { cache.flush(); } - /* GtkSettings enum mirrors that in gtk2_interface.h */ + /* GtkSettings enum mirrors that in gtk_interface.h */ public Object getSetting(Settings property) { synchronized(sun.awt.UNIXToolkit.GTK_LOCK) { return native_get_gtk_setting(property.ordinal()); diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKIconFactory.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKIconFactory.java index 46f8d3ff189c0..4f04d729099f7 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKIconFactory.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKIconFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,7 +44,7 @@ class GTKIconFactory { static final int CHECK_ICON_EXTRA_INSET = 1; static final int DEFAULT_ICON_SPACING = 2; static final int DEFAULT_ICON_SIZE = 13; - static final int DEFAULT_TOGGLE_MENU_ITEM_SIZE = 12; // For pre-gtk2.4 + static final int DEFAULT_TOGGLE_MENU_ITEM_SIZE = 12; private static final String RADIO_BUTTON_ICON = "paintRadioButtonIcon"; private static final String CHECK_BOX_ICON = "paintCheckBoxIcon"; @@ -214,7 +214,7 @@ int getIconDimension(SynthContext context) { Region region = context.getRegion(); GTKStyle style = (GTKStyle) context.getStyle(); - if (GTKLookAndFeel.is3() && region == Region.MENU) { + if (region == Region.MENU) { Object value = style.getClassSpecificValue("arrow-scaling"); if (value instanceof Number) { iconDimension = (int)(((Number) value).floatValue() * diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKLookAndFeel.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKLookAndFeel.java index 93ba22d8dd3da..681c0e5195838 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKLookAndFeel.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKLookAndFeel.java @@ -77,7 +77,6 @@ */ @SuppressWarnings("serial") // Superclass not serializable public class GTKLookAndFeel extends SynthLookAndFeel { - private static boolean IS_22; private static boolean IS_3; /** @@ -124,17 +123,6 @@ public class GTKLookAndFeel extends SynthLookAndFeel { */ private static String gtkThemeName = "Default"; - /** - * Returns true if running on system containing at least 2.2. - */ - static boolean is2_2() { - // NOTE: We're currently hard coding to use 2.2. - // If we want to support both GTK 2.0 and 2.2, we'll - // need to get the major/minor/micro version from the .so. - // Refer to bug 4912613 for details. - return IS_22; - } - static boolean is3() { return IS_3; } @@ -1454,17 +1442,7 @@ public void initialize() { throw new InternalError("Unable to load native GTK libraries"); } - if (UNIXToolkit.getGtkVersion() == UNIXToolkit.GtkVersions.GTK2) { - @SuppressWarnings("removal") - String version = AccessController.doPrivileged( - new GetPropertyAction("jdk.gtk.version")); - if (version != null) { - IS_22 = version.equals("2.2"); - } else { - IS_22 = true; - } - } else if (UNIXToolkit.getGtkVersion() == - UNIXToolkit.GtkVersions.GTK3) { + if (UNIXToolkit.getGtkVersion() == UNIXToolkit.GtkVersions.GTK3) { IS_3 = true; } diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKPainter.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKPainter.java index 5d77800f88e5f..4787696a367eb 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKPainter.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKPainter.java @@ -211,20 +211,7 @@ public void paintRadioButtonMenuItemBackground(SynthContext context, int gtkState = GTKLookAndFeel.synthStateToGTKState( id, context.getComponentState()); if (gtkState == SynthConstants.MOUSE_OVER) { - if (GTKLookAndFeel.is3()) { - paintComponentBackground(context, g, x, y, w, h); - return; - } - synchronized (UNIXToolkit.GTK_LOCK) { - if (! ENGINE.paintCachedImage(g, x, y, w, h, id)) { - ShadowType shadow = (GTKLookAndFeel.is2_2() ? - ShadowType.NONE : ShadowType.OUT); - ENGINE.startPainting(g, x, y, w, h, id); - ENGINE.paintBox(g, context, id, gtkState, - shadow, "menuitem", x, y, w, h); - ENGINE.finishPainting(); - } - } + paintComponentBackground(context, g, x, y, w, h); } } @@ -570,21 +557,7 @@ public void paintMenuItemBackground(SynthContext context, int gtkState = GTKLookAndFeel.synthStateToGTKState( context.getRegion(), context.getComponentState()); if (gtkState == SynthConstants.MOUSE_OVER) { - if (GTKLookAndFeel.is3()) { - paintComponentBackground(context, g, x, y, w, h); - return; - } - Region id = Region.MENU_ITEM; - synchronized (UNIXToolkit.GTK_LOCK) { - if (! ENGINE.paintCachedImage(g, x, y, w, h, id)) { - ShadowType shadow = (GTKLookAndFeel.is2_2() ? - ShadowType.NONE : ShadowType.OUT); - ENGINE.startPainting(g, x, y, w, h, id); - ENGINE.paintBox(g, context, id, gtkState, shadow, - "menuitem", x, y, w, h); - ENGINE.finishPainting(); - } - } + paintComponentBackground(context, g, x, y, w, h); } } @@ -698,17 +671,14 @@ public void paintSeparatorBackground(SynthContext context, } else { h -= (insets.top + insets.bottom); } - if (GTKLookAndFeel.is3()) { - if (id == Region.POPUP_MENU_SEPARATOR) { - detail = "menuitem"; - h -= (insets.top + insets.bottom); - } else { - detail = "separator"; - } + + if (id == Region.POPUP_MENU_SEPARATOR) { + detail = "menuitem"; + h -= (insets.top + insets.bottom); } else { - detail = orientation == JSeparator.HORIZONTAL ? - "hseparator" : "vseparator"; + detail = "separator"; } + synchronized (UNIXToolkit.GTK_LOCK) { if (! ENGINE.paintCachedImage(g, x, y, w, h, id, state, detail, orientation)) { @@ -823,15 +793,15 @@ public void paintSliderTrackBackground(SynthContext context, // The ubuntulooks engine paints slider troughs differently depending // on the current slider value and its component orientation. JSlider slider = (JSlider)context.getComponent(); - if (GTKLookAndFeel.is3()) { - if (slider.getOrientation() == JSlider.VERTICAL) { - y += 1; - h -= 2; - } else { - x += 1; - w -= 2; - } + + if (slider.getOrientation() == JSlider.VERTICAL) { + y += 1; + h -= 2; + } else { + x += 1; + w -= 2; } + double value = slider.getValue(); double min = slider.getMinimum(); double max = slider.getMaximum(); @@ -865,7 +835,7 @@ public void paintSliderThumbBackground(SynthContext context, Region id = context.getRegion(); int gtkState = GTKLookAndFeel.synthStateToGTKState( id, context.getComponentState()); - boolean hasFocus = GTKLookAndFeel.is3() && + boolean hasFocus = ((context.getComponentState() & SynthConstants.FOCUSED) != 0); synchronized (UNIXToolkit.GTK_LOCK) { if (! ENGINE.paintCachedImage(g, x, y, w, h, id, gtkState, dir, @@ -1059,21 +1029,10 @@ private void paintTextBackground(SynthContext context, Graphics g, int yThickness = style.getYThickness(); ENGINE.startPainting(g, x, y, w, h, id, state); - if (GTKLookAndFeel.is3()) { - ENGINE.paintBackground(g, context, id, gtkState, null, - x, y, w, h); - } + ENGINE.paintBackground(g, context, id, gtkState, null, + x, y, w, h); ENGINE.paintShadow(g, context, id, gtkState, ShadowType.IN, "entry", x, y, w, h); - if (!GTKLookAndFeel.is3()) { - ENGINE.paintFlatBox(g, context, id, - gtkState, ShadowType.NONE, "entry_bg", - x + xThickness, - y + yThickness, - w - (2 * xThickness), - h - (2 * yThickness), - ColorType.TEXT_BACKGROUND); - } if (focusSize > 0 && (state & SynthConstants.FOCUSED) != 0) { if (!interiorFocus) { @@ -1084,14 +1043,14 @@ private void paintTextBackground(SynthContext context, Graphics g, } else { if (containerParent instanceof JComboBox) { x += (focusSize + 2); - y += focusSize + (GTKLookAndFeel.is3() ? 3 : 1); - w -= 2 * focusSize + (GTKLookAndFeel.is3() ? 4 : 1); - h -= 2 * focusSize + (GTKLookAndFeel.is3() ? 6 : 2); + y += focusSize + 3; + w -= 2 * focusSize + 4; + h -= 2 * focusSize + 6; } else { - x += focusSize + (GTKLookAndFeel.is3() ? 2 : 0); - y += focusSize + (GTKLookAndFeel.is3() ? 2 :0 ); - w -= 2 * focusSize + (GTKLookAndFeel.is3() ? 4 : 0); - h -= 2 * focusSize + (GTKLookAndFeel.is3() ? 4 : 0); + x += focusSize + 2; + y += focusSize + 2; + w -= 2 * focusSize + 4; + h -= 2 * focusSize + 4; } } ENGINE.paintFocus(g, context, id, gtkState, @@ -1437,11 +1396,6 @@ public void paintMenuArrowIcon(SynthContext context, Graphics g, if (gtkState == SynthConstants.MOUSE_OVER) { shadow = ShadowType.IN; } - if (!GTKLookAndFeel.is3()) { - x += 3; - y += 3; - w = h = 7; - } ENGINE.paintArrow(g, context, Region.MENU_ITEM, gtkState, shadow, dir, "menuitem", x, y, w, h); } diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKStyle.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKStyle.java index 3ba534ea2a723..90c051353686e 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKStyle.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKStyle.java @@ -751,14 +751,7 @@ public boolean isOpaque(SynthContext context) { region == Region.EDITOR_PANE) { return true; } - if (!GTKLookAndFeel.is3()) { - if (region == Region.FORMATTED_TEXT_FIELD || - region == Region.PASSWORD_FIELD || - region == Region.SPINNER || - region == Region.TEXT_FIELD) { - return true; - } - } + Component c = context.getComponent(); String name = c.getName(); if (name == "ComboBox.renderer" || name == "ComboBox.listRenderer") { @@ -884,7 +877,7 @@ else if ("CheckBox.iconTextGap".equals(key) || int focusPad = getClassSpecificIntValue(context, "focus-padding", 1); return indicatorSpacing + focusSize + focusPad; - } else if (GTKLookAndFeel.is3() && "ComboBox.forceOpaque".equals(key)) { + } else if ("ComboBox.forceOpaque".equals(key)) { return true; } else if ("Tree.expanderSize".equals(key)) { Object value = getClassSpecificValue("expander-size"); diff --git a/src/java.desktop/unix/classes/sun/awt/UNIXToolkit.java b/src/java.desktop/unix/classes/sun/awt/UNIXToolkit.java index 191a12092a1ff..d509fe802b028 100644 --- a/src/java.desktop/unix/classes/sun/awt/UNIXToolkit.java +++ b/src/java.desktop/unix/classes/sun/awt/UNIXToolkit.java @@ -70,19 +70,12 @@ public abstract class UNIXToolkit extends SunToolkit private static final int[] BAND_OFFSETS_ALPHA = { 0, 1, 2, 3 }; private static final int DEFAULT_DATATRANSFER_TIMEOUT = 10000; - private static final String GTK2_DEPRECATION_MESSAGE = - "WARNING: the GTK 2 library is deprecated and " + - "its support will be removed in a future release"; - private static volatile boolean gtk2WarningIssued = false; - // Allowed GTK versions public enum GtkVersions { ANY(0), - GTK2(Constants.GTK2_MAJOR_NUMBER), GTK3(Constants.GTK3_MAJOR_NUMBER); static class Constants { - static final int GTK2_MAJOR_NUMBER = 2; static final int GTK3_MAJOR_NUMBER = 3; } @@ -94,8 +87,6 @@ static class Constants { public static GtkVersions getVersion(int number) { switch (number) { - case Constants.GTK2_MAJOR_NUMBER: - return GTK2; case Constants.GTK3_MAJOR_NUMBER: return GTK3; default: @@ -498,15 +489,7 @@ public static GtkVersions getEnabledGtkVersion() { @SuppressWarnings("removal") String version = AccessController.doPrivileged( new GetPropertyAction("jdk.gtk.version")); - if (version == null) { - return GtkVersions.ANY; - } else if (version.startsWith("2")) { - if (!gtk2WarningIssued) { - System.err.println(GTK2_DEPRECATION_MESSAGE); - gtk2WarningIssued = true; - } - return GtkVersions.GTK2; - } else if("3".equals(version) ){ + if ("3".equals(version)) { return GtkVersions.GTK3; } return GtkVersions.ANY; diff --git a/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.c b/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.c deleted file mode 100644 index 7dba83e9024d2..0000000000000 --- a/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.c +++ /dev/null @@ -1,2603 +0,0 @@ -/* - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * 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. - */ - -#ifdef HEADLESS - #error This file should not be included in headless library -#endif - -#include -#include -#include -#include -#include -#include -#include "gtk2_interface.h" -#include "java_awt_Transparency.h" -#include "jvm_md.h" -#include "sizecalc.h" -#include -#include "awt.h" - -#define GTK_TYPE_BORDER ((*fp_gtk_border_get_type)()) - -#define G_TYPE_FUNDAMENTAL_SHIFT (2) -#define G_TYPE_MAKE_FUNDAMENTAL(x) ((GType) ((x) << G_TYPE_FUNDAMENTAL_SHIFT)) - -#define CONV_BUFFER_SIZE 128 - -#define NO_SYMBOL_EXCEPTION 1 - -static void *gtk2_libhandle = NULL; -static void *gthread_libhandle = NULL; - -static jmp_buf j; - -/* Widgets */ -static GtkWidget *gtk2_widget = NULL; -static GtkWidget *gtk2_window = NULL; -static GtkFixed *gtk2_fixed = NULL; - -/* Paint system */ -static GdkPixmap *gtk2_white_pixmap = NULL; -static GdkPixmap *gtk2_black_pixmap = NULL; -static GdkPixbuf *gtk2_white_pixbuf = NULL; -static GdkPixbuf *gtk2_black_pixbuf = NULL; -static int gtk2_pixbuf_width = 0; -static int gtk2_pixbuf_height = 0; - -/* Static buffer for conversion from java.lang.String to UTF-8 */ -static char convertionBuffer[CONV_BUFFER_SIZE]; - -static gboolean new_combo = TRUE; -const char ENV_PREFIX[] = "GTK_MODULES="; - - -static GtkWidget *gtk2_widgets[_GTK_WIDGET_TYPE_SIZE]; - -/************************* - * Glib function pointers - *************************/ - -static gboolean (*fp_g_main_context_iteration)(GMainContext *context, - gboolean may_block); - -static GValue* (*fp_g_value_init)(GValue *value, GType g_type); -static gboolean (*fp_g_type_is_a)(GType type, GType is_a_type); -static gboolean (*fp_g_value_get_boolean)(const GValue *value); -static gchar (*fp_g_value_get_char)(const GValue *value); -static guchar (*fp_g_value_get_uchar)(const GValue *value); -static gint (*fp_g_value_get_int)(const GValue *value); -static guint (*fp_g_value_get_uint)(const GValue *value); -static glong (*fp_g_value_get_long)(const GValue *value); -static gulong (*fp_g_value_get_ulong)(const GValue *value); -static gint64 (*fp_g_value_get_int64)(const GValue *value); -static guint64 (*fp_g_value_get_uint64)(const GValue *value); -static gfloat (*fp_g_value_get_float)(const GValue *value); -static gdouble (*fp_g_value_get_double)(const GValue *value); -static const gchar* (*fp_g_value_get_string)(const GValue *value); -static gint (*fp_g_value_get_enum)(const GValue *value); -static guint (*fp_g_value_get_flags)(const GValue *value); -static GParamSpec* (*fp_g_value_get_param)(const GValue *value); -static gpointer* (*fp_g_value_get_boxed)(const GValue *value); -static gpointer* (*fp_g_value_get_pointer)(const GValue *value); -static GObject* (*fp_g_value_get_object)(const GValue *value); -static GParamSpec* (*fp_g_param_spec_int)(const gchar *name, - const gchar *nick, const gchar *blurb, - gint minimum, gint maximum, gint default_value, - GParamFlags flags); -static void (*fp_g_object_get)(gpointer object, - const gchar* fpn, ...); -static void (*fp_g_object_set)(gpointer object, - const gchar *first_property_name, - ...); -/************************ - * GDK function pointers - ************************/ -static GdkPixmap *(*fp_gdk_pixmap_new)(GdkDrawable *drawable, - gint width, gint height, gint depth); -static GdkGC *(*fp_gdk_gc_new)(GdkDrawable*); -static void (*fp_gdk_rgb_gc_set_foreground)(GdkGC*, guint32); -static void (*fp_gdk_draw_rectangle)(GdkDrawable*, GdkGC*, gboolean, - gint, gint, gint, gint); -static GdkPixbuf *(*fp_gdk_pixbuf_new)(GdkColorspace colorspace, - gboolean has_alpha, int bits_per_sample, int width, int height); -static void (*fp_gdk_drawable_get_size)(GdkDrawable *drawable, - gint* width, gint* height); - -/************************ - * Gtk function pointers - ************************/ -static gboolean (*fp_gtk_init_check)(int* argc, char** argv); - -/* Painting */ -static void (*fp_gtk_paint_hline)(GtkStyle* style, GdkWindow* window, - GtkStateType state_type, GdkRectangle* area, GtkWidget* widget, - const gchar* detail, gint x1, gint x2, gint y); -static void (*fp_gtk_paint_vline)(GtkStyle* style, GdkWindow* window, - GtkStateType state_type, GdkRectangle* area, GtkWidget* widget, - const gchar* detail, gint y1, gint y2, gint x); -static void (*fp_gtk_paint_shadow)(GtkStyle* style, GdkWindow* window, - GtkStateType state_type, GtkShadowType shadow_type, - GdkRectangle* area, GtkWidget* widget, const gchar* detail, - gint x, gint y, gint width, gint height); -static void (*fp_gtk_paint_arrow)(GtkStyle* style, GdkWindow* window, - GtkStateType state_type, GtkShadowType shadow_type, - GdkRectangle* area, GtkWidget* widget, const gchar* detail, - GtkArrowType arrow_type, gboolean fill, gint x, gint y, - gint width, gint height); -static void (*fp_gtk_paint_box)(GtkStyle* style, GdkWindow* window, - GtkStateType state_type, GtkShadowType shadow_type, - GdkRectangle* area, GtkWidget* widget, const gchar* detail, - gint x, gint y, gint width, gint height); -static void (*fp_gtk_paint_flat_box)(GtkStyle* style, GdkWindow* window, - GtkStateType state_type, GtkShadowType shadow_type, - GdkRectangle* area, GtkWidget* widget, const gchar* detail, - gint x, gint y, gint width, gint height); -static void (*fp_gtk_paint_check)(GtkStyle* style, GdkWindow* window, - GtkStateType state_type, GtkShadowType shadow_type, - GdkRectangle* area, GtkWidget* widget, const gchar* detail, - gint x, gint y, gint width, gint height); -static void (*fp_gtk_paint_option)(GtkStyle* style, GdkWindow* window, - GtkStateType state_type, GtkShadowType shadow_type, - GdkRectangle* area, GtkWidget* widget, const gchar* detail, - gint x, gint y, gint width, gint height); -static void (*fp_gtk_paint_box_gap)(GtkStyle* style, GdkWindow* window, - GtkStateType state_type, GtkShadowType shadow_type, - GdkRectangle* area, GtkWidget* widget, const gchar* detail, - gint x, gint y, gint width, gint height, - GtkPositionType gap_side, gint gap_x, gint gap_width); -static void (*fp_gtk_paint_extension)(GtkStyle* style, GdkWindow* window, - GtkStateType state_type, GtkShadowType shadow_type, - GdkRectangle* area, GtkWidget* widget, const gchar* detail, - gint x, gint y, gint width, gint height, GtkPositionType gap_side); -static void (*fp_gtk_paint_focus)(GtkStyle* style, GdkWindow* window, - GtkStateType state_type, GdkRectangle* area, GtkWidget* widget, - const gchar* detail, gint x, gint y, gint width, gint height); -static void (*fp_gtk_paint_slider)(GtkStyle* style, GdkWindow* window, - GtkStateType state_type, GtkShadowType shadow_type, - GdkRectangle* area, GtkWidget* widget, const gchar* detail, - gint x, gint y, gint width, gint height, GtkOrientation orientation); -static void (*fp_gtk_paint_handle)(GtkStyle* style, GdkWindow* window, - GtkStateType state_type, GtkShadowType shadow_type, - GdkRectangle* area, GtkWidget* widget, const gchar* detail, - gint x, gint y, gint width, gint height, GtkOrientation orientation); -static void (*fp_gtk_paint_expander)(GtkStyle* style, GdkWindow* window, - GtkStateType state_type, GdkRectangle* area, GtkWidget* widget, - const gchar* detail, gint x, gint y, GtkExpanderStyle expander_style); -static void (*fp_gtk_style_apply_default_background)(GtkStyle* style, - GdkWindow* window, gboolean set_bg, GtkStateType state_type, - GdkRectangle* area, gint x, gint y, gint width, gint height); - -/* Widget creation */ -static GtkWidget* (*fp_gtk_arrow_new)(GtkArrowType arrow_type, - GtkShadowType shadow_type); -static GtkWidget* (*fp_gtk_button_new)(); -static GtkWidget* (*fp_gtk_check_button_new)(); -static GtkWidget* (*fp_gtk_check_menu_item_new)(); -static GtkWidget* (*fp_gtk_color_selection_dialog_new)(const gchar* title); -static GtkWidget* (*fp_gtk_combo_box_new)(); -static GtkWidget* (*fp_gtk_combo_box_entry_new)(); -static GtkWidget* (*fp_gtk_entry_new)(); -static GtkWidget* (*fp_gtk_fixed_new)(); -static GtkWidget* (*fp_gtk_handle_box_new)(); -static GtkWidget* (*fp_gtk_hpaned_new)(); -static GtkWidget* (*fp_gtk_vpaned_new)(); -static GtkWidget* (*fp_gtk_hscale_new)(GtkAdjustment* adjustment); -static GtkWidget* (*fp_gtk_vscale_new)(GtkAdjustment* adjustment); -static GtkWidget* (*fp_gtk_hscrollbar_new)(GtkAdjustment* adjustment); -static GtkWidget* (*fp_gtk_vscrollbar_new)(GtkAdjustment* adjustment); -static GtkWidget* (*fp_gtk_hseparator_new)(); -static GtkWidget* (*fp_gtk_vseparator_new)(); -static GtkWidget* (*fp_gtk_image_new)(); -static GtkWidget* (*fp_gtk_label_new)(const gchar* str); -static GtkWidget* (*fp_gtk_menu_new)(); -static GtkWidget* (*fp_gtk_menu_bar_new)(); -static GtkWidget* (*fp_gtk_menu_item_new)(); -static GtkWidget* (*fp_gtk_notebook_new)(); -static GtkWidget* (*fp_gtk_progress_bar_new)(); -static GtkWidget* (*fp_gtk_progress_bar_set_orientation)( - GtkProgressBar *pbar, - GtkProgressBarOrientation orientation); -static GtkWidget* (*fp_gtk_radio_button_new)(GSList *group); -static GtkWidget* (*fp_gtk_radio_menu_item_new)(GSList *group); -static GtkWidget* (*fp_gtk_scrolled_window_new)(GtkAdjustment *hadjustment, - GtkAdjustment *vadjustment); -static GtkWidget* (*fp_gtk_separator_menu_item_new)(); -static GtkWidget* (*fp_gtk_separator_tool_item_new)(); -static GtkWidget* (*fp_gtk_text_view_new)(); -static GtkWidget* (*fp_gtk_toggle_button_new)(); -static GtkWidget* (*fp_gtk_toolbar_new)(); -static GtkWidget* (*fp_gtk_tree_view_new)(); -static GtkWidget* (*fp_gtk_viewport_new)(GtkAdjustment *hadjustment, - GtkAdjustment *vadjustment); -static GtkWidget* (*fp_gtk_window_new)(GtkWindowType type); -static GtkWidget* (*fp_gtk_dialog_new)(); -static GtkWidget* (*fp_gtk_spin_button_new)(GtkAdjustment *adjustment, - gdouble climb_rate, guint digits); -static GtkWidget* (*fp_gtk_frame_new)(const gchar *label); - -/* Other widget operations */ -static GtkObject* (*fp_gtk_adjustment_new)(gdouble value, - gdouble lower, gdouble upper, gdouble step_increment, - gdouble page_increment, gdouble page_size); -static void (*fp_gtk_container_add)(GtkContainer *window, GtkWidget *widget); -static void (*fp_gtk_menu_shell_append)(GtkMenuShell *menu_shell, - GtkWidget *child); -static void (*fp_gtk_menu_item_set_submenu)(GtkMenuItem *menu_item, - GtkWidget *submenu); -static void (*fp_gtk_widget_realize)(GtkWidget *widget); -static GdkPixbuf* (*fp_gtk_widget_render_icon)(GtkWidget *widget, - const gchar *stock_id, GtkIconSize size, const gchar *detail); -static void (*fp_gtk_widget_set_name)(GtkWidget *widget, const gchar *name); -static void (*fp_gtk_widget_set_parent)(GtkWidget *widget, GtkWidget *parent); -static void (*fp_gtk_widget_set_direction)(GtkWidget *widget, - GtkTextDirection direction); -static void (*fp_gtk_widget_style_get)(GtkWidget *widget, - const gchar *first_property_name, ...); -static void (*fp_gtk_widget_class_install_style_property)( - GtkWidgetClass* class, GParamSpec *pspec); -static GParamSpec* (*fp_gtk_widget_class_find_style_property)( - GtkWidgetClass* class, const gchar* property_name); -static void (*fp_gtk_widget_style_get_property)(GtkWidget* widget, - const gchar* property_name, GValue* value); -static char* (*fp_pango_font_description_to_string)( - const PangoFontDescription* fd); -static GtkSettings* (*fp_gtk_settings_get_default)(); -static GtkSettings* (*fp_gtk_widget_get_settings)(GtkWidget *widget); -static GType (*fp_gtk_border_get_type)(); -static void (*fp_gtk_arrow_set)(GtkWidget* arrow, - GtkArrowType arrow_type, - GtkShadowType shadow_type); -static void (*fp_gtk_widget_size_request)(GtkWidget *widget, - GtkRequisition *requisition); -static GtkAdjustment* (*fp_gtk_range_get_adjustment)(GtkRange* range); - -/* Method bodies */ - -static void throw_exception(JNIEnv *env, const char* name, const char* message) -{ - jclass class = (*env)->FindClass(env, name); - - if (class != NULL) - (*env)->ThrowNew(env, class, message); - - (*env)->DeleteLocalRef(env, class); -} - -/* This is a workaround for the bug: - * http://sourceware.org/bugzilla/show_bug.cgi?id=1814 - * (dlsym/dlopen clears dlerror state) - * This bug is specific to Linux, but there is no harm in - * applying this workaround on Solaris as well. - */ -static void* dl_symbol(const char* name) -{ - void* result = dlsym(gtk2_libhandle, name); - if (!result) - longjmp(j, NO_SYMBOL_EXCEPTION); - - return result; -} - -static void* dl_symbol_gthread(const char* name) -{ - void* result = dlsym(gthread_libhandle, name); - if (!result) - longjmp(j, NO_SYMBOL_EXCEPTION); - - return result; -} - -gboolean gtk2_check(const char* lib_name, gboolean load) -{ - if (gtk2_libhandle != NULL) { - /* We've already successfully opened the GTK libs, so return true. */ - return TRUE; - } else { - void *lib = NULL; - -#ifdef RTLD_NOLOAD - /* Just check if gtk libs are already in the process space */ - lib = dlopen(lib_name, RTLD_LAZY | RTLD_NOLOAD); - if (!load || lib != NULL) { - return lib != NULL; - } -#else -#ifdef _AIX - /* On AIX we could implement this with the help of loadquery(L_GETINFO, ..) */ - /* (see reload_table() in hotspot/src/os/aix/vm/loadlib_aix.cpp) but it is */ - /* probably not worth it because most AIX servers don't have GTK libs anyway */ -#endif -#endif - - lib = dlopen(lib_name, RTLD_LAZY | RTLD_LOCAL); - if (lib == NULL) { - return FALSE; - } - - fp_gtk_check_version = dlsym(lib, "gtk_check_version"); - /* Check for GTK 2.2+ */ - if (!fp_gtk_check_version(2, 2, 0)) { - return TRUE; - } - - // 8048289: workaround for https://bugzilla.gnome.org/show_bug.cgi?id=733065 - // dlclose(lib); - - return FALSE; - } -} - -#define ADD_SUPPORTED_ACTION(actionStr) \ -do { \ - jfieldID fld_action = (*env)->GetStaticFieldID(env, cls_action, actionStr, "Ljava/awt/Desktop$Action;"); \ - if (!(*env)->ExceptionCheck(env)) { \ - jobject action = (*env)->GetStaticObjectField(env, cls_action, fld_action); \ - (*env)->CallBooleanMethod(env, supportedActions, mid_arrayListAdd, action); \ - } else { \ - (*env)->ExceptionClear(env); \ - } \ -} while(0); - - -static void update_supported_actions(JNIEnv *env) { - GVfs * (*fp_g_vfs_get_default) (void); - const gchar * const * (*fp_g_vfs_get_supported_uri_schemes) (GVfs * vfs); - const gchar * const * schemes = NULL; - - jclass cls_action = (*env)->FindClass(env, "java/awt/Desktop$Action"); - CHECK_NULL(cls_action); - jclass cls_xDesktopPeer = (*env)->FindClass(env, "sun/awt/X11/XDesktopPeer"); - CHECK_NULL(cls_xDesktopPeer); - jfieldID fld_supportedActions = (*env)->GetStaticFieldID(env, cls_xDesktopPeer, "supportedActions", "Ljava/util/List;"); - CHECK_NULL(fld_supportedActions); - jobject supportedActions = (*env)->GetStaticObjectField(env, cls_xDesktopPeer, fld_supportedActions); - - jclass cls_arrayList = (*env)->FindClass(env, "java/util/ArrayList"); - CHECK_NULL(cls_arrayList); - jmethodID mid_arrayListAdd = (*env)->GetMethodID(env, cls_arrayList, "add", "(Ljava/lang/Object;)Z"); - CHECK_NULL(mid_arrayListAdd); - jmethodID mid_arrayListClear = (*env)->GetMethodID(env, cls_arrayList, "clear", "()V"); - CHECK_NULL(mid_arrayListClear); - - (*env)->CallVoidMethod(env, supportedActions, mid_arrayListClear); - - ADD_SUPPORTED_ACTION("OPEN"); - - /** - * gtk_show_uri() documentation says: - * - * > you need to install gvfs to get support for uri schemes such as http:// - * > or ftp://, as only local files are handled by GIO itself. - * - * So OPEN action was safely added here. - * However, it looks like Solaris 11 have gvfs support only for 32-bit - * applications only by default. - */ - - fp_g_vfs_get_default = dl_symbol("g_vfs_get_default"); - fp_g_vfs_get_supported_uri_schemes = dl_symbol("g_vfs_get_supported_uri_schemes"); - dlerror(); - - if (fp_g_vfs_get_default && fp_g_vfs_get_supported_uri_schemes) { - GVfs * vfs = fp_g_vfs_get_default(); - schemes = vfs ? fp_g_vfs_get_supported_uri_schemes(vfs) : NULL; - if (schemes) { - int i = 0; - while (schemes[i]) { - if (strcmp(schemes[i], "http") == 0) { - ADD_SUPPORTED_ACTION("BROWSE"); - ADD_SUPPORTED_ACTION("MAIL"); - break; - } - i++; - } - } - } else { -#ifdef DEBUG - fprintf(stderr, "Cannot load g_vfs_get_supported_uri_schemes\n"); -#endif /* DEBUG */ - } - -} -/** - * Functions for awt_Desktop.c - */ -static gboolean gtk2_show_uri_load(JNIEnv *env) { - gboolean success = FALSE; - dlerror(); - const char *gtk_version = fp_gtk_check_version(2, 14, 0); - if (gtk_version != NULL) { - // The gtk_show_uri is available from GTK+ 2.14 -#ifdef DEBUG - fprintf (stderr, "The version of GTK is %s. " - "The gtk_show_uri function is supported " - "since GTK+ 2.14.\n", gtk_version); -#endif /* DEBUG */ - } else { - // Loading symbols only if the GTK version is 2.14 and higher - fp_gtk_show_uri = dl_symbol("gtk_show_uri"); - const char *dlsym_error = dlerror(); - if (dlsym_error) { -#ifdef DEBUG - fprintf (stderr, "Cannot load symbol: %s \n", dlsym_error); -#endif /* DEBUG */ - } else if (fp_gtk_show_uri == NULL) { -#ifdef DEBUG - fprintf(stderr, "dlsym(gtk_show_uri) returned NULL\n"); -#endif /* DEBUG */ - } else { - gtk->gtk_show_uri = fp_gtk_show_uri; - update_supported_actions(env); - success = TRUE; - } - } - return success; -} - -/** - * Functions for sun_awt_X11_GtkFileDialogPeer.c - */ -static void gtk2_file_chooser_load() -{ - fp_gtk_file_chooser_get_filename = dl_symbol( - "gtk_file_chooser_get_filename"); - fp_gtk_file_chooser_dialog_new = dl_symbol("gtk_file_chooser_dialog_new"); - fp_gtk_file_chooser_set_current_folder = dl_symbol( - "gtk_file_chooser_set_current_folder"); - fp_gtk_file_chooser_set_filename = dl_symbol( - "gtk_file_chooser_set_filename"); - fp_gtk_file_chooser_set_current_name = dl_symbol( - "gtk_file_chooser_set_current_name"); - fp_gtk_file_filter_add_custom = dl_symbol("gtk_file_filter_add_custom"); - fp_gtk_file_chooser_set_filter = dl_symbol("gtk_file_chooser_set_filter"); - fp_gtk_file_chooser_get_type = dl_symbol("gtk_file_chooser_get_type"); - fp_gtk_file_filter_new = dl_symbol("gtk_file_filter_new"); - if (fp_gtk_check_version(2, 8, 0) == NULL) { - fp_gtk_file_chooser_set_do_overwrite_confirmation = dl_symbol( - "gtk_file_chooser_set_do_overwrite_confirmation"); - } - fp_gtk_file_chooser_set_select_multiple = dl_symbol( - "gtk_file_chooser_set_select_multiple"); - fp_gtk_file_chooser_get_current_folder = dl_symbol( - "gtk_file_chooser_get_current_folder"); - fp_gtk_file_chooser_get_filenames = dl_symbol( - "gtk_file_chooser_get_filenames"); - fp_gtk_g_slist_length = dl_symbol("g_slist_length"); - fp_gdk_x11_drawable_get_xid = dl_symbol("gdk_x11_drawable_get_xid"); -} - -GtkApi* gtk2_load(JNIEnv *env, const char* lib_name) -{ - gboolean result; - int i; - int (*handler)(); - int (*io_handler)(); - char *gtk_modules_env; - - gtk2_libhandle = dlopen(lib_name, RTLD_LAZY | RTLD_LOCAL); - if (gtk2_libhandle == NULL) { - return FALSE; - } - - gthread_libhandle = dlopen(GTHREAD_LIB_VERSIONED, RTLD_LAZY | RTLD_LOCAL); - if (gthread_libhandle == NULL) { - gthread_libhandle = dlopen(GTHREAD_LIB, RTLD_LAZY | RTLD_LOCAL); - if (gthread_libhandle == NULL) - return FALSE; - } - - if (setjmp(j) == 0) - { - fp_gtk_check_version = dl_symbol("gtk_check_version"); - /* Check for GTK 2.2+ */ - if (fp_gtk_check_version(2, 2, 0)) { - longjmp(j, NO_SYMBOL_EXCEPTION); - } - - /* GLib */ - fp_glib_check_version = dlsym(gtk2_libhandle, "glib_check_version"); - if (!fp_glib_check_version) { - dlerror(); - } - fp_g_free = dl_symbol("g_free"); - fp_g_object_unref = dl_symbol("g_object_unref"); - - fp_g_main_context_iteration = - dl_symbol("g_main_context_iteration"); - - fp_g_value_init = dl_symbol("g_value_init"); - fp_g_type_is_a = dl_symbol("g_type_is_a"); - - fp_g_value_get_boolean = dl_symbol("g_value_get_boolean"); - fp_g_value_get_char = dl_symbol("g_value_get_char"); - fp_g_value_get_uchar = dl_symbol("g_value_get_uchar"); - fp_g_value_get_int = dl_symbol("g_value_get_int"); - fp_g_value_get_uint = dl_symbol("g_value_get_uint"); - fp_g_value_get_long = dl_symbol("g_value_get_long"); - fp_g_value_get_ulong = dl_symbol("g_value_get_ulong"); - fp_g_value_get_int64 = dl_symbol("g_value_get_int64"); - fp_g_value_get_uint64 = dl_symbol("g_value_get_uint64"); - fp_g_value_get_float = dl_symbol("g_value_get_float"); - fp_g_value_get_double = dl_symbol("g_value_get_double"); - fp_g_value_get_string = dl_symbol("g_value_get_string"); - fp_g_value_get_enum = dl_symbol("g_value_get_enum"); - fp_g_value_get_flags = dl_symbol("g_value_get_flags"); - fp_g_value_get_param = dl_symbol("g_value_get_param"); - fp_g_value_get_boxed = dl_symbol("g_value_get_boxed"); - fp_g_value_get_pointer = dl_symbol("g_value_get_pointer"); - fp_g_value_get_object = dl_symbol("g_value_get_object"); - fp_g_param_spec_int = dl_symbol("g_param_spec_int"); - fp_g_object_get = dl_symbol("g_object_get"); - fp_g_object_set = dl_symbol("g_object_set"); - - /* GDK */ - fp_gdk_get_default_root_window = - dl_symbol("gdk_get_default_root_window"); - fp_gdk_pixmap_new = dl_symbol("gdk_pixmap_new"); - fp_gdk_pixbuf_get_from_drawable = - dl_symbol("gdk_pixbuf_get_from_drawable"); - fp_gdk_pixbuf_scale_simple = - dl_symbol("gdk_pixbuf_scale_simple"); - fp_gdk_gc_new = dl_symbol("gdk_gc_new"); - fp_gdk_rgb_gc_set_foreground = - dl_symbol("gdk_rgb_gc_set_foreground"); - fp_gdk_draw_rectangle = dl_symbol("gdk_draw_rectangle"); - fp_gdk_drawable_get_size = dl_symbol("gdk_drawable_get_size"); - - /* Pixbuf */ - fp_gdk_pixbuf_new = dl_symbol("gdk_pixbuf_new"); - fp_gdk_pixbuf_new_from_file = - dl_symbol("gdk_pixbuf_new_from_file"); - fp_gdk_pixbuf_get_width = dl_symbol("gdk_pixbuf_get_width"); - fp_gdk_pixbuf_get_height = dl_symbol("gdk_pixbuf_get_height"); - fp_gdk_pixbuf_get_pixels = dl_symbol("gdk_pixbuf_get_pixels"); - fp_gdk_pixbuf_get_rowstride = - dl_symbol("gdk_pixbuf_get_rowstride"); - fp_gdk_pixbuf_get_has_alpha = - dl_symbol("gdk_pixbuf_get_has_alpha"); - fp_gdk_pixbuf_get_bits_per_sample = - dl_symbol("gdk_pixbuf_get_bits_per_sample"); - fp_gdk_pixbuf_get_n_channels = - dl_symbol("gdk_pixbuf_get_n_channels"); - fp_gdk_pixbuf_get_colorspace = - dl_symbol("gdk_pixbuf_get_colorspace"); - - /* GTK painting */ - fp_gtk_init_check = dl_symbol("gtk_init_check"); - fp_gtk_paint_hline = dl_symbol("gtk_paint_hline"); - fp_gtk_paint_vline = dl_symbol("gtk_paint_vline"); - fp_gtk_paint_shadow = dl_symbol("gtk_paint_shadow"); - fp_gtk_paint_arrow = dl_symbol("gtk_paint_arrow"); - fp_gtk_paint_box = dl_symbol("gtk_paint_box"); - fp_gtk_paint_flat_box = dl_symbol("gtk_paint_flat_box"); - fp_gtk_paint_check = dl_symbol("gtk_paint_check"); - fp_gtk_paint_option = dl_symbol("gtk_paint_option"); - fp_gtk_paint_box_gap = dl_symbol("gtk_paint_box_gap"); - fp_gtk_paint_extension = dl_symbol("gtk_paint_extension"); - fp_gtk_paint_focus = dl_symbol("gtk_paint_focus"); - fp_gtk_paint_slider = dl_symbol("gtk_paint_slider"); - fp_gtk_paint_handle = dl_symbol("gtk_paint_handle"); - fp_gtk_paint_expander = dl_symbol("gtk_paint_expander"); - fp_gtk_style_apply_default_background = - dl_symbol("gtk_style_apply_default_background"); - - /* GTK widgets */ - fp_gtk_arrow_new = dl_symbol("gtk_arrow_new"); - fp_gtk_button_new = dl_symbol("gtk_button_new"); - fp_gtk_spin_button_new = dl_symbol("gtk_spin_button_new"); - fp_gtk_check_button_new = dl_symbol("gtk_check_button_new"); - fp_gtk_check_menu_item_new = - dl_symbol("gtk_check_menu_item_new"); - fp_gtk_color_selection_dialog_new = - dl_symbol("gtk_color_selection_dialog_new"); - fp_gtk_entry_new = dl_symbol("gtk_entry_new"); - fp_gtk_fixed_new = dl_symbol("gtk_fixed_new"); - fp_gtk_handle_box_new = dl_symbol("gtk_handle_box_new"); - fp_gtk_image_new = dl_symbol("gtk_image_new"); - fp_gtk_hpaned_new = dl_symbol("gtk_hpaned_new"); - fp_gtk_vpaned_new = dl_symbol("gtk_vpaned_new"); - fp_gtk_hscale_new = dl_symbol("gtk_hscale_new"); - fp_gtk_vscale_new = dl_symbol("gtk_vscale_new"); - fp_gtk_hscrollbar_new = dl_symbol("gtk_hscrollbar_new"); - fp_gtk_vscrollbar_new = dl_symbol("gtk_vscrollbar_new"); - fp_gtk_hseparator_new = dl_symbol("gtk_hseparator_new"); - fp_gtk_vseparator_new = dl_symbol("gtk_vseparator_new"); - fp_gtk_label_new = dl_symbol("gtk_label_new"); - fp_gtk_menu_new = dl_symbol("gtk_menu_new"); - fp_gtk_menu_bar_new = dl_symbol("gtk_menu_bar_new"); - fp_gtk_menu_item_new = dl_symbol("gtk_menu_item_new"); - fp_gtk_menu_item_set_submenu = - dl_symbol("gtk_menu_item_set_submenu"); - fp_gtk_notebook_new = dl_symbol("gtk_notebook_new"); - fp_gtk_progress_bar_new = - dl_symbol("gtk_progress_bar_new"); - fp_gtk_progress_bar_set_orientation = - dl_symbol("gtk_progress_bar_set_orientation"); - fp_gtk_radio_button_new = - dl_symbol("gtk_radio_button_new"); - fp_gtk_radio_menu_item_new = - dl_symbol("gtk_radio_menu_item_new"); - fp_gtk_scrolled_window_new = - dl_symbol("gtk_scrolled_window_new"); - fp_gtk_separator_menu_item_new = - dl_symbol("gtk_separator_menu_item_new"); - fp_gtk_text_view_new = dl_symbol("gtk_text_view_new"); - fp_gtk_toggle_button_new = - dl_symbol("gtk_toggle_button_new"); - fp_gtk_toolbar_new = dl_symbol("gtk_toolbar_new"); - fp_gtk_tree_view_new = dl_symbol("gtk_tree_view_new"); - fp_gtk_viewport_new = dl_symbol("gtk_viewport_new"); - fp_gtk_window_new = dl_symbol("gtk_window_new"); - fp_gtk_window_present = dl_symbol("gtk_window_present"); - fp_gtk_window_move = dl_symbol("gtk_window_move"); - fp_gtk_window_resize = dl_symbol("gtk_window_resize"); - - fp_gtk_dialog_new = dl_symbol("gtk_dialog_new"); - fp_gtk_frame_new = dl_symbol("gtk_frame_new"); - - fp_gtk_adjustment_new = dl_symbol("gtk_adjustment_new"); - fp_gtk_container_add = dl_symbol("gtk_container_add"); - fp_gtk_menu_shell_append = - dl_symbol("gtk_menu_shell_append"); - fp_gtk_widget_realize = dl_symbol("gtk_widget_realize"); - fp_gtk_widget_destroy = dl_symbol("gtk_widget_destroy"); - fp_gtk_widget_render_icon = - dl_symbol("gtk_widget_render_icon"); - fp_gtk_widget_set_name = - dl_symbol("gtk_widget_set_name"); - fp_gtk_widget_set_parent = - dl_symbol("gtk_widget_set_parent"); - fp_gtk_widget_set_direction = - dl_symbol("gtk_widget_set_direction"); - fp_gtk_widget_style_get = - dl_symbol("gtk_widget_style_get"); - fp_gtk_widget_class_install_style_property = - dl_symbol("gtk_widget_class_install_style_property"); - fp_gtk_widget_class_find_style_property = - dl_symbol("gtk_widget_class_find_style_property"); - fp_gtk_widget_style_get_property = - dl_symbol("gtk_widget_style_get_property"); - fp_pango_font_description_to_string = - dl_symbol("pango_font_description_to_string"); - fp_gtk_settings_get_default = - dl_symbol("gtk_settings_get_default"); - fp_gtk_widget_get_settings = - dl_symbol("gtk_widget_get_settings"); - fp_gtk_border_get_type = dl_symbol("gtk_border_get_type"); - fp_gtk_arrow_set = dl_symbol("gtk_arrow_set"); - fp_gtk_widget_size_request = - dl_symbol("gtk_widget_size_request"); - fp_gtk_range_get_adjustment = - dl_symbol("gtk_range_get_adjustment"); - - fp_gtk_widget_hide = dl_symbol("gtk_widget_hide"); - fp_gtk_main_quit = dl_symbol("gtk_main_quit"); - fp_g_signal_connect_data = dl_symbol("g_signal_connect_data"); - fp_gtk_widget_show = dl_symbol("gtk_widget_show"); - fp_gtk_main = dl_symbol("gtk_main"); - - fp_g_path_get_dirname = dl_symbol("g_path_get_dirname"); - - /** - * GLib thread system - */ - if (GLIB_CHECK_VERSION(2, 20, 0)) { - fp_g_thread_get_initialized = dl_symbol_gthread("g_thread_get_initialized"); - } - fp_g_thread_init = dl_symbol_gthread("g_thread_init"); - fp_gdk_threads_init = dl_symbol("gdk_threads_init"); - fp_gdk_threads_enter = dl_symbol("gdk_threads_enter"); - fp_gdk_threads_leave = dl_symbol("gdk_threads_leave"); - - /** - * Functions for sun_awt_X11_GtkFileDialogPeer.c - */ - if (fp_gtk_check_version(2, 4, 0) == NULL) { - // The current GtkFileChooser is available from GTK+ 2.4 - gtk2_file_chooser_load(); - } - - /* Some functions may be missing in pre-2.4 GTK. - We handle them specially here. - */ - fp_gtk_combo_box_new = dlsym(gtk2_libhandle, "gtk_combo_box_new"); - if (fp_gtk_combo_box_new == NULL) { - fp_gtk_combo_box_new = dl_symbol("gtk_combo_new"); - } - - fp_gtk_combo_box_entry_new = - dlsym(gtk2_libhandle, "gtk_combo_box_entry_new"); - if (fp_gtk_combo_box_entry_new == NULL) { - fp_gtk_combo_box_entry_new = dl_symbol("gtk_combo_new"); - new_combo = FALSE; - } - - fp_gtk_separator_tool_item_new = - dlsym(gtk2_libhandle, "gtk_separator_tool_item_new"); - if (fp_gtk_separator_tool_item_new == NULL) { - fp_gtk_separator_tool_item_new = - dl_symbol("gtk_vseparator_new"); - } - - fp_g_list_append = dl_symbol("g_list_append"); - fp_g_list_free = dl_symbol("g_list_free"); - fp_g_list_free_full = dl_symbol("g_list_free_full"); - } - /* Now we have only one kind of exceptions: NO_SYMBOL_EXCEPTION - * Otherwise we can check the return value of setjmp method. - */ - else - { - dlclose(gtk2_libhandle); - gtk2_libhandle = NULL; - - dlclose(gthread_libhandle); - gthread_libhandle = NULL; - - return FALSE; - } - - /* - * Strip the AT-SPI GTK_MODULES if present - */ - gtk_modules_env = getenv ("GTK_MODULES"); - if ((gtk_modules_env && strstr(gtk_modules_env, "atk-bridge")) || - (gtk_modules_env && strstr(gtk_modules_env, "gail"))) { - /* careful, strtok modifies its args */ - gchar *tmp_env = strdup(gtk_modules_env); - if (tmp_env) { - /* the new env will be smaller than the old one */ - gchar *s, *new_env = SAFE_SIZE_STRUCT_ALLOC(malloc, - sizeof(ENV_PREFIX), 1, strlen (gtk_modules_env)); - - if (new_env) { - strcpy(new_env, ENV_PREFIX); - - /* strip out 'atk-bridge' and 'gail' */ - size_t PREFIX_LENGTH = strlen(ENV_PREFIX); - gchar *tmp_ptr = NULL; - for (s = strtok_r(tmp_env, ":", &tmp_ptr); s; - s = strtok_r(NULL, ":", &tmp_ptr)) { - if ((!strstr(s, "atk-bridge")) && (!strstr(s, "gail"))) { - if (strlen(new_env) > PREFIX_LENGTH) { - new_env = strcat(new_env, ":"); - } - new_env = strcat(new_env, s); - } - } - if (putenv(new_env) != 0) { - /* no free() on success, putenv() doesn't copy string */ - free(new_env); - } - } - free(tmp_env); - } - } - /* - * GTK should be initialized with gtk_init_check() before use. - * - * gtk_init_check installs its own error handlers. It is critical that - * we preserve error handler set from AWT. Otherwise we'll crash on - * BadMatch errors which we would normally ignore. The IO error handler - * is preserved here, too, just for consistency. - */ - AWT_LOCK(); - handler = XSetErrorHandler(NULL); - io_handler = XSetIOErrorHandler(NULL); - - if (fp_gtk_check_version(2, 2, 0) == NULL) { - - // Calling g_thread_init() multiple times leads to crash on GLib < 2.24 - // We can use g_thread_get_initialized () but it is available only for - // GLib >= 2.20. - gboolean is_g_thread_get_initialized = FALSE; - if (GLIB_CHECK_VERSION(2, 20, 0)) { - is_g_thread_get_initialized = fp_g_thread_get_initialized(); - } - - if (!is_g_thread_get_initialized) { - fp_g_thread_init(NULL); - } - - //According the GTK documentation, gdk_threads_init() should be - //called before gtk_init() or gtk_init_check() - fp_gdk_threads_init(); - } - result = (*fp_gtk_init_check)(NULL, NULL); - - XSetErrorHandler(handler); - XSetIOErrorHandler(io_handler); - AWT_UNLOCK(); - - /* Initialize widget array. */ - for (i = 0; i < _GTK_WIDGET_TYPE_SIZE; i++) - { - gtk2_widgets[i] = NULL; - } - if (result) { - GtkApi* gtk = (GtkApi*)malloc(sizeof(GtkApi)); - gtk2_init(gtk); - return gtk; - } - return NULL; -} - -int gtk2_unload() -{ - int i; - char *gtk2_error; - - if (!gtk2_libhandle) - return TRUE; - - /* Release painting objects */ - if (gtk2_white_pixmap != NULL) { - (*fp_g_object_unref)(gtk2_white_pixmap); - (*fp_g_object_unref)(gtk2_black_pixmap); - (*fp_g_object_unref)(gtk2_white_pixbuf); - (*fp_g_object_unref)(gtk2_black_pixbuf); - gtk2_white_pixmap = gtk2_black_pixmap = - gtk2_white_pixbuf = gtk2_black_pixbuf = NULL; - } - gtk2_pixbuf_width = 0; - gtk2_pixbuf_height = 0; - - if (gtk2_window != NULL) { - /* Destroying toplevel widget will destroy all contained widgets */ - (*fp_gtk_widget_destroy)(gtk2_window); - - /* Unset some static data so they get reinitialized on next load */ - gtk2_window = NULL; - } - - dlerror(); - dlclose(gtk2_libhandle); - dlclose(gthread_libhandle); - if ((gtk2_error = dlerror()) != NULL) - { - return FALSE; - } - return TRUE; -} - -/* Dispatch all pending events from the GTK event loop. - * This is needed to catch theme change and update widgets' style. - */ -static void flush_gtk_event_loop() -{ - while( (*fp_g_main_context_iteration)(NULL, FALSE)); -} - -/* - * Initialize components of containment hierarchy. This creates a GtkFixed - * inside a GtkWindow. All widgets get realized. - */ -static void init_containers() -{ - if (gtk2_window == NULL) - { - gtk2_window = (*fp_gtk_window_new)(GTK_WINDOW_TOPLEVEL); - gtk2_fixed = (GtkFixed *)(*fp_gtk_fixed_new)(); - (*fp_gtk_container_add)((GtkContainer*)gtk2_window, - (GtkWidget *)gtk2_fixed); - (*fp_gtk_widget_realize)(gtk2_window); - (*fp_gtk_widget_realize)((GtkWidget *)gtk2_fixed); - } -} - -/* - * Ensure everything is ready for drawing an element of the specified width - * and height. - * - * We should somehow handle translucent images. GTK can draw to X Drawables - * only, which don't support alpha. When we retrieve the image back from - * the server, translucency information is lost. There're several ways to - * work around this: - * 1) Subclass GdkPixmap and cache translucent objects on client side. This - * requires us to implement parts of X server drawing logic on client side. - * Many X requests can potentially be "translucent"; e.g. XDrawLine with - * fill=tile and a translucent tile is a "translucent" operation, whereas - * XDrawLine with fill=solid is an "opaque" one. Moreover themes can (and some - * do) intermix transparent and opaque operations which makes caching even - * more problematic. - * 2) Use Xorg 32bit ARGB visual when available. GDK has no native support - * for it (as of version 2.6). Also even in JDS 3 Xorg does not support - * these visuals by default, which makes optimizing for them pointless. - * We can consider doing this at a later point when ARGB visuals become more - * popular. - * 3') GTK has plans to use Cairo as its graphical backend (presumably in - * 2.8), and Cairo supports alpha. With it we could also get rid of the - * unnecessary round trip to server and do all the drawing on client side. - * 4) For now we draw to two different pixmaps and restore alpha channel by - * comparing results. This can be optimized by using subclassed pixmap and - * doing the second drawing only if necessary. -*/ -static void gtk2_init_painting(JNIEnv *env, gint width, gint height) -{ - GdkGC *gc; - GdkPixbuf *white, *black; - - init_containers(); - - if (gtk2_pixbuf_width < width || gtk2_pixbuf_height < height) - { - white = (*fp_gdk_pixbuf_new)(GDK_COLORSPACE_RGB, TRUE, 8, width, height); - black = (*fp_gdk_pixbuf_new)(GDK_COLORSPACE_RGB, TRUE, 8, width, height); - - if (white == NULL || black == NULL) - { - snprintf(convertionBuffer, CONV_BUFFER_SIZE, "Couldn't create pixbuf of size %dx%d", width, height); - throw_exception(env, "java/lang/RuntimeException", convertionBuffer); - fp_gdk_threads_leave(); - return; - } - - if (gtk2_white_pixmap != NULL) { - /* free old stuff */ - (*fp_g_object_unref)(gtk2_white_pixmap); - (*fp_g_object_unref)(gtk2_black_pixmap); - (*fp_g_object_unref)(gtk2_white_pixbuf); - (*fp_g_object_unref)(gtk2_black_pixbuf); - } - - gtk2_white_pixmap = (*fp_gdk_pixmap_new)(gtk2_window->window, width, height, -1); - gtk2_black_pixmap = (*fp_gdk_pixmap_new)(gtk2_window->window, width, height, -1); - - gtk2_white_pixbuf = white; - gtk2_black_pixbuf = black; - - gtk2_pixbuf_width = width; - gtk2_pixbuf_height = height; - } - - /* clear the pixmaps */ - gc = (*fp_gdk_gc_new)(gtk2_white_pixmap); - (*fp_gdk_rgb_gc_set_foreground)(gc, 0xffffff); - (*fp_gdk_draw_rectangle)(gtk2_white_pixmap, gc, TRUE, 0, 0, width, height); - (*fp_g_object_unref)(gc); - - gc = (*fp_gdk_gc_new)(gtk2_black_pixmap); - (*fp_gdk_rgb_gc_set_foreground)(gc, 0x000000); - (*fp_gdk_draw_rectangle)(gtk2_black_pixmap, gc, TRUE, 0, 0, width, height); - (*fp_g_object_unref)(gc); -} - -/* - * Restore image from white and black pixmaps and copy it into destination - * buffer. This method compares two pixbufs taken from white and black - * pixmaps and decodes color and alpha components. Pixbufs are RGB without - * alpha, destination buffer is ABGR. - * - * The return value is the transparency type of the resulting image, either - * one of java_awt_Transparency_OPAQUE, java_awt_Transparency_BITMASK, and - * java_awt_Transparency_TRANSLUCENT. - */ -static gint gtk2_copy_image(gint *dst, gint width, gint height) -{ - gint i, j, r, g, b; - guchar *white, *black; - gint stride, padding; - gboolean is_opaque = TRUE; - gboolean is_bitmask = TRUE; - - (*fp_gdk_pixbuf_get_from_drawable)(gtk2_white_pixbuf, gtk2_white_pixmap, - NULL, 0, 0, 0, 0, width, height); - (*fp_gdk_pixbuf_get_from_drawable)(gtk2_black_pixbuf, gtk2_black_pixmap, - NULL, 0, 0, 0, 0, width, height); - - white = (*fp_gdk_pixbuf_get_pixels)(gtk2_white_pixbuf); - black = (*fp_gdk_pixbuf_get_pixels)(gtk2_black_pixbuf); - stride = (*fp_gdk_pixbuf_get_rowstride)(gtk2_black_pixbuf); - padding = stride - width * 4; - if (padding >= 0 && stride > 0) { - for (i = 0; i < height; i++) { - for (j = 0; j < width; j++) { - int r1 = *white++; - int r2 = *black++; - int alpha = 0xff + r2 - r1; - - switch (alpha) { - case 0: /* transparent pixel */ - r = g = b = 0; - black += 3; - white += 3; - is_opaque = FALSE; - break; - - case 0xff: /* opaque pixel */ - r = r2; - g = *black++; - b = *black++; - black++; - white += 3; - break; - - default: /* translucent pixel */ - r = 0xff * r2 / alpha; - g = 0xff * *black++ / alpha; - b = 0xff * *black++ / alpha; - black++; - white += 3; - is_opaque = FALSE; - is_bitmask = FALSE; - break; - } - - *dst++ = (alpha << 24 | r << 16 | g << 8 | b); - } - - white += padding; - black += padding; - } - } - return is_opaque ? java_awt_Transparency_OPAQUE : - (is_bitmask ? java_awt_Transparency_BITMASK : - java_awt_Transparency_TRANSLUCENT); -} - -static void -gtk2_set_direction(GtkWidget *widget, GtkTextDirection dir) -{ - /* - * Some engines (inexplicably) look at the direction of the widget's - * parent, so we need to set the direction of both the widget and its - * parent. - */ - (*fp_gtk_widget_set_direction)(widget, dir); - if (widget->parent != NULL) { - (*fp_gtk_widget_set_direction)(widget->parent, dir); - } -} - -/* - * Initializes the widget to correct state for some engines. - * This is a pure empirical method. - */ -static void init_toggle_widget(WidgetType widget_type, gint synth_state) -{ - gboolean is_active = ((synth_state & SELECTED) != 0); - - if (widget_type == RADIO_BUTTON || - widget_type == CHECK_BOX || - widget_type == TOGGLE_BUTTON) { - ((GtkToggleButton*)gtk2_widget)->active = is_active; - } - - if ((synth_state & FOCUSED) != 0) { - ((GtkObject*)gtk2_widget)->flags |= GTK_HAS_FOCUS; - } else { - ((GtkObject*)gtk2_widget)->flags &= ~GTK_HAS_FOCUS; - } - - if ((((synth_state & MOUSE_OVER) != 0) && ((synth_state & PRESSED) == 0)) || - (((synth_state & FOCUSED) != 0) && ((synth_state & PRESSED) != 0))) { - gtk2_widget->state = GTK_STATE_PRELIGHT; - } else if ((synth_state & DISABLED) != 0) { - gtk2_widget->state = GTK_STATE_INSENSITIVE; - } else { - gtk2_widget->state = is_active ? GTK_STATE_ACTIVE : GTK_STATE_NORMAL; - } -} - -/* GTK state_type filter */ -static GtkStateType get_gtk_state_type(WidgetType widget_type, gint synth_state) -{ - GtkStateType result = GTK_STATE_NORMAL; - - if ((synth_state & DISABLED) != 0) { - result = GTK_STATE_INSENSITIVE; - } else if ((synth_state & PRESSED) != 0) { - result = GTK_STATE_ACTIVE; - } else if ((synth_state & MOUSE_OVER) != 0) { - result = GTK_STATE_PRELIGHT; - } - return result; -} - -/* GTK shadow_type filter */ -static GtkShadowType get_gtk_shadow_type(WidgetType widget_type, gint synth_state) -{ - GtkShadowType result = GTK_SHADOW_OUT; - - if ((synth_state & SELECTED) != 0) { - result = GTK_SHADOW_IN; - } - return result; -} - - -static GtkWidget* gtk2_get_arrow(GtkArrowType arrow_type, GtkShadowType shadow_type) -{ - GtkWidget *arrow = NULL; - if (NULL == gtk2_widgets[_GTK_ARROW_TYPE]) - { - gtk2_widgets[_GTK_ARROW_TYPE] = (*fp_gtk_arrow_new)(arrow_type, shadow_type); - (*fp_gtk_container_add)((GtkContainer *)gtk2_fixed, gtk2_widgets[_GTK_ARROW_TYPE]); - (*fp_gtk_widget_realize)(gtk2_widgets[_GTK_ARROW_TYPE]); - } - arrow = gtk2_widgets[_GTK_ARROW_TYPE]; - - (*fp_gtk_arrow_set)(arrow, arrow_type, shadow_type); - return arrow; -} - -static GtkAdjustment* create_adjustment() -{ - return (GtkAdjustment *) - (*fp_gtk_adjustment_new)(50.0, 0.0, 100.0, 10.0, 20.0, 20.0); -} - -/** - * Returns a pointer to the cached native widget for the specified widget - * type. - */ -static GtkWidget *gtk2_get_widget(WidgetType widget_type) -{ - gboolean init_result = FALSE; - GtkWidget *result = NULL; - switch (widget_type) - { - case BUTTON: - case TABLE_HEADER: - if (init_result = (NULL == gtk2_widgets[_GTK_BUTTON_TYPE])) - { - gtk2_widgets[_GTK_BUTTON_TYPE] = (*fp_gtk_button_new)(); - } - result = gtk2_widgets[_GTK_BUTTON_TYPE]; - break; - case CHECK_BOX: - if (init_result = (NULL == gtk2_widgets[_GTK_CHECK_BUTTON_TYPE])) - { - gtk2_widgets[_GTK_CHECK_BUTTON_TYPE] = - (*fp_gtk_check_button_new)(); - } - result = gtk2_widgets[_GTK_CHECK_BUTTON_TYPE]; - break; - case CHECK_BOX_MENU_ITEM: - if (init_result = (NULL == gtk2_widgets[_GTK_CHECK_MENU_ITEM_TYPE])) - { - gtk2_widgets[_GTK_CHECK_MENU_ITEM_TYPE] = - (*fp_gtk_check_menu_item_new)(); - } - result = gtk2_widgets[_GTK_CHECK_MENU_ITEM_TYPE]; - break; - /************************************************************ - * Creation a dedicated color chooser is dangerous because - * it deadlocks the EDT - ************************************************************/ -/* case COLOR_CHOOSER: - if (init_result = - (NULL == gtk2_widgets[_GTK_COLOR_SELECTION_DIALOG_TYPE])) - { - gtk2_widgets[_GTK_COLOR_SELECTION_DIALOG_TYPE] = - (*fp_gtk_color_selection_dialog_new)(NULL); - } - result = gtk2_widgets[_GTK_COLOR_SELECTION_DIALOG_TYPE]; - break;*/ - case COMBO_BOX: - if (init_result = (NULL == gtk2_widgets[_GTK_COMBO_BOX_TYPE])) - { - gtk2_widgets[_GTK_COMBO_BOX_TYPE] = - (*fp_gtk_combo_box_new)(); - } - result = gtk2_widgets[_GTK_COMBO_BOX_TYPE]; - break; - case COMBO_BOX_ARROW_BUTTON: - if (init_result = - (NULL == gtk2_widgets[_GTK_COMBO_BOX_ARROW_BUTTON_TYPE])) - { - gtk2_widgets[_GTK_COMBO_BOX_ARROW_BUTTON_TYPE] = - (*fp_gtk_toggle_button_new)(); - } - result = gtk2_widgets[_GTK_COMBO_BOX_ARROW_BUTTON_TYPE]; - break; - case COMBO_BOX_TEXT_FIELD: - if (init_result = - (NULL == gtk2_widgets[_GTK_COMBO_BOX_TEXT_FIELD_TYPE])) - { - result = gtk2_widgets[_GTK_COMBO_BOX_TEXT_FIELD_TYPE] = - (*fp_gtk_entry_new)(); - } - result = gtk2_widgets[_GTK_COMBO_BOX_TEXT_FIELD_TYPE]; - break; - case DESKTOP_ICON: - case INTERNAL_FRAME_TITLE_PANE: - case LABEL: - if (init_result = (NULL == gtk2_widgets[_GTK_LABEL_TYPE])) - { - gtk2_widgets[_GTK_LABEL_TYPE] = - (*fp_gtk_label_new)(NULL); - } - result = gtk2_widgets[_GTK_LABEL_TYPE]; - break; - case DESKTOP_PANE: - case PANEL: - case ROOT_PANE: - if (init_result = (NULL == gtk2_widgets[_GTK_CONTAINER_TYPE])) - { - /* There is no constructor for a container type. I've - * chosen GtkFixed container since it has a default - * constructor. - */ - gtk2_widgets[_GTK_CONTAINER_TYPE] = - (*fp_gtk_fixed_new)(); - } - result = gtk2_widgets[_GTK_CONTAINER_TYPE]; - break; - case EDITOR_PANE: - case TEXT_AREA: - case TEXT_PANE: - if (init_result = (NULL == gtk2_widgets[_GTK_TEXT_VIEW_TYPE])) - { - gtk2_widgets[_GTK_TEXT_VIEW_TYPE] = - (*fp_gtk_text_view_new)(); - } - result = gtk2_widgets[_GTK_TEXT_VIEW_TYPE]; - break; - case FORMATTED_TEXT_FIELD: - case PASSWORD_FIELD: - case TEXT_FIELD: - if (init_result = (NULL == gtk2_widgets[_GTK_ENTRY_TYPE])) - { - gtk2_widgets[_GTK_ENTRY_TYPE] = - (*fp_gtk_entry_new)(); - } - result = gtk2_widgets[_GTK_ENTRY_TYPE]; - break; - case HANDLE_BOX: - if (init_result = (NULL == gtk2_widgets[_GTK_HANDLE_BOX_TYPE])) - { - gtk2_widgets[_GTK_HANDLE_BOX_TYPE] = - (*fp_gtk_handle_box_new)(); - } - result = gtk2_widgets[_GTK_HANDLE_BOX_TYPE]; - break; - case HSCROLL_BAR: - case HSCROLL_BAR_BUTTON_LEFT: - case HSCROLL_BAR_BUTTON_RIGHT: - case HSCROLL_BAR_TRACK: - case HSCROLL_BAR_THUMB: - if (init_result = (NULL == gtk2_widgets[_GTK_HSCROLLBAR_TYPE])) - { - gtk2_widgets[_GTK_HSCROLLBAR_TYPE] = - (*fp_gtk_hscrollbar_new)(create_adjustment()); - } - result = gtk2_widgets[_GTK_HSCROLLBAR_TYPE]; - break; - case HSEPARATOR: - if (init_result = (NULL == gtk2_widgets[_GTK_HSEPARATOR_TYPE])) - { - gtk2_widgets[_GTK_HSEPARATOR_TYPE] = - (*fp_gtk_hseparator_new)(); - } - result = gtk2_widgets[_GTK_HSEPARATOR_TYPE]; - break; - case HSLIDER: - case HSLIDER_THUMB: - case HSLIDER_TRACK: - if (init_result = (NULL == gtk2_widgets[_GTK_HSCALE_TYPE])) - { - gtk2_widgets[_GTK_HSCALE_TYPE] = - (*fp_gtk_hscale_new)(NULL); - } - result = gtk2_widgets[_GTK_HSCALE_TYPE]; - break; - case HSPLIT_PANE_DIVIDER: - case SPLIT_PANE: - if (init_result = (NULL == gtk2_widgets[_GTK_HPANED_TYPE])) - { - gtk2_widgets[_GTK_HPANED_TYPE] = (*fp_gtk_hpaned_new)(); - } - result = gtk2_widgets[_GTK_HPANED_TYPE]; - break; - case IMAGE: - if (init_result = (NULL == gtk2_widgets[_GTK_IMAGE_TYPE])) - { - gtk2_widgets[_GTK_IMAGE_TYPE] = (*fp_gtk_image_new)(); - } - result = gtk2_widgets[_GTK_IMAGE_TYPE]; - break; - case INTERNAL_FRAME: - if (init_result = (NULL == gtk2_widgets[_GTK_WINDOW_TYPE])) - { - gtk2_widgets[_GTK_WINDOW_TYPE] = - (*fp_gtk_window_new)(GTK_WINDOW_TOPLEVEL); - } - result = gtk2_widgets[_GTK_WINDOW_TYPE]; - break; - case TOOL_TIP: - if (init_result = (NULL == gtk2_widgets[_GTK_TOOLTIP_TYPE])) - { - result = (*fp_gtk_window_new)(GTK_WINDOW_TOPLEVEL); - (*fp_gtk_widget_set_name)(result, "gtk-tooltips"); - gtk2_widgets[_GTK_TOOLTIP_TYPE] = result; - } - result = gtk2_widgets[_GTK_TOOLTIP_TYPE]; - break; - case LIST: - case TABLE: - case TREE: - case TREE_CELL: - if (init_result = (NULL == gtk2_widgets[_GTK_TREE_VIEW_TYPE])) - { - gtk2_widgets[_GTK_TREE_VIEW_TYPE] = - (*fp_gtk_tree_view_new)(); - } - result = gtk2_widgets[_GTK_TREE_VIEW_TYPE]; - break; - case TITLED_BORDER: - if (init_result = (NULL == gtk2_widgets[_GTK_FRAME_TYPE])) - { - gtk2_widgets[_GTK_FRAME_TYPE] = fp_gtk_frame_new(NULL); - } - result = gtk2_widgets[_GTK_FRAME_TYPE]; - break; - case POPUP_MENU: - if (init_result = (NULL == gtk2_widgets[_GTK_MENU_TYPE])) - { - gtk2_widgets[_GTK_MENU_TYPE] = - (*fp_gtk_menu_new)(); - } - result = gtk2_widgets[_GTK_MENU_TYPE]; - break; - case MENU: - case MENU_ITEM: - case MENU_ITEM_ACCELERATOR: - if (init_result = (NULL == gtk2_widgets[_GTK_MENU_ITEM_TYPE])) - { - gtk2_widgets[_GTK_MENU_ITEM_TYPE] = - (*fp_gtk_menu_item_new)(); - } - result = gtk2_widgets[_GTK_MENU_ITEM_TYPE]; - break; - case MENU_BAR: - if (init_result = (NULL == gtk2_widgets[_GTK_MENU_BAR_TYPE])) - { - gtk2_widgets[_GTK_MENU_BAR_TYPE] = - (*fp_gtk_menu_bar_new)(); - } - result = gtk2_widgets[_GTK_MENU_BAR_TYPE]; - break; - case COLOR_CHOOSER: - case OPTION_PANE: - if (init_result = (NULL == gtk2_widgets[_GTK_DIALOG_TYPE])) - { - gtk2_widgets[_GTK_DIALOG_TYPE] = - (*fp_gtk_dialog_new)(); - } - result = gtk2_widgets[_GTK_DIALOG_TYPE]; - break; - case POPUP_MENU_SEPARATOR: - if (init_result = - (NULL == gtk2_widgets[_GTK_SEPARATOR_MENU_ITEM_TYPE])) - { - gtk2_widgets[_GTK_SEPARATOR_MENU_ITEM_TYPE] = - (*fp_gtk_separator_menu_item_new)(); - } - result = gtk2_widgets[_GTK_SEPARATOR_MENU_ITEM_TYPE]; - break; - case HPROGRESS_BAR: - if (init_result = (NULL == gtk2_widgets[_GTK_HPROGRESS_BAR_TYPE])) - { - gtk2_widgets[_GTK_HPROGRESS_BAR_TYPE] = - (*fp_gtk_progress_bar_new)(); - } - result = gtk2_widgets[_GTK_HPROGRESS_BAR_TYPE]; - break; - case VPROGRESS_BAR: - if (init_result = (NULL == gtk2_widgets[_GTK_VPROGRESS_BAR_TYPE])) - { - gtk2_widgets[_GTK_VPROGRESS_BAR_TYPE] = - (*fp_gtk_progress_bar_new)(); - /* - * Vertical JProgressBars always go bottom-to-top, - * regardless of the ComponentOrientation. - */ - (*fp_gtk_progress_bar_set_orientation)( - (GtkProgressBar *)gtk2_widgets[_GTK_VPROGRESS_BAR_TYPE], - GTK_PROGRESS_BOTTOM_TO_TOP); - } - result = gtk2_widgets[_GTK_VPROGRESS_BAR_TYPE]; - break; - case RADIO_BUTTON: - if (init_result = (NULL == gtk2_widgets[_GTK_RADIO_BUTTON_TYPE])) - { - gtk2_widgets[_GTK_RADIO_BUTTON_TYPE] = - (*fp_gtk_radio_button_new)(NULL); - } - result = gtk2_widgets[_GTK_RADIO_BUTTON_TYPE]; - break; - case RADIO_BUTTON_MENU_ITEM: - if (init_result = - (NULL == gtk2_widgets[_GTK_RADIO_MENU_ITEM_TYPE])) - { - gtk2_widgets[_GTK_RADIO_MENU_ITEM_TYPE] = - (*fp_gtk_radio_menu_item_new)(NULL); - } - result = gtk2_widgets[_GTK_RADIO_MENU_ITEM_TYPE]; - break; - case SCROLL_PANE: - if (init_result = - (NULL == gtk2_widgets[_GTK_SCROLLED_WINDOW_TYPE])) - { - gtk2_widgets[_GTK_SCROLLED_WINDOW_TYPE] = - (*fp_gtk_scrolled_window_new)(NULL, NULL); - } - result = gtk2_widgets[_GTK_SCROLLED_WINDOW_TYPE]; - break; - case SPINNER: - case SPINNER_ARROW_BUTTON: - case SPINNER_TEXT_FIELD: - if (init_result = (NULL == gtk2_widgets[_GTK_SPIN_BUTTON_TYPE])) - { - result = gtk2_widgets[_GTK_SPIN_BUTTON_TYPE] = - (*fp_gtk_spin_button_new)(NULL, 0, 0); - } - result = gtk2_widgets[_GTK_SPIN_BUTTON_TYPE]; - break; - case TABBED_PANE: - case TABBED_PANE_TAB_AREA: - case TABBED_PANE_CONTENT: - case TABBED_PANE_TAB: - if (init_result = (NULL == gtk2_widgets[_GTK_NOTEBOOK_TYPE])) - { - gtk2_widgets[_GTK_NOTEBOOK_TYPE] = - (*fp_gtk_notebook_new)(); - } - result = gtk2_widgets[_GTK_NOTEBOOK_TYPE]; - break; - case TOGGLE_BUTTON: - if (init_result = (NULL == gtk2_widgets[_GTK_TOGGLE_BUTTON_TYPE])) - { - gtk2_widgets[_GTK_TOGGLE_BUTTON_TYPE] = - (*fp_gtk_toggle_button_new)(); - } - result = gtk2_widgets[_GTK_TOGGLE_BUTTON_TYPE]; - break; - case TOOL_BAR: - case TOOL_BAR_DRAG_WINDOW: - if (init_result = (NULL == gtk2_widgets[_GTK_TOOLBAR_TYPE])) - { - gtk2_widgets[_GTK_TOOLBAR_TYPE] = - (*fp_gtk_toolbar_new)(); - } - result = gtk2_widgets[_GTK_TOOLBAR_TYPE]; - break; - case TOOL_BAR_SEPARATOR: - if (init_result = - (NULL == gtk2_widgets[_GTK_SEPARATOR_TOOL_ITEM_TYPE])) - { - gtk2_widgets[_GTK_SEPARATOR_TOOL_ITEM_TYPE] = - (*fp_gtk_separator_tool_item_new)(); - } - result = gtk2_widgets[_GTK_SEPARATOR_TOOL_ITEM_TYPE]; - break; - case VIEWPORT: - if (init_result = (NULL == gtk2_widgets[_GTK_VIEWPORT_TYPE])) - { - GtkAdjustment *adjustment = create_adjustment(); - gtk2_widgets[_GTK_VIEWPORT_TYPE] = - (*fp_gtk_viewport_new)(adjustment, adjustment); - } - result = gtk2_widgets[_GTK_VIEWPORT_TYPE]; - break; - case VSCROLL_BAR: - case VSCROLL_BAR_BUTTON_UP: - case VSCROLL_BAR_BUTTON_DOWN: - case VSCROLL_BAR_TRACK: - case VSCROLL_BAR_THUMB: - if (init_result = (NULL == gtk2_widgets[_GTK_VSCROLLBAR_TYPE])) - { - gtk2_widgets[_GTK_VSCROLLBAR_TYPE] = - (*fp_gtk_vscrollbar_new)(create_adjustment()); - } - result = gtk2_widgets[_GTK_VSCROLLBAR_TYPE]; - break; - case VSEPARATOR: - if (init_result = (NULL == gtk2_widgets[_GTK_VSEPARATOR_TYPE])) - { - gtk2_widgets[_GTK_VSEPARATOR_TYPE] = - (*fp_gtk_vseparator_new)(); - } - result = gtk2_widgets[_GTK_VSEPARATOR_TYPE]; - break; - case VSLIDER: - case VSLIDER_THUMB: - case VSLIDER_TRACK: - if (init_result = (NULL == gtk2_widgets[_GTK_VSCALE_TYPE])) - { - gtk2_widgets[_GTK_VSCALE_TYPE] = - (*fp_gtk_vscale_new)(NULL); - } - result = gtk2_widgets[_GTK_VSCALE_TYPE]; - /* - * Vertical JSliders start at the bottom, while vertical - * GtkVScale widgets start at the top (by default), so to fix - * this we set the "inverted" flag to get the Swing behavior. - */ - ((GtkRange*)result)->inverted = 1; - break; - case VSPLIT_PANE_DIVIDER: - if (init_result = (NULL == gtk2_widgets[_GTK_VPANED_TYPE])) - { - gtk2_widgets[_GTK_VPANED_TYPE] = (*fp_gtk_vpaned_new)(); - } - result = gtk2_widgets[_GTK_VPANED_TYPE]; - break; - default: - result = NULL; - break; - } - - if (result != NULL && init_result) - { - if (widget_type == RADIO_BUTTON_MENU_ITEM || - widget_type == CHECK_BOX_MENU_ITEM || - widget_type == MENU_ITEM || - widget_type == MENU || - widget_type == POPUP_MENU_SEPARATOR) - { - GtkWidget *menu = gtk2_get_widget(POPUP_MENU); - (*fp_gtk_menu_shell_append)((GtkMenuShell *)menu, result); - } - else if (widget_type == POPUP_MENU) - { - GtkWidget *menu_bar = gtk2_get_widget(MENU_BAR); - GtkWidget *root_menu = (*fp_gtk_menu_item_new)(); - (*fp_gtk_menu_item_set_submenu)((GtkMenuItem*)root_menu, result); - (*fp_gtk_menu_shell_append)((GtkMenuShell *)menu_bar, root_menu); - } - else if (widget_type == COMBO_BOX_ARROW_BUTTON || - widget_type == COMBO_BOX_TEXT_FIELD) - { - /* - * We add a regular GtkButton/GtkEntry to a GtkComboBoxEntry - * in order to trick engines into thinking it's a real combobox - * arrow button/text field. - */ - GtkWidget *combo = (*fp_gtk_combo_box_entry_new)(); - - if (new_combo && widget_type == COMBO_BOX_ARROW_BUTTON) { - (*fp_gtk_widget_set_parent)(result, combo); - ((GtkBin*)combo)->child = result; - } else { - (*fp_gtk_container_add)((GtkContainer *)combo, result); - } - (*fp_gtk_container_add)((GtkContainer *)gtk2_fixed, combo); - } - else if (widget_type != TOOL_TIP && - widget_type != INTERNAL_FRAME && - widget_type != OPTION_PANE) - { - (*fp_gtk_container_add)((GtkContainer *)gtk2_fixed, result); - } - (*fp_gtk_widget_realize)(result); - } - return result; -} - -void gtk2_paint_arrow(WidgetType widget_type, GtkStateType state_type, - GtkShadowType shadow_type, const gchar *detail, - gint x, gint y, gint width, gint height, - GtkArrowType arrow_type, gboolean fill) -{ - static int w, h; - static GtkRequisition size; - - if (widget_type == COMBO_BOX_ARROW_BUTTON || widget_type == TABLE) - gtk2_widget = gtk2_get_arrow(arrow_type, shadow_type); - else - gtk2_widget = gtk2_get_widget(widget_type); - - switch (widget_type) - { - case SPINNER_ARROW_BUTTON: - x = 1; - y = ((arrow_type == GTK_ARROW_UP) ? 2 : 0); - height -= 2; - width -= 3; - - w = width / 2; - w -= w % 2 - 1; - h = (w + 1) / 2; - break; - - case HSCROLL_BAR_BUTTON_LEFT: - case HSCROLL_BAR_BUTTON_RIGHT: - case VSCROLL_BAR_BUTTON_UP: - case VSCROLL_BAR_BUTTON_DOWN: - w = width / 2; - h = height / 2; - break; - - case COMBO_BOX_ARROW_BUTTON: - case TABLE: - x = 1; - (*fp_gtk_widget_size_request)(gtk2_widget, &size); - w = size.width - ((GtkMisc*)gtk2_widget)->xpad * 2; - h = size.height - ((GtkMisc*)gtk2_widget)->ypad * 2; - w = h = MIN(MIN(w, h), MIN(width,height)) * 0.7; - break; - - default: - w = width; - h = height; - break; - } - x += (width - w) / 2; - y += (height - h) / 2; - - (*fp_gtk_paint_arrow)(gtk2_widget->style, gtk2_white_pixmap, state_type, - shadow_type, NULL, gtk2_widget, detail, arrow_type, fill, - x, y, w, h); - (*fp_gtk_paint_arrow)(gtk2_widget->style, gtk2_black_pixmap, state_type, - shadow_type, NULL, gtk2_widget, detail, arrow_type, fill, - x, y, w, h); -} - -static void gtk2_paint_box(WidgetType widget_type, GtkStateType state_type, - GtkShadowType shadow_type, const gchar *detail, - gint x, gint y, gint width, gint height, - gint synth_state, GtkTextDirection dir) -{ - gtk2_widget = gtk2_get_widget(widget_type); - - /* - * The clearlooks engine sometimes looks at the widget's state field - * instead of just the state_type variable that we pass in, so to account - * for those cases we set the widget's state field accordingly. The - * flags field is similarly important for things like focus/default state. - */ - gtk2_widget->state = state_type; - - if (widget_type == HSLIDER_TRACK) { - /* - * For horizontal JSliders with right-to-left orientation, we need - * to set the "inverted" flag to match the native GTK behavior where - * the foreground highlight is on the right side of the slider thumb. - * This is needed especially for the ubuntulooks engine, which looks - * exclusively at the "inverted" flag to determine on which side of - * the thumb to paint the highlight... - */ - ((GtkRange*)gtk2_widget)->inverted = (dir == GTK_TEXT_DIR_RTL); - - /* - * Note however that other engines like clearlooks will look at both - * the "inverted" field and the text direction to determine how - * the foreground highlight is painted: - * !inverted && ltr --> paint highlight on left side - * !inverted && rtl --> paint highlight on right side - * inverted && ltr --> paint highlight on right side - * inverted && rtl --> paint highlight on left side - * So the only way to reliably get the desired results for horizontal - * JSlider (i.e., highlight on left side for LTR ComponentOrientation - * and highlight on right side for RTL ComponentOrientation) is to - * always override text direction as LTR, and then set the "inverted" - * flag accordingly (as we have done above). - */ - dir = GTK_TEXT_DIR_LTR; - } - - /* - * Some engines (e.g. clearlooks) will paint the shadow of certain - * widgets (e.g. COMBO_BOX_ARROW_BUTTON) differently depending on the - * the text direction. - */ - gtk2_set_direction(gtk2_widget, dir); - - switch (widget_type) { - case BUTTON: - if (synth_state & DEFAULT) { - ((GtkObject*)gtk2_widget)->flags |= GTK_HAS_DEFAULT; - } else { - ((GtkObject*)gtk2_widget)->flags &= ~GTK_HAS_DEFAULT; - } - break; - case TOGGLE_BUTTON: - init_toggle_widget(widget_type, synth_state); - break; - case HSCROLL_BAR_BUTTON_LEFT: - /* - * The clearlooks engine will draw a "left" button when: - * x == w->allocation.x - * - * The ubuntulooks engine will draw a "left" button when: - * [x,y,width,height] - * intersects - * [w->alloc.x,w->alloc.y,width,height] - * - * The values that are set below should ensure that a "left" - * button is rendered for both of these (and other) engines. - */ - gtk2_widget->allocation.x = x; - gtk2_widget->allocation.y = y; - gtk2_widget->allocation.width = width; - gtk2_widget->allocation.height = height; - break; - case HSCROLL_BAR_BUTTON_RIGHT: - /* - * The clearlooks engine will draw a "right" button when: - * x + width == w->allocation.x + w->allocation.width - * - * The ubuntulooks engine will draw a "right" button when: - * [x,y,width,height] - * does not intersect - * [w->alloc.x,w->alloc.y,width,height] - * but does intersect - * [w->alloc.x+width,w->alloc.y,width,height] - * - * The values that are set below should ensure that a "right" - * button is rendered for both of these (and other) engines. - */ - gtk2_widget->allocation.x = x+width; - gtk2_widget->allocation.y = 0; - gtk2_widget->allocation.width = 0; - gtk2_widget->allocation.height = height; - break; - case VSCROLL_BAR_BUTTON_UP: - /* - * The clearlooks engine will draw an "up" button when: - * y == w->allocation.y - * - * The ubuntulooks engine will draw an "up" button when: - * [x,y,width,height] - * intersects - * [w->alloc.x,w->alloc.y,width,height] - * - * The values that are set below should ensure that an "up" - * button is rendered for both of these (and other) engines. - */ - gtk2_widget->allocation.x = x; - gtk2_widget->allocation.y = y; - gtk2_widget->allocation.width = width; - gtk2_widget->allocation.height = height; - break; - case VSCROLL_BAR_BUTTON_DOWN: - /* - * The clearlooks engine will draw a "down" button when: - * y + height == w->allocation.y + w->allocation.height - * - * The ubuntulooks engine will draw a "down" button when: - * [x,y,width,height] - * does not intersect - * [w->alloc.x,w->alloc.y,width,height] - * but does intersect - * [w->alloc.x,w->alloc.y+height,width,height] - * - * The values that are set below should ensure that a "down" - * button is rendered for both of these (and other) engines. - */ - gtk2_widget->allocation.x = x; - gtk2_widget->allocation.y = y+height; - gtk2_widget->allocation.width = width; - gtk2_widget->allocation.height = 0; - break; - default: - break; - } - - (*fp_gtk_paint_box)(gtk2_widget->style, gtk2_white_pixmap, state_type, - shadow_type, NULL, gtk2_widget, detail, x, y, width, height); - (*fp_gtk_paint_box)(gtk2_widget->style, gtk2_black_pixmap, state_type, - shadow_type, NULL, gtk2_widget, detail, x, y, width, height); - - /* - * Reset the text direction to the default value so that we don't - * accidentally affect other operations and widgets. - */ - gtk2_set_direction(gtk2_widget, GTK_TEXT_DIR_LTR); -} - -void gtk2_paint_box_gap(WidgetType widget_type, GtkStateType state_type, - GtkShadowType shadow_type, const gchar *detail, - gint x, gint y, gint width, gint height, - GtkPositionType gap_side, gint gap_x, gint gap_width) -{ - /* Clearlooks needs a real clip area to paint the gap properly */ - GdkRectangle area = { x, y, width, height }; - - gtk2_widget = gtk2_get_widget(widget_type); - (*fp_gtk_paint_box_gap)(gtk2_widget->style, gtk2_white_pixmap, state_type, - shadow_type, &area, gtk2_widget, detail, - x, y, width, height, gap_side, gap_x, gap_width); - (*fp_gtk_paint_box_gap)(gtk2_widget->style, gtk2_black_pixmap, state_type, - shadow_type, &area, gtk2_widget, detail, - x, y, width, height, gap_side, gap_x, gap_width); -} - -static void gtk2_paint_check(WidgetType widget_type, gint synth_state, - const gchar *detail, gint x, gint y, gint width, gint height) -{ - GtkStateType state_type = get_gtk_state_type(widget_type, synth_state); - GtkShadowType shadow_type = get_gtk_shadow_type(widget_type, synth_state); - - gtk2_widget = gtk2_get_widget(widget_type); - init_toggle_widget(widget_type, synth_state); - - (*fp_gtk_paint_check)(gtk2_widget->style, gtk2_white_pixmap, state_type, - shadow_type, NULL, gtk2_widget, detail, - x, y, width, height); - (*fp_gtk_paint_check)(gtk2_widget->style, gtk2_black_pixmap, state_type, - shadow_type, NULL, gtk2_widget, detail, - x, y, width, height); -} - -static void gtk2_paint_expander(WidgetType widget_type, GtkStateType state_type, - const gchar *detail, gint x, gint y, gint width, gint height, - GtkExpanderStyle expander_style) -{ - gtk2_widget = gtk2_get_widget(widget_type); - (*fp_gtk_paint_expander)(gtk2_widget->style, gtk2_white_pixmap, - state_type, NULL, gtk2_widget, detail, - x + width / 2, y + height / 2, expander_style); - (*fp_gtk_paint_expander)(gtk2_widget->style, gtk2_black_pixmap, - state_type, NULL, gtk2_widget, detail, - x + width / 2, y + height / 2, expander_style); -} - -static void gtk2_paint_extension(WidgetType widget_type, GtkStateType state_type, - GtkShadowType shadow_type, const gchar *detail, - gint x, gint y, gint width, gint height, GtkPositionType gap_side) -{ - gtk2_widget = gtk2_get_widget(widget_type); - (*fp_gtk_paint_extension)(gtk2_widget->style, gtk2_white_pixmap, - state_type, shadow_type, NULL, gtk2_widget, detail, - x, y, width, height, gap_side); - (*fp_gtk_paint_extension)(gtk2_widget->style, gtk2_black_pixmap, - state_type, shadow_type, NULL, gtk2_widget, detail, - x, y, width, height, gap_side); -} - -static void gtk2_paint_flat_box(WidgetType widget_type, GtkStateType state_type, - GtkShadowType shadow_type, const gchar *detail, - gint x, gint y, gint width, gint height, gboolean has_focus) -{ - gtk2_widget = gtk2_get_widget(widget_type); - - if (has_focus) - ((GtkObject*)gtk2_widget)->flags |= GTK_HAS_FOCUS; - else - ((GtkObject*)gtk2_widget)->flags &= ~GTK_HAS_FOCUS; - - (*fp_gtk_paint_flat_box)(gtk2_widget->style, gtk2_white_pixmap, - state_type, shadow_type, NULL, gtk2_widget, detail, - x, y, width, height); - (*fp_gtk_paint_flat_box)(gtk2_widget->style, gtk2_black_pixmap, - state_type, shadow_type, NULL, gtk2_widget, detail, - x, y, width, height); -} - -static void gtk2_paint_focus(WidgetType widget_type, GtkStateType state_type, - const char *detail, gint x, gint y, gint width, gint height) -{ - gtk2_widget = gtk2_get_widget(widget_type); - (*fp_gtk_paint_focus)(gtk2_widget->style, gtk2_white_pixmap, state_type, - NULL, gtk2_widget, detail, x, y, width, height); - (*fp_gtk_paint_focus)(gtk2_widget->style, gtk2_black_pixmap, state_type, - NULL, gtk2_widget, detail, x, y, width, height); -} - -static void gtk2_paint_handle(WidgetType widget_type, GtkStateType state_type, - GtkShadowType shadow_type, const gchar *detail, - gint x, gint y, gint width, gint height, GtkOrientation orientation) -{ - gtk2_widget = gtk2_get_widget(widget_type); - (*fp_gtk_paint_handle)(gtk2_widget->style, gtk2_white_pixmap, state_type, - shadow_type, NULL, gtk2_widget, detail, - x, y, width, height, orientation); - (*fp_gtk_paint_handle)(gtk2_widget->style, gtk2_black_pixmap, state_type, - shadow_type, NULL, gtk2_widget, detail, - x, y, width, height, orientation); -} - -static void gtk2_paint_hline(WidgetType widget_type, GtkStateType state_type, - const gchar *detail, gint x, gint y, gint width, gint height) -{ - gtk2_widget = gtk2_get_widget(widget_type); - (*fp_gtk_paint_hline)(gtk2_widget->style, gtk2_white_pixmap, state_type, - NULL, gtk2_widget, detail, x, x + width, y); - (*fp_gtk_paint_hline)(gtk2_widget->style, gtk2_black_pixmap, state_type, - NULL, gtk2_widget, detail, x, x + width, y); -} - -static void gtk2_paint_option(WidgetType widget_type, gint synth_state, - const gchar *detail, gint x, gint y, gint width, gint height) -{ - GtkStateType state_type = get_gtk_state_type(widget_type, synth_state); - GtkShadowType shadow_type = get_gtk_shadow_type(widget_type, synth_state); - - gtk2_widget = gtk2_get_widget(widget_type); - init_toggle_widget(widget_type, synth_state); - - (*fp_gtk_paint_option)(gtk2_widget->style, gtk2_white_pixmap, state_type, - shadow_type, NULL, gtk2_widget, detail, - x, y, width, height); - (*fp_gtk_paint_option)(gtk2_widget->style, gtk2_black_pixmap, state_type, - shadow_type, NULL, gtk2_widget, detail, - x, y, width, height); -} - -static void gtk2_paint_shadow(WidgetType widget_type, GtkStateType state_type, - GtkShadowType shadow_type, const gchar *detail, - gint x, gint y, gint width, gint height, - gint synth_state, GtkTextDirection dir) -{ - gtk2_widget = gtk2_get_widget(widget_type); - - /* - * The clearlooks engine sometimes looks at the widget's state field - * instead of just the state_type variable that we pass in, so to account - * for those cases we set the widget's state field accordingly. The - * flags field is similarly important for things like focus state. - */ - gtk2_widget->state = state_type; - - /* - * Some engines (e.g. clearlooks) will paint the shadow of certain - * widgets (e.g. COMBO_BOX_TEXT_FIELD) differently depending on the - * the text direction. - */ - gtk2_set_direction(gtk2_widget, dir); - - switch (widget_type) { - case COMBO_BOX_TEXT_FIELD: - case FORMATTED_TEXT_FIELD: - case PASSWORD_FIELD: - case SPINNER_TEXT_FIELD: - case TEXT_FIELD: - if (synth_state & FOCUSED) { - ((GtkObject*)gtk2_widget)->flags |= GTK_HAS_FOCUS; - } else { - ((GtkObject*)gtk2_widget)->flags &= ~GTK_HAS_FOCUS; - } - break; - default: - break; - } - - (*fp_gtk_paint_shadow)(gtk2_widget->style, gtk2_white_pixmap, state_type, - shadow_type, NULL, gtk2_widget, detail, x, y, width, height); - (*fp_gtk_paint_shadow)(gtk2_widget->style, gtk2_black_pixmap, state_type, - shadow_type, NULL, gtk2_widget, detail, x, y, width, height); - - /* - * Reset the text direction to the default value so that we don't - * accidentally affect other operations and widgets. - */ - gtk2_set_direction(gtk2_widget, GTK_TEXT_DIR_LTR); -} - -static void gtk2_paint_slider(WidgetType widget_type, GtkStateType state_type, - GtkShadowType shadow_type, const gchar *detail, - gint x, gint y, gint width, gint height, GtkOrientation orientation, - gboolean has_focus) -{ - gtk2_widget = gtk2_get_widget(widget_type); - (*fp_gtk_paint_slider)(gtk2_widget->style, gtk2_white_pixmap, state_type, - shadow_type, NULL, gtk2_widget, detail, - x, y, width, height, orientation); - (*fp_gtk_paint_slider)(gtk2_widget->style, gtk2_black_pixmap, state_type, - shadow_type, NULL, gtk2_widget, detail, - x, y, width, height, orientation); -} - -static void gtk2_paint_vline(WidgetType widget_type, GtkStateType state_type, - const gchar *detail, gint x, gint y, gint width, gint height) -{ - gtk2_widget = gtk2_get_widget(widget_type); - (*fp_gtk_paint_vline)(gtk2_widget->style, gtk2_white_pixmap, state_type, - NULL, gtk2_widget, detail, y, y + height, x); - (*fp_gtk_paint_vline)(gtk2_widget->style, gtk2_black_pixmap, state_type, - NULL, gtk2_widget, detail, y, y + height, x); -} - -static void gtk_paint_background(WidgetType widget_type, GtkStateType state_type, - gint x, gint y, gint width, gint height) -{ - gtk2_widget = gtk2_get_widget(widget_type); - (*fp_gtk_style_apply_default_background)(gtk2_widget->style, - gtk2_white_pixmap, TRUE, state_type, NULL, x, y, width, height); - (*fp_gtk_style_apply_default_background)(gtk2_widget->style, - gtk2_black_pixmap, TRUE, state_type, NULL, x, y, width, height); -} - -static GdkPixbuf *gtk2_get_stock_icon(gint widget_type, const gchar *stock_id, - GtkIconSize size, GtkTextDirection direction, const char *detail) -{ - init_containers(); - gtk2_widget = gtk2_get_widget((widget_type < 0) ? IMAGE : widget_type); - gtk2_widget->state = GTK_STATE_NORMAL; - (*fp_gtk_widget_set_direction)(gtk2_widget, direction); - return (*fp_gtk_widget_render_icon)(gtk2_widget, stock_id, size, detail); -} - -static jboolean gtk2_get_pixbuf_data(JNIEnv *env, GdkPixbuf* pixbuf, - jmethodID icon_upcall_method, jobject this) { - if (!pixbuf) { - return JNI_FALSE; - } - guchar *pixbuf_data = (*fp_gdk_pixbuf_get_pixels)(pixbuf); - if (pixbuf_data) { - int row_stride = (*fp_gdk_pixbuf_get_rowstride)(pixbuf); - int width = (*fp_gdk_pixbuf_get_width)(pixbuf); - int height = (*fp_gdk_pixbuf_get_height)(pixbuf); - int bps = (*fp_gdk_pixbuf_get_bits_per_sample)(pixbuf); - int channels = (*fp_gdk_pixbuf_get_n_channels)(pixbuf); - gboolean alpha = (*fp_gdk_pixbuf_get_has_alpha)(pixbuf); - - jbyteArray data = (*env)->NewByteArray(env, (row_stride * height)); - JNU_CHECK_EXCEPTION_RETURN(env, JNI_FALSE); - - (*env)->SetByteArrayRegion(env, data, 0, (row_stride * height), - (jbyte *)pixbuf_data); - (*fp_g_object_unref)(pixbuf); - - /* Call the callback method to create the image on the Java side. */ - (*env)->CallVoidMethod(env, this, icon_upcall_method, data, - width, height, row_stride, bps, channels, alpha); - return JNI_TRUE; - } - return JNI_FALSE; -} - -static jboolean gtk2_get_file_icon_data(JNIEnv *env, const char *filename, - GError **error, jmethodID icon_upcall_method, jobject this) { - GdkPixbuf* pixbuf = fp_gdk_pixbuf_new_from_file(filename, error); - return gtk2_get_pixbuf_data(env, pixbuf, icon_upcall_method, this); -} - -static jboolean gtk2_get_icon_data(JNIEnv *env, gint widget_type, - const gchar *stock_id, GtkIconSize size, - GtkTextDirection direction, const char *detail, - jmethodID icon_upcall_method, jobject this) { - GdkPixbuf* pixbuf = gtk2_get_stock_icon(widget_type, stock_id, size, - direction, detail); - return gtk2_get_pixbuf_data(env, pixbuf, icon_upcall_method, this); -} - -/*************************************************/ -static gint gtk2_get_xthickness(JNIEnv *env, WidgetType widget_type) -{ - init_containers(); - - gtk2_widget = gtk2_get_widget(widget_type); - GtkStyle* style = gtk2_widget->style; - return style->xthickness; -} - -static gint gtk2_get_ythickness(JNIEnv *env, WidgetType widget_type) -{ - init_containers(); - - gtk2_widget = gtk2_get_widget(widget_type); - GtkStyle* style = gtk2_widget->style; - return style->ythickness; -} - -/*************************************************/ -static guint8 recode_color(guint16 channel) -{ - return (guint8)(channel>>8); -} - -static gint gtk2_get_color_for_state(JNIEnv *env, WidgetType widget_type, - GtkStateType state_type, ColorType color_type) -{ - gint result = 0; - GdkColor *color = NULL; - - init_containers(); - - gtk2_widget = gtk2_get_widget(widget_type); - GtkStyle* style = gtk2_widget->style; - - switch (color_type) - { - case FOREGROUND: - color = &(style->fg[state_type]); - break; - case BACKGROUND: - color = &(style->bg[state_type]); - break; - case TEXT_FOREGROUND: - color = &(style->text[state_type]); - break; - case TEXT_BACKGROUND: - color = &(style->base[state_type]); - break; - case LIGHT: - color = &(style->light[state_type]); - break; - case DARK: - color = &(style->dark[state_type]); - break; - case MID: - color = &(style->mid[state_type]); - break; - case FOCUS: - case BLACK: - color = &(style->black); - break; - case WHITE: - color = &(style->white); - break; - } - - if (color) - result = recode_color(color->red) << 16 | - recode_color(color->green) << 8 | - recode_color(color->blue); - - return result; -} - -/*************************************************/ -static jobject create_Boolean(JNIEnv *env, jboolean boolean_value); -static jobject create_Integer(JNIEnv *env, jint int_value); -static jobject create_Long(JNIEnv *env, jlong long_value); -static jobject create_Float(JNIEnv *env, jfloat float_value); -static jobject create_Double(JNIEnv *env, jdouble double_value); -static jobject create_Character(JNIEnv *env, jchar char_value); -static jobject create_Insets(JNIEnv *env, GtkBorder *border); - -static jobject gtk2_get_class_value(JNIEnv *env, WidgetType widget_type, - const char* key) -{ - init_containers(); - - gtk2_widget = gtk2_get_widget(widget_type); - - GValue value; - value.g_type = 0; - - GParamSpec* param = (*fp_gtk_widget_class_find_style_property)( - ((GTypeInstance*)gtk2_widget)->g_class, key); - if( param ) - { - (*fp_g_value_init)( &value, param->value_type ); - (*fp_gtk_widget_style_get_property)(gtk2_widget, key, &value); - - if( (*fp_g_type_is_a)( param->value_type, G_TYPE_BOOLEAN )) - { - gboolean val = (*fp_g_value_get_boolean)(&value); - return create_Boolean(env, (jboolean)val); - } - else if( (*fp_g_type_is_a)( param->value_type, G_TYPE_CHAR )) - { - gchar val = (*fp_g_value_get_char)(&value); - return create_Character(env, (jchar)val); - } - else if( (*fp_g_type_is_a)( param->value_type, G_TYPE_UCHAR )) - { - guchar val = (*fp_g_value_get_uchar)(&value); - return create_Character(env, (jchar)val); - } - else if( (*fp_g_type_is_a)( param->value_type, G_TYPE_INT )) - { - gint val = (*fp_g_value_get_int)(&value); - return create_Integer(env, (jint)val); - } - else if( (*fp_g_type_is_a)( param->value_type, G_TYPE_UINT )) - { - guint val = (*fp_g_value_get_uint)(&value); - return create_Integer(env, (jint)val); - } - else if( (*fp_g_type_is_a)( param->value_type, G_TYPE_LONG )) - { - glong val = (*fp_g_value_get_long)(&value); - return create_Long(env, (jlong)val); - } - else if( (*fp_g_type_is_a)( param->value_type, G_TYPE_ULONG )) - { - gulong val = (*fp_g_value_get_ulong)(&value); - return create_Long(env, (jlong)val); - } - else if( (*fp_g_type_is_a)( param->value_type, G_TYPE_INT64 )) - { - gint64 val = (*fp_g_value_get_int64)(&value); - return create_Long(env, (jlong)val); - } - else if( (*fp_g_type_is_a)( param->value_type, G_TYPE_UINT64 )) - { - guint64 val = (*fp_g_value_get_uint64)(&value); - return create_Long(env, (jlong)val); - } - else if( (*fp_g_type_is_a)( param->value_type, G_TYPE_FLOAT )) - { - gfloat val = (*fp_g_value_get_float)(&value); - return create_Float(env, (jfloat)val); - } - else if( (*fp_g_type_is_a)( param->value_type, G_TYPE_DOUBLE )) - { - gdouble val = (*fp_g_value_get_double)(&value); - return create_Double(env, (jdouble)val); - } - else if( (*fp_g_type_is_a)( param->value_type, G_TYPE_ENUM )) - { - gint val = (*fp_g_value_get_enum)(&value); - return create_Integer(env, (jint)val); - } - else if( (*fp_g_type_is_a)( param->value_type, G_TYPE_FLAGS )) - { - guint val = (*fp_g_value_get_flags)(&value); - return create_Integer(env, (jint)val); - } - else if( (*fp_g_type_is_a)( param->value_type, G_TYPE_STRING )) - { - const gchar* val = (*fp_g_value_get_string)(&value); - - /* We suppose that all values come in C locale and - * utf-8 representation of a string is the same as - * the string itself. If this isn't so we should - * use g_convert. - */ - return (*env)->NewStringUTF(env, val); - } - else if( (*fp_g_type_is_a)( param->value_type, GTK_TYPE_BORDER )) - { - GtkBorder *border = (GtkBorder*)(*fp_g_value_get_boxed)(&value); - return border ? create_Insets(env, border) : NULL; - } - - /* TODO: Other types are not supported yet.*/ -/* else if( (*fp_g_type_is_a)( param->value_type, G_TYPE_PARAM )) - { - GParamSpec* val = (*fp_g_value_get_param)(&value); - printf( "Param: %p\n", val ); - } - else if( (*fp_g_type_is_a)( param->value_type, G_TYPE_BOXED )) - { - gpointer* val = (*fp_g_value_get_boxed)(&value); - printf( "Boxed: %p\n", val ); - } - else if( (*fp_g_type_is_a)( param->value_type, G_TYPE_POINTER )) - { - gpointer* val = (*fp_g_value_get_pointer)(&value); - printf( "Pointer: %p\n", val ); - } - else if( (*fp_g_type_is_a)( param->value_type, G_TYPE_OBJECT )) - { - GObject* val = (GObject*)(*fp_g_value_get_object)(&value); - printf( "Object: %p\n", val ); - }*/ - } - - return NULL; -} - -static void gtk2_set_range_value(WidgetType widget_type, jdouble value, - jdouble min, jdouble max, jdouble visible) -{ - GtkAdjustment *adj; - - gtk2_widget = gtk2_get_widget(widget_type); - - adj = (*fp_gtk_range_get_adjustment)((GtkRange *)gtk2_widget); - adj->value = (gdouble)value; - adj->lower = (gdouble)min; - adj->upper = (gdouble)max; - adj->page_size = (gdouble)visible; -} - -/*************************************************/ -static jobject create_Object(JNIEnv *env, jmethodID *cid, - const char* class_name, - const char* signature, - jvalue* value) -{ - jclass class; - jobject result; - - class = (*env)->FindClass(env, class_name); - if( class == NULL ) - return NULL; /* can't find/load the class, exception thrown */ - - if( *cid == NULL) - { - *cid = (*env)->GetMethodID(env, class, "", signature); - if( *cid == NULL ) - { - (*env)->DeleteLocalRef(env, class); - return NULL; /* can't find/get the method, exception thrown */ - } - } - - result = (*env)->NewObjectA(env, class, *cid, value); - - (*env)->DeleteLocalRef(env, class); - return result; -} - -jobject create_Boolean(JNIEnv *env, jboolean boolean_value) -{ - static jmethodID cid = NULL; - jvalue value; - - value.z = boolean_value; - - return create_Object(env, &cid, "java/lang/Boolean", "(Z)V", &value); -} - -jobject create_Integer(JNIEnv *env, jint int_value) -{ - static jmethodID cid = NULL; - jvalue value; - - value.i = int_value; - - return create_Object(env, &cid, "java/lang/Integer", "(I)V", &value); -} - -jobject create_Long(JNIEnv *env, jlong long_value) -{ - static jmethodID cid = NULL; - jvalue value; - - value.j = long_value; - - return create_Object(env, &cid, "java/lang/Long", "(J)V", &value); -} - -jobject create_Float(JNIEnv *env, jfloat float_value) -{ - static jmethodID cid = NULL; - jvalue value; - - value.f = float_value; - - return create_Object(env, &cid, "java/lang/Float", "(F)V", &value); -} - -jobject create_Double(JNIEnv *env, jdouble double_value) -{ - static jmethodID cid = NULL; - jvalue value; - - value.d = double_value; - - return create_Object(env, &cid, "java/lang/Double", "(D)V", &value); -} - -jobject create_Character(JNIEnv *env, jchar char_value) -{ - static jmethodID cid = NULL; - jvalue value; - - value.c = char_value; - - return create_Object(env, &cid, "java/lang/Character", "(C)V", &value); -} - - -jobject create_Insets(JNIEnv *env, GtkBorder *border) -{ - static jmethodID cid = NULL; - jvalue values[4]; - - values[0].i = border->top; - values[1].i = border->left; - values[2].i = border->bottom; - values[3].i = border->right; - - return create_Object(env, &cid, "java/awt/Insets", "(IIII)V", values); -} - -/*********************************************/ -static jstring gtk2_get_pango_font_name(JNIEnv *env, WidgetType widget_type) -{ - init_containers(); - - gtk2_widget = gtk2_get_widget(widget_type); - jstring result = NULL; - GtkStyle* style = gtk2_widget->style; - - if (style && style->font_desc) - { - gchar* val = (*fp_pango_font_description_to_string)(style->font_desc); - result = (*env)->NewStringUTF(env, val); - (*fp_g_free)( val ); - } - - return result; -} - -/***********************************************/ -static jobject get_string_property(JNIEnv *env, GtkSettings* settings, const gchar* key) -{ - jobject result = NULL; - gchar* strval = NULL; - - (*fp_g_object_get)(settings, key, &strval, NULL); - result = (*env)->NewStringUTF(env, strval); - (*fp_g_free)(strval); - - return result; -} - -static jobject get_integer_property(JNIEnv *env, GtkSettings* settings, const gchar* key) -{ - gint intval = 0; - (*fp_g_object_get)(settings, key, &intval, NULL); - return create_Integer(env, intval); -} - -static jobject get_boolean_property(JNIEnv *env, GtkSettings* settings, const gchar* key) -{ - gint intval = 0; - (*fp_g_object_get)(settings, key, &intval, NULL); - return create_Boolean(env, intval); -} - -static jobject gtk2_get_setting(JNIEnv *env, Setting property) -{ - GtkSettings* settings = (*fp_gtk_settings_get_default)(); - - switch (property) - { - case GTK_FONT_NAME: - return get_string_property(env, settings, "gtk-font-name"); - case GTK_ICON_SIZES: - return get_string_property(env, settings, "gtk-icon-sizes"); - case GTK_CURSOR_BLINK: - return get_boolean_property(env, settings, "gtk-cursor-blink"); - case GTK_CURSOR_BLINK_TIME: - return get_integer_property(env, settings, "gtk-cursor-blink-time"); - } - - return NULL; -} - -static gboolean gtk2_get_drawable_data(JNIEnv *env, jintArray pixelArray, jint x, - jint y, jint width, jint height, jint jwidth, int dx, int dy) { - GdkPixbuf *pixbuf; - jint *ary; - - GdkWindow *root = (*fp_gdk_get_default_root_window)(); - - pixbuf = (*fp_gdk_pixbuf_get_from_drawable)(NULL, root, NULL, x, y, - 0, 0, width, height); - - if (pixbuf) { - int nchan = (*fp_gdk_pixbuf_get_n_channels)(pixbuf); - int stride = (*fp_gdk_pixbuf_get_rowstride)(pixbuf); - - if ((*fp_gdk_pixbuf_get_width)(pixbuf) == width - && (*fp_gdk_pixbuf_get_height)(pixbuf) == height - && (*fp_gdk_pixbuf_get_bits_per_sample)(pixbuf) == 8 - && (*fp_gdk_pixbuf_get_colorspace)(pixbuf) == GDK_COLORSPACE_RGB - && nchan >= 3 - ) { - guchar *p, *pix = (*fp_gdk_pixbuf_get_pixels)(pixbuf); - - ary = (*env)->GetPrimitiveArrayCritical(env, pixelArray, NULL); - if (ary) { - jint _x, _y; - int index; - for (_y = 0; _y < height; _y++) { - for (_x = 0; _x < width; _x++) { - p = pix + (intptr_t) _y * stride + _x * nchan; - - index = (_y + dy) * jwidth + (_x + dx); - ary[index] = 0xff000000 - | (p[0] << 16) - | (p[1] << 8) - | (p[2]); - - } - } - (*env)->ReleasePrimitiveArrayCritical(env, pixelArray, ary, 0); - } - } - (*fp_g_object_unref)(pixbuf); - } - return JNI_FALSE; -} - -static GdkWindow* gtk2_get_window(void *widget) { - return ((GtkWidget*)widget)->window; -} - -void gtk2_init(GtkApi* gtk) { - gtk->version = GTK_2; - - gtk->show_uri_load = >k2_show_uri_load; - gtk->unload = >k2_unload; - gtk->flush_event_loop = &flush_gtk_event_loop; - gtk->gtk_check_version = fp_gtk_check_version; - gtk->get_setting = >k2_get_setting; - - gtk->paint_arrow = >k2_paint_arrow; - gtk->paint_box = >k2_paint_box; - gtk->paint_box_gap = >k2_paint_box_gap; - gtk->paint_expander = >k2_paint_expander; - gtk->paint_extension = >k2_paint_extension; - gtk->paint_flat_box = >k2_paint_flat_box; - gtk->paint_focus = >k2_paint_focus; - gtk->paint_handle = >k2_paint_handle; - gtk->paint_hline = >k2_paint_hline; - gtk->paint_vline = >k2_paint_vline; - gtk->paint_option = >k2_paint_option; - gtk->paint_shadow = >k2_paint_shadow; - gtk->paint_slider = >k2_paint_slider; - gtk->paint_background = >k_paint_background; - gtk->paint_check = >k2_paint_check; - gtk->set_range_value = >k2_set_range_value; - - gtk->init_painting = >k2_init_painting; - gtk->copy_image = >k2_copy_image; - - gtk->get_xthickness = >k2_get_xthickness; - gtk->get_ythickness = >k2_get_ythickness; - gtk->get_color_for_state = >k2_get_color_for_state; - gtk->get_class_value = >k2_get_class_value; - - gtk->get_pango_font_name = >k2_get_pango_font_name; - gtk->get_icon_data = >k2_get_icon_data; - gtk->get_file_icon_data = >k2_get_file_icon_data; - gtk->gdk_threads_enter = fp_gdk_threads_enter; - gtk->gdk_threads_leave = fp_gdk_threads_leave; - gtk->gtk_show_uri = fp_gtk_show_uri; - gtk->get_drawable_data = >k2_get_drawable_data; - gtk->g_free = fp_g_free; - - gtk->gtk_file_chooser_get_filename = fp_gtk_file_chooser_get_filename; - gtk->gtk_widget_hide = fp_gtk_widget_hide; - gtk->gtk_main_quit = fp_gtk_main_quit; - gtk->gtk_file_chooser_dialog_new = fp_gtk_file_chooser_dialog_new; - gtk->gtk_file_chooser_set_current_folder = - fp_gtk_file_chooser_set_current_folder; - gtk->gtk_file_chooser_set_filename = fp_gtk_file_chooser_set_filename; - gtk->gtk_file_chooser_set_current_name = - fp_gtk_file_chooser_set_current_name; - gtk->gtk_file_filter_add_custom = fp_gtk_file_filter_add_custom; - gtk->gtk_file_chooser_set_filter = fp_gtk_file_chooser_set_filter; - gtk->gtk_file_chooser_get_type = fp_gtk_file_chooser_get_type; - gtk->gtk_file_filter_new = fp_gtk_file_filter_new; - gtk->gtk_file_chooser_set_do_overwrite_confirmation = - fp_gtk_file_chooser_set_do_overwrite_confirmation; - gtk->gtk_file_chooser_set_select_multiple = - fp_gtk_file_chooser_set_select_multiple; - gtk->gtk_file_chooser_get_current_folder = - fp_gtk_file_chooser_get_current_folder; - gtk->gtk_file_chooser_get_filenames = fp_gtk_file_chooser_get_filenames; - gtk->gtk_g_slist_length = fp_gtk_g_slist_length; - gtk->g_signal_connect_data = fp_g_signal_connect_data; - gtk->gtk_widget_show = fp_gtk_widget_show; - gtk->gtk_main = fp_gtk_main; - gtk->gtk_main_level = fp_gtk_main_level; - gtk->g_path_get_dirname = fp_g_path_get_dirname; - gtk->gdk_x11_drawable_get_xid = fp_gdk_x11_drawable_get_xid; - gtk->gtk_widget_destroy = fp_gtk_widget_destroy; - gtk->gtk_window_present = fp_gtk_window_present; - gtk->gtk_window_move = fp_gtk_window_move; - gtk->gtk_window_resize = fp_gtk_window_resize; - gtk->get_window = >k2_get_window; - - gtk->g_object_unref = fp_g_object_unref; - gtk->g_list_append = fp_g_list_append; - gtk->g_list_free = fp_g_list_free; - gtk->g_list_free_full = fp_g_list_free_full; -} diff --git a/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.h b/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.h deleted file mode 100644 index 8075d4f419fad..0000000000000 --- a/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.h +++ /dev/null @@ -1,448 +0,0 @@ -/* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * 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. - */ - -#ifdef HEADLESS - #error This file should not be included in headless library -#endif - -#ifndef _GTK2_INTERFACE_H -#define _GTK2_INTERFACE_H - -#include -#include -#include -#include "gtk_interface.h" - -#define GTK_HAS_FOCUS (1 << 12) -#define GTK_HAS_DEFAULT (1 << 14) - -typedef enum -{ - GTK_WINDOW_TOPLEVEL, - GTK_WINDOW_POPUP -} GtkWindowType; - -typedef enum -{ - G_PARAM_READABLE = 1 << 0, - G_PARAM_WRITABLE = 1 << 1, - G_PARAM_CONSTRUCT = 1 << 2, - G_PARAM_CONSTRUCT_ONLY = 1 << 3, - G_PARAM_LAX_VALIDATION = 1 << 4, - G_PARAM_PRIVATE = 1 << 5 -} GParamFlags; - -/* We define all structure pointers to be void* */ -typedef void GVfs; - -typedef void GdkColormap; -typedef void GdkDrawable; -typedef void GdkGC; -typedef void GdkPixmap; - -typedef void GtkFixed; -typedef void GtkMenuItem; -typedef void GtkMenuShell; -typedef void GtkWidgetClass; -typedef void PangoFontDescription; -typedef void GtkSettings; - -/* Some real structures */ -typedef struct -{ - guint32 pixel; - guint16 red; - guint16 green; - guint16 blue; -} GdkColor; - -typedef struct { - gint fd; - gushort events; - gushort revents; -} GPollFD; - -typedef struct { - gint x; - gint y; - gint width; - gint height; -} GtkAllocation; - -typedef struct { - gint width; - gint height; -} GtkRequisition; - -typedef struct { - GtkWidgetClass *g_class; -} GTypeInstance; - -typedef struct { - gint left; - gint right; - gint top; - gint bottom; -} GtkBorder; - -/****************************************************** - * FIXME: it is more safe to include gtk headers for - * the precise type definition of GType and other - * structures. This is a place where getting rid of gtk - * headers may be dangerous. - ******************************************************/ - -typedef struct -{ - GType g_type; - - union { - gint v_int; - guint v_uint; - glong v_long; - gulong v_ulong; - gint64 v_int64; - guint64 v_uint64; - gfloat v_float; - gdouble v_double; - gpointer v_pointer; - } data[2]; -} GValue; - -typedef struct -{ - GTypeInstance g_type_instance; - - gchar *name; - GParamFlags flags; - GType value_type; - GType owner_type; -} GParamSpec; - -typedef struct { - GTypeInstance g_type_instance; - guint ref_count; - void *qdata; -} GObject; - -typedef struct { - GObject parent_instance; - guint32 flags; -} GtkObject; - -typedef struct -{ - GObject parent_instance; - - GdkColor fg[5]; - GdkColor bg[5]; - GdkColor light[5]; - GdkColor dark[5]; - GdkColor mid[5]; - GdkColor text[5]; - GdkColor base[5]; - GdkColor text_aa[5]; /* Halfway between text/base */ - - GdkColor black; - GdkColor white; - PangoFontDescription *font_desc; - - gint xthickness; - gint ythickness; - - GdkGC *fg_gc[5]; - GdkGC *bg_gc[5]; - GdkGC *light_gc[5]; - GdkGC *dark_gc[5]; - GdkGC *mid_gc[5]; - GdkGC *text_gc[5]; - GdkGC *base_gc[5]; - GdkGC *text_aa_gc[5]; - GdkGC *black_gc; - GdkGC *white_gc; - - GdkPixmap *bg_pixmap[5]; -} GtkStyle; - -typedef struct _GtkWidget GtkWidget; -struct _GtkWidget -{ - GtkObject object; - guint16 private_flags; - guint8 state; - guint8 saved_state; - gchar *name; - GtkStyle *style; - GtkRequisition requisition; - GtkAllocation allocation; - GdkWindow *window; - GtkWidget *parent; -}; - -typedef struct -{ - GtkWidget widget; - - gfloat xalign; - gfloat yalign; - - guint16 xpad; - guint16 ypad; -} GtkMisc; - -typedef struct { - GtkWidget widget; - GtkWidget *focus_child; - guint border_width : 16; - guint need_resize : 1; - guint resize_mode : 2; - guint reallocate_redraws : 1; - guint has_focus_chain : 1; -} GtkContainer; - -typedef struct { - GtkContainer container; - GtkWidget *child; -} GtkBin; - -typedef struct { - GtkBin bin; - GdkWindow *event_window; - gchar *label_text; - guint activate_timeout; - guint constructed : 1; - guint in_button : 1; - guint button_down : 1; - guint relief : 2; - guint use_underline : 1; - guint use_stock : 1; - guint depressed : 1; - guint depress_on_activate : 1; - guint focus_on_click : 1; -} GtkButton; - -typedef struct { - GtkButton button; - guint active : 1; - guint draw_indicator : 1; - guint inconsistent : 1; -} GtkToggleButton; - -typedef struct _GtkAdjustment GtkAdjustment; -struct _GtkAdjustment -{ - GtkObject parent_instance; - - gdouble lower; - gdouble upper; - gdouble value; - gdouble step_increment; - gdouble page_increment; - gdouble page_size; -}; - -typedef enum -{ - GTK_UPDATE_CONTINUOUS, - GTK_UPDATE_DISCONTINUOUS, - GTK_UPDATE_DELAYED -} GtkUpdateType; - -typedef struct _GtkRange GtkRange; -struct _GtkRange -{ - GtkWidget widget; - GtkAdjustment *adjustment; - GtkUpdateType update_policy; - guint inverted : 1; - /*< protected >*/ - guint flippable : 1; - guint has_stepper_a : 1; - guint has_stepper_b : 1; - guint has_stepper_c : 1; - guint has_stepper_d : 1; - guint need_recalc : 1; - guint slider_size_fixed : 1; - gint min_slider_size; - GtkOrientation orientation; - GdkRectangle range_rect; - gint slider_start, slider_end; - gint round_digits; - /*< private >*/ - guint trough_click_forward : 1; - guint update_pending : 1; - /*GtkRangeLayout * */ void *layout; - /*GtkRangeStepTimer * */ void* timer; - gint slide_initial_slider_position; - gint slide_initial_coordinate; - guint update_timeout_id; - GdkWindow *event_window; -}; - -typedef struct _GtkProgressBar GtkProgressBar; - -typedef enum -{ - GTK_PROGRESS_CONTINUOUS, - GTK_PROGRESS_DISCRETE -} GtkProgressBarStyle; - -typedef enum -{ - GTK_PROGRESS_LEFT_TO_RIGHT, - GTK_PROGRESS_RIGHT_TO_LEFT, - GTK_PROGRESS_BOTTOM_TO_TOP, - GTK_PROGRESS_TOP_TO_BOTTOM -} GtkProgressBarOrientation; - -typedef struct _GtkProgress GtkProgress; - -struct _GtkProgress -{ - GtkWidget widget; - GtkAdjustment *adjustment; - GdkPixmap *offscreen_pixmap; - gchar *format; - gfloat x_align; - gfloat y_align; - guint show_text : 1; - guint activity_mode : 1; - guint use_text_format : 1; -}; - -struct _GtkProgressBar -{ - GtkProgress progress; - GtkProgressBarStyle bar_style; - GtkProgressBarOrientation orientation; - guint blocks; - gint in_block; - gint activity_pos; - guint activity_step; - guint activity_blocks; - gdouble pulse_fraction; - guint activity_dir : 1; - guint ellipsize : 3; -}; - -/** - * Returns : - * NULL if the GLib library is compatible with the given version, or a string - * describing the version mismatch. - * Please note that the glib_check_version() is available since 2.6, - * so you should use GLIB_CHECK_VERSION macro instead. - */ -static gchar* (*fp_glib_check_version)(guint required_major, guint required_minor, - guint required_micro); - -/** - * Returns : - * TRUE if the GLib library is compatible with the given version - */ -#define GLIB_CHECK_VERSION(major, minor, micro) \ - (fp_glib_check_version && fp_glib_check_version(major, minor, micro) == NULL) - -/** - * Returns : - * NULL if the GTK+ library is compatible with the given version, or a string - * describing the version mismatch. - */ -static gchar* (*fp_gtk_check_version)(guint required_major, guint required_minor, - guint required_micro); - -static void gtk2_init(GtkApi* gtk); - -static void (*fp_g_free)(gpointer mem); -static void (*fp_g_object_unref)(gpointer object); -static GdkWindow *(*fp_gdk_get_default_root_window) (void); - -static int (*fp_gdk_pixbuf_get_bits_per_sample)(const GdkPixbuf *pixbuf); -static guchar *(*fp_gdk_pixbuf_get_pixels)(const GdkPixbuf *pixbuf); -static gboolean (*fp_gdk_pixbuf_get_has_alpha)(const GdkPixbuf *pixbuf); -static int (*fp_gdk_pixbuf_get_height)(const GdkPixbuf *pixbuf); -static int (*fp_gdk_pixbuf_get_n_channels)(const GdkPixbuf *pixbuf); -static int (*fp_gdk_pixbuf_get_rowstride)(const GdkPixbuf *pixbuf); -static int (*fp_gdk_pixbuf_get_width)(const GdkPixbuf *pixbuf); -static GdkPixbuf *(*fp_gdk_pixbuf_new_from_file)(const char *filename, GError **error); -static GdkColorspace (*fp_gdk_pixbuf_get_colorspace)(const GdkPixbuf *pixbuf); - -static GdkPixbuf *(*fp_gdk_pixbuf_get_from_drawable)(GdkPixbuf *dest, - GdkDrawable *src, GdkColormap *cmap, int src_x, int src_y, - int dest_x, int dest_y, int width, int height); -static GdkPixbuf *(*fp_gdk_pixbuf_scale_simple)(GdkPixbuf *src, - int dest_width, int dest_heigh, GdkInterpType interp_type); - - -static void (*fp_gtk_widget_destroy)(void *widget); -static void (*fp_gtk_window_present)(GtkWindow *window); -static void (*fp_gtk_window_move)(GtkWindow *window, gint x, gint y); -static void (*fp_gtk_window_resize)(GtkWindow *window, gint width, gint height); - -/** - * Function Pointers for GtkFileChooser - */ -static gchar* (*fp_gtk_file_chooser_get_filename)(GtkFileChooser *chooser); -static void (*fp_gtk_widget_hide)(void *widget); -static void (*fp_gtk_main_quit)(void); -static void* (*fp_gtk_file_chooser_dialog_new)(const gchar *title, - GtkWindow *parent, GtkFileChooserAction action, - const gchar *first_button_text, ...); -static gboolean (*fp_gtk_file_chooser_set_current_folder)(GtkFileChooser *chooser, - const gchar *filename); -static gboolean (*fp_gtk_file_chooser_set_filename)(GtkFileChooser *chooser, - const char *filename); -static void (*fp_gtk_file_chooser_set_current_name)(GtkFileChooser *chooser, - const gchar *name); -static void (*fp_gtk_file_filter_add_custom)(GtkFileFilter *filter, - GtkFileFilterFlags needed, GtkFileFilterFunc func, gpointer data, - GDestroyNotify notify); -static void (*fp_gtk_file_chooser_set_filter)(GtkFileChooser *chooser, - GtkFileFilter *filter); -static GType (*fp_gtk_file_chooser_get_type)(void); -static GtkFileFilter* (*fp_gtk_file_filter_new)(void); -static void (*fp_gtk_file_chooser_set_do_overwrite_confirmation)( - GtkFileChooser *chooser, gboolean do_overwrite_confirmation); -static void (*fp_gtk_file_chooser_set_select_multiple)( - GtkFileChooser *chooser, gboolean select_multiple); -static gchar* (*fp_gtk_file_chooser_get_current_folder)(GtkFileChooser *chooser); -static GSList* (*fp_gtk_file_chooser_get_filenames)(GtkFileChooser *chooser); -static guint (*fp_gtk_g_slist_length)(GSList *list); -static gulong (*fp_g_signal_connect_data)(gpointer instance, - const gchar *detailed_signal, GCallback c_handler, gpointer data, - GClosureNotify destroy_data, GConnectFlags connect_flags); -static void (*fp_gtk_widget_show)(void *widget); -static void (*fp_gtk_main)(void); -static guint (*fp_gtk_main_level)(void); -static gchar* (*fp_g_path_get_dirname) (const gchar *file_name); -static XID (*fp_gdk_x11_drawable_get_xid) (GdkWindow *drawable); - -static GList* (*fp_g_list_append) (GList *list, gpointer data); -static void (*fp_g_list_free) (GList *list); -static void (*fp_g_list_free_full) (GList *list, GDestroyNotify free_func); - -static gboolean (*fp_gtk_show_uri)(GdkScreen *screen, const gchar *uri, - guint32 timestamp, GError **error); - -#endif /* !_GTK2_INTERFACE_H */ diff --git a/src/java.desktop/unix/native/libawt_xawt/awt/gtk_interface.c b/src/java.desktop/unix/native/libawt_xawt/awt/gtk_interface.c index c8573ed3fbfb9..fcf84948c66ee 100644 --- a/src/java.desktop/unix/native/libawt_xawt/awt/gtk_interface.c +++ b/src/java.desktop/unix/native/libawt_xawt/awt/gtk_interface.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,10 +32,8 @@ #include "jvm_md.h" #include "gtk_interface.h" -GtkApi* gtk2_load(JNIEnv *env, const char* lib_name); GtkApi* gtk3_load(JNIEnv *env, const char* lib_name); -gboolean gtk2_check(const char* lib_name, gboolean load); gboolean gtk3_check(const char* lib_name, gboolean load); GtkApi *gtk; @@ -56,13 +54,6 @@ static GtkLib gtk_libs[] = { >k3_load, >k3_check }, - { - GTK_2, - JNI_LIB_NAME("gtk-x11-2.0"), - VERSIONED_JNI_LIB_NAME("gtk-x11-2.0", "0"), - >k2_load, - >k2_check - } }; static GtkLib** get_libs_order(GtkVersion version) { diff --git a/src/java.desktop/unix/native/libawt_xawt/awt/screencast_pipewire.c b/src/java.desktop/unix/native/libawt_xawt/awt/screencast_pipewire.c index e2f4ea31d2edb..6884b939ae727 100644 --- a/src/java.desktop/unix/native/libawt_xawt/awt/screencast_pipewire.c +++ b/src/java.desktop/unix/native/libawt_xawt/awt/screencast_pipewire.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -675,7 +675,6 @@ static gboolean isAllDataReady() { static void *pipewire_libhandle = NULL; -//glib_version_2_68 false for gtk2, as it comes from gtk3_interface.c extern gboolean glib_version_2_68; diff --git a/test/jdk/java/awt/Gtk/GtkVersionTest/GtkVersionTest.java b/test/jdk/java/awt/Gtk/GtkVersionTest/GtkVersionTest.java index d2e460d4a1637..3d530178a8afc 100644 --- a/test/jdk/java/awt/Gtk/GtkVersionTest/GtkVersionTest.java +++ b/test/jdk/java/awt/Gtk/GtkVersionTest/GtkVersionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,8 +45,9 @@ public static void main(String[] args) { public static void main(String[] args) throws Exception { test(null, "3"); - test("2", "2"); - test("2.2", "2"); +// GTK 2 is removed, but the test can still be useful. +// test("2", "2"); +// test("2.2", "2"); test("3", "3"); } diff --git a/test/jdk/java/awt/Robot/HiDPIScreenCapture/ScreenCaptureGtkTest.java b/test/jdk/java/awt/Robot/HiDPIScreenCapture/ScreenCaptureGtkTest.java index 1f6298a2a612f..155933404e8c5 100644 --- a/test/jdk/java/awt/Robot/HiDPIScreenCapture/ScreenCaptureGtkTest.java +++ b/test/jdk/java/awt/Robot/HiDPIScreenCapture/ScreenCaptureGtkTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2022, JetBrains s.r.o.. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -41,10 +41,9 @@ * @test * @key headful * @bug 8280861 - * @summary Verifies Robot screen capture capabilities with different + * @summary Verifies Robot screen capture capabilities with available * Gtk backends and presence of UI scaling * @requires os.family == "linux" - * @run main/othervm -Djdk.gtk.version=2 -Dsun.java2d.uiScale=1 ScreenCaptureGtkTest * @run main/othervm -Djdk.gtk.version=3 -Dsun.java2d.uiScale=1 ScreenCaptureGtkTest */ @@ -53,12 +52,6 @@ public class ScreenCaptureGtkTest { Color.GREEN, Color.BLUE, Color.ORANGE, Color.RED}; public static void main(String[] args) throws Exception { - if ("2".equals(System.getProperty("jdk.gtk.version")) - && System.getenv("WAYLAND_DISPLAY") != null) { - // screen capture is not supported with gtk2 on Wayland - return; - } - final int topOffset = 50; final int leftOffset = 50; diff --git a/test/jdk/javax/swing/LookAndFeel/8145547/DemandGTK.java b/test/jdk/javax/swing/LookAndFeel/8145547/DemandGTK.java index a8d460bc48e0b..906126071ff1d 100644 --- a/test/jdk/javax/swing/LookAndFeel/8145547/DemandGTK.java +++ b/test/jdk/javax/swing/LookAndFeel/8145547/DemandGTK.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,6 @@ @bug 8156121 @key headful @requires os.family == "linux" - @run main/othervm -Djdk.gtk.version=2 DemandGTK @run main/othervm -Djdk.gtk.version=3 DemandGTK */ diff --git a/test/jdk/javax/swing/LookAndFeel/8145547/DemandGTK2.sh b/test/jdk/javax/swing/LookAndFeel/8145547/DemandGTK2.sh deleted file mode 100644 index eddae8748a7d1..0000000000000 --- a/test/jdk/javax/swing/LookAndFeel/8145547/DemandGTK2.sh +++ /dev/null @@ -1,91 +0,0 @@ -#!/bin/ksh -p - -# -# 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 -# 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 Try to force GTK2. We must bail out to GTK3 (if any) if no 2 available. -# -# @key headful -# @bug 8156128 8212903 -# @compile ProvokeGTK.java -# @requires os.family == "linux" -# @run shell/timeout=400 DemandGTK2.sh - -# -# Note that we depend on -# strace in the PATH -# /sbin/ldconfig (which may be not in PATH) -# It is true for OEL 7 and Ubuntu 14, 16 -# but may fail in future. Save tomorrow for tomorrow. -# -# Read DemandGTK2.txt how to prepare GTK2-less machine. -# - -which strace -if [ $? -ne 0 ] -then - echo "Please provide strace: \"which strace\" failed." - exit 1 -fi - -HAVE_2=`/sbin/ldconfig -v 2>/dev/null | grep libgtk-x11-2 | wc -l` -HAVE_3=`/sbin/ldconfig -v 2>/dev/null | grep libgtk-3.so | wc -l` - - -if [ "${HAVE_2}" = "0" ] -then - - if [ "${HAVE_3}" = "0" ] - then - echo "Neither GTK2 nor GTK3 found: system misconfiguration. Exit." - exit 1 - fi - echo "No GTK 2 library found: we should bail out to 3" - strace -o strace.log -fe open,openat ${TESTJAVA}/bin/java -cp ${TESTCLASSPATH} -Djdk.gtk.version=2 ProvokeGTK - EXECRES=$? - grep 'libgtk-3.*=\ *[0-9]*$' strace.log > logg -else - echo "There is GTK 2 library: we should use it" - strace -o strace.log -fe open,openat ${TESTJAVA}/bin/java -cp ${TESTCLASSPATH} -Djdk.gtk.version=2 ProvokeGTK - EXECRES=$? - grep 'libgtk-x11.*=\ *[0-9]*$' strace.log > logg -fi - -if [ ${EXECRES} -ne 0 ] -then - echo "java execution failed for unknown reason, see logs" - exit 2 -fi - -cat logg -if [ -s logg ] -then - echo "Success." - exit 0 -else - echo "Failed. Examine logs." - exit 3 -fi - - diff --git a/test/jdk/javax/swing/LookAndFeel/8145547/DemandGTK2.txt b/test/jdk/javax/swing/LookAndFeel/8145547/DemandGTK2.txt deleted file mode 100644 index 7313e3ee4a754..0000000000000 --- a/test/jdk/javax/swing/LookAndFeel/8145547/DemandGTK2.txt +++ /dev/null @@ -1,36 +0,0 @@ -How to prepare an Ubuntu machine for GTK-2-less test run. - -The test DemandGTK2.sh should work well without GTK-2 switching to version 3 -if there's no GTK-2 library available. -At the moment, it's not easy to find a system with GTK-3 and without GTK-2: -many programs still depend on version 2. -We can, however, rename GTK-2 library for a single test run and then restore -it back. - -(1) Find GTK2 library: run - /sbin/ldconfig -v 2>/dev/null | grep libgtk-x11-2 - -It will output one or two lines like -libgtk-x11-2.0.so.0 -> libgtk-x11-2.0.so.0.2400.23 -Search for the target of that symlink for instance with locate: -locate libgtk-x11-2.0.so.0.2400.23 -Finally, you'll find the libraries. On my current machine they are -/usr/lib/i386-linux-gnu/libgtk-x11-2.0.so.0.2400.23 -/usr/lib/x86_64-linux-gnu/libgtk-x11-2.0.so.0.2400.23 - -I'm running 64-bit JDK and need to tamper with x86_64 copy only. - -(2) Find running programs depending on this library. They probably would crash -if you rename it. Stop them for this test run. -That said, I'm afraid it would be impossible to do on a system older than Ubuntu 16.04. -On my Ubuntu 16.04 I have only hud-service using this library, and that's OK, it will restart -after a crash, if any. -To find these programs, run -lsof /usr/lib/x86_64-linux-gnu/libgtk-x11-2.0.so.0.2400.23 - -(3) Now, -sudo mv /usr/lib/x86_64-linux-gnu/libgtk-x11-2.0.so.0.2400.23 /usr/lib/x86_64-linux-gnu/bak.libgtk-x11-2.0.so.0.2400.23 -jtreg DemandGTK2.sh -sudo mv /usr/lib/x86_64-linux-gnu/bak.libgtk-x11-2.0.so.0.2400.23 /usr/lib/x86_64-linux-gnu/libgtk-x11-2.0.so.0.2400.23 - -Needless to say, you should substitute your own library path and however you run jtreg. diff --git a/test/jdk/javax/swing/LookAndFeel/8145547/DemandGTK3.sh b/test/jdk/javax/swing/LookAndFeel/8145547/DemandGTK3.sh index bb00493c8622f..2383cc828519b 100644 --- a/test/jdk/javax/swing/LookAndFeel/8145547/DemandGTK3.sh +++ b/test/jdk/javax/swing/LookAndFeel/8145547/DemandGTK3.sh @@ -1,7 +1,7 @@ #!/bin/ksh -p # -# Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,7 @@ # @test -# @summary Try to force GTK3. We must bail out to GTK2 if no 3 available. +# @summary Try to force GTK3. # # @key headful # @bug 8156128 8212903 @@ -53,11 +53,8 @@ HAVE_3=`/sbin/ldconfig -v 2>/dev/null | grep libgtk-3.so | wc -l` if [ "${HAVE_3}" = "0" ] then - - echo "No GTK 3 library found: we should bail out to 2" - strace -o strace.log -fe open,openat ${TESTJAVA}/bin/java -cp ${TESTCLASSPATH} -Djdk.gtk.version=3 ProvokeGTK - EXECRES=$? - grep 'libgtk-x11.*=\ *[0-9]*$' strace.log > logg + echo "No GTK 3 library found, do nothing" + exit 0 else echo "There is GTK 3 library: we should use it" strace -o strace.log -fe open,openat ${TESTJAVA}/bin/java -cp ${TESTCLASSPATH} -Djdk.gtk.version=3 ProvokeGTK From ddbd7a78f191462695ecbeeef7fd6312e322b15a Mon Sep 17 00:00:00 2001 From: Alexander Zvegintsev Date: Thu, 8 Aug 2024 10:53:23 +0000 Subject: [PATCH 233/353] 8337320: Update ProblemList.txt with tests known to fail on XWayland Reviewed-by: prr --- test/jdk/ProblemList.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 84c7a7d855f73..3b8421eb9cc77 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -473,6 +473,12 @@ java/awt/image/multiresolution/MultiResolutionJOptionPaneIconTest.java 8274106 m # This test fails on macOS 14 java/awt/Choice/SelectNewItemTest/SelectNewItemTest.java 8324782 macosx-all +# Wayland related + +java/awt/Mouse/EnterExitEvents/ResizingFrameTest.java 8332158 linux-x64 +java/awt/FullScreen/FullscreenWindowProps/FullscreenWindowProps.java 8280991 linux-x64 +java/awt/FullScreen/SetFullScreenTest.java 8332155 linux-x64 + ############################################################################ # jdk_beans From 4b740d87ee50ba49305add4aae6490bebb6963ba Mon Sep 17 00:00:00 2001 From: Erik Gahlin Date: Thu, 8 Aug 2024 10:57:43 +0000 Subject: [PATCH 234/353] 8225209: jdk/jfr/event/compiler/TestCodeSweeper.java fails Reviewed-by: mgronlun --- test/jdk/ProblemList.txt | 1 - .../jfr/event/compiler/TestCodeSweeper.java | 56 +++++++++++++------ 2 files changed, 39 insertions(+), 18 deletions(-) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 3b8421eb9cc77..8aedbc7793116 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -744,7 +744,6 @@ jdk/incubator/vector/LoadJsvmlTest.java 8305390 windows- # jdk_jfr -jdk/jfr/event/compiler/TestCodeSweeper.java 8225209 generic-all jdk/jfr/event/runtime/TestResidentSetSizeEvent.java 8309846 aix-ppc64 jdk/jfr/startupargs/TestStartName.java 8214685 windows-x64 jdk/jfr/startupargs/TestStartDuration.java 8214685 windows-x64 diff --git a/test/jdk/jdk/jfr/event/compiler/TestCodeSweeper.java b/test/jdk/jdk/jfr/event/compiler/TestCodeSweeper.java index cb2a3f41b5582..df95af5b9be0a 100644 --- a/test/jdk/jdk/jfr/event/compiler/TestCodeSweeper.java +++ b/test/jdk/jdk/jfr/event/compiler/TestCodeSweeper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,9 +27,11 @@ import java.lang.reflect.Method; import java.time.Instant; import java.util.ArrayList; +import java.util.Collections; import java.util.List; -import jdk.jfr.Recording; +import jdk.jfr.Event; +import jdk.jfr.consumer.RecordingStream; import jdk.jfr.consumer.RecordedEvent; import jdk.test.lib.Asserts; import jdk.test.lib.jfr.EventNames; @@ -39,7 +41,7 @@ import jdk.test.whitebox.code.CodeBlob; /** - * Test for events: vm/code_cache/full vm/compiler/failure + * Test for events: jdk.CodeCacheFull jdk.CompilationFailure * * We verify that we should get at least one of each of the events listed above. * @@ -58,13 +60,15 @@ */ public class TestCodeSweeper { + static class ProvocationEvent extends Event { + } private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); private static final int COMP_LEVEL_SIMPLE = 1; private static final int COMP_LEVEL_FULL_OPTIMIZATION = 4; private static final int SIZE = 1; private static final String METHOD_NAME = "verifyFullEvent"; - private static final String pathFull = EventNames.CodeCacheFull; - private static final String pathFailure = EventNames.CompilationFailure; + private static final String EVENT_CODE_CACHE_FULL = EventNames.CodeCacheFull; + private static final String EVENT_COMPILATION_FAILURE = EventNames.CompilationFailure; public static final long SEGMENT_SIZE = WhiteBox.getWhiteBox().getUintxVMFlag("CodeCacheSegmentSize"); public static final long MIN_BLOCK_LENGTH = WhiteBox.getWhiteBox().getUintxVMFlag("CodeCacheMinBlockLength"); public static final long MIN_ALLOCATION = SEGMENT_SIZE * MIN_BLOCK_LENGTH; @@ -77,26 +81,41 @@ public static void main(String[] args) throws Throwable { System.out.println("This test will warn that the code cache is full."); System.out.println("That is expected and is the purpose of the test."); System.out.println("************************************************"); - - Recording r = new Recording(); - r.enable(pathFull); - r.enable(pathFailure); - r.start(); - provokeEvents(); - r.stop(); + List events = Collections.synchronizedList(new ArrayList<>()); + try (RecordingStream rs = new RecordingStream()) { + rs.setReuse(false); + rs.enable(EVENT_CODE_CACHE_FULL); + rs.enable(EVENT_COMPILATION_FAILURE); + rs.onEvent(EVENT_CODE_CACHE_FULL, events::add); + rs.onEvent(EVENT_COMPILATION_FAILURE, events::add); + rs.onEvent(ProvocationEvent.class.getName(), e -> { + if (!events.isEmpty()) { + rs.close(); + return; + } + // Retry if CodeCacheFull or CompilationFailure events weren't provoked + try { + provokeEvents(); + } catch (Exception ex) { + ex.printStackTrace(); + rs.close(); + } + }); + rs.startAsync(); + provokeEvents(); + rs.awaitTermination(); + } int countEventFull = 0; int countEventFailure = 0; - - List events = Events.fromRecording(r); Events.hasEvents(events); - for (RecordedEvent event : events) { + for (RecordedEvent event : new ArrayList<>(events)) { switch (event.getEventType().getName()) { - case pathFull: + case EVENT_CODE_CACHE_FULL: countEventFull++; verifyFullEvent(event); break; - case pathFailure: + case EVENT_COMPILATION_FAILURE: countEventFailure++; verifyFailureEvent(event); break; @@ -115,6 +134,8 @@ private static boolean canAllocate(double size, long maxSize, MemoryPoolMXBean b } private static void provokeEvents() throws NoSuchMethodException, InterruptedException { + System.out.println("provokeEvents()"); + ProvocationEvent provocationEvent = new ProvocationEvent(); // Prepare for later, since we don't want to trigger any compilation // setting this up. Method method = TestCodeSweeper.class.getDeclaredMethod(METHOD_NAME, new Class[] { RecordedEvent.class }); @@ -159,6 +180,7 @@ private static void provokeEvents() throws NoSuchMethodException, InterruptedExc for (Long blob : blobs) { WHITE_BOX.freeCodeBlob(blob); } + provocationEvent.commit(); } private static void verifyFullEvent(RecordedEvent event) throws Throwable { From 6a9a867d645b8fe86f4ca2b04a43bf5aa8f9d487 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20Gr=C3=B6nlund?= Date: Thu, 8 Aug 2024 14:38:46 +0000 Subject: [PATCH 235/353] 8337994: [REDO] Native memory leak when not recording any events Reviewed-by: egahlin --- .../share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp | 9 +++++++++ .../share/jfr/recorder/service/jfrRecorderService.cpp | 6 +----- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp index 203ec3a3ec494..279b871d8181a 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp @@ -883,6 +883,15 @@ static void do_clds(CldWriter& cldw) { ModuleCldWriter mcw(&cldw); KlassAndModuleCldWriter kmcw(&kcw, &mcw); _artifacts->iterate_klasses(kmcw); + if (is_initial_typeset_for_chunk()) { + CldPtr bootloader = get_cld(Universe::boolArrayKlass()); + assert(bootloader != nullptr, "invariant"); + if (IS_NOT_SERIALIZED(bootloader)) { + write__cld(_writer, bootloader); + assert(IS_SERIALIZED(bootloader), "invariant"); + cldw.add(1); + } + } _artifacts->tally(cldw); } diff --git a/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp b/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp index fc2043a4d921d..0395b711c6521 100644 --- a/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp +++ b/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp @@ -639,11 +639,7 @@ static void write_thread_local_buffer(JfrChunkWriter& chunkwriter, Thread* t) { size_t JfrRecorderService::flush() { size_t total_elements = flush_metadata(_chunkwriter); - const size_t storage_elements = flush_storage(_storage, _chunkwriter); - if (0 == storage_elements) { - return total_elements; - } - total_elements += storage_elements; + total_elements = flush_storage(_storage, _chunkwriter); if (_string_pool.is_modified()) { total_elements += flush_stringpool(_string_pool, _chunkwriter); } From 78773b1769922611318243b6680d59518ed4e015 Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Thu, 8 Aug 2024 15:52:17 +0000 Subject: [PATCH 236/353] 8338015: Fix "Java Java" typo in package info file of java.lang.classfile Reviewed-by: jiefu, jpai, liach --- .../share/classes/java/lang/classfile/package-info.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/java.base/share/classes/java/lang/classfile/package-info.java b/src/java.base/share/classes/java/lang/classfile/package-info.java index b5991b0e951b9..921cf9e1a3443 100644 --- a/src/java.base/share/classes/java/lang/classfile/package-info.java +++ b/src/java.base/share/classes/java/lang/classfile/package-info.java @@ -26,8 +26,8 @@ /** *

    Provides classfile parsing, generation, and transformation library.

    * The {@code java.lang.classfile} package contains classes for reading, writing, and - * modifying Java class files, as specified in Chapter {@jvms 4} of the Java - * Java Virtual Machine Specification. + * modifying Java class files, as specified in Chapter {@jvms 4} of the + * Java Virtual Machine Specification. * *

    Reading classfiles

    * The main class for reading classfiles is {@link java.lang.classfile.ClassModel}; we From 9695f09581bac856ad97943cca15c65dc21d2adf Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Thu, 8 Aug 2024 16:11:08 +0000 Subject: [PATCH 237/353] 8337683: Fix -Wconversion problem with arrayOop.hpp Reviewed-by: stefank, dholmes --- src/hotspot/share/oops/arrayOop.hpp | 18 +++++++++--------- src/hotspot/share/runtime/atomic.hpp | 5 +++-- src/hotspot/share/utilities/byteswap.hpp | 3 ++- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/hotspot/share/oops/arrayOop.hpp b/src/hotspot/share/oops/arrayOop.hpp index 0aa26500bd8d2..1ca8a9530a48c 100644 --- a/src/hotspot/share/oops/arrayOop.hpp +++ b/src/hotspot/share/oops/arrayOop.hpp @@ -68,10 +68,10 @@ class arrayOopDesc : public oopDesc { // The header is considered the oop part of this type plus the length. // This is not equivalent to sizeof(arrayOopDesc) which should not appear in the code. static int header_size_in_bytes() { - size_t hs = length_offset_in_bytes() + sizeof(int); + int hs = length_offset_in_bytes() + (int)sizeof(int); #ifdef ASSERT // make sure it isn't called before UseCompressedOops is initialized. - static size_t arrayoopdesc_hs = 0; + static int arrayoopdesc_hs = 0; if (arrayoopdesc_hs == 0) arrayoopdesc_hs = hs; assert(arrayoopdesc_hs == hs, "header size can't change"); #endif // ASSERT @@ -83,13 +83,13 @@ class arrayOopDesc : public oopDesc { // it occupies the second half of the _klass field in oopDesc. static int length_offset_in_bytes() { return UseCompressedClassPointers ? klass_gap_offset_in_bytes() : - sizeof(arrayOopDesc); + (int)sizeof(arrayOopDesc); } // Returns the offset of the first element. static int base_offset_in_bytes(BasicType type) { - size_t hs = header_size_in_bytes(); - return (int)(element_type_should_be_aligned(type) ? align_up(hs, BytesPerLong) : hs); + int hs = header_size_in_bytes(); + return element_type_should_be_aligned(type) ? align_up(hs, BytesPerLong) : hs; } // Returns the address of the first element. The elements in the array will not @@ -134,14 +134,14 @@ class arrayOopDesc : public oopDesc { assert(type < T_CONFLICT, "wrong type"); assert(type2aelembytes(type) != 0, "wrong type"); - size_t hdr_size_in_bytes = base_offset_in_bytes(type); + int hdr_size_in_bytes = base_offset_in_bytes(type); // This is rounded-up and may overlap with the first array elements. - size_t hdr_size_in_words = align_up(hdr_size_in_bytes, HeapWordSize) / HeapWordSize; + int hdr_size_in_words = align_up(hdr_size_in_bytes, HeapWordSize) / HeapWordSize; const size_t max_element_words_per_size_t = - align_down((SIZE_MAX/HeapWordSize - hdr_size_in_words), MinObjAlignment); + align_down((SIZE_MAX/HeapWordSize - (size_t)hdr_size_in_words), MinObjAlignment); const size_t max_elements_per_size_t = - HeapWordSize * max_element_words_per_size_t / type2aelembytes(type); + HeapWordSize * max_element_words_per_size_t / (size_t)type2aelembytes(type); if ((size_t)max_jint < max_elements_per_size_t) { // It should be ok to return max_jint here, but parts of the code // (CollectedHeap, Klass::oop_oop_iterate(), and more) uses an int for diff --git a/src/hotspot/share/runtime/atomic.hpp b/src/hotspot/share/runtime/atomic.hpp index 399a78fd3fce1..bf198b5f5621f 100644 --- a/src/hotspot/share/runtime/atomic.hpp +++ b/src/hotspot/share/runtime/atomic.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,7 @@ #include "runtime/orderAccess.hpp" #include "utilities/align.hpp" #include "utilities/bytes.hpp" +#include "utilities/checkedCast.hpp" #include "utilities/macros.hpp" #include @@ -1118,7 +1119,7 @@ inline T Atomic::CmpxchgByteUsingInt::operator()(T volatile* dest, uint8_t canon_compare_value = compare_value; volatile uint32_t* aligned_dest = reinterpret_cast(align_down(dest, sizeof(uint32_t))); - size_t offset = pointer_delta(dest, aligned_dest, 1); + uint32_t offset = checked_cast(pointer_delta(dest, aligned_dest, 1)); uint32_t idx = (Endian::NATIVE == Endian::BIG) ? (sizeof(uint32_t) - 1 - offset) diff --git a/src/hotspot/share/utilities/byteswap.hpp b/src/hotspot/share/utilities/byteswap.hpp index fba0775cf4992..9c3b53630b39b 100644 --- a/src/hotspot/share/utilities/byteswap.hpp +++ b/src/hotspot/share/utilities/byteswap.hpp @@ -26,6 +26,7 @@ #define SHARE_UTILITIES_BYTESWAP_HPP #include "metaprogramming/enableIf.hpp" +#include "utilities/checkedCast.hpp" #include "utilities/globalDefinitions.hpp" #include @@ -63,7 +64,7 @@ struct ByteswapFallbackImpl; template struct ByteswapFallbackImpl { inline constexpr uint16_t operator()(uint16_t x) const { - return (((x & UINT16_C(0x00ff)) << 8) | ((x & UINT16_C(0xff00)) >> 8)); + return checked_cast(((x & UINT16_C(0x00ff)) << 8) | ((x & UINT16_C(0xff00)) >> 8)); } }; From 53c9f037fb2805aab5ab9729166ce7d5bc7a77f9 Mon Sep 17 00:00:00 2001 From: Jiangli Zhou Date: Thu, 8 Aug 2024 16:31:02 +0000 Subject: [PATCH 238/353] 8336849: Remove .llvm_addrsig section from JDK/VM static libraries (.a files) Reviewed-by: ihse --- make/common/native/Link.gmk | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/make/common/native/Link.gmk b/make/common/native/Link.gmk index 2090218ffbb34..ca03c6ee6b12f 100644 --- a/make/common/native/Link.gmk +++ b/make/common/native/Link.gmk @@ -109,6 +109,11 @@ define CreateStaticLibrary $(if $$($1_LINK_OBJS_RELATIVE), $$(CD) $$(OUTPUTDIR) ; ) \ $$($1_LD) $(LDFLAGS_CXX_PARTIAL_LINKING) $$($1_SYSROOT_LDFLAGS) \ -o $$($1_TARGET_RELOCATABLE) $$($1_LD_OBJ_ARG)) + # 'ld -r' might invalidate the .llvm_addrsig section, and this will cause subsequent + # calls to lld (with '-Wl,--icf=safe') to fail when linking with this library, so + # remove that section. + $$(call ExecuteWithLog, $$($1_OBJECT_DIR)/$$($1_SAFE_NAME)_objcopy_remove_llvm_addrsig_section, \ + $$($1_OBJCOPY) --remove-section=.llvm_addrsig $$($1_TARGET_RELOCATABLE)) endif $$(call ExecuteWithLog, $$($1_OBJECT_DIR)/$$($1_SAFE_NAME)_run_ar, \ $(if $$($1_LINK_OBJS_RELATIVE), $$(CD) $$(OUTPUTDIR) ; ) \ From bfb75b96266f4c5840e2edea13f9aa2c801518cf Mon Sep 17 00:00:00 2001 From: Roger Riggs Date: Thu, 8 Aug 2024 16:53:38 +0000 Subject: [PATCH 239/353] 8336926: jdk/internal/util/ReferencedKeyTest.java can fail with ConcurrentModificationException Reviewed-by: bpb, shade, dfuchs --- .../jdk/internal/util/ReferencedKeyMap.java | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/java.base/share/classes/jdk/internal/util/ReferencedKeyMap.java b/src/java.base/share/classes/jdk/internal/util/ReferencedKeyMap.java index 9c364cd781350..810d43ae38a3a 100644 --- a/src/java.base/share/classes/jdk/internal/util/ReferencedKeyMap.java +++ b/src/java.base/share/classes/jdk/internal/util/ReferencedKeyMap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -219,8 +219,14 @@ public boolean containsValue(Object value) { @Override public V get(Object key) { - Objects.requireNonNull(key, "key must not be null"); removeStaleReferences(); + return getNoCheckStale(key); + } + + // Internal get(key) without removing stale references that would modify the keyset. + // Use when iterating or streaming over the keys to avoid ConcurrentModificationException. + private V getNoCheckStale(Object key) { + Objects.requireNonNull(key, "key must not be null"); return map.get(lookupKey(key)); } @@ -291,7 +297,7 @@ public Collection values() { public Set> entrySet() { removeStaleReferences(); return filterKeySet() - .map(k -> new AbstractMap.SimpleEntry<>(k, get(k))) + .map(k -> new AbstractMap.SimpleEntry<>(k, getNoCheckStale(k))) .collect(Collectors.toSet()); } @@ -335,7 +341,7 @@ public V replace(K key, V value) { public String toString() { removeStaleReferences(); return filterKeySet() - .map(k -> k + "=" + get(k)) + .map(k -> k + "=" + getNoCheckStale(k)) .collect(Collectors.joining(", ", "{", "}")); } From e7a0b5b09bcfcd8b09667e51ec588e206f0652ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20Gr=C3=B6nlund?= Date: Thu, 8 Aug 2024 18:45:11 +0000 Subject: [PATCH 240/353] 8334780: Crash: assert(h_array_list.not_null()) failed: invariant Reviewed-by: egahlin, shade --- src/hotspot/share/jfr/support/jfrJdkJfrEvent.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/jfr/support/jfrJdkJfrEvent.cpp b/src/hotspot/share/jfr/support/jfrJdkJfrEvent.cpp index cd47630228931..0c2fb0206ecee 100644 --- a/src/hotspot/share/jfr/support/jfrJdkJfrEvent.cpp +++ b/src/hotspot/share/jfr/support/jfrJdkJfrEvent.cpp @@ -136,7 +136,9 @@ jobject JdkJfrEvent::get_all_klasses(TRAPS) { transform_klasses_to_local_jni_handles(event_subklasses, THREAD); Handle h_array_list(THREAD, new_java_util_arraylist(THREAD)); - assert(h_array_list.not_null(), "invariant"); + if (h_array_list.is_null()) { + return empty_java_util_arraylist; + } static const char add_method_name[] = "add"; static const char add_method_signature[] = "(Ljava/lang/Object;)Z"; From 9f08a01cb6ebb08f67749aabdff4efaedfaf3228 Mon Sep 17 00:00:00 2001 From: Leonid Mesnik Date: Thu, 8 Aug 2024 19:47:50 +0000 Subject: [PATCH 241/353] 8338010: WB_IsFrameDeoptimized miss ResourceMark Reviewed-by: dholmes, shade --- src/hotspot/share/prims/whitebox.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index 6ee33a6107998..544eeabb5c212 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -799,6 +799,7 @@ WB_END WB_ENTRY(jboolean, WB_IsFrameDeoptimized(JNIEnv* env, jobject o, jint depth)) bool result = false; if (thread->has_last_Java_frame()) { + ResourceMark rm(THREAD); RegisterMap reg_map(thread, RegisterMap::UpdateMap::include, RegisterMap::ProcessFrames::include, From 55c509708e9b89a7609fd41b6e5a271f250bbacd Mon Sep 17 00:00:00 2001 From: Jiawei Tang Date: Fri, 9 Aug 2024 02:29:15 +0000 Subject: [PATCH 242/353] 8337331: crash: pinned virtual thread will lead to jvm crash when running with the javaagent option Reviewed-by: dholmes, sspitsyn --- src/hotspot/share/prims/jvmtiExport.cpp | 10 +-- .../TestPinCaseWithCFLH.java | 77 +++++++++++++++++++ 2 files changed, 82 insertions(+), 5 deletions(-) create mode 100644 test/hotspot/jtreg/serviceability/jvmti/vthread/TestPinCaseWithCFLH/TestPinCaseWithCFLH.java diff --git a/src/hotspot/share/prims/jvmtiExport.cpp b/src/hotspot/share/prims/jvmtiExport.cpp index f79116f5ebeb0..95cc54d93134f 100644 --- a/src/hotspot/share/prims/jvmtiExport.cpp +++ b/src/hotspot/share/prims/jvmtiExport.cpp @@ -929,9 +929,8 @@ class JvmtiClassFileLoadHookPoster : public StackObj { _cached_class_file_ptr = cache_ptr; _has_been_modified = false; - if (_thread->is_in_any_VTMS_transition()) { - return; // no events should be posted if thread is in any VTMS transition - } + assert(!_thread->is_in_any_VTMS_transition(), "CFLH events are not allowed in any VTMS transition"); + _state = JvmtiExport::get_jvmti_thread_state(_thread); if (_state != nullptr) { _class_being_redefined = _state->get_class_being_redefined(); @@ -1091,8 +1090,9 @@ bool JvmtiExport::post_class_file_load_hook(Symbol* h_name, if (JvmtiEnv::get_phase() < JVMTI_PHASE_PRIMORDIAL) { return false; } - if (JavaThread::current()->is_in_tmp_VTMS_transition()) { - return false; // skip CFLH events in tmp VTMS transition + + if (JavaThread::current()->is_in_any_VTMS_transition()) { + return false; // no events should be posted if thread is in any VTMS transition } JvmtiClassFileLoadHookPoster poster(h_name, class_loader, diff --git a/test/hotspot/jtreg/serviceability/jvmti/vthread/TestPinCaseWithCFLH/TestPinCaseWithCFLH.java b/test/hotspot/jtreg/serviceability/jvmti/vthread/TestPinCaseWithCFLH/TestPinCaseWithCFLH.java new file mode 100644 index 0000000000000..02755a0289fc1 --- /dev/null +++ b/test/hotspot/jtreg/serviceability/jvmti/vthread/TestPinCaseWithCFLH/TestPinCaseWithCFLH.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +import java.lang.instrument.ClassFileTransformer; +import java.lang.instrument.IllegalClassFormatException; +import java.lang.instrument.Instrumentation; +import java.security.ProtectionDomain; +import jdk.test.lib.thread.VThreadPinner; + +/* + * @test + * @summary javaagent + tracePinnedThreads will cause jvm crash/ run into deadlock when the virtual thread is pinned + * @library /test/lib + * @requires vm.continuations + * @requires vm.jvmti + * @modules java.base/java.lang:+open + * @compile TestPinCaseWithCFLH.java + * @build jdk.test.lib.Utils + * @run driver jdk.test.lib.util.JavaAgentBuilder + * TestPinCaseWithCFLH TestPinCaseWithCFLH.jar + * @run main/othervm/timeout=100 -Djdk.virtualThreadScheduler.maxPoolSize=1 + * -Djdk.tracePinnedThreads=full --enable-native-access=ALL-UNNAMED + * -javaagent:TestPinCaseWithCFLH.jar TestPinCaseWithCFLH + */ +public class TestPinCaseWithCFLH { + + public static class TestClassFileTransformer implements ClassFileTransformer { + public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined, + ProtectionDomain protectionDomain, byte[] classfileBuffer) + throws IllegalClassFormatException { + return classfileBuffer; + } + } + + // Called when agent is loaded at startup + public static void premain(String agentArgs, Instrumentation instrumentation) throws Exception { + instrumentation.addTransformer(new TestClassFileTransformer()); + } + + private static int result = 0; + + public static void main(String[] args) throws Exception{ + Thread t1 = Thread.ofVirtual().name("vthread-1").start(() -> { + VThreadPinner.runPinned(() -> { + try { + // try yield, will pin, + // javaagent + tracePinnedThreads should not lead to crash + // (because of the class `PinnedThreadPrinter`) + Thread.sleep(500); + } catch (Exception e) { + e.printStackTrace(); + } + }); + }); + t1.join(); + } + +} \ No newline at end of file From 0c1e9111d226b601236b9826e27ecc67a8b625fb Mon Sep 17 00:00:00 2001 From: Gui Cao Date: Fri, 9 Aug 2024 02:59:37 +0000 Subject: [PATCH 243/353] 8338019: Fix simple -Wzero-as-null-pointer-constant warnings in riscv code Reviewed-by: fyang, mli, luhenry --- src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp | 2 +- src/hotspot/cpu/riscv/c1_Runtime1_riscv.cpp | 2 +- src/hotspot/cpu/riscv/frame_riscv.cpp | 2 +- src/hotspot/cpu/riscv/nativeInst_riscv.cpp | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp index 798679185d3a2..3d146b87707aa 100644 --- a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp @@ -542,7 +542,7 @@ void LIR_Assembler::const2mem(LIR_Opr src, LIR_Opr dest, BasicType type, CodeEmi insn = &MacroAssembler::sw; break; case T_OBJECT: // fall through case T_ARRAY: - assert(c->as_jobject() == 0, "should be"); + assert(c->as_jobject() == nullptr, "should be"); if (UseCompressedOops && !wide) { insn = &MacroAssembler::sw; } else { diff --git a/src/hotspot/cpu/riscv/c1_Runtime1_riscv.cpp b/src/hotspot/cpu/riscv/c1_Runtime1_riscv.cpp index 9fa8939837a85..e999b703b3e7b 100644 --- a/src/hotspot/cpu/riscv/c1_Runtime1_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_Runtime1_riscv.cpp @@ -1066,4 +1066,4 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { #undef __ -const char *Runtime1::pd_name_for_address(address entry) { Unimplemented(); return 0; } +const char *Runtime1::pd_name_for_address(address entry) { Unimplemented(); } diff --git a/src/hotspot/cpu/riscv/frame_riscv.cpp b/src/hotspot/cpu/riscv/frame_riscv.cpp index 32825a02c5eac..96dca4704ad95 100644 --- a/src/hotspot/cpu/riscv/frame_riscv.cpp +++ b/src/hotspot/cpu/riscv/frame_riscv.cpp @@ -269,7 +269,7 @@ void frame::patch_pc(Thread* thread, address pc) { // Either the return address is the original one or we are going to // patch in the same address that's already there. - assert(_pc == pc_old || pc == pc_old || pc_old == 0, "must be"); + assert(_pc == pc_old || pc == pc_old || pc_old == nullptr, "must be"); DEBUG_ONLY(address old_pc = _pc;) *pc_addr = pc; _pc = pc; // must be set before call to get_deopt_original_pc diff --git a/src/hotspot/cpu/riscv/nativeInst_riscv.cpp b/src/hotspot/cpu/riscv/nativeInst_riscv.cpp index f0357f1cd3029..6c9e0986869b6 100644 --- a/src/hotspot/cpu/riscv/nativeInst_riscv.cpp +++ b/src/hotspot/cpu/riscv/nativeInst_riscv.cpp @@ -685,7 +685,7 @@ address NativeJump::jump_destination() const { // load // return -1 if jump to self or to 0 - if ((dest == (address) this) || dest == 0) { + if ((dest == (address) this) || dest == nullptr) { dest = (address) -1; } @@ -714,7 +714,7 @@ address NativeGeneralJump::jump_destination() const { // a general jump // return -1 if jump to self or to 0 - if ((dest == (address) this) || dest == 0) { + if ((dest == (address) this) || dest == nullptr) { dest = (address) -1; } From 9ab8c6b9ba90ffd12600a250c8704571e9feb78d Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Fri, 9 Aug 2024 05:09:27 +0000 Subject: [PATCH 244/353] 8335130: The test "javax/swing/plaf/synth/ComponentsOrientationSupport/5033822/bug5033822.java" fails because the background color of the tabs is displayed incorrectly. Reviewed-by: achung, psadhukhan --- .../sun/java/swing/plaf/gtk/GTKPainter.java | 34 ++++++++-------- .../swing/plaf/nimbus/SynthPainterImpl.java | 39 ++++++++++--------- .../swing/plaf/synth/SynthTabbedPaneUI.java | 8 +--- 3 files changed, 41 insertions(+), 40 deletions(-) diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKPainter.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKPainter.java index 4787696a367eb..ea27a2a6e0d9b 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKPainter.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKPainter.java @@ -935,25 +935,27 @@ public void paintTabbedPaneTabBackground(SynthContext context, Graphics g, int x, int y, int w, int h, int tabIndex) { - Region id = context.getRegion(); - int state = context.getComponentState(); - int gtkState = ((state & SynthConstants.SELECTED) != 0 ? - SynthConstants.ENABLED : SynthConstants.PRESSED); JTabbedPane pane = (JTabbedPane)context.getComponent(); - int placement = pane.getTabPlacement(); + if (UIManager.getBoolean("TabbedPane.tabsOpaque") || pane.isOpaque()) { + Region id = context.getRegion(); + int state = context.getComponentState(); + int gtkState = ((state & SynthConstants.SELECTED) != 0 ? + SynthConstants.ENABLED : SynthConstants.PRESSED); + int placement = pane.getTabPlacement(); - // Fill the tab rect area - g.fillRect(x, y, w, h); + // Fill the tab rect area + g.fillRect(x, y, w, h); - synchronized (UNIXToolkit.GTK_LOCK) { - if (! ENGINE.paintCachedImage(g, x, y, w, h, - id, gtkState, placement, tabIndex)) { - PositionType side = POSITIONS[placement - 1]; - ENGINE.startPainting(g, x, y, w, h, - id, gtkState, placement, tabIndex); - ENGINE.paintExtension(g, context, id, gtkState, - ShadowType.OUT, "tab", x, y, w, h, side, tabIndex); - ENGINE.finishPainting(); + synchronized (UNIXToolkit.GTK_LOCK) { + if (!ENGINE.paintCachedImage(g, x, y, w, h, + id, gtkState, placement, tabIndex)) { + PositionType side = POSITIONS[placement - 1]; + ENGINE.startPainting(g, x, y, w, h, + id, gtkState, placement, tabIndex); + ENGINE.paintExtension(g, context, id, gtkState, + ShadowType.OUT, "tab", x, y, w, h, side, tabIndex); + ENGINE.finishPainting(); + } } } } diff --git a/src/java.desktop/share/classes/javax/swing/plaf/nimbus/SynthPainterImpl.java b/src/java.desktop/share/classes/javax/swing/plaf/nimbus/SynthPainterImpl.java index c990c968ff6fa..9dfd422f6dddb 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/nimbus/SynthPainterImpl.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/nimbus/SynthPainterImpl.java @@ -2098,24 +2098,27 @@ public void paintTabbedPaneTabBackground(SynthContext context, Graphics g, public void paintTabbedPaneTabBackground(SynthContext context, Graphics g, int x, int y, int w, int h, int tabIndex, int orientation) { - if (orientation == JTabbedPane.LEFT) { - AffineTransform transform = new AffineTransform(); - transform.scale(-1, 1); - transform.rotate(Math.toRadians(90)); - paintBackground(context, g, y, x, h, w, transform); - } else if (orientation == JTabbedPane.RIGHT) { - AffineTransform transform = new AffineTransform(); - transform.rotate(Math.toRadians(90)); - transform.translate(0, -(x + w)); - paintBackground(context, g, y, 0, h, w, transform); - } else if (orientation == JTabbedPane.BOTTOM) { - AffineTransform transform = new AffineTransform(); - transform.translate(x,y); - transform.scale(1, -1); - transform.translate(0,-h); - paintBackground(context, g, 0, 0, w, h, transform); - } else { - paintBackground(context, g, x, y, w, h, null); + JTabbedPane pane = (JTabbedPane)context.getComponent(); + if (UIManager.getBoolean("TabbedPane.tabsOpaque") || pane.isOpaque()) { + if (orientation == JTabbedPane.LEFT) { + AffineTransform transform = new AffineTransform(); + transform.scale(-1, 1); + transform.rotate(Math.toRadians(90)); + paintBackground(context, g, y, x, h, w, transform); + } else if (orientation == JTabbedPane.RIGHT) { + AffineTransform transform = new AffineTransform(); + transform.rotate(Math.toRadians(90)); + transform.translate(0, -(x + w)); + paintBackground(context, g, y, 0, h, w, transform); + } else if (orientation == JTabbedPane.BOTTOM) { + AffineTransform transform = new AffineTransform(); + transform.translate(x, y); + transform.scale(1, -1); + transform.translate(0, -h); + paintBackground(context, g, 0, 0, w, h, transform); + } else { + paintBackground(context, g, x, y, w, h, null); + } } } diff --git a/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthTabbedPaneUI.java b/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthTabbedPaneUI.java index 837c4d8298f9e..3378ef9e8b3de 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthTabbedPaneUI.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthTabbedPaneUI.java @@ -127,7 +127,6 @@ public class SynthTabbedPaneUI extends BasicTabbedPaneUI // Background color for unselected tabs private Color unselectedBackground; private boolean contentOpaque = true; - private boolean tabsOpaque = true; /** * @@ -156,7 +155,6 @@ private boolean scrollableTabLayoutEnabled() { protected void installDefaults() { selectColor = UIManager.getColor("TabbedPane.selected"); contentOpaque = UIManager.getBoolean("TabbedPane.contentOpaque"); - tabsOpaque = UIManager.getBoolean("TabbedPane.tabsOpaque"); unselectedBackground = UIManager.getColor("TabbedPane.unselectedBackground"); updateStyle(tabPane); } @@ -655,10 +653,8 @@ private void paintTab(SynthContext ss, Graphics g, g.setColor(getUnselectedBackgroundAt(tabIndex)); } - if (tabsOpaque || tabPane.isOpaque()) { - tabContext.getPainter().paintTabbedPaneTabBackground(tabContext, g, - x, y, width, height, tabIndex, placement); - } + tabContext.getPainter().paintTabbedPaneTabBackground(tabContext, g, + x, y, width, height, tabIndex, placement); tabContext.getPainter().paintTabbedPaneTabBorder(tabContext, g, x, y, width, height, tabIndex, placement); From 00aac4097abd3c5e6144734cfd44228bc31892fb Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Fri, 9 Aug 2024 06:26:22 +0000 Subject: [PATCH 245/353] 8338058: map_or_reserve_memory_aligned Windows enhance remap assertion Reviewed-by: mdoerr, clanger --- src/hotspot/os/windows/os_windows.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp index 1cc7d9aa33adf..65ba13b0d9e81 100644 --- a/src/hotspot/os/windows/os_windows.cpp +++ b/src/hotspot/os/windows/os_windows.cpp @@ -3463,6 +3463,7 @@ static char* map_or_reserve_memory_aligned(size_t size, size_t alignment, int fi } assert(aligned_base != nullptr, "Did not manage to re-map after %d attempts?", max_attempts); + assert(aligned_base != nullptr, "Did not manage to re-map after %d attempts (size %zu, alignment %zu, file descriptor %d)", max_attempts, size, alignment, file_desc); return aligned_base; } From c01f53ac2dab1d4d2cd1e4d45a67f9373d4a9c7e Mon Sep 17 00:00:00 2001 From: Christian Hagedorn Date: Fri, 9 Aug 2024 07:17:59 +0000 Subject: [PATCH 246/353] 8337876: [IR Framework] Add support for IR tests with @Stable Reviewed-by: shade, kvn --- .../jtreg/compiler/lib/ir_framework/README.md | 11 ++- .../lib/ir_framework/TestFramework.java | 13 +++- .../ir_framework/driver/TestVMProcess.java | 15 ++-- .../tests/TestPhaseIRMatching.java | 2 +- .../tests/TestPrivilegedMode.java | 69 +++++++++++++++++++ 5 files changed, 103 insertions(+), 7 deletions(-) create mode 100644 test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestPrivilegedMode.java diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/README.md b/test/hotspot/jtreg/compiler/lib/ir_framework/README.md index 3f6e0d4163faa..55d9fcbaecead 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/README.md +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/README.md @@ -157,7 +157,16 @@ The framework allows the use of additional compiler control annotations for help - [@ForceCompile](./ForceCompile.java) - [@ForceCompileClassInitializer](./ForceCompileClassInitializer.java) -### 2.5 Framework Debug and Stress Flags +### 2.5 IR Tests with Privileged Classes +To run tests in a privileged mode (e.g. when using `@Stable`, `@Contended`, `@ReservedStackAccess` etc.), one need to add the test classes to the boot classpath. This can easily be achieved by calling `TestFramework.addTestClassesToBootClassPath()` on the test framework object: +``` +TestFramework testFramework = new TestFramework(); +testFramework + .addTestClassesToBootClassPath() + .start(); +``` + +### 2.6 Framework Debug and Stress Flags The framework provides various stress and debug flags. They should mainly be used as JTreg VM and/or Javaoptions (apart from `VerifyIR`). The following (property) flags are supported: - `-DVerifyIR=false`: Explicitly disable IR verification. This is useful, for example, if some scenarios use VM flags that let `@IR` annotation rules fail and the user does not want to provide separate IR rules or add flag preconditions to the already existing IR rules. diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/TestFramework.java b/test/hotspot/jtreg/compiler/lib/ir_framework/TestFramework.java index 67fadbc4eac31..d477aa44763fa 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/TestFramework.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/TestFramework.java @@ -172,6 +172,7 @@ public class TestFramework { private Set scenarioIndices; private List flags; private int defaultWarmup = -1; + private boolean testClassesOnBootClassPath; /* * Public interface methods @@ -323,6 +324,15 @@ public TestFramework addScenarios(Scenario... scenarios) { return this; } + /** + * Add test classes to boot classpath. This adds all classes found on path {@link jdk.test.lib.Utils#TEST_CLASSES} + * to the boot classpath with "-Xbootclasspath/a". This is useful when trying to run tests in a privileged mode. + */ + public TestFramework addTestClassesToBootClassPath() { + this.testClassesOnBootClassPath = true; + return this; + } + /** * Start the testing of the implicitly (by {@link #TestFramework()}) or explicitly (by {@link #TestFramework(Class)}) * set test class. @@ -744,7 +754,8 @@ private boolean onlyWhitelistedJTregVMAndJavaOptsFlags() { } private void runTestVM(List additionalFlags) { - TestVMProcess testVMProcess = new TestVMProcess(additionalFlags, testClass, helperClasses, defaultWarmup); + TestVMProcess testVMProcess = new TestVMProcess(additionalFlags, testClass, helperClasses, defaultWarmup, + testClassesOnBootClassPath); if (shouldVerifyIR) { try { TestClassParser testClassParser = new TestClassParser(testClass); diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/TestVMProcess.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/TestVMProcess.java index 04f8096d96917..8c168b73260cf 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/TestVMProcess.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/TestVMProcess.java @@ -34,6 +34,7 @@ import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools; +import java.io.File; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -63,11 +64,12 @@ public class TestVMProcess { private OutputAnalyzer oa; private String irEncoding; - public TestVMProcess(List additionalFlags, Class testClass, Set> helperClasses, int defaultWarmup) { + public TestVMProcess(List additionalFlags, Class testClass, Set> helperClasses, int defaultWarmup, + boolean testClassesOnBootClassPath) { this.cmds = new ArrayList<>(); TestFrameworkSocket socket = new TestFrameworkSocket(); try (socket) { - prepareTestVMFlags(additionalFlags, socket, testClass, helperClasses, defaultWarmup); + prepareTestVMFlags(additionalFlags, socket, testClass, helperClasses, defaultWarmup, testClassesOnBootClassPath); start(); } processSocketOutput(socket); @@ -91,11 +93,16 @@ public static String getLastTestVMOutput() { } private void prepareTestVMFlags(List additionalFlags, TestFrameworkSocket socket, Class testClass, - Set> helperClasses, int defaultWarmup) { + Set> helperClasses, int defaultWarmup, boolean testClassesOnBootClassPath) { // Set java.library.path so JNI tests which rely on jtreg nativepath setting work cmds.add("-Djava.library.path=" + Utils.TEST_NATIVE_PATH); // Need White Box access in test VM. - cmds.add("-Xbootclasspath/a:."); + String bootClassPath = "-Xbootclasspath/a:."; + if (testClassesOnBootClassPath) { + // Add test classes themselves to boot classpath to make them privileged. + bootClassPath += File.pathSeparator + Utils.TEST_CLASSES; + } + cmds.add(bootClassPath); cmds.add("-XX:+UnlockDiagnosticVMOptions"); cmds.add("-XX:+WhiteBoxAPI"); // Ignore CompileCommand flags which have an impact on the profiling information. diff --git a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestPhaseIRMatching.java b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestPhaseIRMatching.java index 9a39fb5310f35..f0056ebc79da9 100644 --- a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestPhaseIRMatching.java +++ b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestPhaseIRMatching.java @@ -66,7 +66,7 @@ private static void run(Class testClass) { List noAdditionalFlags = new ArrayList<>(); FlagVMProcess flagVMProcess = new FlagVMProcess(testClass, noAdditionalFlags); List testVMFlags = flagVMProcess.getTestVMFlags(); - TestVMProcess testVMProcess = new TestVMProcess(testVMFlags, testClass, null, -1); + TestVMProcess testVMProcess = new TestVMProcess(testVMFlags, testClass, null, -1, false); TestClassParser testClassParser = new TestClassParser(testClass); Matchable testClassMatchable = testClassParser.parse(testVMProcess.getHotspotPidFileName(), testVMProcess.getIrEncoding()); diff --git a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestPrivilegedMode.java b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestPrivilegedMode.java new file mode 100644 index 0000000000000..347b2eb39fbfc --- /dev/null +++ b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestPrivilegedMode.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package ir_framework.tests; + +import compiler.lib.ir_framework.*; +import compiler.lib.ir_framework.driver.irmatching.IRViolationException; + +import jdk.internal.vm.annotation.Stable; +import jdk.test.lib.Asserts; + +/* + * @test + * @requires vm.flagless + * @summary Test that IR framework successfully adds test class to boot classpath in order to run in privileged mode. + * @modules java.base/jdk.internal.vm.annotation + * @library /test/lib / + * @run driver ir_framework.tests.TestPrivilegedMode + */ + +public class TestPrivilegedMode { + static @Stable int iFld; // Treated as constant after first being set. + + public static void main(String[] args) { + try { + TestFramework.run(); + Asserts.fail("should not reach"); + } catch (IRViolationException e) { + // Without adding test class to boot classpath, we fail to replace the field load by a constant. + Asserts.assertTrue(e.getExceptionInfo().contains("Matched forbidden node")); + Asserts.assertTrue(e.getExceptionInfo().contains("LoadI")); + } + + // When adding the test class to the boot classpath, we can replace the field load by a constant. + new TestFramework().addTestClassesToBootClassPath().start(); + } + + @Test + @Arguments(setup = "setup") + @IR(failOn = IRNode.LOAD_I) + public int test() { + return iFld; + } + + @Setup + public void setup() { + iFld = 34; + } +} From 82d5768c1bdccfaf97a41f32a8bfcfd03a0fb378 Mon Sep 17 00:00:00 2001 From: Andrey Turbanov Date: Fri, 9 Aug 2024 07:20:01 +0000 Subject: [PATCH 247/353] 8337840: Remove redundant null check in ObjectOutputStream.writeProxyDesc Reviewed-by: rriggs --- src/java.base/share/classes/java/io/ObjectOutputStream.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/java.base/share/classes/java/io/ObjectOutputStream.java b/src/java.base/share/classes/java/io/ObjectOutputStream.java index 2dcf174cf5399..3650b10135356 100644 --- a/src/java.base/share/classes/java/io/ObjectOutputStream.java +++ b/src/java.base/share/classes/java/io/ObjectOutputStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1272,7 +1272,7 @@ private void writeProxyDesc(ObjectStreamClass desc, boolean unshared) } bout.setBlockDataMode(true); - if (cl != null && isCustomSubclass()) { + if (isCustomSubclass()) { ReflectUtil.checkPackageAccess(cl); } annotateProxyClass(cl); From f74109bd178c92a9dff1ca6fce03b25f51a0384f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20Sikstr=C3=B6m?= Date: Fri, 9 Aug 2024 07:29:56 +0000 Subject: [PATCH 248/353] 8337939: ZGC: Make assertions and checks less convoluted and explicit Reviewed-by: stefank, ayang, eosterlund --- src/hotspot/share/gc/z/zAddress.cpp | 6 ++-- src/hotspot/share/gc/z/zAddress.inline.hpp | 30 +++++++++++++++---- src/hotspot/share/gc/z/zBarrier.inline.hpp | 6 ++-- src/hotspot/share/gc/z/zBarrierSet.inline.hpp | 4 +-- src/hotspot/share/gc/z/zHeapIterator.cpp | 2 +- src/hotspot/share/gc/z/zMark.cpp | 4 +-- src/hotspot/share/gc/z/zMark.inline.hpp | 4 +-- src/hotspot/share/gc/z/zPage.inline.hpp | 2 +- .../share/gc/z/zReferenceProcessor.cpp | 4 +-- src/hotspot/share/gc/z/zVerify.cpp | 24 +++++++++------ 10 files changed, 55 insertions(+), 31 deletions(-) diff --git a/src/hotspot/share/gc/z/zAddress.cpp b/src/hotspot/share/gc/z/zAddress.cpp index d1c199fad070c..1cd33e44a05d1 100644 --- a/src/hotspot/share/gc/z/zAddress.cpp +++ b/src/hotspot/share/gc/z/zAddress.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -93,9 +93,7 @@ static void initialize_check_oop_function() { #ifdef CHECK_UNHANDLED_OOPS if (ZVerifyOops) { // Enable extra verification of usages of oops in oopsHierarchy.hpp - check_oop_function = [](oopDesc* obj) { - (void)to_zaddress(obj); - }; + check_oop_function = &check_is_valid_zaddress; } #endif } diff --git a/src/hotspot/share/gc/z/zAddress.inline.hpp b/src/hotspot/share/gc/z/zAddress.inline.hpp index 4adbf50bc86c6..bbc92a7e2aaf3 100644 --- a/src/hotspot/share/gc/z/zAddress.inline.hpp +++ b/src/hotspot/share/gc/z/zAddress.inline.hpp @@ -333,10 +333,22 @@ inline void dereferenceable_test(zaddress addr) { } #endif -inline zaddress to_zaddress(uintptr_t value) { - const zaddress addr = zaddress(value); +inline void check_is_valid_zaddress(zaddress addr) { assert_is_valid(addr); DEBUG_ONLY(dereferenceable_test(addr)); +} + +inline void check_is_valid_zaddress(uintptr_t value) { + check_is_valid_zaddress(zaddress(value)); +} + +inline void check_is_valid_zaddress(oopDesc* o) { + check_is_valid_zaddress(uintptr_t(o)); +} + +inline zaddress to_zaddress(uintptr_t value) { + const zaddress addr = zaddress(value); + check_is_valid_zaddress(addr); return addr; } @@ -344,7 +356,7 @@ inline zaddress to_zaddress(oopDesc* o) { return to_zaddress(uintptr_t(o)); } -inline oop to_oop(zaddress addr) { +inline void assert_is_oop_or_null(zaddress addr) { const oop obj = cast_to_oop(addr); assert(!ZVerifyOops || oopDesc::is_oop_or_null(obj), "Broken oop: " PTR_FORMAT " [" PTR_FORMAT " " PTR_FORMAT " " PTR_FORMAT " " PTR_FORMAT "]", p2i(obj), @@ -352,7 +364,16 @@ inline oop to_oop(zaddress addr) { *(uintptr_t*)(untype(addr) + 0x08), *(uintptr_t*)(untype(addr) + 0x10), *(uintptr_t*)(untype(addr) + 0x18)); - return obj; +} + +inline void assert_is_oop(zaddress addr) { + assert(!is_null(addr), "Should not be null"); + assert_is_oop_or_null(addr); +} + +inline oop to_oop(zaddress addr) { + assert_is_oop_or_null(addr); + return cast_to_oop(addr); } inline zaddress operator+(zaddress addr, size_t size) { @@ -378,7 +399,6 @@ inline void assert_is_valid(zaddress_unsafe addr) { DEBUG_ONLY(is_valid(addr, true /* assert_on_failure */);) } - inline uintptr_t untype(zaddress_unsafe addr) { return static_cast(addr); } diff --git a/src/hotspot/share/gc/z/zBarrier.inline.hpp b/src/hotspot/share/gc/z/zBarrier.inline.hpp index b3191e9ae3f7a..a3eb7a9ca67d6 100644 --- a/src/hotspot/share/gc/z/zBarrier.inline.hpp +++ b/src/hotspot/share/gc/z/zBarrier.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -745,7 +745,7 @@ inline void ZBarrier::mark_and_remember(volatile zpointer* p, zaddress addr) { template inline void ZBarrier::mark(zaddress addr) { - assert(!ZVerifyOops || oopDesc::is_oop(to_oop(addr), false), "must be oop"); + assert_is_oop(addr); if (ZHeap::heap()->is_old(addr)) { ZGeneration::old()->mark_object_if_active(addr); @@ -757,7 +757,7 @@ inline void ZBarrier::mark(zaddress addr) { template inline void ZBarrier::mark_young(zaddress addr) { assert(ZGeneration::young()->is_phase_mark(), "Should only be called during marking"); - assert(!ZVerifyOops || oopDesc::is_oop(to_oop(addr), false), "must be oop"); + assert_is_oop(addr); assert(ZHeap::heap()->is_young(addr), "Must be young"); ZGeneration::young()->mark_object(addr); diff --git a/src/hotspot/share/gc/z/zBarrierSet.inline.hpp b/src/hotspot/share/gc/z/zBarrierSet.inline.hpp index d53b69345dd98..174cdfd9e909d 100644 --- a/src/hotspot/share/gc/z/zBarrierSet.inline.hpp +++ b/src/hotspot/share/gc/z/zBarrierSet.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -430,7 +430,7 @@ class ZLoadBarrierOopClosure : public BasicOopIterateClosure { template inline void ZBarrierSet::AccessBarrier::clone_in_heap(oop src, oop dst, size_t size) { - assert_is_valid(to_zaddress(src)); + check_is_valid_zaddress(src); if (dst->is_objArray()) { // Cloning an object array is similar to performing array copy. diff --git a/src/hotspot/share/gc/z/zHeapIterator.cpp b/src/hotspot/share/gc/z/zHeapIterator.cpp index 50fc921131fe7..e149a976add92 100644 --- a/src/hotspot/share/gc/z/zHeapIterator.cpp +++ b/src/hotspot/share/gc/z/zHeapIterator.cpp @@ -146,7 +146,7 @@ class ZHeapIteratorUncoloredRootOopClosure : public OopClosure { oop load_oop(oop* p) { const oop o = Atomic::load(p); - assert_is_valid(to_zaddress(o)); + check_is_valid_zaddress(o); return RawAccess<>::oop_load(p); } diff --git a/src/hotspot/share/gc/z/zMark.cpp b/src/hotspot/share/gc/z/zMark.cpp index eb342495f5799..d33b86c83e57c 100644 --- a/src/hotspot/share/gc/z/zMark.cpp +++ b/src/hotspot/share/gc/z/zMark.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -365,7 +365,7 @@ void ZMark::follow_array_object(objArrayOop obj, bool finalizable) { } // Should be convertible to colorless oop - assert_is_valid(to_zaddress(obj)); + check_is_valid_zaddress(obj); zpointer* const addr = (zpointer*)obj->base(); const size_t length = (size_t)obj->length(); diff --git a/src/hotspot/share/gc/z/zMark.inline.hpp b/src/hotspot/share/gc/z/zMark.inline.hpp index b530259361027..9edc57a60002e 100644 --- a/src/hotspot/share/gc/z/zMark.inline.hpp +++ b/src/hotspot/share/gc/z/zMark.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,7 +47,7 @@ template inline void ZMark::mark_object(zaddress addr) { - assert(!ZVerifyOops || oopDesc::is_oop(to_oop(addr)), "Should be oop"); + assert_is_oop(addr); ZPage* const page = _page_table->get(addr); if (page->is_allocating()) { diff --git a/src/hotspot/share/gc/z/zPage.inline.hpp b/src/hotspot/share/gc/z/zPage.inline.hpp index fcf69c685f7b6..d8ecad571907c 100644 --- a/src/hotspot/share/gc/z/zPage.inline.hpp +++ b/src/hotspot/share/gc/z/zPage.inline.hpp @@ -311,7 +311,7 @@ inline bool ZPage::mark_object(zaddress addr, bool finalizable, bool& inc_live) assert(is_in(addr), "Invalid address"); // Verify oop - (void)to_oop(addr); + assert_is_oop(addr); // Set mark bit const BitMap::idx_t index = bit_index(addr); diff --git a/src/hotspot/share/gc/z/zReferenceProcessor.cpp b/src/hotspot/share/gc/z/zReferenceProcessor.cpp index df8cb2b0e959f..1252de2ac2723 100644 --- a/src/hotspot/share/gc/z/zReferenceProcessor.cpp +++ b/src/hotspot/share/gc/z/zReferenceProcessor.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -143,7 +143,7 @@ bool ZReferenceProcessor::is_inactive(zaddress reference, oop referent, Referenc return !is_null(reference_next(reference)); } else { // Verification - (void)to_zaddress(referent); + check_is_valid_zaddress(referent); // A non-FinalReference is inactive if the referent is null. The referent can only // be null if the application called Reference.enqueue() or Reference.clear(). diff --git a/src/hotspot/share/gc/z/zVerify.cpp b/src/hotspot/share/gc/z/zVerify.cpp index d47886ec7c2fc..b735965e9d49b 100644 --- a/src/hotspot/share/gc/z/zVerify.cpp +++ b/src/hotspot/share/gc/z/zVerify.cpp @@ -111,6 +111,16 @@ static bool z_is_null_relaxed(zpointer o) { return (untype(o) & ~color_mask) == 0; } +static void z_verify_oop_object(zaddress addr, zpointer o, void* p) { + const oop obj = cast_to_oop(addr); + guarantee(oopDesc::is_oop(obj), BAD_OOP_ARG(o, p)); +} + +static void z_verify_root_oop_object(zaddress addr, void* p) { + const oop obj = cast_to_oop(addr); + guarantee(oopDesc::is_oop(obj), BAD_OOP_ARG(addr, p)); +} + static void z_verify_old_oop(zpointer* p) { const zpointer o = *p; assert(o != zpointer::null, "Old should not contain raw null"); @@ -121,7 +131,7 @@ static void z_verify_old_oop(zpointer* p) { // safepoint after reference processing, where we hold the driver lock and // know there is no concurrent remembered set processing in the young generation. const zaddress addr = ZPointer::uncolor(o); - guarantee(oopDesc::is_oop(to_oop(addr)), BAD_OOP_ARG(o, p)); + z_verify_oop_object(addr, o, p); } else { const zaddress addr = ZBarrier::load_barrier_on_oop_field_preloaded(nullptr, o); // Old to young pointers might not be mark good if the young @@ -143,15 +153,11 @@ static void z_verify_young_oop(zpointer* p) { guarantee(ZPointer::is_marked_young(o), BAD_OOP_ARG(o, p)); if (ZPointer::is_load_good(o)) { - guarantee(oopDesc::is_oop(to_oop(ZPointer::uncolor(o))), BAD_OOP_ARG(o, p)); + z_verify_oop_object(ZPointer::uncolor(o), o, p); } } } -static void z_verify_root_oop_object(zaddress o, void* p) { - guarantee(oopDesc::is_oop(to_oop(o)), BAD_OOP_ARG(o, p)); -} - static void z_verify_uncolored_root_oop(zaddress* p) { assert(!ZHeap::heap()->is_in((uintptr_t)p), "Roots shouldn't be in heap"); const zaddress o = *p; @@ -168,7 +174,7 @@ static void z_verify_possibly_weak_oop(zpointer* p) { const zaddress addr = ZBarrier::load_barrier_on_oop_field_preloaded(nullptr, o); guarantee(ZHeap::heap()->is_old(addr) || ZPointer::is_marked_young(o), BAD_OOP_ARG(o, p)); guarantee(ZHeap::heap()->is_young(addr) || ZHeap::heap()->is_object_live(addr), BAD_OOP_ARG(o, p)); - guarantee(oopDesc::is_oop(to_oop(addr)), BAD_OOP_ARG(o, p)); + z_verify_oop_object(addr, o, p); // Verify no missing remset entries. We are holding the driver lock here and that // allows us to more precisely verify the remembered set, as there is no concurrent @@ -211,14 +217,14 @@ class ZVerifyColoredRootClosure : public OopClosure { // Minor collections could have relocated the object; // use load barrier to find correct object. const zaddress addr = ZBarrier::load_barrier_on_oop_field_preloaded(nullptr, o); - z_verify_root_oop_object(addr, p); + z_verify_oop_object(addr, o, p); } else { // Don't know the state of the oop if (is_valid(o)) { // it looks like a valid colored oop; // use load barrier to find correct object. const zaddress addr = ZBarrier::load_barrier_on_oop_field_preloaded(nullptr, o); - z_verify_root_oop_object(addr, p); + z_verify_oop_object(addr, o, p); } } } From 53fce38a3ff8700fef640fffc066efc21ff9c25f Mon Sep 17 00:00:00 2001 From: Erik Gahlin Date: Fri, 9 Aug 2024 07:53:15 +0000 Subject: [PATCH 249/353] 8338062: JFR: Remove TestStartDuration.java and TestStartName.java from ProblemList.txt Reviewed-by: mgronlun --- test/jdk/ProblemList.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 8aedbc7793116..293d9d108d32c 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -745,8 +745,6 @@ jdk/incubator/vector/LoadJsvmlTest.java 8305390 windows- # jdk_jfr jdk/jfr/event/runtime/TestResidentSetSizeEvent.java 8309846 aix-ppc64 -jdk/jfr/startupargs/TestStartName.java 8214685 windows-x64 -jdk/jfr/startupargs/TestStartDuration.java 8214685 windows-x64 jdk/jfr/jvm/TestWaste.java 8282427 generic-all ############################################################################ From 6ebd5d74d57b334e7cf0b1282d7bb469a56fb3d6 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Fri, 9 Aug 2024 08:23:44 +0000 Subject: [PATCH 250/353] 8338036: Serial: Remove Generation::update_counters Reviewed-by: kbarrett --- src/hotspot/share/gc/serial/generation.hpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/hotspot/share/gc/serial/generation.hpp b/src/hotspot/share/gc/serial/generation.hpp index beb29928f4826..c6a9f94a8703a 100644 --- a/src/hotspot/share/gc/serial/generation.hpp +++ b/src/hotspot/share/gc/serial/generation.hpp @@ -114,8 +114,7 @@ class Generation: public CHeapObj { public: // Performance Counter support - virtual void update_counters() = 0; - virtual CollectorCounters* counters() { return _gc_counters; } + CollectorCounters* counters() { return _gc_counters; } GCMemoryManager* gc_manager() const { assert(_gc_manager != nullptr, "not initialized yet"); From c37e8638c98cb4516569304e9a0ab477affb0641 Mon Sep 17 00:00:00 2001 From: Hamlin Li Date: Fri, 9 Aug 2024 09:12:41 +0000 Subject: [PATCH 251/353] 8314125: RISC-V: implement Base64 intrinsic - encoding Reviewed-by: fyang, luhenry --- src/hotspot/cpu/riscv/assembler_riscv.hpp | 13 + src/hotspot/cpu/riscv/stubGenerator_riscv.cpp | 223 ++++++++++++++++++ src/hotspot/cpu/riscv/vm_version_riscv.cpp | 5 + 3 files changed, 241 insertions(+) diff --git a/src/hotspot/cpu/riscv/assembler_riscv.hpp b/src/hotspot/cpu/riscv/assembler_riscv.hpp index e4280ab34e1ce..79279be7acc1b 100644 --- a/src/hotspot/cpu/riscv/assembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/assembler_riscv.hpp @@ -1828,6 +1828,19 @@ enum Nf { #undef INSN +#define INSN(NAME, op, width, umop, mop, mew, nf) \ + void NAME(VectorRegister Vd_or_Vs3, Register Rs1, VectorMask vm = unmasked) { \ + patch_VLdSt(op, Vd_or_Vs3, width, Rs1, umop, vm, mop, mew, nf); \ + } + + // Vector Unit-Stride Segment Load Instructions + INSN(vlseg3e8_v, 0b0000111, 0b000, 0b00000, 0b00, 0b0, g3); + + // Vector Unit-Stride Segment Store Instructions + INSN(vsseg4e8_v, 0b0100111, 0b000, 0b00000, 0b00, 0b0, g4); + +#undef INSN + #define INSN(NAME, op, width, mop, mew) \ void NAME(VectorRegister Vd, Register Rs1, VectorRegister Vs2, VectorMask vm = unmasked, Nf nf = g1) { \ patch_VLdSt(op, Vd, width, Rs1, Vs2->raw_encoding(), vm, mop, mew, nf); \ diff --git a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp index 198835d733f79..6a2c6c7d6c9bd 100644 --- a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp +++ b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp @@ -5103,6 +5103,225 @@ class StubGenerator: public StubCodeGenerator { return (address) start; } + /** + * vector registers: + * input VectorRegister's: intputV1-V3, for m2 they could be v2, v4, v6, for m1 they could be v1, v2, v3 + * index VectorRegister's: idxV1-V4, for m2 they could be v8, v10, v12, v14, for m1 they could be v4, v5, v6, v7 + * output VectorRegister's: outputV1-V4, for m2 they could be v16, v18, v20, v22, for m1 they could be v8, v9, v10, v11 + * + * NOTE: each field will occupy a vector register group + */ + void base64_vector_encode_round(Register src, Register dst, Register codec, + Register size, Register stepSrc, Register stepDst, + VectorRegister inputV1, VectorRegister inputV2, VectorRegister inputV3, + VectorRegister idxV1, VectorRegister idxV2, VectorRegister idxV3, VectorRegister idxV4, + VectorRegister outputV1, VectorRegister outputV2, VectorRegister outputV3, VectorRegister outputV4, + Assembler::LMUL lmul) { + // set vector register type/len + __ vsetvli(x0, size, Assembler::e8, lmul); + + // segmented load src into v registers: mem(src) => vr(3) + __ vlseg3e8_v(inputV1, src); + + // src = src + register_group_len_bytes * 3 + __ add(src, src, stepSrc); + + // encoding + // 1. compute index into lookup table: vr(3) => vr(4) + __ vsrl_vi(idxV1, inputV1, 2); + + __ vsrl_vi(idxV2, inputV2, 2); + __ vsll_vi(inputV1, inputV1, 6); + __ vor_vv(idxV2, idxV2, inputV1); + __ vsrl_vi(idxV2, idxV2, 2); + + __ vsrl_vi(idxV3, inputV3, 4); + __ vsll_vi(inputV2, inputV2, 4); + __ vor_vv(idxV3, inputV2, idxV3); + __ vsrl_vi(idxV3, idxV3, 2); + + __ vsll_vi(idxV4, inputV3, 2); + __ vsrl_vi(idxV4, idxV4, 2); + + // 2. indexed load: vr(4) => vr(4) + __ vluxei8_v(outputV1, codec, idxV1); + __ vluxei8_v(outputV2, codec, idxV2); + __ vluxei8_v(outputV3, codec, idxV3); + __ vluxei8_v(outputV4, codec, idxV4); + + // segmented store encoded data in v registers back to dst: vr(4) => mem(dst) + __ vsseg4e8_v(outputV1, dst); + + // dst = dst + register_group_len_bytes * 4 + __ add(dst, dst, stepDst); + } + + /** + * void j.u.Base64.Encoder.encodeBlock(byte[] src, int sp, int sl, byte[] dst, int dp, boolean isURL) + * + * Input arguments: + * c_rarg0 - src, source array + * c_rarg1 - sp, src start offset + * c_rarg2 - sl, src end offset + * c_rarg3 - dst, dest array + * c_rarg4 - dp, dst start offset + * c_rarg5 - isURL, Base64 or URL character set + */ + address generate_base64_encodeBlock() { + alignas(64) static const char toBase64[64] = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' + }; + + alignas(64) static const char toBase64URL[64] = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_' + }; + + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", "encodeBlock"); + address start = __ pc(); + __ enter(); + + Register src = c_rarg0; + Register soff = c_rarg1; + Register send = c_rarg2; + Register dst = c_rarg3; + Register doff = c_rarg4; + Register isURL = c_rarg5; + + Register codec = c_rarg6; + Register length = c_rarg7; // total length of src data in bytes + + Label ProcessData, Exit; + + // length should be multiple of 3 + __ sub(length, send, soff); + // real src/dst to process data + __ add(src, src, soff); + __ add(dst, dst, doff); + + // load the codec base address + __ la(codec, ExternalAddress((address) toBase64)); + __ beqz(isURL, ProcessData); + __ la(codec, ExternalAddress((address) toBase64URL)); + __ BIND(ProcessData); + + // vector version + if (UseRVV) { + Label ProcessM2, ProcessM1, ProcessScalar; + + Register size = soff; + Register stepSrcM1 = send; + Register stepSrcM2 = doff; + Register stepDst = isURL; + + __ mv(size, MaxVectorSize * 2); + __ mv(stepSrcM1, MaxVectorSize * 3); + __ slli(stepSrcM2, stepSrcM1, 1); + __ mv(stepDst, MaxVectorSize * 2 * 4); + + __ blt(length, stepSrcM2, ProcessM1); + + __ BIND(ProcessM2); + base64_vector_encode_round(src, dst, codec, + size, stepSrcM2, stepDst, + v2, v4, v6, // inputs + v8, v10, v12, v14, // indexes + v16, v18, v20, v22, // outputs + Assembler::m2); + + __ sub(length, length, stepSrcM2); + __ bge(length, stepSrcM2, ProcessM2); + + __ BIND(ProcessM1); + __ blt(length, stepSrcM1, ProcessScalar); + + __ srli(size, size, 1); + __ srli(stepDst, stepDst, 1); + base64_vector_encode_round(src, dst, codec, + size, stepSrcM1, stepDst, + v1, v2, v3, // inputs + v4, v5, v6, v7, // indexes + v8, v9, v10, v11, // outputs + Assembler::m1); + __ sub(length, length, stepSrcM1); + + __ BIND(ProcessScalar); + } + + // scalar version + { + Register byte1 = soff, byte0 = send, byte2 = doff; + Register combined24Bits = isURL; + + __ beqz(length, Exit); + + Label ScalarLoop; + __ BIND(ScalarLoop); + { + // plain: [byte0[7:0] : byte1[7:0] : byte2[7:0]] => + // encoded: [byte0[7:2] : byte0[1:0]+byte1[7:4] : byte1[3:0]+byte2[7:6] : byte2[5:0]] + + // load 3 bytes src data + __ lbu(byte0, Address(src, 0)); + __ lbu(byte1, Address(src, 1)); + __ lbu(byte2, Address(src, 2)); + __ addi(src, src, 3); + + // construct 24 bits from 3 bytes + __ slliw(byte0, byte0, 16); + __ slliw(byte1, byte1, 8); + __ orr(combined24Bits, byte0, byte1); + __ orr(combined24Bits, combined24Bits, byte2); + + // get codec index and encode(ie. load from codec by index) + __ slliw(byte0, combined24Bits, 8); + __ srliw(byte0, byte0, 26); + __ add(byte0, codec, byte0); + __ lbu(byte0, byte0); + + __ slliw(byte1, combined24Bits, 14); + __ srliw(byte1, byte1, 26); + __ add(byte1, codec, byte1); + __ lbu(byte1, byte1); + + __ slliw(byte2, combined24Bits, 20); + __ srliw(byte2, byte2, 26); + __ add(byte2, codec, byte2); + __ lbu(byte2, byte2); + + __ andi(combined24Bits, combined24Bits, 0x3f); + __ add(combined24Bits, codec, combined24Bits); + __ lbu(combined24Bits, combined24Bits); + + // store 4 bytes encoded data + __ sb(byte0, Address(dst, 0)); + __ sb(byte1, Address(dst, 1)); + __ sb(byte2, Address(dst, 2)); + __ sb(combined24Bits, Address(dst, 3)); + + __ sub(length, length, 3); + __ addi(dst, dst, 4); + // loop back + __ bnez(length, ScalarLoop); + } + } + + __ BIND(Exit); + + __ leave(); + __ ret(); + + return (address) start; + } + void adler32_process_bytes(Register buff, Register s1, Register s2, VectorRegister vtable, VectorRegister vzero, VectorRegister vbytes, VectorRegister vs1acc, VectorRegister vs2acc, Register temp0, Register temp1, Register temp2, Register temp3, @@ -5996,6 +6215,10 @@ static const int64_t right_3_bits = right_n_bits(3); StubRoutines::_sha1_implCompressMB = generate_sha1_implCompress(true, "sha1_implCompressMB"); } + if (UseBASE64Intrinsics) { + StubRoutines::_base64_encodeBlock = generate_base64_encodeBlock(); + } + if (UseAdler32Intrinsics) { StubRoutines::_updateBytesAdler32 = generate_updateBytesAdler32(); } diff --git a/src/hotspot/cpu/riscv/vm_version_riscv.cpp b/src/hotspot/cpu/riscv/vm_version_riscv.cpp index ac2d6cde1a227..e9c6226f44639 100644 --- a/src/hotspot/cpu/riscv/vm_version_riscv.cpp +++ b/src/hotspot/cpu/riscv/vm_version_riscv.cpp @@ -265,6 +265,11 @@ void VM_Version::c2_initialize() { // as there are extra checks inside it which could disable UseRVV // in some situations. + // Base64 + if (FLAG_IS_DEFAULT(UseBASE64Intrinsics)) { + FLAG_SET_DEFAULT(UseBASE64Intrinsics, true); + } + if (FLAG_IS_DEFAULT(UseVectorizedHashCodeIntrinsic)) { FLAG_SET_DEFAULT(UseVectorizedHashCodeIntrinsic, true); } From 140716078694a338e2c2f837841761262cee5542 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Walln=C3=B6fer?= Date: Fri, 9 Aug 2024 09:24:50 +0000 Subject: [PATCH 252/353] 8313931: Javadoc: links to type parameters actually generate links to classes Reviewed-by: jjg --- .../doclets/formats/html/ClassWriter.java | 50 +++++-- .../doclets/formats/html/HtmlIds.java | 16 +++ .../doclets/formats/html/HtmlLinkFactory.java | 13 +- .../formats/html/resources/script.js.template | 18 ++- .../formats/html/resources/stylesheet.css | 22 +++- .../formats/html/taglets/LinkTaglet.java | 24 +++- .../formats/html/taglets/ParamTaglet.java | 6 +- .../doclets/toolkit/util/CommentHelper.java | 6 + .../TestDeprecatedDocs.java | 8 +- .../TestDirectedInheritance.java | 6 +- .../doclet/testErasure/TestErasure.java | 8 +- .../TestGenericMethodLinkTaglet.java | 6 +- .../jdk/javadoc/doclet/testHref/TestHref.java | 5 +- .../doclet/testInterface/TestInterface.java | 36 ++--- .../TestLinkTagletTypeParam.java | 124 ++++++++++++++++++ .../TestMemberInheritance.java | 4 +- .../doclet/testModules/TestModules.java | 2 +- .../TestNewLanguageFeatures.java | 22 ++-- .../testParamTaglet/TestParamTaglet.java | 6 +- .../doclet/testProperty/TestProperty.java | 4 +- .../testRecordTypes/TestRecordTypes.java | 2 +- .../TestSerializedForm.java | 5 +- .../javadoc/doclet/testThrows/TestThrows.java | 4 +- .../testTypeParams/TestTypeParameters.java | 20 ++- .../testTypeParams/pkg/CtorTypeParam.java | 6 + .../doclet/testUnicode/TestUnicode.java | 4 +- 26 files changed, 336 insertions(+), 91 deletions(-) create mode 100644 test/langtools/jdk/javadoc/doclet/testLinkTaglet/TestLinkTagletTypeParam.java diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriter.java index a1fd27fefdd58..8218e5128be3b 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriter.java @@ -37,6 +37,7 @@ import javax.lang.model.element.Name; import javax.lang.model.element.PackageElement; import javax.lang.model.element.TypeElement; +import javax.lang.model.element.TypeParameterElement; import javax.lang.model.element.VariableElement; import javax.lang.model.type.TypeMirror; import javax.lang.model.util.SimpleElementVisitor8; @@ -155,7 +156,7 @@ protected void buildClassTree(Content classContent) { * @param target the content to which the documentation will be added */ protected void buildClassInfo(Content target) { - Content c = HtmlTree.DIV(HtmlStyles.horizontalScroll); + var c = new ContentBuilder(); buildParamInfo(c); buildSuperInterfacesInfo(c); buildImplementedInterfacesInfo(c); @@ -164,11 +165,13 @@ protected void buildClassInfo(Content target) { buildInterfaceUsageInfo(c); buildNestedClassInfo(c); buildFunctionalInterfaceInfo(c); - buildClassSignature(c); - buildDeprecationInfo(c); - buildClassDescription(c); - buildClassTagInfo(c); - + c.add(new HtmlTree(HtmlTag.HR)); + var div = HtmlTree.DIV(HtmlStyles.horizontalScroll); + buildClassSignature(div); + buildDeprecationInfo(div); + buildClassDescription(div); + buildClassTagInfo(div); + c.add(div); target.add(getClassInfo(c)); } @@ -432,12 +435,9 @@ private void setRecordDocumentation(TypeElement elem) { protected Content getHeader(String header) { HtmlTree body = getBody(getWindowTitle(utils.getSimpleName(typeElement))); var div = HtmlTree.DIV(HtmlStyles.header); - HtmlLinkInfo linkInfo = new HtmlLinkInfo(configuration, - HtmlLinkInfo.Kind.SHOW_TYPE_PARAMS_AND_BOUNDS, typeElement) - .linkToSelf(false); // Let's not link to ourselves in the header var heading = HtmlTree.HEADING_TITLE(Headings.PAGE_TITLE_HEADING, HtmlStyles.title, Text.of(header)); - heading.add(getTypeParameterLinks(linkInfo)); + heading.add(getTypeParameters()); div.add(heading); bodyContents.setHeader(getHeader(PageMode.CLASS, typeElement)) .addMainContent(MarkerComments.START_OF_CLASS_DATA) @@ -445,6 +445,35 @@ protected Content getHeader(String header) { return body; } + // Renders type parameters for the class heading, creating id attributes + // if @param block tags are missing in doc comment. + private Content getTypeParameters() { + var content = new ContentBuilder(); + var typeParams = typeElement.getTypeParameters(); + if (!typeParams.isEmpty()) { + // Generate id attributes if @param tags are missing for type parameters. + // Note that this does not handle the case where some but not all @param tags are missing. + var needsId = !utils.hasBlockTag(typeElement, DocTree.Kind.PARAM); + var linkInfo = new HtmlLinkInfo(configuration, + HtmlLinkInfo.Kind.SHOW_TYPE_PARAMS_AND_BOUNDS, typeElement) + .linkToSelf(false); // Let's not link to ourselves in the header + content.add("<"); + var first = true; + for (TypeParameterElement t : typeParams) { + if (!first) { + content.add(",").add(new HtmlTree(HtmlTag.WBR)); + } + var typeParamLink = getLink(linkInfo.forType(t.asType())); + content.add(needsId + ? HtmlTree.SPAN_ID(htmlIds.forTypeParam(t.getSimpleName().toString(), typeElement), typeParamLink) + : typeParamLink); + first = false; + } + content.add(">"); + } + return content; + } + protected Content getClassContentHeader() { return getContentHeader(); } @@ -473,7 +502,6 @@ public TypeElement getCurrentPageElement() { } protected void addClassSignature(Content classInfo) { - classInfo.add(new HtmlTree(HtmlTag.HR)); classInfo.add(new Signatures.TypeSignature(typeElement, this) .toContent()); } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlIds.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlIds.java index 1b9896fafa006..8b48c7a6f2262 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlIds.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlIds.java @@ -462,6 +462,22 @@ public static HtmlId forText(String text, Map counts) { return HtmlId.of(count == 0 ? base : base + "-" + count); } + /** + * Returns an id for text documenting a type parameter of a class or method. + * + * @param paramName the name of the type parameter + * @param owner the enclosing element + * + * @return the id + */ + public HtmlId forTypeParam(String paramName, Element owner) { + if (utils.isExecutableElement(owner)) { + return HtmlId.of(forMember((ExecutableElement) owner).getFirst().name() + + "-type-param-" + paramName); + } + return HtmlId.of("type-param-" + paramName); + } + /** * Returns an id for one of the kinds of section in the pages for item group summaries. * diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlLinkFactory.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlLinkFactory.java index 22af1e4a0244c..8e0c010dd1ae4 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlLinkFactory.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlLinkFactory.java @@ -162,9 +162,11 @@ public Content visitTypeVariable(TypeVariable type, HtmlLinkInfo linkInfo) { Element owner = typevariable.asElement().getEnclosingElement(); if (linkInfo.linkTypeParameters() && utils.isTypeElement(owner)) { linkInfo.setTypeElement((TypeElement) owner); - Content label = newContent(); - label.add(utils.getTypeName(type, false)); - linkInfo.label(label).skipPreview(true); + if (linkInfo.getLabel() == null || linkInfo.getLabel().isEmpty()) { + Content label = newContent(); + label.add(utils.getTypeName(type, false)); + linkInfo.label(label).skipPreview(true); + } link.add(getClassLink(linkInfo)); } else { // No need to link method type parameters. @@ -242,6 +244,11 @@ protected Content getClassLink(HtmlLinkInfo linkInfo) { boolean isTypeLink = linkInfo.getType() != null && utils.isTypeVariable(utils.getComponentType(linkInfo.getType())); title = getClassToolTip(typeElement, isTypeLink); + if (isTypeLink) { + linkInfo.fragment(m_writer.configuration.htmlIds.forTypeParam( + utils.getTypeName(utils.getComponentType(linkInfo.getType()), false), + typeElement).name()); + } } Content label = linkInfo.getClassLinkLabel(configuration); if (linkInfo.getContext() == HtmlLinkInfo.Kind.SHOW_TYPE_PARAMS_IN_LABEL) { diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script.js.template b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script.js.template index ef09e6df90fd7..71ef847670822 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script.js.template +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script.js.template @@ -232,6 +232,20 @@ document.addEventListener("readystatechange", (e) => { }); document.addEventListener("DOMContentLoaded", function(e) { setTopMargin(); + // Reset animation for type parameter target highlight + document.querySelectorAll("a").forEach((link) => { + link.addEventListener("click", (e) => { + const href = e.currentTarget.getAttribute("href"); + if (href && href.startsWith("#") && href.indexOf("type-param-") > -1) { + const target = document.getElementById(decodeURI(href.substring(1))); + if (target) { + target.style.animation = "none"; + void target.offsetHeight; + target.style.removeProperty("animation"); + } + } + }) + }); // Make sure current element is visible in breadcrumb navigation on small displays const subnav = document.querySelector("ol.sub-nav-list"); if (subnav && subnav.lastElementChild) { @@ -286,7 +300,7 @@ document.addEventListener("DOMContentLoaded", function(e) { }); var expanded = false; var windowWidth; - function collapse() { + function collapse(e) { if (expanded) { mainnav.removeAttribute("style"); if (toc) { @@ -336,7 +350,7 @@ document.addEventListener("DOMContentLoaded", function(e) { document.querySelectorAll("h1, h2, h3, h4, h5, h6") .forEach((hdr, idx) => { // Create anchor links for headers with an associated id attribute - var id = hdr.getAttribute("id") || hdr.parentElement.getAttribute("id") + var id = hdr.parentElement.getAttribute("id") || hdr.getAttribute("id") || (hdr.querySelector("a") && hdr.querySelector("a").getAttribute("id")); if (id) { var template = document.createElement('template'); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/stylesheet.css b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/stylesheet.css index 4e37588f6cda5..1130f14dc35b4 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/stylesheet.css +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/stylesheet.css @@ -63,7 +63,7 @@ --search-input-text-color: #000000; --search-input-placeholder-color: #909090; /* Highlight color for active search tag target */ - --search-tag-highlight-color: #ffff00; + --search-tag-highlight-color: #ffff66; /* Adjustments for icon and active background colors of copy-to-clipboard buttons */ --copy-icon-brightness: 100%; --copy-button-background-color-active: rgba(168, 168, 176, 0.3); @@ -307,7 +307,7 @@ ol.sub-nav-list a.current-selection { */ .title { color:var(--title-color); - margin:10px 0; + margin:10px 0 12px 0; } .sub-title { margin:5px 0 0 0; @@ -988,6 +988,22 @@ input::placeholder { .search-tag-result:target { background-color:var(--search-tag-highlight-color); } +dd > span:target, +h1 > span:target { + animation: 2.4s ease-out highlight; +} +section.class-description dd > span:target, +section.class-description h1 > span:target { + scroll-margin-top: 20em; +} +@keyframes highlight { + from { + background-color: var(--search-tag-highlight-color); + } + 60% { + background-color: var(--search-tag-highlight-color); + } +} details.page-search-details { display: inline-block; } @@ -1040,7 +1056,7 @@ span#page-search-link { z-index: 5; } .inherited-list { - margin: 10px 0 10px 0; + margin: 10px 0; } .horizontal-scroll { overflow: auto hidden; diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/LinkTaglet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/LinkTaglet.java index e16acd0315ad7..b16a1490b6303 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/LinkTaglet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/LinkTaglet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -176,7 +176,7 @@ Content linkSeeReferenceOutput(Element holder, return htmlWriter.getPackageLink(refPackage, labelContent, refFragment); } else { // @see is not referencing an included class, module or package. Check for cross-links. - String refModuleName = ch.getReferencedModuleName(refSignature); + String refModuleName = ch.getReferencedModuleName(refSignature); DocLink elementCrossLink = (refPackage != null) ? htmlWriter.getCrossPackageLink(refPackage) : (config.extern.isModule(refModuleName)) ? htmlWriter.getCrossModuleLink(utils.elementUtils.getModuleElement(refModuleName)) @@ -190,12 +190,28 @@ Content linkSeeReferenceOutput(Element holder, if (!config.isDocLintReferenceGroupEnabled()) { reportWarning.accept( "doclet.link.see.reference_not_found", - new Object[] { refSignature}); + new Object[] {refSignature}); } return htmlWriter.invalidTagOutput(resources.getText("doclet.link.see.reference_invalid"), - Optional.of(labelContent.isEmpty() ? text: labelContent)); + Optional.of(labelContent.isEmpty() ? text : labelContent)); } } + } else if (utils.isTypeParameterElement(ref)) { + // This is a type parameter of a generic class, method or constructor + if (labelContent.isEmpty()) { + labelContent = plainOrCode(isPlain, Text.of(utils.getSimpleName(ref))); + } + if (refMem == null) { + return htmlWriter.getLink( + new HtmlLinkInfo(config, HtmlLinkInfo.Kind.LINK_TYPE_PARAMS, ref.asType()) + .label(labelContent)); + } else { + // HtmlLinkFactory does not render type parameters of generic methods as links, so instead of + // teaching it how to do it (making the code even more complex) just create the link directly. + return htmlWriter.getLink(new HtmlLinkInfo(config, HtmlLinkInfo.Kind.PLAIN, refClass) + .fragment(config.htmlIds.forTypeParam(ref.getSimpleName().toString(), refMem).name()) + .label((labelContent))); + } } else if (refFragment == null) { // Must be a class reference since refClass is not null and refFragment is null. if (labelContent.isEmpty() && refTree != null) { diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/ParamTaglet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/ParamTaglet.java index ed46e6c5c864f..8a3c47bbfd4b6 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/ParamTaglet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/ParamTaglet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -278,7 +278,9 @@ private Content paramTagOutput(Element element, ParamTree paramTag, String param body.add(" - "); List description = ch.getDescription(paramTag); body.add(htmlWriter.commentTagsToContent(element, description, context.within(paramTag))); - return HtmlTree.DD(body); + return HtmlTree.DD(paramTag.isTypeParameter() + ? HtmlTree.SPAN_ID(config.htmlIds.forTypeParam(paramName, element), body) + : body); } private record Documentation(ParamTree paramTree, ExecutableElement method) { } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/CommentHelper.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/CommentHelper.java index d7a0bd2d0a070..30aa86aea7196 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/CommentHelper.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/CommentHelper.java @@ -188,6 +188,12 @@ public Element getReferencedMember(Element e) { Utils utils = configuration.utils; if (e == null) { return null; + } else if (utils.isTypeParameterElement(e)) { + // Return the enclosing member for type parameters of generic methods or constructors. + Element encl = e.getEnclosingElement(); + if (utils.isExecutableElement(encl)) { + return encl; + } } return (utils.isExecutableElement(e) || utils.isVariableElement(e)) ? e : null; } diff --git a/test/langtools/jdk/javadoc/doclet/testDeprecatedDocs/TestDeprecatedDocs.java b/test/langtools/jdk/javadoc/doclet/testDeprecatedDocs/TestDeprecatedDocs.java index 2bd9da5957837..165fadc8e051f 100644 --- a/test/langtools/jdk/javadoc/doclet/testDeprecatedDocs/TestDeprecatedDocs.java +++ b/test/langtools/jdk/javadoc/doclet/testDeprecatedDocs/TestDeprecatedDocs.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -102,7 +102,6 @@ public void test() { checkOutput("pkg/TestAnnotationType.html", true, """ -
    @Deprecated(forRemoval=true) @Documented public @interface
    @Deprecated(forRemoval=true) public class TestClass extends java.lang.Object
    @@ -212,7 +210,6 @@ public void test() { checkOutput("pkg/TestEnum.html", true, """ -
    @Deprecated(forRemoval=true) public enum TestEnum extends java.lang.Enum<
    @Deprecated(forRemoval=true) public class TestError extends java.lang.Error
    @@ -244,7 +240,6 @@ public void test() { checkOutput("pkg/TestException.html", true, """ -
    @Deprecated(forRemoval=true) public class TestException extends java.lang.Exception
    @@ -255,7 +250,6 @@ public void test() { checkOutput("pkg/TestInterface.html", true, """ -
    @Deprecated(forRemoval=true) public class TestInterface extends java.lang.Object
    diff --git a/test/langtools/jdk/javadoc/doclet/testDirectedInheritance/TestDirectedInheritance.java b/test/langtools/jdk/javadoc/doclet/testDirectedInheritance/TestDirectedInheritance.java index 89eb68db1dfdc..0f2b398e626bc 100644 --- a/test/langtools/jdk/javadoc/doclet/testDirectedInheritance/TestDirectedInheritance.java +++ b/test/langtools/jdk/javadoc/doclet/testDirectedInheritance/TestDirectedInheritance.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -154,8 +154,8 @@ public interface E1 extends I1, I2 {
    I2: main description
    """, """
    Type Parameters:
    -
    E - I2: first type parameter
    -
    F - I2: second type parameter
    +
    E - I2: first type parameter
    +
    F - I2: second type parameter
    Parameters:
    eObj - I2: parameter
    Returns:
    diff --git a/test/langtools/jdk/javadoc/doclet/testErasure/TestErasure.java b/test/langtools/jdk/javadoc/doclet/testErasure/TestErasure.java index f80074c50e250..ee2ec08b884e6 100644 --- a/test/langtools/jdk/javadoc/doclet/testErasure/TestErasure.java +++ b/test/langtools/jdk/javadoc/doclet/testErasure/TestErasure.java @@ -199,7 +199,7 @@ class X { }
     
    \ Foo\ - (T arg)
    + (T arg)
     
     <T extends X>
    \ @@ -227,10 +227,10 @@ class X { } // methods checkOutput("Foo.html", true, """
    abstract T
    + method-summary-table-tab3">abstract T
    m\ - (T arg)
    + (T arg)
     
    Test Feature
    """); } -} \ No newline at end of file +} diff --git a/test/langtools/jdk/javadoc/doclet/testGenericMethodLinkTaglet/TestGenericMethodLinkTaglet.java b/test/langtools/jdk/javadoc/doclet/testGenericMethodLinkTaglet/TestGenericMethodLinkTaglet.java index a9a4be1b262b9..db23064e9ca8d 100644 --- a/test/langtools/jdk/javadoc/doclet/testGenericMethodLinkTaglet/TestGenericMethodLinkTaglet.java +++ b/test/langtools/jdk/javadoc/doclet/testGenericMethodLinkTaglet/TestGenericMethodLinkTaglet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 8188248 + * @bug 8188248 8313931 * @summary NullPointerException on generic methods * @library /tools/lib ../../lib * @modules jdk.javadoc/jdk.javadoc.internal.tool @@ -67,7 +67,7 @@ public void test(Path base) throws Exception { checkOutput("pkg/A.html", true, """ - A"""); + param T"""); } void createTestClass(Path srcDir) throws Exception { diff --git a/test/langtools/jdk/javadoc/doclet/testHref/TestHref.java b/test/langtools/jdk/javadoc/doclet/testHref/TestHref.java index f21ad223fb459..b9dff5ff2a897 100644 --- a/test/langtools/jdk/javadoc/doclet/testHref/TestHref.java +++ b/test/langtools/jdk/javadoc/doclet/testHref/TestHref.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -75,7 +75,8 @@ public void test() { checkOutput("pkg/C4.html", true, //Header does not link to the page itself. - "Class C4<E extends C4<E>>", + """ + Class C4<E extends C4<E>>""", //Signature does not link to the page itself. """ public abstract class method in interface&\ nbsp;Interface<CE>""", + href="#type-param-CE" title="type parameter in Child">CE>""", //Make sure "Overrides" has substituted type parameters. """
    Overrides:
    method in class Parent<Parent<CE>
    """); checkOutput("pkg/Parent.html", true, @@ -190,7 +190,7 @@ public void test1() {
    Overrides:
    method1 in class&\ nbsp;GrandParent<<\ - a href="Child.html" title="type parameter in Child">CE>"""); + a href="#type-param-CE" title="type parameter in Child">CE>"""); } @Test @@ -209,17 +209,17 @@ public void test2() { erface in pkg2">Spliterator Spliterator.\ OfDouble, Spliter\ - ator.OfInt<Integer>, Spliterator.OfPrimitive<T,T_C\ - ONS,T,T_C\ + ONS,T_SPLITR extends Spliterator.OfPrimitive<T,<\ - a href="Spliterator.OfPrimitive.html" title="type parameter in Spliterator.OfPri\ - mitive">T_CONS,T,<\ + a href="Spliterator.OfPrimitive.html#type-param-T_CONS" title="type parameter in Spliterator.OfPri\ + mitive">T_CONS,T_SPLITR>>"""); checkOutput("pkg2/Spliterator.html", true, """ @@ -236,21 +236,21 @@ public void test2() {
    static interface 
    Spliterator.OfInt<Integer&\ + Spliterator.OfInt.html#type-param-Integer" title="type parameter in Spliterator.OfInt">Integer&\ gt;
     
    static interface 
    Spliterator.OfPrimitive\ - <T,T,T_CONS,T_SPLITR extends <\ + e.html#type-param-T_SPLITR" title="type parameter in Spliterator.OfPrimitive">T_SPLITR extends <\ a href="Spliterator.OfPrimitive.html" title="interface in pkg2">Spliterator.OfPr\ - imitive<T,<T,T_CONS,T_SPLITRT_SPLITR>>
     
    """); diff --git a/test/langtools/jdk/javadoc/doclet/testLinkTaglet/TestLinkTagletTypeParam.java b/test/langtools/jdk/javadoc/doclet/testLinkTaglet/TestLinkTagletTypeParam.java new file mode 100644 index 0000000000000..5cb1f687d452f --- /dev/null +++ b/test/langtools/jdk/javadoc/doclet/testLinkTaglet/TestLinkTagletTypeParam.java @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8313931 + * @summary Javadoc: links to type parameters actually generate links to classes + * @library /tools/lib ../../lib + * @modules jdk.javadoc/jdk.javadoc.internal.tool + * @build toolbox.ToolBox javadoc.tester.* + * @run main TestLinkTagletTypeParam + */ + +import javadoc.tester.JavadocTester; +import toolbox.ToolBox; + +import java.io.IOException; +import java.nio.file.Path; + +public class TestLinkTagletTypeParam extends JavadocTester { + + public static void main(String... args) throws Exception { + var tester = new TestLinkTagletTypeParam(); + tester.runTests(); + } + + ToolBox tb = new ToolBox(); + + @JavadocTester.Test + public void testClassTypeParameterLink(Path base) throws IOException { + Path src = base.resolve("src"); + + tb.writeJavaFiles(src, + """ + /** + * Link to {@link F}. + * + * @param the first type param + * @param an Appendable + * + * @see APND the second type parameter + */ + public class Test { + private Test() {} + } + """); + + javadoc("-Xdoclint:none", + "-d", base.resolve("api").toString(), + "-sourcepath", src.toString(), + src.resolve("Test.java").toString()); + checkExit(JavadocTester.Exit.OK); + + checkOrder("Test.html", + """ +
    Type Parameters:
    +
    F - the first type param
    +
    APND - an Appendable
    """, + """ + Link to
    F.""", + """ +
    See Also:
    +
    + """); + } + + @JavadocTester.Test + public void testMethodTypeParameterLink(Path base) throws IOException { + Path src = base.resolve("src"); + + tb.writeJavaFiles(src, + """ + /** + * Class comment. + */ + public class Test { + /** + * Link to {@link T} and {@linkplain T link with label}. + * + * @param the T + * @param appendable the appendable + */ + public T append(final T appendable) { + return appendable; + } + } + """); + + javadoc("-Xdoclint:reference", + "-d", base.resolve("api").toString(), + "-sourcepath", src.toString(), + src.resolve("Test.java").toString()); + + checkOutput(JavadocTester.Output.OUT, true, + ""); + + checkOutput("Test.html", true, + """ + Link to T and link with label."""); + } +} diff --git a/test/langtools/jdk/javadoc/doclet/testMemberInheritance/TestMemberInheritance.java b/test/langtools/jdk/javadoc/doclet/testMemberInheritance/TestMemberInheritance.java index 705cae327e3a3..559f7b08d3877 100644 --- a/test/langtools/jdk/javadoc/doclet/testMemberInheritance/TestMemberInheritance.java +++ b/test/langtools/jdk/javadoc/doclet/testMemberInheritance/TestMemberInheritance.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -120,8 +120,8 @@ interface in pkg">BaseInterface
    checkOutput("pkg2/DocumentedNonGenericChild.html", true, """
    -

    +
    public abstract class DocumentedNonGenericChild extends java.lang.Object
    diff --git a/test/langtools/jdk/javadoc/doclet/testModules/TestModules.java b/test/langtools/jdk/javadoc/doclet/testModules/TestModules.java index 79bad12f95db2..4d3628544f81e 100644 --- a/test/langtools/jdk/javadoc/doclet/testModules/TestModules.java +++ b/test/langtools/jdk/javadoc/doclet/testModules/TestModules.java @@ -1360,8 +1360,8 @@ void checkLinkSource(boolean includePrivate) { checkOutput("moduleA/testpkgmdlA/TestClassInModuleA.html", true, """
    -

    +
    public class TestClassInModuleA diff --git a/test/langtools/jdk/javadoc/doclet/testNewLanguageFeatures/TestNewLanguageFeatures.java b/test/langtools/jdk/javadoc/doclet/testNewLanguageFeatures/TestNewLanguageFeatures.java index a54fbbcff75f0..eafad8c3245f2 100644 --- a/test/langtools/jdk/javadoc/doclet/testNewLanguageFeatures/TestNewLanguageFeatures.java +++ b/test/langtools/jdk/javadoc/doclet/testNewLanguageFeatures/TestNewLanguageFeatures.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -117,7 +117,7 @@ void checkTypeParameters() { // Check class type parameters section. """
    Type Parameters:
    -
    E - the type parameter for this class.""", +
    E - the type parameter for this class.
    """, // Type parameters in @see/@link """
    @@ -130,12 +130,14 @@ void checkTypeParameters() {
    """, // Method that uses class type parameter. """ - (E param)""", + (E param)""", // Method type parameter section. """
    Type Parameters:
    -
    T - This is the first type parameter.
    -
    V - This is the second type parameter.""", +
    T - Th\ + is is the first type parameter.
    +
    V - Th\ + is is the second type parameter.
    """, // Signature of method with type parameters """
    public E[]
    methodThatReturnsTypeParameterA(E[] \ + ref="#type-param-E" title="type parameter in TypeParameters">E[] \ e)""", """
    public E[] methodThatReturnsTypePa\ - rameterA((E[] e)
    """, """ @@ -176,7 +178,7 @@ void checkTypeParameters() { """
    <X extends java.lang.Throwable>
    E
    \ + href="#type-param-E" title="type parameter in TypeParameters">E
    \
  • -
    T2 - type 2
    +
    T2 - type 2
    Parameters:
    t1 - param 1
    t3 - param 3
    @@ -92,7 +92,7 @@ public void test() { checkOutput("pkg/C.Nested.html", true, """
    Type Parameters:
    -
    T1 - type 1
    +
    T1 - type 1
    """); } } diff --git a/test/langtools/jdk/javadoc/doclet/testProperty/TestProperty.java b/test/langtools/jdk/javadoc/doclet/testProperty/TestProperty.java index 7ce046c07575c..94ad1a8040f6a 100644 --- a/test/langtools/jdk/javadoc/doclet/testProperty/TestProperty.java +++ b/test/langtools/jdk/javadoc/doclet/testProperty/TestProperty.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -110,7 +110,7 @@ class in pkg">ObjectProperty
    <public final <\ span class="return-type">Obje\ - ctProperty<java.util.List<T>> listProperty<\ /div>
    This is an Object property where the Object is a single List<T>.
    diff --git a/test/langtools/jdk/javadoc/doclet/testRecordTypes/TestRecordTypes.java b/test/langtools/jdk/javadoc/doclet/testRecordTypes/TestRecordTypes.java index f9aa3cfd6fa49..3b6a8a4fc72e4 100644 --- a/test/langtools/jdk/javadoc/doclet/testRecordTypes/TestRecordTypes.java +++ b/test/langtools/jdk/javadoc/doclet/testRecordTypes/TestRecordTypes.java @@ -175,7 +175,7 @@ public record R(int r1) { }"""); """
    Type Parameters:
    -
    T - This is a type parameter.
    +
    T - This is a type parameter.
    Record Components:
    r1 - This is a component.
    """, diff --git a/test/langtools/jdk/javadoc/doclet/testSerializedForm/TestSerializedForm.java b/test/langtools/jdk/javadoc/doclet/testSerializedForm/TestSerializedForm.java index 9bf2ac362c611..af3e36aa7d897 100644 --- a/test/langtools/jdk/javadoc/doclet/testSerializedForm/TestSerializedForm.java +++ b/test/langtools/jdk/javadoc/doclet/testSerializedForm/TestSerializedForm.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -219,6 +219,7 @@ public void test2() { """ Fields[] singleArray""", """ - java.lang.Class<E> someClass"""); + java.lang.Class<E> someClass"""); } } diff --git a/test/langtools/jdk/javadoc/doclet/testThrows/TestThrows.java b/test/langtools/jdk/javadoc/doclet/testThrows/TestThrows.java index ca4592ea5f84c..e4c578578998f 100644 --- a/test/langtools/jdk/javadoc/doclet/testThrows/TestThrows.java +++ b/test/langtools/jdk/javadoc/doclet/testThrows/TestThrows.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -83,7 +83,7 @@ public interface C { """
    Type Parameters:
    -
    T - the throwable
    +
    T - the throwable
    Throws:
    T - if a specific error occurs
    java.lang.Exception - if an exception occurs
    diff --git a/test/langtools/jdk/javadoc/doclet/testTypeParams/TestTypeParameters.java b/test/langtools/jdk/javadoc/doclet/testTypeParams/TestTypeParameters.java index 0d95ee38cdc94..dad610acb302e 100644 --- a/test/langtools/jdk/javadoc/doclet/testTypeParams/TestTypeParameters.java +++ b/test/langtools/jdk/javadoc/doclet/testTypeParams/TestTypeParameters.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 4927167 4974929 6381729 7010344 8025633 8081854 8182765 8187288 8261976 + * @bug 4927167 4974929 6381729 7010344 8025633 8081854 8182765 8187288 8261976 8313931 * @summary When the type parameters are more than 10 characters in length, * make sure there is a line break between type params and return type * in member summary. Also, test for type parameter links in package-summary and @@ -110,10 +110,22 @@ public void test3() {
     <T extends java.lang.Runnable>
    -
     
    """, +
    +
    Generic constructor.
    """, """
    public\  <T extends java.lang.Runnable>\ -  CtorTypeParam()
    """); +  CtorTypeParam()
    """, + """ + T""", + """ +
    Type Parameters:
    +
    T - the type parameter
    """, + """ +
    See Also:
    +
    + """); } } diff --git a/test/langtools/jdk/javadoc/doclet/testTypeParams/pkg/CtorTypeParam.java b/test/langtools/jdk/javadoc/doclet/testTypeParams/pkg/CtorTypeParam.java index a7f2309475d28..690471861dbd9 100644 --- a/test/langtools/jdk/javadoc/doclet/testTypeParams/pkg/CtorTypeParam.java +++ b/test/langtools/jdk/javadoc/doclet/testTypeParams/pkg/CtorTypeParam.java @@ -24,6 +24,12 @@ package pkg; public class CtorTypeParam { + /** + * Generic constructor. {@link T} + * + * @param the type parameter + * @see T link to type parameter + */ public CtorTypeParam() { } } diff --git a/test/langtools/jdk/javadoc/doclet/testUnicode/TestUnicode.java b/test/langtools/jdk/javadoc/doclet/testUnicode/TestUnicode.java index 76008260343ca..cf30488ec7bc2 100644 --- a/test/langtools/jdk/javadoc/doclet/testUnicode/TestUnicode.java +++ b/test/langtools/jdk/javadoc/doclet/testUnicode/TestUnicode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -101,7 +101,7 @@ public class Code<##> { """
    Type Parameters:
    -
    ## - the ##
    +
    ## - the ##
    """.replaceAll("##", chineseElephant), """ From 2b5aec2aad3883d4d407ec3a572f78755d60190d Mon Sep 17 00:00:00 2001 From: Alexander Zvegintsev Date: Fri, 9 Aug 2024 11:28:59 +0000 Subject: [PATCH 253/353] 8338109: java/awt/Mouse/EnterExitEvents/ResizingFrameTest.java duplicate in ProblemList Reviewed-by: aivanov --- 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 293d9d108d32c..6cde711138310 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -375,7 +375,7 @@ java/awt/Modal/MultipleDialogs/MultipleDialogs3Test.java 8198665 macosx-all java/awt/Modal/MultipleDialogs/MultipleDialogs4Test.java 8198665 macosx-all java/awt/Modal/MultipleDialogs/MultipleDialogs5Test.java 8198665 macosx-all java/awt/Mouse/EnterExitEvents/DragWindowOutOfFrameTest.java 8177326 macosx-all -java/awt/Mouse/EnterExitEvents/ResizingFrameTest.java 8005021 macosx-all +java/awt/Mouse/EnterExitEvents/ResizingFrameTest.java 8005021,8332158 macosx-all,linux-x64 java/awt/Mouse/EnterExitEvents/FullscreenEnterEventTest.java 8051455 macosx-all java/awt/Mouse/MouseModifiersUnitTest/MouseModifiersUnitTest_Standard.java 7124407,8302787 macosx-all,windows-all java/awt/Mouse/RemovedComponentMouseListener/RemovedComponentMouseListener.java 8157170 macosx-all @@ -475,7 +475,6 @@ java/awt/Choice/SelectNewItemTest/SelectNewItemTest.java 8324782 macosx-all # Wayland related -java/awt/Mouse/EnterExitEvents/ResizingFrameTest.java 8332158 linux-x64 java/awt/FullScreen/FullscreenWindowProps/FullscreenWindowProps.java 8280991 linux-x64 java/awt/FullScreen/SetFullScreenTest.java 8332155 linux-x64 From 069e0ea69f43960164d3e077d2c7b950cde77927 Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Fri, 9 Aug 2024 12:00:15 +0000 Subject: [PATCH 254/353] 8338064: Give better error for ConcurrentHashTable corruption Reviewed-by: dholmes, shade --- .../share/utilities/concurrentHashTable.hpp | 5 ++ .../utilities/concurrentHashTable.inline.hpp | 6 +- .../StringTableCorruptionTest.java | 59 +++++++++++++++++++ 3 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 test/hotspot/jtreg/runtime/stringtable/StringTableCorruptionTest.java diff --git a/src/hotspot/share/utilities/concurrentHashTable.hpp b/src/hotspot/share/utilities/concurrentHashTable.hpp index 991ea9fe3c609..4e506d5fe84f1 100644 --- a/src/hotspot/share/utilities/concurrentHashTable.hpp +++ b/src/hotspot/share/utilities/concurrentHashTable.hpp @@ -65,6 +65,7 @@ class ConcurrentHashTable : public CHeapObj { // the InternalTable or user-defined memory. class Node { private: + DEBUG_ONLY(size_t _saved_hash); Node * volatile _next; VALUE _value; public: @@ -77,6 +78,10 @@ class ConcurrentHashTable : public CHeapObj { Node* next() const; void set_next(Node* node) { _next = node; } Node* const volatile * next_ptr() { return &_next; } +#ifdef ASSERT + size_t saved_hash() const { return _saved_hash; } + void set_saved_hash(size_t hash) { _saved_hash = hash; } +#endif VALUE* value() { return &_value; } diff --git a/src/hotspot/share/utilities/concurrentHashTable.inline.hpp b/src/hotspot/share/utilities/concurrentHashTable.inline.hpp index 78c7e148bbb3c..f035aeae44847 100644 --- a/src/hotspot/share/utilities/concurrentHashTable.inline.hpp +++ b/src/hotspot/share/utilities/concurrentHashTable.inline.hpp @@ -679,7 +679,9 @@ inline bool ConcurrentHashTable:: // Keep in odd list odd = aux->next_ptr(); } else { - fatal("aux_index does not match even or odd indices"); + const char* msg = "Cannot resize table: Node hash code has changed possibly due to corruption of the contents."; + DEBUG_ONLY(fatal("%s Node hash code changed from " SIZE_FORMAT " to " SIZE_FORMAT, msg, aux->saved_hash(), aux_hash);) + NOT_DEBUG(fatal("%s", msg);) } } aux = aux_next; @@ -892,6 +894,7 @@ inline bool ConcurrentHashTable:: size_t i = 0; uintx hash = lookup_f.get_hash(); Node* new_node = Node::create_node(_context, value, nullptr); + DEBUG_ONLY(new_node->set_saved_hash(hash);) while (true) { { @@ -1117,6 +1120,7 @@ inline bool ConcurrentHashTable:: Bucket* bucket = get_bucket_in(table, hash); assert(!bucket->have_redirect() && !bucket->is_locked(), "bad"); Node* new_node = Node::create_node(_context, value, bucket->first()); + DEBUG_ONLY(new_node->set_saved_hash(hash);) if (!bucket->cas_first(new_node, bucket->first())) { assert(false, "bad"); } diff --git a/test/hotspot/jtreg/runtime/stringtable/StringTableCorruptionTest.java b/test/hotspot/jtreg/runtime/stringtable/StringTableCorruptionTest.java new file mode 100644 index 0000000000000..e4d6a2e5d0f95 --- /dev/null +++ b/test/hotspot/jtreg/runtime/stringtable/StringTableCorruptionTest.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8333356 + * @summary Verify new error message for corrupting string table contents. + * @requires vm.flagless + * @modules java.base/java.lang:open + * @library /test/lib + * @modules java.base/jdk.internal.misc + * @run driver StringTableCorruptionTest test + */ + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; + +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +public class StringTableCorruptionTest { + public static void main(String[] args) throws Exception { + if (args.length > 0) { + ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("--add-opens", "java.base/java.lang=ALL-UNNAMED", + "-XX:-CreateCoredumpOnCrash", "StringTableCorruptionTest"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldContain("Node hash code has changed possibly due to corruption of the contents."); + output.shouldNotHaveExitValue(0); + return; + } + + Field f = String.class.getDeclaredField("value"); + f.setAccessible(true); + f.set("s1".intern(), f.get("s2")); + for (int i = 0; i < 4_000_000; i++) { + ("s_" + i).intern(); + } + } +} From 3cf3f300de1e9d2c8767877ed3a26679e34b7d22 Mon Sep 17 00:00:00 2001 From: Casper Norrbin Date: Fri, 9 Aug 2024 14:32:29 +0000 Subject: [PATCH 255/353] 8330191: Fix typo in precompiled.hpp Reviewed-by: jsjolen, szaldana --- src/hotspot/share/precompiled/precompiled.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/precompiled/precompiled.hpp b/src/hotspot/share/precompiled/precompiled.hpp index c53a78de87bca..07922d129697e 100644 --- a/src/hotspot/share/precompiled/precompiled.hpp +++ b/src/hotspot/share/precompiled/precompiled.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +29,7 @@ // These header files are included in at least 130 C++ files, as of // measurements made in November 2018. This list excludes files named -// *.include.hpp, since including them decreased build performance. +// *.inline.hpp, since including them decreased build performance. #include "classfile/classLoaderData.hpp" #include "classfile/javaClasses.hpp" From 60fa08fcfe5c6551ee3120330ade93e45df618c7 Mon Sep 17 00:00:00 2001 From: Vladimir Kozlov Date: Fri, 9 Aug 2024 17:08:19 +0000 Subject: [PATCH 256/353] 8337797: Additional ExternalAddress cleanup Reviewed-by: adinn, thartmann --- src/hotspot/cpu/aarch64/jniFastGetField_aarch64.cpp | 4 ++-- src/hotspot/cpu/riscv/jniFastGetField_riscv.cpp | 9 ++------- src/hotspot/cpu/x86/assembler_x86.cpp | 1 + src/hotspot/cpu/x86/jniFastGetField_x86_32.cpp | 8 ++++---- src/hotspot/cpu/x86/jniFastGetField_x86_64.cpp | 6 +++--- src/hotspot/cpu/x86/macroAssembler_x86.cpp | 4 ++-- src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp | 4 ++-- src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp | 4 ++-- src/hotspot/cpu/x86/stubGenerator_x86_64_arraycopy.cpp | 2 +- src/hotspot/os_cpu/windows_x86/os_windows_x86.cpp | 4 ++-- 10 files changed, 21 insertions(+), 25 deletions(-) diff --git a/src/hotspot/cpu/aarch64/jniFastGetField_aarch64.cpp b/src/hotspot/cpu/aarch64/jniFastGetField_aarch64.cpp index e79b93651b072..aea268ea94443 100644 --- a/src/hotspot/cpu/aarch64/jniFastGetField_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/jniFastGetField_aarch64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -201,7 +201,7 @@ address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) { { __ enter(); - __ lea(rscratch1, ExternalAddress(slow_case_addr)); + __ lea(rscratch1, RuntimeAddress(slow_case_addr)); __ blr(rscratch1); __ leave(); __ ret(lr); diff --git a/src/hotspot/cpu/riscv/jniFastGetField_riscv.cpp b/src/hotspot/cpu/riscv/jniFastGetField_riscv.cpp index 8423ecad8a3da..f7d702c631069 100644 --- a/src/hotspot/cpu/riscv/jniFastGetField_riscv.cpp +++ b/src/hotspot/cpu/riscv/jniFastGetField_riscv.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved. * Copyright (c) 2020, 2023, Huawei Technologies Co., Ltd. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -173,12 +173,7 @@ address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) { { __ enter(); - ExternalAddress target(slow_case_addr); - __ relocate(target.rspec(), [&] { - int32_t offset; - __ la(t0, target.target(), offset); - __ jalr(t0, offset); - }); + __ rt_call(slow_case_addr); __ leave(); __ ret(); } diff --git a/src/hotspot/cpu/x86/assembler_x86.cpp b/src/hotspot/cpu/x86/assembler_x86.cpp index 001ff472f40bb..207d3fbb61eba 100644 --- a/src/hotspot/cpu/x86/assembler_x86.cpp +++ b/src/hotspot/cpu/x86/assembler_x86.cpp @@ -1780,6 +1780,7 @@ void Assembler::call(Register dst) { void Assembler::call(Address adr) { + assert(!adr._rspec.reloc()->is_data(), "should not use ExternalAddress for call"); InstructionMark im(this); prefix(adr); emit_int8((unsigned char)0xFF); diff --git a/src/hotspot/cpu/x86/jniFastGetField_x86_32.cpp b/src/hotspot/cpu/x86/jniFastGetField_x86_32.cpp index 34be2a61b5a47..52e4388c5d249 100644 --- a/src/hotspot/cpu/x86/jniFastGetField_x86_32.cpp +++ b/src/hotspot/cpu/x86/jniFastGetField_x86_32.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -138,7 +138,7 @@ address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) { default: ShouldNotReachHere(); } // tail call - __ jump (ExternalAddress(slow_case_addr)); + __ jump (RuntimeAddress(slow_case_addr)); __ flush (); @@ -251,7 +251,7 @@ address JNI_FastGetField::generate_fast_get_long_field() { __ pop (rsi); address slow_case_addr = jni_GetLongField_addr();; // tail call - __ jump (ExternalAddress(slow_case_addr)); + __ jump (RuntimeAddress(slow_case_addr)); __ flush (); @@ -350,7 +350,7 @@ address JNI_FastGetField::generate_fast_get_float_field0(BasicType type) { default: ShouldNotReachHere(); } // tail call - __ jump (ExternalAddress(slow_case_addr)); + __ jump (RuntimeAddress(slow_case_addr)); __ flush (); diff --git a/src/hotspot/cpu/x86/jniFastGetField_x86_64.cpp b/src/hotspot/cpu/x86/jniFastGetField_x86_64.cpp index 4506205c259fb..e94b7d12b0b3c 100644 --- a/src/hotspot/cpu/x86/jniFastGetField_x86_64.cpp +++ b/src/hotspot/cpu/x86/jniFastGetField_x86_64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -118,7 +118,7 @@ address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) { default: break; } // tail call - __ jump (ExternalAddress(slow_case_addr), rscratch1); + __ jump (RuntimeAddress(slow_case_addr), rscratch1); __ flush (); @@ -206,7 +206,7 @@ address JNI_FastGetField::generate_fast_get_float_field0(BasicType type) { default: break; } // tail call - __ jump (ExternalAddress(slow_case_addr), rscratch1); + __ jump (RuntimeAddress(slow_case_addr), rscratch1); __ flush (); diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp index affd18f937ca8..c8234d6b9b88b 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp @@ -2329,7 +2329,7 @@ void MacroAssembler::incrementl(Address dst, int value) { void MacroAssembler::jump(AddressLiteral dst, Register rscratch) { assert(rscratch != noreg || always_reachable(dst), "missing"); - + assert(!dst.rspec().reloc()->is_data(), "should not use ExternalAddress for jump"); if (reachable(dst)) { jmp_literal(dst.target(), dst.rspec()); } else { @@ -2340,7 +2340,7 @@ void MacroAssembler::jump(AddressLiteral dst, Register rscratch) { void MacroAssembler::jump_cc(Condition cc, AddressLiteral dst, Register rscratch) { assert(rscratch != noreg || always_reachable(dst), "missing"); - + assert(!dst.rspec().reloc()->is_data(), "should not use ExternalAddress for jump_cc"); if (reachable(dst)) { InstructionMark im(this); relocate(dst.reloc()); diff --git a/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp b/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp index 80be7c7d5b642..d313c1b216a40 100644 --- a/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp +++ b/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp @@ -704,10 +704,10 @@ static void range_check(MacroAssembler* masm, Register pc_reg, Register temp_reg address code_start, address code_end, Label& L_ok) { Label L_fail; - __ lea(temp_reg, ExternalAddress(code_start)); + __ lea(temp_reg, AddressLiteral(code_start, relocInfo::none)); __ cmpptr(pc_reg, temp_reg); __ jcc(Assembler::belowEqual, L_fail); - __ lea(temp_reg, ExternalAddress(code_end)); + __ lea(temp_reg, AddressLiteral(code_end, relocInfo::none)); __ cmpptr(pc_reg, temp_reg); __ jcc(Assembler::below, L_ok); __ bind(L_fail); diff --git a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp index f2488ef4e7445..d27b1d141fc29 100644 --- a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp +++ b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp @@ -824,10 +824,10 @@ static void range_check(MacroAssembler* masm, Register pc_reg, Register temp_reg address code_start, address code_end, Label& L_ok) { Label L_fail; - __ lea(temp_reg, ExternalAddress(code_start)); + __ lea(temp_reg, AddressLiteral(code_start, relocInfo::none)); __ cmpptr(pc_reg, temp_reg); __ jcc(Assembler::belowEqual, L_fail); - __ lea(temp_reg, ExternalAddress(code_end)); + __ lea(temp_reg, AddressLiteral(code_end, relocInfo::none)); __ cmpptr(pc_reg, temp_reg); __ jcc(Assembler::below, L_ok); __ bind(L_fail); diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_arraycopy.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_arraycopy.cpp index d8f7a6b272bc9..5b316881d0346 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_arraycopy.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_arraycopy.cpp @@ -215,7 +215,7 @@ void StubGenerator::array_overlap_test(address no_overlap_target, Label* NOLp, A __ cmpptr(to, from); __ lea(end_from, Address(from, count, sf, 0)); if (NOLp == nullptr) { - ExternalAddress no_overlap(no_overlap_target); + RuntimeAddress no_overlap(no_overlap_target); __ jump_cc(Assembler::belowEqual, no_overlap); __ cmpptr(to, end_from); __ jump_cc(Assembler::aboveEqual, no_overlap); diff --git a/src/hotspot/os_cpu/windows_x86/os_windows_x86.cpp b/src/hotspot/os_cpu/windows_x86/os_windows_x86.cpp index 7e0814c014bec..62022d780a20b 100644 --- a/src/hotspot/os_cpu/windows_x86/os_windows_x86.cpp +++ b/src/hotspot/os_cpu/windows_x86/os_windows_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -180,7 +180,7 @@ bool os::win32::register_code_area(char *low, char *high) { MacroAssembler* masm = new MacroAssembler(&cb); pDCD = (pDynamicCodeData) masm->pc(); - masm->jump(ExternalAddress((address)&HandleExceptionFromCodeCache), rscratch1); + masm->jump(RuntimeAddress((address)&HandleExceptionFromCodeCache), rscratch1); masm->flush(); // Create an Unwind Structure specifying no unwind info From 358d77dafbe0e35d5b20340fccddc0fb8f3db82a Mon Sep 17 00:00:00 2001 From: Dmitry Chuyko Date: Fri, 9 Aug 2024 17:56:37 +0000 Subject: [PATCH 257/353] 8337657: AArch64: No need for acquire fence in safepoint poll during JNI calls Reviewed-by: phh --- src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp | 12 ++---------- .../aarch64/templateInterpreterGenerator_aarch64.cpp | 11 ++--------- 2 files changed, 4 insertions(+), 19 deletions(-) diff --git a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp index 65c026b95abbd..8ce4230baa2b4 100644 --- a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp @@ -1883,16 +1883,8 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, // Check for safepoint operation in progress and/or pending suspend requests. { - // We need an acquire here to ensure that any subsequent load of the - // global SafepointSynchronize::_state flag is ordered after this load - // of the thread-local polling word. We don't want this poll to - // return false (i.e. not safepointing) and a later poll of the global - // SafepointSynchronize::_state spuriously to return true. - // - // This is to avoid a race when we're in a native->Java transition - // racing the code which wakes up from a safepoint. - - __ safepoint_poll(safepoint_in_progress, true /* at_return */, true /* acquire */, false /* in_nmethod */); + // No need for acquire as Java threads always disarm themselves. + __ safepoint_poll(safepoint_in_progress, true /* at_return */, false /* acquire */, false /* in_nmethod */); __ ldrw(rscratch1, Address(rthread, JavaThread::suspend_flags_offset())); __ cbnzw(rscratch1, safepoint_in_progress); __ bind(safepoint_in_progress_done); diff --git a/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp index d639d9cf17ee5..ed2450a9110e5 100644 --- a/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp @@ -1413,15 +1413,8 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { { Label L, Continue; - // We need an acquire here to ensure that any subsequent load of the - // global SafepointSynchronize::_state flag is ordered after this load - // of the thread-local polling word. We don't want this poll to - // return false (i.e. not safepointing) and a later poll of the global - // SafepointSynchronize::_state spuriously to return true. - // - // This is to avoid a race when we're in a native->Java transition - // racing the code which wakes up from a safepoint. - __ safepoint_poll(L, true /* at_return */, true /* acquire */, false /* in_nmethod */); + // No need for acquire as Java threads always disarm themselves. + __ safepoint_poll(L, true /* at_return */, false /* acquire */, false /* in_nmethod */); __ ldrw(rscratch2, Address(rthread, JavaThread::suspend_flags_offset())); __ cbz(rscratch2, Continue); __ bind(L); From 6a3d045221c338fefec9bd59245324eae60b156b Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Sun, 11 Aug 2024 18:34:18 +0000 Subject: [PATCH 258/353] 8337709: Use allocated states for chunking large array processing Reviewed-by: iwalulya, tschatzl --- .../share/gc/g1/g1ParScanThreadState.cpp | 90 +++++++---- .../share/gc/g1/g1ParScanThreadState.hpp | 12 +- .../share/gc/shared/partialArrayState.cpp | 152 ++++++++++++++++++ .../share/gc/shared/partialArrayState.hpp | 136 ++++++++++++++++ .../gc/shared/partialArrayTaskStepper.cpp | 6 +- .../gc/shared/partialArrayTaskStepper.hpp | 59 ++++--- .../shared/partialArrayTaskStepper.inline.hpp | 71 +++----- src/hotspot/share/gc/shared/taskqueue.hpp | 21 ++- .../shared/test_partialArrayTaskStepper.cpp | 42 ++--- 9 files changed, 444 insertions(+), 145 deletions(-) create mode 100644 src/hotspot/share/gc/shared/partialArrayState.cpp create mode 100644 src/hotspot/share/gc/shared/partialArrayState.hpp diff --git a/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp b/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp index e4ac20ca7ea92..f81c3241a1a90 100644 --- a/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp +++ b/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp @@ -35,6 +35,7 @@ #include "gc/g1/g1Trace.hpp" #include "gc/g1/g1YoungGCAllocationFailureInjector.inline.hpp" #include "gc/shared/continuationGCSupport.inline.hpp" +#include "gc/shared/partialArrayState.hpp" #include "gc/shared/partialArrayTaskStepper.inline.hpp" #include "gc/shared/preservedMarks.inline.hpp" #include "gc/shared/stringdedup/stringDedup.hpp" @@ -43,6 +44,7 @@ #include "oops/access.inline.hpp" #include "oops/oop.inline.hpp" #include "runtime/atomic.hpp" +#include "runtime/mutexLocker.hpp" #include "runtime/prefetch.inline.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" @@ -61,7 +63,8 @@ G1ParScanThreadState::G1ParScanThreadState(G1CollectedHeap* g1h, uint worker_id, uint num_workers, G1CollectionSet* collection_set, - G1EvacFailureRegions* evac_failure_regions) + G1EvacFailureRegions* evac_failure_regions, + PartialArrayStateAllocator* pas_allocator) : _g1h(g1h), _task_queue(g1h->task_queue(worker_id)), _rdc_local_qset(rdcqs), @@ -80,8 +83,8 @@ G1ParScanThreadState::G1ParScanThreadState(G1CollectedHeap* g1h, _surviving_young_words(nullptr), _surviving_words_length(collection_set->young_region_length() + 1), _old_gen_is_full(false), - _partial_objarray_chunk_size(ParGCArrayScanChunk), - _partial_array_stepper(num_workers), + _partial_array_state_allocator(pas_allocator), + _partial_array_stepper(num_workers, ParGCArrayScanChunk), _string_dedup_requests(), _max_num_optional_regions(collection_set->optional_region_length()), _numa(g1h->numa()), @@ -169,9 +172,9 @@ void G1ParScanThreadState::verify_task(oop* task) const { "task=" PTR_FORMAT " p=" PTR_FORMAT, p2i(task), p2i(p)); } -void G1ParScanThreadState::verify_task(PartialArrayScanTask task) const { +void G1ParScanThreadState::verify_task(PartialArrayState* task) const { // Must be in the collection set--it's already been copied. - oop p = task.to_source_array(); + oop p = task->source(); assert(_g1h->is_in_cset(p), "p=" PTR_FORMAT, p2i(p)); } @@ -180,8 +183,8 @@ void G1ParScanThreadState::verify_task(ScannerTask task) const { verify_task(task.to_narrow_oop_ptr()); } else if (task.is_oop_ptr()) { verify_task(task.to_oop_ptr()); - } else if (task.is_partial_array_task()) { - verify_task(task.to_partial_array_task()); + } else if (task.is_partial_array_state()) { + verify_task(task.to_partial_array_state()); } else { ShouldNotReachHere(); } @@ -223,34 +226,39 @@ void G1ParScanThreadState::do_oop_evac(T* p) { } MAYBE_INLINE_EVACUATION -void G1ParScanThreadState::do_partial_array(PartialArrayScanTask task) { - oop from_obj = task.to_source_array(); +void G1ParScanThreadState::do_partial_array(PartialArrayState* state) { + oop to_obj = state->destination(); +#ifdef ASSERT + oop from_obj = state->source(); assert(_g1h->is_in_reserved(from_obj), "must be in heap."); assert(from_obj->is_objArray(), "must be obj array"); assert(from_obj->is_forwarded(), "must be forwarded"); - - oop to_obj = from_obj->forwardee(); assert(from_obj != to_obj, "should not be chunking self-forwarded objects"); assert(to_obj->is_objArray(), "must be obj array"); +#endif // ASSERT + objArrayOop to_array = objArrayOop(to_obj); - PartialArrayTaskStepper::Step step - = _partial_array_stepper.next(objArrayOop(from_obj), - to_array, - _partial_objarray_chunk_size); - for (uint i = 0; i < step._ncreate; ++i) { - push_on_queue(ScannerTask(PartialArrayScanTask(from_obj))); + // Claim a chunk and get number of additional tasks to enqueue. + PartialArrayTaskStepper::Step step = _partial_array_stepper.next(state); + // Push any additional partial scan tasks needed. Pushed before processing + // the claimed chunk to allow other workers to steal while we're processing. + if (step._ncreate > 0) { + state->add_references(step._ncreate); + for (uint i = 0; i < step._ncreate; ++i) { + push_on_queue(ScannerTask(state)); + } } 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. + // Process claimed task. to_array->oop_iterate_range(&_scanner, - step._index, - step._index + _partial_objarray_chunk_size); + checked_cast(step._index), + checked_cast(step._index + _partial_array_stepper.chunk_size())); + // Release reference to the state, now that we're done with it. + _partial_array_state_allocator->release(_worker_id, state); } MAYBE_INLINE_EVACUATION @@ -260,20 +268,30 @@ void G1ParScanThreadState::start_partial_objarray(G1HeapRegionAttr dest_attr, assert(from_obj->is_objArray(), "precondition"); assert(from_obj->is_forwarded(), "precondition"); assert(from_obj->forwardee() == to_obj, "precondition"); - assert(from_obj != to_obj, "should not be scanning self-forwarded objects"); assert(to_obj->is_objArray(), "precondition"); objArrayOop to_array = objArrayOop(to_obj); - PartialArrayTaskStepper::Step step - = _partial_array_stepper.start(objArrayOop(from_obj), - to_array, - _partial_objarray_chunk_size); + size_t array_length = to_array->length(); + PartialArrayTaskStepper::Step step = _partial_array_stepper.start(array_length); // Push any needed partial scan tasks. Pushed before processing the // initial chunk to allow other workers to steal while we're processing. - for (uint i = 0; i < step._ncreate; ++i) { - push_on_queue(ScannerTask(PartialArrayScanTask(from_obj))); + if (step._ncreate > 0) { + assert(step._index < array_length, "invariant"); + assert(((array_length - step._index) % _partial_array_stepper.chunk_size()) == 0, + "invariant"); + PartialArrayState* state = + _partial_array_state_allocator->allocate(_worker_id, + from_obj, to_obj, + step._index, + array_length, + step._ncreate); + for (uint i = 0; i < step._ncreate; ++i) { + push_on_queue(ScannerTask(state)); + } + } else { + assert(step._index == array_length, "invariant"); } // Skip the card enqueue iff the object (to_array) is in survivor region. @@ -284,9 +302,8 @@ void G1ParScanThreadState::start_partial_objarray(G1HeapRegionAttr dest_attr, 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 - // module. The length of to_array is not correct, but fortunately - // the iteration ignores that length field and relies on start/end. - to_array->oop_iterate_range(&_scanner, 0, step._index); + // module. + to_array->oop_iterate_range(&_scanner, 0, checked_cast(step._index)); } MAYBE_INLINE_EVACUATION @@ -297,7 +314,7 @@ void G1ParScanThreadState::dispatch_task(ScannerTask task) { } else if (task.is_oop_ptr()) { do_oop_evac(task.to_oop_ptr()); } else { - do_partial_array(task.to_partial_array_task()); + do_partial_array(task.to_partial_array_state()); } } @@ -582,7 +599,8 @@ G1ParScanThreadState* G1ParScanThreadStateSet::state_for_worker(uint worker_id) worker_id, _num_workers, _collection_set, - _evac_failure_regions); + _evac_failure_regions, + &_partial_array_state_allocator); } return _states[worker_id]; } @@ -715,7 +733,9 @@ G1ParScanThreadStateSet::G1ParScanThreadStateSet(G1CollectedHeap* g1h, _surviving_young_words_total(NEW_C_HEAP_ARRAY(size_t, collection_set->young_region_length() + 1, mtGC)), _num_workers(num_workers), _flushed(false), - _evac_failure_regions(evac_failure_regions) { + _evac_failure_regions(evac_failure_regions), + _partial_array_state_allocator(num_workers) +{ _preserved_marks_set.init(num_workers); for (uint i = 0; i < num_workers; ++i) { _states[i] = nullptr; diff --git a/src/hotspot/share/gc/g1/g1ParScanThreadState.hpp b/src/hotspot/share/gc/g1/g1ParScanThreadState.hpp index 24ca682e14118..1cfd6fca08a6f 100644 --- a/src/hotspot/share/gc/g1/g1ParScanThreadState.hpp +++ b/src/hotspot/share/gc/g1/g1ParScanThreadState.hpp @@ -32,6 +32,7 @@ #include "gc/shared/ageTable.hpp" #include "gc/shared/copyFailedInfo.hpp" #include "gc/shared/gc_globals.hpp" +#include "gc/shared/partialArrayState.hpp" #include "gc/shared/partialArrayTaskStepper.hpp" #include "gc/shared/preservedMarks.hpp" #include "gc/shared/stringdedup/stringDedup.hpp" @@ -87,7 +88,8 @@ class G1ParScanThreadState : public CHeapObj { // available for allocation. bool _old_gen_is_full; // Size (in elements) of a partial objArray task chunk. - int _partial_objarray_chunk_size; + size_t _partial_objarray_chunk_size; + PartialArrayStateAllocator* _partial_array_state_allocator; PartialArrayTaskStepper _partial_array_stepper; StringDedup::Requests _string_dedup_requests; @@ -129,7 +131,8 @@ class G1ParScanThreadState : public CHeapObj { uint worker_id, uint num_workers, G1CollectionSet* collection_set, - G1EvacFailureRegions* evac_failure_regions); + G1EvacFailureRegions* evac_failure_regions, + PartialArrayStateAllocator* partial_array_state_allocator); virtual ~G1ParScanThreadState(); void set_ref_discoverer(ReferenceDiscoverer* rd) { _scanner.set_ref_discoverer(rd); } @@ -140,7 +143,7 @@ class G1ParScanThreadState : public CHeapObj { void verify_task(narrowOop* task) const NOT_DEBUG_RETURN; void verify_task(oop* task) const NOT_DEBUG_RETURN; - void verify_task(PartialArrayScanTask task) const NOT_DEBUG_RETURN; + void verify_task(PartialArrayState* task) const NOT_DEBUG_RETURN; void verify_task(ScannerTask task) const NOT_DEBUG_RETURN; void push_on_queue(ScannerTask task); @@ -169,7 +172,7 @@ class G1ParScanThreadState : public CHeapObj { size_t flush_stats(size_t* surviving_young_words, uint num_workers, BufferNodeList* buffer_log); private: - void do_partial_array(PartialArrayScanTask task); + void do_partial_array(PartialArrayState* state); void start_partial_objarray(G1HeapRegionAttr dest_dir, oop from, oop to); HeapWord* allocate_copy_slow(G1HeapRegionAttr* dest_attr, @@ -252,6 +255,7 @@ class G1ParScanThreadStateSet : public StackObj { uint _num_workers; bool _flushed; G1EvacFailureRegions* _evac_failure_regions; + PartialArrayStateAllocator _partial_array_state_allocator; public: G1ParScanThreadStateSet(G1CollectedHeap* g1h, diff --git a/src/hotspot/share/gc/shared/partialArrayState.cpp b/src/hotspot/share/gc/shared/partialArrayState.cpp new file mode 100644 index 0000000000000..583c5dede4026 --- /dev/null +++ b/src/hotspot/share/gc/shared/partialArrayState.cpp @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "gc/shared/partialArrayState.hpp" +#include "memory/allocation.inline.hpp" +#include "memory/arena.hpp" +#include "nmt/memflags.hpp" +#include "oops/oopsHierarchy.hpp" +#include "runtime/atomic.hpp" +#include "runtime/orderAccess.hpp" +#include "utilities/debug.hpp" +#include "utilities/globalDefinitions.hpp" +#include "utilities/macros.hpp" +#include + +PartialArrayState::PartialArrayState(oop src, oop dst, + size_t index, size_t length, + size_t initial_refcount) + : _source(src), + _destination(dst), + _length(length), + _index(index), + _refcount(initial_refcount) +{ + assert(index <= length, "precondition"); +} + +void PartialArrayState::add_references(size_t count) { + size_t new_count = Atomic::add(&_refcount, count, memory_order_relaxed); + assert(new_count >= count, "reference count overflow"); +} + +class PartialArrayStateAllocator::Impl : public CHeapObj { + struct FreeListEntry; + + Arena* _arenas; + FreeListEntry** _free_lists; + uint _num_workers; + +public: + Impl(uint num_workers); + ~Impl(); + + NONCOPYABLE(Impl); + + PartialArrayState* allocate(uint worker_id, + oop src, oop dst, + size_t index, size_t length, + size_t initial_refcount); + void release(uint worker_id, PartialArrayState* state); +}; + +struct PartialArrayStateAllocator::Impl::FreeListEntry { + FreeListEntry* _next; + + FreeListEntry(FreeListEntry* next) : _next(next) {} + ~FreeListEntry() = default; + + NONCOPYABLE(FreeListEntry); +}; + +PartialArrayStateAllocator::Impl::Impl(uint num_workers) + : _arenas(NEW_C_HEAP_ARRAY(Arena, num_workers, mtGC)), + _free_lists(NEW_C_HEAP_ARRAY(FreeListEntry*, num_workers, mtGC)), + _num_workers(num_workers) +{ + for (uint i = 0; i < _num_workers; ++i) { + ::new (&_arenas[i]) Arena(mtGC); + _free_lists[i] = nullptr; + } +} + +PartialArrayStateAllocator::Impl::~Impl() { + // We don't need to clean up the free lists. Deallocating the entries + // does nothing, since we're using arena allocation. Instead, leave it + // to the arena destructor to release the memory. + FREE_C_HEAP_ARRAY(FreeListEntry*, _free_lists); + for (uint i = 0; i < _num_workers; ++i) { + _arenas[i].~Arena(); + } +} + +PartialArrayState* PartialArrayStateAllocator::Impl::allocate(uint worker_id, + oop src, oop dst, + size_t index, + size_t length, + size_t initial_refcount) { + void* p; + FreeListEntry* head = _free_lists[worker_id]; + if (head == nullptr) { + p = NEW_ARENA_OBJ(&_arenas[worker_id], PartialArrayState); + } else { + _free_lists[worker_id] = head->_next; + head->~FreeListEntry(); + p = head; + } + return ::new (p) PartialArrayState(src, dst, index, length, initial_refcount); +} + +void PartialArrayStateAllocator::Impl::release(uint worker_id, PartialArrayState* state) { + size_t refcount = Atomic::sub(&state->_refcount, size_t(1), memory_order_release); + if (refcount != 0) { + assert(refcount + 1 != 0, "refcount underflow"); + } else { + OrderAccess::acquire(); + state->~PartialArrayState(); + _free_lists[worker_id] = ::new (state) FreeListEntry(_free_lists[worker_id]); + } +} + +PartialArrayStateAllocator::PartialArrayStateAllocator(uint num_workers) + : _impl(new Impl(num_workers)) +{} + +PartialArrayStateAllocator::~PartialArrayStateAllocator() { + delete _impl; +} + +PartialArrayState* PartialArrayStateAllocator::allocate(uint worker_id, + oop src, oop dst, + size_t index, + size_t length, + size_t initial_refcount) { + return _impl->allocate(worker_id, src, dst, index, length, initial_refcount); +} + +void PartialArrayStateAllocator::release(uint worker_id, PartialArrayState* state) { + _impl->release(worker_id, state); +} + diff --git a/src/hotspot/share/gc/shared/partialArrayState.hpp b/src/hotspot/share/gc/shared/partialArrayState.hpp new file mode 100644 index 0000000000000..f3bfc3ed8b859 --- /dev/null +++ b/src/hotspot/share/gc/shared/partialArrayState.hpp @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_GC_SHARED_PARTIALARRAYSTATE_HPP +#define SHARE_GC_SHARED_PARTIALARRAYSTATE_HPP + +#include "oops/oopsHierarchy.hpp" +#include "utilities/globalDefinitions.hpp" +#include "utilities/macros.hpp" + +class PartialArrayStateAllocator; + +// Instances of this class are used to represent processing progress for an +// array task in a taskqueue. When a sufficiently large array needs to be +// processed, such that it is desirable to split up the processing into +// parallelizable subtasks, a state object is allocated for the array. +// Multiple tasks referring to the state can then be added to the taskqueue +// for later processing, either by the current thread or by some other thread +// that steals one of those tasks. +// +// Processing a state involves using the state to claim a segment of the +// array, and processing that segment. Claiming is done by atomically +// incrementing the index, thereby claiming the segment from the old to new +// index values. New tasks should also be added as needed to ensure the +// entire array will be processed. A PartialArrayTaskStepper can be used to +// help with this. +// +// States are allocated and released using a PartialArrayStateAllocator. +// States are reference counted to aid in that management. Each task +// referring to a given state that is added to a taskqueue must increase the +// reference count by one. When the processing of a task referring to a state +// is complete, the reference count must be decreased by one. When the +// reference count reaches zero the state should be released to the allocator +// for later reuse. +class PartialArrayState { + oop _source; + oop _destination; + size_t _length; + volatile size_t _index; + volatile size_t _refcount; + + friend class PartialArrayStateAllocator; + + PartialArrayState(oop src, oop dst, + size_t index, size_t length, + size_t initial_refcount); + ~PartialArrayState() = default; + + NONCOPYABLE(PartialArrayState); + +public: + // Add count references, one per referring task being added to a taskqueue. + void add_references(size_t count); + + // The source array oop. + oop source() const { return _source; } + + // The destination array oop. In some circumstances the source and + // destination may be the same. + oop destination() const { return _destination; } + + // The length of the array oop. + size_t length() const { return _length; } + + // A pointer to the start index for the next segment to process, for atomic + // update. + volatile size_t* index_addr() { return &_index; } +}; + +// This class provides memory management for PartialArrayStates. +// +// States are initially allocated from a set of arenas owned by the allocator. +// This allows the entire set of allocated states to be discarded without the +// need to keep track of or find them under some circumstances. For example, +// if G1 concurrent marking is aborted and needs to restart because of a full +// marking queue, the queue doesn't need to be searched for tasks referring to +// states to allow releasing them. Instead the queue contents can just be +// discarded, and the memory for the no longer referenced states will +// eventually be reclaimed when the arenas are reset. +// +// A set of free-lists is placed in front of the arena allocators. This +// causes the maximum number of allocated states to be based on the number of +// in-progress arrays, rather than the total number of arrays that need to be +// processed. The use of free-list allocators is the reason for reference +// counting states. +// +// The arena and free-list to use for an allocation operation is designated by +// the worker_id used in the operation. This avoids locking and such on those +// data structures, at the cost of possibly doing more total arena allocation +// that would be needed with a single shared arena and free-list. +class PartialArrayStateAllocator { + class Impl; + Impl* _impl; + +public: + PartialArrayStateAllocator(uint num_workers); + ~PartialArrayStateAllocator(); + + NONCOPYABLE(PartialArrayStateAllocator); + + // Create a new state, obtaining the memory for it from the free-list or + // arena associated with worker_id. + PartialArrayState* allocate(uint worker_id, + oop src, oop dst, + size_t index, size_t length, + size_t initial_refcount); + + // Decrement the state's refcount. If the new refcount is zero, add the + // state to the free-list associated with worker_id. The state must have + // been allocated by this allocator, but that allocation doesn't need to + // have been associated with worker_id. + void release(uint worker_id, PartialArrayState* state); +}; + +#endif // SHARE_GC_SHARED_PARTIALARRAYSTATE_HPP diff --git a/src/hotspot/share/gc/shared/partialArrayTaskStepper.cpp b/src/hotspot/share/gc/shared/partialArrayTaskStepper.cpp index ed52d7abff18c..6faa162ac7bed 100644 --- a/src/hotspot/share/gc/shared/partialArrayTaskStepper.cpp +++ b/src/hotspot/share/gc/shared/partialArrayTaskStepper.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "gc/shared/partialArrayTaskStepper.hpp" #include "oops/arrayOop.hpp" +#include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/powerOfTwo.hpp" @@ -48,7 +49,8 @@ static uint compute_task_fanout(uint task_limit) { return result; } -PartialArrayTaskStepper::PartialArrayTaskStepper(uint n_workers) : +PartialArrayTaskStepper::PartialArrayTaskStepper(uint n_workers, size_t chunk_size) : + _chunk_size(chunk_size), _task_limit(compute_task_limit(n_workers)), _task_fanout(compute_task_fanout(_task_limit)) {} diff --git a/src/hotspot/share/gc/shared/partialArrayTaskStepper.hpp b/src/hotspot/share/gc/shared/partialArrayTaskStepper.hpp index aec993f907ce6..a68d9bd361209 100644 --- a/src/hotspot/share/gc/shared/partialArrayTaskStepper.hpp +++ b/src/hotspot/share/gc/shared/partialArrayTaskStepper.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,55 +28,52 @@ #include "oops/arrayOop.hpp" #include "utilities/globalDefinitions.hpp" -// Helper for handling PartialArrayTasks. +class PartialArrayState; + +// Helper for partial array chunking tasks. // // When an array is large, we want to split it up into chunks that can be -// processed in parallel. Each task (implicitly) represents such a chunk. -// We can enqueue multiple tasks at the same time. We want to enqueue -// enough tasks to benefit from the available parallelism, while not so many -// as to substantially expand the task queues. -// -// A task directly refers to the from-space array. The from-space array's -// forwarding pointer refers to the associated to-space array, and its -// length is the actual length. The to-space array's length field is used to -// indicate processing progress. It is the starting index of the next chunk -// to process, or equals the actual length when there are no more chunks to -// be processed. +// processed in parallel. Each task (implicitly) represents such a chunk. We +// can enqueue multiple tasks at the same time. We want to enqueue enough +// tasks to benefit from the available parallelism, while not so many as to +// substantially expand the task queues. class PartialArrayTaskStepper { public: - PartialArrayTaskStepper(uint n_workers); + PartialArrayTaskStepper(uint n_workers, size_t chunk_size); struct Step { - int _index; // Array index for the step. + size_t _index; // Array index for the step. uint _ncreate; // Number of new tasks to create. }; - // Set to's length to the end of the initial chunk, which is the start of - // the first partial task if the array is large enough to need splitting. - // Returns a Step with _index being that index and _ncreate being the - // initial number of partial tasks to enqueue. - inline Step start(arrayOop from, arrayOop to, int chunk_size) const; + // Called with the length of the array to be processed. Returns a Step with + // _index being the end of the initial chunk, which the caller should + // process. This is also the starting index for the next chunk to process. + // The _ncreate is the number of tasks to enqueue to continue processing the + // array. If _ncreate is zero then _index will be length. + inline Step start(size_t length) const; + + // Atomically increment state's index by chunk_size() to claim the next + // chunk. Returns a Step with _index being the starting index of the + // claimed chunk and _ncreate being the number of additional partial tasks + // to enqueue. + inline Step next(PartialArrayState* state) const; - // Increment to's length by chunk_size to claim the next chunk. Returns a - // Step with _index being the starting index of the claimed chunk and - // _ncreate being the number of additional partial tasks to enqueue. - // precondition: chunk_size must be the same as used to start the task sequence. - inline Step next(arrayOop from, arrayOop to, int chunk_size) const; + // The size of chunks to claim for each task. + inline size_t chunk_size() const; class TestSupport; // For unit tests private: + // Size (number of elements) of a chunk to process. + size_t _chunk_size; // Limit on the number of partial array tasks to create for a given array. uint _task_limit; // Maximum number of new tasks to create when processing an existing task. uint _task_fanout; - // Split start/next into public part dealing with oops and private - // impl dealing with lengths and pointers to lengths, for unit testing. - // length is the actual length obtained from the from-space object. - // to_length_addr is the address of the to-space object's length value. - inline Step start_impl(int length, int* to_length_addr, int chunk_size) const; - inline Step next_impl(int length, int* to_length_addr, int chunk_size) const; + // For unit tests. + inline Step next_impl(size_t length, volatile size_t* index_addr) const; }; #endif // SHARE_GC_SHARED_PARTIALARRAYTASKSTEPPER_HPP diff --git a/src/hotspot/share/gc/shared/partialArrayTaskStepper.inline.hpp b/src/hotspot/share/gc/shared/partialArrayTaskStepper.inline.hpp index aa9a02c49025a..1d43578b5fea5 100644 --- a/src/hotspot/share/gc/shared/partialArrayTaskStepper.inline.hpp +++ b/src/hotspot/share/gc/shared/partialArrayTaskStepper.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,66 +25,46 @@ #ifndef SHARE_GC_SHARED_PARTIALARRAYTASKSTEPPER_INLINE_HPP #define SHARE_GC_SHARED_PARTIALARRAYTASKSTEPPER_INLINE_HPP +#include "gc/shared/partialArrayState.hpp" #include "gc/shared/partialArrayTaskStepper.hpp" - -#include "oops/arrayOop.hpp" #include "runtime/atomic.hpp" +#include "utilities/checkedCast.hpp" +#include "utilities/debug.hpp" -PartialArrayTaskStepper::Step -PartialArrayTaskStepper::start_impl(int length, - int* to_length_addr, - int chunk_size) const { - assert(chunk_size > 0, "precondition"); - - int end = length % chunk_size; // End of initial chunk. - // Set to's length to end of initial chunk. Partial tasks use that length - // field as the start of the next chunk to process. Must be done before - // enqueuing partial scan tasks, in case other threads steal any of those - // tasks. - // - // The value of end can be 0, either because of a 0-length array or - // because length is a multiple of the chunk size. Both of those are - // relatively rare and handled in the normal course of the iteration, so - // not worth doing anything special about here. - *to_length_addr = end; +size_t PartialArrayTaskStepper::chunk_size() const { + return _chunk_size; +} +PartialArrayTaskStepper::Step +PartialArrayTaskStepper::start(size_t length) const { + size_t end = length % _chunk_size; // End of initial chunk. // If the initial chunk is the complete array, then don't need any partial // tasks. Otherwise, start with just one partial task; see new task // calculation in next(). - Step result = { end, (length > end) ? 1u : 0u }; - return result; + return Step{ end, (length > end) ? 1u : 0u }; } PartialArrayTaskStepper::Step -PartialArrayTaskStepper::start(arrayOop from, arrayOop to, int chunk_size) const { - return start_impl(from->length(), to->length_addr(), chunk_size); -} - -PartialArrayTaskStepper::Step -PartialArrayTaskStepper::next_impl(int length, - int* to_length_addr, - int chunk_size) const { - assert(chunk_size > 0, "precondition"); - - // The start of the next task is in the length field of the to-space object. +PartialArrayTaskStepper::next_impl(size_t length, volatile size_t* index_addr) const { + // The start of the next task is in the state's index. // Atomically increment by the chunk size to claim the associated chunk. // Because we limit the number of enqueued tasks to being no more than the // number of remaining chunks to process, we can use an atomic add for the // claim, rather than a CAS loop. - int start = Atomic::fetch_then_add(to_length_addr, - chunk_size, - memory_order_relaxed); + size_t start = Atomic::fetch_then_add(index_addr, + _chunk_size, + memory_order_relaxed); - assert(start < length, "invariant: start %d, length %d", start, length); - assert(((length - start) % chunk_size) == 0, - "invariant: start %d, length %d, chunk size %d", - start, length, chunk_size); + assert(start < length, "invariant: start %zu, length %zu", start, length); + assert(((length - start) % _chunk_size) == 0, + "invariant: start %zu, length %zu, chunk size %zu", + start, length, _chunk_size); // Determine the number of new tasks to create. // Zero-based index for this partial task. The initial task isn't counted. - uint task_num = (start / chunk_size); + uint task_num = checked_cast(start / _chunk_size); // Number of tasks left to process, including this one. - uint remaining_tasks = (length - start) / chunk_size; + uint remaining_tasks = checked_cast((length - start) / _chunk_size); assert(remaining_tasks > 0, "invariant"); // Compute number of pending tasks, including this one. The maximum number // of tasks is a function of task_num (N) and _task_fanout (F). @@ -106,13 +86,12 @@ PartialArrayTaskStepper::next_impl(int length, // of tasks to add for this task. uint pending = MIN3(max_pending, remaining_tasks, _task_limit); uint ncreate = MIN2(_task_fanout, MIN2(remaining_tasks, _task_limit + 1) - pending); - Step result = { start, ncreate }; - return result; + return Step{ start, ncreate }; } PartialArrayTaskStepper::Step -PartialArrayTaskStepper::next(arrayOop from, arrayOop to, int chunk_size) const { - return next_impl(from->length(), to->length_addr(), chunk_size); +PartialArrayTaskStepper::next(PartialArrayState* state) const { + return next_impl(state->length(), state->index_addr()); } #endif // SHARE_GC_SHARED_PARTIALARRAYTASKSTEPPER_INLINE_HPP diff --git a/src/hotspot/share/gc/shared/taskqueue.hpp b/src/hotspot/share/gc/shared/taskqueue.hpp index 2e21ba33b0bf7..2ea75e1457c48 100644 --- a/src/hotspot/share/gc/shared/taskqueue.hpp +++ b/src/hotspot/share/gc/shared/taskqueue.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -576,6 +576,7 @@ class ObjArrayTask // Wrapper over an oop that is a partially scanned array. // Can be converted to a ScannerTask for placement in associated task queues. // Refers to the partially copied source array oop. +// Temporarily retained to support ParallelGC until it adopts PartialArrayState. class PartialArrayScanTask { oop _src; @@ -586,7 +587,9 @@ class PartialArrayScanTask { oop to_source_array() const { return _src; } }; -// Discriminated union over oop*, narrowOop*, and PartialArrayScanTask. +class PartialArrayState; + +// Discriminated union over oop*, narrowOop*, and PartialArrayState. // Uses a low tag in the associated pointer to identify the category. // Used as a task queue element type. class ScannerTask { @@ -624,9 +627,13 @@ class ScannerTask { explicit ScannerTask(narrowOop* p) : _p(encode(p, NarrowOopTag)) {} + // Temporarily retained to support ParallelGC until it adopts PartialArrayState. explicit ScannerTask(PartialArrayScanTask t) : _p(encode(t.to_source_array(), PartialArrayTag)) {} + explicit ScannerTask(PartialArrayState* state) : + _p(encode(state, PartialArrayTag)) {} + // Trivially copyable. // Predicate implementations assume OopTag == 0, others are powers of 2. @@ -639,10 +646,15 @@ class ScannerTask { return (raw_value() & NarrowOopTag) != 0; } + // Temporarily retained to support ParallelGC until it adopts PartialArrayState. bool is_partial_array_task() const { return (raw_value() & PartialArrayTag) != 0; } + bool is_partial_array_state() const { + return (raw_value() & PartialArrayTag) != 0; + } + oop* to_oop_ptr() const { return static_cast(decode(OopTag)); } @@ -651,9 +663,14 @@ class ScannerTask { return static_cast(decode(NarrowOopTag)); } + // Temporarily retained to support ParallelGC until it adopts PartialArrayState. PartialArrayScanTask to_partial_array_task() const { return PartialArrayScanTask(cast_to_oop(decode(PartialArrayTag))); } + + PartialArrayState* to_partial_array_state() const { + return static_cast(decode(PartialArrayTag)); + } }; #endif // SHARE_GC_SHARED_TASKQUEUE_HPP diff --git a/test/hotspot/gtest/gc/shared/test_partialArrayTaskStepper.cpp b/test/hotspot/gtest/gc/shared/test_partialArrayTaskStepper.cpp index fb797ba12c18f..3bb3a74437c8e 100644 --- a/test/hotspot/gtest/gc/shared/test_partialArrayTaskStepper.cpp +++ b/test/hotspot/gtest/gc/shared/test_partialArrayTaskStepper.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,50 +32,42 @@ using Stepper = PartialArrayTaskStepper; class PartialArrayTaskStepper::TestSupport : AllStatic { public: - static Step start(const Stepper* stepper, - int length, - int* to_length_addr, - uint chunk_size) { - return stepper->start_impl(length, to_length_addr, chunk_size); - } - static Step next(const Stepper* stepper, - int length, - int* to_length_addr, - uint chunk_size) { - return stepper->next_impl(length, to_length_addr, chunk_size); + size_t length, + size_t* to_length_addr) { + return stepper->next_impl(length, to_length_addr); } }; using StepperSupport = PartialArrayTaskStepper::TestSupport; -static int simulate(const Stepper* stepper, - int length, - int* to_length_addr, - uint chunk_size) { - Step init = StepperSupport::start(stepper, length, to_length_addr, chunk_size); +static uint simulate(const Stepper* stepper, + size_t length, + size_t* to_length_addr) { + Step init = stepper->start(length); + *to_length_addr = init._index; uint queue_count = init._ncreate; - int task = 0; + uint task = 0; for ( ; queue_count > 0; ++task) { --queue_count; - Step step = StepperSupport::next(stepper, length, to_length_addr, chunk_size); + Step step = StepperSupport::next(stepper, length, to_length_addr); queue_count += step._ncreate; } return task; } -static void run_test(int length, int chunk_size, uint n_workers) { - const PartialArrayTaskStepper stepper(n_workers); - int to_length; - int tasks = simulate(&stepper, length, &to_length, chunk_size); +static void run_test(size_t length, size_t chunk_size, uint n_workers) { + const PartialArrayTaskStepper stepper(n_workers, chunk_size); + size_t to_length; + uint tasks = simulate(&stepper, length, &to_length); ASSERT_EQ(length, to_length); ASSERT_EQ(tasks, length / chunk_size); } TEST(PartialArrayTaskStepperTest, doit) { - for (int chunk_size = 50; chunk_size <= 500; chunk_size += 50) { + for (size_t chunk_size = 50; chunk_size <= 500; chunk_size += 50) { for (uint n_workers = 1; n_workers <= 256; n_workers = (n_workers * 3 / 2 + 1)) { - for (int length = 0; length <= 1000000; length = (length * 2 + 1)) { + for (size_t length = 0; length <= 1000000; length = (length * 2 + 1)) { run_test(length, chunk_size, n_workers); } // Ensure we hit boundary cases for length % chunk_size == 0. From 0e7c1c1afeaba1c125b70cabe7b1b7a3193ee5c3 Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Mon, 12 Aug 2024 06:26:27 +0000 Subject: [PATCH 259/353] 8338112: Test testlibrary_tests/ir_framework/tests/TestPrivilegedMode.java fails with release build Reviewed-by: chagedorn, thartmann --- .../ir_framework/tests/TestPrivilegedMode.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestPrivilegedMode.java b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestPrivilegedMode.java index 347b2eb39fbfc..2122be83a0ff2 100644 --- a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestPrivilegedMode.java +++ b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestPrivilegedMode.java @@ -31,7 +31,7 @@ /* * @test - * @requires vm.flagless + * @requires vm.debug == true & vm.compiler2.enabled & vm.flagless * @summary Test that IR framework successfully adds test class to boot classpath in order to run in privileged mode. * @modules java.base/jdk.internal.vm.annotation * @library /test/lib / From 692f5cbdb9bd94f03e5f18ddf07d56fbb5c0d456 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Mon, 12 Aug 2024 07:32:10 +0000 Subject: [PATCH 260/353] 8338101: remove old remap assertion in map_or_reserve_memory_aligned after JDK-8338058 Reviewed-by: mdoerr, clanger --- src/hotspot/os/windows/os_windows.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp index 65ba13b0d9e81..cb0fe95269b9f 100644 --- a/src/hotspot/os/windows/os_windows.cpp +++ b/src/hotspot/os/windows/os_windows.cpp @@ -3462,8 +3462,8 @@ static char* map_or_reserve_memory_aligned(size_t size, size_t alignment, int fi os::attempt_reserve_memory_at(aligned_base, size, false, flag); } - assert(aligned_base != nullptr, "Did not manage to re-map after %d attempts?", max_attempts); - assert(aligned_base != nullptr, "Did not manage to re-map after %d attempts (size %zu, alignment %zu, file descriptor %d)", max_attempts, size, alignment, file_desc); + assert(aligned_base != nullptr, + "Did not manage to re-map after %d attempts (size %zu, alignment %zu, file descriptor %d)", max_attempts, size, alignment, file_desc); return aligned_base; } From 03204600c596214895ef86581eba9722f76d39b3 Mon Sep 17 00:00:00 2001 From: Andrew Haley Date: Mon, 12 Aug 2024 07:38:43 +0000 Subject: [PATCH 261/353] 8337958: Out-of-bounds array access in secondary_super_cache Reviewed-by: vlivanov, shade --- src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp | 4 ++-- src/hotspot/cpu/riscv/macroAssembler_riscv.cpp | 4 ++-- src/hotspot/cpu/x86/macroAssembler_x86.cpp | 5 ++--- src/hotspot/share/oops/klass.cpp | 13 ++++++++----- 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp index 25dfaca6dca20..9dd4371cf69e2 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp @@ -1730,8 +1730,8 @@ void MacroAssembler::lookup_secondary_supers_table_slow_path(Register r_super_kl // The bitmap is full to bursting. // Implicit invariant: BITMAP_FULL implies (length > 0) assert(Klass::SECONDARY_SUPERS_BITMAP_FULL == ~uintx(0), ""); - cmn(r_bitmap, (u1)1); - br(EQ, L_huge); + cmpw(r_array_length, (u1)(Klass::SECONDARY_SUPERS_TABLE_SIZE - 2)); + br(GT, L_huge); // NB! Our caller has checked bits 0 and 1 in the bitmap. The // current slot (at secondary_supers[r_array_index]) has not yet diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index e0b24b7fd66ca..c6624cb45bb4e 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -3973,8 +3973,8 @@ void MacroAssembler::lookup_secondary_supers_table_slow_path(Register r_super_kl // Check if bitmap is SECONDARY_SUPERS_BITMAP_FULL assert(Klass::SECONDARY_SUPERS_BITMAP_FULL == ~uintx(0), "Adjust this code"); - addi(t0, r_bitmap, (u1)1); - beqz(t0, L_bitmap_full); + subw(t0, r_array_length, Klass::SECONDARY_SUPERS_TABLE_SIZE - 2); + bgtz(t0, L_bitmap_full); // NB! Our caller has checked bits 0 and 1 in the bitmap. The // current slot (at secondary_supers[r_array_index]) has not yet diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp index c8234d6b9b88b..78bcabb2000b3 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp @@ -4945,9 +4945,8 @@ void MacroAssembler::lookup_secondary_supers_table_slow_path(Register r_super_kl // The bitmap is full to bursting. // Implicit invariant: BITMAP_FULL implies (length > 0) - assert(Klass::SECONDARY_SUPERS_BITMAP_FULL == ~uintx(0), ""); - cmpq(r_bitmap, (int32_t)-1); // sign-extends immediate to 64-bit value - jcc(Assembler::equal, L_huge); + cmpl(r_array_length, (int32_t)Klass::SECONDARY_SUPERS_TABLE_SIZE - 2); + jcc(Assembler::greater, L_huge); // NB! Our caller has checked bits 0 and 1 in the bitmap. The // current slot (at secondary_supers[r_array_index]) has not yet diff --git a/src/hotspot/share/oops/klass.cpp b/src/hotspot/share/oops/klass.cpp index 1fed317a86016..964bb030b960e 100644 --- a/src/hotspot/share/oops/klass.cpp +++ b/src/hotspot/share/oops/klass.cpp @@ -306,6 +306,7 @@ void Klass::set_secondary_supers(Array* secondaries, uintx bitmap) { if (UseSecondarySupersTable && secondaries != nullptr) { uintx real_bitmap = compute_secondary_supers_bitmap(secondaries); assert(bitmap == real_bitmap, "must be"); + assert(secondaries->length() >= (int)population_count(bitmap), "must be"); } #endif _bitmap = bitmap; @@ -344,11 +345,12 @@ uintx Klass::hash_secondary_supers(Array* secondaries, bool rewrite) { return uintx(1) << hash_slot; } - // For performance reasons we don't use a hashed table unless there - // are at least two empty slots in it. If there were only one empty - // slot it'd take a long time to create the table and the resulting - // search would be no faster than linear probing. - if (length > SECONDARY_SUPERS_TABLE_SIZE - 2) { + // Invariant: _secondary_supers.length >= population_count(_secondary_supers_bitmap) + + // Don't attempt to hash a table that's completely full, because in + // the case of an absent interface linear probing would not + // terminate. + if (length >= SECONDARY_SUPERS_TABLE_SIZE) { return SECONDARY_SUPERS_BITMAP_FULL; } @@ -788,6 +790,7 @@ void Klass::remove_java_mirror() { void Klass::restore_unshareable_info(ClassLoaderData* loader_data, Handle protection_domain, TRAPS) { assert(is_klass(), "ensure C++ vtable is restored"); assert(is_shared(), "must be set"); + assert(secondary_supers()->length() >= (int)population_count(_bitmap), "must be"); JFR_ONLY(RESTORE_ID(this);) if (log_is_enabled(Trace, cds, unshareable)) { ResourceMark rm(THREAD); From a6c0630737bbf2f2e6c64863ff9b43c50c4742b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20Sikstr=C3=B6m?= Date: Mon, 12 Aug 2024 10:58:05 +0000 Subject: [PATCH 262/353] 8337938: ZUtils::alloc_aligned allocates without reporting to NMT Reviewed-by: stefank, kbarrett --- src/hotspot/os/posix/gc/z/zUtils_posix.cpp | 43 ------------------- .../os/windows/gc/z/zUtils_windows.cpp | 40 ----------------- src/hotspot/share/gc/z/zStat.cpp | 4 +- src/hotspot/share/gc/z/zUtils.hpp | 4 +- src/hotspot/share/gc/z/zUtils.inline.hpp | 15 ++++++- src/hotspot/share/gc/z/zValue.inline.hpp | 6 +-- 6 files changed, 21 insertions(+), 91 deletions(-) delete mode 100644 src/hotspot/os/posix/gc/z/zUtils_posix.cpp delete mode 100644 src/hotspot/os/windows/gc/z/zUtils_windows.cpp diff --git a/src/hotspot/os/posix/gc/z/zUtils_posix.cpp b/src/hotspot/os/posix/gc/z/zUtils_posix.cpp deleted file mode 100644 index dc5af2b973a25..0000000000000 --- a/src/hotspot/os/posix/gc/z/zUtils_posix.cpp +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "gc/z/zUtils.hpp" -#include "utilities/debug.hpp" -#include "utilities/globalDefinitions.hpp" - -#include - -uintptr_t ZUtils::alloc_aligned(size_t alignment, size_t size) { - void* res = nullptr; - - // Use raw posix_memalign as long as we have no wrapper for it - ALLOW_C_FUNCTION(::posix_memalign, int rc = posix_memalign(&res, alignment, size);) - if (rc != 0) { - fatal("posix_memalign() failed"); - } - - memset(res, 0, size); - - return (uintptr_t)res; -} diff --git a/src/hotspot/os/windows/gc/z/zUtils_windows.cpp b/src/hotspot/os/windows/gc/z/zUtils_windows.cpp deleted file mode 100644 index 29f7f55e2d145..0000000000000 --- a/src/hotspot/os/windows/gc/z/zUtils_windows.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" -#include "gc/z/zUtils.hpp" -#include "utilities/debug.hpp" - -#include - -uintptr_t ZUtils::alloc_aligned(size_t alignment, size_t size) { - void* const res = _aligned_malloc(size, alignment); - - if (res == nullptr) { - fatal("_aligned_malloc failed"); - } - - memset(res, 0, size); - - return (uintptr_t)res; -} diff --git a/src/hotspot/share/gc/z/zStat.cpp b/src/hotspot/share/gc/z/zStat.cpp index 613f7b2740b43..c2a7a23c04f53 100644 --- a/src/hotspot/share/gc/z/zStat.cpp +++ b/src/hotspot/share/gc/z/zStat.cpp @@ -35,7 +35,7 @@ #include "gc/z/zRelocationSetSelector.inline.hpp" #include "gc/z/zStat.hpp" #include "gc/z/zTracer.inline.hpp" -#include "gc/z/zUtils.hpp" +#include "gc/z/zUtils.inline.hpp" #include "memory/metaspaceUtils.hpp" #include "memory/resourceArea.hpp" #include "runtime/atomic.hpp" @@ -364,7 +364,7 @@ void ZStatValue::initialize() { // Allocation aligned memory const size_t size = _cpu_offset * ZCPU::count(); - _base = ZUtils::alloc_aligned(ZCacheLineSize, size); + _base = ZUtils::alloc_aligned_unfreeable(ZCacheLineSize, size); } const char* ZStatValue::group() const { diff --git a/src/hotspot/share/gc/z/zUtils.hpp b/src/hotspot/share/gc/z/zUtils.hpp index f82ef06235c82..59e789d5b380f 100644 --- a/src/hotspot/share/gc/z/zUtils.hpp +++ b/src/hotspot/share/gc/z/zUtils.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,7 @@ class ZUtils : public AllStatic { static const char* thread_name(); // Allocation - static uintptr_t alloc_aligned(size_t alignment, size_t size); + static uintptr_t alloc_aligned_unfreeable(size_t alignment, size_t size); // Size conversion static size_t bytes_to_words(size_t size_in_words); diff --git a/src/hotspot/share/gc/z/zUtils.inline.hpp b/src/hotspot/share/gc/z/zUtils.inline.hpp index eda9fca9398a7..b6acf12df3020 100644 --- a/src/hotspot/share/gc/z/zUtils.inline.hpp +++ b/src/hotspot/share/gc/z/zUtils.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,11 +28,24 @@ #include "gc/z/zAddress.inline.hpp" #include "oops/oop.inline.hpp" +#include "runtime/os.hpp" #include "utilities/align.hpp" #include "utilities/copy.hpp" #include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" +inline uintptr_t ZUtils::alloc_aligned_unfreeable(size_t alignment, size_t size) { + const size_t padded_size = size + (alignment - 1); + void* const addr = os::malloc(padded_size, mtGC); + void* const aligned_addr = align_up(addr, alignment); + + memset(aligned_addr, 0, size); + + // Since free expects pointers returned by malloc, aligned_addr cannot be + // freed since it is most likely not the same as addr after alignment. + return (uintptr_t)aligned_addr; +} + inline size_t ZUtils::bytes_to_words(size_t size_in_bytes) { assert(is_aligned(size_in_bytes, BytesPerWord), "Size not word aligned"); return size_in_bytes >> LogBytesPerWord; diff --git a/src/hotspot/share/gc/z/zValue.inline.hpp b/src/hotspot/share/gc/z/zValue.inline.hpp index b8c86cdd5c540..2367bac0f0aab 100644 --- a/src/hotspot/share/gc/z/zValue.inline.hpp +++ b/src/hotspot/share/gc/z/zValue.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,7 @@ #include "gc/z/zCPU.inline.hpp" #include "gc/z/zGlobals.hpp" #include "gc/z/zNUMA.hpp" -#include "gc/z/zUtils.hpp" +#include "gc/z/zUtils.inline.hpp" #include "runtime/globals.hpp" #include "utilities/align.hpp" @@ -58,7 +58,7 @@ uintptr_t ZValueStorage::alloc(size_t size) { // Allocate new block of memory const size_t block_alignment = offset; const size_t block_size = offset * S::count(); - _top = ZUtils::alloc_aligned(block_alignment, block_size); + _top = ZUtils::alloc_aligned_unfreeable(block_alignment, block_size); _end = _top + offset; // Retry allocation From 89a15f1414f89d2dd32eac791e9155fcb4207e56 Mon Sep 17 00:00:00 2001 From: Daniel Gredler Date: Mon, 12 Aug 2024 12:09:22 +0000 Subject: [PATCH 263/353] 8337681: PNGImageWriter uses much more memory than necessary Reviewed-by: prr, lbourges --- .../imageio/plugins/png/PNGImageWriter.java | 22 ++- .../plugins/png/RasterReuseWriteTest.java | 182 ++++++++++++++++++ 2 files changed, 199 insertions(+), 5 deletions(-) create mode 100644 test/jdk/javax/imageio/plugins/png/RasterReuseWriteTest.java diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGImageWriter.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGImageWriter.java index 27707613f76ee..ca9ba7631ca03 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGImageWriter.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGImageWriter.java @@ -26,6 +26,7 @@ package com.sun.imageio.plugins.png; import java.awt.Rectangle; +import java.awt.image.BufferedImage; import java.awt.image.IndexColorModel; import java.awt.image.Raster; import java.awt.image.RenderedImage; @@ -919,17 +920,28 @@ private void encodePass(ImageOutputStream os, int bitDepth = metadata.IHDR_bitDepth; for (int row = minY + yOffset; row < minY + height; row += ySkip) { - Rectangle rect = new Rectangle(minX, row, width, 1); - Raster ras = image.getData(rect); + Raster ras; + if (image instanceof BufferedImage bi) { + // Use the raster directly (no copy). + ras = bi.getRaster(); + } else if (image.getNumXTiles() == 1 && image.getNumYTiles() == 1 && + image.getTileWidth() == width && image.getTileHeight() == height) { + // Use the single tile directly (no copy). + ras = image.getTile(image.getMinTileX(), image.getMinTileY()); + } else { + // Make a copy of the raster data. + Rectangle rect = new Rectangle(minX, row, width, 1); + ras = image.getData(rect); + } + if (sourceBands != null) { - ras = ras.createChild(minX, row, width, 1, minX, row, - sourceBands); + ras = ras.createChild(minX, row, width, 1, minX, row, sourceBands); } ras.getPixels(minX, row, width, 1, samples); if (image.getColorModel().isAlphaPremultiplied()) { - WritableRaster wr = ras.createCompatibleWritableRaster(); + WritableRaster wr = ras.createCompatibleWritableRaster(minX, row, width, 1); wr.setPixels(wr.getMinX(), wr.getMinY(), wr.getWidth(), wr.getHeight(), samples); diff --git a/test/jdk/javax/imageio/plugins/png/RasterReuseWriteTest.java b/test/jdk/javax/imageio/plugins/png/RasterReuseWriteTest.java new file mode 100644 index 0000000000000..64adaa6d196d2 --- /dev/null +++ b/test/jdk/javax/imageio/plugins/png/RasterReuseWriteTest.java @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8337681 + * @summary Test that raster use optimization does not cause any regressions. + */ + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.geom.AffineTransform; +import java.awt.image.BufferedImage; +import java.awt.image.RenderedImage; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import javax.imageio.IIOImage; +import javax.imageio.ImageIO; +import javax.imageio.ImageReader; +import javax.imageio.ImageWriteParam; +import javax.imageio.ImageWriter; +import javax.imageio.stream.ImageInputStream; +import javax.imageio.stream.ImageOutputStream; +import javax.imageio.stream.MemoryCacheImageOutputStream; + +public class RasterReuseWriteTest { + + public static void main(String[] args) throws Exception { + test(BufferedImage.TYPE_INT_RGB); + test(BufferedImage.TYPE_INT_ARGB); + test(BufferedImage.TYPE_INT_ARGB_PRE); + test(BufferedImage.TYPE_4BYTE_ABGR); + test(BufferedImage.TYPE_4BYTE_ABGR_PRE); + } + + private static void test(int type) throws Exception { + + // swaps blue and red + int bands = (type == BufferedImage.TYPE_INT_RGB ? 3 : 4); + int[] sourceBands = bands == 3 ? new int[] { 2, 1, 0 } : + new int[] { 2, 1, 0, 3 }; + + // test writing a BufferedImage without source bands + BufferedImage img1 = createImage(256, 256, type); + byte[] bytes1 = writePng(img1, null); + BufferedImage img2 = ImageIO.read(new ByteArrayInputStream(bytes1)); + compare(img1, img2, false); + + // test writing a BufferedImage with source bands + BufferedImage img3 = createImage(256, 256, type); + byte[] bytes3 = writePng(img3, sourceBands); + BufferedImage img4 = ImageIO.read(new ByteArrayInputStream(bytes3)); + compare(img3, img4, true); + + // test writing a non-BufferedImage with source bands and one tile + RenderedImage img5 = toTiledImage(img1, 256); + byte[] bytes5 = writePng(img5, sourceBands); + BufferedImage img6 = ImageIO.read(new ByteArrayInputStream(bytes5)); + compare(img5, img6, true); + + // test writing a non-BufferedImage with source bands and multiple tiles + RenderedImage img7 = toTiledImage(img1, 128); + byte[] bytes7 = writePng(img7, sourceBands); + BufferedImage img8 = ImageIO.read(new ByteArrayInputStream(bytes7)); + compare(img7, img8, true); + } + + private static BufferedImage createImage(int w, int h, int type) throws Exception { + BufferedImage img = new BufferedImage(w, h, type); + Graphics2D g2d = img.createGraphics(); + g2d.setColor(Color.WHITE); + g2d.fillRect(0, 0, w, h); + g2d.setColor(Color.GREEN); + g2d.drawRect(20, 20, 100, 50); + g2d.setColor(Color.RED); + g2d.drawRect(80, 10, 100, 40); + g2d.setColor(Color.BLUE); + g2d.fillRect(40, 60, 120, 30); + g2d.dispose(); + return img; + } + + private static byte[] writePng(RenderedImage img, int[] sourceBands) throws Exception { + ImageWriter writer = ImageIO.getImageWritersByFormatName("png").next(); + ImageWriteParam param = writer.getDefaultWriteParam(); + param.setSourceBands(sourceBands); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ImageOutputStream stream = new MemoryCacheImageOutputStream(baos); + writer.setOutput(stream); + writer.write(null, new IIOImage(img, null, null), param); + writer.dispose(); + stream.flush(); + return baos.toByteArray(); + } + + private static void compare(RenderedImage img1, RenderedImage img2, boolean blueAndRedSwapped) { + int[] pixels1 = getRgbPixels(img1); + int[] pixels2 = getRgbPixels(img2); + for (int i = 0; i < pixels1.length; i++) { + int expected; + if (blueAndRedSwapped && pixels1[i] == 0xFFFF0000) { + expected = 0xFF0000FF; // red -> blue + } else if (blueAndRedSwapped && pixels1[i] == 0xFF0000FF) { + expected = 0xFFFF0000; // blue -> red + } else { + expected = pixels1[i]; // no change + } + int actual = pixels2[i]; + if (actual != expected) { + throw new RuntimeException("Pixel " + i + ": expected " + + Integer.toHexString(expected) + ", but got " + + Integer.toHexString(actual)); + } + } + } + + private static int[] getRgbPixels(RenderedImage img) { + int w = img.getWidth(); + int h = img.getHeight(); + if (img instanceof BufferedImage bi) { + return bi.getRGB(0, 0, w, h, null, 0, w); + } else { + BufferedImage bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); + Graphics2D g2d = bi.createGraphics(); + g2d.drawRenderedImage(img, new AffineTransform()); + g2d.dispose(); + return bi.getRGB(0, 0, w, h, null, 0, w); + } + } + + private static RenderedImage toTiledImage(BufferedImage img, int tileSize) throws Exception { + + // write to TIFF + ImageWriter writer = ImageIO.getImageWritersByFormatName("tiff").next(); + ImageWriteParam param = writer.getDefaultWriteParam(); + param.setTilingMode(ImageWriteParam.MODE_EXPLICIT); + param.setTiling(tileSize, tileSize, 0, 0); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ImageOutputStream stream = new MemoryCacheImageOutputStream(baos); + writer.setOutput(stream); + writer.write(null, new IIOImage(img, null, null), param); + writer.dispose(); + stream.flush(); + byte[] bytes = baos.toByteArray(); + + // read from TIFF + ImageReader reader = ImageIO.getImageReadersByFormatName("tiff").next(); + ImageInputStream input = ImageIO.createImageInputStream(new ByteArrayInputStream(bytes)); + reader.setInput(input); + RenderedImage ri = reader.readAsRenderedImage(0, null); + if (ri instanceof BufferedImage) { + throw new RuntimeException("Unexpected BufferedImage"); + } + int tw = ri.getTileWidth(); + int th = ri.getTileHeight(); + if (tw != tileSize || th != tileSize) { + throw new RuntimeException("Expected tile size " + tileSize + + ", but found " + tw + "x" + th); + } + return ri; + } +} From 61d1dc59535a3dc186bc1986a04efdb4e5a8fa18 Mon Sep 17 00:00:00 2001 From: Vicente Romero Date: Mon, 12 Aug 2024 13:52:57 +0000 Subject: [PATCH 264/353] 8334466: Ambiguous method call with generics may cause FunctionDescriptorLookupError Reviewed-by: jlahoda --- .../com/sun/tools/javac/comp/Resolve.java | 14 ++++++++--- ...WithFunctionDescriptorLookupErrorTest.java | 25 +++++++++++++++++++ ...hWithFunctionDescriptorLookupErrorTest.out | 2 ++ 3 files changed, 38 insertions(+), 3 deletions(-) create mode 100644 test/langtools/tools/javac/lambda/CrashWithFunctionDescriptorLookupErrorTest.java create mode 100644 test/langtools/tools/javac/lambda/CrashWithFunctionDescriptorLookupErrorTest.out diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java index c71b6d341dc12..5bf1bc0ead149 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 @@ -1219,9 +1219,17 @@ private boolean unrelatedInterfaces(Type t, Type s) { /** Parameters {@code t} and {@code s} are unrelated functional interface types. */ private boolean functionalInterfaceMostSpecific(Type t, Type s, JCTree tree) { - Type tDesc = types.findDescriptorType(types.capture(t)); - Type tDescNoCapture = types.findDescriptorType(t); - Type sDesc = types.findDescriptorType(s); + Type tDesc; + Type tDescNoCapture; + Type sDesc; + try { + tDesc = types.findDescriptorType(types.capture(t)); + tDescNoCapture = types.findDescriptorType(t); + sDesc = types.findDescriptorType(s); + } catch (Types.FunctionDescriptorLookupError ex) { + // don't report, a more meaningful error should be reported upstream + return false; + } final List tTypeParams = tDesc.getTypeArguments(); final List tTypeParamsNoCapture = tDescNoCapture.getTypeArguments(); final List sTypeParams = sDesc.getTypeArguments(); diff --git a/test/langtools/tools/javac/lambda/CrashWithFunctionDescriptorLookupErrorTest.java b/test/langtools/tools/javac/lambda/CrashWithFunctionDescriptorLookupErrorTest.java new file mode 100644 index 0000000000000..bfdfc30609de4 --- /dev/null +++ b/test/langtools/tools/javac/lambda/CrashWithFunctionDescriptorLookupErrorTest.java @@ -0,0 +1,25 @@ +/* + * @test /nodynamiccopyright/ + * @bug 8334466 + * @summary Ambiguous method call with generics may cause FunctionDescriptorLookupError + * @compile/fail/ref=CrashWithFunctionDescriptorLookupErrorTest.out -XDrawDiagnostics CrashWithFunctionDescriptorLookupErrorTest.java + */ + +import java.util.List; + +class CrashWithFunctionDescriptorLookupErrorTest { + void m() { + List list = List.of(new X()); + test(list.get(0)); + } + + void test(A a) { } + void test(B b) { } + + interface A> { T a(); } + interface B> { T b(); } + class X implements A, B { + public X a() { return null; } + public X b() { return null; } + } +} diff --git a/test/langtools/tools/javac/lambda/CrashWithFunctionDescriptorLookupErrorTest.out b/test/langtools/tools/javac/lambda/CrashWithFunctionDescriptorLookupErrorTest.out new file mode 100644 index 0000000000000..06afbc8bc18a6 --- /dev/null +++ b/test/langtools/tools/javac/lambda/CrashWithFunctionDescriptorLookupErrorTest.out @@ -0,0 +1,2 @@ +CrashWithFunctionDescriptorLookupErrorTest.java:13:9: compiler.err.ref.ambiguous: test, kindname.method, test(CrashWithFunctionDescriptorLookupErrorTest.A), CrashWithFunctionDescriptorLookupErrorTest, kindname.method, test(CrashWithFunctionDescriptorLookupErrorTest.B), CrashWithFunctionDescriptorLookupErrorTest +1 error From a36fb368e1a3630d32908884f4abdc3382eb9aaa Mon Sep 17 00:00:00 2001 From: Magnus Ihse Bursie Date: Mon, 12 Aug 2024 15:33:31 +0000 Subject: [PATCH 265/353] 8338108: Give better error message in configure if a full XCode is missing Reviewed-by: jwaters, erikj, shade --- make/autoconf/toolchain.m4 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/make/autoconf/toolchain.m4 b/make/autoconf/toolchain.m4 index 57064df1ed75f..12d450cc708cd 100644 --- a/make/autoconf/toolchain.m4 +++ b/make/autoconf/toolchain.m4 @@ -678,6 +678,9 @@ AC_DEFUN_ONCE([TOOLCHAIN_DETECT_TOOLCHAIN_EXTRA], test_metal=`$METAL --version 2>&1` if test $? -ne 0; then AC_MSG_RESULT([no]) + AC_MSG_NOTICE([A full XCode is required to build the JDK (not only command line tools)]) + AC_MSG_NOTICE([If you have XCode installed, you might need to reset the Xcode active developer directory]) + AC_MSG_NOTICE([using 'sudo xcode-select -r']) AC_MSG_ERROR([XCode tool 'metal' neither found in path nor with xcrun]) else AC_MSG_RESULT([yes, will be using '$METAL']) From 04b146a31f55825e2c8e3c8e42310b3b3337ae95 Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Mon, 12 Aug 2024 15:43:40 +0000 Subject: [PATCH 266/353] 8337334: Test tools/javac/7142086/T7142086.java timeout with fastdebug binary Reviewed-by: vromero --- test/langtools/TEST.ROOT | 3 ++- test/langtools/tools/javac/7142086/T7142086.java | 12 ++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/test/langtools/TEST.ROOT b/test/langtools/TEST.ROOT index 11daad5244f31..d816d5b096b79 100644 --- a/test/langtools/TEST.ROOT +++ b/test/langtools/TEST.ROOT @@ -42,4 +42,5 @@ requires.extraPropDefns.vmOpts = \ -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI \ --add-exports java.base/jdk.internal.foreign=ALL-UNNAMED requires.properties= \ - vm.continuations + vm.continuations \ + vm.debug diff --git a/test/langtools/tools/javac/7142086/T7142086.java b/test/langtools/tools/javac/7142086/T7142086.java index bc8260bd486f6..b6521b7ffbc05 100644 --- a/test/langtools/tools/javac/7142086/T7142086.java +++ b/test/langtools/tools/javac/7142086/T7142086.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,12 +23,20 @@ /* * @test - * @bug 7142086 + * @bug 7142086 8337334 + * @requires vm.debug == false * @summary performance problem in Check.checkOverrideClashes(...) * @modules jdk.compiler * @run main/timeout=10 T7142086 */ +/* + * @test + * @requires vm.debug == true + * @modules jdk.compiler + * @run main/timeout=20 T7142086 + */ + import com.sun.source.util.JavacTask; import java.net.URI; import java.util.List; From f84240bca80d2ff01e198bb67931ad4725a5b334 Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Mon, 12 Aug 2024 16:03:41 +0000 Subject: [PATCH 267/353] 8338011: CDS archived heap object support for 64-bit Windows Reviewed-by: stuefe, shade, ccheung --- src/hotspot/share/cds/filemap.cpp | 42 +++++++++++++++++--------- src/hotspot/share/cds/heapShared.cpp | 1 - src/hotspot/share/utilities/macros.hpp | 4 +-- 3 files changed, 30 insertions(+), 17 deletions(-) diff --git a/src/hotspot/share/cds/filemap.cpp b/src/hotspot/share/cds/filemap.cpp index 96c826fb67e82..c5a9d5cceed53 100644 --- a/src/hotspot/share/cds/filemap.cpp +++ b/src/hotspot/share/cds/filemap.cpp @@ -2178,21 +2178,35 @@ bool FileMapInfo::map_heap_region_impl() { // Map the archived heap data. No need to call MemTracker::record_virtual_memory_type() // for mapped region as it is part of the reserved java heap, which is already recorded. char* addr = (char*)_mapped_heap_memregion.start(); - char* base = map_memory(_fd, _full_path, r->file_offset(), - addr, _mapped_heap_memregion.byte_size(), r->read_only(), - r->allow_exec()); - if (base == nullptr || base != addr) { - dealloc_heap_region(); - log_info(cds)("UseSharedSpaces: Unable to map at required address in java heap. " - INTPTR_FORMAT ", size = " SIZE_FORMAT " bytes", - p2i(addr), _mapped_heap_memregion.byte_size()); - return false; - } + char* base; - if (VerifySharedSpaces && !r->check_region_crc(base)) { - dealloc_heap_region(); - log_info(cds)("UseSharedSpaces: mapped heap region is corrupt"); - return false; + if (MetaspaceShared::use_windows_memory_mapping()) { + if (!read_region(MetaspaceShared::hp, addr, + align_up(_mapped_heap_memregion.byte_size(), os::vm_page_size()), + /* do_commit = */ true)) { + dealloc_heap_region(); + log_error(cds)("Failed to read archived heap region into " INTPTR_FORMAT, p2i(addr)); + return false; + } + // Checks for VerifySharedSpaces is already done inside read_region() + base = addr; + } else { + base = map_memory(_fd, _full_path, r->file_offset(), + addr, _mapped_heap_memregion.byte_size(), r->read_only(), + r->allow_exec()); + if (base == nullptr || base != addr) { + dealloc_heap_region(); + log_info(cds)("UseSharedSpaces: Unable to map at required address in java heap. " + INTPTR_FORMAT ", size = " SIZE_FORMAT " bytes", + p2i(addr), _mapped_heap_memregion.byte_size()); + return false; + } + + if (VerifySharedSpaces && !r->check_region_crc(base)) { + dealloc_heap_region(); + log_info(cds)("UseSharedSpaces: mapped heap region is corrupt"); + return false; + } } r->set_mapped_base(base); diff --git a/src/hotspot/share/cds/heapShared.cpp b/src/hotspot/share/cds/heapShared.cpp index ff84ddc13fc6c..0a0dc56c894a4 100644 --- a/src/hotspot/share/cds/heapShared.cpp +++ b/src/hotspot/share/cds/heapShared.cpp @@ -1554,7 +1554,6 @@ void HeapShared::archive_object_subgraphs(ArchivableStaticFieldInfo fields[], // by any of these static fields. // At runtime, these classes are initialized before X's archived fields // are restored by HeapShared::initialize_from_archived_subgraph(). - int i; for (int i = 0; fields[i].valid(); ) { ArchivableStaticFieldInfo* info = &fields[i]; const char* klass_name = info->klass_name; diff --git a/src/hotspot/share/utilities/macros.hpp b/src/hotspot/share/utilities/macros.hpp index 244b18ecdd422..1034dec0d9aaa 100644 --- a/src/hotspot/share/utilities/macros.hpp +++ b/src/hotspot/share/utilities/macros.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -621,7 +621,7 @@ #define COMPILER_HEADER(basename) XSTR(COMPILER_HEADER_STEM(basename).hpp) #define COMPILER_HEADER_INLINE(basename) XSTR(COMPILER_HEADER_STEM(basename).inline.hpp) -#if INCLUDE_CDS && INCLUDE_G1GC && defined(_LP64) && !defined(_WINDOWS) +#if INCLUDE_CDS && INCLUDE_G1GC && defined(_LP64) #define INCLUDE_CDS_JAVA_HEAP 1 #define CDS_JAVA_HEAP_ONLY(x) x #define NOT_CDS_JAVA_HEAP(x) From 8d0831478338e9b084b2c47f46eba9faae3a5eb6 Mon Sep 17 00:00:00 2001 From: Liam Miller-Cushon Date: Mon, 12 Aug 2024 17:15:39 +0000 Subject: [PATCH 268/353] 8337795: Type annotation attached to incorrect type during class reading Reviewed-by: vromero --- .../com/sun/tools/javac/jvm/ClassReader.java | 145 ++++++++---------- .../processing/model/type/BasicAnnoTests.java | 4 + 2 files changed, 65 insertions(+), 84 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java index dba5fb6a1975c..fcc1efda8dcc0 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java @@ -36,9 +36,9 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; -import java.util.function.BiFunction; import java.util.function.IntFunction; import java.util.function.Predicate; +import java.util.stream.IntStream; import javax.lang.model.element.Modifier; import javax.lang.model.element.NestingKind; @@ -2461,13 +2461,8 @@ private Type addTypeAnnotations(Type type, Predicate fil .add(attribute); } - // Search the structure of the type to find the contained types at each type path - Map> attributesByType = new HashMap<>(); - new TypeAnnotationLocator(attributesByPath, attributesByType).visit(type, List.nil()); - // Rewrite the type and add the annotations - type = new TypeAnnotationTypeMapping(attributesByType).visit(type, null); - Assert.check(attributesByType.isEmpty(), "Failed to apply annotations to types"); + type = new TypeAnnotationStructuralTypeMapping(attributesByPath).visit(type, List.nil()); return type; } @@ -2495,120 +2490,102 @@ private static Predicate classExtends(int index) { } /** - * Visit all contained types, assembling a type path to represent the current location, and - * record the types at each type path that need to be annotated. + * A type mapping that rewrites the type to include type annotations. + * + *

    This logic is similar to {@link Type.StructuralTypeMapping}, but also tracks the path to + * the contained types being rewritten, and so cannot easily share the existing logic. */ - private static class TypeAnnotationLocator - extends Types.DefaultTypeVisitor> { + private static final class TypeAnnotationStructuralTypeMapping + extends Types.TypeMapping> { + private final Map, - ListBuffer> attributesByPath; - private final Map> attributesByType; + ListBuffer> attributesByPath; - private TypeAnnotationLocator( + private TypeAnnotationStructuralTypeMapping( Map, ListBuffer> - attributesByPath, - Map> attributesByType) { + attributesByPath) { this.attributesByPath = attributesByPath; - this.attributesByType = attributesByType; } + @Override - public Void visitClassType(ClassType t, List path) { + public Type visitClassType(ClassType t, List path) { // As described in JVMS 4.7.20.2, type annotations on nested types are located with // 'left-to-right' steps starting on 'the outermost part of the type for which a type // annotation is admissible'. So the current path represents the outermost containing // type of the type being visited, and we add type path steps for every contained nested // type. - List enclosing = List.nil(); - for (Type curr = t; - curr != null && curr != Type.noType; + Type outer = t.getEnclosingType(); + Type outer1 = outer != Type.noType ? visit(outer, path) : outer; + for (Type curr = t.getEnclosingType(); + curr != Type.noType; curr = curr.getEnclosingType()) { - enclosing = enclosing.prepend((ClassType) curr); - } - for (ClassType te : enclosing) { - if (te.typarams_field != null) { - int i = 0; - for (Type typaram : te.typarams_field) { - visit(typaram, path.append(new TypeAnnotationPosition.TypePathEntry( - TypeAnnotationPosition.TypePathEntryKind.TYPE_ARGUMENT, i++))); - } - } - visitType(te, path); path = path.append(TypeAnnotationPosition.TypePathEntry.INNER_TYPE); } - return null; + List typarams = t.getTypeArguments(); + List typarams1 = rewriteTypeParams(path, typarams); + if (outer1 != outer || typarams != typarams1) { + t = new ClassType(outer1, typarams1, t.tsym, t.getMetadata()); + } + return reannotate(t, path); } - @Override - public Void visitWildcardType( - WildcardType t, List path) { - visit(t.type, path.append(TypeAnnotationPosition.TypePathEntry.WILDCARD)); - return super.visitWildcardType(t, path); + private List rewriteTypeParams( + List path, List typarams) { + var i = IntStream.iterate(0, x -> x + 1).iterator(); + return typarams.map(typaram -> visit(typaram, + path.append(new TypeAnnotationPosition.TypePathEntry( + TypeAnnotationPosition.TypePathEntryKind.TYPE_ARGUMENT, i.nextInt())))); } @Override - public Void visitArrayType(ArrayType t, List path) { - visit(t.elemtype, path.append(TypeAnnotationPosition.TypePathEntry.ARRAY)); - return super.visitArrayType(t, path); + public Type visitWildcardType( + WildcardType wt, List path) { + Type t = wt.type; + if (t != null) { + t = visit(t, path.append(TypeAnnotationPosition.TypePathEntry.WILDCARD)); + } + if (t != wt.type) { + wt = new WildcardType(t, wt.kind, wt.tsym, wt.bound, wt.getMetadata()); + } + return reannotate(wt, path); } @Override - public Void visitType(Type t, List path) { - ListBuffer attributes = attributesByPath.remove(path); - if (attributes != null) { - attributesByType.put(t, attributes.toList()); + public Type visitArrayType(ArrayType t, List path) { + Type elemtype = t.elemtype; + Type elemtype1 = + visit(elemtype, path.append(TypeAnnotationPosition.TypePathEntry.ARRAY)); + if (elemtype1 != elemtype) { + t = new ArrayType(elemtype1, t.tsym, t.getMetadata()); } - return null; + return reannotate(t, path); } - } - - /** A type mapping that rewrites the type to include type annotations. */ - private static class TypeAnnotationTypeMapping extends Type.StructuralTypeMapping { - private final Map> attributesByType; - - private TypeAnnotationTypeMapping( - Map> attributesByType) { - this.attributesByType = attributesByType; + @Override + public Type visitType(Type t, List path) { + return reannotate(t, path); } - private Type reannotate(T t, BiFunction f) { - // We're relying on object identify of Type instances to record where the annotations - // need to be added, so we have to retrieve the annotations for each type before - // rewriting it, and then add them after its contained types have been rewritten. - List attributes = attributesByType.remove(t); - Type mapped = f.apply(t, null); - if (attributes == null) { - return mapped; + Type reannotate(Type type, List path) { + List attributes = attributesForPath(path); + if (attributes.isEmpty()) { + return type; } // Runtime-visible and -invisible annotations are completed separately, so if the same // type has annotations from both it will get annotated twice. - TypeMetadata.Annotations existing = mapped.getMetadata(TypeMetadata.Annotations.class); + TypeMetadata.Annotations existing = type.getMetadata(TypeMetadata.Annotations.class); if (existing != null) { existing.annotationBuffer().addAll(attributes); - return mapped; + return type; } - return mapped.annotatedType(attributes); + return type.annotatedType(attributes); } - @Override - public Type visitClassType(ClassType t, Void unused) { - return reannotate(t, super::visitClassType); - } - - @Override - public Type visitWildcardType(WildcardType t, Void unused) { - return reannotate(t, super::visitWildcardType); - } - - @Override - public Type visitArrayType(ArrayType t, Void unused) { - return reannotate(t, super::visitArrayType); - } - - @Override - public Type visitType(Type t, Void unused) { - return reannotate(t, (x, u) -> x); + List attributesForPath( + List path) { + ListBuffer attributes = attributesByPath.remove(path); + return attributes != null ? attributes.toList() : List.nil(); } } diff --git a/test/langtools/tools/javac/processing/model/type/BasicAnnoTests.java b/test/langtools/tools/javac/processing/model/type/BasicAnnoTests.java index d45edc8e3d6e3..acd91eac8c785 100644 --- a/test/langtools/tools/javac/processing/model/type/BasicAnnoTests.java +++ b/test/langtools/tools/javac/processing/model/type/BasicAnnoTests.java @@ -717,4 +717,8 @@ private class GenericNested { GenericNested(@TA(120) GenericInner120 GenericInner120.this) {} } } + + @Test(posn=1, annoType=TA.class, expect="130") + @Test(posn=23, annoType=TA.class, expect="131") + public Map<@TA(130) String, @TA(131) String> f130; } From 99edb4a45d6a4a871dec9c07b41b3ab66b89a4b6 Mon Sep 17 00:00:00 2001 From: Vladimir Kozlov Date: Mon, 12 Aug 2024 17:20:20 +0000 Subject: [PATCH 269/353] 8337702: Use new ForwardExceptionNode to call StubRoutines::forward_exception_entry() Reviewed-by: thartmann --- src/hotspot/cpu/aarch64/aarch64.ad | 13 ++++++++ src/hotspot/cpu/arm/arm.ad | 14 +++++++++ src/hotspot/cpu/ppc/ppc.ad | 15 +++++++++ src/hotspot/cpu/riscv/riscv.ad | 16 ++++++++++ src/hotspot/cpu/s390/s390.ad | 14 +++++++++ src/hotspot/cpu/x86/x86_32.ad | 12 ++++++++ src/hotspot/cpu/x86/x86_64.ad | 12 ++++++++ src/hotspot/share/adlc/formssel.cpp | 34 ++++++++++++--------- src/hotspot/share/opto/callnode.hpp | 11 +++++++ src/hotspot/share/opto/classes.hpp | 1 + src/hotspot/share/opto/domgraph.cpp | 1 + src/hotspot/share/opto/gcm.cpp | 5 ++- src/hotspot/share/opto/generateOptoStub.cpp | 14 ++++----- src/hotspot/share/opto/matcher.cpp | 15 ++++++++- src/hotspot/share/runtime/vmStructs.cpp | 1 + 15 files changed, 153 insertions(+), 25 deletions(-) diff --git a/src/hotspot/cpu/aarch64/aarch64.ad b/src/hotspot/cpu/aarch64/aarch64.ad index d8db75961d8af..66a24a61f29c2 100644 --- a/src/hotspot/cpu/aarch64/aarch64.ad +++ b/src/hotspot/cpu/aarch64/aarch64.ad @@ -16184,6 +16184,19 @@ instruct TailjmpInd(iRegPNoSpNoRfp jump_target, iRegP_R0 ex_oop) ins_pipe(pipe_class_call); %} +// Forward exception. +instruct ForwardExceptionjmp() +%{ + match(ForwardException); + ins_cost(CALL_COST); + + format %{ "b forward_exception_stub" %} + ins_encode %{ + __ far_jump(RuntimeAddress(StubRoutines::forward_exception_entry())); + %} + ins_pipe(pipe_class_call); +%} + // Create exception oop: created by stack-crawling runtime code. // Created exception is now available to this handler, and is setup // just prior to jumping to this handler. No code emitted. diff --git a/src/hotspot/cpu/arm/arm.ad b/src/hotspot/cpu/arm/arm.ad index 638c48ad5aa31..2c7de0a58a204 100644 --- a/src/hotspot/cpu/arm/arm.ad +++ b/src/hotspot/cpu/arm/arm.ad @@ -8953,6 +8953,20 @@ instruct tailjmpInd(IPRegP jump_target, RExceptionRegP ex_oop) %{ ins_pipe(tail_call); %} +// Forward exception. +instruct ForwardExceptionjmp() +%{ + match(ForwardException); + ins_cost(CALL_COST); + + format %{ "b forward_exception_stub" %} + ins_encode %{ + // OK to trash Rtemp, because Rtemp is used by stub + __ jump(StubRoutines::forward_exception_entry(), relocInfo::runtime_call_type, Rtemp); + %} + ins_pipe(tail_call); +%} + // Create exception oop: created by stack-crawling runtime code. // Created exception is now available to this handler, and is setup // just prior to jumping to this handler. No code emitted. diff --git a/src/hotspot/cpu/ppc/ppc.ad b/src/hotspot/cpu/ppc/ppc.ad index 38485da958132..b34d3ef150140 100644 --- a/src/hotspot/cpu/ppc/ppc.ad +++ b/src/hotspot/cpu/ppc/ppc.ad @@ -14534,6 +14534,21 @@ instruct tailjmpInd(iRegPdstNoScratch jump_target, rarg1RegP ex_oop) %{ ins_pipe(pipe_class_call); %} +// Forward exception. +instruct ForwardExceptionjmp() +%{ + match(ForwardException); + ins_cost(CALL_COST); + + format %{ "Jmp forward_exception_stub" %} + ins_encode %{ + __ set_inst_mark(); + __ b64_patchable(StubRoutines::forward_exception_entry(), relocInfo::runtime_call_type); + __ clear_inst_mark(); + %} + ins_pipe(pipe_class_call); +%} + // Create exception oop: created by stack-crawling runtime code. // Created exception is now available to this handler, and is setup // just prior to jumping to this handler. No code emitted. diff --git a/src/hotspot/cpu/riscv/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad index 1e26c2bf14202..d3e2b0549e9ea 100644 --- a/src/hotspot/cpu/riscv/riscv.ad +++ b/src/hotspot/cpu/riscv/riscv.ad @@ -10617,6 +10617,22 @@ instruct TailjmpInd(iRegPNoSpNoFp jump_target, iRegP_R10 ex_oop) ins_pipe(pipe_class_call); %} +// Forward exception. +instruct ForwardExceptionjmp() +%{ + match(ForwardException); + + ins_cost(BRANCH_COST); + + format %{ "j forward_exception_stub\t#@ForwardException" %} + + ins_encode %{ + __ far_jump(RuntimeAddress(StubRoutines::forward_exception_entry())); + %} + + ins_pipe(pipe_class_call); +%} + // Create exception oop: created by stack-crawling runtime code. // Created exception is now available to this handler, and is setup // just prior to jumping to this handler. No code emitted. diff --git a/src/hotspot/cpu/s390/s390.ad b/src/hotspot/cpu/s390/s390.ad index e3dcfdb8759da..4de1a4e7b7f35 100644 --- a/src/hotspot/cpu/s390/s390.ad +++ b/src/hotspot/cpu/s390/s390.ad @@ -9517,6 +9517,20 @@ instruct tailjmpInd(iRegP jump_target, rarg1RegP ex_oop) %{ ins_pipe(pipe_class_dummy); %} +// Forward exception. +instruct ForwardExceptionjmp() %{ + match(ForwardException); + ins_cost(CALL_COST); + format %{ "Jmp forward_exception_stub" %} + ins_encode %{ + __ set_inst_mark(); + __ load_const_optimized(Z_R1_scratch, (address)StubRoutines::forward_exception_entry()); + __ z_br(Z_R1_scratch); + __ clear_inst_mark(); + %} + ins_pipe(pipe_class_dummy); +%} + // Create exception oop: created by stack-crawling runtime code. // Created exception is now available to this handler, and is setup // just prior to jumping to this handler. No code emitted. diff --git a/src/hotspot/cpu/x86/x86_32.ad b/src/hotspot/cpu/x86/x86_32.ad index 49a3cad37df2f..7aa4f6a29a116 100644 --- a/src/hotspot/cpu/x86/x86_32.ad +++ b/src/hotspot/cpu/x86/x86_32.ad @@ -13583,6 +13583,18 @@ instruct tailjmpInd(eRegP_no_EBP jump_target, eAXRegP ex_oop) %{ ins_pipe( pipe_jmp ); %} +// Forward exception. +instruct ForwardExceptionjmp() +%{ + match(ForwardException); + + format %{ "JMP forward_exception_stub" %} + ins_encode %{ + __ jump(RuntimeAddress(StubRoutines::forward_exception_entry()), noreg); + %} + ins_pipe(pipe_jmp); +%} + // Create exception oop: created by stack-crawling runtime code. // Created exception is now available to this handler, and is setup // just prior to jumping to this handler. No code emitted. diff --git a/src/hotspot/cpu/x86/x86_64.ad b/src/hotspot/cpu/x86/x86_64.ad index 1490cfa60b34f..3bc4cac2f06a7 100644 --- a/src/hotspot/cpu/x86/x86_64.ad +++ b/src/hotspot/cpu/x86/x86_64.ad @@ -12592,6 +12592,18 @@ instruct tailjmpInd(no_rbp_RegP jump_target, rax_RegP ex_oop) ins_pipe(pipe_jmp); %} +// Forward exception. +instruct ForwardExceptionjmp() +%{ + match(ForwardException); + + format %{ "jmp forward_exception_stub" %} + ins_encode %{ + __ jump(RuntimeAddress(StubRoutines::forward_exception_entry()), noreg); + %} + ins_pipe(pipe_jmp); +%} + // Create exception oop: created by stack-crawling runtime code. // Created exception is now available to this handler, and is setup // just prior to jumping to this handler. No code emitted. diff --git a/src/hotspot/share/adlc/formssel.cpp b/src/hotspot/share/adlc/formssel.cpp index be97547f8ce11..e7df38ff221a9 100644 --- a/src/hotspot/share/adlc/formssel.cpp +++ b/src/hotspot/share/adlc/formssel.cpp @@ -210,15 +210,16 @@ bool InstructForm::is_pinned(FormDict &globals) { if ( ! _matrule) return false; int index = 0; - if (_matrule->find_type("Goto", index)) return true; - if (_matrule->find_type("If", index)) return true; - if (_matrule->find_type("CountedLoopEnd",index)) return true; - if (_matrule->find_type("Return", index)) return true; - if (_matrule->find_type("Rethrow", index)) return true; - if (_matrule->find_type("TailCall", index)) return true; - if (_matrule->find_type("TailJump", index)) return true; - if (_matrule->find_type("Halt", index)) return true; - if (_matrule->find_type("Jump", index)) return true; + if (_matrule->find_type("Goto", index)) return true; + if (_matrule->find_type("If", index)) return true; + if (_matrule->find_type("CountedLoopEnd", index)) return true; + if (_matrule->find_type("Return", index)) return true; + if (_matrule->find_type("Rethrow", index)) return true; + if (_matrule->find_type("TailCall", index)) return true; + if (_matrule->find_type("TailJump", index)) return true; + if (_matrule->find_type("ForwardException", index)) return true; + if (_matrule->find_type("Halt", index)) return true; + if (_matrule->find_type("Jump", index)) return true; return is_parm(globals); } @@ -228,12 +229,13 @@ bool InstructForm::is_projection(FormDict &globals) { if ( ! _matrule) return false; int index = 0; - if (_matrule->find_type("Goto", index)) return true; - if (_matrule->find_type("Return", index)) return true; - if (_matrule->find_type("Rethrow", index)) return true; - if (_matrule->find_type("TailCall",index)) return true; - if (_matrule->find_type("TailJump",index)) return true; - if (_matrule->find_type("Halt", index)) return true; + if (_matrule->find_type("Goto", index)) return true; + if (_matrule->find_type("Return", index)) return true; + if (_matrule->find_type("Rethrow", index)) return true; + if (_matrule->find_type("TailCall", index)) return true; + if (_matrule->find_type("TailJump", index)) return true; + if (_matrule->find_type("ForwardException", index)) return true; + if (_matrule->find_type("Halt", index)) return true; return false; } @@ -376,6 +378,7 @@ bool InstructForm::is_ideal_return() const { if (_matrule->find_type("Rethrow",index)) return true; if (_matrule->find_type("TailCall",index)) return true; if (_matrule->find_type("TailJump",index)) return true; + if (_matrule->find_type("ForwardException", index)) return true; return false; } @@ -894,6 +897,7 @@ uint InstructForm::oper_input_base(FormDict &globals) { strcmp(_matrule->_opType,"Rethrow" )==0 || strcmp(_matrule->_opType,"TailCall" )==0 || strcmp(_matrule->_opType,"TailJump" )==0 || + strcmp(_matrule->_opType,"ForwardException")==0 || strcmp(_matrule->_opType,"SafePoint" )==0 || strcmp(_matrule->_opType,"Halt" )==0 ) return AdlcVMDeps::Parms; // Skip the machine-state edges diff --git a/src/hotspot/share/opto/callnode.hpp b/src/hotspot/share/opto/callnode.hpp index 120bb112ec56b..2d3835b71ad42 100644 --- a/src/hotspot/share/opto/callnode.hpp +++ b/src/hotspot/share/opto/callnode.hpp @@ -152,6 +152,17 @@ class RethrowNode : public Node { }; +//------------------------------ForwardExceptionNode--------------------------- +// Pop stack frame and jump to StubRoutines::forward_exception_entry() +class ForwardExceptionNode : public ReturnNode { +public: + ForwardExceptionNode(Node* cntrl, Node* i_o, Node* memory, Node* frameptr, Node* retadr) + : ReturnNode(TypeFunc::Parms, cntrl, i_o, memory, frameptr, retadr) { + } + + virtual int Opcode() const; +}; + //------------------------------TailCallNode----------------------------------- // Pop stack frame and jump indirect class TailCallNode : public ReturnNode { diff --git a/src/hotspot/share/opto/classes.hpp b/src/hotspot/share/opto/classes.hpp index dc61377687302..8bee6279446ef 100644 --- a/src/hotspot/share/opto/classes.hpp +++ b/src/hotspot/share/opto/classes.hpp @@ -184,6 +184,7 @@ macro(FastLock) macro(FastUnlock) macro(FmaD) macro(FmaF) +macro(ForwardException) macro(Goto) macro(Halt) macro(CountPositives) diff --git a/src/hotspot/share/opto/domgraph.cpp b/src/hotspot/share/opto/domgraph.cpp index 363005d1181c2..84f83ef131bbd 100644 --- a/src/hotspot/share/opto/domgraph.cpp +++ b/src/hotspot/share/opto/domgraph.cpp @@ -239,6 +239,7 @@ uint Block_Stack::most_frequent_successor( Block *b ) { break; case Op_TailCall: case Op_TailJump: + case Op_ForwardException: case Op_Return: case Op_Halt: case Op_Rethrow: diff --git a/src/hotspot/share/opto/gcm.cpp b/src/hotspot/share/opto/gcm.cpp index 23ae8cbcb6b08..3880bea07d711 100644 --- a/src/hotspot/share/opto/gcm.cpp +++ b/src/hotspot/share/opto/gcm.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2031,6 +2031,7 @@ float Block::succ_prob(uint i) { case Op_TailCall: case Op_TailJump: + case Op_ForwardException: case Op_Return: case Op_Halt: case Op_Rethrow: @@ -2084,6 +2085,7 @@ int Block::num_fall_throughs() { case Op_NeverBranch: case Op_TailCall: case Op_TailJump: + case Op_ForwardException: case Op_Return: case Op_Halt: case Op_Rethrow: @@ -2129,6 +2131,7 @@ bool Block::succ_fall_through(uint i) { case Op_NeverBranch: case Op_TailCall: case Op_TailJump: + case Op_ForwardException: case Op_Return: case Op_Halt: case Op_Rethrow: diff --git a/src/hotspot/share/opto/generateOptoStub.cpp b/src/hotspot/share/opto/generateOptoStub.cpp index 9bd7d42a3f9d7..e22f484c17955 100644 --- a/src/hotspot/share/opto/generateOptoStub.cpp +++ b/src/hotspot/share/opto/generateOptoStub.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -255,13 +255,11 @@ void GraphKit::gen_stub(address C_function, Node* if_not_null = _gvn.transform( new IfTrueNode(iff) ); assert (StubRoutines::forward_exception_entry() != nullptr, "must be generated before"); - Node *exc_target = makecon(TypeRawPtr::make( StubRoutines::forward_exception_entry() )); - Node *to_exc = new TailCallNode(if_not_null, - i_o(), - exit_memory, - frameptr(), - returnadr(), - exc_target, null()); + Node *to_exc = new ForwardExceptionNode(if_not_null, + i_o(), + exit_memory, + frameptr(), + returnadr()); root()->add_req(_gvn.transform(to_exc)); // bind to root to keep live C->init_start(start); diff --git a/src/hotspot/share/opto/matcher.cpp b/src/hotspot/share/opto/matcher.cpp index 4e2306602e6f7..bf773d43d3d39 100644 --- a/src/hotspot/share/opto/matcher.cpp +++ b/src/hotspot/share/opto/matcher.cpp @@ -804,6 +804,10 @@ void Matcher::Fixup_Save_On_Entry( ) { if (ret_edge_cnt > TypeFunc::Parms) ret_rms[TypeFunc::Parms+0] = _return_value_mask; + // Input RegMask array shared by all ForwardExceptions + uint forw_exc_edge_cnt = TypeFunc::Parms; + RegMask* forw_exc_rms = init_input_masks( forw_exc_edge_cnt + soe_cnt, _return_addr_mask, c_frame_ptr_mask ); + // Input RegMask array shared by all Rethrows. uint reth_edge_cnt = TypeFunc::Parms+1; RegMask *reth_rms = init_input_masks( reth_edge_cnt + soe_cnt, _return_addr_mask, c_frame_ptr_mask ); @@ -863,6 +867,7 @@ void Matcher::Fixup_Save_On_Entry( ) { case Op_Rethrow : exit->_in_rms = reth_rms; break; case Op_TailCall : exit->_in_rms = tail_call_rms; break; case Op_TailJump : exit->_in_rms = tail_jump_rms; break; + case Op_ForwardException: exit->_in_rms = forw_exc_rms; break; case Op_Halt : exit->_in_rms = halt_rms; break; default : ShouldNotReachHere(); } @@ -882,6 +887,7 @@ void Matcher::Fixup_Save_On_Entry( ) { reth_rms [ reth_edge_cnt] = mreg2regmask[i]; tail_call_rms[tail_call_edge_cnt] = mreg2regmask[i]; tail_jump_rms[tail_jump_edge_cnt] = mreg2regmask[i]; + forw_exc_rms [ forw_exc_edge_cnt] = mreg2regmask[i]; // Halts need the SOE registers, but only in the stack as debug info. // A just-prior uncommon-trap or deoptimization will use the SOE regs. halt_rms [ halt_edge_cnt] = *idealreg2spillmask[_register_save_type[i]]; @@ -899,6 +905,7 @@ void Matcher::Fixup_Save_On_Entry( ) { reth_rms [ reth_edge_cnt].Insert(OptoReg::Name(i+1)); tail_call_rms[tail_call_edge_cnt].Insert(OptoReg::Name(i+1)); tail_jump_rms[tail_jump_edge_cnt].Insert(OptoReg::Name(i+1)); + forw_exc_rms [ forw_exc_edge_cnt].Insert(OptoReg::Name(i+1)); halt_rms [ halt_edge_cnt].Insert(OptoReg::Name(i+1)); mproj = new MachProjNode( start, proj_cnt, ret_rms[ret_edge_cnt], Op_RegD ); proj_cnt += 2; // Skip 2 for doubles @@ -911,6 +918,7 @@ void Matcher::Fixup_Save_On_Entry( ) { reth_rms [ reth_edge_cnt] = RegMask::Empty; tail_call_rms[tail_call_edge_cnt] = RegMask::Empty; tail_jump_rms[tail_jump_edge_cnt] = RegMask::Empty; + forw_exc_rms [ forw_exc_edge_cnt] = RegMask::Empty; halt_rms [ halt_edge_cnt] = RegMask::Empty; mproj = C->top(); } @@ -925,6 +933,7 @@ void Matcher::Fixup_Save_On_Entry( ) { reth_rms [ reth_edge_cnt].Insert(OptoReg::Name(i+1)); tail_call_rms[tail_call_edge_cnt].Insert(OptoReg::Name(i+1)); tail_jump_rms[tail_jump_edge_cnt].Insert(OptoReg::Name(i+1)); + forw_exc_rms [ forw_exc_edge_cnt].Insert(OptoReg::Name(i+1)); halt_rms [ halt_edge_cnt].Insert(OptoReg::Name(i+1)); mproj = new MachProjNode( start, proj_cnt, ret_rms[ret_edge_cnt], Op_RegL ); proj_cnt += 2; // Skip 2 for longs @@ -937,6 +946,7 @@ void Matcher::Fixup_Save_On_Entry( ) { reth_rms [ reth_edge_cnt] = RegMask::Empty; tail_call_rms[tail_call_edge_cnt] = RegMask::Empty; tail_jump_rms[tail_jump_edge_cnt] = RegMask::Empty; + forw_exc_rms [ forw_exc_edge_cnt] = RegMask::Empty; halt_rms [ halt_edge_cnt] = RegMask::Empty; mproj = C->top(); } else { @@ -948,11 +958,13 @@ void Matcher::Fixup_Save_On_Entry( ) { reth_edge_cnt ++; tail_call_edge_cnt ++; tail_jump_edge_cnt ++; + forw_exc_edge_cnt++; halt_edge_cnt ++; // Add a use of the SOE register to all exit paths - for( uint j=1; j < root->req(); j++ ) + for (uint j=1; j < root->req(); j++) { root->in(j)->add_req(mproj); + } } // End of if a save-on-entry register } // End of for all machine registers } @@ -1070,6 +1082,7 @@ static void match_alias_type(Compile* C, Node* n, Node* m) { case Op_Halt: case Op_TailCall: case Op_TailJump: + case Op_ForwardException: nidx = Compile::AliasIdxBot; nat = TypePtr::BOTTOM; break; diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index 4b6381bd05ebd..27dc10d2adb17 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -1422,6 +1422,7 @@ declare_c2_type(RethrowNode, Node) \ declare_c2_type(TailCallNode, ReturnNode) \ declare_c2_type(TailJumpNode, ReturnNode) \ + declare_c2_type(ForwardExceptionNode, ReturnNode) \ declare_c2_type(SafePointNode, MultiNode) \ declare_c2_type(CallNode, SafePointNode) \ declare_c2_type(CallJavaNode, CallNode) \ From 2ca136a7adb6defaea3b7a69d30e6c36bda66e6a Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Mon, 12 Aug 2024 17:26:51 +0000 Subject: [PATCH 270/353] 8337815: Relax G1EvacStats atomic operations Reviewed-by: kbarrett, tschatzl, shade --- src/hotspot/share/gc/g1/g1EvacStats.inline.hpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1EvacStats.inline.hpp b/src/hotspot/share/gc/g1/g1EvacStats.inline.hpp index 4b4c6e104b7e3..d4cae1f983652 100644 --- a/src/hotspot/share/gc/g1/g1EvacStats.inline.hpp +++ b/src/hotspot/share/gc/g1/g1EvacStats.inline.hpp @@ -30,25 +30,25 @@ #include "runtime/atomic.hpp" inline void G1EvacStats::add_direct_allocated(size_t value) { - Atomic::add(&_direct_allocated, value); + Atomic::add(&_direct_allocated, value, memory_order_relaxed); } inline void G1EvacStats::add_num_plab_filled(size_t value) { - Atomic::add(&_num_plab_filled, value); + Atomic::add(&_num_plab_filled, value, memory_order_relaxed); } inline void G1EvacStats::add_num_direct_allocated(size_t value) { - Atomic::add(&_num_direct_allocated, value); + Atomic::add(&_num_direct_allocated, value, memory_order_relaxed); } inline void G1EvacStats::add_region_end_waste(size_t value) { - Atomic::add(&_region_end_waste, value); - Atomic::inc(&_regions_filled); + Atomic::add(&_region_end_waste, value, memory_order_relaxed); + Atomic::inc(&_regions_filled, memory_order_relaxed); } inline void G1EvacStats::add_failure_used_and_waste(size_t used, size_t waste) { - Atomic::add(&_failure_used, used); - Atomic::add(&_failure_waste, waste); + Atomic::add(&_failure_used, used, memory_order_relaxed); + Atomic::add(&_failure_waste, waste, memory_order_relaxed); } #endif // SHARE_GC_G1_G1EVACSTATS_INLINE_HPP From 41e31d6b0ae00d70b6fb20c89318fde2bc605edb Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Mon, 12 Aug 2024 17:56:46 +0000 Subject: [PATCH 271/353] 8337622: IllegalArgumentException in java.lang.reflect.Field.get Reviewed-by: dholmes, shade --- src/hotspot/share/classfile/javaClasses.cpp | 7 --- src/hotspot/share/classfile/javaClasses.hpp | 1 + .../reflect/ComponentTypeFieldTest.java | 50 +++++++++++++++++++ 3 files changed, 51 insertions(+), 7 deletions(-) create mode 100644 test/hotspot/jtreg/runtime/reflect/ComponentTypeFieldTest.java diff --git a/src/hotspot/share/classfile/javaClasses.cpp b/src/hotspot/share/classfile/javaClasses.cpp index ab9460e2b9b01..8a6c8a8ce0b36 100644 --- a/src/hotspot/share/classfile/javaClasses.cpp +++ b/src/hotspot/share/classfile/javaClasses.cpp @@ -1452,19 +1452,12 @@ void java_lang_Class::compute_offsets() { InstanceKlass* k = vmClasses::Class_klass(); CLASS_FIELDS_DO(FIELD_COMPUTE_OFFSET); - - // Init lock is a C union with component_mirror. Only instanceKlass mirrors have - // init_lock and only ArrayKlass mirrors have component_mirror. Since both are oops - // GC treats them the same. - _init_lock_offset = _component_mirror_offset; - CLASS_INJECTED_FIELDS(INJECTED_FIELD_COMPUTE_OFFSET); } #if INCLUDE_CDS void java_lang_Class::serialize_offsets(SerializeClosure* f) { f->do_bool(&_offsets_computed); - f->do_u4((u4*)&_init_lock_offset); CLASS_FIELDS_DO(FIELD_SERIALIZE_OFFSET); diff --git a/src/hotspot/share/classfile/javaClasses.hpp b/src/hotspot/share/classfile/javaClasses.hpp index 57914e189b75d..eb3c5e29fdb11 100644 --- a/src/hotspot/share/classfile/javaClasses.hpp +++ b/src/hotspot/share/classfile/javaClasses.hpp @@ -209,6 +209,7 @@ class java_lang_String : AllStatic { macro(java_lang_Class, static_oop_field_count, int_signature, false) \ macro(java_lang_Class, protection_domain, object_signature, false) \ macro(java_lang_Class, source_file, object_signature, false) \ + macro(java_lang_Class, init_lock, object_signature, false) class java_lang_Class : AllStatic { friend class VMStructs; diff --git a/test/hotspot/jtreg/runtime/reflect/ComponentTypeFieldTest.java b/test/hotspot/jtreg/runtime/reflect/ComponentTypeFieldTest.java new file mode 100644 index 0000000000000..6296a7f970e74 --- /dev/null +++ b/test/hotspot/jtreg/runtime/reflect/ComponentTypeFieldTest.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8337622 + * @summary (reflect) java.lang.Class componentType field not found. + * @library /test/lib + * @modules java.base/java.lang:open + * @run main ComponentTypeFieldTest + */ + +import java.lang.reflect.Field; +import static jdk.test.lib.Asserts.*; + +public class ComponentTypeFieldTest { + + public static void main(String[] args) throws Exception { + Field f = Class.class.getDeclaredField("componentType"); + f.setAccessible(true); + Object val = f.get(Runnable.class); + assertTrue(val == null); + System.out.println("val is " + val); + + Object arrayVal = f.get(Integer[].class); + System.out.println("val is " + arrayVal); + String arrayValString = arrayVal.toString(); + assertTrue(arrayValString.equals("class java.lang.Integer")); + } +} From b93b74e3ebd220e94fb5e33d2ebc62181db97bb0 Mon Sep 17 00:00:00 2001 From: Roger Riggs Date: Mon, 12 Aug 2024 19:28:46 +0000 Subject: [PATCH 272/353] 8338060: jdk/internal/util/ReferencedKeyTest should be more robust Reviewed-by: never --- .../jdk/internal/util/ReferencedKeyTest.java | 130 ++++++++++-------- 1 file changed, 76 insertions(+), 54 deletions(-) diff --git a/test/jdk/jdk/internal/util/ReferencedKeyTest.java b/test/jdk/jdk/internal/util/ReferencedKeyTest.java index 75690fa6e258a..c68908a8d5a42 100644 --- a/test/jdk/jdk/internal/util/ReferencedKeyTest.java +++ b/test/jdk/jdk/internal/util/ReferencedKeyTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 8285932 8310913 + * @bug 8285932 8310913 8336390 8338060 * @summary Test features provided by the ReferencedKeyMap/ReferencedKeySet classes. * @modules java.base/jdk.internal.util * @compile --patch-module java.base=${test.src} ReferencedKeyTest.java @@ -36,14 +36,27 @@ import java.lang.ref.Reference; import java.lang.ref.ReferenceQueue; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.function.BooleanSupplier; +import java.util.function.Function; import java.util.function.Supplier; +import java.util.stream.IntStream; public class ReferencedKeyTest { - static long BASE_KEY = 10_000_000L; + private static String BASE_KEY = "BASEKEY-"; + + // Return a String (identity object) that can be a key in WeakHashMap. + private static String genKey(int i) { + return BASE_KEY + i; + } + + // Return a String of the letter 'a' plus the integer (0..0xffff) + private static String genValue(int i) { + return String.valueOf((char) ('a' + i)); + } public static void main(String[] args) { mapTest(false, HashMap::new); @@ -63,73 +76,77 @@ static void assertTrue(boolean test, String message) { } } - static void mapTest(boolean isSoft, Supplier, String>> supplier) { - Map map = ReferencedKeyMap.create(isSoft, supplier); - populate(map); + static void mapTest(boolean isSoft, Supplier, String>> supplier) { + Map map = ReferencedKeyMap.create(isSoft, supplier); + var strongKeys = populate(map); // Retain references to the keys + methods(map); + Reference.reachabilityFence(strongKeys); + + strongKeys = null; // drop strong key references if (!isSoft) { if (!collect(() -> map.isEmpty())) { throw new RuntimeException("WeakReference map not collecting!"); } } - populate(map); - methods(map); } - static void setTest(boolean isSoft, Supplier, ReferenceKey>> supplier) { - ReferencedKeySet set = ReferencedKeySet.create(isSoft, supplier); - populate(set); + static void setTest(boolean isSoft, Supplier, ReferenceKey>> supplier) { + ReferencedKeySet set = ReferencedKeySet.create(isSoft, supplier); + var strongKeys = populate(set); // Retain references to the keys + methods(set); + Reference.reachabilityFence(strongKeys); + + strongKeys = null; // drop strong key references if (!isSoft) { if (!collect(() -> set.isEmpty())) { throw new RuntimeException("WeakReference set not collecting!"); } } - populate(set); - methods(set); } - static void methods(Map map) { + static void methods(Map map) { assertTrue(map.size() == 26, "missing key"); - assertTrue(map.containsKey(BASE_KEY + 'a' -'a'), "missing key"); - assertTrue(map.get(BASE_KEY + 'b' -'a').equals("b"), "wrong key"); + assertTrue(map.containsKey(genKey('a' -'a')), "missing key"); + assertTrue(map.get(genKey('b' -'a')).equals("b"), "wrong key"); assertTrue(map.containsValue("c"), "missing value"); - map.remove(BASE_KEY + 'd' -'a'); - assertTrue(map.get(BASE_KEY + 'd' -'a') == null, "not removed"); - map.putAll(Map.of(1L, "A", 2L, "B")); - assertTrue(map.get(2L).equals("B"), "collection not added"); - assertTrue(map.containsKey(1L), "key missing"); + map.remove(genKey('d' -'a')); + assertTrue(map.get(genKey('d' -'a')) == null, "not removed"); + map.putAll(Map.of(genKey(1), "A", genKey(2), "B")); + assertTrue(map.get(genKey(2)).equals("B"), "collection not added"); + assertTrue(map.containsKey(genKey(1)), "key missing"); assertTrue(map.containsValue("A"), "key missing"); - assertTrue(map.entrySet().contains(Map.entry(1L, "A")), "key missing"); - map.putIfAbsent(3L, "C"); - assertTrue(map.get(3L).equals("C"), "key missing"); - map.putIfAbsent(2L, "D"); - assertTrue(map.get(2L).equals("B"), "key replaced"); - map.remove(3L); - assertTrue(map.get(3L) == null, "key not removed"); - map.replace(2L, "D"); - assertTrue(map.get(2L).equals("D"), "key not replaced"); - map.replace(2L, "B", "E"); - assertTrue(map.get(2L).equals("D"), "key replaced"); + assertTrue(map.entrySet().contains(Map.entry(genKey(1), "A")), "key missing"); + map.putIfAbsent(genKey(3), "C"); + assertTrue(map.get(genKey(3)).equals("C"), "key missing"); + map.putIfAbsent(genKey(2), "D"); + assertTrue(map.get(genKey(2)).equals("B"), "key replaced"); + map.remove(genKey(3)); + assertTrue(map.get(genKey(3)) == null, "key not removed"); + map.replace(genKey(2), "D"); + assertTrue(map.get(genKey(2)).equals("D"), "key not replaced"); + map.replace(genKey(2), "B", "E"); + assertTrue(map.get(genKey(2)).equals("D"), "key replaced"); } - static void methods(ReferencedKeySet set) { + static void methods(ReferencedKeySet set) { assertTrue(set.size() == 26, "missing key"); - assertTrue(set.contains(BASE_KEY + 3), "missing key"); - set.remove(BASE_KEY + 3); - assertTrue(!set.contains(BASE_KEY + 3), "not removed"); - Long element1 = set.get(BASE_KEY + 2); - Long element2 = set.get(BASE_KEY + 3); - Long element3 = set.get(BASE_KEY + 4); - Long intern1 = set.intern(BASE_KEY + 2); - Long intern2 = set.intern(BASE_KEY + 3); - Long intern3 = set.intern(BASE_KEY + 4, e -> e); + assertTrue(set.contains(genKey(3)), "missing key"); + set.remove(genKey(3)); + assertTrue(!set.contains(genKey(3)), "not removed"); + String element1 = set.get(genKey(2)); + String element2 = set.get(genKey(3)); + String element3 = set.get(genKey(4)); + String intern1 = set.intern(genKey(2)); + String intern2 = set.intern(genKey(3)); + String intern3 = set.intern(genKey(4), e -> e); assertTrue(element1 != null, "missing key"); assertTrue(element2 == null, "not removed"); assertTrue(element1 == intern1, "intern failed"); // must be same object assertTrue(intern2 != null, "intern failed"); assertTrue(element3 == intern3, "intern failed"); - Long value1 = Long.valueOf(BASE_KEY + 999); - Long value2 = Long.valueOf(BASE_KEY + 999); + String value1 = genKey(999); + String value2 = genKey(999); assertTrue(set.add(value1), "key not added"); assertTrue(!set.add(value1), "key added after second attempt"); assertTrue(!set.add(value2), "key should not have been added"); @@ -164,18 +181,23 @@ static boolean collect(BooleanSupplier booleanSupplier) { return booleanSupplier.getAsBoolean(); } - static void populate(Map map) { - for (int i = 0; i < 26; i++) { - Long key = BASE_KEY + i; - String value = String.valueOf((char) ('a' + i)); - map.put(key, value); + static List populate(Map map) { + var keyRefs = genStrings(0, 26, ReferencedKeyTest::genKey); + var valueRefs = genStrings(0, 26, ReferencedKeyTest::genValue); + for (int i = 0; i < keyRefs.size(); i++) { + map.put(keyRefs.get(i), valueRefs.get(i)); } + return keyRefs; } - static void populate(Set set) { - for (int i = 0; i < 26; i++) { - Long value = BASE_KEY + i; - set.add(value); - } + static List populate(Set set) { + var keyRefs = genStrings(0, 26, ReferencedKeyTest::genKey); + set.addAll(keyRefs); + return keyRefs; + } + + // Generate a List of consecutive strings using a function int -> String + static List genStrings(int min, int maxExclusive, Function genString) { + return IntStream.range(min, maxExclusive).mapToObj(i -> genString.apply(i)).toList(); } } From 4417c276e484c1fe137ed7f4a7c28709d0c99af2 Mon Sep 17 00:00:00 2001 From: Leonid Mesnik Date: Mon, 12 Aug 2024 19:43:36 +0000 Subject: [PATCH 273/353] 8330535: Update nsk/jdb tests to use driver instead of othervm Reviewed-by: cjplummer --- .../caught_exception002/caught_exception002.java | 10 +++------- .../nsk/jdb/classes/classes001/classes001.java | 10 +++------- .../jdb/classpath/classpath001/classpath001.java | 10 +++------- .../vmTestbase/nsk/jdb/clear/clear002/clear002.java | 10 +++------- .../vmTestbase/nsk/jdb/clear/clear003/clear003.java | 10 +++------- .../vmTestbase/nsk/jdb/clear/clear004/clear004.java | 8 ++------ .../vmTestbase/nsk/jdb/down/down002/down002.java | 10 +++------- .../vmTestbase/nsk/jdb/dump/dump002/dump002.java | 10 +++------- .../vmTestbase/nsk/jdb/eval/eval001/eval001.java | 10 +++------- .../nsk/jdb/exclude/exclude001/exclude001.java | 10 +++------- .../nsk/jdb/fields/fields001/fields001.java | 10 +++------- .../nsk/jdb/hidden_class/hc001/hc001.java | 10 +++------- .../nsk/jdb/ignore/ignore001/ignore001.java | 10 +++------- .../jdb/interrupt/interrupt001/interrupt001.java | 10 +++------- .../vmTestbase/nsk/jdb/kill/kill001/kill001.java | 10 +++------- .../vmTestbase/nsk/jdb/kill/kill002/kill002.java | 10 +++------- .../vmTestbase/nsk/jdb/klass/class001/class001.java | 10 +++------- .../vmTestbase/nsk/jdb/list/list002/list002.java | 10 +++------- .../vmTestbase/nsk/jdb/list/list003/list003.java | 11 ++++------- .../nsk/jdb/locals/locals002/locals002.java | 10 +++------- .../nsk/jdb/methods/methods002/methods002.java | 10 +++------- .../nsk/jdb/monitor/monitor001/monitor001.java | 10 +++------- .../nsk/jdb/monitor/monitor002/monitor002.java | 10 +++------- .../vmTestbase/nsk/jdb/next/next001/next001.java | 10 +++------- .../jdb/options/connect/connect001/connect001.java | 10 +++------- .../jdb/options/connect/connect002/connect002.java | 10 +++------- .../jdb/options/connect/connect003/connect003.java | 10 +++------- .../jdb/options/connect/connect004/connect004.java | 10 +++------- .../jdb/options/connect/connect005/connect005.java | 13 ++++--------- .../listconnectors001/listconnectors001.java | 10 +++------- .../jtreg/vmTestbase/nsk/jdb/pop/pop001/pop001.java | 10 +++------- .../pop_exception001/pop_exception001.java | 10 +++------- .../vmTestbase/nsk/jdb/print/print002/print002.java | 10 +++------- .../vmTestbase/nsk/jdb/read/read001/read001.java | 10 +++------- .../nsk/jdb/redefine/redefine001/redefine001.java | 10 +++------- .../nsk/jdb/reenter/reenter001/reenter001.java | 10 +++------- .../nsk/jdb/regression/b4689395/b4689395.java | 10 +++------- .../nsk/jdb/repeat/repeat001/repeat001.java | 10 +++------- .../nsk/jdb/resume/resume002/resume002.java | 10 +++------- .../jtreg/vmTestbase/nsk/jdb/run/run002/run002.java | 10 +++------- .../jtreg/vmTestbase/nsk/jdb/set/set001/set001.java | 10 +++------- .../jtreg/vmTestbase/nsk/jdb/set/set002/set002.java | 10 +++------- .../vmTestbase/nsk/jdb/step/step002/step002.java | 10 +++------- .../nsk/jdb/step_up/step_up001/step_up001.java | 10 +++------- .../nsk/jdb/stop_at/stop_at002/stop_at002.java | 8 ++------ .../nsk/jdb/stop_at/stop_at003/stop_at003.java | 10 +++------- .../nsk/jdb/stop_in/stop_in002/stop_in002.java | 10 +++------- .../nsk/jdb/suspend/suspend001/suspend001.java | 10 +++------- .../nsk/jdb/thread/thread002/thread002.java | 10 +++------- .../threadgroup/threadgroup002/threadgroup002.java | 10 +++------- .../threadgroups002/threadgroups002.java | 10 +++------- .../nsk/jdb/threads/threads002/threads002.java | 10 +++------- .../nsk/jdb/threads/threads003/threads003.java | 10 +++------- .../vmTestbase/nsk/jdb/trace/trace001/trace001.java | 10 +++------- .../uncaught_exception002.java | 10 +++------- .../jdb/unmonitor/unmonitor001/unmonitor001.java | 10 +++------- .../nsk/jdb/untrace/untrace001/untrace001.java | 10 +++------- .../nsk/jdb/unwatch/unwatch001/unwatch001.java | 10 +++------- .../nsk/jdb/unwatch/unwatch002/unwatch002.java | 10 +++------- .../jtreg/vmTestbase/nsk/jdb/up/up002/up002.java | 10 +++------- .../jtreg/vmTestbase/nsk/jdb/use/use001/use001.java | 10 +++------- .../vmTestbase/nsk/jdb/watch/watch001/watch001.java | 10 +++------- .../vmTestbase/nsk/jdb/watch/watch002/watch002.java | 10 +++------- .../vmTestbase/nsk/jdb/where/where004/where004.java | 10 +++------- .../vmTestbase/nsk/jdb/where/where005/where005.java | 10 +++------- .../vmTestbase/nsk/jdb/where/where006/where006.java | 10 +++------- .../nsk/jdb/wherei/wherei001/wherei001.java | 10 +++------- .../jtreg/vmTestbase/nsk/share/jdb/JdbTest.java | 11 +++++------ .../jtreg/vmTestbase/nsk/share/jdb/Launcher.java | 6 ++++-- 69 files changed, 210 insertions(+), 477 deletions(-) diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/caught_exception/caught_exception002/caught_exception002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/caught_exception/caught_exception002/caught_exception002.java index 4eef7900d4231..04ace5ba49c5d 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/caught_exception/caught_exception002/caught_exception002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/caught_exception/caught_exception002/caught_exception002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,7 +46,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.caught_exception.caught_exception002.caught_exception002a - * @run main/othervm + * @run driver * nsk.jdb.caught_exception.caught_exception002.caught_exception002 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -69,14 +69,10 @@ public class caught_exception002 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new caught_exception002().runTest(argv, out); + new caught_exception002().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.caught_exception.caught_exception002"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/classes/classes001/classes001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/classes/classes001/classes001.java index 40a5ebaa9393c..8543c7c6f1e1d 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/classes/classes001/classes001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/classes/classes001/classes001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,7 +37,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.classes.classes001.classes001a - * @run main/othervm + * @run driver * nsk.jdb.classes.classes001.classes001 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -60,14 +60,10 @@ public class classes001 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new classes001().runTest(argv, out); + new classes001().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.classes.classes001"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/classpath/classpath001/classpath001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/classpath/classpath001/classpath001.java index 0eea9a92ab26f..25a86fe64cbd9 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/classpath/classpath001/classpath001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/classpath/classpath001/classpath001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,7 +36,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.classpath.classpath001.classpath001a - * @run main/othervm + * @run driver * nsk.jdb.classpath.classpath001.classpath001 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -59,14 +59,10 @@ public class classpath001 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new classpath001().runTest(argv, out); + new classpath001().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.classpath.classpath001"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/clear/clear002/clear002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/clear/clear002/clear002.java index 7869a1340a7cd..cca80dad46502 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/clear/clear002/clear002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/clear/clear002/clear002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,7 +38,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.clear.clear002.clear002a - * @run main/othervm + * @run driver * nsk.jdb.clear.clear002.clear002 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -61,14 +61,10 @@ public class clear002 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new clear002().runTest(argv, out); + new clear002().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.clear.clear002"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/clear/clear003/clear003.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/clear/clear003/clear003.java index cbbc851f29a6f..003b1f36eddb7 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/clear/clear003/clear003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/clear/clear003/clear003.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,7 +39,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.clear.clear003.clear003a - * @run main/othervm + * @run driver * nsk.jdb.clear.clear003.clear003 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -62,14 +62,10 @@ public class clear003 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new clear003().runTest(argv, out); + new clear003().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.clear.clear003"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/clear/clear004/clear004.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/clear/clear004/clear004.java index c0ec8d2037095..5dfd33430e38c 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/clear/clear004/clear004.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/clear/clear004/clear004.java @@ -40,7 +40,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.clear.clear004.clear004a - * @run main/othervm + * @run driver * nsk.jdb.clear.clear004.clear004 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -63,14 +63,10 @@ public class clear004 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new clear004().runTest(argv, out); + new clear004().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.clear.clear004"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/down/down002/down002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/down/down002/down002.java index 29a40d9471d67..99f4254891d1e 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/down/down002/down002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/down/down002/down002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,7 +43,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.down.down002.down002a - * @run main/othervm + * @run driver * nsk.jdb.down.down002.down002 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -66,14 +66,10 @@ public class down002 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new down002().runTest(argv, out); + new down002().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.down.down002"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/dump/dump002/dump002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/dump/dump002/dump002.java index 3e3b5b9b85872..66a26e69f7769 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/dump/dump002/dump002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/dump/dump002/dump002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,7 +47,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.dump.dump002.dump002a - * @run main/othervm + * @run driver * nsk.jdb.dump.dump002.dump002 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -70,15 +70,11 @@ public class dump002 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; compoundPromptIdent = COMPOUND_PROMPT_IDENT; - return new dump002().runTest(argv, out); + new dump002().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.dump.dump002"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/eval/eval001/eval001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/eval/eval001/eval001.java index 98848ced90bc7..fc4fb14dd2db6 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/eval/eval001/eval001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/eval/eval001/eval001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,7 +52,7 @@ * @clean nsk.jdb.eval.eval001.eval001a * @compile -g:lines,source,vars eval001a.java * - * @run main/othervm + * @run driver * nsk.jdb.eval.eval001.eval001 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -75,14 +75,10 @@ public class eval001 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new eval001().runTest(argv, out); + new eval001().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.eval.eval001"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/exclude/exclude001/exclude001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/exclude/exclude001/exclude001.java index cee8ca44d585b..c7805cc6c95de 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/exclude/exclude001/exclude001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/exclude/exclude001/exclude001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -59,7 +59,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.exclude.exclude001.exclude001a - * @run main/othervm/timeout=600 + * @run driver/timeout=600 * nsk.jdb.exclude.exclude001.exclude001 * -arch=${os.family}-${os.simpleArch} * -waittime=10 @@ -82,14 +82,10 @@ public class exclude001 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new exclude001().runTest(argv, out); + new exclude001().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.exclude.exclude001"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/fields/fields001/fields001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/fields/fields001/fields001.java index b5e2ccb58e566..c1cbba3232a84 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/fields/fields001/fields001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/fields/fields001/fields001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,7 +41,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.fields.fields001.fields001a - * @run main/othervm + * @run driver * nsk.jdb.fields.fields001.fields001 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -64,14 +64,10 @@ public class fields001 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new fields001().runTest(argv, out); + new fields001().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.fields.fields001"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/hidden_class/hc001/hc001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/hidden_class/hc001/hc001.java index 5040eef9cefb2..a7c74e28aaece 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/hidden_class/hc001/hc001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/hidden_class/hc001/hc001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,7 @@ * jdk.jdwp.agent * @build nsk.jdb.hidden_class.hc001.hc001a * - * @run main/othervm + * @run driver * nsk.jdb.hidden_class.hc001.hc001 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -60,13 +60,9 @@ public class hc001 extends JdbTest { static final int MAX_SLEEP_CNT = 3; public static void main(String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; // needed for JdbTest.runTest firstBreak = MAIN_METHOD_NAME; // needed for JdbTest.runTest - return new hc001().runTest(argv, out); + new hc001().runTest(argv); } static boolean checkPattern(String[] arr, String pattern) { diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/ignore/ignore001/ignore001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/ignore/ignore001/ignore001.java index 6eb8c91e1eb78..48d256d22fc7e 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/ignore/ignore001/ignore001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/ignore/ignore001/ignore001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,7 +40,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.ignore.ignore001.ignore001a - * @run main/othervm + * @run driver * nsk.jdb.ignore.ignore001.ignore001 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -63,14 +63,10 @@ public class ignore001 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new ignore001().runTest(argv, out); + new ignore001().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.ignore.ignore001"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/interrupt/interrupt001/interrupt001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/interrupt/interrupt001/interrupt001.java index 73f251b71e998..51bbdf6757a2d 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/interrupt/interrupt001/interrupt001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/interrupt/interrupt001/interrupt001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,7 +47,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.interrupt.interrupt001.interrupt001a - * @run main/othervm + * @run driver * nsk.jdb.interrupt.interrupt001.interrupt001 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -73,13 +73,9 @@ public class interrupt001 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; - return new interrupt001().runTest(argv, out); + new interrupt001().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.interrupt.interrupt001"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/kill/kill001/kill001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/kill/kill001/kill001.java index b770aafc510db..a96498954b69b 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/kill/kill001/kill001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/kill/kill001/kill001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -49,7 +49,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.kill.kill001.kill001a - * @run main/othervm + * @run driver * nsk.jdb.kill.kill001.kill001 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -74,13 +74,9 @@ public class kill001 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; - return new kill001().runTest(argv, out); + new kill001().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.kill.kill001"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/kill/kill002/kill002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/kill/kill002/kill002.java index 230dcdf12baaf..ed5306346dc3c 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/kill/kill002/kill002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/kill/kill002/kill002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,7 +43,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.kill.kill002.kill002a - * @run main/othervm + * @run driver * nsk.jdb.kill.kill002.kill002 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -66,13 +66,9 @@ public class kill002 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; - return new kill002().runTest(argv, out); + new kill002().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.kill.kill002"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/klass/class001/class001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/klass/class001/class001.java index 4c548348dc356..ee37e393f702d 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/klass/class001/class001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/klass/class001/class001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,7 +40,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.klass.class001.class001a - * @run main/othervm + * @run driver * nsk.jdb.klass.class001.class001 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -63,14 +63,10 @@ public class class001 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new class001().runTest(argv, out); + new class001().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.klass.class001"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/list/list002/list002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/list/list002/list002.java index 4180ea3bb453b..38282a425ecd4 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/list/list002/list002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/list/list002/list002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,7 +44,7 @@ * /test/lib * @build nsk.jdb.list.list002.list002a * @run driver jdk.test.lib.FileInstaller list002a.java src/nsk/jdb/list/list002/list002a.java - * @run main/othervm + * @run driver * nsk.jdb.list.list002.list002 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -68,14 +68,10 @@ public class list002 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new list002().runTest(argv, out); + new list002().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.list.list002"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/list/list003/list003.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/list/list003/list003.java index d06bf38bd8527..e7d773486eedb 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/list/list003/list003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/list/list003/list003.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,7 +37,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.list.list003.list003a - * @run main/othervm + * @run driver * nsk.jdb.list.list003.list003 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -47,6 +47,7 @@ * -jdb.option="-J-Duser.language=en -J-Duser.country=US" * -java.options="${test.vm.opts} ${test.java.opts}" * -workdir=. + * -jdb.option="-sourcepath ${test.src}/../../../.." * -debugee.vmkeys="${test.vm.opts} ${test.java.opts}" */ @@ -98,13 +99,9 @@ protected List parseListOutput(String[] lines) { } public static void main(String[] args) { - System.exit(run(args, System.out) + JCK_STATUS_BASE); - } - - public static int run(String[] args, PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; - return new list003().runTest(args, out); + new list003().runTest(args); } @Override diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/locals/locals002/locals002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/locals/locals002/locals002.java index 793cdc0460876..09a97ff83a528 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/locals/locals002/locals002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/locals/locals002/locals002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,7 +52,7 @@ * @clean nsk.jdb.locals.locals002.locals002a * @compile -g:lines,source,vars locals002a.java * - * @run main/othervm + * @run driver * nsk.jdb.locals.locals002.locals002 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -75,15 +75,11 @@ public class locals002 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; compoundPromptIdent = COMPOUND_PROMPT_IDENT; - return new locals002().runTest(argv, out); + new locals002().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.locals.locals002"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/methods/methods002/methods002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/methods/methods002/methods002.java index 2bacbab101bd4..ef480d52c037c 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/methods/methods002/methods002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/methods/methods002/methods002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,7 +50,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.methods.methods002.methods002a - * @run main/othervm + * @run driver * nsk.jdb.methods.methods002.methods002 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -73,14 +73,10 @@ public class methods002 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new methods002().runTest(argv, out); + new methods002().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.methods.methods002"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/monitor/monitor001/monitor001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/monitor/monitor001/monitor001.java index 1fd1f8c328b87..94cac5ca787a9 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/monitor/monitor001/monitor001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/monitor/monitor001/monitor001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,7 +46,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.monitor.monitor001.monitor001a - * @run main/othervm + * @run driver * nsk.jdb.monitor.monitor001.monitor001 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -69,14 +69,10 @@ public class monitor001 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new monitor001().runTest(argv, out); + new monitor001().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.monitor.monitor001"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/monitor/monitor002/monitor002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/monitor/monitor002/monitor002.java index 53c856128ce7b..790eb7469168d 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/monitor/monitor002/monitor002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/monitor/monitor002/monitor002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,7 +42,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.monitor.monitor002.monitor002a - * @run main/othervm + * @run driver * nsk.jdb.monitor.monitor002.monitor002 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -65,14 +65,10 @@ public class monitor002 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new monitor002().runTest(argv, out); + new monitor002().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.monitor.monitor002"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/next/next001/next001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/next/next001/next001.java index 206199f0bb325..3d0c810b5c4a4 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/next/next001/next001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/next/next001/next001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,7 +46,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.next.next001.next001a - * @run main/othervm + * @run driver * nsk.jdb.next.next001.next001 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -69,14 +69,10 @@ public class next001 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new next001().runTest(argv, out); + new next001().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.next.next001"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/connect/connect001/connect001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/connect/connect001/connect001.java index a78f3a96db421..85cdbb279974e 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/connect/connect001/connect001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/connect/connect001/connect001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,7 +46,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.options.connect.connect001.connect001a - * @run main/othervm + * @run driver * nsk.jdb.options.connect.connect001.connect001 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -71,14 +71,10 @@ public class connect001 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new connect001().runTest(argv, out); + new connect001().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.options.connect.connect001"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/connect/connect002/connect002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/connect/connect002/connect002.java index 78bcf2fb9737e..a3219de0cc4e3 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/connect/connect002/connect002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/connect/connect002/connect002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,7 +46,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.options.connect.connect002.connect002a - * @run main/othervm + * @run driver * nsk.jdb.options.connect.connect002.connect002 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -71,14 +71,10 @@ public class connect002 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new connect002().runTest(argv, out); + new connect002().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.options.connect.connect002"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/connect/connect003/connect003.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/connect/connect003/connect003.java index 701f611d2ff39..465e3c9deb241 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/connect/connect003/connect003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/connect/connect003/connect003.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,7 +46,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.options.connect.connect003.connect003a - * @run main/othervm + * @run driver * nsk.jdb.options.connect.connect003.connect003 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -71,14 +71,10 @@ public class connect003 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new connect003().runTest(argv, out); + new connect003().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.options.connect.connect003"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/connect/connect004/connect004.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/connect/connect004/connect004.java index adaa58627dd47..075e9c30268ef 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/connect/connect004/connect004.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/connect/connect004/connect004.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,7 +46,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.options.connect.connect004.connect004a - * @run main/othervm + * @run driver * nsk.jdb.options.connect.connect004.connect004 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -71,14 +71,10 @@ public class connect004 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new connect004().runTest(argv, out); + new connect004().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.options.connect.connect004"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/connect/connect005/connect005.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/connect/connect005/connect005.java index 8a67039246605..7bd44a5927cc7 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/connect/connect005/connect005.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/connect/connect005/connect005.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,7 +46,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.options.connect.connect005.connect005a - * @run main/othervm + * @run driver * nsk.jdb.options.connect.connect005.connect005 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -70,15 +70,10 @@ public class connect005 extends JdbTest { - public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { - debuggeeClass = DEBUGGEE_CLASS; + public static void main (String argv[]) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new connect005().runTest(argv, out); + new connect005().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.options.connect.connect005"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/listconnectors/listconnectors001/listconnectors001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/listconnectors/listconnectors001/listconnectors001.java index d814df91cc693..b4961be11eeee 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/listconnectors/listconnectors001/listconnectors001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/options/listconnectors/listconnectors001/listconnectors001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -51,7 +51,7 @@ * * @library /vmTestbase * /test/lib - * @run main/othervm + * @run driver * nsk.jdb.options.listconnectors.listconnectors001.listconnectors001 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -75,14 +75,10 @@ public class listconnectors001 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new listconnectors001().runTest(argv, out); + new listconnectors001().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.options.connect"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/pop/pop001/pop001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/pop/pop001/pop001.java index e449a5771f27c..c508538fa1e66 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/pop/pop001/pop001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/pop/pop001/pop001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,7 +47,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.pop.pop001.pop001a - * @run main/othervm + * @run driver * nsk.jdb.pop.pop001.pop001 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -70,14 +70,10 @@ public class pop001 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new pop001().runTest(argv, out); + new pop001().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.pop.pop001"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/pop_exception/pop_exception001/pop_exception001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/pop_exception/pop_exception001/pop_exception001.java index f70a5ffb96023..49921cd26cc0e 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/pop_exception/pop_exception001/pop_exception001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/pop_exception/pop_exception001/pop_exception001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.pop_exception.pop_exception001.pop_exception001a - * @run main/othervm + * @run driver * nsk.jdb.pop_exception.pop_exception001.pop_exception001 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -63,14 +63,10 @@ public class pop_exception001 extends JdbTest { static final String LAST_BREAK = DEBUGGEE_CLASS + ".lastBreak"; public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new pop_exception001().runTest(argv, out); + new pop_exception001().runTest(argv); } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/print/print002/print002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/print/print002/print002.java index e339a0a321b97..1993c1f4d95fc 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/print/print002/print002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/print/print002/print002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,7 +52,7 @@ * @clean nsk.jdb.print.print002.print002a * @compile -g:lines,source,vars print002a.java * - * @run main/othervm + * @run driver * nsk.jdb.print.print002.print002 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -75,14 +75,10 @@ public class print002 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new print002().runTest(argv, out); + new print002().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.print.print002"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/read/read001/read001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/read/read001/read001.java index b5ca64334d775..60c80139a651f 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/read/read001/read001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/read/read001/read001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,7 +52,7 @@ * @clean nsk.jdb.read.read001.read001a * @compile -g:lines,source,vars read001a.java * - * @run main/othervm + * @run driver * nsk.jdb.read.read001.read001 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -76,14 +76,10 @@ public class read001 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new read001().runTest(argv, out); + new read001().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.read.read001"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/redefine/redefine001/redefine001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/redefine/redefine001/redefine001.java index 80ff33889a410..d3988ac443ca8 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/redefine/redefine001/redefine001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/redefine/redefine001/redefine001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -56,7 +56,7 @@ * -cp ${test.class.path} * ${test.src}/newclass_g/RedefinedClass.java * - * @run main/othervm + * @run driver * nsk.jdb.redefine.redefine001.redefine001 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -80,14 +80,10 @@ public class redefine001 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new redefine001().runTest(argv, out); + new redefine001().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.redefine.redefine001"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/reenter/reenter001/reenter001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/reenter/reenter001/reenter001.java index ebc063942c608..4013d85ab7527 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/reenter/reenter001/reenter001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/reenter/reenter001/reenter001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,7 +46,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.reenter.reenter001.reenter001a - * @run main/othervm + * @run driver * nsk.jdb.reenter.reenter001.reenter001 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -69,14 +69,10 @@ public class reenter001 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new reenter001().runTest(argv, out); + new reenter001().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.reenter.reenter001"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/regression/b4689395/b4689395.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/regression/b4689395/b4689395.java index 82d8235fee724..2cb3cc0eccfc4 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/regression/b4689395/b4689395.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/regression/b4689395/b4689395.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -101,7 +101,7 @@ * -cp ${test.class.path} * ${test.src}/newclass/b4689395a.java * - * @run main/othervm + * @run driver * nsk.jdb.regression.b4689395.b4689395 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -131,13 +131,9 @@ public class b4689395 extends JdbTest { private String classFile; public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; - return new b4689395().runTest(argv, out); + new b4689395().runTest(argv); } public b4689395() { diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/repeat/repeat001/repeat001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/repeat/repeat001/repeat001.java index e0489db28291e..67ce5ea4e7498 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/repeat/repeat001/repeat001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/repeat/repeat001/repeat001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,7 +38,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.repeat.repeat001.repeat001a - * @run main/othervm + * @run driver * nsk.jdb.repeat.repeat001.repeat001 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -68,13 +68,9 @@ public class repeat001 extends JdbTest { static final String FIRST_BREAK = DEBUGGEE_CLASS + ".main"; public static void main(String[] args) { - System.exit(run(args, System.out) + JCK_STATUS_BASE); - } - - public static int run(String[] args, PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; - return new repeat001().runTest(args, out); + new repeat001().runTest(args); } protected static boolean isPrompt(String line) { diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/resume/resume002/resume002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/resume/resume002/resume002.java index ab4df2625fe21..9607413036c88 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/resume/resume002/resume002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/resume/resume002/resume002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,7 +50,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.resume.resume002.resume002a - * @run main/othervm + * @run driver * nsk.jdb.resume.resume002.resume002 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -73,14 +73,10 @@ public class resume002 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new resume002().runTest(argv, out); + new resume002().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.resume.resume002"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/run/run002/run002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/run/run002/run002.java index da837ab0f8bce..9b23ac4de25a9 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/run/run002/run002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/run/run002/run002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,7 +44,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.run.run002.run002a - * @run main/othervm + * @run driver * nsk.jdb.run.run002.run002 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -67,14 +67,10 @@ public class run002 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new run002().runTest(argv, out); + new run002().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.run.run002"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/set/set001/set001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/set/set001/set001.java index d00362b228cbf..7b97f47b5294a 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/set/set001/set001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/set/set001/set001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -53,7 +53,7 @@ * @clean nsk.jdb.set.set001.set001a * @compile -g:lines,source,vars set001a.java * - * @run main/othervm + * @run driver * nsk.jdb.set.set001.set001 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -76,14 +76,10 @@ public class set001 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new set001().runTest(argv, out); + new set001().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.set.set001"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/set/set002/set002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/set/set002/set002.java index dca4e554afaf9..91d8482104045 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/set/set002/set002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/set/set002/set002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -53,7 +53,7 @@ * @clean nsk.jdb.set.set002.set002a * @compile -g:lines,source,vars set002a.java * - * @run main/othervm + * @run driver * nsk.jdb.set.set002.set002 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -76,15 +76,11 @@ public class set002 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new set002().runTest(argv, out); + new set002().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.set.set002"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/step/step002/step002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/step/step002/step002.java index 4df163ca1a92c..c9cc342783e3f 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/step/step002/step002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/step/step002/step002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -56,7 +56,7 @@ * @clean nsk.jdb.step.step002.step002a * @compile -g:lines,source,vars step002a.java * - * @run main/othervm + * @run driver * nsk.jdb.step.step002.step002 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -79,14 +79,10 @@ public class step002 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new step002().runTest(argv, out); + new step002().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.step.step002"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/step_up/step_up001/step_up001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/step_up/step_up001/step_up001.java index 590a476dbbe60..d4c60f937fa2e 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/step_up/step_up001/step_up001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/step_up/step_up001/step_up001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,7 +45,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.step_up.step_up001.step_up001a - * @run main/othervm + * @run driver * nsk.jdb.step_up.step_up001.step_up001 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -68,14 +68,10 @@ public class step_up001 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new step_up001().runTest(argv, out); + new step_up001().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.step_up.step_up001"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/stop_at/stop_at002/stop_at002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/stop_at/stop_at002/stop_at002.java index 9dae8c17cfc36..30cb6ed2c68af 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/stop_at/stop_at002/stop_at002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/stop_at/stop_at002/stop_at002.java @@ -37,7 +37,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.stop_at.stop_at002.stop_at002a - * @run main/othervm + * @run driver * nsk.jdb.stop_at.stop_at002.stop_at002 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -67,14 +67,10 @@ public class stop_at002 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new stop_at002().runTest(argv, out); + new stop_at002().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.stop_at.stop_at002"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/stop_at/stop_at003/stop_at003.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/stop_at/stop_at003/stop_at003.java index ecd66ca7c9573..06eacea58b913 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/stop_at/stop_at003/stop_at003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/stop_at/stop_at003/stop_at003.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -49,7 +49,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.stop_at.stop_at003.stop_at003a - * @run main/othervm + * @run driver * nsk.jdb.stop_at.stop_at003.stop_at003 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -79,14 +79,10 @@ public class stop_at003 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new stop_at003().runTest(argv, out); + new stop_at003().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.stop_at.stop_at003"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/stop_in/stop_in002/stop_in002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/stop_in/stop_in002/stop_in002.java index e4c2058fd97a3..710f05c078c46 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/stop_in/stop_in002/stop_in002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/stop_in/stop_in002/stop_in002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,7 +50,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.stop_in.stop_in002.stop_in002a - * @run main/othervm + * @run driver * nsk.jdb.stop_in.stop_in002.stop_in002 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -80,14 +80,10 @@ public class stop_in002 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new stop_in002().runTest(argv, out); + new stop_in002().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.stop_in.stop_in002"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/suspend/suspend001/suspend001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/suspend/suspend001/suspend001.java index 18e5c27d31c6c..20c9778f25109 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/suspend/suspend001/suspend001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/suspend/suspend001/suspend001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,7 +46,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.suspend.suspend001.suspend001a - * @run main/othervm + * @run driver * nsk.jdb.suspend.suspend001.suspend001 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -69,14 +69,10 @@ public class suspend001 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new suspend001().runTest(argv, out); + new suspend001().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.suspend.suspend001"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/thread/thread002/thread002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/thread/thread002/thread002.java index 487ac49e66ec9..c8b55b0beee56 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/thread/thread002/thread002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/thread/thread002/thread002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,7 +43,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.thread.thread002.thread002a - * @run main/othervm + * @run driver * nsk.jdb.thread.thread002.thread002 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -66,14 +66,10 @@ public class thread002 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new thread002().runTest(argv, out); + new thread002().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.thread.thread002"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/threadgroup/threadgroup002/threadgroup002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/threadgroup/threadgroup002/threadgroup002.java index 72bbf3584741d..8ff58b11bec19 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/threadgroup/threadgroup002/threadgroup002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/threadgroup/threadgroup002/threadgroup002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,7 +45,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.threadgroup.threadgroup002.threadgroup002a - * @run main/othervm + * @run driver * nsk.jdb.threadgroup.threadgroup002.threadgroup002 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -69,14 +69,10 @@ public class threadgroup002 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new threadgroup002().runTest(argv, out); + new threadgroup002().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.threadgroup.threadgroup002"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/threadgroups/threadgroups002/threadgroups002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/threadgroups/threadgroups002/threadgroups002.java index 67ee29006b474..56f4dceda9e2d 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/threadgroups/threadgroups002/threadgroups002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/threadgroups/threadgroups002/threadgroups002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,7 +41,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.threadgroups.threadgroups002.threadgroups002a - * @run main/othervm + * @run driver * nsk.jdb.threadgroups.threadgroups002.threadgroups002 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -64,14 +64,10 @@ public class threadgroups002 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new threadgroups002().runTest(argv, out); + new threadgroups002().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.threadgroups.threadgroups002"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/threads/threads002/threads002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/threads/threads002/threads002.java index e9afd794d812a..fdc52ad7a2ab5 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/threads/threads002/threads002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/threads/threads002/threads002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,7 +40,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.threads.threads002.threads002a - * @run main/othervm + * @run driver * nsk.jdb.threads.threads002.threads002 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -65,14 +65,10 @@ public class threads002 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new threads002().runTest(argv, out); + new threads002().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.threads.threads002"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/threads/threads003/threads003.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/threads/threads003/threads003.java index 4332eb69cf94b..f290cc71bb598 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/threads/threads003/threads003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/threads/threads003/threads003.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,7 +41,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.threads.threads003.threads003a - * @run main/othervm + * @run driver * nsk.jdb.threads.threads003.threads003 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -65,14 +65,10 @@ public class threads003 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new threads003().runTest(argv, out); + new threads003().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.threads.threads003"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/trace/trace001/trace001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/trace/trace001/trace001.java index 0e289f93aee20..492d5b438c893 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/trace/trace001/trace001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/trace/trace001/trace001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,7 +47,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.trace.trace001.trace001a - * @run main/othervm + * @run driver * nsk.jdb.trace.trace001.trace001 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -71,14 +71,10 @@ public class trace001 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new trace001().runTest(argv, out); + new trace001().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.trace.trace001"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/uncaught_exception/uncaught_exception002/uncaught_exception002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/uncaught_exception/uncaught_exception002/uncaught_exception002.java index dd1d0748c0ff2..32f7750cdb5ec 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/uncaught_exception/uncaught_exception002/uncaught_exception002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/uncaught_exception/uncaught_exception002/uncaught_exception002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,7 +52,7 @@ * @clean nsk.jdb.uncaught_exception.uncaught_exception002.uncaught_exception002a * @compile -g:lines,source,vars uncaught_exception002a.java * - * @run main/othervm + * @run driver * nsk.jdb.uncaught_exception.uncaught_exception002.uncaught_exception002 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -75,14 +75,10 @@ public class uncaught_exception002 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new uncaught_exception002(true).runTest(argv, out); + new uncaught_exception002(true).runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.uncaught_exception.uncaught_exception002"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/unmonitor/unmonitor001/unmonitor001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/unmonitor/unmonitor001/unmonitor001.java index 7d98824be73c4..195b2427ae58e 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/unmonitor/unmonitor001/unmonitor001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/unmonitor/unmonitor001/unmonitor001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -56,7 +56,7 @@ * @clean nsk.jdb.unmonitor.unmonitor001.unmonitor001a * @compile -g:lines,source,vars unmonitor001a.java * - * @run main/othervm + * @run driver * nsk.jdb.unmonitor.unmonitor001.unmonitor001 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -79,14 +79,10 @@ public class unmonitor001 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new unmonitor001().runTest(argv, out); + new unmonitor001().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.unmonitor.unmonitor001"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/untrace/untrace001/untrace001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/untrace/untrace001/untrace001.java index daad477dbb439..0891e5b931cc4 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/untrace/untrace001/untrace001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/untrace/untrace001/untrace001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -54,7 +54,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.untrace.untrace001.untrace001a - * @run main/othervm + * @run driver * nsk.jdb.untrace.untrace001.untrace001 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -77,14 +77,10 @@ public class untrace001 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new untrace001().runTest(argv, out); + new untrace001().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.untrace.untrace001"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/unwatch/unwatch001/unwatch001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/unwatch/unwatch001/unwatch001.java index b8c71645edb47..aff9890e58d8b 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/unwatch/unwatch001/unwatch001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/unwatch/unwatch001/unwatch001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,7 +50,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.unwatch.unwatch001.unwatch001a - * @run main/othervm + * @run driver * nsk.jdb.unwatch.unwatch001.unwatch001 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -73,14 +73,10 @@ public class unwatch001 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new unwatch001().runTest(argv, out); + new unwatch001().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.unwatch.unwatch001"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/unwatch/unwatch002/unwatch002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/unwatch/unwatch002/unwatch002.java index e32cc0b8e5dc6..1078e2b3da358 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/unwatch/unwatch002/unwatch002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/unwatch/unwatch002/unwatch002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -51,7 +51,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.unwatch.unwatch002.unwatch002a - * @run main/othervm + * @run driver * nsk.jdb.unwatch.unwatch002.unwatch002 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -74,14 +74,10 @@ public class unwatch002 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new unwatch002().runTest(argv, out); + new unwatch002().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.unwatch.unwatch002"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/up/up002/up002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/up/up002/up002.java index 5b2cb393df4e8..78c01074abb1a 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/up/up002/up002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/up/up002/up002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,7 +43,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.up.up002.up002a - * @run main/othervm + * @run driver * nsk.jdb.up.up002.up002 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -66,14 +66,10 @@ public class up002 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new up002().runTest(argv, out); + new up002().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.up.up002"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/use/use001/use001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/use/use001/use001.java index 1454b39b2bf8e..81ad1dd48accb 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/use/use001/use001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/use/use001/use001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,7 +43,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.use.use001.use001a - * @run main/othervm + * @run driver * nsk.jdb.use.use001.use001 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -67,14 +67,10 @@ public class use001 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new use001().runTest(argv, out); + new use001().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.use.use001"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/watch/watch001/watch001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/watch/watch001/watch001.java index 8d434fcfc7444..dfc154d1b4186 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/watch/watch001/watch001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/watch/watch001/watch001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,7 +48,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.watch.watch001.watch001a - * @run main/othervm + * @run driver * nsk.jdb.watch.watch001.watch001 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -71,15 +71,11 @@ public class watch001 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; compoundPromptIdent = COMPOUND_PROMPT_IDENT; - return new watch001().runTest(argv, out); + new watch001().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.watch.watch001"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/watch/watch002/watch002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/watch/watch002/watch002.java index cb0535117d9fd..84c80a59ebf73 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/watch/watch002/watch002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/watch/watch002/watch002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,7 +48,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.watch.watch002.watch002a - * @run main/othervm + * @run driver * nsk.jdb.watch.watch002.watch002 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -71,15 +71,11 @@ public class watch002 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; compoundPromptIdent = COMPOUND_PROMPT_IDENT; - return new watch002().runTest(argv, out); + new watch002().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.watch.watch002"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/where/where004/where004.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/where/where004/where004.java index e4cbf50e62f68..9002c35e16e5a 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/where/where004/where004.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/where/where004/where004.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,7 +41,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.where.where004.where004a - * @run main/othervm + * @run driver * nsk.jdb.where.where004.where004 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -64,14 +64,10 @@ public class where004 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new where004().runTest(argv, out); + new where004().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.where.where004"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/where/where005/where005.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/where/where005/where005.java index b949916aae74e..2fded98727291 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/where/where005/where005.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/where/where005/where005.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,7 +42,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.where.where005.where005a - * @run main/othervm + * @run driver * nsk.jdb.where.where005.where005 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -65,14 +65,10 @@ public class where005 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new where005(true).runTest(argv, out); + new where005(true).runTest(argv); } public where005 (boolean debuggeeShouldFail) { diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/where/where006/where006.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/where/where006/where006.java index bf7622c48b345..11dc185238f07 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/where/where006/where006.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/where/where006/where006.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,7 +42,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.where.where006.where006a - * @run main/othervm + * @run driver * nsk.jdb.where.where006.where006 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -65,14 +65,10 @@ public class where006 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new where006().runTest(argv, out); + new where006().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.where.where006"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/wherei/wherei001/wherei001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/wherei/wherei001/wherei001.java index 431206b55510e..e4d75620f0b49 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/wherei/wherei001/wherei001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/wherei/wherei001/wherei001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,7 +37,7 @@ * @library /vmTestbase * /test/lib * @build nsk.jdb.wherei.wherei001.wherei001a - * @run main/othervm + * @run driver * nsk.jdb.wherei.wherei001.wherei001 * -arch=${os.family}-${os.simpleArch} * -waittime=5 @@ -60,14 +60,10 @@ public class wherei001 extends JdbTest { public static void main (String argv[]) { - System.exit(run(argv, System.out) + JCK_STATUS_BASE); - } - - public static int run(String argv[], PrintStream out) { debuggeeClass = DEBUGGEE_CLASS; firstBreak = FIRST_BREAK; lastBreak = LAST_BREAK; - return new wherei001().runTest(argv, out); + new wherei001().runTest(argv); } static final String PACKAGE_NAME = "nsk.jdb.wherei.wherei001"; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jdb/JdbTest.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jdb/JdbTest.java index 349216f4329c4..aa7ad833b53dc 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/share/jdb/JdbTest.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdb/JdbTest.java @@ -125,14 +125,15 @@ protected void initJdb() { protected void afterJdbExit() { } - protected int runTest(String argv[], PrintStream out) { + protected void runTest(String argv[]) { + PrintStream out = System.out; try { argumentHandler = new JdbArgumentHandler(argv); log = new Log(out, argumentHandler); if (shouldPass()) { log.println("TEST PASSED"); - return PASSED; + return; } try { @@ -226,16 +227,14 @@ protected int runTest(String argv[], PrintStream out) { if (!success) { log.complain("TEST FAILED"); - return FAILED; + throw new RuntimeException("TEST FAILED"); } } catch (Throwable t) { out.println("Caught unexpected exception while starting the test: " + t); t.printStackTrace(out); - out.println("TEST FAILED"); - return FAILED; + throw new RuntimeException("TEST FAILED", t); } out.println("TEST PASSED"); - return PASSED; } } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jdb/Launcher.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jdb/Launcher.java index 35df95b2d6f8a..d443741349560 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/share/jdb/Launcher.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdb/Launcher.java @@ -180,10 +180,12 @@ private String[] makeJdbCmdLine (String classToExecute) { } else /* LaunchingConnector or DefaultConnector */ { connect.append("vmexec=" + argumentHandler.getLaunchExecName().trim()); + connect.append(",options="); + connect.append(" \"-cp\""); + connect.append(" \"" + System.getProperty("test.class.path") + "\""); + String debuggeeOpts = argumentHandler.getDebuggeeOptions(); if (debuggeeOpts.trim().length() > 0) { - //connect.append(",options=" + debuggeeOpts.trim()); - connect.append(",options="); for (String arg : debuggeeOpts.split("\\s+")) { connect.append(" \""); connect.append(arg); From 5079c38ddf345b21d8cb1c959bc36c4341e11da6 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Mon, 12 Aug 2024 22:12:01 +0000 Subject: [PATCH 274/353] 8338160: Fix -Wzero-as-null-pointer-constant warnings in management.cpp Reviewed-by: dholmes --- src/hotspot/share/services/management.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/hotspot/share/services/management.cpp b/src/hotspot/share/services/management.cpp index 2c9f36c098d07..ac7e1daf39706 100644 --- a/src/hotspot/share/services/management.cpp +++ b/src/hotspot/share/services/management.cpp @@ -1820,7 +1820,7 @@ JVM_END // of a given length and return the objArrayOop static objArrayOop get_memory_usage_objArray(jobjectArray array, int length, TRAPS) { if (array == nullptr) { - THROW_(vmSymbols::java_lang_NullPointerException(), 0); + THROW_NULL(vmSymbols::java_lang_NullPointerException()); } objArrayOop oa = objArrayOop(JNIHandles::resolve_non_null(array)); @@ -1828,16 +1828,16 @@ static objArrayOop get_memory_usage_objArray(jobjectArray array, int length, TRA // array must be of the given length if (length != array_h->length()) { - THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), - "The length of the given MemoryUsage array does not match the number of memory pools.", 0); + THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), + "The length of the given MemoryUsage array does not match the number of memory pools."); } // check if the element of array is of type MemoryUsage class Klass* usage_klass = Management::java_lang_management_MemoryUsage_klass(CHECK_NULL); Klass* element_klass = ObjArrayKlass::cast(array_h->klass())->element_klass(); if (element_klass != usage_klass) { - THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), - "The element type is not MemoryUsage class", 0); + THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), + "The element type is not MemoryUsage class"); } return array_h(); From e70c9bccaae375be1ee6812dabc9fbaff01a6ab0 Mon Sep 17 00:00:00 2001 From: Zhengyu Gu Date: Mon, 12 Aug 2024 23:00:04 +0000 Subject: [PATCH 275/353] 8338248: PartialArrayStateAllocator::Impl leaks Arena array Reviewed-by: kbarrett, shade --- src/hotspot/share/gc/shared/partialArrayState.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hotspot/share/gc/shared/partialArrayState.cpp b/src/hotspot/share/gc/shared/partialArrayState.cpp index 583c5dede4026..fd23a32022208 100644 --- a/src/hotspot/share/gc/shared/partialArrayState.cpp +++ b/src/hotspot/share/gc/shared/partialArrayState.cpp @@ -100,6 +100,7 @@ PartialArrayStateAllocator::Impl::~Impl() { for (uint i = 0; i < _num_workers; ++i) { _arenas[i].~Arena(); } + FREE_C_HEAP_ARRAY(Arena*, _arenas); } PartialArrayState* PartialArrayStateAllocator::Impl::allocate(uint worker_id, From d77e6fe45c7b834db457a772ce0bea514d2e44f3 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Tue, 13 Aug 2024 05:46:38 +0000 Subject: [PATCH 276/353] 8338154: Fix -Wzero-as-null-pointer-constant warnings in gtest framework Reviewed-by: ihse, dholmes, jwaters --- make/hotspot/lib/CompileGtest.gmk | 3 ++- test/hotspot/gtest/gtestMain.cpp | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/make/hotspot/lib/CompileGtest.gmk b/make/hotspot/lib/CompileGtest.gmk index 696adb0c95f10..424743ba27976 100644 --- a/make/hotspot/lib/CompileGtest.gmk +++ b/make/hotspot/lib/CompileGtest.gmk @@ -57,7 +57,8 @@ $(eval $(call SetupJdkLibrary, BUILD_GTEST_LIBGTEST, \ $(GTEST_FRAMEWORK_SRC)/googletest/src \ $(GTEST_FRAMEWORK_SRC)/googlemock/src, \ INCLUDE_FILES := gtest-all.cc gmock-all.cc, \ - DISABLED_WARNINGS_gcc := undef unused-result format-nonliteral maybe-uninitialized, \ + DISABLED_WARNINGS_gcc := undef unused-result format-nonliteral \ + maybe-uninitialized zero-as-null-pointer-constant, \ DISABLED_WARNINGS_clang := undef unused-result format-nonliteral, \ DEFAULT_CFLAGS := false, \ CFLAGS := $(JVM_CFLAGS) \ diff --git a/test/hotspot/gtest/gtestMain.cpp b/test/hotspot/gtest/gtestMain.cpp index bc8ca29f72d45..0bd251e8094b3 100644 --- a/test/hotspot/gtest/gtestMain.cpp +++ b/test/hotspot/gtest/gtestMain.cpp @@ -336,7 +336,7 @@ static void run_in_new_thread(const args_t* args) { extern "C" void* thread_wrapper(void* p) { const args_t* const p_args = (const args_t*) p; runUnitTestsInner(p_args->argc, p_args->argv); - return 0; + return nullptr; } static void run_in_new_thread(const args_t* args) { From 73ddb7deab26c526337ec6e7cd5f528f698a552c Mon Sep 17 00:00:00 2001 From: Emanuel Peter Date: Tue, 13 Aug 2024 05:52:44 +0000 Subject: [PATCH 277/353] 8335628: C2 SuperWord: cleanup: remove SuperWord::longer_type_for_conversion Reviewed-by: chagedorn, kvn --- src/hotspot/share/opto/superword.cpp | 25 +------------------------ src/hotspot/share/opto/superword.hpp | 3 --- 2 files changed, 1 insertion(+), 27 deletions(-) diff --git a/src/hotspot/share/opto/superword.cpp b/src/hotspot/share/opto/superword.cpp index 0e1328a448577..2a43d2ec0af4a 100644 --- a/src/hotspot/share/opto/superword.cpp +++ b/src/hotspot/share/opto/superword.cpp @@ -691,9 +691,7 @@ bool SuperWord::can_pack_into_pair(Node* s1, Node* s2) { BasicType bt2 = velt_basic_type(s2); if(!is_java_primitive(bt1) || !is_java_primitive(bt2)) return false; - BasicType longer_bt = longer_type_for_conversion(s1); - if (Matcher::max_vector_size_auto_vectorization(bt1) < 2 || - (longer_bt != T_ILLEGAL && Matcher::max_vector_size_auto_vectorization(longer_bt) < 2)) { + if (Matcher::max_vector_size_auto_vectorization(bt1) < 2) { return false; // No vectors for this type } @@ -2442,27 +2440,6 @@ VStatus VLoopBody::construct() { return VStatus::make_success(); } -BasicType SuperWord::longer_type_for_conversion(Node* n) const { - if (!(VectorNode::is_convert_opcode(n->Opcode()) || - VectorNode::is_scalar_op_that_returns_int_but_vector_op_returns_long(n->Opcode())) || - !in_bb(n->in(1))) { - return T_ILLEGAL; - } - assert(in_bb(n), "must be in the bb"); - BasicType src_t = velt_basic_type(n->in(1)); - BasicType dst_t = velt_basic_type(n); - // Do not use superword for non-primitives. - // Superword does not support casting involving unsigned types. - if (!is_java_primitive(src_t) || is_unsigned_subword_type(src_t) || - !is_java_primitive(dst_t) || is_unsigned_subword_type(dst_t)) { - return T_ILLEGAL; - } - int src_size = type2aelembytes(src_t); - int dst_size = type2aelembytes(dst_t); - return src_size == dst_size ? T_ILLEGAL - : (src_size > dst_size ? src_t : dst_t); -} - void VLoopTypes::compute_vector_element_type() { #ifndef PRODUCT if (_vloop.is_trace_vector_element_type()) { diff --git a/src/hotspot/share/opto/superword.hpp b/src/hotspot/share/opto/superword.hpp index 65f870825251f..8b24e0cf3a11a 100644 --- a/src/hotspot/share/opto/superword.hpp +++ b/src/hotspot/share/opto/superword.hpp @@ -623,9 +623,6 @@ class SuperWord : public ResourceObj { // Is use->in(u_idx) a vector use? bool is_vector_use(Node* use, int u_idx) const; - // Return the longer type for vectorizable type-conversion node or illegal type for other nodes. - BasicType longer_type_for_conversion(Node* n) const; - bool is_velt_basic_type_compatible_use_def(Node* use, Node* def) const; bool schedule_and_apply() const; From c27a8c8c8b867e6812b905f6154762802a498dbd Mon Sep 17 00:00:00 2001 From: Emanuel Peter Date: Tue, 13 Aug 2024 05:52:58 +0000 Subject: [PATCH 278/353] 8338124: C2 SuperWord: MulAddS2I input permutation still partially broken after JDK-8333840 Reviewed-by: chagedorn, thartmann, kvn --- src/hotspot/share/opto/superword.cpp | 2 +- .../loopopts/superword/TestMulAddS2I.java | 18 +++++++++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/opto/superword.cpp b/src/hotspot/share/opto/superword.cpp index 2a43d2ec0af4a..bb5fed78b0274 100644 --- a/src/hotspot/share/opto/superword.cpp +++ b/src/hotspot/share/opto/superword.cpp @@ -2270,7 +2270,7 @@ Node_List* PackSet::strided_pack_input_at_index_or_null(const Node_List* pack, c return nullptr; // size mismatch } - for (uint i = 1; i < pack->size(); i++) { + for (uint i = 0; i < pack->size(); i++) { if (pack->at(i)->in(index) != pack_in->at(i * stride + offset)) { return nullptr; // use-def mismatch } diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestMulAddS2I.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestMulAddS2I.java index e0f073c7f8f7d..fb99fc5983a16 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/TestMulAddS2I.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestMulAddS2I.java @@ -53,6 +53,7 @@ public class TestMulAddS2I { static final int[] GOLDEN_J; static final int[] GOLDEN_K; static final int[] GOLDEN_L; + static final int[] GOLDEN_M; static { for (int i = 0; i < RANGE; i++) { @@ -71,6 +72,7 @@ public class TestMulAddS2I { GOLDEN_J = testj(new int[ITER]); GOLDEN_K = testk(new int[ITER]); GOLDEN_L = testl(new int[ITER]); + GOLDEN_M = testm(new int[ITER]); } @@ -80,7 +82,7 @@ public static void main(String[] args) { } @Run(test = {"testa", "testb", "testc", "testd", "teste", "testf", "testg", "testh", - "testi", "testj", "testk", "testl"}) + "testi", "testj", "testk", "testl", "testm"}) @Warmup(0) public static void run() { compare(testa(), GOLDEN_A, "testa"); @@ -95,6 +97,7 @@ public static void run() { compare(testj(new int[ITER]), GOLDEN_J, "testj"); compare(testk(new int[ITER]), GOLDEN_K, "testk"); compare(testl(new int[ITER]), GOLDEN_L, "testl"); + compare(testm(new int[ITER]), GOLDEN_M, "testm"); } public static void compare(int[] out, int[] golden, String name) { @@ -299,4 +302,17 @@ public static int[] testl(int[] out) { return out; } + @Test + @IR(counts = {IRNode.MUL_ADD_S2I, "> 0"}, + applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"}) + @IR(counts = {IRNode.MUL_ADD_VS2VI, "= 0"}) + public static int[] testm(int[] out) { + for (int i = 0; i < ITER-4; i+=4) { + // Unrolled, with some swaps that prevent vectorization. + out[i+0] += ((sArr1[2*i+0] * sArr2[2*i+1]) + (sArr1[2*i+1] * sArr2[2*i+0])); // bad + out[i+1] += ((sArr1[2*i+2] * sArr2[2*i+2]) + (sArr1[2*i+3] * sArr2[2*i+3])); // ok + // 2-element gap + } + return out; + } } From 73f7a5f15dbba54a98f3916ff1190520ac07874d Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Tue, 13 Aug 2024 07:27:49 +0000 Subject: [PATCH 279/353] 8338155: Fix -Wzero-as-null-pointer-constant warnings involving PTHREAD_MUTEX_INITIALIZER Reviewed-by: dholmes, dlong --- src/hotspot/os/linux/os_perf_linux.cpp | 5 ++++- src/hotspot/os/posix/threadCritical_posix.cpp | 8 +++++++- src/hotspot/share/utilities/compilerWarnings.hpp | 6 +++++- src/hotspot/share/utilities/compilerWarnings_gcc.hpp | 5 ++++- 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/hotspot/os/linux/os_perf_linux.cpp b/src/hotspot/os/linux/os_perf_linux.cpp index 87abbebe25faf..a31a58e55af93 100644 --- a/src/hotspot/os/linux/os_perf_linux.cpp +++ b/src/hotspot/os/linux/os_perf_linux.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -430,7 +430,10 @@ static int get_boot_time(uint64_t* time) { } static int perf_context_switch_rate(double* rate) { + PRAGMA_DIAG_PUSH + PRAGMA_ZERO_AS_NULL_POINTER_CONSTANT_IGNORED static pthread_mutex_t contextSwitchLock = PTHREAD_MUTEX_INITIALIZER; + PRAGMA_DIAG_POP static uint64_t bootTime; static uint64_t lastTimeNanos; static uint64_t lastSwitches; diff --git a/src/hotspot/os/posix/threadCritical_posix.cpp b/src/hotspot/os/posix/threadCritical_posix.cpp index 45eba4c15852c..cd3b42e71ba8b 100644 --- a/src/hotspot/os/posix/threadCritical_posix.cpp +++ b/src/hotspot/os/posix/threadCritical_posix.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2014 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -26,6 +26,7 @@ #include "precompiled.hpp" #include "runtime/javaThread.hpp" #include "runtime/threadCritical.hpp" +#include "utilities/compilerWarnings.hpp" // put OS-includes here # include @@ -35,7 +36,12 @@ // static pthread_t tc_owner = 0; + +PRAGMA_DIAG_PUSH +PRAGMA_ZERO_AS_NULL_POINTER_CONSTANT_IGNORED static pthread_mutex_t tc_mutex = PTHREAD_MUTEX_INITIALIZER; +PRAGMA_DIAG_POP + static int tc_count = 0; ThreadCritical::ThreadCritical() { diff --git a/src/hotspot/share/utilities/compilerWarnings.hpp b/src/hotspot/share/utilities/compilerWarnings.hpp index 28954843dc323..ddcaf022fa690 100644 --- a/src/hotspot/share/utilities/compilerWarnings.hpp +++ b/src/hotspot/share/utilities/compilerWarnings.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -82,6 +82,10 @@ #define PRAGMA_NONNULL_IGNORED #endif +#ifndef PRAGMA_ZERO_AS_NULL_POINTER_CONSTANT_IGNORED +#define PRAGMA_ZERO_AS_NULL_POINTER_CONSTANT_IGNORED +#endif + // Support warnings for use of certain C functions, except where explicitly // permitted. // diff --git a/src/hotspot/share/utilities/compilerWarnings_gcc.hpp b/src/hotspot/share/utilities/compilerWarnings_gcc.hpp index 53373ec628a46..1dd5892e4c348 100644 --- a/src/hotspot/share/utilities/compilerWarnings_gcc.hpp +++ b/src/hotspot/share/utilities/compilerWarnings_gcc.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -67,6 +67,9 @@ #define PRAGMA_NONNULL_IGNORED PRAGMA_DISABLE_GCC_WARNING("-Wnonnull") +#define PRAGMA_ZERO_AS_NULL_POINTER_CONSTANT_IGNORED \ + PRAGMA_DISABLE_GCC_WARNING("-Wzero-as-null-pointer-constant") + #if (__GNUC__ >= 10) // TODO: Re-enable warning attribute for Clang once // https://github.com/llvm/llvm-project/issues/56519 is fixed and released. From 5bf27098e22172ed5d3ec0c43fe0553f8322c4b1 Mon Sep 17 00:00:00 2001 From: Saint Wesonga Date: Tue, 13 Aug 2024 08:10:29 +0000 Subject: [PATCH 280/353] 8334475: UnsafeIntrinsicsTest.java#ZGenerationalDebug assert(!assert_on_failure) failed: Has low-order bits set Reviewed-by: stefank, eosterlund, aboldtch --- .../windows_aarch64/copy_windows_aarch64.hpp | 63 +++++++------------ 1 file changed, 23 insertions(+), 40 deletions(-) diff --git a/src/hotspot/os_cpu/windows_aarch64/copy_windows_aarch64.hpp b/src/hotspot/os_cpu/windows_aarch64/copy_windows_aarch64.hpp index ce2ad2d046f88..96a34fe967b64 100644 --- a/src/hotspot/os_cpu/windows_aarch64/copy_windows_aarch64.hpp +++ b/src/hotspot/os_cpu/windows_aarch64/copy_windows_aarch64.hpp @@ -26,8 +26,27 @@ #ifndef OS_CPU_WINDOWS_AARCH64_COPY_WINDOWS_AARCH64_HPP #define OS_CPU_WINDOWS_AARCH64_COPY_WINDOWS_AARCH64_HPP +#include "runtime/atomic.hpp" + #include +template +static void pd_conjoint_atomic_helper(const T* from, T* to, size_t count) { + if (from > to) { + while (count-- > 0) { + // Copy forwards + Atomic::store(to++, Atomic::load(from++)); + } + } else { + from += count - 1; + to += count - 1; + while (count-- > 0) { + // Copy backwards + Atomic::store(to--, Atomic::load(from--)); + } + } +} + static void pd_conjoint_words(const HeapWord* from, HeapWord* to, size_t count) { (void)memmove(to, from, count * HeapWordSize); } @@ -71,55 +90,19 @@ static void pd_conjoint_bytes_atomic(const void* from, void* to, size_t count) { } static void pd_conjoint_jshorts_atomic(const jshort* from, jshort* to, size_t count) { - if (from > to) { - while (count-- > 0) { - // Copy forwards - *to++ = *from++; - } - } else { - from += count - 1; - to += count - 1; - while (count-- > 0) { - // Copy backwards - *to-- = *from--; - } - } + pd_conjoint_atomic_helper(from, to, count); } static void pd_conjoint_jints_atomic(const jint* from, jint* to, size_t count) { - if (from > to) { - while (count-- > 0) { - // Copy forwards - *to++ = *from++; - } - } else { - from += count - 1; - to += count - 1; - while (count-- > 0) { - // Copy backwards - *to-- = *from--; - } - } + pd_conjoint_atomic_helper(from, to, count); } static void pd_conjoint_jlongs_atomic(const jlong* from, jlong* to, size_t count) { - pd_conjoint_oops_atomic((const oop*)from, (oop*)to, count); + pd_conjoint_atomic_helper(from, to, count); } static void pd_conjoint_oops_atomic(const oop* from, oop* to, size_t count) { - if (from > to) { - while (count-- > 0) { - // Copy forwards - *to++ = *from++; - } - } else { - from += count - 1; - to += count - 1; - while (count-- > 0) { - // Copy backwards - *to-- = *from--; - } - } + pd_conjoint_atomic_helper(from, to, count); } static void pd_arrayof_conjoint_bytes(const HeapWord* from, HeapWord* to, size_t count) { From ba69ed7c58fcf99ed18dfd8840125ddcac9460bb Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Tue, 13 Aug 2024 08:11:47 +0000 Subject: [PATCH 281/353] 8338202: Shenandoah: Improve handshake closure labels Reviewed-by: rkennke, ysr, wkemper --- src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp | 2 +- .../share/gc/shenandoah/shenandoahConcurrentMark.cpp | 2 +- src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp | 6 +++--- src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp | 2 +- src/hotspot/share/gc/shenandoah/shenandoahUnload.cpp | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp index ac2e732052a28..86d6d91f72c9a 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp @@ -823,7 +823,7 @@ void ShenandoahConcurrentGC::op_weak_roots() { // Perform handshake to flush out dead oops { ShenandoahTimingsTracker t(ShenandoahPhaseTimings::conc_weak_roots_rendezvous); - heap->rendezvous_threads(); + heap->rendezvous_threads("Shenandoah Concurrent Weak Roots"); } } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp index 31157616e0ef8..dde446d824b77 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp @@ -179,7 +179,7 @@ class ShenandoahFlushSATBHandshakeClosure : public HandshakeClosure { SATBMarkQueueSet& _qset; public: ShenandoahFlushSATBHandshakeClosure(SATBMarkQueueSet& qset) : - HandshakeClosure("Shenandoah Flush SATB Handshake"), + HandshakeClosure("Shenandoah Flush SATB"), _qset(qset) {} void do_thread(Thread* thread) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index eb6de9719dc62..0a20307abcbbf 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -1744,12 +1744,12 @@ void ShenandoahHeap::parallel_heap_region_iterate(ShenandoahHeapRegionClosure* b class ShenandoahRendezvousClosure : public HandshakeClosure { public: - inline ShenandoahRendezvousClosure() : HandshakeClosure("ShenandoahRendezvous") {} + inline ShenandoahRendezvousClosure(const char* name) : HandshakeClosure(name) {} inline void do_thread(Thread* thread) {} }; -void ShenandoahHeap::rendezvous_threads() { - ShenandoahRendezvousClosure cl; +void ShenandoahHeap::rendezvous_threads(const char* name) { + ShenandoahRendezvousClosure cl(name); Handshake::execute(&cl); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp index f3625da218cf2..86bd7b83bbe1b 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp @@ -400,7 +400,7 @@ class ShenandoahHeap : public CollectedHeap, public ShenandoahSpaceInfo { void update_heap_region_states(bool concurrent); void rebuild_free_set(bool concurrent); - void rendezvous_threads(); + void rendezvous_threads(const char* name); void recycle_trash(); public: void notify_gc_progress(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahUnload.cpp b/src/hotspot/share/gc/shenandoah/shenandoahUnload.cpp index 02a7fbeb8b5be..f33b76bcd4e1c 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahUnload.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahUnload.cpp @@ -168,7 +168,7 @@ void ShenandoahUnload::unload() { // Make sure stale metadata and nmethods are no longer observable { ShenandoahTimingsTracker t(ShenandoahPhaseTimings::conc_class_unload_rendezvous); - heap->rendezvous_threads(); + heap->rendezvous_threads("Shenandoah Class Unloading"); } // Purge stale metadata and nmethods that were unlinked From fbe4cc96e223882a18c7ff666fe6f68b3fa2cfe4 Mon Sep 17 00:00:00 2001 From: Viktor Klang Date: Tue, 13 Aug 2024 09:51:08 +0000 Subject: [PATCH 282/353] 8336384: AbstractQueuedSynchronizer.acquire should cancel acquire when failing due to a LinkageError or other errors Reviewed-by: alanb --- .../locks/AbstractQueuedLongSynchronizer.java | 19 ++++++++++++------- .../locks/AbstractQueuedSynchronizer.java | 19 ++++++++++++------- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java b/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java index f4d7d0c08c0c9..2de1d17e7c18c 100644 --- a/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java +++ b/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java @@ -369,14 +369,19 @@ final int acquire(Node node, long arg, boolean shared, } else if (node.status == 0) { node.status = WAITING; // enable signal and recheck } else { - long nanos; spins = postSpins = (byte)((postSpins << 1) | 1); - if (!timed) - LockSupport.park(this); - else if ((nanos = time - System.nanoTime()) > 0L) - LockSupport.parkNanos(this, nanos); - else - break; + try { + long nanos; + if (!timed) + LockSupport.park(this); + else if ((nanos = time - System.nanoTime()) > 0L) + LockSupport.parkNanos(this, nanos); + else + break; + } catch (Error | RuntimeException ex) { + cancelAcquire(node, interrupted, interruptible); // cancel & rethrow + throw ex; + } node.clearStatus(); if ((interrupted |= Thread.interrupted()) && interruptible) break; diff --git a/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java b/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java index 1f51419f94c18..2ea0d3ed3b091 100644 --- a/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java +++ b/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java @@ -748,14 +748,19 @@ final int acquire(Node node, int arg, boolean shared, } else if (node.status == 0) { node.status = WAITING; // enable signal and recheck } else { - long nanos; spins = postSpins = (byte)((postSpins << 1) | 1); - if (!timed) - LockSupport.park(this); - else if ((nanos = time - System.nanoTime()) > 0L) - LockSupport.parkNanos(this, nanos); - else - break; + try { + long nanos; + if (!timed) + LockSupport.park(this); + else if ((nanos = time - System.nanoTime()) > 0L) + LockSupport.parkNanos(this, nanos); + else + break; + } catch (Error | RuntimeException ex) { + cancelAcquire(node, interrupted, interruptible); // cancel & rethrow + throw ex; + } node.clearStatus(); if ((interrupted |= Thread.interrupted()) && interruptible) break; From ff8a9f9267c480fe0be8470cda870fd77763fb31 Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Tue, 13 Aug 2024 11:48:50 +0000 Subject: [PATCH 283/353] 8337318: Deoptimization::relock_objects fails assert(monitor->owner() == Thread::current()) failed: must be Co-authored-by: Richard Reingruber Reviewed-by: rrich, dholmes, shade, pchilanomate --- src/hotspot/share/runtime/synchronizer.cpp | 4 +- test/jdk/com/sun/jdi/EATests.java | 83 +++++++++++++++++++++- 2 files changed, 84 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/runtime/synchronizer.cpp b/src/hotspot/share/runtime/synchronizer.cpp index 2d45163d0f4a2..b4ff263d455b4 100644 --- a/src/hotspot/share/runtime/synchronizer.cpp +++ b/src/hotspot/share/runtime/synchronizer.cpp @@ -596,8 +596,8 @@ bool ObjectSynchronizer::enter_fast_impl(Handle obj, BasicLock* lock, JavaThread log_info(monitorinflation)("LockStack capacity exceeded, inflating."); ObjectMonitor* monitor = inflate_for(locking_thread, lock_stack.bottom(), inflate_cause_vm_internal); - assert(monitor->owner() == Thread::current(), "must be owner=" PTR_FORMAT " current=" PTR_FORMAT " mark=" PTR_FORMAT, - p2i(monitor->owner()), p2i(Thread::current()), monitor->object()->mark_acquire().value()); + assert(monitor->owner() == locking_thread, "must be owner=" PTR_FORMAT " locking_thread=" PTR_FORMAT " mark=" PTR_FORMAT, + p2i(monitor->owner()), p2i(locking_thread), monitor->object()->mark_acquire().value()); assert(!lock_stack.is_full(), "must have made room here"); } diff --git a/test/jdk/com/sun/jdi/EATests.java b/test/jdk/com/sun/jdi/EATests.java index 7285948165989..adeb21741438f 100644 --- a/test/jdk/com/sun/jdi/EATests.java +++ b/test/jdk/com/sun/jdi/EATests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 SAP SE. All rights reserved. + * Copyright (c) 2020, 2024 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -288,6 +288,7 @@ public static void main(String[] args) { // Relocking test cases new EARelockingSimpleTarget() .run(); + new EARelockingWithManyLightweightLocksTarget() .run(); new EARelockingSimpleWithAccessInOtherThreadTarget() .run(); new EARelockingSimpleWithAccessInOtherThread_02_DynamicCall_Target() .run(); new EARelockingRecursiveTarget() .run(); @@ -413,6 +414,7 @@ protected void runTests() throws Exception { // Relocking test cases new EARelockingSimple() .run(this); + new EARelockingWithManyLightweightLocks() .run(this); new EARelockingSimpleWithAccessInOtherThread() .run(this); new EARelockingSimpleWithAccessInOtherThread_02_DynamicCall() .run(this); new EARelockingRecursive() .run(this); @@ -1797,6 +1799,85 @@ public void dontinline_testMethod() { ///////////////////////////////////////////////////////////////////////////// +/** + * Like {@link EARelockingSimple}. The difference is that there are many + * lightweight locked objects when the relocking is done. With + * -XX:LockingMode=2 the lock stack of the thread will be full + * because of this. + */ + +class EARelockingWithManyLightweightLocks extends EATestCaseBaseDebugger { + + public void runTestCase() throws Exception { + BreakpointEvent bpe = resumeTo(TARGET_TESTCASE_BASE_NAME, "dontinline_brkpt", "()V"); + printStack(bpe.thread()); + @SuppressWarnings("unused") + ObjectReference o = getLocalRef(bpe.thread().frame(1), XYVAL_NAME, "l1"); + } +} + +class EARelockingWithManyLightweightLocksTarget extends EATestCaseBaseTarget { + + static class Lock { + } + + public static Lock L0, L1, L2, L3, L4, L5, L6, L7, L8, L9; + + void allocateLocks() { + L0 = new Lock(); + L1 = new Lock(); + L2 = new Lock(); + L3 = new Lock(); + L4 = new Lock(); + L5 = new Lock(); + L6 = new Lock(); + L7 = new Lock(); + L8 = new Lock(); + L9 = new Lock(); + } + + @Override + public void setUp() { + super.setUp(); + allocateLocks(); + } + + @Override + public void warmupDone() { + super.warmupDone(); + allocateLocks(); // get rid of already inflated ones + } + + public void dontinline_testMethod() { + XYVal l1 = new XYVal(4, 2); + synchronized(L0) { + synchronized(L1) { + synchronized(L2) { + synchronized(L3) { + synchronized(L4) { + synchronized(L5) { + synchronized(L6) { + synchronized(L7) { + synchronized(L8) { + synchronized(L9) { + synchronized (l1) { + dontinline_brkpt(); + } + } + } + } + } + } + } + } + } + } + } + } +} + +///////////////////////////////////////////////////////////////////////////// + // The debugger reads and publishes an object with eliminated locking to an instance field. // A 2nd thread in the debuggee finds it there and changes its state using a synchronized method. // Without eager relocking the accesses are unsynchronized which can be observed. From 76e33b6c1517599e14ee34371c945aafcd752e4e Mon Sep 17 00:00:00 2001 From: Axel Boldt-Christmas Date: Tue, 13 Aug 2024 13:13:14 +0000 Subject: [PATCH 284/353] 8336148: Test runtime/locking/TestRecursiveMonitorChurn.java failed: Unexpected Inflation Reviewed-by: dholmes, eosterlund --- .../runtime/locking/TestRecursiveMonitorChurn.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/hotspot/jtreg/runtime/locking/TestRecursiveMonitorChurn.java b/test/hotspot/jtreg/runtime/locking/TestRecursiveMonitorChurn.java index 19dd90015bf1c..806f32aad882b 100644 --- a/test/hotspot/jtreg/runtime/locking/TestRecursiveMonitorChurn.java +++ b/test/hotspot/jtreg/runtime/locking/TestRecursiveMonitorChurn.java @@ -70,6 +70,18 @@ public static void main(String[] args) { if (pre_monitor_count != post_monitor_count) { final long monitor_count_change = post_monitor_count - pre_monitor_count; System.out.println("Unexpected change in monitor count: " + monitor_count_change); + + // Intermittent deflation and inflation may occur due to running the test + // with stress flags (like DeoptimizeALot) or with added instrumentation + // which runs in the same VM. + // An arbitrary fuzzy max difference of 10 (= 0.01% of COUNT) is chosen to + // allow for these occurrences to be skipped while still catching regressions. + final long fuzzy_max_difference = 10; + if (Math.abs(monitor_count_change) < fuzzy_max_difference) { + final String type = monitor_count_change < 0 ? "deflation" : "inflation"; + throw new SkippedException("Intermittent " + type + " detected. Invalid test."); + } + if (monitor_count_change < 0) { throw new RuntimeException("Unexpected Deflation"); } From 877fd5a768647790d0a43aaca247043bae70d708 Mon Sep 17 00:00:00 2001 From: Casper Norrbin Date: Tue, 13 Aug 2024 14:43:44 +0000 Subject: [PATCH 285/353] 8337595: Remove empty statements in src/hotspot/share/memory/metaspace Reviewed-by: stefank, dholmes, jwaters --- src/hotspot/share/memory/metaspace/metaspaceCommon.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/memory/metaspace/metaspaceCommon.hpp b/src/hotspot/share/memory/metaspace/metaspaceCommon.hpp index eae75e8194cc4..511f4e6e09244 100644 --- a/src/hotspot/share/memory/metaspace/metaspaceCommon.hpp +++ b/src/hotspot/share/memory/metaspace/metaspaceCommon.hpp @@ -85,7 +85,7 @@ void print_percentage(outputStream* st, size_t total, size_t part); SIZE_FORMAT_X " is not aligned to " \ SIZE_FORMAT_X, (size_t)(uintptr_t)value, (size_t)(alignment)) #define assert_is_aligned_metaspace_pointer(p) \ - assert_is_aligned((p), metaspace::AllocationAlignmentByteSize); + assert_is_aligned((p), metaspace::AllocationAlignmentByteSize) #else #define assert_is_aligned(value, alignment) #define assert_is_aligned_metaspace_pointer(pointer) @@ -141,8 +141,8 @@ void print_number_of_classes(outputStream* out, uintx classes, uintx classes_sha #define HAVE_UL #ifdef HAVE_UL -#define UL(level, message) log_##level(metaspace)(LOGFMT ": " message, LOGFMT_ARGS); -#define UL2(level, message, ...) log_##level(metaspace)(LOGFMT ": " message, LOGFMT_ARGS, __VA_ARGS__); +#define UL(level, message) log_##level(metaspace)(LOGFMT ": " message, LOGFMT_ARGS) +#define UL2(level, message, ...) log_##level(metaspace)(LOGFMT ": " message, LOGFMT_ARGS, __VA_ARGS__) #else #define UL(level, ...) #define UL2(level, ...) From 9e282e5c966a9c065de8b901b7d30bb5c9ccf243 Mon Sep 17 00:00:00 2001 From: Liam Miller-Cushon Date: Tue, 13 Aug 2024 15:05:49 +0000 Subject: [PATCH 286/353] 8337998: CompletionFailure in getEnclosingType attaching type annotations Reviewed-by: vromero --- .../com/sun/tools/javac/jvm/ClassReader.java | 15 ++- .../tools/javac/resources/compiler.properties | 5 + .../CompletionErrorOnEnclosingType.java | 98 +++++++++++++++++++ .../tools/javac/diags/examples.not-yet.txt | 1 + 4 files changed, 116 insertions(+), 3 deletions(-) create mode 100644 test/langtools/tools/javac/annotations/typeAnnotations/CompletionErrorOnEnclosingType.java diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java index fcc1efda8dcc0..bd05cf91e9112 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java @@ -62,6 +62,7 @@ import com.sun.tools.javac.jvm.ClassFile.Version; import com.sun.tools.javac.jvm.PoolConstant.NameAndType; import com.sun.tools.javac.main.Option; +import com.sun.tools.javac.resources.CompilerProperties.Errors; import com.sun.tools.javac.resources.CompilerProperties.Fragments; import com.sun.tools.javac.resources.CompilerProperties.Warnings; import com.sun.tools.javac.util.*; @@ -2311,9 +2312,17 @@ public void run() { * 4.7.20-A target_type to locate the correct type to rewrite, and then interpreting the JVMS * 4.7.20.2 type_path to associate the annotation with the correct contained type. */ - private static void addTypeAnnotationsToSymbol( - Symbol s, List attributes) { - new TypeAnnotationSymbolVisitor(attributes).visit(s, null); + private void addTypeAnnotationsToSymbol(Symbol s, List attributes) { + try { + new TypeAnnotationSymbolVisitor(attributes).visit(s, null); + } catch (CompletionFailure ex) { + JavaFileObject prev = log.useSource(currentClassFile); + try { + log.error(Errors.CantAttachTypeAnnotations(attributes, s.owner, s.name, ex.getDetailValue())); + } finally { + log.useSource(prev); + } + } } private static class TypeAnnotationSymbolVisitor diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties index 8576106e15f5a..10f06ad70176d 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties @@ -2345,6 +2345,11 @@ compiler.warn.annotation.method.not.found=\ compiler.warn.annotation.method.not.found.reason=\ Cannot find annotation method ''{1}()'' in type ''{0}'': {2} +# 0: list of annotation, 1: symbol, 2: name, 3: message segment +compiler.err.cant.attach.type.annotations=\ + Cannot attach type annotations {0} to {1}.{2}:\n\ + {3} + # 0: file object, 1: symbol, 2: name compiler.warn.unknown.enum.constant=\ unknown enum constant {1}.{2} diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/CompletionErrorOnEnclosingType.java b/test/langtools/tools/javac/annotations/typeAnnotations/CompletionErrorOnEnclosingType.java new file mode 100644 index 0000000000000..11b4e1ccbd44c --- /dev/null +++ b/test/langtools/tools/javac/annotations/typeAnnotations/CompletionErrorOnEnclosingType.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2024, Alphabet LLC. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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 8337998 + * @summary CompletionFailure in getEnclosingType attaching type annotations + * @library /tools/javac/lib /tools/lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + */ + +import toolbox.*; +import toolbox.Task.*; + +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; + +public class CompletionErrorOnEnclosingType { + ToolBox tb = new ToolBox(); + + public static void main(String... args) throws Exception { + CompletionErrorOnEnclosingType t = new CompletionErrorOnEnclosingType(); + t.testMissingEnclosingType(); + } + + void testMissingEnclosingType() throws Exception { + String annoSrc = + """ + import static java.lang.annotation.ElementType.TYPE_USE; + import java.lang.annotation.Target; + @Target(TYPE_USE) + @interface Anno {} + + class A {} + + class B { + private @Anno A a; + } + """; + String cSrc = + """ + class C { + B b; + } + """; + + Path base = Paths.get("."); + Path src = base.resolve("src"); + tb.createDirectories(src); + tb.writeJavaFiles(src, annoSrc, cSrc); + Path out = base.resolve("out"); + tb.createDirectories(out); + new JavacTask(tb).outdir(out).files(tb.findJavaFiles(src)).run(); + + // now if we remove A.class there will be an error but javac should not crash + tb.deleteFiles(out.resolve("A.class")); + List log = + new JavacTask(tb) + .outdir(out) + .classpath(out) + .options("-XDrawDiagnostics") + .files(src.resolve("C.java")) + .run(Expect.FAIL) + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + + var expectedOutput = + List.of( + "B.class:-:-: compiler.err.cant.attach.type.annotations: @Anno, B, a," + + " (compiler.misc.class.file.not.found: A)", + "1 error"); + if (!expectedOutput.equals(log)) { + throw new Exception("expected output not found: " + log); + } + } +} diff --git a/test/langtools/tools/javac/diags/examples.not-yet.txt b/test/langtools/tools/javac/diags/examples.not-yet.txt index 9a447927761e8..b260333850978 100644 --- a/test/langtools/tools/javac/diags/examples.not-yet.txt +++ b/test/langtools/tools/javac/diags/examples.not-yet.txt @@ -41,6 +41,7 @@ compiler.err.signature.doesnt.match.intf # UNUSED compiler.err.signature.doesnt.match.supertype # UNUSED compiler.err.source.cant.overwrite.input.file compiler.err.stack.sim.error +compiler.err.cant.attach.type.annotations # bad class file compiler.err.type.var.more.than.once # UNUSED compiler.err.type.var.more.than.once.in.result # UNUSED compiler.err.unexpected.type From 6af1d6ff210b3ddbc7d1585428b49631248a500b Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Tue, 13 Aug 2024 15:14:06 +0000 Subject: [PATCH 287/353] 8335927: Revisit AnnotationConstantValueEntry and AnnotationValue.OfConstant Reviewed-by: asotona --- .../java/lang/classfile/AnnotationValue.java | 347 +++++++++++++----- .../AnnotationConstantValueEntry.java | 19 +- .../constantpool/ConstantPoolBuilder.java | 19 - .../classfile/impl/AnnotationImpl.java | 47 +-- .../classfile/impl/AnnotationReader.java | 4 +- .../classfile/impl/ClassPrinterImpl.java | 20 +- test/jdk/jdk/classfile/AnnotationTest.java | 54 +-- test/jdk/jdk/classfile/ClassPrinterTest.java | 11 +- .../helpers/RebuildingTransformation.java | 4 +- .../classfile/AnonymousClassTest.java | 2 +- .../AnnotationDefaultVerifier.java | 4 +- .../annotations/TestAnnotationInfo.java | 8 +- 12 files changed, 358 insertions(+), 181 deletions(-) diff --git a/src/java.base/share/classes/java/lang/classfile/AnnotationValue.java b/src/java.base/share/classes/java/lang/classfile/AnnotationValue.java index 919c8a0441dde..a4a1c218ac12b 100644 --- a/src/java.base/share/classes/java/lang/classfile/AnnotationValue.java +++ b/src/java.base/share/classes/java/lang/classfile/AnnotationValue.java @@ -26,6 +26,7 @@ import java.lang.classfile.constantpool.AnnotationConstantValueEntry; import java.lang.classfile.constantpool.DoubleEntry; +import java.lang.classfile.constantpool.DynamicConstantPoolEntry; import java.lang.classfile.constantpool.FloatEntry; import java.lang.classfile.constantpool.IntegerEntry; import java.lang.classfile.constantpool.LongEntry; @@ -34,7 +35,7 @@ import jdk.internal.classfile.impl.TemporaryConstantPool; import java.lang.constant.ClassDesc; -import java.lang.constant.ConstantDesc; +import java.lang.constant.Constable; import java.util.ArrayList; import java.util.List; import jdk.internal.javac.PreviewFeature; @@ -49,191 +50,373 @@ * @since 22 */ @PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API) -public sealed interface AnnotationValue - permits AnnotationValue.OfAnnotation, AnnotationValue.OfArray, - AnnotationValue.OfConstant, AnnotationValue.OfClass, - AnnotationValue.OfEnum { +public sealed interface AnnotationValue { /** - * Models an annotation-valued element + * Models an annotation-valued element. + * The {@linkplain #tag tag} of this element is {@value ClassFile#AEV_ANNOTATION}. * * @since 22 */ @PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API) sealed interface OfAnnotation extends AnnotationValue permits AnnotationImpl.OfAnnotationImpl { - /** {@return the annotation} */ + /** {@return the annotation value} */ Annotation annotation(); } /** - * Models an array-valued element + * Models an array-valued element. + * The {@linkplain #tag tag} of this element is {@value ClassFile#AEV_ARRAY}. * * @since 22 */ @PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API) sealed interface OfArray extends AnnotationValue permits AnnotationImpl.OfArrayImpl { - /** {@return the values} */ + /** + * {@return the array elements of the array value} + * + * @apiNote + * All array elements derived from Java source code have the same type, + * which must not be an array type. ({@jls 9.6.1}) + */ List values(); } /** - * Models a constant-valued element + * Models a constant-valued element. * * @sealedGraph * @since 22 */ @PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API) - sealed interface OfConstant extends AnnotationValue - permits AnnotationValue.OfString, AnnotationValue.OfDouble, - AnnotationValue.OfFloat, AnnotationValue.OfLong, - AnnotationValue.OfInteger, AnnotationValue.OfShort, - AnnotationValue.OfCharacter, AnnotationValue.OfByte, - AnnotationValue.OfBoolean, AnnotationImpl.OfConstantImpl { - /** {@return the constant} */ + sealed interface OfConstant + extends AnnotationValue + permits OfString, OfDouble, OfFloat, OfLong, OfInt, OfShort, OfChar, OfByte, + OfBoolean, AnnotationImpl.OfConstantImpl { + /** + * {@return the constant pool entry backing this constant element} + * + * @apiNote + * Different types of constant values may share the same type of entry. + * For example, {@link OfInt} and {@link OfChar} are both + * backed by {@link IntegerEntry}. Use {@link #resolvedValue + * resolvedValue()} for a value of accurate type. + */ AnnotationConstantValueEntry constant(); - /** {@return the constant} */ - ConstantDesc constantValue(); - } - /** - * Models a constant-valued element + /** + * {@return the resolved live constant value, as an object} The type of + * the returned value may be a wrapper class or {@link String}. + * + * @apiNote + * The returned object, despite being {@link Constable}, may not + * {@linkplain Constable#describeConstable() describe} the right constant + * for encoding the annotation value in a class file. For example, + * {@link Character} returned by {@link OfChar} describes itself as a + * {@link DynamicConstantPoolEntry}, but it is actually backed by + * {@link IntegerEntry} in annotation format. + * Use {@link #constant constant()} for a correct constant pool representation. + */ + Constable resolvedValue(); + } + + /** + * Models a string-valued element. + * The {@linkplain #tag tag} of this element is {@value ClassFile#AEV_STRING}. * * @since 22 */ @PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API) - sealed interface OfString extends AnnotationValue.OfConstant + sealed interface OfString extends OfConstant permits AnnotationImpl.OfStringImpl { - /** {@return the constant} */ + /** {@return the backing UTF8 entry} */ + @Override + Utf8Entry constant(); + + /** {@return the constant string value} */ String stringValue(); + + /** + * {@return the resolved string value} + * + * @implSpec + * This method returns the same as {@link #stringValue()}. + */ + @Override + default String resolvedValue() { + return stringValue(); + } } /** - * Models a constant-valued element + * Models a double-valued element. + * The {@linkplain #tag tag} of this element is {@value ClassFile#AEV_DOUBLE}. * * @since 22 */ @PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API) - sealed interface OfDouble extends AnnotationValue.OfConstant + sealed interface OfDouble extends OfConstant permits AnnotationImpl.OfDoubleImpl { - /** {@return the constant} */ + /** {@return the backing double entry} */ + @Override + DoubleEntry constant(); + + /** {@return the constant double value} */ double doubleValue(); + + /** + * {@return the resolved double value} + * + * @implSpec + * This method returns the same as {@link #doubleValue()}. + */ + @Override + default Double resolvedValue() { + return doubleValue(); + } } /** - * Models a constant-valued element + * Models a float-valued element. + * The {@linkplain #tag tag} of this element is {@value ClassFile#AEV_FLOAT}. * * @since 22 */ @PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API) - sealed interface OfFloat extends AnnotationValue.OfConstant + sealed interface OfFloat extends OfConstant permits AnnotationImpl.OfFloatImpl { - /** {@return the constant} */ + /** {@return the backing float entry} */ + @Override + FloatEntry constant(); + + /** {@return the constant float value} */ float floatValue(); + + /** + * {@return the resolved float value} + * + * @implSpec + * This method returns the same as {@link #floatValue()}. + */ + @Override + default Float resolvedValue() { + return floatValue(); + } } /** - * Models a constant-valued element + * Models a long-valued element. + * The {@linkplain #tag tag} of this element is {@value ClassFile#AEV_LONG}. * * @since 22 */ @PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API) - sealed interface OfLong extends AnnotationValue.OfConstant + sealed interface OfLong extends OfConstant permits AnnotationImpl.OfLongImpl { - /** {@return the constant} */ + /** {@return the backing long entry} */ + @Override + LongEntry constant(); + + /** {@return the constant long value} */ long longValue(); + + /** + * {@return the resolved long value} + * + * @implSpec + * This method returns the same as {@link #longValue()}. + */ + @Override + default Long resolvedValue() { + return longValue(); + } } /** - * Models a constant-valued element + * Models an int-valued element. + * The {@linkplain #tag tag} of this element is {@value ClassFile#AEV_INT}. * * @since 22 */ @PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API) - sealed interface OfInteger extends AnnotationValue.OfConstant - permits AnnotationImpl.OfIntegerImpl { - /** {@return the constant} */ + sealed interface OfInt extends OfConstant + permits AnnotationImpl.OfIntImpl { + /** {@return the backing integer entry} */ + @Override + IntegerEntry constant(); + + /** {@return the constant int value} */ int intValue(); + + /** + * {@return the resolved int value} + * + * @implSpec + * This method returns the same as {@link #intValue()}. + */ + @Override + default Integer resolvedValue() { + return intValue(); + } } /** - * Models a constant-valued element + * Models a short-valued element. + * The {@linkplain #tag tag} of this element is {@value ClassFile#AEV_SHORT}. * * @since 22 */ @PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API) - sealed interface OfShort extends AnnotationValue.OfConstant + sealed interface OfShort extends OfConstant permits AnnotationImpl.OfShortImpl { - /** {@return the constant} */ + /** {@return the backing integer entry} */ + @Override + IntegerEntry constant(); + + /** + * {@return the constant short value} + * @jvms 2.11.1 Types and the Java Virtual Machine + */ short shortValue(); + + /** + * {@return the resolved short value} + * + * @implSpec + * This method returns the same as {@link #shortValue()}. + */ + @Override + default Short resolvedValue() { + return shortValue(); + } } /** - * Models a constant-valued element + * Models a char-valued element. + * The {@linkplain #tag tag} of this element is {@value ClassFile#AEV_CHAR}. * * @since 22 */ @PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API) - sealed interface OfCharacter extends AnnotationValue.OfConstant - permits AnnotationImpl.OfCharacterImpl { - /** {@return the constant} */ + sealed interface OfChar extends OfConstant + permits AnnotationImpl.OfCharImpl { + /** {@return the backing integer entry} */ + @Override + IntegerEntry constant(); + + /** + * {@return the constant char value} + * @jvms 2.11.1 Types and the Java Virtual Machine + */ char charValue(); + + /** + * {@return the resolved char value} + * + * @implSpec + * This method returns the same as {@link #charValue()}. + */ + @Override + default Character resolvedValue() { + return charValue(); + } } /** - * Models a constant-valued element + * Models a byte-valued element. + * The {@linkplain #tag tag} of this element is {@value ClassFile#AEV_BYTE}. * * @since 22 */ @PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API) - sealed interface OfByte extends AnnotationValue.OfConstant + sealed interface OfByte extends OfConstant permits AnnotationImpl.OfByteImpl { - /** {@return the constant} */ + /** {@return the backing integer entry} */ + @Override + IntegerEntry constant(); + + /** + * {@return the constant byte value} + * @jvms 2.11.1 Types and the Java Virtual Machine + */ byte byteValue(); + + /** + * {@return the resolved byte value} + * + * @implSpec + * This method returns the same as {@link #byteValue()}. + */ + @Override + default Byte resolvedValue() { + return byteValue(); + } } /** - * Models a constant-valued element + * Models a boolean-valued element. + * The {@linkplain #tag tag} of this element is {@value ClassFile#AEV_BOOLEAN}. * * @since 22 */ @PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API) - sealed interface OfBoolean extends AnnotationValue.OfConstant + sealed interface OfBoolean extends OfConstant permits AnnotationImpl.OfBooleanImpl { - /** {@return the constant} */ + /** {@return the backing integer entry} */ + @Override + IntegerEntry constant(); + + /** + * {@return the constant boolean value} + * @jvms 2.3.4 The boolean Type + */ boolean booleanValue(); + + /** + * {@return the resolved boolean value} + * + * @implSpec + * This method returns the same as {@link #booleanValue()}. + */ + @Override + default Boolean resolvedValue() { + return booleanValue(); + } } /** - * Models a class-valued element + * Models a class-valued element. + * The {@linkplain #tag tag} of this element is {@value ClassFile#AEV_CLASS}. * * @since 22 */ @PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API) sealed interface OfClass extends AnnotationValue permits AnnotationImpl.OfClassImpl { - /** {@return the class name} */ + /** {@return the class descriptor string} */ Utf8Entry className(); - /** {@return the class symbol} */ + /** {@return the class descriptor} */ default ClassDesc classSymbol() { return ClassDesc.ofDescriptor(className().stringValue()); } } /** - * Models an enum-valued element + * Models an enum-valued element. + * The {@linkplain #tag tag} of this element is {@value ClassFile#AEV_ENUM}. * * @since 22 */ @PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API) sealed interface OfEnum extends AnnotationValue permits AnnotationImpl.OfEnumImpl { - /** {@return the enum class name} */ + /** {@return the enum class descriptor string} */ Utf8Entry className(); - /** {@return the enum class symbol} */ + /** {@return the enum class descriptor} */ default ClassDesc classSymbol() { return ClassDesc.ofDescriptor(className().stringValue()); } @@ -249,7 +432,7 @@ default ClassDesc classSymbol() { /** * {@return an annotation element for a enum-valued element} - * @param className the name of the enum class + * @param className the descriptor string of the enum class * @param constantName the name of the enum constant */ static OfEnum ofEnum(Utf8Entry className, @@ -259,7 +442,7 @@ static OfEnum ofEnum(Utf8Entry className, /** * {@return an annotation element for a enum-valued element} - * @param className the name of the enum class + * @param className the descriptor of the enum class * @param constantName the name of the enum constant */ static OfEnum ofEnum(ClassDesc className, String constantName) { @@ -269,7 +452,7 @@ static OfEnum ofEnum(ClassDesc className, String constantName) { /** * {@return an annotation element for a class-valued element} - * @param className the name of the enum class + * @param className the descriptor string of the class */ static OfClass ofClass(Utf8Entry className) { return new AnnotationImpl.OfClassImpl(className); @@ -277,7 +460,7 @@ static OfClass ofClass(Utf8Entry className) { /** * {@return an annotation element for a class-valued element} - * @param className the name of the enum class + * @param className the descriptor of the class */ static OfClass ofClass(ClassDesc className) { return ofClass(TemporaryConstantPool.INSTANCE.utf8Entry(className.descriptorString())); @@ -287,7 +470,7 @@ static OfClass ofClass(ClassDesc className) { * {@return an annotation element for a string-valued element} * @param value the string */ - static OfConstant ofString(Utf8Entry value) { + static OfString ofString(Utf8Entry value) { return new AnnotationImpl.OfStringImpl(value); } @@ -295,7 +478,7 @@ static OfConstant ofString(Utf8Entry value) { * {@return an annotation element for a string-valued element} * @param value the string */ - static OfConstant ofString(String value) { + static OfString ofString(String value) { return ofString(TemporaryConstantPool.INSTANCE.utf8Entry(value)); } @@ -303,7 +486,7 @@ static OfConstant ofString(String value) { * {@return an annotation element for a double-valued element} * @param value the double value */ - static OfConstant ofDouble(DoubleEntry value) { + static OfDouble ofDouble(DoubleEntry value) { return new AnnotationImpl.OfDoubleImpl(value); } @@ -311,7 +494,7 @@ static OfConstant ofDouble(DoubleEntry value) { * {@return an annotation element for a double-valued element} * @param value the double value */ - static OfConstant ofDouble(double value) { + static OfDouble ofDouble(double value) { return ofDouble(TemporaryConstantPool.INSTANCE.doubleEntry(value)); } @@ -319,7 +502,7 @@ static OfConstant ofDouble(double value) { * {@return an annotation element for a float-valued element} * @param value the float value */ - static OfConstant ofFloat(FloatEntry value) { + static OfFloat ofFloat(FloatEntry value) { return new AnnotationImpl.OfFloatImpl(value); } @@ -327,7 +510,7 @@ static OfConstant ofFloat(FloatEntry value) { * {@return an annotation element for a float-valued element} * @param value the float value */ - static OfConstant ofFloat(float value) { + static OfFloat ofFloat(float value) { return ofFloat(TemporaryConstantPool.INSTANCE.floatEntry(value)); } @@ -335,7 +518,7 @@ static OfConstant ofFloat(float value) { * {@return an annotation element for a long-valued element} * @param value the long value */ - static OfConstant ofLong(LongEntry value) { + static OfLong ofLong(LongEntry value) { return new AnnotationImpl.OfLongImpl(value); } @@ -343,7 +526,7 @@ static OfConstant ofLong(LongEntry value) { * {@return an annotation element for a long-valued element} * @param value the long value */ - static OfConstant ofLong(long value) { + static OfLong ofLong(long value) { return ofLong(TemporaryConstantPool.INSTANCE.longEntry(value)); } @@ -351,15 +534,15 @@ static OfConstant ofLong(long value) { * {@return an annotation element for an int-valued element} * @param value the int value */ - static OfConstant ofInt(IntegerEntry value) { - return new AnnotationImpl.OfIntegerImpl(value); + static OfInt ofInt(IntegerEntry value) { + return new AnnotationImpl.OfIntImpl(value); } /** * {@return an annotation element for an int-valued element} * @param value the int value */ - static OfConstant ofInt(int value) { + static OfInt ofInt(int value) { return ofInt(TemporaryConstantPool.INSTANCE.intEntry(value)); } @@ -367,7 +550,7 @@ static OfConstant ofInt(int value) { * {@return an annotation element for a short-valued element} * @param value the short value */ - static OfConstant ofShort(IntegerEntry value) { + static OfShort ofShort(IntegerEntry value) { return new AnnotationImpl.OfShortImpl(value); } @@ -375,7 +558,7 @@ static OfConstant ofShort(IntegerEntry value) { * {@return an annotation element for a short-valued element} * @param value the short value */ - static OfConstant ofShort(short value) { + static OfShort ofShort(short value) { return ofShort(TemporaryConstantPool.INSTANCE.intEntry(value)); } @@ -383,15 +566,15 @@ static OfConstant ofShort(short value) { * {@return an annotation element for a char-valued element} * @param value the char value */ - static OfConstant ofChar(IntegerEntry value) { - return new AnnotationImpl.OfCharacterImpl(value); + static OfChar ofChar(IntegerEntry value) { + return new AnnotationImpl.OfCharImpl(value); } /** * {@return an annotation element for a char-valued element} * @param value the char value */ - static OfConstant ofChar(char value) { + static OfChar ofChar(char value) { return ofChar(TemporaryConstantPool.INSTANCE.intEntry(value)); } @@ -399,7 +582,7 @@ static OfConstant ofChar(char value) { * {@return an annotation element for a byte-valued element} * @param value the byte value */ - static OfConstant ofByte(IntegerEntry value) { + static OfByte ofByte(IntegerEntry value) { return new AnnotationImpl.OfByteImpl(value); } @@ -407,7 +590,7 @@ static OfConstant ofByte(IntegerEntry value) { * {@return an annotation element for a byte-valued element} * @param value the byte value */ - static OfConstant ofByte(byte value) { + static OfByte ofByte(byte value) { return ofByte(TemporaryConstantPool.INSTANCE.intEntry(value)); } @@ -415,7 +598,7 @@ static OfConstant ofByte(byte value) { * {@return an annotation element for a boolean-valued element} * @param value the boolean value */ - static OfConstant ofBoolean(IntegerEntry value) { + static OfBoolean ofBoolean(IntegerEntry value) { return new AnnotationImpl.OfBooleanImpl(value); } @@ -423,7 +606,7 @@ static OfConstant ofBoolean(IntegerEntry value) { * {@return an annotation element for a boolean-valued element} * @param value the boolean value */ - static OfConstant ofBoolean(boolean value) { + static OfBoolean ofBoolean(boolean value) { int i = value ? 1 : 0; return ofBoolean(TemporaryConstantPool.INSTANCE.intEntry(i)); } @@ -438,7 +621,7 @@ static OfAnnotation ofAnnotation(Annotation value) { /** * {@return an annotation element for an array-valued element} - * @param values the values + * @param values the array elements */ static OfArray ofArray(List values) { return new AnnotationImpl.OfArrayImpl(values); @@ -446,7 +629,7 @@ static OfArray ofArray(List values) { /** * {@return an annotation element for an array-valued element} - * @param values the values + * @param values the array elements */ static OfArray ofArray(AnnotationValue... values) { return ofArray(List.of(values)); diff --git a/src/java.base/share/classes/java/lang/classfile/constantpool/AnnotationConstantValueEntry.java b/src/java.base/share/classes/java/lang/classfile/constantpool/AnnotationConstantValueEntry.java index 3a7053a49f505..d405f68570ebe 100644 --- a/src/java.base/share/classes/java/lang/classfile/constantpool/AnnotationConstantValueEntry.java +++ b/src/java.base/share/classes/java/lang/classfile/constantpool/AnnotationConstantValueEntry.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,13 +24,23 @@ */ package java.lang.classfile.constantpool; +import java.lang.classfile.AnnotationValue; import java.lang.constant.ConstantDesc; import jdk.internal.javac.PreviewFeature; /** - * A constant pool entry that may be used as an annotation constant, - * which includes the four kinds of primitive constants, and UTF8 constants. + * A constant pool entry that may be used by annotation constant values, + * which includes the four kinds of primitive constants and UTF8 constants. + * These entries are also the only entries that do not refer to other + * constant pool entries. * + * @apiNote + * An annotation constant value entry alone is not sufficient to determine + * the annotation constant; for example, an {@link IntegerEntry} of {@code 1} + * can mean {@code true} in {@link AnnotationValue.OfBoolean} or {@code 1} + * in {@link AnnotationValue.OfInt}. + * + * @see AnnotationValue.OfConstant * @sealedGraph * @since 22 */ @@ -40,7 +50,8 @@ public sealed interface AnnotationConstantValueEntry extends PoolEntry /** * {@return the constant value} The constant value will be an {@link Integer}, - * {@link Long}, {@link Float}, {@link Double}, or {@link String}. + * {@link Long}, {@link Float}, {@link Double} for the primitive constants, + * or {@link String} for UTF8 constants. */ ConstantDesc constantValue(); } diff --git a/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantPoolBuilder.java b/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantPoolBuilder.java index c092717547692..db77f8e2e8a17 100644 --- a/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantPoolBuilder.java +++ b/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantPoolBuilder.java @@ -510,25 +510,6 @@ default LoadableConstantEntry loadableConstantEntry(ConstantDesc c) { throw new IllegalArgumentException("Illegal type: " + (c == null ? null : c.getClass())); } - /** - * {@return An {@link AnnotationConstantValueEntry} describing the provided - * constant} The constant should be an Integer, String, Long, Float, - * Double, ClassDesc (for a Class constant), or MethodTypeDesc (for a MethodType - * constant.) - * - * @param c the constant - */ - default AnnotationConstantValueEntry annotationConstantValueEntry(ConstantDesc c) { - if (c instanceof Integer i) return intEntry(i); - if (c instanceof String s) return utf8Entry(s); - if (c instanceof Long l) return longEntry(l); - if (c instanceof Float f) return floatEntry(f); - if (c instanceof Double d) return doubleEntry(d); - if (c instanceof ClassDesc cd) return utf8Entry(cd); - if (c instanceof MethodTypeDesc mtd) return utf8Entry(mtd); - throw new IllegalArgumentException("Illegal type: " + (c == null ? null : c.getClass())); - } - /** * {@return a {@link BootstrapMethodEntry} describing the provided * bootstrap method and static arguments} diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationImpl.java index 03353e272a675..794e7915960ac 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationImpl.java @@ -27,7 +27,6 @@ import java.lang.classfile.*; import java.lang.classfile.constantpool.*; -import java.lang.constant.ConstantDesc; import java.util.List; import static java.lang.classfile.ClassFile.*; @@ -80,12 +79,7 @@ public void writeTo(BufWriterImpl buf) { } } - public sealed interface OfConstantImpl extends AnnotationValue.OfConstant, Util.Writable - permits AnnotationImpl.OfStringImpl, AnnotationImpl.OfDoubleImpl, - AnnotationImpl.OfFloatImpl, AnnotationImpl.OfLongImpl, - AnnotationImpl.OfIntegerImpl, AnnotationImpl.OfShortImpl, - AnnotationImpl.OfCharacterImpl, AnnotationImpl.OfByteImpl, - AnnotationImpl.OfBooleanImpl { + public sealed interface OfConstantImpl extends AnnotationValue.OfConstant, Util.Writable { @Override default void writeTo(BufWriterImpl buf) { @@ -93,15 +87,10 @@ default void writeTo(BufWriterImpl buf) { buf.writeIndex(constant()); } - @Override - default ConstantDesc constantValue() { - return constant().constantValue(); - } - } public record OfStringImpl(Utf8Entry constant) - implements AnnotationImpl.OfConstantImpl, AnnotationValue.OfString { + implements OfConstantImpl, AnnotationValue.OfString { @Override public char tag() { @@ -115,7 +104,7 @@ public String stringValue() { } public record OfDoubleImpl(DoubleEntry constant) - implements AnnotationImpl.OfConstantImpl, AnnotationValue.OfDouble { + implements OfConstantImpl, AnnotationValue.OfDouble { @Override public char tag() { @@ -129,7 +118,7 @@ public double doubleValue() { } public record OfFloatImpl(FloatEntry constant) - implements AnnotationImpl.OfConstantImpl, AnnotationValue.OfFloat { + implements OfConstantImpl, AnnotationValue.OfFloat { @Override public char tag() { @@ -143,7 +132,7 @@ public float floatValue() { } public record OfLongImpl(LongEntry constant) - implements AnnotationImpl.OfConstantImpl, AnnotationValue.OfLong { + implements OfConstantImpl, AnnotationValue.OfLong { @Override public char tag() { @@ -156,8 +145,8 @@ public long longValue() { } } - public record OfIntegerImpl(IntegerEntry constant) - implements AnnotationImpl.OfConstantImpl, AnnotationValue.OfInteger { + public record OfIntImpl(IntegerEntry constant) + implements OfConstantImpl, AnnotationValue.OfInt { @Override public char tag() { @@ -171,7 +160,7 @@ public int intValue() { } public record OfShortImpl(IntegerEntry constant) - implements AnnotationImpl.OfConstantImpl, AnnotationValue.OfShort { + implements OfConstantImpl, AnnotationValue.OfShort { @Override public char tag() { @@ -180,12 +169,12 @@ public char tag() { @Override public short shortValue() { - return (short)constant().intValue(); + return (short) constant().intValue(); } } - public record OfCharacterImpl(IntegerEntry constant) - implements AnnotationImpl.OfConstantImpl, AnnotationValue.OfCharacter { + public record OfCharImpl(IntegerEntry constant) + implements OfConstantImpl, AnnotationValue.OfChar { @Override public char tag() { @@ -194,12 +183,12 @@ public char tag() { @Override public char charValue() { - return (char)constant().intValue(); + return (char) constant().intValue(); } } public record OfByteImpl(IntegerEntry constant) - implements AnnotationImpl.OfConstantImpl, AnnotationValue.OfByte { + implements OfConstantImpl, AnnotationValue.OfByte { @Override public char tag() { @@ -208,12 +197,12 @@ public char tag() { @Override public byte byteValue() { - return (byte)constant().intValue(); + return (byte) constant().intValue(); } } public record OfBooleanImpl(IntegerEntry constant) - implements AnnotationImpl.OfConstantImpl, AnnotationValue.OfBoolean { + implements OfConstantImpl, AnnotationValue.OfBoolean { @Override public char tag() { @@ -222,15 +211,15 @@ public char tag() { @Override public boolean booleanValue() { - return constant().intValue() == 1; + return constant().intValue() != 0; } } public record OfArrayImpl(List values) implements AnnotationValue.OfArray, Util.Writable { - public OfArrayImpl(List values) { - this.values = List.copyOf(values); + public OfArrayImpl { + values = List.copyOf(values); } @Override diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationReader.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationReader.java index 2ada13aaba82c..e21938bbc0cd5 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationReader.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationReader.java @@ -60,10 +60,10 @@ public static AnnotationValue readElementValue(ClassReader classReader, int p) { ++p; return switch (tag) { case AEV_BYTE -> new AnnotationImpl.OfByteImpl(classReader.readEntry(p, IntegerEntry.class)); - case AEV_CHAR -> new AnnotationImpl.OfCharacterImpl(classReader.readEntry(p, IntegerEntry.class)); + case AEV_CHAR -> new AnnotationImpl.OfCharImpl(classReader.readEntry(p, IntegerEntry.class)); case AEV_DOUBLE -> new AnnotationImpl.OfDoubleImpl(classReader.readEntry(p, DoubleEntry.class)); case AEV_FLOAT -> new AnnotationImpl.OfFloatImpl(classReader.readEntry(p, FloatEntry.class)); - case AEV_INT -> new AnnotationImpl.OfIntegerImpl(classReader.readEntry(p, IntegerEntry.class)); + case AEV_INT -> new AnnotationImpl.OfIntImpl(classReader.readEntry(p, IntegerEntry.class)); case AEV_LONG -> new AnnotationImpl.OfLongImpl(classReader.readEntry(p, LongEntry.class)); case AEV_SHORT -> new AnnotationImpl.OfShortImpl(classReader.readEntry(p, IntegerEntry.class)); case AEV_BOOLEAN -> new AnnotationImpl.OfBooleanImpl(classReader.readEntry(p, IntegerEntry.class)); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassPrinterImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassPrinterImpl.java index fac2eba95fe6b..75346dd59985f 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassPrinterImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassPrinterImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -507,15 +507,15 @@ private static String toXmlName(String name) { private static Node[] elementValueToTree(AnnotationValue v) { return switch (v) { - case OfString cv -> leafs("string", String.valueOf(cv.constantValue())); - case OfDouble cv -> leafs("double", String.valueOf(cv.constantValue())); - case OfFloat cv -> leafs("float", String.valueOf(cv.constantValue())); - case OfLong cv -> leafs("long", String.valueOf(cv.constantValue())); - case OfInteger cv -> leafs("int", String.valueOf(cv.constantValue())); - case OfShort cv -> leafs("short", String.valueOf(cv.constantValue())); - case OfCharacter cv -> leafs("char", String.valueOf(cv.constantValue())); - case OfByte cv -> leafs("byte", String.valueOf(cv.constantValue())); - case OfBoolean cv -> leafs("boolean", String.valueOf((int)cv.constantValue() != 0)); + case OfString cv -> leafs("string", String.valueOf(cv.stringValue())); + case OfDouble cv -> leafs("double", String.valueOf(cv.doubleValue())); + case OfFloat cv -> leafs("float", String.valueOf(cv.floatValue())); + case OfLong cv -> leafs("long", String.valueOf(cv.longValue())); + case OfInt cv -> leafs("int", String.valueOf(cv.intValue())); + case OfShort cv -> leafs("short", String.valueOf(cv.shortValue())); + case OfChar cv -> leafs("char", String.valueOf(cv.charValue())); + case OfByte cv -> leafs("byte", String.valueOf(cv.byteValue())); + case OfBoolean cv -> leafs("boolean", String.valueOf(cv.booleanValue())); case OfClass clv -> leafs("class", clv.className().stringValue()); case OfEnum ev -> leafs("enum class", ev.className().stringValue(), "constant name", ev.constantName().stringValue()); diff --git a/test/jdk/jdk/classfile/AnnotationTest.java b/test/jdk/jdk/classfile/AnnotationTest.java index 4ed3b2141ad47..6b6b88b3de180 100644 --- a/test/jdk/jdk/classfile/AnnotationTest.java +++ b/test/jdk/jdk/classfile/AnnotationTest.java @@ -28,6 +28,8 @@ */ import java.lang.constant.ClassDesc; import static java.lang.constant.ConstantDescs.*; + +import java.lang.constant.ConstantDesc; import java.lang.constant.MethodTypeDesc; import java.util.AbstractMap; import java.util.ArrayList; @@ -39,6 +41,8 @@ import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute; import java.lang.classfile.*; import java.lang.classfile.constantpool.ConstantPoolBuilder; +import java.util.stream.Stream; + import org.junit.jupiter.api.Test; import static java.util.stream.Collectors.toList; @@ -53,26 +57,30 @@ class AnnotationTest { enum E {C}; - private static Map constants + // name -> (value, poolValue) + private static final Map> constants = Map.ofEntries( - new AbstractMap.SimpleImmutableEntry<>("i", 1), - new AbstractMap.SimpleImmutableEntry<>("j", 1L), - new AbstractMap.SimpleImmutableEntry<>("s", 1), - new AbstractMap.SimpleImmutableEntry<>("b", 1), - new AbstractMap.SimpleImmutableEntry<>("f", 1.0f), - new AbstractMap.SimpleImmutableEntry<>("d", 1.0d), - new AbstractMap.SimpleImmutableEntry<>("z", 1), - new AbstractMap.SimpleImmutableEntry<>("c", (int) '1'), - new AbstractMap.SimpleImmutableEntry<>("st", "1"), - new AbstractMap.SimpleImmutableEntry<>("cl", ClassDesc.of("foo.Bar")), - new AbstractMap.SimpleImmutableEntry<>("en", E.C), - new AbstractMap.SimpleImmutableEntry<>("arr", new Object[] {1, "1", 1.0f}) + Map.entry("i", Map.entry(1, 1)), + Map.entry("j", Map.entry(1L, 1L)), + Map.entry("s", Map.entry((short) 1, 1)), + Map.entry("b", Map.entry((byte) 1, 1)), + Map.entry("f", Map.entry(1.0f, 1.0f)), + Map.entry("d", Map.entry(1.0d, 1.0d)), + Map.entry("z", Map.entry(true, 1)), + Map.entry("c", Map.entry('1', (int) '1')), + Map.entry("st", Map.entry("1", "1")) ); - private static final List constantElements = + private static final List constantElements = Stream.concat( constants.entrySet().stream() - .map(e -> AnnotationElement.of(e.getKey(), AnnotationValue.of(e.getValue()))) - .toList(); + .map(e -> Map.entry(e.getKey(), e.getValue().getKey())), + Stream.of( + Map.entry("cl", ClassDesc.of("foo.Bar")), + Map.entry("en", E.C), + Map.entry("arr", new Object[] {1, "1", 1.0f}) + )) + .map(e -> AnnotationElement.of(e.getKey(), AnnotationValue.of(e.getValue()))) + .toList(); private static List elements() { List list = new ArrayList<>(constantElements); @@ -88,9 +96,12 @@ private static boolean assertAnno(Annotation a, String annoClassDescriptor, bool names.add(evp.name().stringValue()); switch (evp.name().stringValue()) { case "i", "j", "s", "b", "f", "d", "z", "c", "st": - assertTrue (evp.value() instanceof AnnotationValue.OfConstant c); - assertEquals(((AnnotationValue.OfConstant) evp.value()).constantValue(), - constants.get(evp.name().stringValue())); + if (!(evp.value() instanceof AnnotationValue.OfConstant c)) + return fail(); + assertEquals(c.resolvedValue(), + constants.get(evp.name().stringValue()).getKey()); + assertEquals(c.constant().constantValue(), + constants.get(evp.name().stringValue()).getValue()); break; case "cl": assertTrue (evp.value() instanceof AnnotationValue.OfClass c @@ -105,8 +116,9 @@ private static boolean assertAnno(Annotation a, String annoClassDescriptor, bool && assertAnno(c.annotation(), "LBar;", false)); break; case "arr": - assertTrue (evp.value() instanceof AnnotationValue.OfArray); - List values = ((AnnotationValue.OfArray) evp.value()).values(); + if (!(evp.value() instanceof AnnotationValue.OfArray arr)) + return fail(); + List values = arr.values(); assertEquals(values.stream().map(v -> ((AnnotationValue.OfConstant) v).constant().constantValue()).collect(toSet()), Set.of(1, 1.0f, "1")); break; diff --git a/test/jdk/jdk/classfile/ClassPrinterTest.java b/test/jdk/jdk/classfile/ClassPrinterTest.java index 9c25ff7e13af7..7668648f82901 100644 --- a/test/jdk/jdk/classfile/ClassPrinterTest.java +++ b/test/jdk/jdk/classfile/ClassPrinterTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,7 @@ /* * @test + * @bug 8335927 * @summary Testing ClassFile ClassPrinter. * @run junit ClassPrinterTest */ @@ -249,7 +250,7 @@ record components: flags: [PROTECTED] method type: (ZLjava/lang/Throwable;)Ljava/lang/Void; attributes: [AnnotationDefault, RuntimeVisibleParameterAnnotations, RuntimeInvisibleParameterAnnotations, Exceptions, Code] - annotation default: {array: [{boolean: true}, {byte: 12}, {char: 99}, {class: LPhee;}, {double: 1.3}, {enum class: LBoo;, constant name: BOO}, {float: 3.7}, {int: 33}, {long: 3333}, {short: 25}, {string: BOO}, {annotation class: LPhoo;}]} + annotation default: {array: [{boolean: true}, {byte: 12}, {char: c}, {class: LPhee;}, {double: 1.3}, {enum class: LBoo;, constant name: BOO}, {float: 3.7}, {int: 33}, {long: 3333}, {short: 25}, {string: BOO}, {annotation class: LPhoo;}]} visible parameter annotations: parameter 1: [{annotation class: LPhoo;, values: [{name: flfl, value: {float: 22.0}}, {name: frfl, value: {float: 11.0}}]}] invisible parameter annotations: @@ -500,7 +501,7 @@ void testPrintJsonTraceAll() throws IOException { "flags": ["PROTECTED"], "method type": "(ZLjava/lang/Throwable;)Ljava/lang/Void;", "attributes": ["AnnotationDefault", "RuntimeVisibleParameterAnnotations", "RuntimeInvisibleParameterAnnotations", "Exceptions", "Code"], - "annotation default": {"array": [{"boolean": "true"}, {"byte": "12"}, {"char": "99"}, {"class": "LPhee;"}, {"double": "1.3"}, {"enum class": "LBoo;", "constant name": "BOO"}, {"float": "3.7"}, {"int": "33"}, {"long": "3333"}, {"short": "25"}, {"string": "BOO"}, {"annotation class": "LPhoo;"}]}, + "annotation default": {"array": [{"boolean": "true"}, {"byte": "12"}, {"char": "c"}, {"class": "LPhee;"}, {"double": "1.3"}, {"enum class": "LBoo;", "constant name": "BOO"}, {"float": "3.7"}, {"int": "33"}, {"long": "3333"}, {"short": "25"}, {"string": "BOO"}, {"annotation class": "LPhoo;"}]}, "visible parameter annotations": { "parameter 1": [{"annotation class": "LPhoo;", "values": [{"name": "flfl", "value": {"float": "22.0"}}, {"name": "frfl", "value": {"float": "11.0"}}]}]}, "invisible parameter annotations": { @@ -756,7 +757,7 @@ void testPrintXmlTraceAll() throws IOException { PROTECTED (ZLjava/lang/Throwable;)Ljava/lang/Void; AnnotationDefaultRuntimeVisibleParameterAnnotationsRuntimeInvisibleParameterAnnotationsExceptionsCode - true1299LPhee;1.3LBoo;BOO3.733333325BOOLPhoo; + true12cLPhee;1.3LBoo;BOO3.733333325BOOLPhoo; LPhoo;flfl22.0frfl11.0 @@ -907,6 +908,6 @@ private static void assertOut(StringBuilder out, String expected) { // System.out.println("-----------------"); // System.out.println(out.toString()); // System.out.println("-----------------"); - assertArrayEquals(out.toString().trim().split(" *\r?\n"), expected.trim().split("\n")); + assertArrayEquals(expected.trim().split("\n"), out.toString().trim().split(" *\r?\n")); } } diff --git a/test/jdk/jdk/classfile/helpers/RebuildingTransformation.java b/test/jdk/jdk/classfile/helpers/RebuildingTransformation.java index 2af3cd9410fde..7667403aaabc7 100644 --- a/test/jdk/jdk/classfile/helpers/RebuildingTransformation.java +++ b/test/jdk/jdk/classfile/helpers/RebuildingTransformation.java @@ -165,9 +165,9 @@ static AnnotationValue transformAnnotationValue(AnnotationValue av) { case AnnotationValue.OfDouble v -> AnnotationValue.of(v.doubleValue()); case AnnotationValue.OfFloat v -> AnnotationValue.of(v.floatValue()); case AnnotationValue.OfLong v -> AnnotationValue.of(v.longValue()); - case AnnotationValue.OfInteger v -> AnnotationValue.of(v.intValue()); + case AnnotationValue.OfInt v -> AnnotationValue.of(v.intValue()); case AnnotationValue.OfShort v -> AnnotationValue.of(v.shortValue()); - case AnnotationValue.OfCharacter v -> AnnotationValue.of(v.charValue()); + case AnnotationValue.OfChar v -> AnnotationValue.of(v.charValue()); case AnnotationValue.OfByte v -> AnnotationValue.of(v.byteValue()); case AnnotationValue.OfBoolean v -> AnnotationValue.of(v.booleanValue()); case AnnotationValue.OfClass oc -> AnnotationValue.of(oc.classSymbol()); diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/classfile/AnonymousClassTest.java b/test/langtools/tools/javac/annotations/typeAnnotations/classfile/AnonymousClassTest.java index 64c33ed9fd94c..94610ddf05518 100644 --- a/test/langtools/tools/javac/annotations/typeAnnotations/classfile/AnonymousClassTest.java +++ b/test/langtools/tools/javac/annotations/typeAnnotations/classfile/AnonymousClassTest.java @@ -246,7 +246,7 @@ private static String annotationValueDebugString(ClassModel cm, Annotation annot private static String elementValueDebugString(AnnotationValue value) { if (value.tag() == 'I') { - return Integer.toString(((AnnotationValue.OfInteger) value).intValue()); + return Integer.toString(((AnnotationValue.OfInt) value).intValue()); } else { throw new UnsupportedOperationException(String.format("%c", value.tag())); } diff --git a/test/langtools/tools/javac/classfiles/attributes/AnnotationDefault/AnnotationDefaultVerifier.java b/test/langtools/tools/javac/classfiles/attributes/AnnotationDefault/AnnotationDefaultVerifier.java index d85b37aa3a395..8efb13ccbdf8d 100644 --- a/test/langtools/tools/javac/classfiles/attributes/AnnotationDefault/AnnotationDefaultVerifier.java +++ b/test/langtools/tools/javac/classfiles/attributes/AnnotationDefault/AnnotationDefaultVerifier.java @@ -103,7 +103,7 @@ public void testElementValue( case AnnotationValue.OfByte ev -> { testCase.checkEquals((int)ev.byteValue(), Integer.parseInt(values[0]), "const_value_index"); } - case AnnotationValue.OfCharacter ev -> { + case AnnotationValue.OfChar ev -> { testCase.checkEquals((int)ev.charValue(), Integer.parseInt(values[0]), "const_value_index"); } case AnnotationValue.OfShort ev -> { @@ -113,7 +113,7 @@ public void testElementValue( testCase.checkEquals(ev.booleanValue()? 1: 0, Integer.parseInt(values[0]), "const_value_index"); } default -> { - testCase.checkEquals(((AnnotationValue.OfInteger) element_value).intValue(), Integer.parseInt(values[0]), "const_value_index"); + testCase.checkEquals(((AnnotationValue.OfInt) element_value).intValue(), Integer.parseInt(values[0]), "const_value_index"); } } } diff --git a/test/langtools/tools/javac/classfiles/attributes/annotations/TestAnnotationInfo.java b/test/langtools/tools/javac/classfiles/attributes/annotations/TestAnnotationInfo.java index 5bf587d1b8b4c..3f422b541c064 100644 --- a/test/langtools/tools/javac/classfiles/attributes/annotations/TestAnnotationInfo.java +++ b/test/langtools/tools/javac/classfiles/attributes/annotations/TestAnnotationInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -123,7 +123,7 @@ public void testElementValue(TestResult testResult, testResult.checkEquals((int)((AnnotationValue.OfShort) element_value).shortValue(), value, "const_value_index : " + value); break; default: - testResult.checkEquals(((AnnotationValue.OfInteger) element_value).intValue(), value, "const_value_index : " + value); + testResult.checkEquals(((AnnotationValue.OfInt) element_value).intValue(), value, "const_value_index : " + value); } } @@ -169,8 +169,8 @@ public void testElementValue(TestResult testResult, ClassModel classFile, AnnotationValue element_value) { testTag(testResult, element_value.tag()); - AnnotationValue.OfCharacter ev = - (AnnotationValue.OfCharacter) element_value; + AnnotationValue.OfChar ev = + (AnnotationValue.OfChar) element_value; testResult.checkEquals(ev.charValue(), value, "const_value_index : " + value); } From 58b957054437edee7d0abc365133985ac30a6af4 Mon Sep 17 00:00:00 2001 From: Alan Bateman Date: Tue, 13 Aug 2024 16:05:38 +0000 Subject: [PATCH 288/353] 8338142: (dc) DatagramChannelImpl.blockingReceive can use untimed-park when no timeout set Reviewed-by: dfuchs --- .../classes/sun/nio/ch/DatagramChannelImpl.java | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/java.base/share/classes/sun/nio/ch/DatagramChannelImpl.java b/src/java.base/share/classes/sun/nio/ch/DatagramChannelImpl.java index 5c06ac7d9be02..06e79f416ac7a 100644 --- a/src/java.base/share/classes/sun/nio/ch/DatagramChannelImpl.java +++ b/src/java.base/share/classes/sun/nio/ch/DatagramChannelImpl.java @@ -674,7 +674,6 @@ void blockingReceive(DatagramPacket p, long nanos) throws IOException { configureSocketNonBlocking(); } else { configureSocketNonBlockingIfVirtualThread(); - nanos = Long.MAX_VALUE; } // p.bufLength is the maximum size of the datagram that can be received @@ -689,7 +688,9 @@ void blockingReceive(DatagramPacket p, long nanos) throws IOException { SocketAddress remote = beginRead(true, false); boolean connected = (remote != null); do { - long remainingNanos = nanos - (System.nanoTime() - startNanos); + long remainingNanos = (nanos > 0) + ? nanos - (System.nanoTime() - startNanos) + : 0; ByteBuffer dst = tryBlockingReceive(connected, bufLength, remainingNanos); // if datagram received then get sender and copy to DatagramPacket @@ -756,11 +757,15 @@ private ByteBuffer tryBlockingReceive(boolean connected, int len, long nanos) Util.offerFirstTemporaryDirectBuffer(dst); dst = null; } - long remainingNanos = nanos - (System.nanoTime() - startNanos); - if (remainingNanos <= 0) { - throw new SocketTimeoutException("Receive timed out"); + if (nanos > 0) { + long remainingNanos = nanos - (System.nanoTime() - startNanos); + if (remainingNanos <= 0) { + throw new SocketTimeoutException("Receive timed out"); + } + park(Net.POLLIN, remainingNanos); + } else { + park(Net.POLLIN); } - park(Net.POLLIN, remainingNanos); // virtual thread needs to re-allocate temporary direct buffer after parking if (Thread.currentThread().isVirtual()) { dst = Util.getTemporaryDirectBuffer(len); From 21ca91e55dd83dc011e67a2d056e3e3bd44d40b5 Mon Sep 17 00:00:00 2001 From: Afshin Zafari Date: Tue, 13 Aug 2024 16:25:43 +0000 Subject: [PATCH 289/353] 8300800: UB: Shift exponent 32 is too large for 32-bit type 'int' Reviewed-by: kbarrett, adinn, gziemski --- src/hotspot/cpu/aarch64/immediate_aarch64.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/cpu/aarch64/immediate_aarch64.cpp b/src/hotspot/cpu/aarch64/immediate_aarch64.cpp index 7caafc19fbd31..9c67a0dfeada9 100644 --- a/src/hotspot/cpu/aarch64/immediate_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/immediate_aarch64.cpp @@ -295,7 +295,7 @@ static int expandLogicalImmediate(uint32_t immN, uint32_t immr, uint64_t and_bits_sub = replicate(and_bit, 1, nbits); uint64_t or_bits_sub = replicate(or_bit, 1, nbits); uint64_t and_bits_top = (and_bits_sub << nbits) | ones(nbits); - uint64_t or_bits_top = (0 << nbits) | or_bits_sub; + uint64_t or_bits_top = (UCONST64(0) << nbits) | or_bits_sub; tmask = ((tmask & (replicate(and_bits_top, 2 * nbits, 32 / nbits))) From 84c3065e8004122f3455a8c28c8719b2c8111c17 Mon Sep 17 00:00:00 2001 From: Neethu Prasad Date: Tue, 13 Aug 2024 17:22:41 +0000 Subject: [PATCH 290/353] 8335865: Shenandoah: Improve THP pretouch after JDK-8315923 Reviewed-by: shade, wkemper --- .../share/gc/shenandoah/shenandoahHeap.cpp | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index 0a20307abcbbf..7904cd5f1cd1d 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -283,14 +283,7 @@ jint ShenandoahHeap::initialize() { // Reserve aux bitmap for use in object_iterate(). We don't commit it here. size_t aux_bitmap_page_size = bitmap_page_size; -#ifdef LINUX - // In THP "advise" mode, we refrain from advising the system to use large pages - // since we know these commits will be short lived, and there is no reason to trash - // the THP area with this bitmap. - if (UseTransparentHugePages) { - aux_bitmap_page_size = os::vm_page_size(); - } -#endif + ReservedSpace aux_bitmap(_bitmap_size, aux_bitmap_page_size); os::trace_page_sizes_for_requested_size("Aux Bitmap", bitmap_size_orig, aux_bitmap_page_size, @@ -387,16 +380,6 @@ jint ShenandoahHeap::initialize() { _pretouch_heap_page_size = heap_page_size; _pretouch_bitmap_page_size = bitmap_page_size; -#ifdef LINUX - // UseTransparentHugePages would madvise that backing memory can be coalesced into huge - // pages. But, the kernel needs to know that every small page is used, in order to coalesce - // them into huge one. Therefore, we need to pretouch with smaller pages. - if (UseTransparentHugePages) { - _pretouch_heap_page_size = (size_t)os::vm_page_size(); - _pretouch_bitmap_page_size = (size_t)os::vm_page_size(); - } -#endif - // OS memory managers may want to coalesce back-to-back pages. Make their jobs // simpler by pre-touching continuous spaces (heap and bitmap) separately. From ca99f37f82bf59fc720babbc155502ef92d34de6 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Tue, 13 Aug 2024 18:02:24 +0000 Subject: [PATCH 291/353] 8338156: Fix -Wzero-as-null-pointer-constant warnings in jvmciCompilerToVM.cpp Reviewed-by: tschatzl, jwaters, dnsimon --- src/hotspot/share/jvmci/jvmciCompilerToVM.cpp | 64 +++++++++---------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp index 5a9b18fc4d3db..af72322ff4bf2 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp @@ -549,8 +549,8 @@ C2V_END C2V_VMENTRY_NULL(jobject, getImplementor, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass))) Klass* klass = UNPACK_PAIR(Klass, klass); if (!klass->is_interface()) { - THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), - err_msg("Expected interface type, got %s", klass->external_name())); + THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), + err_msg("Expected interface type, got %s", klass->external_name())); } InstanceKlass* iklass = InstanceKlass::cast(klass); JVMCIKlassHandle handle(THREAD, iklass->implementor()); @@ -589,7 +589,7 @@ C2V_VMENTRY_NULL(jobject, lookupType, (JNIEnv* env, jobject, jstring jname, ARGU TempNewSymbol class_name = SymbolTable::new_symbol(str); if (class_name->utf8_length() <= 1) { - JVMCI_THROW_MSG_0(InternalError, err_msg("Primitive type %s should be handled in Java code", str)); + JVMCI_THROW_MSG_NULL(InternalError, err_msg("Primitive type %s should be handled in Java code", str)); } #ifdef ASSERT @@ -598,8 +598,8 @@ C2V_VMENTRY_NULL(jobject, lookupType, (JNIEnv* env, jobject, jstring jname, ARGU if (strstr(val, "") != nullptr) { tty->print_cr("CompilerToVM.lookupType: %s", str); } else if (strstr(str, val) != nullptr) { - THROW_MSG_0(vmSymbols::java_lang_Exception(), - err_msg("lookupTypeException: %s", str)); + THROW_MSG_NULL(vmSymbols::java_lang_Exception(), + err_msg("lookupTypeException: %s", str)); } } #endif @@ -617,7 +617,7 @@ C2V_VMENTRY_NULL(jobject, lookupType, (JNIEnv* env, jobject, jstring jname, ARGU case 1: class_loader = Handle(THREAD, SystemDictionary::java_platform_loader()); break; case 2: class_loader = Handle(THREAD, SystemDictionary::java_system_loader()); break; default: - JVMCI_THROW_MSG_0(InternalError, err_msg("Illegal class loader value: %d", accessing_klass_loader)); + JVMCI_THROW_MSG_NULL(InternalError, err_msg("Illegal class loader value: %d", accessing_klass_loader)); } JVMCIENV->runtime()->initialize(JVMCI_CHECK_NULL); } @@ -660,7 +660,7 @@ C2V_VMENTRY_NULL(jobject, getArrayType, (JNIEnv* env, jobject, jchar type_char, JVMCIKlassHandle array_klass(THREAD); Klass* klass = UNPACK_PAIR(Klass, klass); if (klass == nullptr) { - BasicType type = JVMCIENV->typeCharToBasicType(type_char, JVMCI_CHECK_0); + BasicType type = JVMCIENV->typeCharToBasicType(type_char, JVMCI_CHECK_NULL); if (type == T_VOID) { return nullptr; } @@ -812,7 +812,7 @@ C2V_VMENTRY_NULL(jobjectArray, resolveBootstrapMethod, (JNIEnv* env, jobject, AR bool is_indy = tag.is_invoke_dynamic(); bool is_condy = tag.is_dynamic_constant(); if (!(is_condy || is_indy)) { - JVMCI_THROW_MSG_0(IllegalArgumentException, err_msg("Unexpected constant pool tag at index %d: %d", index, tag.value())); + JVMCI_THROW_MSG_NULL(IllegalArgumentException, err_msg("Unexpected constant pool tag at index %d: %d", index, tag.value())); } // Get the indy entry based on CP index int indy_index = -1; @@ -1969,11 +1969,11 @@ C2V_END C2V_VMENTRY_NULL(jobject, getInterfaces, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass))) Klass* klass = UNPACK_PAIR(Klass, klass); if (klass == nullptr) { - JVMCI_THROW_0(NullPointerException); + JVMCI_THROW_NULL(NullPointerException); } if (!klass->is_instance_klass()) { - JVMCI_THROW_MSG_0(InternalError, err_msg("Class %s must be instance klass", klass->external_name())); + JVMCI_THROW_MSG_NULL(InternalError, err_msg("Class %s must be instance klass", klass->external_name())); } InstanceKlass* iklass = InstanceKlass::cast(klass); @@ -1993,7 +1993,7 @@ C2V_END C2V_VMENTRY_NULL(jobject, getComponentType, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass))) Klass* klass = UNPACK_PAIR(Klass, klass); if (klass == nullptr) { - JVMCI_THROW_0(NullPointerException); + JVMCI_THROW_NULL(NullPointerException); } if (!klass->is_array_klass()) { @@ -2002,8 +2002,8 @@ C2V_VMENTRY_NULL(jobject, getComponentType, (JNIEnv* env, jobject, ARGUMENT_PAIR oop mirror = klass->java_mirror(); oop component_mirror = java_lang_Class::component_mirror(mirror); if (component_mirror == nullptr) { - JVMCI_THROW_MSG_0(NullPointerException, - err_msg("Component mirror for array class %s is null", klass->external_name())) + JVMCI_THROW_MSG_NULL(NullPointerException, + err_msg("Component mirror for array class %s is null", klass->external_name())) } Klass* component_klass = java_lang_Class::as_Klass(component_mirror); @@ -2106,7 +2106,7 @@ C2V_END C2V_VMENTRY_NULL(jobject, unboxPrimitive, (JNIEnv* env, jobject, jobject object)) if (object == nullptr) { - JVMCI_THROW_0(NullPointerException); + JVMCI_THROW_NULL(NullPointerException); } Handle box = JVMCIENV->asConstant(JVMCIENV->wrap(object), JVMCI_CHECK_NULL); BasicType type = java_lang_boxing_object::basic_type(box()); @@ -2120,7 +2120,7 @@ C2V_END C2V_VMENTRY_NULL(jobject, boxPrimitive, (JNIEnv* env, jobject, jobject object)) if (object == nullptr) { - JVMCI_THROW_0(NullPointerException); + JVMCI_THROW_NULL(NullPointerException); } JVMCIObject box = JVMCIENV->wrap(object); BasicType type = JVMCIENV->get_box_type(box); @@ -2165,7 +2165,7 @@ C2V_END C2V_VMENTRY_NULL(jobjectArray, getDeclaredConstructors, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass))) Klass* klass = UNPACK_PAIR(Klass, klass); if (klass == nullptr) { - JVMCI_THROW_0(NullPointerException); + JVMCI_THROW_NULL(NullPointerException); } if (!klass->is_instance_klass()) { JVMCIObjectArray methods = JVMCIENV->new_ResolvedJavaMethod_array(0, JVMCI_CHECK_NULL); @@ -2192,7 +2192,7 @@ C2V_END C2V_VMENTRY_NULL(jobjectArray, getDeclaredMethods, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass))) Klass* klass = UNPACK_PAIR(Klass, klass); if (klass == nullptr) { - JVMCI_THROW_0(NullPointerException); + JVMCI_THROW_NULL(NullPointerException); } if (!klass->is_instance_klass()) { JVMCIObjectArray methods = JVMCIENV->new_ResolvedJavaMethod_array(0, JVMCI_CHECK_NULL); @@ -2219,7 +2219,7 @@ C2V_END C2V_VMENTRY_NULL(jobjectArray, getDeclaredFieldsInfo, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass))) Klass* klass = UNPACK_PAIR(Klass, klass); if (klass == nullptr) { - JVMCI_THROW_0(NullPointerException); + JVMCI_THROW_NULL(NullPointerException); } if (!klass->is_instance_klass()) { JVMCI_THROW_MSG_NULL(IllegalArgumentException, "not an InstanceKlass"); @@ -2346,7 +2346,7 @@ C2V_END C2V_VMENTRY_NULL(jobject, readFieldValue, (JNIEnv* env, jobject, jobject object, ARGUMENT_PAIR(expected_type), long displacement, jchar type_char)) if (object == nullptr) { - JVMCI_THROW_0(NullPointerException); + JVMCI_THROW_NULL(NullPointerException); } // asConstant will throw an NPE if a constant contains null @@ -2396,7 +2396,7 @@ C2V_END C2V_VMENTRY_NULL(jobject, asJavaType, (JNIEnv* env, jobject, jobject object)) if (object == nullptr) { - JVMCI_THROW_0(NullPointerException); + JVMCI_THROW_NULL(NullPointerException); } Handle obj = JVMCIENV->asConstant(JVMCIENV->wrap(object), JVMCI_CHECK_NULL); if (java_lang_Class::is_instance(obj())) { @@ -2416,7 +2416,7 @@ C2V_END C2V_VMENTRY_NULL(jobject, asString, (JNIEnv* env, jobject, jobject object)) if (object == nullptr) { - JVMCI_THROW_0(NullPointerException); + JVMCI_THROW_NULL(NullPointerException); } Handle obj = JVMCIENV->asConstant(JVMCIENV->wrap(object), JVMCI_CHECK_NULL); const char* str = java_lang_String::as_utf8_string(obj()); @@ -2435,7 +2435,7 @@ C2V_END C2V_VMENTRY_NULL(jobject, getJavaMirror, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass))) Klass* klass = UNPACK_PAIR(Klass, klass); if (klass == nullptr) { - JVMCI_THROW_0(NullPointerException); + JVMCI_THROW_NULL(NullPointerException); } Handle mirror(THREAD, klass->java_mirror()); JVMCIObject result = JVMCIENV->get_object_constant(mirror()); @@ -2457,7 +2457,7 @@ C2V_VMENTRY_0(jint, getArrayLength, (JNIEnv* env, jobject, jobject x)) C2V_VMENTRY_NULL(jobject, readArrayElement, (JNIEnv* env, jobject, jobject x, int index)) if (x == nullptr) { - JVMCI_THROW_0(NullPointerException); + JVMCI_THROW_NULL(NullPointerException); } Handle xobj = JVMCIENV->asConstant(JVMCIENV->wrap(x), JVMCI_CHECK_NULL); if (xobj->klass()->is_array_klass()) { @@ -2543,16 +2543,16 @@ C2V_VMENTRY_NULL(jlongArray, registerNativeMethods, (JNIEnv* env, jobject, jclas } sl_handle = JVMCI::get_shared_library(sl_path, false); if (sl_handle == nullptr) { - JVMCI_THROW_MSG_0(InternalError, err_msg("Error initializing JVMCI runtime %d", runtime->id())); + JVMCI_THROW_MSG_NULL(InternalError, err_msg("Error initializing JVMCI runtime %d", runtime->id())); } } if (mirror == nullptr) { - JVMCI_THROW_0(NullPointerException); + JVMCI_THROW_NULL(NullPointerException); } Klass* klass = java_lang_Class::as_Klass(JNIHandles::resolve(mirror)); if (klass == nullptr || !klass->is_instance_klass()) { - JVMCI_THROW_MSG_0(IllegalArgumentException, "clazz is for primitive type"); + JVMCI_THROW_MSG_NULL(IllegalArgumentException, "clazz is for primitive type"); } InstanceKlass* iklass = InstanceKlass::cast(klass); @@ -2587,14 +2587,14 @@ C2V_VMENTRY_NULL(jlongArray, registerNativeMethods, (JNIEnv* env, jobject, jclas char* jni_long_name = st.as_string(); entry = (address) os::dll_lookup(sl_handle, jni_long_name); if (entry == nullptr) { - JVMCI_THROW_MSG_0(UnsatisfiedLinkError, err_msg("%s [neither %s nor %s exist in %s]", + JVMCI_THROW_MSG_NULL(UnsatisfiedLinkError, err_msg("%s [neither %s nor %s exist in %s]", method->name_and_sig_as_C_string(), jni_name, jni_long_name, sl_path)); } } if (method->has_native_function() && entry != method->native_function()) { - JVMCI_THROW_MSG_0(UnsatisfiedLinkError, err_msg("%s [cannot re-link from " PTR_FORMAT " to " PTR_FORMAT "]", + JVMCI_THROW_MSG_NULL(UnsatisfiedLinkError, err_msg("%s [cannot re-link from " PTR_FORMAT " to " PTR_FORMAT "]", method->name_and_sig_as_C_string(), p2i(method->native_function()), p2i(entry))); } method->set_native_function(entry, Method::native_bind_event_is_interesting); @@ -2605,9 +2605,9 @@ C2V_VMENTRY_NULL(jlongArray, registerNativeMethods, (JNIEnv* env, jobject, jclas } } - typeArrayOop info_oop = oopFactory::new_longArray(4, CHECK_0); + typeArrayOop info_oop = oopFactory::new_longArray(4, CHECK_NULL); jlongArray info = (jlongArray) JNIHandles::make_local(THREAD, info_oop); - runtime->init_JavaVM_info(info, JVMCI_CHECK_0); + runtime->init_JavaVM_info(info, JVMCI_CHECK_NULL); return info; C2V_END @@ -3154,8 +3154,8 @@ C2V_VMENTRY_NULL(jobject, getThreadLocalObject, (JNIEnv* env, jobject, jint id)) if (id == 0) { return JNIHandles::make_local(thread->get_jvmci_reserved_oop0()); } - THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), - err_msg("%d is not a valid thread local id", id)); + THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), + err_msg("%d is not a valid thread local id", id)); C2V_END C2V_VMENTRY(void, setThreadLocalLong, (JNIEnv* env, jobject, jint id, jlong value)) From 8e682aca24fba0803dceef513957fb2122895b87 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Tue, 13 Aug 2024 18:03:52 +0000 Subject: [PATCH 292/353] 8338158: Cleanup ShouldNotXXX uses in machnode.cpp Reviewed-by: chagedorn, kvn, dlong --- src/hotspot/share/opto/machnode.cpp | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/hotspot/share/opto/machnode.cpp b/src/hotspot/share/opto/machnode.cpp index 39b804f7e5c96..e271637893b28 100644 --- a/src/hotspot/share/opto/machnode.cpp +++ b/src/hotspot/share/opto/machnode.cpp @@ -45,9 +45,9 @@ int MachOper::reg(PhaseRegAlloc *ra_, const Node *node, int idx) const { } intptr_t MachOper::constant() const { return 0x00; } relocInfo::relocType MachOper::constant_reloc() const { return relocInfo::none; } -jdouble MachOper::constantD() const { ShouldNotReachHere(); return 0.0; } -jfloat MachOper::constantF() const { ShouldNotReachHere(); return 0.0; } -jlong MachOper::constantL() const { ShouldNotReachHere(); return CONST64(0) ; } +jdouble MachOper::constantD() const { ShouldNotReachHere(); } +jfloat MachOper::constantF() const { ShouldNotReachHere(); } +jlong MachOper::constantL() const { ShouldNotReachHere(); } TypeOopPtr *MachOper::oop() const { return nullptr; } int MachOper::ccode() const { return 0x00; } // A zero, default, indicates this value is not needed. @@ -62,8 +62,8 @@ int MachOper::index_position() const { return -1; } // no index input // Check for PC-Relative displacement relocInfo::relocType MachOper::disp_reloc() const { return relocInfo::none; } // Return the label -Label* MachOper::label() const { ShouldNotReachHere(); return 0; } -intptr_t MachOper::method() const { ShouldNotReachHere(); return 0; } +Label* MachOper::label() const { ShouldNotReachHere(); } +intptr_t MachOper::method() const { ShouldNotReachHere(); } //------------------------------negate----------------------------------------- @@ -80,7 +80,6 @@ const Type *MachOper::type() const { //------------------------------in_RegMask------------------------------------- const RegMask *MachOper::in_RegMask(int index) const { ShouldNotReachHere(); - return nullptr; } //------------------------------dump_spec-------------------------------------- @@ -93,14 +92,12 @@ void MachOper::dump_spec(outputStream *st) const { } // Print any per-operand special info uint MachOper::hash() const { ShouldNotCallThis(); - return 5; } //------------------------------cmp-------------------------------------------- // Print any per-operand special info bool MachOper::cmp( const MachOper &oper ) const { ShouldNotCallThis(); - return opcode() == oper.opcode(); } //------------------------------hash------------------------------------------- @@ -207,7 +204,6 @@ void MachNode::fill_new_machnode(MachNode* node) const { // Return an equivalent instruction using memory for cisc_operand position MachNode *MachNode::cisc_version(int offset) { ShouldNotCallThis(); - return nullptr; } void MachNode::use_cisc_RegMask() { From 90527a57848f452be3be089a703cbc2af2d1657a Mon Sep 17 00:00:00 2001 From: Neethu Prasad Date: Tue, 13 Aug 2024 19:56:07 +0000 Subject: [PATCH 293/353] 8336742: Shenandoah: Add more verbose logging/stats for mark termination attempts Reviewed-by: shade, wkemper, rkennke --- .../gc/shenandoah/shenandoahConcurrentMark.cpp | 5 ++++- .../gc/shenandoah/shenandoahPhaseTimings.cpp | 16 ++++++++++------ .../gc/shenandoah/shenandoahPhaseTimings.hpp | 5 +++-- .../share/gc/shenandoah/shenandoahUtils.cpp | 6 +++--- .../share/gc/shenandoah/shenandoahUtils.hpp | 3 ++- 5 files changed, 22 insertions(+), 13 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp index dde446d824b77..6ed75a9d96106 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp @@ -206,7 +206,10 @@ void ShenandoahConcurrentMark::concurrent_mark() { } size_t before = qset.completed_buffers_num(); - Handshake::execute(&flush_satb); + { + ShenandoahTimingsTracker t(ShenandoahPhaseTimings::conc_mark_satb_flush, true); + Handshake::execute(&flush_satb); + } size_t after = qset.completed_buffers_num(); if (before == after) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.cpp b/src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.cpp index 738657ac6bda0..5e60cf923937f 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.cpp @@ -137,17 +137,21 @@ bool ShenandoahPhaseTimings::is_root_work_phase(Phase phase) { } } -void ShenandoahPhaseTimings::set_cycle_data(Phase phase, double time) { +void ShenandoahPhaseTimings::set_cycle_data(Phase phase, double time, bool should_aggregate) { + const double cycle_data = _cycle_data[phase]; + if (should_aggregate) { + _cycle_data[phase] = (cycle_data == uninitialized()) ? time : (cycle_data + time); + } else { #ifdef ASSERT - double d = _cycle_data[phase]; - assert(d == uninitialized(), "Should not be set yet: %s, current value: %lf", phase_name(phase), d); + assert(cycle_data == uninitialized(), "Should not be set yet: %s, current value: %lf", phase_name(phase), cycle_data); #endif - _cycle_data[phase] = time; + _cycle_data[phase] = time; + } } -void ShenandoahPhaseTimings::record_phase_time(Phase phase, double time) { +void ShenandoahPhaseTimings::record_phase_time(Phase phase, double time, bool should_aggregate) { if (!_policy->is_at_shutdown()) { - set_cycle_data(phase, time); + set_cycle_data(phase, time, should_aggregate); } } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.hpp b/src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.hpp index a6ca335a0d7de..01c83e08d37c2 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.hpp @@ -57,6 +57,7 @@ class outputStream; f(conc_mark_roots, "Concurrent Mark Roots ") \ SHENANDOAH_PAR_PHASE_DO(conc_mark_roots, " CMR: ", f) \ f(conc_mark, "Concurrent Marking") \ + f(conc_mark_satb_flush, " Flush SATB") \ \ f(final_mark_gross, "Pause Final Mark (G)") \ f(final_mark, "Pause Final Mark (N)") \ @@ -216,13 +217,13 @@ class ShenandoahPhaseTimings : public CHeapObj { ShenandoahWorkerData* worker_data(Phase phase, ParPhase par_phase); Phase worker_par_phase(Phase phase, ParPhase par_phase); - void set_cycle_data(Phase phase, double time); + void set_cycle_data(Phase phase, double time, bool should_aggregate = false); static double uninitialized() { return -1; } public: ShenandoahPhaseTimings(uint max_workers); - void record_phase_time(Phase phase, double time); + void record_phase_time(Phase phase, double time, bool should_aggregate = false); void record_workers_start(Phase phase); void record_workers_end(Phase phase); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahUtils.cpp b/src/hotspot/share/gc/shenandoah/shenandoahUtils.cpp index 64074a9672cca..ca56b06e79dc9 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahUtils.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahUtils.cpp @@ -111,8 +111,8 @@ ShenandoahConcurrentPhase::~ShenandoahConcurrentPhase() { _timer->register_gc_concurrent_end(); } -ShenandoahTimingsTracker::ShenandoahTimingsTracker(ShenandoahPhaseTimings::Phase phase) : - _timings(ShenandoahHeap::heap()->phase_timings()), _phase(phase) { +ShenandoahTimingsTracker::ShenandoahTimingsTracker(ShenandoahPhaseTimings::Phase phase, bool should_aggregate) : + _timings(ShenandoahHeap::heap()->phase_timings()), _phase(phase), _should_aggregate(should_aggregate) { assert(Thread::current()->is_VM_thread() || Thread::current()->is_ConcurrentGC_thread(), "Must be set by these threads"); _parent_phase = _current_phase; @@ -121,7 +121,7 @@ ShenandoahTimingsTracker::ShenandoahTimingsTracker(ShenandoahPhaseTimings::Phase } ShenandoahTimingsTracker::~ShenandoahTimingsTracker() { - _timings->record_phase_time(_phase, os::elapsedTime() - _start); + _timings->record_phase_time(_phase, os::elapsedTime() - _start, _should_aggregate); _current_phase = _parent_phase; } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahUtils.hpp b/src/hotspot/share/gc/shenandoah/shenandoahUtils.hpp index 15f0ee61407b1..ffa9d764d3c97 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahUtils.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahUtils.hpp @@ -64,11 +64,12 @@ class ShenandoahTimingsTracker : public StackObj { ShenandoahPhaseTimings* const _timings; const ShenandoahPhaseTimings::Phase _phase; + const bool _should_aggregate; ShenandoahPhaseTimings::Phase _parent_phase; double _start; public: - ShenandoahTimingsTracker(ShenandoahPhaseTimings::Phase phase); + ShenandoahTimingsTracker(ShenandoahPhaseTimings::Phase phase, bool should_aggregate = false); ~ShenandoahTimingsTracker(); static ShenandoahPhaseTimings::Phase current_phase() { return _current_phase; } From f132b347e13a57d9654f0ab11db0636999576036 Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Tue, 13 Aug 2024 22:59:13 +0000 Subject: [PATCH 294/353] 8336854: CAInterop.java#actalisauthenticationrootca conflicted with /manual and /timeout Reviewed-by: rhalade --- .../cert/CertPathValidator/certification/CAInterop.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/CAInterop.java b/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/CAInterop.java index 889926077a9fe..ab04391b1f385 100644 --- a/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/CAInterop.java +++ b/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/CAInterop.java @@ -25,14 +25,16 @@ * @test id=actalisauthenticationrootca * @bug 8189131 * @summary Interoperability tests with Actalis CA + * Before this test set to manual, the original timeout + * value if 180 * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop * @run main/othervm/manual -Djava.security.debug=certpath,ocsp * CAInterop actalisauthenticationrootca OCSP - * @run main/othervm/manual/timeout=180 -Djava.security.debug=certpath,ocsp + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp * -Dcom.sun.security.ocsp.useget=false * CAInterop actalisauthenticationrootca OCSP - * @run main/othervm/manual/timeout=180 -Djava.security.debug=certpath,ocsp + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp * CAInterop actalisauthenticationrootca CRL */ From 720b44648bcff997278af92746f942b2425298a5 Mon Sep 17 00:00:00 2001 From: Jaikiran Pai Date: Wed, 14 Aug 2024 05:42:14 +0000 Subject: [PATCH 295/353] 8335181: Incorrect handling of HTTP/2 GOAWAY frames in HttpClient Reviewed-by: dfuchs --- .../jdk/internal/net/http/ExchangeImpl.java | 15 +- .../internal/net/http/Http2Connection.java | 58 ++- .../jdk/internal/net/http/MultiExchange.java | 27 +- .../classes/jdk/internal/net/http/Stream.java | 67 +++- .../internal/net/http/WindowController.java | 13 +- .../internal/net/http/frame/GoAwayFrame.java | 6 +- .../net/httpclient/http2/H2GoAwayTest.java | 336 ++++++++++++++++++ .../test/lib/common/HttpServerAdapters.java | 30 +- .../test/lib/http2/Http2TestExchange.java | 8 +- .../test/lib/http2/Http2TestExchangeImpl.java | 5 + .../test/lib/http2/Http2TestServer.java | 14 +- .../lib/http2/Http2TestServerConnection.java | 102 +++++- 12 files changed, 625 insertions(+), 56 deletions(-) create mode 100644 test/jdk/java/net/httpclient/http2/H2GoAwayTest.java diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/ExchangeImpl.java b/src/java.net.http/share/classes/jdk/internal/net/http/ExchangeImpl.java index 854ea73cc3679..404f970cc59ef 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/ExchangeImpl.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/ExchangeImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -58,6 +58,10 @@ abstract class ExchangeImpl { final Exchange exchange; + // this will be set to true only when the peer explicitly states (through a GOAWAY frame or + // a relevant error code in reset frame) that the corresponding stream (id) wasn't processed + private volatile boolean unprocessedByPeer; + ExchangeImpl(Exchange e) { // e == null means a http/2 pushed stream this.exchange = e; @@ -265,4 +269,13 @@ void upgraded() { } // Called when server returns non 100 response to // an Expect-Continue void expectContinueFailed(int rcode) { } + + final boolean isUnprocessedByPeer() { + return this.unprocessedByPeer; + } + + // Marks the exchange as unprocessed by the peer + final void markUnprocessedByPeer() { + this.unprocessedByPeer = true; + } } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/Http2Connection.java b/src/java.net.http/share/classes/jdk/internal/net/http/Http2Connection.java index 3321ffdfce0a7..9457ff6998832 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/Http2Connection.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/Http2Connection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,6 +47,8 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.Flow; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import java.util.function.Function; @@ -358,6 +360,7 @@ private record PushContinuationState(HeaderDecoder pushContDecoder, PushPromiseF private final String key; // for HttpClientImpl.connections map private final FramesDecoder framesDecoder; private final FramesEncoder framesEncoder = new FramesEncoder(); + private final AtomicLong lastProcessedStreamInGoAway = new AtomicLong(-1); /** * Send Window controller for both connection and stream windows. @@ -725,7 +728,9 @@ final int maxConcurrentServerInitiatedStreams() { void close() { if (markHalfClosedLocal()) { - if (connection.channel().isOpen()) { + // we send a GOAWAY frame only if the remote side hasn't already indicated + // the intention to close the connection by previously sending a GOAWAY of its own + if (connection.channel().isOpen() && !isMarked(closedState, HALF_CLOSED_REMOTE)) { Log.logTrace("Closing HTTP/2 connection: to {0}", connection.address()); GoAwayFrame f = new GoAwayFrame(0, ErrorFrame.NO_ERROR, @@ -1205,13 +1210,46 @@ private void handlePing(PingFrame frame) sendUnorderedFrame(frame); } - private void handleGoAway(GoAwayFrame frame) - throws IOException - { - if (markHalfClosedLRemote()) { - shutdown(new IOException( - connection.channel().getLocalAddress() - + ": GOAWAY received")); + private void handleGoAway(final GoAwayFrame frame) { + final long lastProcessedStream = frame.getLastStream(); + assert lastProcessedStream >= 0 : "unexpected last stream id: " + + lastProcessedStream + " in GOAWAY frame"; + + markHalfClosedRemote(); + setFinalStream(); // don't allow any new streams on this connection + if (debug.on()) { + debug.log("processing incoming GOAWAY with last processed stream id:%s in frame %s", + lastProcessedStream, frame); + } + // see if this connection has previously received a GOAWAY from the peer and if yes + // then check if this new last processed stream id is lesser than the previous + // known last processed stream id. Only update the last processed stream id if the new + // one is lesser than the previous one. + long prevLastProcessed = lastProcessedStreamInGoAway.get(); + while (prevLastProcessed == -1 || lastProcessedStream < prevLastProcessed) { + if (lastProcessedStreamInGoAway.compareAndSet(prevLastProcessed, + lastProcessedStream)) { + break; + } + prevLastProcessed = lastProcessedStreamInGoAway.get(); + } + handlePeerUnprocessedStreams(lastProcessedStreamInGoAway.get()); + } + + private void handlePeerUnprocessedStreams(final long lastProcessedStream) { + final AtomicInteger numClosed = new AtomicInteger(); // atomic merely to allow usage within lambda + streams.forEach((id, exchange) -> { + if (id > lastProcessedStream) { + // any streams with an stream id higher than the last processed stream + // can be retried (on a new connection). we close the exchange as unprocessed + // to facilitate the retrying. + client2.client().theExecutor().ensureExecutedAsync(exchange::closeAsUnprocessed); + numClosed.incrementAndGet(); + } + }); + if (debug.on()) { + debug.log(numClosed.get() + " stream(s), with id greater than " + lastProcessedStream + + ", will be closed as unprocessed"); } } @@ -1745,7 +1783,7 @@ private boolean markHalfClosedLocal() { return markClosedState(HALF_CLOSED_LOCAL); } - private boolean markHalfClosedLRemote() { + private boolean markHalfClosedRemote() { return markClosedState(HALF_CLOSED_REMOTE); } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/MultiExchange.java b/src/java.net.http/share/classes/jdk/internal/net/http/MultiExchange.java index d6d03a9aa8af9..2c15a704ef978 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/MultiExchange.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/MultiExchange.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -90,7 +90,7 @@ class MultiExchange implements Cancelable { Exchange exchange; // the current exchange Exchange previous; volatile Throwable retryCause; - volatile boolean expiredOnce; + volatile boolean retriedOnce; volatile HttpResponse response; // Maximum number of times a request will be retried/redirected @@ -469,7 +469,7 @@ private CompletableFuture responseAsyncImpl() { return exch.ignoreBody().handle((r,t) -> { previousreq = currentreq; currentreq = newrequest; - expiredOnce = false; + retriedOnce = false; setExchange(new Exchange<>(currentreq, this, acc)); return responseAsyncImpl(); }).thenCompose(Function.identity()); @@ -482,7 +482,7 @@ private CompletableFuture responseAsyncImpl() { return completedFuture(response); } // all exceptions thrown are handled here - CompletableFuture errorCF = getExceptionalCF(ex); + CompletableFuture errorCF = getExceptionalCF(ex, exch.exchImpl); if (errorCF == null) { return responseAsyncImpl(); } else { @@ -554,36 +554,39 @@ private Throwable retryCause(Throwable t) { * Takes a Throwable and returns a suitable CompletableFuture that is * completed exceptionally, or null. */ - private CompletableFuture getExceptionalCF(Throwable t) { + private CompletableFuture getExceptionalCF(Throwable t, ExchangeImpl exchImpl) { if ((t instanceof CompletionException) || (t instanceof ExecutionException)) { if (t.getCause() != null) { t = t.getCause(); } } + final boolean retryAsUnprocessed = exchImpl != null && exchImpl.isUnprocessedByPeer(); if (cancelled && !requestCancelled() && t instanceof IOException) { if (!(t instanceof HttpTimeoutException)) { t = toTimeoutException((IOException)t); } - } else if (retryOnFailure(t)) { + } else if (retryAsUnprocessed || retryOnFailure(t)) { Throwable cause = retryCause(t); if (!(t instanceof ConnectException)) { // we may need to start a new connection, and if so // we want to start with a fresh connect timeout again. if (connectTimeout != null) connectTimeout.reset(); - if (!canRetryRequest(currentreq)) { - return failedFuture(cause); // fails with original cause + if (!retryAsUnprocessed && !canRetryRequest(currentreq)) { + // a (peer) processed request which cannot be retried, fail with + // the original cause + return failedFuture(cause); } } // ConnectException: retry, but don't reset the connectTimeout. // allow the retry mechanism to do its work retryCause = cause; - if (!expiredOnce) { + if (!retriedOnce) { if (debug.on()) { debug.log(t.getClass().getSimpleName() - + " (async): retrying due to: ", t); + + " (async): retrying " + currentreq + " due to: ", t); } - expiredOnce = true; + retriedOnce = true; // The connection was abruptly closed. // We return null to retry the same request a second time. // The request filters have already been applied to the @@ -594,7 +597,7 @@ private CompletableFuture getExceptionalCF(Throwable t) { } else { if (debug.on()) { debug.log(t.getClass().getSimpleName() - + " (async): already retried once.", t); + + " (async): already retried once " + currentreq, t); } t = cause; } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/Stream.java b/src/java.net.http/share/classes/jdk/internal/net/http/Stream.java index 1bb520a6fb13b..1a007e82adcdc 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/Stream.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/Stream.java @@ -641,20 +641,39 @@ void handleReset(ResetFrame frame, Flow.Subscriber subscriber) { stateLock.unlock(); } try { - int error = frame.getErrorCode(); - IOException e = new IOException("Received RST_STREAM: " - + ErrorFrame.stringForCode(error)); - if (errorRef.compareAndSet(null, e)) { - if (subscriber != null) { - subscriber.onError(e); + final int error = frame.getErrorCode(); + // A REFUSED_STREAM error code implies that the stream wasn't processed by the + // peer and the client is free to retry the request afresh. + if (error == ErrorFrame.REFUSED_STREAM) { + // Here we arrange for the request to be retried. Note that we don't call + // closeAsUnprocessed() method here because the "closed" state is already set + // to true a few lines above and calling close() from within + // closeAsUnprocessed() will end up being a no-op. We instead do the additional + // bookkeeping here. + markUnprocessedByPeer(); + errorRef.compareAndSet(null, new IOException("request not processed by peer")); + if (debug.on()) { + debug.log("request unprocessed by peer (REFUSED_STREAM) " + this.request); + } + } else { + final String reason = ErrorFrame.stringForCode(error); + final IOException failureCause = new IOException("Received RST_STREAM: " + reason); + if (debug.on()) { + debug.log(streamid + " received RST_STREAM with code: " + reason); + } + if (errorRef.compareAndSet(null, failureCause)) { + if (subscriber != null) { + subscriber.onError(failureCause); + } } } - completeResponseExceptionally(e); + final Throwable failureCause = errorRef.get(); + completeResponseExceptionally(failureCause); if (!requestBodyCF.isDone()) { - requestBodyCF.completeExceptionally(errorRef.get()); // we may be sending the body.. + requestBodyCF.completeExceptionally(failureCause); // we may be sending the body.. } if (responseBodyCF != null) { - responseBodyCF.completeExceptionally(errorRef.get()); + responseBodyCF.completeExceptionally(failureCause); } } finally { connection.decrementStreamsCount(streamid); @@ -1663,7 +1682,35 @@ Throwable getCancelCause() { } final String dbgString() { - return connection.dbgString() + "/Stream("+streamid+")"; + final int id = streamid; + final String sid = id == 0 ? "?" : String.valueOf(id); + return connection.dbgString() + "/Stream(" + sid + ")"; + } + + /** + * An unprocessed exchange is one that hasn't been processed by a peer. The local end of the + * connection would be notified about such exchanges when it receives a GOAWAY frame with + * a stream id that tells which exchanges have been unprocessed. + * This method is called on such unprocessed exchanges and the implementation of this method + * will arrange for the request, corresponding to this exchange, to be retried afresh on a + * new connection. + */ + void closeAsUnprocessed() { + try { + // We arrange for the request to be retried on a new connection as allowed by the RFC-9113 + markUnprocessedByPeer(); + this.errorRef.compareAndSet(null, new IOException("request not processed by peer")); + if (debug.on()) { + debug.log("closing " + this.request + " as unprocessed by peer"); + } + // close the exchange and complete the response CF exceptionally + close(); + completeResponseExceptionally(this.errorRef.get()); + } finally { + // decrementStreamsCount isn't really needed but we do it to make sure + // the log messages, where these counts/states get reported, show the accurate state. + connection.decrementStreamsCount(streamid); + } } private class HeadersConsumer extends ValidatingHeadersConsumer { diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/WindowController.java b/src/java.net.http/share/classes/jdk/internal/net/http/WindowController.java index 1df81640345fa..a30c21a7a7d0d 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/WindowController.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/WindowController.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -100,13 +100,16 @@ void removeStream(int streamid) { controllerLock.lock(); try { Integer old = streams.remove(streamid); - // Odd stream numbers (client streams) should have been registered. + // A client initiated stream might be closed (as unprocessed, due to a + // GOAWAY received on the connection) even before the stream is + // registered with this WindowController instance (when sending out request headers). + // Thus, for client initiated streams, we don't enforce the presence of the + // stream in the registered "streams" map. + // Even stream numbers (server streams - aka Push Streams) should // not be registered final boolean isClientStream = (streamid & 0x1) == 1; - if (old == null && isClientStream) { - throw new InternalError("Expected entry for streamid: " + streamid); - } else if (old != null && !isClientStream) { + if (old != null && !isClientStream) { throw new InternalError("Unexpected entry for streamid: " + streamid); } } finally { diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/frame/GoAwayFrame.java b/src/java.net.http/share/classes/jdk/internal/net/http/frame/GoAwayFrame.java index 45ec7553f5afd..662e5dd98b301 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/frame/GoAwayFrame.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/frame/GoAwayFrame.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -57,7 +57,9 @@ int length() { @Override public String toString() { - return super.toString() + " Debugdata: " + new String(debugData, UTF_8); + return super.toString() + + " lastStreamId=" + lastStream + + ", Debugdata: " + new String(debugData, UTF_8); } public int getLastStream() { diff --git a/test/jdk/java/net/httpclient/http2/H2GoAwayTest.java b/test/jdk/java/net/httpclient/http2/H2GoAwayTest.java new file mode 100644 index 0000000000000..755bb2e16cc11 --- /dev/null +++ b/test/jdk/java/net/httpclient/http2/H2GoAwayTest.java @@ -0,0 +1,336 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.IOException; +import java.io.OutputStream; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.net.http.HttpResponse.BodyHandlers; +import java.util.ArrayList; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.atomic.AtomicInteger; + +import javax.net.ssl.SSLContext; + +import jdk.httpclient.test.lib.common.HttpServerAdapters.HttpTestExchange; +import jdk.httpclient.test.lib.common.HttpServerAdapters.HttpTestHandler; +import jdk.httpclient.test.lib.common.HttpServerAdapters.HttpTestServer; +import jdk.test.lib.net.SimpleSSLContext; +import jdk.test.lib.net.URIBuilder; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import static java.net.http.HttpClient.Version.HTTP_2; +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.fail; + +/* + * @test + * @bug 8335181 + * @summary verify that the HttpClient correctly handles incoming GOAWAY frames and + * retries any unprocessed requests on a new connection + * @library /test/lib /test/jdk/java/net/httpclient/lib + * @build jdk.httpclient.test.lib.common.HttpServerAdapters + * jdk.test.lib.net.SimpleSSLContext + * @run junit H2GoAwayTest + */ +public class H2GoAwayTest { + private static final String REQ_PATH = "/test"; + private static HttpTestServer server; + private static String REQ_URI_BASE; + private static SSLContext sslCtx; + + @BeforeAll + static void beforeAll() throws Exception { + sslCtx = new SimpleSSLContext().get(); + assertNotNull(sslCtx, "SSLContext couldn't be created"); + server = HttpTestServer.create(HTTP_2, sslCtx); + server.addHandler(new Handler(), REQ_PATH); + server.start(); + System.out.println("Server started at " + server.getAddress()); + REQ_URI_BASE = URIBuilder.newBuilder().scheme("https") + .loopback() + .port(server.getAddress().getPort()) + .path(REQ_PATH) + .build().toString(); + } + + @AfterAll + static void afterAll() { + if (server != null) { + System.out.println("Stopping server at " + server.getAddress()); + server.stop(); + } + } + + /** + * Verifies that when several requests are sent using send() and the server + * connection is configured to send a GOAWAY after processing only a few requests, then + * the remaining requests are retried on a different connection + */ + @Test + public void testSequential() throws Exception { + final LimitedPerConnRequestApprover reqApprover = new LimitedPerConnRequestApprover(); + server.setRequestApprover(reqApprover::allowNewRequest); + try (final HttpClient client = HttpClient.newBuilder().version(HTTP_2) + .sslContext(sslCtx).build()) { + final String[] reqMethods = {"HEAD", "GET", "POST"}; + for (final String reqMethod : reqMethods) { + final int numReqs = LimitedPerConnRequestApprover.MAX_REQS_PER_CONN + 3; + final Set connectionKeys = new LinkedHashSet<>(); + for (int i = 1; i <= numReqs; i++) { + final URI reqURI = new URI(REQ_URI_BASE + "?seq&" + reqMethod + "=" + i); + final HttpRequest req = HttpRequest.newBuilder() + .uri(reqURI) + .method(reqMethod, HttpRequest.BodyPublishers.noBody()) + .build(); + System.out.println("initiating request " + req); + final HttpResponse resp = client.send(req, BodyHandlers.ofString()); + final String respBody = resp.body(); + System.out.println("received response: " + respBody); + assertEquals(200, resp.statusCode(), + "unexpected status code for request " + resp.request()); + // response body is the logical key of the connection on which the + // request was handled + connectionKeys.add(respBody); + } + System.out.println("connections involved in handling the requests: " + + connectionKeys); + // all requests have finished, we now just do a basic check that + // more than one connection was involved in processing these requests + assertEquals(2, connectionKeys.size(), + "unexpected number of connections " + connectionKeys); + } + } finally { + server.setRequestApprover(null); // reset + } + } + + /** + * Verifies that when a server responds with a GOAWAY and then never processes the new retried + * requests on a new connection too, then the application code receives the request failure. + * This tests the send() API of the HttpClient. + */ + @Test + public void testUnprocessedRaisesException() throws Exception { + try (final HttpClient client = HttpClient.newBuilder().version(HTTP_2) + .sslContext(sslCtx).build()) { + final Random random = new Random(); + final String[] reqMethods = {"HEAD", "GET", "POST"}; + for (final String reqMethod : reqMethods) { + final int maxAllowedReqs = 2; + final int numReqs = maxAllowedReqs + 3; // 3 more requests than max allowed + // configure the approver + final LimitedRequestApprover reqApprover = new LimitedRequestApprover(maxAllowedReqs); + server.setRequestApprover(reqApprover::allowNewRequest); + try { + int numSuccess = 0; + int numFailed = 0; + for (int i = 1; i <= numReqs; i++) { + final String reqQueryPart = "?sync&" + reqMethod + "=" + i; + final URI reqURI = new URI(REQ_URI_BASE + reqQueryPart); + final HttpRequest req = HttpRequest.newBuilder() + .uri(reqURI) + .method(reqMethod, HttpRequest.BodyPublishers.noBody()) + .build(); + System.out.println("initiating request " + req); + if (i <= maxAllowedReqs) { + // expected to successfully complete + numSuccess++; + final HttpResponse resp = client.send(req, BodyHandlers.ofString()); + final String respBody = resp.body(); + System.out.println("received response: " + respBody); + assertEquals(200, resp.statusCode(), + "unexpected status code for request " + resp.request()); + } else { + // expected to fail as unprocessed + try { + final HttpResponse resp = client.send(req, BodyHandlers.ofString()); + fail("Request was expected to fail as unprocessed," + + " but got response: " + resp.body() + ", status code: " + + resp.statusCode()); + } catch (IOException ioe) { + // verify it failed for the right reason + if (ioe.getMessage() == null + || !ioe.getMessage().contains("request not processed by peer")) { + // propagate the original failure + throw ioe; + } + numFailed++; // failed due to right reason + System.out.println("received expected failure: " + ioe + + ", for request " + reqURI); + } + } + } + // verify the correct number of requests succeeded/failed + assertEquals(maxAllowedReqs, numSuccess, "unexpected number of requests succeeded"); + assertEquals((numReqs - maxAllowedReqs), numFailed, "unexpected number of requests failed"); + } finally { + server.setRequestApprover(null); // reset + } + } + } + } + + /** + * Verifies that when a server responds with a GOAWAY and then never processes the new retried + * requests on a new connection too, then the application code receives the request failure. + * This tests the sendAsync() API of the HttpClient. + */ + @Test + public void testUnprocessedRaisesExceptionAsync() throws Throwable { + try (final HttpClient client = HttpClient.newBuilder().version(HTTP_2) + .sslContext(sslCtx).build()) { + final Random random = new Random(); + final String[] reqMethods = {"HEAD", "GET", "POST"}; + for (final String reqMethod : reqMethods) { + final int maxAllowedReqs = 2; + final int numReqs = maxAllowedReqs + 3; // 3 more requests than max allowed + // configure the approver + final LimitedRequestApprover reqApprover = new LimitedRequestApprover(maxAllowedReqs); + server.setRequestApprover(reqApprover::allowNewRequest); + try { + final List>> futures = new ArrayList<>(); + for (int i = 1; i <= numReqs; i++) { + final URI reqURI = new URI(REQ_URI_BASE + "?async&" + reqMethod + "=" + i); + final HttpRequest req = HttpRequest.newBuilder() + .uri(reqURI) + .method(reqMethod, HttpRequest.BodyPublishers.noBody()) + .build(); + System.out.println("initiating request " + req); + final Future> f = client.sendAsync(req, BodyHandlers.ofString()); + futures.add(f); + } + // wait for responses + int numFailed = 0; + int numSuccess = 0; + for (int i = 1; i <= numReqs; i++) { + final String reqQueryPart = "?async&" + reqMethod + "=" + i; + try { + System.out.println("waiting response of request " + + REQ_URI_BASE + reqQueryPart); + final HttpResponse resp = futures.get(i - 1).get(); + numSuccess++; + final String respBody = resp.body(); + System.out.println("request: " + resp.request() + + ", received response: " + respBody); + assertEquals(200, resp.statusCode(), + "unexpected status code for request " + resp.request()); + } catch (ExecutionException ee) { + final Throwable cause = ee.getCause(); + if (!(cause instanceof IOException ioe)) { + throw cause; + } + // verify it failed for the right reason + if (ioe.getMessage() == null + || !ioe.getMessage().contains("request not processed by peer")) { + // propagate the original failure + throw ioe; + } + numFailed++; // failed due to the right reason + System.out.println("received expected failure: " + ioe + + ", for request " + REQ_URI_BASE + reqQueryPart); + } + } + // verify the correct number of requests succeeded/failed + assertEquals(maxAllowedReqs, numSuccess, "unexpected number of requests succeeded"); + assertEquals((numReqs - maxAllowedReqs), numFailed, "unexpected number of requests failed"); + } finally { + server.setRequestApprover(null); // reset + } + } + } + } + + // only allows fixed number of requests, irrespective of which server connection handles + // it. requests that are rejected will either be sent a GOAWAY on the connection + // or a RST_FRAME with a REFUSED_STREAM on the stream + private static final class LimitedRequestApprover { + private final int maxAllowedReqs; + private final AtomicInteger numApproved = new AtomicInteger(); + + private LimitedRequestApprover(final int maxAllowedReqs) { + this.maxAllowedReqs = maxAllowedReqs; + } + + public boolean allowNewRequest(final String serverConnKey) { + final int approved = numApproved.incrementAndGet(); + return approved <= maxAllowedReqs; + } + } + + // allows a certain number of requests per server connection. + // requests that are rejected will either be sent a GOAWAY on the connection + // or a RST_FRAME with a REFUSED_STREAM on the stream + private static final class LimitedPerConnRequestApprover { + private static final int MAX_REQS_PER_CONN = 6; + private final Map numApproved = + new ConcurrentHashMap<>(); + private final Map numDisapproved = + new ConcurrentHashMap<>(); + + public boolean allowNewRequest(final String serverConnKey) { + final AtomicInteger approved = numApproved.computeIfAbsent(serverConnKey, + (k) -> new AtomicInteger()); + int curr = approved.get(); + while (curr < MAX_REQS_PER_CONN) { + if (approved.compareAndSet(curr, curr + 1)) { + return true; // new request allowed + } + curr = approved.get(); + } + final AtomicInteger disapproved = numDisapproved.computeIfAbsent(serverConnKey, + (k) -> new AtomicInteger()); + final int numUnprocessed = disapproved.incrementAndGet(); + System.out.println(approved.get() + " processed, " + + numUnprocessed + " unprocessed requests on connection " + serverConnKey); + return false; + } + } + + private static final class Handler implements HttpTestHandler { + + @Override + public void handle(final HttpTestExchange exchange) throws IOException { + final String connectionKey = exchange.getConnectionKey(); + System.out.println("responding to request: " + exchange.getRequestURI() + + " on connection " + connectionKey); + final byte[] response = connectionKey.getBytes(UTF_8); + exchange.sendResponseHeaders(200, response.length); + try (final OutputStream os = exchange.getResponseBody()) { + os.write(response); + } + } + } +} diff --git a/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/common/HttpServerAdapters.java b/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/common/HttpServerAdapters.java index e18dd87a50753..36498684a9a95 100644 --- a/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/common/HttpServerAdapters.java +++ b/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/common/HttpServerAdapters.java @@ -58,6 +58,7 @@ import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.ExecutorService; +import java.util.function.Predicate; import java.util.logging.Level; import java.util.logging.Logger; import java.util.stream.Collectors; @@ -239,6 +240,7 @@ public static abstract class HttpTestExchange implements AutoCloseable { public abstract String getRequestMethod(); public abstract void close(); public abstract InetSocketAddress getRemoteAddress(); + public abstract String getConnectionKey(); public void serverPush(URI uri, HttpHeaders headers, byte[] body) { ByteArrayInputStream bais = new ByteArrayInputStream(body); serverPush(uri, headers, bais); @@ -253,7 +255,7 @@ public static HttpTestExchange of(HttpExchange exchange) { return new Http1TestExchange(exchange); } public static HttpTestExchange of(Http2TestExchange exchange) { - return new Http2TestExchangeImpl(exchange); + return new H2ExchangeImpl(exchange); } abstract void doFilter(Filter.Chain chain) throws IOException; @@ -306,15 +308,21 @@ public InetSocketAddress getRemoteAddress() { public URI getRequestURI() { return exchange.getRequestURI(); } @Override public String getRequestMethod() { return exchange.getRequestMethod(); } + + @Override + public String getConnectionKey() { + return exchange.getLocalAddress() + "->" + exchange.getRemoteAddress(); + } + @Override public String toString() { return this.getClass().getSimpleName() + ": " + exchange.toString(); } } - private static final class Http2TestExchangeImpl extends HttpTestExchange { + private static final class H2ExchangeImpl extends HttpTestExchange { private final Http2TestExchange exchange; - Http2TestExchangeImpl(Http2TestExchange exch) { + H2ExchangeImpl(Http2TestExchange exch) { this.exchange = exch; } @Override @@ -363,6 +371,11 @@ public InetSocketAddress getRemoteAddress() { return exchange.getRemoteAddress(); } + @Override + public String getConnectionKey() { + return exchange.getConnectionKey(); + } + @Override public URI getRequestURI() { return exchange.getRequestURI(); } @Override @@ -708,6 +721,7 @@ static void enableLogging() { public abstract HttpTestContext addHandler(HttpTestHandler handler, String root); public abstract InetSocketAddress getAddress(); public abstract Version getVersion(); + public abstract void setRequestApprover(final Predicate approver); public String serverAuthority() { InetSocketAddress address = getAddress(); @@ -856,6 +870,11 @@ public InetSocketAddress getAddress() { impl.getAddress().getPort()); } public Version getVersion() { return Version.HTTP_1_1; } + + @Override + public void setRequestApprover(final Predicate approver) { + throw new UnsupportedOperationException("not supported"); + } } private static class Http1TestContext extends HttpTestContext { @@ -907,6 +926,11 @@ public InetSocketAddress getAddress() { impl.getAddress().getPort()); } public Version getVersion() { return Version.HTTP_2; } + + @Override + public void setRequestApprover(final Predicate approver) { + this.impl.setRequestApprover(approver); + } } private static class Http2TestContext diff --git a/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestExchange.java b/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestExchange.java index 208a8d54e0848..d982349dac500 100644 --- a/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestExchange.java +++ b/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestExchange.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -71,4 +71,10 @@ public interface Http2TestExchange { * It may also complete exceptionally */ CompletableFuture sendPing(); + + /** + * {@return the identification of the connection on which this exchange is being + * processed} + */ + String getConnectionKey(); } diff --git a/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestExchangeImpl.java b/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestExchangeImpl.java index 63a4de6ef9059..d25019f9094c0 100644 --- a/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestExchangeImpl.java +++ b/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestExchangeImpl.java @@ -220,6 +220,11 @@ public void serverPush(URI uri, HttpHeaders headers, InputStream content) { } } + @Override + public String getConnectionKey() { + return conn.connectionKey(); + } + private boolean isHeadRequest() { return HEAD.equalsIgnoreCase(getRequestMethod()); } diff --git a/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestServer.java b/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestServer.java index ffa05d5c11c3b..ca7e7d3dc3007 100644 --- a/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestServer.java +++ b/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestServer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,8 @@ import java.util.concurrent.ThreadFactory; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Predicate; + import javax.net.ServerSocketFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLParameters; @@ -59,6 +61,8 @@ public class Http2TestServer implements AutoCloseable { final Set connections; final Properties properties; final String name; + // request approver which takes the server connection key as the input + private volatile Predicate newRequestApprover; private static ThreadFactory defaultThreadFac = (Runnable r) -> { @@ -285,6 +289,14 @@ public String serverName() { return serverName; } + public void setRequestApprover(final Predicate approver) { + this.newRequestApprover = approver; + } + + Predicate getRequestApprover() { + return this.newRequestApprover; + } + private synchronized void putConnection(InetSocketAddress addr, Http2TestServerConnection c) { if (!stopping) connections.add(c); diff --git a/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestServerConnection.java b/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestServerConnection.java index ff10d4087e932..1aeeee60b197e 100644 --- a/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestServerConnection.java +++ b/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestServerConnection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -75,13 +75,18 @@ import java.util.Optional; import java.util.Properties; import java.util.Random; +import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ExecutorService; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.BiPredicate; import java.util.function.Consumer; +import java.util.function.Predicate; import static java.nio.charset.StandardCharsets.ISO_8859_1; import static java.nio.charset.StandardCharsets.UTF_8; +import static jdk.internal.net.http.frame.ErrorFrame.REFUSED_STREAM; import static jdk.internal.net.http.frame.SettingsFrame.HEADER_TABLE_SIZE; /** @@ -110,6 +115,10 @@ public class Http2TestServerConnection { volatile boolean stopping; volatile int nextPushStreamId = 2; ConcurrentLinkedQueue pings = new ConcurrentLinkedQueue<>(); + // the max stream id of a processed H2 request. -1 implies none were processed. + private final AtomicInteger maxProcessedRequestStreamId = new AtomicInteger(-1); + // the stream id that was sent in a GOAWAY frame. -1 implies no GOAWAY frame was sent. + private final AtomicInteger goAwayRequestStreamId = new AtomicInteger(-1); final static ByteBuffer EMPTY_BUFFER = ByteBuffer.allocate(0); final static byte[] EMPTY_BARRAY = new byte[0]; @@ -234,11 +243,29 @@ CompletableFuture sendPing() { return ping.response(); } - void goAway(int error) throws IOException { - int laststream = nextstream >= 3 ? nextstream - 2 : 1; - - GoAwayFrame go = new GoAwayFrame(laststream, error); - outputQ.put(go); + private void sendGoAway(final int error) throws IOException { + int maxProcessedStreamId = maxProcessedRequestStreamId.get(); + if (maxProcessedStreamId == -1) { + maxProcessedStreamId = 0; + } + boolean send = false; + int currentGoAwayReqStrmId = goAwayRequestStreamId.get(); + // update the last processed stream id and send a goaway frame if the new last processed + // stream id is lesser than the last processed stream id sent in + // a previous goaway frame (if any) + while (currentGoAwayReqStrmId == -1 || maxProcessedStreamId < currentGoAwayReqStrmId) { + if (goAwayRequestStreamId.compareAndSet(currentGoAwayReqStrmId, maxProcessedStreamId)) { + send = true; + break; + } + currentGoAwayReqStrmId = goAwayRequestStreamId.get(); + } + if (!send) { + return; + } + final GoAwayFrame frame = new GoAwayFrame(maxProcessedStreamId, error); + outputQ.put(frame); + System.err.println("Sending GOAWAY frame " + frame + " from server connection " + this); } /** @@ -331,8 +358,9 @@ void close(int error) { q.orderlyClose(); }); try { - if (error != -1) - goAway(error); + if (error != -1) { + sendGoAway(error); + } outputQ.orderlyClose(); socket.close(); } catch (Exception e) { @@ -612,6 +640,14 @@ void createPrimordialStream(Http1InitialRequest request) throws IOException { path = path + "?" + uri.getRawQuery(); headersBuilder.setHeader(":path", path); + // skip processing the request if configured to do so + final String connKey = connectionKey(); + if (!shouldProcessNewHTTPRequest(connKey)) { + System.err.println("Rejecting primordial stream 1 and sending GOAWAY" + + " on server connection " + connKey + ", for request: " + path); + sendGoAway(ErrorFrame.NO_ERROR); + return; + } Queue q = new Queue(sentinel); byte[] body = getRequestBody(request); addHeaders(getHeaders(request.headers), headersBuilder); @@ -620,11 +656,24 @@ void createPrimordialStream(Http1InitialRequest request) throws IOException { addRequestBodyToQueue(body, q); streams.put(1, q); + maxProcessedRequestStreamId.set(1); exec.submit(() -> { handleRequest(headers, q, 1, true /*complete request has been read*/); }); } + private boolean shouldProcessNewHTTPRequest(final String serverConnKey) { + final Predicate approver = this.server.getRequestApprover(); + if (approver == null) { + return true; // process the request + } + return approver.test(serverConnKey); + } + + final String connectionKey() { + return this.server.getAddress() + "->" + this.socket.getRemoteSocketAddress(); + } + // all other streams created here @SuppressWarnings({"rawtypes","unchecked"}) void createStream(HeaderFrame frame) throws IOException { @@ -632,7 +681,7 @@ void createStream(HeaderFrame frame) throws IOException { frames.add(frame); int streamid = frame.streamid(); if (streamid != nextstream) { - throw new IOException("unexpected stream id"); + throw new IOException("unexpected stream id: " + streamid); } nextstream += 2; @@ -663,12 +712,30 @@ void createStream(HeaderFrame frame) throws IOException { throw new IOException("Unexpected Upgrade in headers:" + headers); } disallowedHeader = headers.firstValue("HTTP2-Settings"); - if (disallowedHeader.isPresent()) + if (disallowedHeader.isPresent()) { throw new IOException("Unexpected HTTP2-Settings in headers:" + headers); + } - + // skip processing the request if the server is configured to do so + final String connKey = connectionKey(); + final String path = headers.firstValue(":path").orElse(""); + if (!shouldProcessNewHTTPRequest(connKey)) { + System.err.println("Rejecting stream " + streamid + + " and sending GOAWAY on server connection " + + connKey + ", for request: " + path); + sendGoAway(ErrorFrame.NO_ERROR); + return; + } Queue q = new Queue(sentinel); streams.put(streamid, q); + // keep track of the largest request id that we have processed + int currentLargest = maxProcessedRequestStreamId.get(); + while (streamid > currentLargest) { + if (maxProcessedRequestStreamId.compareAndSet(currentLargest, streamid)) { + break; + } + currentLargest = maxProcessedRequestStreamId.get(); + } exec.submit(() -> { handleRequest(headers, q, streamid, endStreamReceived); }); @@ -763,6 +830,8 @@ void readLoop() { while (!stopping) { Http2Frame frame = readFrameImpl(); if (frame == null) { + System.err.println("EOF reached on connection " + connectionKey() + + ", will no longer accept incoming frames"); closeIncoming(); return; } @@ -786,6 +855,17 @@ void readLoop() { // TODO: close connection continue; } else { + final int streamId = frame.streamid(); + final int finalProcessedStreamId = goAwayRequestStreamId.get(); + // if we already sent a goaway, then don't create new streams with + // higher stream ids. + if (finalProcessedStreamId != -1 && streamId > finalProcessedStreamId) { + System.err.println(connectionKey() + " resetting stream " + streamId + + " as REFUSED_STREAM"); + final ResetFrame rst = new ResetFrame(streamId, REFUSED_STREAM); + outputQ.put(rst); + continue; + } createStream((HeadersFrame) frame); } } else { From 3dd07b91bbf644aa867452806e9388089fa97548 Mon Sep 17 00:00:00 2001 From: Qizheng Xing Date: Wed, 14 Aug 2024 06:28:34 +0000 Subject: [PATCH 296/353] 8336163: Remove declarations of some debug-only methods in release build Reviewed-by: dholmes, eliu, kvn --- src/hotspot/share/cds/heapShared.hpp | 4 ++++ src/hotspot/share/compiler/compilationPolicy.hpp | 2 ++ src/hotspot/share/opto/node.hpp | 2 ++ src/hotspot/share/runtime/frame.hpp | 6 ++++++ src/hotspot/share/runtime/registerMap.hpp | 10 +++++----- 5 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/hotspot/share/cds/heapShared.hpp b/src/hotspot/share/cds/heapShared.hpp index fa34289a38eda..2c87b050ca66d 100644 --- a/src/hotspot/share/cds/heapShared.hpp +++ b/src/hotspot/share/cds/heapShared.hpp @@ -371,7 +371,9 @@ class HeapShared: AllStatic { KlassSubGraphInfo* subgraph_info, oop orig_obj); +#ifndef PRODUCT static ResourceBitMap calculate_oopmap(MemRegion region); // marks all the oop pointers +#endif static void add_to_dumped_interned_strings(oop string); // Scratch objects for archiving Klass::java_mirror() @@ -426,7 +428,9 @@ class HeapShared: AllStatic { static void init_roots(oop roots_oop) NOT_CDS_JAVA_HEAP_RETURN; static void serialize_tables(SerializeClosure* soc) NOT_CDS_JAVA_HEAP_RETURN; +#ifndef PRODUCT static bool is_a_test_class_in_unnamed_module(Klass* ik) NOT_CDS_JAVA_HEAP_RETURN_(false); +#endif }; #if INCLUDE_CDS_JAVA_HEAP diff --git a/src/hotspot/share/compiler/compilationPolicy.hpp b/src/hotspot/share/compiler/compilationPolicy.hpp index 3ec60cd89c793..fe33fb8cfba28 100644 --- a/src/hotspot/share/compiler/compilationPolicy.hpp +++ b/src/hotspot/share/compiler/compilationPolicy.hpp @@ -179,8 +179,10 @@ class CompilationPolicy : AllStatic { // Set carry flags in the counters (in Method* and MDO). inline static void handle_counter_overflow(const methodHandle& method); +#ifdef ASSERT // Verify that a level is consistent with the compilation mode static bool verify_level(CompLevel level); +#endif // Clamp the request level according to various constraints. inline static CompLevel limit_level(CompLevel level); // Common transition function. Given a predicate determines if a method should transition to another level. diff --git a/src/hotspot/share/opto/node.hpp b/src/hotspot/share/opto/node.hpp index 10e1e7b100696..3e39e1ed2fbfb 100644 --- a/src/hotspot/share/opto/node.hpp +++ b/src/hotspot/share/opto/node.hpp @@ -834,7 +834,9 @@ class Node { juint _class_id; juint _flags; +#ifdef ASSERT static juint max_flags(); +#endif protected: // These methods should be called from constructors only. diff --git a/src/hotspot/share/runtime/frame.hpp b/src/hotspot/share/runtime/frame.hpp index 4113360724de0..468437a648464 100644 --- a/src/hotspot/share/runtime/frame.hpp +++ b/src/hotspot/share/runtime/frame.hpp @@ -387,7 +387,9 @@ class frame { static int interpreter_frame_monitor_size(); static int interpreter_frame_monitor_size_in_bytes(); +#ifdef ASSERT void interpreter_frame_verify_monitor(BasicObjectLock* value) const; +#endif // Return/result value from this interpreter frame // If the method return type is T_OBJECT or T_ARRAY populates oop_result @@ -438,8 +440,10 @@ class frame { void print_on_error(outputStream* st, char* buf, int buflen, bool verbose = false) const; static void print_C_frame(outputStream* st, char* buf, int buflen, address pc); +#ifndef PRODUCT // Add annotated descriptions of memory locations belonging to this frame to values void describe(FrameValues& values, int frame_no, const RegisterMap* reg_map=nullptr); +#endif // Conversion from a VMReg to physical stack location template @@ -492,9 +496,11 @@ class frame { // Verification void verify(const RegisterMap* map) const; +#ifdef ASSERT static bool verify_return_pc(address x); // Usage: // assert(frame::verify_return_pc(return_address), "must be a return pc"); +#endif #include CPU_HEADER(frame) diff --git a/src/hotspot/share/runtime/registerMap.hpp b/src/hotspot/share/runtime/registerMap.hpp index 5cf68a87b7120..a63a25cbb3562 100644 --- a/src/hotspot/share/runtime/registerMap.hpp +++ b/src/hotspot/share/runtime/registerMap.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -153,19 +153,19 @@ class RegisterMap : public StackObj { const RegisterMap* as_RegisterMap() const { return this; } RegisterMap* as_RegisterMap() { return this; } +#ifndef PRODUCT void print_on(outputStream* st) const; void print() const; - void set_async(bool value) { NOT_PRODUCT(_async = value;) } - void set_skip_missing(bool value) { NOT_PRODUCT(_skip_missing = value;) } - -#ifndef PRODUCT bool is_async() const { return _async; } bool should_skip_missing() const { return _skip_missing; } VMReg find_register_spilled_here(void* p, intptr_t* sp); #endif + void set_async(bool value) { NOT_PRODUCT(_async = value;) } + void set_skip_missing(bool value) { NOT_PRODUCT(_skip_missing = value;) } + // the following contains the definition of pd_xxx methods #include CPU_HEADER(registerMap) From 66bee2532f849cfb7ab63857ecd7d773c2566722 Mon Sep 17 00:00:00 2001 From: Ivan Walulya Date: Wed, 14 Aug 2024 09:13:21 +0000 Subject: [PATCH 297/353] 8338315: G1: G1CardTableEntryClosure:do_card_ptr remove unused parameter worker_id Reviewed-by: tschatzl --- src/hotspot/share/gc/g1/g1CardTableEntryClosure.hpp | 4 ++-- src/hotspot/share/gc/g1/g1RemSet.cpp | 4 ++-- src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1CardTableEntryClosure.hpp b/src/hotspot/share/gc/g1/g1CardTableEntryClosure.hpp index 8fe0d7752ebba..e2b53d69e0687 100644 --- a/src/hotspot/share/gc/g1/g1CardTableEntryClosure.hpp +++ b/src/hotspot/share/gc/g1/g1CardTableEntryClosure.hpp @@ -36,7 +36,7 @@ class G1CardTableEntryClosure: public CHeapObj { typedef CardTable::CardValue CardValue; // Process the card whose card table entry is "card_ptr". - virtual void do_card_ptr(CardValue* card_ptr, uint worker_id) = 0; + virtual void do_card_ptr(CardValue* card_ptr) = 0; // Process all the card_ptrs in node. void apply_to_buffer(BufferNode* node, uint worker_id) { @@ -44,7 +44,7 @@ class G1CardTableEntryClosure: public CHeapObj { size_t capacity = node->capacity(); for (size_t i = node->index(); i < capacity; ++i) { CardValue* card_ptr = static_cast(buffer[i]); - do_card_ptr(card_ptr, worker_id); + do_card_ptr(card_ptr); } } }; diff --git a/src/hotspot/share/gc/g1/g1RemSet.cpp b/src/hotspot/share/gc/g1/g1RemSet.cpp index f2426cdfca5f9..0f9b9d17df7b3 100644 --- a/src/hotspot/share/gc/g1/g1RemSet.cpp +++ b/src/hotspot/share/gc/g1/g1RemSet.cpp @@ -1230,11 +1230,10 @@ class G1MergeHeapRootsTask : public WorkerTask { _cards_skipped(0) {} - void do_card_ptr(CardValue* card_ptr, uint worker_id) { + void do_card_ptr(CardValue* card_ptr) override { // The only time we care about recording cards that // contain references that point into the collection set // is during RSet updating within an evacuation pause. - // In this case worker_id should be the id of a GC worker thread. assert(SafepointSynchronize::is_at_safepoint(), "not during an evacuation pause"); uint const region_idx = _ct->region_idx_for(card_ptr); @@ -1342,6 +1341,7 @@ class G1MergeHeapRootsTask : public WorkerTask { FREE_C_HEAP_ARRAY(Stack, _dirty_card_buffers); } } + virtual void work(uint worker_id) { G1CollectedHeap* g1h = G1CollectedHeap::heap(); G1GCPhaseTimes* p = g1h->phase_times(); diff --git a/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp b/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp index c5ebdb3d22dd0..e1f0df05c2227 100644 --- a/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp +++ b/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp @@ -522,7 +522,7 @@ class RedirtyLoggedCardTableEntryClosure : public G1CardTableEntryClosure { _g1_ct(g1h->card_table()), _evac_failure_regions(evac_failure_regions) { } - void do_card_ptr(CardValue* card_ptr, uint worker_id) { + void do_card_ptr(CardValue* card_ptr) override { G1HeapRegion* hr = region_for_card(card_ptr); // Should only dirty cards in regions that won't be freed. From 9fe1777fafca30cf60acb5402c7c70800137136e Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Wed, 14 Aug 2024 09:16:02 +0000 Subject: [PATCH 298/353] 8338280: Parallel: Inline ParallelCompactData::verify_clear Reviewed-by: tschatzl --- src/hotspot/share/gc/parallel/psParallelCompact.cpp | 11 +++-------- src/hotspot/share/gc/parallel/psParallelCompact.hpp | 1 - 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.cpp b/src/hotspot/share/gc/parallel/psParallelCompact.cpp index 4d54f11805ac2..4bff8f8a7d06a 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.cpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.cpp @@ -521,19 +521,14 @@ bool ParallelCompactData::summarize(SplitInfo& split_info, } #ifdef ASSERT -void ParallelCompactData::verify_clear(const PSVirtualSpace* vspace) +void ParallelCompactData::verify_clear() { - const size_t* const beg = (const size_t*)vspace->committed_low_addr(); - const size_t* const end = (const size_t*)vspace->committed_high_addr(); + const size_t* const beg = (const size_t*) _region_vspace->committed_low_addr(); + const size_t* const end = (const size_t*) _region_vspace->committed_high_addr(); for (const size_t* p = beg; p < end; ++p) { assert(*p == 0, "not zero"); } } - -void ParallelCompactData::verify_clear() -{ - verify_clear(_region_vspace); -} #endif // #ifdef ASSERT STWGCTimer PSParallelCompact::_gc_timer; diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.hpp b/src/hotspot/share/gc/parallel/psParallelCompact.hpp index 1e04beb8c66f6..7e71f07722353 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.hpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.hpp @@ -393,7 +393,6 @@ class ParallelCompactData inline bool is_region_aligned(HeapWord* addr) const; #ifdef ASSERT - void verify_clear(const PSVirtualSpace* vspace); void verify_clear(); #endif // #ifdef ASSERT From 38bd8a36704a962f0ad1052fd2ec150a61663256 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Wed, 14 Aug 2024 09:52:23 +0000 Subject: [PATCH 299/353] 8338236: Compile error in cgroup code on Linux when using clang Reviewed-by: mdoerr, sgehwolf --- src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp | 4 ++-- src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp b/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp index 251fbde85f0bb..56af87881e757 100644 --- a/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp +++ b/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -62,7 +62,7 @@ class CgroupV1Controller: public CgroupController { void set_subsystem_path(char *cgroup_path); char *subsystem_path() override { return _path; } - bool is_read_only() { return _read_only; } + bool is_read_only() override { return _read_only; } }; class CgroupV1MemoryController final : public CgroupMemoryController { diff --git a/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp b/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp index 02774fb70aec8..cd100f298747c 100644 --- a/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp +++ b/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2022, Red Hat Inc. + * Copyright (c) 2020, 2024, Red Hat Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -128,8 +128,8 @@ class CgroupV2Subsystem: public CgroupSubsystem { const char * container_type() override { return "cgroupv2"; } - CachingCgroupController* memory_controller() { return _memory; } - CachingCgroupController* cpu_controller() { return _cpu; } + CachingCgroupController* memory_controller() override { return _memory; } + CachingCgroupController* cpu_controller() override { return _cpu; } }; #endif // CGROUP_V2_SUBSYSTEM_LINUX_HPP From fbe4f05636c8f692bd40bbe11fb5bb8b77b77042 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Wed, 14 Aug 2024 12:20:17 +0000 Subject: [PATCH 300/353] 8337976: Insufficient error recovery in parser for switch inside class body Reviewed-by: vromero --- .../com/sun/tools/javac/comp/Attr.java | 13 +++- .../sun/tools/javac/parser/JavacParser.java | 22 +++++- .../sun/tools/javac/parser/VirtualParser.java | 2 +- .../tools/javac/resources/compiler.properties | 3 + .../diags/examples/StatementNotExpected.java | 28 +++++++ .../tools/javac/parser/JavacParserTest.java | 78 ++++++++++++++++++- .../javac/records/RecordCompilationTests.java | 2 +- .../tools/javac/recovery/T8337976.java | 10 +++ .../tools/javac/recovery/T8337976.out | 5 ++ 9 files changed, 156 insertions(+), 7 deletions(-) create mode 100644 test/langtools/tools/javac/diags/examples/StatementNotExpected.java create mode 100644 test/langtools/tools/javac/recovery/T8337976.java create mode 100644 test/langtools/tools/javac/recovery/T8337976.out 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 9b79846ba40df..54edc19560bd1 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 @@ -5251,7 +5251,18 @@ public void visitAnnotatedType(JCAnnotatedType tree) { public void visitErroneous(JCErroneous tree) { if (tree.errs != null) { - Env errEnv = env.dup(env.tree, env.info.dup()); + WriteableScope newScope = env.info.scope; + + if (env.tree instanceof JCClassDecl) { + Symbol fakeOwner = + new MethodSymbol(BLOCK, names.empty, null, + env.info.scope.owner); + newScope = newScope.dupUnshared(fakeOwner); + } + + Env errEnv = + env.dup(env.tree, + env.info.dup(newScope)); errEnv.info.returnResult = unknownExprInfo; for (JCTree err : tree.errs) attribTree(err, errEnv, new ResultInfo(KindSelector.ERR, pt())); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java index f570ad54c58e8..6fc93fdc591ab 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java @@ -455,7 +455,7 @@ protected JCErroneous syntaxError(int pos, Error errorKey) { return syntaxError(pos, List.nil(), errorKey); } - protected JCErroneous syntaxError(int pos, List errs, Error errorKey) { + protected JCErroneous syntaxError(int pos, List errs, Error errorKey) { setErrorEndPos(pos); JCErroneous err = F.at(pos).Erroneous(errs); reportSyntaxError(err, errorKey); @@ -4733,6 +4733,12 @@ protected List classOrInterfaceOrRecordBodyDeclaration(JCModifiers mods, } ignoreDanglingComments(); // no declaration with which dangling comments can be associated return List.of(block(pos, mods.flags)); + } else if (isDefiniteStatementStartToken()) { + int startPos = token.pos; + List statements = blockStatement(); + return List.of(syntaxError(startPos, + statements, + Errors.StatementNotExpected)); } else { return constructorOrMethodOrFieldDeclaration(mods, className, isInterface, isRecord, dc); } @@ -4910,7 +4916,19 @@ protected boolean isDeclaration() { token.kind == INTERFACE || token.kind == ENUM || isRecordStart() && allowRecords; - } + } + + /** + * {@return true if and only if the current token is definitelly a token that + * starts a statement.} + */ + private boolean isDefiniteStatementStartToken() { + return switch (token.kind) { + case IF, WHILE, DO, SWITCH, RETURN, TRY, FOR, ASSERT, BREAK, + CONTINUE, THROW -> true; + default -> false; + }; + } protected boolean isRecordStart() { if (token.kind == IDENTIFIER && token.name() == names.record && peekToken(TokenKind.IDENTIFIER)) { diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/VirtualParser.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/VirtualParser.java index f32c1bf47565c..ec3a373ab4ec2 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/VirtualParser.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/VirtualParser.java @@ -62,7 +62,7 @@ protected JCErroneous syntaxError(int pos, Error errorKey) { } @Override - protected JCErroneous syntaxError(int pos, List errs, Error errorKey) { + protected JCErroneous syntaxError(int pos, List errs, Error errorKey) { hasErrors = true; return F.Erroneous(); } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties index 10f06ad70176d..6fd59438220c7 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties @@ -1616,6 +1616,9 @@ compiler.err.file.sb.on.source.or.patch.path.for.module=\ compiler.err.no.java.lang=\ Unable to find package java.lang in platform classes +compiler.err.statement.not.expected=\ + statements not expected outside of methods and initializers + ##### # Fatal Errors diff --git a/test/langtools/tools/javac/diags/examples/StatementNotExpected.java b/test/langtools/tools/javac/diags/examples/StatementNotExpected.java new file mode 100644 index 0000000000000..a6b965a804489 --- /dev/null +++ b/test/langtools/tools/javac/diags/examples/StatementNotExpected.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +// key: compiler.err.statement.not.expected + +class StatementNotExpected { + return null; +} diff --git a/test/langtools/tools/javac/parser/JavacParserTest.java b/test/langtools/tools/javac/parser/JavacParserTest.java index 93b2b51a8fa39..547de1088b460 100644 --- a/test/langtools/tools/javac/parser/JavacParserTest.java +++ b/test/langtools/tools/javac/parser/JavacParserTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 7073631 7159445 7156633 8028235 8065753 8205418 8205913 8228451 8237041 8253584 8246774 8256411 8256149 8259050 8266436 8267221 8271928 8275097 8293897 8295401 8304671 8310326 8312093 8312204 8315452 + * @bug 7073631 7159445 7156633 8028235 8065753 8205418 8205913 8228451 8237041 8253584 8246774 8256411 8256149 8259050 8266436 8267221 8271928 8275097 8293897 8295401 8304671 8310326 8312093 8312204 8315452 8337976 * @summary tests error and diagnostics positions * @author Jan Lahoda * @modules jdk.compiler/com.sun.tools.javac.api @@ -2409,6 +2409,80 @@ void testPartialTopLevelModifiers() throws IOException { (ERROR: public )"""); } + @Test //JDK-8337976 + void testStatementsInClass() throws IOException { + String code = """ + package test; + public class Test { + if (true); + while (true); + do {} while (true); + for ( ; ; ); + switch (0) { default: } + assert true; + break; + continue; + return ; + throw new RuntimeException(); + try { + } catch (RuntimeException ex) {} + } + """; + DiagnosticCollector coll = + new DiagnosticCollector<>(); + JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, coll, + List.of("--enable-preview", "--source", SOURCE_VERSION), + null, Arrays.asList(new MyFileObject(code))); + CompilationUnitTree cut = ct.parse().iterator().next(); + + String result = toStringWithErrors(cut).replaceAll("\\R", "\n"); + System.out.println("RESULT\n" + result); + assertEquals("incorrect AST", + result, + """ + package test; + \n\ + public class Test { + (ERROR: if (true) ;) + (ERROR: while (true) ;) + (ERROR: do { + } while (true);) + (ERROR: for (; ; ) ;) + (ERROR: switch (0) { + default: + + }) + (ERROR: assert true;) + (ERROR: break;) + (ERROR: continue;) + (ERROR: return;) + (ERROR: throw new RuntimeException();) + (ERROR: try { + } catch (RuntimeException ex) { + }) + }"""); + + List codes = new LinkedList<>(); + + for (Diagnostic d : coll.getDiagnostics()) { + codes.add(d.getLineNumber() + ":" + d.getColumnNumber() + ":" + d.getCode()); + } + + assertEquals("testStatementsInClass: " + codes, + List.of("3:5:compiler.err.statement.not.expected", + "4:5:compiler.err.statement.not.expected", + "5:5:compiler.err.statement.not.expected", + "6:5:compiler.err.statement.not.expected", + "7:5:compiler.err.statement.not.expected", + "8:5:compiler.err.statement.not.expected", + "9:5:compiler.err.statement.not.expected", + "10:5:compiler.err.statement.not.expected", + "11:5:compiler.err.statement.not.expected", + "12:5:compiler.err.statement.not.expected", + "13:5:compiler.err.statement.not.expected"), + codes); + } + void run(String[] args) throws Exception { int passed = 0, failed = 0; final Pattern p = (args != null && args.length > 0) diff --git a/test/langtools/tools/javac/records/RecordCompilationTests.java b/test/langtools/tools/javac/records/RecordCompilationTests.java index cbd00f9c607cb..d80ade50a3b76 100644 --- a/test/langtools/tools/javac/records/RecordCompilationTests.java +++ b/test/langtools/tools/javac/records/RecordCompilationTests.java @@ -1358,7 +1358,7 @@ void testAcceptRecordId() { try { String[] testOptions = {}; setCompileOptions(testOptions); - assertFail("compiler.err.illegal.start.of.type", + assertFail("compiler.err.statement.not.expected", "class R {\n" + " record RR(int i) {\n" + " return null;\n" + diff --git a/test/langtools/tools/javac/recovery/T8337976.java b/test/langtools/tools/javac/recovery/T8337976.java new file mode 100644 index 0000000000000..cac987f40834f --- /dev/null +++ b/test/langtools/tools/javac/recovery/T8337976.java @@ -0,0 +1,10 @@ +/** + * @test /nodynamiccopyright/ + * @bug 8337976 + * @summary Verify javac does not crash and produces nice errors for certain erroneous code. + * @compile/fail/ref=T8337976.out -XDrawDiagnostics -XDshould-stop.at=FLOW -XDdev T8337976.java + */ +public class T8337976 { + switch (0) { default: undefined u;} + if (true) { undefined u; } +} diff --git a/test/langtools/tools/javac/recovery/T8337976.out b/test/langtools/tools/javac/recovery/T8337976.out new file mode 100644 index 0000000000000..bae578cecf3d6 --- /dev/null +++ b/test/langtools/tools/javac/recovery/T8337976.out @@ -0,0 +1,5 @@ +T8337976.java:8:5: compiler.err.statement.not.expected +T8337976.java:9:5: compiler.err.statement.not.expected +T8337976.java:8:27: compiler.err.cant.resolve.location: kindname.class, undefined, , , (compiler.misc.location: kindname.class, T8337976, null) +T8337976.java:9:17: compiler.err.cant.resolve.location: kindname.class, undefined, , , (compiler.misc.location: kindname.class, T8337976, null) +4 errors From a5d948fb9841f654cccc9567c60e8d28e7d719ae Mon Sep 17 00:00:00 2001 From: John Engebretson Date: Wed, 14 Aug 2024 14:11:53 +0000 Subject: [PATCH 301/353] 8332842: Optimize empty CopyOnWriteArrayList allocations Reviewed-by: shade, alanb --- .../util/concurrent/CopyOnWriteArrayList.java | 22 ++- .../CopyOnWriteArrayListBenchmark.java | 166 ++++++++++++++++++ 2 files changed, 184 insertions(+), 4 deletions(-) create mode 100644 test/micro/org/openjdk/bench/java/util/concurrent/CopyOnWriteArrayListBenchmark.java diff --git a/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArrayList.java b/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArrayList.java index 7182f98706d52..f0f60730eb65e 100644 --- a/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArrayList.java +++ b/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArrayList.java @@ -100,6 +100,8 @@ public class CopyOnWriteArrayList implements List, RandomAccess, Cloneable, java.io.Serializable { private static final long serialVersionUID = 8673264195747942595L; + private static final Object[] EMPTY_ELEMENTDATA = {}; + /** * The lock protecting all mutators. (We have a mild preference * for builtin monitors over ReentrantLock when either will do.) @@ -128,7 +130,7 @@ final void setArray(Object[] a) { * Creates an empty list. */ public CopyOnWriteArrayList() { - setArray(new Object[0]); + setArray(EMPTY_ELEMENTDATA); } /** @@ -143,6 +145,8 @@ public CopyOnWriteArrayList(Collection c) { Object[] es; if (c.getClass() == CopyOnWriteArrayList.class) es = ((CopyOnWriteArrayList)c).getArray(); + else if (c.isEmpty()) + es = EMPTY_ELEMENTDATA; else { es = c.toArray(); if (c.getClass() != java.util.ArrayList.class) @@ -159,7 +163,10 @@ public CopyOnWriteArrayList(Collection c) { * @throws NullPointerException if the specified array is null */ public CopyOnWriteArrayList(E[] toCopyIn) { - setArray(Arrays.copyOf(toCopyIn, toCopyIn.length, Object[].class)); + if (toCopyIn.length == 0) + setArray(EMPTY_ELEMENTDATA); + else + setArray(Arrays.copyOf(toCopyIn, toCopyIn.length, Object[].class)); } /** @@ -533,6 +540,8 @@ public E remove(int index) { Object[] newElements; if (numMoved == 0) newElements = Arrays.copyOf(es, len - 1); + else if (len == 1) + newElements = EMPTY_ELEMENTDATA; else { newElements = new Object[len - 1]; System.arraycopy(es, 0, newElements, 0, index); @@ -618,6 +627,11 @@ private boolean remove(Object o, Object[] snapshot, int index) { if (index < 0) return false; } + if (len == 1) { + // one element exists and that element should be removed + setArray(EMPTY_ELEMENTDATA); + return true; + } Object[] newElements = new Object[len - 1]; System.arraycopy(current, 0, newElements, 0, index); System.arraycopy(current, index + 1, @@ -804,7 +818,7 @@ public int addAllAbsent(Collection c) { */ public void clear() { synchronized (lock) { - setArray(new Object[0]); + setArray(EMPTY_ELEMENTDATA); } } @@ -1022,7 +1036,7 @@ private void readObject(java.io.ObjectInputStream s) // Read in array length and allocate array int len = s.readInt(); SharedSecrets.getJavaObjectInputStreamAccess().checkArray(s, Object[].class, len); - Object[] es = new Object[len]; + Object[] es = (len == 0 ? EMPTY_ELEMENTDATA : new Object[len]); // Read in all elements in the proper order. for (int i = 0; i < len; i++) diff --git a/test/micro/org/openjdk/bench/java/util/concurrent/CopyOnWriteArrayListBenchmark.java b/test/micro/org/openjdk/bench/java/util/concurrent/CopyOnWriteArrayListBenchmark.java new file mode 100644 index 0000000000000..0ce091d1724a0 --- /dev/null +++ b/test/micro/org/openjdk/bench/java/util/concurrent/CopyOnWriteArrayListBenchmark.java @@ -0,0 +1,166 @@ +/* + * 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. + */ +package org.openjdk.bench.java.util.concurrent; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.TimeUnit; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; + +@BenchmarkMode(Mode.AverageTime) +@State(Scope.Benchmark) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@Fork(1) +@Warmup(iterations = 3, time = 1, timeUnit = TimeUnit.SECONDS) +@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS) +public class CopyOnWriteArrayListBenchmark { + + private static byte[] getSerializedBytes(CopyOnWriteArrayList list) throws IOException { + ByteArrayOutputStream bytesOut = new ByteArrayOutputStream(); + ObjectOutputStream objectOut = new ObjectOutputStream(bytesOut); + objectOut.writeObject(list); + + objectOut.close(); + return bytesOut.toByteArray(); + } + + private Collection emptyCollection = new ArrayList<>(); + private Object[] emptyArray = new Object[0]; + + private Collection oneItemCollection = Arrays.asList(""); + private Object[] oneItemArray = new Object[] { "" }; + + private CopyOnWriteArrayList emptyInstance = new CopyOnWriteArrayList<>(); + private CopyOnWriteArrayList oneItemInstance = new CopyOnWriteArrayList<>(oneItemArray); + + private byte[] emptyInstanceBytes; + private byte[] oneInstanceBytes; + + public CopyOnWriteArrayListBenchmark() { + try { + emptyInstanceBytes = getSerializedBytes(emptyInstance); + oneInstanceBytes = getSerializedBytes(oneItemInstance); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @Benchmark + public void clear() { + // have to create a new instance on each execution + ((CopyOnWriteArrayList) oneItemInstance.clone()).clear(); + } + + @Benchmark + public void clearEmpty() { + emptyInstance.clear(); + } + + @Benchmark + public CopyOnWriteArrayList createInstanceArray() { + return new CopyOnWriteArrayList<>(oneItemArray); + } + + @Benchmark + public CopyOnWriteArrayList createInstanceArrayEmpty() { + return new CopyOnWriteArrayList<>(emptyArray); + } + + @Benchmark + public CopyOnWriteArrayList createInstanceCollection() { + return new CopyOnWriteArrayList<>(oneItemCollection); + } + + @Benchmark + public CopyOnWriteArrayList createInstanceCollectionEmpty() { + return new CopyOnWriteArrayList<>(emptyCollection); + } + + @Benchmark + public CopyOnWriteArrayList createInstanceDefault() { + return new CopyOnWriteArrayList(); + } + + @Benchmark + public CopyOnWriteArrayList readInstance() throws IOException, ClassNotFoundException { + try (ObjectInputStream objIn = new ObjectInputStream(new ByteArrayInputStream(oneInstanceBytes))) { + return (CopyOnWriteArrayList) objIn.readObject(); + } + } + + @Benchmark + public CopyOnWriteArrayList readInstanceEmpty() throws IOException, ClassNotFoundException { + try (ObjectInputStream objIn = new ObjectInputStream(new ByteArrayInputStream(emptyInstanceBytes))) { + return (CopyOnWriteArrayList) objIn.readObject(); + } + } + + @Benchmark + public CopyOnWriteArrayList removeObjectLastRemaining() { + CopyOnWriteArrayList list = new CopyOnWriteArrayList<>(); + list.add(""); + list.remove(""); + return list; + } + + @Benchmark + public CopyOnWriteArrayList removeIndexLastRemaining() { + CopyOnWriteArrayList list = new CopyOnWriteArrayList<>(); + list.add(""); + list.remove(0); + return list; + } + @Benchmark + public CopyOnWriteArrayList removeObject() { + CopyOnWriteArrayList list = new CopyOnWriteArrayList<>(); + list.add(""); + list.add("a"); + list.remove(""); + return list; + } + + @Benchmark + public CopyOnWriteArrayList remove() { + CopyOnWriteArrayList list = new CopyOnWriteArrayList<>(); + list.add(""); + list.add("a"); + list.remove(0); + return list; + } +} From d8e4d3f2d6c187f2487acd390a4e5fa2a99010ea Mon Sep 17 00:00:00 2001 From: Zdenek Zambersky Date: Wed, 14 Aug 2024 15:20:07 +0000 Subject: [PATCH 302/353] 8338402: GHA: some of bundles may not get removed Reviewed-by: ihse, shade --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b16335b7091c2..6a1b4420e3ad7 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -371,7 +371,7 @@ jobs: -H 'Accept: application/vnd.github+json' \ -H 'Authorization: Bearer ${{ github.token }}' \ -H 'X-GitHub-Api-Version: 2022-11-28' \ - '${{ github.api_url }}/repos/${{ github.repository }}/actions/runs/${{ github.run_id }}/artifacts')" + '${{ github.api_url }}/repos/${{ github.repository }}/actions/runs/${{ github.run_id }}/artifacts?per_page=100')" BUNDLE_ARTIFACT_IDS="$(echo "$ALL_ARTIFACT_IDS" | jq -r -c '.artifacts | map(select(.name|startswith("bundles-"))) | .[].id')" for id in $BUNDLE_ARTIFACT_IDS; do echo "Removing $id" From 0e3903f2eb854715acee92cfc5ee2d4a2e800f61 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Wed, 14 Aug 2024 16:49:11 +0000 Subject: [PATCH 303/353] 8338393: Parallel: Remove unused ParallelCompactData::clear_range Reviewed-by: tschatzl --- src/hotspot/share/gc/parallel/psParallelCompact.hpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.hpp b/src/hotspot/share/gc/parallel/psParallelCompact.hpp index 7e71f07722353..3f487ec3ef483 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.hpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.hpp @@ -374,9 +374,6 @@ class ParallelCompactData HeapWord** target_next); void clear_range(size_t beg_region, size_t end_region); - void clear_range(HeapWord* beg, HeapWord* end) { - clear_range(addr_to_region_idx(beg), addr_to_region_idx(end)); - } // Return the number of words between addr and the start of the region // containing addr. From 6a390147959e0fb88de6ee13204cff72cd910f09 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Wed, 14 Aug 2024 16:56:28 +0000 Subject: [PATCH 304/353] 8338110: Exclude Fingerprinter::do_type from ubsan checks Reviewed-by: jwaters, rrich --- src/hotspot/share/runtime/signature.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/hotspot/share/runtime/signature.hpp b/src/hotspot/share/runtime/signature.hpp index 3f7d062ab6654..25de9c0a1f03a 100644 --- a/src/hotspot/share/runtime/signature.hpp +++ b/src/hotspot/share/runtime/signature.hpp @@ -28,6 +28,7 @@ #include "memory/allocation.hpp" #include "oops/method.hpp" +#include "sanitizers/ub.hpp" // Static routines and parsing loops for processing field and method @@ -338,6 +339,7 @@ class Fingerprinter: public SignatureIterator { void do_type_calling_convention(BasicType type); friend class SignatureIterator; // so do_parameters_on can call do_type + ATTRIBUTE_NO_UBSAN void do_type(BasicType type) { assert(fp_is_valid_type(type), "bad parameter type"); _accumulator |= ((fingerprint_t)type << _shift_count); From c0384b6f3584501fb3bd93854734eeacf6620a7e Mon Sep 17 00:00:00 2001 From: Phil Race Date: Wed, 14 Aug 2024 17:58:24 +0000 Subject: [PATCH 305/353] 8337237: Use FFM instead of Unsafe for Java 2D RenderBuffer class Reviewed-by: jvernee, jdv --- .../classes/sun/java2d/pipe/RenderBuffer.java | 134 ++++++++---------- 1 file changed, 60 insertions(+), 74 deletions(-) diff --git a/src/java.desktop/share/classes/sun/java2d/pipe/RenderBuffer.java b/src/java.desktop/share/classes/sun/java2d/pipe/RenderBuffer.java index 57f24a4eadafb..2b57d98ef4080 100644 --- a/src/java.desktop/share/classes/sun/java2d/pipe/RenderBuffer.java +++ b/src/java.desktop/share/classes/sun/java2d/pipe/RenderBuffer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,58 +25,54 @@ package sun.java2d.pipe; -import jdk.internal.misc.Unsafe; +import java.lang.foreign.Arena; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.ValueLayout; +import static java.lang.foreign.ValueLayout.*; /** - * The RenderBuffer class is a simplified, high-performance, Unsafe wrapper + * The RenderBuffer class is a simplified, high-performance class * used for buffering rendering operations in a single-threaded rendering - * environment. It's functionality is similar to the ByteBuffer and related + * environment. Its functionality is similar to the ByteBuffer and related * NIO classes. However, the methods in this class perform little to no * alignment or bounds checks for performance reasons. Therefore, it is * the caller's responsibility to ensure that all put() calls are properly * aligned and within bounds: * - int and float values must be aligned on 4-byte boundaries * - long and double values must be aligned on 8-byte boundaries + * Failure to do so will result in exceptions from the FFM API, or worse. * * This class only includes the bare minimum of methods to support * single-threaded rendering. For example, there is no put(double[]) method * because we currently have no need for such a method in the STR classes. */ -public class RenderBuffer { +public final class RenderBuffer { /** * These constants represent the size of various data types (in bytes). */ - protected static final long SIZEOF_BYTE = 1L; - protected static final long SIZEOF_SHORT = 2L; - protected static final long SIZEOF_INT = 4L; - protected static final long SIZEOF_FLOAT = 4L; - protected static final long SIZEOF_LONG = 8L; - protected static final long SIZEOF_DOUBLE = 8L; + private static final int SIZEOF_BYTE = Byte.BYTES; + private static final int SIZEOF_SHORT = Short.BYTES; + private static final int SIZEOF_INT = Integer.BYTES; + private static final int SIZEOF_FLOAT = Float.BYTES; + private static final int SIZEOF_LONG = Long.BYTES; + private static final int SIZEOF_DOUBLE = Double.BYTES; /** - * Represents the number of elements at which we have empirically - * determined that the average cost of a JNI call exceeds the expense - * of an element by element copy. In other words, if the number of - * elements in an array to be copied exceeds this value, then we should - * use the copyFromArray() method to complete the bulk put operation. - * (This value can be adjusted if the cost of JNI downcalls is reduced - * in a future release.) + * Measurements show that using the copy API from a segment backed by a heap + * array gets reliably faster than individual puts around a length of 10. + * However the time is miniscule in the context of what it is used for + * and much more than adequate, so no problem expected if this changes over time. */ - private static final int COPY_FROM_ARRAY_THRESHOLD = 6; - - protected final Unsafe unsafe; - protected final long baseAddress; - protected final long endAddress; - protected long curAddress; - protected final int capacity; - - protected RenderBuffer(int numBytes) { - unsafe = Unsafe.getUnsafe(); - curAddress = baseAddress = unsafe.allocateMemory(numBytes); - endAddress = baseAddress + numBytes; - capacity = numBytes; + private static final int COPY_FROM_ARRAY_THRESHOLD = 10; + + private final MemorySegment segment; + private int curOffset; + + private RenderBuffer(int numBytes) { + segment = Arena.global().allocate(numBytes, SIZEOF_DOUBLE); + curOffset = 0; } /** @@ -90,7 +86,7 @@ public static RenderBuffer allocate(int numBytes) { * Returns the base address of the underlying memory buffer. */ public final long getAddress() { - return baseAddress; + return segment.address(); } /** @@ -99,27 +95,27 @@ public final long getAddress() { */ public final int capacity() { - return capacity; + return (int)segment.byteSize(); } public final int remaining() { - return (int)(endAddress - curAddress); + return (capacity() - curOffset); } public final int position() { - return (int)(curAddress - baseAddress); + return curOffset; } - public final void position(long numBytes) { - curAddress = baseAddress + numBytes; + public final void position(int bytePos) { + curOffset = bytePos; } public final void clear() { - curAddress = baseAddress; + curOffset = 0; } - public final RenderBuffer skip(long numBytes) { - curAddress += numBytes; + public final RenderBuffer skip(int numBytes) { + curOffset += numBytes; return this; } @@ -128,8 +124,8 @@ public final RenderBuffer skip(long numBytes) { */ public final RenderBuffer putByte(byte x) { - unsafe.putByte(curAddress, x); - curAddress += SIZEOF_BYTE; + segment.set(JAVA_BYTE, curOffset, x); + curOffset += SIZEOF_BYTE; return this; } @@ -139,10 +135,8 @@ public RenderBuffer put(byte[] x) { public RenderBuffer put(byte[] x, int offset, int length) { if (length > COPY_FROM_ARRAY_THRESHOLD) { - long offsetInBytes = offset * SIZEOF_BYTE + Unsafe.ARRAY_BYTE_BASE_OFFSET; - long lengthInBytes = length * SIZEOF_BYTE; - unsafe.copyMemory(x, offsetInBytes, null, curAddress, lengthInBytes); - position(position() + lengthInBytes); + MemorySegment.copy(x, offset, segment, JAVA_BYTE, curOffset, length); + position(position() + length * SIZEOF_BYTE); } else { int end = offset + length; for (int i = offset; i < end; i++) { @@ -158,8 +152,8 @@ public RenderBuffer put(byte[] x, int offset, int length) { public final RenderBuffer putShort(short x) { // assert (position() % SIZEOF_SHORT == 0); - unsafe.putShort(curAddress, x); - curAddress += SIZEOF_SHORT; + segment.set(JAVA_SHORT, curOffset, x); + curOffset += SIZEOF_SHORT; return this; } @@ -170,10 +164,8 @@ public RenderBuffer put(short[] x) { public RenderBuffer put(short[] x, int offset, int length) { // assert (position() % SIZEOF_SHORT == 0); if (length > COPY_FROM_ARRAY_THRESHOLD) { - long offsetInBytes = offset * SIZEOF_SHORT + Unsafe.ARRAY_SHORT_BASE_OFFSET; - long lengthInBytes = length * SIZEOF_SHORT; - unsafe.copyMemory(x, offsetInBytes, null, curAddress, lengthInBytes); - position(position() + lengthInBytes); + MemorySegment.copy(x, offset, segment, JAVA_SHORT, curOffset, length); + position(position() + length * SIZEOF_SHORT); } else { int end = offset + length; for (int i = offset; i < end; i++) { @@ -188,15 +180,15 @@ public RenderBuffer put(short[] x, int offset, int length) { */ public final RenderBuffer putInt(int pos, int x) { - // assert (baseAddress + pos % SIZEOF_INT == 0); - unsafe.putInt(baseAddress + pos, x); + // assert (getAddress() + pos % SIZEOF_INT == 0); + segment.set(JAVA_INT, pos, x); return this; } public final RenderBuffer putInt(int x) { // assert (position() % SIZEOF_INT == 0); - unsafe.putInt(curAddress, x); - curAddress += SIZEOF_INT; + segment.set(JAVA_INT, curOffset, x); + curOffset += SIZEOF_INT; return this; } @@ -207,10 +199,8 @@ public RenderBuffer put(int[] x) { public RenderBuffer put(int[] x, int offset, int length) { // assert (position() % SIZEOF_INT == 0); if (length > COPY_FROM_ARRAY_THRESHOLD) { - long offsetInBytes = offset * SIZEOF_INT + Unsafe.ARRAY_INT_BASE_OFFSET; - long lengthInBytes = length * SIZEOF_INT; - unsafe.copyMemory(x, offsetInBytes, null, curAddress, lengthInBytes); - position(position() + lengthInBytes); + MemorySegment.copy(x, offset, segment, JAVA_INT, curOffset, length); + position(position() + length * SIZEOF_INT); } else { int end = offset + length; for (int i = offset; i < end; i++) { @@ -226,8 +216,8 @@ public RenderBuffer put(int[] x, int offset, int length) { public final RenderBuffer putFloat(float x) { // assert (position() % SIZEOF_FLOAT == 0); - unsafe.putFloat(curAddress, x); - curAddress += SIZEOF_FLOAT; + segment.set(JAVA_FLOAT, curOffset, x); + curOffset += SIZEOF_FLOAT; return this; } @@ -238,10 +228,8 @@ public RenderBuffer put(float[] x) { public RenderBuffer put(float[] x, int offset, int length) { // assert (position() % SIZEOF_FLOAT == 0); if (length > COPY_FROM_ARRAY_THRESHOLD) { - long offsetInBytes = offset * SIZEOF_FLOAT + Unsafe.ARRAY_FLOAT_BASE_OFFSET; - long lengthInBytes = length * SIZEOF_FLOAT; - unsafe.copyMemory(x, offsetInBytes, null, curAddress, lengthInBytes); - position(position() + lengthInBytes); + MemorySegment.copy(x, offset, segment, JAVA_FLOAT, curOffset, length); + position(position() + length * SIZEOF_FLOAT); } else { int end = offset + length; for (int i = offset; i < end; i++) { @@ -257,8 +245,8 @@ public RenderBuffer put(float[] x, int offset, int length) { public final RenderBuffer putLong(long x) { // assert (position() % SIZEOF_LONG == 0); - unsafe.putLong(curAddress, x); - curAddress += SIZEOF_LONG; + segment.set(JAVA_LONG, curOffset, x); + curOffset += SIZEOF_LONG; return this; } @@ -269,10 +257,8 @@ public RenderBuffer put(long[] x) { public RenderBuffer put(long[] x, int offset, int length) { // assert (position() % SIZEOF_LONG == 0); if (length > COPY_FROM_ARRAY_THRESHOLD) { - long offsetInBytes = offset * SIZEOF_LONG + Unsafe.ARRAY_LONG_BASE_OFFSET; - long lengthInBytes = length * SIZEOF_LONG; - unsafe.copyMemory(x, offsetInBytes, null, curAddress, lengthInBytes); - position(position() + lengthInBytes); + MemorySegment.copy(x, offset, segment, JAVA_LONG, curOffset, length); + position(position() + length * SIZEOF_LONG); } else { int end = offset + length; for (int i = offset; i < end; i++) { @@ -288,8 +274,8 @@ public RenderBuffer put(long[] x, int offset, int length) { public final RenderBuffer putDouble(double x) { // assert (position() % SIZEOF_DOUBLE == 0); - unsafe.putDouble(curAddress, x); - curAddress += SIZEOF_DOUBLE; + segment.set(JAVA_DOUBLE, curOffset, x); + curOffset += SIZEOF_DOUBLE; return this; } } From 723ac5763aed0d67516c6746f39a066efc412b48 Mon Sep 17 00:00:00 2001 From: Chris Plummer Date: Wed, 14 Aug 2024 18:41:24 +0000 Subject: [PATCH 306/353] 8332488: Add JVMTI DataDumpRequest to the debug agent Reviewed-by: sspitsyn, lmesnik --- .../share/native/libjdwp/debugInit.c | 11 +- .../share/native/libjdwp/eventFilter.c | 8 +- .../share/native/libjdwp/eventFilter.h | 6 +- .../share/native/libjdwp/eventHandler.c | 59 +++++- .../share/native/libjdwp/eventHandler.h | 4 +- .../share/native/libjdwp/threadControl.c | 13 +- .../share/native/libjdwp/threadControl.h | 4 +- .../share/native/libjdwp/util.c | 4 - .../share/native/libjdwp/util.h | 3 +- test/jdk/com/sun/jdi/DataDumpTest.java | 176 ++++++++++++++++++ 10 files changed, 251 insertions(+), 37 deletions(-) create mode 100644 test/jdk/com/sun/jdi/DataDumpTest.java diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/debugInit.c b/src/jdk.jdwp.agent/share/native/libjdwp/debugInit.c index fe990e97a6531..b221cf6cf2551 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/debugInit.c +++ b/src/jdk.jdwp.agent/share/native/libjdwp/debugInit.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -995,6 +995,8 @@ parseOptions(char *options) gdata->includeVThreads = JNI_FALSE; gdata->rememberVThreadsWhenDisconnected = JNI_FALSE; + gdata->jvmti_data_dump = JNI_FALSE; + /* Options being NULL will end up being an error. */ if (options == NULL) { options = ""; @@ -1159,6 +1161,13 @@ parseOptions(char *options) if ( dopause ) { do_pause(); } + } else if (strcmp(buf, "datadump") == 0) { + // Enable JVMTI DATA_DUMP_REQUEST support. + // This is not a documented flag. This feature is experimental and is only intended + // to be used by debug agent developers. See comment for cbDataDump() for more details. + if ( !get_boolean(&str, &(gdata->jvmti_data_dump)) ) { + goto syntax_error; + } } else if (strcmp(buf, "coredump") == 0) { if ( !get_boolean(&str, &docoredump) ) { goto syntax_error; diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/eventFilter.c b/src/jdk.jdwp.agent/share/native/libjdwp/eventFilter.c index af56d7145c9b7..3ba875e88cdd3 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/eventFilter.c +++ b/src/jdk.jdwp.agent/share/native/libjdwp/eventFilter.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1387,9 +1387,7 @@ eventFilterRestricted_deinstall(HandlerNode *node) return error1 != JVMTI_ERROR_NONE? error1 : error2; } -/***** debugging *****/ - -#ifdef DEBUG +/***** APIs for debugging the debug agent *****/ void eventFilter_dumpHandlerFilters(HandlerNode *node) @@ -1476,5 +1474,3 @@ eventFilter_dumpHandlerFilters(HandlerNode *node) } } } - -#endif /* DEBUG */ diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/eventFilter.h b/src/jdk.jdwp.agent/share/native/libjdwp/eventFilter.h index 9d79509f0d253..984d64815d655 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/eventFilter.h +++ b/src/jdk.jdwp.agent/share/native/libjdwp/eventFilter.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -76,10 +76,8 @@ jvmtiError eventFilter_setPlatformThreadsOnlyFilter(HandlerNode *node, jint inde jboolean eventFilter_predictFiltering(HandlerNode *node, jclass clazz, char *classname); jboolean isBreakpointSet(jclass clazz, jmethodID method, jlocation location); -/***** debugging *****/ +/***** APIs for debugging the debug agent *****/ -#ifdef DEBUG void eventFilter_dumpHandlerFilters(HandlerNode *node); -#endif #endif /* _EVENT_FILTER_H */ diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/eventHandler.c b/src/jdk.jdwp.agent/share/native/libjdwp/eventHandler.c index cf2de8061195b..e4a9bd7994301 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/eventHandler.c +++ b/src/jdk.jdwp.agent/share/native/libjdwp/eventHandler.c @@ -1330,6 +1330,44 @@ cbVMDeath(jvmtiEnv *jvmti_env, JNIEnv *env) LOG_MISC(("END cbVMDeath")); } +/** + * Event callback for JVMTI_EVENT_DATA_DUMP_REQUEST + * + * This callback is made when a JVMTI data dump is requested. The common way of doing + * this is with "jcmd JVMTI.data_dump". + * + * Debug agent data dumps are experimental and only intended to be used by debug agent + * developers. Data dumps are disabled by default. + * + * This callback is enabled by launching the debug agent with datadump=y. The easiest + * way to enabled data dumps with debugger tests or when using jdb is to use the + * _JAVA_JDWP_OPTIONS export. The following works well when running tests: + * + * make test TEST= \ + * JTREG='JAVA_OPTIONS=-XX:+StartAttachListener;OPTIONS=-e:_JAVA_JDWP_OPTIONS=datadump=y' + * + * Data dumps may fail to happen due to the debug agent suspending all threads. + * This causes the Signal Dispatcher and Attach Listener threads to be suspended, + * which can cause issues with jcmd attaching. Running with -XX:+StartAttachListener can + * help, but in general it is best not to try a datadump when all threads are suspended. + * + * Data dumps are also risky when the debug agent is handling events or commands from + * the debugger, due to dumping data that is not lock protected. This can cause a + * crash. + * + * Data dumps are meant to aid with post mortem debugging (debugging after a + * problem has been detected), not for ongoing periodic data gathering. + */ +static void JNICALL +cbDataDump(jvmtiEnv *jvmti_env) +{ + tty_message("Debug Agent Data Dump"); + tty_message("=== START DUMP ==="); + threadControl_dumpAllThreads(); + eventHandler_dumpAllHandlers(JNI_TRUE); + tty_message("=== END DUMP ==="); +} + /** * Delete this handler (do not delete permanent handlers): * Deinsert handler from active list, @@ -1518,6 +1556,19 @@ eventHandler_initialize(jbyte sessionID) if (error != JVMTI_ERROR_NONE) { EXIT_ERROR(error,"Can't enable garbage collection finish events"); } + + /* + * DATA_DUMP_REQUEST is special since it is not tied to any handlers or an EI, + * so it cannot be setup using threadControl_setEventMode(). Use JVMTI API directly. + */ + if (gdata->jvmti_data_dump) { + error = JVMTI_FUNC_PTR(gdata->jvmti,SetEventNotificationMode) + (gdata->jvmti, JVMTI_ENABLE, JVMTI_EVENT_DATA_DUMP_REQUEST, NULL); + if (error != JVMTI_ERROR_NONE) { + EXIT_ERROR(error,"Can't enable data dump request events"); + } + } + /* * Only enable vthread START and END events if we want to remember * vthreads when no debugger is connected. @@ -1580,6 +1631,8 @@ eventHandler_initialize(jbyte sessionID) gdata->callbacks.VirtualThreadStart = &cbVThreadStart; /* Event callback for JVMTI_EVENT_VIRTUAL_THREAD_END */ gdata->callbacks.VirtualThreadEnd = &cbVThreadEnd; + /* Event callback for JVMTI_EVENT_DATA_DUMP_REQUEST */ + gdata->callbacks.DataDumpRequest = &cbDataDump; error = JVMTI_FUNC_PTR(gdata->jvmti,SetEventCallbacks) (gdata->jvmti, &(gdata->callbacks), sizeof(gdata->callbacks)); @@ -1851,9 +1904,7 @@ eventHandler_installExternal(HandlerNode *node) JNI_TRUE); } -/***** debugging *****/ - -#ifdef DEBUG +/***** APIs for debugging the debug agent *****/ void eventHandler_dumpAllHandlers(jboolean dumpPermanent) @@ -1892,5 +1943,3 @@ eventHandler_dumpHandler(HandlerNode *node) tty_message("Handler for %s(%d)\n", eventIndex2EventName(node->ei), node->ei); eventFilter_dumpHandlerFilters(node); } - -#endif /* DEBUG */ diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/eventHandler.h b/src/jdk.jdwp.agent/share/native/libjdwp/eventHandler.h index 096b1ed795ac6..7d3684e6aa0b2 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/eventHandler.h +++ b/src/jdk.jdwp.agent/share/native/libjdwp/eventHandler.h @@ -85,12 +85,10 @@ jboolean eventHandler_synthesizeUnloadEvent(char *signature, JNIEnv *env); jclass getMethodClass(jvmtiEnv *jvmti_env, jmethodID method); -/***** debugging *****/ +/***** APIs for debugging the debug agent *****/ -#ifdef DEBUG void eventHandler_dumpAllHandlers(jboolean dumpPermanent); void eventHandler_dumpHandlers(EventIndex ei, jboolean dumpPermanent); void eventHandler_dumpHandler(HandlerNode *node); -#endif #endif /* _EVENTHANDLER_H */ diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c b/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c index 220e004097945..7e68e65e56ca0 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c +++ b/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c @@ -137,11 +137,6 @@ typedef struct { static DeferredEventModeList deferredEventModes; -#ifdef DEBUG -static void dumpThreadList(ThreadList *list); -static void dumpThread(ThreadNode *node); -#endif - /* Get the state of the thread direct from JVMTI */ static jvmtiError threadState(jthread thread, jint *pstate) @@ -2561,13 +2556,15 @@ threadControl_allVThreads(jint *numVThreads) return vthreads; } -/***** debugging *****/ +/***** APIs for debugging the debug agent *****/ -#ifdef DEBUG +static void dumpThreadList(ThreadList *list); +static void dumpThread(ThreadNode *node); void threadControl_dumpAllThreads() { + tty_message("suspendAllCount: %d", suspendAllCount); tty_message("Dumping runningThreads:"); dumpThreadList(&runningThreads); tty_message("\nDumping runningVThreads:"); @@ -2652,5 +2649,3 @@ dumpThread(ThreadNode *node) { tty_message("\tobjID: %d", commonRef_refToID(getEnv(), node->thread)); #endif } - -#endif /* DEBUG */ diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.h b/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.h index a314ed24bee6c..b7817d359815c 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.h +++ b/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.h @@ -76,11 +76,9 @@ jlong threadControl_getFrameGeneration(jthread thread); jthread *threadControl_allVThreads(jint *numVThreads); -/***** debugging *****/ +/***** APIs for debugging the debug agent *****/ -#ifdef DEBUG void threadControl_dumpAllThreads(); void threadControl_dumpThread(jthread thread); -#endif #endif diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/util.c b/src/jdk.jdwp.agent/share/native/libjdwp/util.c index 0bb7c8837d851..7e198be9a4637 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/util.c +++ b/src/jdk.jdwp.agent/share/native/libjdwp/util.c @@ -1984,8 +1984,6 @@ eventIndex2jvmti(EventIndex ei) return event; } -#ifdef DEBUG - char* eventIndex2EventName(EventIndex ei) { @@ -2040,8 +2038,6 @@ eventIndex2EventName(EventIndex ei) } } -#endif - EventIndex jdwp2EventIndex(jdwpEvent eventType) { diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/util.h b/src/jdk.jdwp.agent/share/native/libjdwp/util.h index c5b8a2b5f519a..75281813709e0 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/util.h +++ b/src/jdk.jdwp.agent/share/native/libjdwp/util.h @@ -90,6 +90,7 @@ typedef struct { jboolean doerrorexit; jboolean modifiedUtf8; jboolean quiet; + jboolean jvmti_data_dump; /* If true, then support JVMTI DATA_DUMP_REQUEST events. */ /* Debug flags (bit mask) */ int debugflags; @@ -389,9 +390,7 @@ void *jvmtiAllocate(jint numBytes); void jvmtiDeallocate(void *buffer); void eventIndexInit(void); -#ifdef DEBUG char* eventIndex2EventName(EventIndex ei); -#endif jdwpEvent eventIndex2jdwp(EventIndex i); jvmtiEvent eventIndex2jvmti(EventIndex i); EventIndex jdwp2EventIndex(jdwpEvent eventType); diff --git a/test/jdk/com/sun/jdi/DataDumpTest.java b/test/jdk/com/sun/jdi/DataDumpTest.java new file mode 100644 index 0000000000000..f46d0d5de4f19 --- /dev/null +++ b/test/jdk/com/sun/jdi/DataDumpTest.java @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.IOException; +import java.io.InputStream; +import java.util.Map; + +import jdk.test.lib.dcmd.PidJcmdExecutor; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +import com.sun.jdi.Bootstrap; +import com.sun.jdi.ClassType; +import com.sun.jdi.VirtualMachine; +import com.sun.jdi.VMDisconnectedException; +import com.sun.jdi.connect.AttachingConnector; +import com.sun.jdi.connect.Connector; +import com.sun.jdi.connect.IllegalConnectorArgumentsException; +import com.sun.jdi.event.ClassPrepareEvent; +import com.sun.jdi.event.Event; +import com.sun.jdi.event.EventSet; +import com.sun.jdi.request.EventRequest; +import com.sun.jdi.request.ClassPrepareRequest; + +/** + * @test + * @bug 8332488 + * @summary Unit test for testing debug agent support for JVMTI.data_dump jcmd. + * + * @library /test/lib + * @modules jdk.jdi + * @run driver DataDumpTest + */ + +class DataDumpTestTarg { + public static void main(String args[]) throws Exception { + // Write something that can be read by the driver + System.out.println("Debuggee started"); + } +} + +public class DataDumpTest { + + public static void main(String[] args) throws Exception { + System.out.println("Test 1: Debuggee start with datadump=y"); + runTest("-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,datadump=y"); + } + + private static void sleep(long ms) { + try { + Thread.sleep(ms); + } catch (InterruptedException e) { + } + } + + private static void runTest(String jdwpArg) throws Exception { + ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( + jdwpArg, + // Probably not required by this test, but best to include when using datadump + "-XX:+StartAttachListener", + "DataDumpTestTarg"); + Process p = null; + OutputAnalyzer out = null; + try { + p = pb.start(); + InputStream is = p.getInputStream(); + out = new OutputAnalyzer(p); + + // Attach a debugger and do the data dump. The data dump output will appear + // in the debuggee output. + attachAndDump(p.pid()); + + out.waitFor(); // Wait for the debuggee to exit + + System.out.println("Deuggee output:"); + System.out.println(out.getOutput()); + + // All these strings are part of the debug agent data dump output. + out.shouldHaveExitValue(0); + out.shouldContain("Debuggee started"); + out.shouldContain("Debug Agent Data Dump"); + out.shouldContain("suspendAllCount: 0"); + out.shouldContain("ClassMatch: classPattern(DataDumpTestTarg)"); + out.shouldContain("Handlers for EI_VM_DEATH"); + } finally { + if (p != null) { + p.destroyForcibly(); + } + } + } + + private static void attachAndDump(long pid) throws IOException, + IllegalConnectorArgumentsException { + // Get the ProcessAttachingConnector, which can attach using the pid of the debuggee. + AttachingConnector ac = Bootstrap.virtualMachineManager().attachingConnectors() + .stream() + .filter(c -> c.name().equals("com.sun.jdi.ProcessAttach")) + .findFirst() + .orElseThrow(() -> new RuntimeException("Unable to locate ProcessAttachingConnector")); + + // Set the connector's "pid" argument to the pid of the debuggee. + Map args = ac.defaultArguments(); + Connector.StringArgument arg = (Connector.StringArgument)args.get("pid"); + arg.setValue("" + pid); + + // Attach to the debuggee. + System.out.println("Debugger is attaching to: " + pid + " ..."); + VirtualMachine vm = ac.attach(args); + + // List all threads as a sanity check. + System.out.println("Attached! Now listing threads ..."); + vm.allThreads().stream().forEach(System.out::println); + + // Request VM to trigger ClassPrepareRequest when DataDumpTestTarg class is prepared. + ClassPrepareRequest classPrepareRequest = vm.eventRequestManager().createClassPrepareRequest(); + classPrepareRequest.addClassFilter("DataDumpTestTarg"); + // Don't use SUSPEND_ALL here. That might prevent the data dump because the + // Signal Dispatcher and Attach Listener threads will be suspended, and they + // may be needed by the jcmd support. + classPrepareRequest.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD); + classPrepareRequest.enable(); + + try { + while (true) { // Exit when we get VMDisconnectedException + EventSet eventSet = vm.eventQueue().remove(); + if (eventSet == null) { + continue; + } + for (Event event : eventSet) { + System.out.println("Received event: " + event); + if (event instanceof ClassPrepareEvent) { + ClassPrepareEvent evt = (ClassPrepareEvent) event; + ClassType classType = (ClassType) evt.referenceType(); + + // Run JVMTI.data_dump jcmd. + OutputAnalyzer out = new PidJcmdExecutor("" + pid).execute("JVMTI.data_dump"); + out.waitFor(); + + // Verify the output of the jcmd. Note the actual dump is in the debuggee + // output, not in the jcmd output, so we don't check it here. + System.out.println("JVMTI.data_dump output:"); + System.out.println(out.getOutput()); + out.shouldContain("Command executed successfully"); + out.shouldHaveExitValue(0); + } + } + eventSet.resume(); + } + } catch (VMDisconnectedException e) { + System.out.println("VM is now disconnected."); + } catch (Exception e) { + e.printStackTrace(); + throw new RuntimeException(e); + } + } +} From aff7936ff088249d1fc787a9f9ef687f987f556c Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Wed, 14 Aug 2024 18:42:59 +0000 Subject: [PATCH 307/353] 8338333: Add jls links to javax.lang.model.element.Modifier Reviewed-by: liach, iris, prappo, vromero, jlahoda --- .../javax/lang/model/element/Modifier.java | 106 ++++++++++++++++-- 1 file changed, 94 insertions(+), 12 deletions(-) diff --git a/src/java.compiler/share/classes/javax/lang/model/element/Modifier.java b/src/java.compiler/share/classes/javax/lang/model/element/Modifier.java index 9dcd8390b60d6..da0195b6cf2d3 100644 --- a/src/java.compiler/share/classes/javax/lang/model/element/Modifier.java +++ b/src/java.compiler/share/classes/javax/lang/model/element/Modifier.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -51,25 +51,68 @@ public enum Modifier { // Note java.lang.reflect.Modifier includes INTERFACE, but that's a VMism. - /** The modifier {@code public} */ PUBLIC, - /** The modifier {@code protected} */ PROTECTED, - /** The modifier {@code private} */ PRIVATE, - /** The modifier {@code abstract} */ ABSTRACT, + /** + * The modifier {@code public} + * + * @jls 6.6 Access Control + */ + PUBLIC, + + /** + * The modifier {@code protected} + * + * @jls 6.6 Access Control + */ + PROTECTED, + + /** + * The modifier {@code private} + * + * @jls 6.6 Access Control + */ + PRIVATE, + + /** + * The modifier {@code abstract} + * + * @jls 8.1.1.1 {@code abstract} Classes + * @jls 8.4.3.1 {@code abstract} Methods + * @jls 9.1.1.1 {@code abstract} Interfaces + */ + ABSTRACT, + /** * The modifier {@code default} + * + * @jls 9.4 Method Declarations * @since 1.8 */ DEFAULT, - /** The modifier {@code static} */ STATIC, + + /** + * The modifier {@code static} + * + * @jls 8.1.1.4 {@code static} Classes + * @jls 8.3.1.1 {@code static} Fields + * @jls 8.4.3.2 {@code static} Methods + * @jls 9.1.1.3 {@code static} Interfaces + */ + STATIC, /** * The modifier {@code sealed} + * + * @jls 8.1.1.2 {@code sealed}, {@code non-sealed}, and {@code final} Classes + * @jls 9.1.1.4 {@code sealed} and {@code non-sealed} Interfaces * @since 17 */ SEALED, /** * The modifier {@code non-sealed} + * + * @jls 8.1.1.2 {@code sealed}, {@code non-sealed}, and {@code final} Classes + * @jls 9.1.1.4 {@code sealed} and {@code non-sealed} Interfaces * @since 17 */ NON_SEALED { @@ -77,12 +120,51 @@ public String toString() { return "non-sealed"; } }, - /** The modifier {@code final} */ FINAL, - /** The modifier {@code transient} */ TRANSIENT, - /** The modifier {@code volatile} */ VOLATILE, - /** The modifier {@code synchronized} */ SYNCHRONIZED, - /** The modifier {@code native} */ NATIVE, - /** The modifier {@code strictfp} */ STRICTFP; + /** + * The modifier {@code final} + * + * @jls 8.1.1.2 {@code sealed}, {@code non-sealed}, and {@code final} Classes + * @jls 8.3.1.2 {@code final} Fields + * @jls 8.4.3.3 {@code final} Methods + */ + FINAL, + + /** + * The modifier {@code transient} + * + * @jls 8.3.1.3 {@code transient} Fields + */ + TRANSIENT, + + /** + * The modifier {@code volatile} + * + * @jls 8.3.1.4 {@code volatile} Fields + */ + VOLATILE, + + /** + * The modifier {@code synchronized} + * + * @jls 8.4.3.6 {@code synchronized} Methods + */ + SYNCHRONIZED, + + /** + * The modifier {@code native} + * + * @jls 8.4.3.4 {@code native} Methods + */ + NATIVE, + + /** + * The modifier {@code strictfp} + * + * @jls 8.1.1.3 {@code strictfp} Classes + * @jls 8.4.3.5 {@code strictfp} Methods + * @jls 9.1.1.2 {@code strictfp} Interfaces + */ + STRICTFP; /** * Returns this modifier's name as defined in The From e3a5e265a7747b02b8f828fbedea0dda7246fc51 Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Wed, 14 Aug 2024 18:55:58 +0000 Subject: [PATCH 308/353] 8338344: Test TestPrivilegedMode.java intermittent fails java.lang.NoClassDefFoundError: jdk/test/lib/Platform Reviewed-by: chagedorn, shade --- .../jtreg/compiler/lib/ir_framework/driver/TestVMProcess.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/TestVMProcess.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/TestVMProcess.java index 8c168b73260cf..feb8fe9e530bf 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/TestVMProcess.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/TestVMProcess.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * 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,7 @@ private void prepareTestVMFlags(List additionalFlags, TestFrameworkSocke String bootClassPath = "-Xbootclasspath/a:."; if (testClassesOnBootClassPath) { // Add test classes themselves to boot classpath to make them privileged. - bootClassPath += File.pathSeparator + Utils.TEST_CLASSES; + bootClassPath += File.pathSeparator + Utils.TEST_CLASS_PATH; } cmds.add(bootClassPath); cmds.add("-XX:+UnlockDiagnosticVMOptions"); From 4669e7b7b02636a8bd7381a9d401aaaf0c1d7294 Mon Sep 17 00:00:00 2001 From: Evgeny Nikitin Date: Thu, 15 Aug 2024 05:36:11 +0000 Subject: [PATCH 309/353] 8337102: JITTester: Fix breaks in static initialization blocks Reviewed-by: kvn, iveresov --- .../jtreg/testlibrary/jittester/conf/default.properties | 2 +- .../factories/StaticConstructorDefinitionFactory.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/hotspot/jtreg/testlibrary/jittester/conf/default.properties b/test/hotspot/jtreg/testlibrary/jittester/conf/default.properties index cd559e5912067..4b0bb7bd3343e 100644 --- a/test/hotspot/jtreg/testlibrary/jittester/conf/default.properties +++ b/test/hotspot/jtreg/testlibrary/jittester/conf/default.properties @@ -8,6 +8,6 @@ classes-file=conf/classes.lst exclude-methods-file=conf/exclude.methods.lst print-complexity=true print-hierarchy=true -disable-static=true +disable-static=false generatorsFactories=jdk.test.lib.jittester.TestGeneratorsFactory generators=JavaCode,ByteCode diff --git a/test/hotspot/jtreg/testlibrary/jittester/src/jdk/test/lib/jittester/factories/StaticConstructorDefinitionFactory.java b/test/hotspot/jtreg/testlibrary/jittester/src/jdk/test/lib/jittester/factories/StaticConstructorDefinitionFactory.java index 0a77fbb7d2c3d..0354559bf67d6 100644 --- a/test/hotspot/jtreg/testlibrary/jittester/src/jdk/test/lib/jittester/factories/StaticConstructorDefinitionFactory.java +++ b/test/hotspot/jtreg/testlibrary/jittester/src/jdk/test/lib/jittester/factories/StaticConstructorDefinitionFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -63,7 +63,7 @@ public StaticConstructorDefinition produce() throws ProductionFailedException { .setOperatorLimit(operatorLimit) .setLevel(level) .setSubBlock(true) - .setCanHaveBreaks(true) + .setCanHaveBreaks(false) .setCanHaveContinues(false) .setCanHaveReturn(false) .getBlockFactory() From 4c344335fe0abc04308f4bfc62c6b3afc110240c Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Thu, 15 Aug 2024 07:39:31 +0000 Subject: [PATCH 310/353] 8338304: clang on Linux - check for lld presence after JDK-8333189 Reviewed-by: erikj, ihse --- make/autoconf/flags-ldflags.m4 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/make/autoconf/flags-ldflags.m4 b/make/autoconf/flags-ldflags.m4 index a2d0d4e606afb..fab8bec789b94 100644 --- a/make/autoconf/flags-ldflags.m4 +++ b/make/autoconf/flags-ldflags.m4 @@ -71,7 +71,9 @@ AC_DEFUN([FLAGS_SETUP_LDFLAGS_HELPER], LDFLAGS_CXX_PARTIAL_LINKING="$MACHINE_FLAG -r" if test "x$OPENJDK_TARGET_OS" = xlinux; then + # Clang needs the lld linker to work correctly BASIC_LDFLAGS="-fuse-ld=lld -Wl,--exclude-libs,ALL" + UTIL_REQUIRE_PROGS(LLD, lld) fi if test "x$OPENJDK_TARGET_OS" = xaix; then BASIC_LDFLAGS="-Wl,-b64 -Wl,-brtl -Wl,-bnorwexec -Wl,-bnolibpath -Wl,-bnoexpall \ From f536f5ab68235d27e9708674f707bcbff7840730 Mon Sep 17 00:00:00 2001 From: Ivan Walulya Date: Thu, 15 Aug 2024 08:26:22 +0000 Subject: [PATCH 311/353] 8336086: G1: Use one G1CardSet instance for all young regions Reviewed-by: tschatzl, ayang --- src/hotspot/share/gc/g1/g1CardSet.cpp | 18 +++++++++- src/hotspot/share/gc/g1/g1CardSet.hpp | 2 ++ src/hotspot/share/gc/g1/g1CollectedHeap.cpp | 9 +++++ src/hotspot/share/gc/g1/g1CollectedHeap.hpp | 12 +++++++ src/hotspot/share/gc/g1/g1CollectionSet.cpp | 2 +- src/hotspot/share/gc/g1/g1ConcurrentMark.cpp | 12 +++++++ src/hotspot/share/gc/g1/g1ConcurrentMark.hpp | 2 ++ .../share/gc/g1/g1ConcurrentRefine.cpp | 14 ++++---- src/hotspot/share/gc/g1/g1FullCollector.cpp | 3 ++ src/hotspot/share/gc/g1/g1HeapRegion.cpp | 4 +++ src/hotspot/share/gc/g1/g1HeapRegion.hpp | 4 +++ .../share/gc/g1/g1HeapRegion.inline.hpp | 8 +++++ .../share/gc/g1/g1HeapRegionRemSet.cpp | 15 +++++++-- .../share/gc/g1/g1HeapRegionRemSet.hpp | 33 +++++++++++++++---- .../share/gc/g1/g1HeapRegionRemSet.inline.hpp | 22 ++++++++----- src/hotspot/share/gc/g1/g1Policy.cpp | 5 +++ src/hotspot/share/gc/g1/g1Policy.hpp | 2 ++ src/hotspot/share/gc/g1/g1RemSet.cpp | 4 +++ src/hotspot/share/gc/g1/g1RemSetSummary.cpp | 11 ++++++- src/hotspot/share/gc/g1/g1YoungCollector.cpp | 15 ++++++--- .../gc/g1/g1YoungGCPostEvacuateTasks.cpp | 9 ++++- 21 files changed, 173 insertions(+), 33 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1CardSet.cpp b/src/hotspot/share/gc/g1/g1CardSet.cpp index 7ab739e0196d0..5c11a1a967700 100644 --- a/src/hotspot/share/gc/g1/g1CardSet.cpp +++ b/src/hotspot/share/gc/g1/g1CardSet.cpp @@ -244,6 +244,10 @@ class G1CardSetHashTable : public CHeapObj { using CHTScanTask = CardSetHash::ScanTask; const static uint BucketClaimSize = 16; + // The claim size for group cardsets should be smaller to facilitate + // better work distribution. The group cardsets should be larger than + // the per region cardsets. + const static uint GroupBucketClaimSize = 4; // Did we insert at least one card in the table? bool volatile _inserted_card; @@ -347,7 +351,15 @@ class G1CardSetHashTable : public CHeapObj { } void reset_table_scanner() { - _table_scanner.set(&_table, BucketClaimSize); + reset_table_scanner(BucketClaimSize); + } + + void reset_table_scanner_for_groups() { + reset_table_scanner(GroupBucketClaimSize); + } + + void reset_table_scanner(uint claim_size) { + _table_scanner.set(&_table, claim_size); } void grow() { @@ -1042,3 +1054,7 @@ void G1CardSet::clear() { void G1CardSet::reset_table_scanner() { _table->reset_table_scanner(); } + +void G1CardSet::reset_table_scanner_for_groups() { + _table->reset_table_scanner_for_groups(); +} diff --git a/src/hotspot/share/gc/g1/g1CardSet.hpp b/src/hotspot/share/gc/g1/g1CardSet.hpp index a9f1859d5c79b..22530ddadaff6 100644 --- a/src/hotspot/share/gc/g1/g1CardSet.hpp +++ b/src/hotspot/share/gc/g1/g1CardSet.hpp @@ -380,6 +380,8 @@ class G1CardSet : public CHeapObj { void reset_table_scanner(); + void reset_table_scanner_for_groups(); + // Iterate over the container, calling a method on every card or card range contained // in the card container. // For every container, first calls diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index aa99fbecbee54..fd73b725a1289 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp @@ -1159,6 +1159,8 @@ G1CollectedHeap::G1CollectedHeap() : _rem_set(nullptr), _card_set_config(), _card_set_freelist_pool(G1CardSetConfiguration::num_mem_object_types()), + _young_regions_cardset_mm(card_set_config(), card_set_freelist_pool()), + _young_regions_cardset(card_set_config(), &_young_regions_cardset_mm), _cm(nullptr), _cm_thread(nullptr), _cr(nullptr), @@ -2693,6 +2695,7 @@ bool G1CollectedHeap::is_old_gc_alloc_region(G1HeapRegion* hr) { void G1CollectedHeap::set_region_short_lived_locked(G1HeapRegion* hr) { _eden.add(hr); _policy->set_region_eden(hr); + hr->install_group_cardset(young_regions_cardset()); } #ifdef ASSERT @@ -2902,6 +2905,8 @@ G1HeapRegion* G1CollectedHeap::new_gc_alloc_region(size_t word_size, G1HeapRegio new_alloc_region->set_survivor(); _survivor.add(new_alloc_region); register_new_survivor_region_with_region_attr(new_alloc_region); + // Install the group cardset. + new_alloc_region->install_group_cardset(young_regions_cardset()); } else { new_alloc_region->set_old(); } @@ -3043,3 +3048,7 @@ void G1CollectedHeap::finish_codecache_marking_cycle() { CodeCache::on_gc_marking_cycle_finish(); CodeCache::arm_all_nmethods(); } + +void G1CollectedHeap::prepare_group_cardsets_for_scan () { + _young_regions_cardset.reset_table_scanner_for_groups(); +} diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp index ea087aae6621f..0f8bf9ffd2b4f 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp @@ -779,7 +779,19 @@ class G1CollectedHeap : public CollectedHeap { G1MonotonicArenaFreePool _card_set_freelist_pool; + // Group cardsets + G1CardSetMemoryManager _young_regions_cardset_mm; + G1CardSet _young_regions_cardset; + public: + G1CardSetConfiguration* card_set_config() { return &_card_set_config; } + + G1CardSet* young_regions_cardset() { return &_young_regions_cardset; }; + + G1CardSetMemoryManager* young_regions_card_set_mm() { return &_young_regions_cardset_mm; } + + void prepare_group_cardsets_for_scan(); + // After a collection pause, reset eden and the collection set. void clear_eden(); void clear_collection_set(); diff --git a/src/hotspot/share/gc/g1/g1CollectionSet.cpp b/src/hotspot/share/gc/g1/g1CollectionSet.cpp index fe4dfafee97bf..d315497268f99 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSet.cpp +++ b/src/hotspot/share/gc/g1/g1CollectionSet.cpp @@ -297,7 +297,7 @@ double G1CollectionSet::finalize_young_part(double target_pause_time_ms, G1Survi verify_young_cset_indices(); - double predicted_base_time_ms = _policy->predict_base_time_ms(pending_cards); + double predicted_base_time_ms = _policy->predict_base_time_ms(pending_cards, _g1h->young_regions_cardset()->occupied()); // Base time already includes the whole remembered set related time, so do not add that here // again. double predicted_eden_time = _policy->predict_young_region_other_time_ms(eden_region_length) + diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp index 3d56973299ee8..52d26418af6cf 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp @@ -2980,6 +2980,7 @@ G1PrintRegionLivenessInfoClosure::G1PrintRegionLivenessInfoClosure(const char* p _total_capacity_bytes(0), _total_live_bytes(0), _total_remset_bytes(0), + _young_cardset_bytes_per_region(0), _total_code_roots_bytes(0) { if (!log_is_enabled(Trace, gc, liveness)) { @@ -2990,6 +2991,13 @@ G1PrintRegionLivenessInfoClosure::G1PrintRegionLivenessInfoClosure(const char* p MemRegion reserved = g1h->reserved(); double now = os::elapsedTime(); + uint num_young_regions = g1h->young_regions_count(); + size_t young_cardset_bytes = g1h->young_regions_cardset()->mem_size(); + + if (num_young_regions > 0) { + _young_cardset_bytes_per_region = young_cardset_bytes / num_young_regions; + } + // Print the header of the output. log_trace(gc, liveness)(G1PPRL_LINE_PREFIX" PHASE %s @ %1.3f", phase_name, now); log_trace(gc, liveness)(G1PPRL_LINE_PREFIX" HEAP" @@ -3041,6 +3049,10 @@ bool G1PrintRegionLivenessInfoClosure::do_heap_region(G1HeapRegion* r) { const char* remset_type = r->rem_set()->get_short_state_str(); FormatBuffer<16> gc_efficiency(""); + if (r->is_young()) { + remset_bytes = _young_cardset_bytes_per_region; + } + _total_used_bytes += used_bytes; _total_capacity_bytes += capacity_bytes; _total_live_bytes += live_bytes; diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp index 918384372bbb8..b197afc65eefc 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp @@ -958,6 +958,8 @@ class G1PrintRegionLivenessInfoClosure : public G1HeapRegionClosure { // Accumulator for the remembered set size size_t _total_remset_bytes; + size_t _young_cardset_bytes_per_region; + // Accumulator for code roots memory size size_t _total_code_roots_bytes; diff --git a/src/hotspot/share/gc/g1/g1ConcurrentRefine.cpp b/src/hotspot/share/gc/g1/g1ConcurrentRefine.cpp index 7d6cc9a41cb64..8357737ef6a7d 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentRefine.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentRefine.cpp @@ -254,21 +254,18 @@ uint64_t G1ConcurrentRefine::adjust_threads_wait_ms() const { } class G1ConcurrentRefine::RemSetSamplingClosure : public G1HeapRegionClosure { - size_t _sampled_card_rs_length; size_t _sampled_code_root_rs_length; public: RemSetSamplingClosure() : - _sampled_card_rs_length(0), _sampled_code_root_rs_length(0) {} + _sampled_code_root_rs_length(0) {} bool do_heap_region(G1HeapRegion* r) override { G1HeapRegionRemSet* rem_set = r->rem_set(); - _sampled_card_rs_length += rem_set->occupied(); _sampled_code_root_rs_length += rem_set->code_roots_list_length(); return false; } - size_t sampled_card_rs_length() const { return _sampled_card_rs_length; } size_t sampled_code_root_rs_length() const { return _sampled_code_root_rs_length; } }; @@ -286,10 +283,15 @@ class G1ConcurrentRefine::RemSetSamplingClosure : public G1HeapRegionClosure { // gen size to keep pause time length goal. void G1ConcurrentRefine::adjust_young_list_target_length() { if (_policy->use_adaptive_young_list_length()) { + G1CollectedHeap* g1h = G1CollectedHeap::heap(); + G1CollectionSet* cset = g1h->collection_set(); RemSetSamplingClosure cl; - G1CollectionSet* cset = G1CollectedHeap::heap()->collection_set(); cset->iterate(&cl); - _policy->revise_young_list_target_length(cl.sampled_card_rs_length(), cl.sampled_code_root_rs_length()); + + size_t card_rs_length = g1h->young_regions_cardset()->occupied(); + + size_t sampled_code_root_rs_length = cl.sampled_code_root_rs_length(); + _policy->revise_young_list_target_length(card_rs_length, sampled_code_root_rs_length); } } diff --git a/src/hotspot/share/gc/g1/g1FullCollector.cpp b/src/hotspot/share/gc/g1/g1FullCollector.cpp index 219480227d3fd..4c66c526151b9 100644 --- a/src/hotspot/share/gc/g1/g1FullCollector.cpp +++ b/src/hotspot/share/gc/g1/g1FullCollector.cpp @@ -172,6 +172,7 @@ class PrepareRegionsClosure : public G1HeapRegionClosure { bool do_heap_region(G1HeapRegion* hr) { hr->prepare_for_full_gc(); + hr->uninstall_group_cardset(); G1CollectedHeap::heap()->prepare_region_for_full_compaction(hr); _collector->before_marking_update_attribute_table(hr); return false; @@ -247,6 +248,8 @@ void G1FullCollector::complete_collection() { _heap->resize_all_tlabs(); + _heap->young_regions_cardset()->clear(); + _heap->policy()->record_full_collection_end(); _heap->gc_epilogue(true); diff --git a/src/hotspot/share/gc/g1/g1HeapRegion.cpp b/src/hotspot/share/gc/g1/g1HeapRegion.cpp index 9851b1df9c9b5..9cb2650f8208c 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegion.cpp +++ b/src/hotspot/share/gc/g1/g1HeapRegion.cpp @@ -119,6 +119,7 @@ void G1HeapRegion::hr_clear(bool clear_space) { clear_young_index_in_cset(); clear_index_in_opt_cset(); uninstall_surv_rate_group(); + uninstall_group_cardset(); set_free(); reset_pre_dummy_top(); @@ -215,6 +216,9 @@ void G1HeapRegion::clear_humongous() { } void G1HeapRegion::prepare_remset_for_scan() { + if (is_young()) { + uninstall_group_cardset(); + } _rem_set->reset_table_scanner(); } diff --git a/src/hotspot/share/gc/g1/g1HeapRegion.hpp b/src/hotspot/share/gc/g1/g1HeapRegion.hpp index ed953094a679f..c17183d40344b 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegion.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegion.hpp @@ -36,6 +36,7 @@ #include "runtime/mutex.hpp" #include "utilities/macros.hpp" +class G1CardSet; class G1CardSetConfiguration; class G1CollectedHeap; class G1CMBitMap; @@ -508,6 +509,9 @@ class G1HeapRegion : public CHeapObj { void install_surv_rate_group(G1SurvRateGroup* surv_rate_group); void uninstall_surv_rate_group(); + void install_group_cardset(G1CardSet* group_cardset); + void uninstall_group_cardset(); + void record_surv_words_in_group(size_t words_survived); // Determine if an address is in the parsable or the to-be-scrubbed area. diff --git a/src/hotspot/share/gc/g1/g1HeapRegion.inline.hpp b/src/hotspot/share/gc/g1/g1HeapRegion.inline.hpp index f31c5fb553e29..4a87c5f25141d 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegion.inline.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegion.inline.hpp @@ -511,4 +511,12 @@ inline void G1HeapRegion::add_pinned_object_count(size_t value) { Atomic::add(&_pinned_object_count, value, memory_order_relaxed); } +inline void G1HeapRegion::install_group_cardset(G1CardSet* group_cardset) { + _rem_set->install_group_cardset(group_cardset); +} + +inline void G1HeapRegion::uninstall_group_cardset() { + _rem_set->uninstall_group_cardset(); +} + #endif // SHARE_GC_G1_G1HEAPREGION_INLINE_HPP diff --git a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.cpp b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.cpp index 6e98b64adbc24..fe1590b94a839 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.cpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.cpp @@ -55,11 +55,19 @@ void G1HeapRegionRemSet::initialize(MemRegion reserved) { _heap_base_address = reserved.start(); } +void G1HeapRegionRemSet::uninstall_group_cardset() { + if (_saved_card_set != nullptr) { + _card_set = _saved_card_set; + _saved_card_set = nullptr; + } +} + G1HeapRegionRemSet::G1HeapRegionRemSet(G1HeapRegion* hr, G1CardSetConfiguration* config) : _code_roots(), _card_set_mm(config, G1CollectedHeap::heap()->card_set_freelist_pool()), - _card_set(config, &_card_set_mm), + _card_set(new G1CardSet(config, &_card_set_mm)), + _saved_card_set(nullptr), _hr(hr), _state(Untracked) { } @@ -68,11 +76,12 @@ void G1HeapRegionRemSet::clear_fcc() { } void G1HeapRegionRemSet::clear(bool only_cardset, bool keep_tracked) { + assert(_saved_card_set == nullptr, "pre-condition"); if (!only_cardset) { _code_roots.clear(); } clear_fcc(); - _card_set.clear(); + _card_set->clear(); if (!keep_tracked) { set_state_untracked(); } else { @@ -83,7 +92,7 @@ void G1HeapRegionRemSet::clear(bool only_cardset, bool keep_tracked) { void G1HeapRegionRemSet::reset_table_scanner() { _code_roots.reset_table_scanner(); - _card_set.reset_table_scanner(); + _card_set->reset_table_scanner(); } G1MonotonicArenaMemoryStats G1HeapRegionRemSet::card_set_memory_stats() const { diff --git a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp index e92ecdc9cf9b0..843eb76bbc9c9 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp @@ -47,7 +47,8 @@ class G1HeapRegionRemSet : public CHeapObj { G1CardSetMemoryManager _card_set_mm; // The set of cards in the Java heap - G1CardSet _card_set; + G1CardSet* _card_set; + G1CardSet* _saved_card_set; G1HeapRegion* _hr; @@ -58,9 +59,24 @@ class G1HeapRegionRemSet : public CHeapObj { public: G1HeapRegionRemSet(G1HeapRegion* hr, G1CardSetConfiguration* config); + ~G1HeapRegionRemSet() { delete _card_set; } bool cardset_is_empty() const { - return _card_set.is_empty(); + return _card_set->is_empty(); + } + + void install_group_cardset(G1CardSet* group_cardset) { + assert(group_cardset != nullptr, "pre-condition"); + assert(_saved_card_set == nullptr, "pre-condition"); + + _saved_card_set = _card_set; + _card_set = group_cardset; + } + + void uninstall_group_cardset(); + + bool has_group_cardset() { + return _saved_card_set != nullptr; } bool is_empty() const { @@ -68,7 +84,7 @@ class G1HeapRegionRemSet : public CHeapObj { } bool occupancy_less_or_equal_than(size_t occ) const { - return (code_roots_list_length() == 0) && _card_set.occupancy_less_or_equal_to(occ); + return (code_roots_list_length() == 0) && _card_set->occupancy_less_or_equal_to(occ); } // Iterate the card based remembered set for merging them into the card table. @@ -77,10 +93,15 @@ class G1HeapRegionRemSet : public CHeapObj { template inline void iterate_for_merge(CardOrRangeVisitor& cl); + template + inline static void iterate_for_merge(G1CardSet* card_set, CardOrRangeVisitor& cl); + size_t occupied() { - return _card_set.occupied(); + return _card_set->occupied(); } + G1CardSet* card_set() { return _card_set; } + static void initialize(MemRegion reserved); // Coarsening statistics since VM start. @@ -125,13 +146,13 @@ class G1HeapRegionRemSet : public CHeapObj { // The actual # of bytes this hr_remset takes up. Also includes the code // root set. size_t mem_size() { - return _card_set.mem_size() + return _card_set->mem_size() + (sizeof(G1HeapRegionRemSet) - sizeof(G1CardSet)) // Avoid double-counting G1CardSet. + code_roots_mem_size(); } size_t unused_mem_size() { - return _card_set.unused_mem_size(); + return _card_set->unused_mem_size(); } // Returns the memory occupancy of all static data structures associated diff --git a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.inline.hpp b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.inline.hpp index 457027ad1260a..0df9874e9dd91 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.inline.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.inline.hpp @@ -108,13 +108,17 @@ class G1HeapRegionRemSetMergeCardClosure : public G1CardSet::ContainerPtrClosure template inline void G1HeapRegionRemSet::iterate_for_merge(CardOrRangeVisitor& cl) { - G1HeapRegionRemSetMergeCardClosure cl2(&_card_set, - cl, - _card_set.config()->log2_card_regions_per_heap_region(), - _card_set.config()->log2_cards_per_card_region()); - _card_set.iterate_containers(&cl2, true /* at_safepoint */); + iterate_for_merge(_card_set, cl); } +template +void G1HeapRegionRemSet::iterate_for_merge(G1CardSet* card_set, CardOrRangeVisitor& cl) { + G1HeapRegionRemSetMergeCardClosure cl2(card_set, + cl, + card_set->config()->log2_card_regions_per_heap_region(), + card_set->config()->log2_cards_per_card_region()); + card_set->iterate_containers(&cl2, true /* at_safepoint */); +} uintptr_t G1HeapRegionRemSet::to_card(OopOrNarrowOopStar from) const { return pointer_delta(from, _heap_base_address, 1) >> CardTable::card_shift(); @@ -130,18 +134,18 @@ void G1HeapRegionRemSet::add_reference(OopOrNarrowOopStar from, uint tid) { // We can't check whether the card is in the remembered set - the card container // may be coarsened just now. //assert(contains_reference(from), "We just found " PTR_FORMAT " in the FromCardCache", p2i(from)); - return; + return; } - _card_set.add_card(to_card(from)); + _card_set->add_card(to_card(from)); } bool G1HeapRegionRemSet::contains_reference(OopOrNarrowOopStar from) { - return _card_set.contains_card(to_card(from)); + return _card_set->contains_card(to_card(from)); } void G1HeapRegionRemSet::print_info(outputStream* st, OopOrNarrowOopStar from) { - _card_set.print_info(st, to_card(from)); + _card_set->print_info(st, to_card(from)); } #endif // SHARE_VM_GC_G1_G1HEAPREGIONREMSET_INLINE_HPP diff --git a/src/hotspot/share/gc/g1/g1Policy.cpp b/src/hotspot/share/gc/g1/g1Policy.cpp index 7d0acd3a326da..e7e57c962c734 100644 --- a/src/hotspot/share/gc/g1/g1Policy.cpp +++ b/src/hotspot/share/gc/g1/g1Policy.cpp @@ -1089,6 +1089,11 @@ double G1Policy::predict_base_time_ms(size_t pending_cards, double G1Policy::predict_base_time_ms(size_t pending_cards) const { bool for_young_only_phase = collector_state()->in_young_only_phase(); size_t card_rs_length = _analytics->predict_card_rs_length(for_young_only_phase); + return predict_base_time_ms(pending_cards, card_rs_length); +} + +double G1Policy::predict_base_time_ms(size_t pending_cards, size_t card_rs_length) const { + bool for_young_only_phase = collector_state()->in_young_only_phase(); size_t code_root_rs_length = _analytics->predict_code_root_rs_length(for_young_only_phase); return predict_base_time_ms(pending_cards, card_rs_length, code_root_rs_length); } diff --git a/src/hotspot/share/gc/g1/g1Policy.hpp b/src/hotspot/share/gc/g1/g1Policy.hpp index 9de27e76d9622..98d444084678c 100644 --- a/src/hotspot/share/gc/g1/g1Policy.hpp +++ b/src/hotspot/share/gc/g1/g1Policy.hpp @@ -138,6 +138,8 @@ class G1Policy: public CHeapObj { double predict_base_time_ms(size_t pending_cards) const; + double predict_base_time_ms(size_t pending_cards, size_t card_rs_length) const; + private: // Base time contains handling remembered sets and constant other time of the // whole young gen, refinement buffers, and copying survivors. diff --git a/src/hotspot/share/gc/g1/g1RemSet.cpp b/src/hotspot/share/gc/g1/g1RemSet.cpp index 0f9b9d17df7b3..f5f65cf1c48aa 100644 --- a/src/hotspot/share/gc/g1/g1RemSet.cpp +++ b/src/hotspot/share/gc/g1/g1RemSet.cpp @@ -1379,6 +1379,10 @@ class G1MergeHeapRootsTask : public WorkerTask { G1ClearBitmapClosure clear(g1h); G1CombinedClosure combined(&merge, &clear); + if (_initial_evacuation) { + G1HeapRegionRemSet::iterate_for_merge(g1h->young_regions_cardset(), merge); + } + g1h->collection_set_iterate_increment_from(&combined, nullptr, worker_id); G1MergeCardSetStats stats = merge.stats(); diff --git a/src/hotspot/share/gc/g1/g1RemSetSummary.cpp b/src/hotspot/share/gc/g1/g1RemSetSummary.cpp index 14fb8c0b8d273..5ea3500a7b0f7 100644 --- a/src/hotspot/share/gc/g1/g1RemSetSummary.cpp +++ b/src/hotspot/share/gc/g1/g1RemSetSummary.cpp @@ -218,15 +218,24 @@ class HRRSStatsIter: public G1HeapRegionClosure { bool do_heap_region(G1HeapRegion* r) { G1HeapRegionRemSet* hrrs = r->rem_set(); + size_t occupied_cards = hrrs->occupied(); // G1HeapRegionRemSet::mem_size() includes the // size of the code roots size_t rs_unused_mem_sz = hrrs->unused_mem_size(); size_t rs_mem_sz = hrrs->mem_size(); + + if (r->is_young()) { + uint num_young = G1CollectedHeap::heap()->young_regions_count(); + occupied_cards /= num_young; + rs_unused_mem_sz /= num_young; + rs_mem_sz /= num_young; + } + if (rs_mem_sz > _max_rs_mem_sz) { _max_rs_mem_sz = rs_mem_sz; _max_rs_mem_sz_region = r; } - size_t occupied_cards = hrrs->occupied(); + size_t code_root_mem_sz = hrrs->code_roots_mem_size(); if (code_root_mem_sz > max_code_root_mem_sz()) { _max_code_root_mem_sz = code_root_mem_sz; diff --git a/src/hotspot/share/gc/g1/g1YoungCollector.cpp b/src/hotspot/share/gc/g1/g1YoungCollector.cpp index cadab2fbc489d..f2fe93015c532 100644 --- a/src/hotspot/share/gc/g1/g1YoungCollector.cpp +++ b/src/hotspot/share/gc/g1/g1YoungCollector.cpp @@ -295,10 +295,9 @@ class G1PrepareEvacuationTask : public WorkerTask { G1MonotonicArenaMemoryStats _card_set_stats; void sample_card_set_size(G1HeapRegion* hr) { - // Sample card set sizes for young gen and humongous before GC: this makes - // the policy to give back memory to the OS keep the most recent amount of - // memory for these regions. - if (hr->is_young() || hr->is_starts_humongous()) { + // Sample card set sizes for humongous before GC: this makes the policy to give + // back memory to the OS keep the most recent amount of memory for these regions. + if (hr->is_starts_humongous()) { _card_set_stats.add(hr->rem_set()->card_set_memory_stats()); } } @@ -507,6 +506,9 @@ void G1YoungCollector::pre_evacuate_collection_set(G1EvacInfo* evacuation_info) { Ticks start = Ticks::now(); rem_set()->prepare_for_scan_heap_roots(); + + _g1h->prepare_group_cardsets_for_scan(); + phase_times()->record_prepare_heap_roots_time_ms((Ticks::now() - start).seconds() * 1000.0); } @@ -514,7 +516,10 @@ void G1YoungCollector::pre_evacuate_collection_set(G1EvacInfo* evacuation_info) G1PrepareEvacuationTask g1_prep_task(_g1h); Tickspan task_time = run_task_timed(&g1_prep_task); - _g1h->set_young_gen_card_set_stats(g1_prep_task.all_card_set_stats()); + G1MonotonicArenaMemoryStats sampled_card_set_stats = g1_prep_task.all_card_set_stats(); + sampled_card_set_stats.add(_g1h->young_regions_card_set_mm()->memory_stats()); + _g1h->set_young_gen_card_set_stats(sampled_card_set_stats); + _g1h->set_humongous_stats(g1_prep_task.humongous_total(), g1_prep_task.humongous_candidates()); phase_times()->record_register_regions(task_time.seconds() * 1000.0); diff --git a/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp b/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp index e1f0df05c2227..a0e9a9b1569ab 100644 --- a/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp +++ b/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp @@ -673,6 +673,10 @@ class FreeCSetStats { G1Policy *policy = g1h->policy(); policy->old_gen_alloc_tracker()->add_allocated_bytes_since_last_gc(_bytes_allocated_in_old_since_last_gc); + + // Add the cards from the group cardsets. + _card_rs_length += g1h->young_regions_cardset()->occupied(); + policy->record_card_rs_length(_card_rs_length); policy->cset_regions_freed(); } @@ -822,9 +826,10 @@ class FreeCSetClosure : public G1HeapRegionClosure { JFREventForRegion event(r, _worker_id); TimerForRegion timer(timer_for_region(r)); - stats()->account_card_rs_length(r); if (r->is_young()) { + // We only use card_rs_length statistics to estimate young regions length. + stats()->account_card_rs_length(r); assert_tracks_surviving_words(r); r->record_surv_words_in_group(_surviving_young_words[r->young_index_in_cset()]); } @@ -911,6 +916,8 @@ class G1PostEvacuateCollectionSetCleanupTask2::FreeCollectionSetTask : public G1 p->record_serial_free_cset_time_ms((Ticks::now() - serial_time).seconds() * 1000.0); _g1h->clear_collection_set(); + + _g1h->young_regions_cardset()->clear(); } double worker_cost() const override { return G1CollectedHeap::heap()->collection_set()->region_length(); } From da7311bbe37c2b9632b117d52a77c659047820b7 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Thu, 15 Aug 2024 08:50:29 +0000 Subject: [PATCH 312/353] 8338286: GHA: Demote x86_32 to hotspot build only Reviewed-by: ihse --- .github/workflows/main.yml | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 6a1b4420e3ad7..1dc0b25c3458f 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -36,7 +36,7 @@ on: platforms: description: 'Platform(s) to execute on (comma separated, e.g. "linux-x64, macos, aarch64")' required: true - default: 'linux-x64, linux-x86, linux-x64-variants, linux-cross-compile, macos-x64, macos-aarch64, windows-x64, windows-aarch64, docs' + default: 'linux-x64, linux-x86-hs, linux-x64-variants, linux-cross-compile, macos-x64, macos-aarch64, windows-x64, windows-aarch64, docs' configure-arguments: description: 'Additional configure arguments' required: false @@ -59,7 +59,7 @@ jobs: runs-on: ubuntu-22.04 outputs: linux-x64: ${{ steps.include.outputs.linux-x64 }} - linux-x86: ${{ steps.include.outputs.linux-x86 }} + linux-x86-hs: ${{ steps.include.outputs.linux-x86-hs }} linux-x64-variants: ${{ steps.include.outputs.linux-x64-variants }} linux-cross-compile: ${{ steps.include.outputs.linux-cross-compile }} macos-x64: ${{ steps.include.outputs.macos-x64 }} @@ -111,7 +111,7 @@ jobs: } echo "linux-x64=$(check_platform linux-x64 linux x64)" >> $GITHUB_OUTPUT - echo "linux-x86=$(check_platform linux-x86 linux x86)" >> $GITHUB_OUTPUT + echo "linux-x86-hs=$(check_platform linux-x86-hs linux x86)" >> $GITHUB_OUTPUT echo "linux-x64-variants=$(check_platform linux-x64-variants variants)" >> $GITHUB_OUTPUT echo "linux-cross-compile=$(check_platform linux-cross-compile cross-compile)" >> $GITHUB_OUTPUT echo "macos-x64=$(check_platform macos-x64 macos x64)" >> $GITHUB_OUTPUT @@ -135,12 +135,13 @@ jobs: make-arguments: ${{ github.event.inputs.make-arguments }} if: needs.select.outputs.linux-x64 == 'true' - build-linux-x86: - name: linux-x86 + build-linux-x86-hs: + name: linux-x86-hs needs: select uses: ./.github/workflows/build-linux.yml with: platform: linux-x86 + make-target: 'hotspot' gcc-major-version: '10' gcc-package-suffix: '-multilib' apt-architecture: 'i386' @@ -150,7 +151,7 @@ jobs: extra-conf-options: '--with-target-bits=32 --enable-fallback-linker --enable-libffi-bundling' configure-arguments: ${{ github.event.inputs.configure-arguments }} make-arguments: ${{ github.event.inputs.make-arguments }} - if: needs.select.outputs.linux-x86 == 'true' + if: needs.select.outputs.linux-x86-hs == 'true' build-linux-x64-hs-nopch: name: linux-x64-hs-nopch @@ -300,16 +301,6 @@ jobs: bootjdk-platform: linux-x64 runs-on: ubuntu-22.04 - test-linux-x86: - name: linux-x86 - needs: - - build-linux-x86 - uses: ./.github/workflows/test.yml - with: - platform: linux-x86 - bootjdk-platform: linux-x64 - runs-on: ubuntu-22.04 - test-macos-x64: name: macos-x64 needs: @@ -347,7 +338,7 @@ jobs: if: always() needs: - build-linux-x64 - - build-linux-x86 + - build-linux-x86-hs - build-linux-x64-hs-nopch - build-linux-x64-hs-zero - build-linux-x64-hs-minimal @@ -358,7 +349,6 @@ jobs: - build-windows-x64 - build-windows-aarch64 - test-linux-x64 - - test-linux-x86 - test-macos-x64 - test-windows-x64 From 74fdd6868d3f71d44ef9f71a0ca9506c04d39148 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Thu, 15 Aug 2024 11:24:22 +0000 Subject: [PATCH 313/353] 8333791: Fix memory barriers for @Stable fields Reviewed-by: liach, vlivanov --- src/hotspot/share/c1/c1_GraphBuilder.cpp | 12 +- src/hotspot/share/c1/c1_IR.cpp | 1 + src/hotspot/share/c1/c1_IR.hpp | 3 + src/hotspot/share/opto/parse.hpp | 10 +- src/hotspot/share/opto/parse1.cpp | 29 +-- src/hotspot/share/opto/parse3.cpp | 21 +- .../irTests/stable/StablePrimArrayTest.java | 170 +++++++++++++++++ .../irTests/stable/StablePrimFinalTest.java | 100 ++++++++++ .../irTests/stable/StablePrimPlainTest.java | 114 +++++++++++ .../stable/StablePrimVolatileTest.java | 114 +++++++++++ .../c2/irTests/stable/StableRefArrayTest.java | 179 ++++++++++++++++++ .../c2/irTests/stable/StableRefFinalTest.java | 97 ++++++++++ .../c2/irTests/stable/StableRefPlainTest.java | 118 ++++++++++++ .../irTests/stable/StableRefVolatileTest.java | 118 ++++++++++++ 14 files changed, 1047 insertions(+), 39 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/c2/irTests/stable/StablePrimArrayTest.java create mode 100644 test/hotspot/jtreg/compiler/c2/irTests/stable/StablePrimFinalTest.java create mode 100644 test/hotspot/jtreg/compiler/c2/irTests/stable/StablePrimPlainTest.java create mode 100644 test/hotspot/jtreg/compiler/c2/irTests/stable/StablePrimVolatileTest.java create mode 100644 test/hotspot/jtreg/compiler/c2/irTests/stable/StableRefArrayTest.java create mode 100644 test/hotspot/jtreg/compiler/c2/irTests/stable/StableRefFinalTest.java create mode 100644 test/hotspot/jtreg/compiler/c2/irTests/stable/StableRefPlainTest.java create mode 100644 test/hotspot/jtreg/compiler/c2/irTests/stable/StableRefVolatileTest.java diff --git a/src/hotspot/share/c1/c1_GraphBuilder.cpp b/src/hotspot/share/c1/c1_GraphBuilder.cpp index 0493b0458cd66..780ced7f433b2 100644 --- a/src/hotspot/share/c1/c1_GraphBuilder.cpp +++ b/src/hotspot/share/c1/c1_GraphBuilder.cpp @@ -1563,7 +1563,7 @@ void GraphBuilder::method_return(Value x, bool ignore_return) { // The conditions for a memory barrier are described in Parse::do_exits(). bool need_mem_bar = false; if (method()->name() == ciSymbols::object_initializer_name() && - (scope()->wrote_final() || + (scope()->wrote_final() || scope()->wrote_stable() || (AlwaysSafeConstructors && scope()->wrote_fields()) || (support_IRIW_for_not_multiple_copy_atomic_cpu && scope()->wrote_volatile()))) { need_mem_bar = true; @@ -1741,15 +1741,17 @@ void GraphBuilder::access_field(Bytecodes::Code code) { } } - if (field->is_final() && (code == Bytecodes::_putfield)) { - scope()->set_wrote_final(); - } - if (code == Bytecodes::_putfield) { scope()->set_wrote_fields(); if (field->is_volatile()) { scope()->set_wrote_volatile(); } + if (field->is_final()) { + scope()->set_wrote_final(); + } + if (field->is_stable()) { + scope()->set_wrote_stable(); + } } const int offset = !needs_patching ? field->offset_in_bytes() : -1; diff --git a/src/hotspot/share/c1/c1_IR.cpp b/src/hotspot/share/c1/c1_IR.cpp index e375d16aafb18..b3faa54cc69b8 100644 --- a/src/hotspot/share/c1/c1_IR.cpp +++ b/src/hotspot/share/c1/c1_IR.cpp @@ -146,6 +146,7 @@ IRScope::IRScope(Compilation* compilation, IRScope* caller, int caller_bci, ciMe _wrote_final = false; _wrote_fields = false; _wrote_volatile = false; + _wrote_stable = false; _start = nullptr; if (osr_bci != -1) { diff --git a/src/hotspot/share/c1/c1_IR.hpp b/src/hotspot/share/c1/c1_IR.hpp index 3035643708a81..e2582c77b3921 100644 --- a/src/hotspot/share/c1/c1_IR.hpp +++ b/src/hotspot/share/c1/c1_IR.hpp @@ -149,6 +149,7 @@ class IRScope: public CompilationResourceObj { bool _wrote_final; // has written final field bool _wrote_fields; // has written fields bool _wrote_volatile; // has written volatile field + bool _wrote_stable; // has written @Stable field BlockBegin* _start; // the start block, successsors are method entries ResourceBitMap _requires_phi_function; // bit is set if phi functions at loop headers are necessary for a local variable @@ -187,6 +188,8 @@ class IRScope: public CompilationResourceObj { bool wrote_fields () const { return _wrote_fields; } void set_wrote_volatile() { _wrote_volatile = true; } bool wrote_volatile () const { return _wrote_volatile; } + void set_wrote_stable() { _wrote_stable = true; } + bool wrote_stable() const { return _wrote_stable; } }; diff --git a/src/hotspot/share/opto/parse.hpp b/src/hotspot/share/opto/parse.hpp index a55c9cb0cb12e..a2690aa6704f0 100644 --- a/src/hotspot/share/opto/parse.hpp +++ b/src/hotspot/share/opto/parse.hpp @@ -358,7 +358,7 @@ class Parse : public GraphKit { bool _wrote_volatile; // Did we write a volatile field? bool _wrote_stable; // Did we write a @Stable field? bool _wrote_fields; // Did we write any field? - Node* _alloc_with_final; // An allocation node with final field + Node* _alloc_with_final_or_stable; // An allocation node with final or @Stable field // Variables which track Java semantics during bytecode parsing: @@ -403,10 +403,10 @@ class Parse : public GraphKit { void set_wrote_stable(bool z) { _wrote_stable = z; } bool wrote_fields() const { return _wrote_fields; } void set_wrote_fields(bool z) { _wrote_fields = z; } - Node* alloc_with_final() const { return _alloc_with_final; } - void set_alloc_with_final(Node* n) { - assert((_alloc_with_final == nullptr) || (_alloc_with_final == n), "different init objects?"); - _alloc_with_final = n; + Node* alloc_with_final_or_stable() const { return _alloc_with_final_or_stable; } + void set_alloc_with_final_or_stable(Node* n) { + assert((_alloc_with_final_or_stable == nullptr) || (_alloc_with_final_or_stable == n), "different init objects?"); + _alloc_with_final_or_stable = n; } Block* block() const { return _block; } diff --git a/src/hotspot/share/opto/parse1.cpp b/src/hotspot/share/opto/parse1.cpp index 14ef93a5eed8c..05627450585ff 100644 --- a/src/hotspot/share/opto/parse1.cpp +++ b/src/hotspot/share/opto/parse1.cpp @@ -412,7 +412,7 @@ Parse::Parse(JVMState* caller, ciMethod* parse_method, float expected_uses) _wrote_volatile = false; _wrote_stable = false; _wrote_fields = false; - _alloc_with_final = nullptr; + _alloc_with_final_or_stable = nullptr; _block = nullptr; _first_return = true; _replaced_nodes_for_exceptions = false; @@ -988,8 +988,8 @@ void Parse::do_exits() { // Figure out if we need to emit the trailing barrier. The barrier is only // needed in the constructors, and only in three cases: // - // 1. The constructor wrote a final. The effects of all initializations - // must be committed to memory before any code after the constructor + // 1. The constructor wrote a final or a @Stable field. All these + // initializations must be ordered before any code after the constructor // publishes the reference to the newly constructed object. Rather // than wait for the publication, we simply block the writes here. // Rather than put a barrier on only those writes which are required @@ -1014,34 +1014,23 @@ void Parse::do_exits() { // exceptional returns, since they cannot publish normally. // if (method()->is_object_initializer() && - (wrote_final() || + (wrote_final() || wrote_stable() || (AlwaysSafeConstructors && wrote_fields()) || (support_IRIW_for_not_multiple_copy_atomic_cpu && wrote_volatile()))) { + Node* recorded_alloc = alloc_with_final_or_stable(); _exits.insert_mem_bar(UseStoreStoreForCtor ? Op_MemBarStoreStore : Op_MemBarRelease, - alloc_with_final()); + recorded_alloc); // If Memory barrier is created for final fields write // and allocation node does not escape the initialize method, // then barrier introduced by allocation node can be removed. - if (DoEscapeAnalysis && alloc_with_final()) { - AllocateNode* alloc = AllocateNode::Ideal_allocation(alloc_with_final()); + if (DoEscapeAnalysis && (recorded_alloc != nullptr)) { + AllocateNode* alloc = AllocateNode::Ideal_allocation(recorded_alloc); alloc->compute_MemBar_redundancy(method()); } if (PrintOpto && (Verbose || WizardMode)) { method()->print_name(); - tty->print_cr(" writes finals and needs a memory barrier"); - } - } - - // Any method can write a @Stable field; insert memory barriers - // after those also. Can't bind predecessor allocation node (if any) - // with barrier because allocation doesn't always dominate - // MemBarRelease. - if (wrote_stable()) { - _exits.insert_mem_bar(Op_MemBarRelease); - if (PrintOpto && (Verbose || WizardMode)) { - method()->print_name(); - tty->print_cr(" writes @Stable and needs a memory barrier"); + tty->print_cr(" writes finals/@Stable and needs a memory barrier"); } } diff --git a/src/hotspot/share/opto/parse3.cpp b/src/hotspot/share/opto/parse3.cpp index a2bf653b17651..a9fad4e3633e6 100644 --- a/src/hotspot/share/opto/parse3.cpp +++ b/src/hotspot/share/opto/parse3.cpp @@ -236,22 +236,25 @@ void Parse::do_put_xxx(Node* obj, ciField* field, bool is_field) { set_wrote_fields(true); // If the field is final, the rules of Java say we are in or . - // Note the presence of writes to final non-static fields, so that we + // If the field is @Stable, we can be in any method, but we only care about + // constructors at this point. + // + // Note the presence of writes to final/@Stable non-static fields, so that we // can insert a memory barrier later on to keep the writes from floating // out of the constructor. - // Any method can write a @Stable field; insert memory barriers after those also. - if (field->is_final()) { - set_wrote_final(true); + if (field->is_final() || field->is_stable()) { + if (field->is_final()) { + set_wrote_final(true); + } + if (field->is_stable()) { + set_wrote_stable(true); + } if (AllocateNode::Ideal_allocation(obj) != nullptr) { // Preserve allocation ptr to create precedent edge to it in membar // generated on exit from constructor. - // Can't bind stable with its allocation, only record allocation for final field. - set_alloc_with_final(obj); + set_alloc_with_final_or_stable(obj); } } - if (field->is_stable()) { - set_wrote_stable(true); - } } } diff --git a/test/hotspot/jtreg/compiler/c2/irTests/stable/StablePrimArrayTest.java b/test/hotspot/jtreg/compiler/c2/irTests/stable/StablePrimArrayTest.java new file mode 100644 index 0000000000000..24733700f81de --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/irTests/stable/StablePrimArrayTest.java @@ -0,0 +1,170 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8333791 + * @requires os.arch=="aarch64" | os.arch=="riscv64" | os.arch=="x86_64" | os.arch=="amd64" + * @requires vm.gc.Parallel + * @requires vm.compiler2.enabled + * @summary Check stable field folding and barriers + * @modules java.base/jdk.internal.vm.annotation + * @library /test/lib / + * @run driver compiler.c2.irTests.stable.StablePrimArrayTest + */ + +package compiler.c2.irTests.stable; + +import compiler.lib.ir_framework.*; +import jdk.test.lib.Asserts; + +import jdk.internal.vm.annotation.Stable; + +public class StablePrimArrayTest { + + public static void main(String[] args) { + TestFramework tf = new TestFramework(); + tf.addTestClassesToBootClassPath(); + tf.addFlags( + "-XX:+UnlockExperimentalVMOptions", + "-XX:CompileThreshold=100", + "-XX:-TieredCompilation", + "-XX:+UseParallelGC" + ); + tf.start(); + } + + static final int[] EMPTY_INTEGER = new int[] { 0 }; + static final int[] FULL_INTEGER = new int[] { 42 }; + + static class Carrier { + @Stable + int[] field; + + @ForceInline + public Carrier(int initLevel) { + switch (initLevel) { + case 0: + // Do nothing. + break; + case 1: + field = EMPTY_INTEGER; + break; + case 2: + field = FULL_INTEGER; + break; + default: + throw new IllegalStateException("Unknown level"); + } + } + + @ForceInline + public void initEmpty() { + field = EMPTY_INTEGER; + } + + @ForceInline + public void initFull() { + field = FULL_INTEGER; + } + + } + + static final Carrier BLANK_CARRIER = new Carrier(0); + static final Carrier INIT_EMPTY_CARRIER = new Carrier(1); + static final Carrier INIT_FULL_CARRIER = new Carrier(2); + + @Test + @IR(counts = { IRNode.LOAD, ">0" }) + @IR(failOn = { IRNode.MEMBAR }) + static int testNoFold() { + // Access should not be folded. + // No barriers expected for plain fields. + int[] is = BLANK_CARRIER.field; + if (is != null) { + return is[0]; + } + return 0; + } + + @Test + @IR(counts = { IRNode.LOAD, ">0" }) + @IR(failOn = { IRNode.MEMBAR }) + static int testPartialFold() { + // Access should not be folded. + // No barriers expected for plain fields. + int[] is = INIT_EMPTY_CARRIER.field; + if (is != null) { + return is[0]; + } + return 0; + } + + + @Test + @IR(failOn = { IRNode.LOAD, IRNode.MEMBAR }) + static int testFold() { + // Access should be completely folded. + int[] is = INIT_FULL_CARRIER.field; + if (is != null) { + return is[0]; + } + return 0; + } + + @Test + @IR(counts = { IRNode.MEMBAR_STORESTORE, "1" }) + static Carrier testConstructorBlankInit() { + // Only the header barrier. + return new Carrier(0); + } + + @Test + @IR(counts = { IRNode.MEMBAR_STORESTORE, "1" }) + static Carrier testConstructorEmptyInit() { + // Only the header barrier. + return new Carrier(1); + } + + @Test + @IR(counts = { IRNode.MEMBAR_STORESTORE, "1" }) + static Carrier testConstructorFullInit() { + // Only the header barrier. + return new Carrier(2); + } + + @Test + @IR(failOn = { IRNode.MEMBAR }) + static void testMethodEmptyInit() { + // Reference inits do not have membars. + INIT_EMPTY_CARRIER.initEmpty(); + } + + @Test + @IR(failOn = { IRNode.MEMBAR }) + static void testMethodFullInit() { + // Reference inits do not have membars. + INIT_FULL_CARRIER.initFull(); + } + +} diff --git a/test/hotspot/jtreg/compiler/c2/irTests/stable/StablePrimFinalTest.java b/test/hotspot/jtreg/compiler/c2/irTests/stable/StablePrimFinalTest.java new file mode 100644 index 0000000000000..355fadf6cc1e1 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/irTests/stable/StablePrimFinalTest.java @@ -0,0 +1,100 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8333791 + * @requires os.arch=="aarch64" | os.arch=="riscv64" | os.arch=="x86_64" | os.arch=="amd64" + * @requires vm.gc.Parallel + * @requires vm.compiler2.enabled + * @summary Check stable field folding and barriers + * @modules java.base/jdk.internal.vm.annotation + * @library /test/lib / + * @run driver compiler.c2.irTests.stable.StablePrimFinalTest + */ + +package compiler.c2.irTests.stable; + +import compiler.lib.ir_framework.*; +import jdk.test.lib.Asserts; + +import jdk.internal.vm.annotation.Stable; + +public class StablePrimFinalTest { + + public static void main(String[] args) { + TestFramework tf = new TestFramework(); + tf.addTestClassesToBootClassPath(); + tf.addFlags( + "-XX:+UnlockExperimentalVMOptions", + "-XX:CompileThreshold=100", + "-XX:-TieredCompilation", + "-XX:+UseParallelGC" + ); + tf.start(); + } + + static class Carrier { + @Stable + final int field; + + @ForceInline + public Carrier(boolean init) { + field = init ? 42 : 0; + } + } + + static final Carrier BLANK_CARRIER = new Carrier(false); + static final Carrier INIT_CARRIER = new Carrier(true); + + @Test + @IR(counts = { IRNode.LOAD, "1" }) + @IR(failOn = { IRNode.MEMBAR }) + static int testNoFold() { + // Access should not be folded. + // No barriers expected for final fields. + return BLANK_CARRIER.field; + } + + @Test + @IR(failOn = { IRNode.LOAD, IRNode.MEMBAR }) + static int testFold() { + // Access should be completely folded. + return INIT_CARRIER.field; + } + + @Test + @IR(counts = { IRNode.MEMBAR_STORESTORE, "1" }) + static Carrier testConstructorBlankInit() { + // Single header+final barrier. + return new Carrier(false); + } + + @Test + @IR(counts = { IRNode.MEMBAR_STORESTORE, "1" }) + static Carrier testConstructorFullInit() { + // Single header+final barrier. + return new Carrier(true); + } + +} diff --git a/test/hotspot/jtreg/compiler/c2/irTests/stable/StablePrimPlainTest.java b/test/hotspot/jtreg/compiler/c2/irTests/stable/StablePrimPlainTest.java new file mode 100644 index 0000000000000..38cc8bfad4e5e --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/irTests/stable/StablePrimPlainTest.java @@ -0,0 +1,114 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8333791 + * @requires os.arch=="aarch64" | os.arch=="riscv64" | os.arch=="x86_64" | os.arch=="amd64" + * @requires vm.gc.Parallel + * @requires vm.compiler2.enabled + * @summary Check stable field folding and barriers + * @modules java.base/jdk.internal.vm.annotation + * @library /test/lib / + * @run driver compiler.c2.irTests.stable.StablePrimPlainTest + */ + +package compiler.c2.irTests.stable; + +import compiler.lib.ir_framework.*; +import jdk.test.lib.Asserts; + +import jdk.internal.vm.annotation.Stable; + +public class StablePrimPlainTest { + + public static void main(String[] args) { + TestFramework tf = new TestFramework(); + tf.addTestClassesToBootClassPath(); + tf.addFlags( + "-XX:+UnlockExperimentalVMOptions", + "-XX:CompileThreshold=100", + "-XX:-TieredCompilation", + "-XX:+UseParallelGC" + ); + tf.start(); + } + + static class Carrier { + @Stable + int field; + + @ForceInline + public Carrier(boolean init) { + if (init) { + field = 42; + } + } + + @ForceInline + public void init() { + field = 42; + } + } + + static final Carrier BLANK_CARRIER = new Carrier(false); + static final Carrier INIT_CARRIER = new Carrier(true); + + @Test + @IR(counts = { IRNode.LOAD, "1" }) + @IR(failOn = { IRNode.MEMBAR }) + static int testNoFold() { + // Access should not be folded. + // No barriers expected for plain fields. + return BLANK_CARRIER.field; + } + + @Test + @IR(failOn = { IRNode.LOAD, IRNode.MEMBAR }) + static int testFold() { + // Access should be completely folded. + return INIT_CARRIER.field; + } + + @Test + @IR(counts = { IRNode.MEMBAR_STORESTORE, "1" }) + static Carrier testConstructorBlankInit() { + // Only the header barrier. + return new Carrier(false); + } + + @Test + @IR(counts = { IRNode.MEMBAR_STORESTORE, "1" }) + static Carrier testConstructorFullInit() { + // Only the header barrier. + return new Carrier(true); + } + + @Test + @IR(failOn = { IRNode.MEMBAR }) + static void testMethodInit() { + // Primitive inits have no membars. + INIT_CARRIER.init(); + } + +} diff --git a/test/hotspot/jtreg/compiler/c2/irTests/stable/StablePrimVolatileTest.java b/test/hotspot/jtreg/compiler/c2/irTests/stable/StablePrimVolatileTest.java new file mode 100644 index 0000000000000..159c2f7321d55 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/irTests/stable/StablePrimVolatileTest.java @@ -0,0 +1,114 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8333791 + * @requires os.arch=="aarch64" | os.arch=="riscv64" | os.arch=="x86_64" | os.arch=="amd64" + * @requires vm.gc.Parallel + * @requires vm.compiler2.enabled + * @summary Check stable field folding and barriers + * @modules java.base/jdk.internal.vm.annotation + * @library /test/lib / + * @run driver compiler.c2.irTests.stable.StablePrimVolatileTest + */ + +package compiler.c2.irTests.stable; + +import compiler.lib.ir_framework.*; +import jdk.test.lib.Asserts; + +import jdk.internal.vm.annotation.Stable; + +public class StablePrimVolatileTest { + + public static void main(String[] args) { + TestFramework tf = new TestFramework(); + tf.addTestClassesToBootClassPath(); + tf.addFlags( + "-XX:+UnlockExperimentalVMOptions", + "-XX:CompileThreshold=100", + "-XX:-TieredCompilation", + "-XX:+UseParallelGC" + ); + tf.start(); + } + + static class Carrier { + @Stable + volatile int field; + + @ForceInline + public Carrier(boolean init) { + if (init) { + field = 42; + } + } + + @ForceInline + public void init() { + field = 42; + } + } + + static final Carrier BLANK_CARRIER = new Carrier(false); + static final Carrier INIT_CARRIER = new Carrier(true); + + @Test + @IR(counts = { IRNode.LOAD, "1" }) + @IR(counts = { IRNode.MEMBAR, ">0" }) + static int testNoFold() { + // Access should not be folded. + // Barriers expected for volatile fields. + return BLANK_CARRIER.field; + } + + @Test + @IR(failOn = { IRNode.LOAD, IRNode.MEMBAR }) + static int testFold() { + // Access should be completely folded. + return INIT_CARRIER.field; + } + + @Test + @IR(counts = { IRNode.MEMBAR_STORESTORE, "1" }) + static Carrier testConstructorBlankInit() { + // Expect only the header barrier. + return new Carrier(false); + } + + @Test + @IR(counts = { IRNode.MEMBAR, ">0" }) + static Carrier testConstructorFullInit() { + // Volatile barriers expected. + return new Carrier(true); + } + + @Test + @IR(counts = { IRNode.MEMBAR, ">0" }) + static void testMethodInit() { + // Volatile barriers expected. + INIT_CARRIER.init(); + } + +} diff --git a/test/hotspot/jtreg/compiler/c2/irTests/stable/StableRefArrayTest.java b/test/hotspot/jtreg/compiler/c2/irTests/stable/StableRefArrayTest.java new file mode 100644 index 0000000000000..027bd2dce3046 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/irTests/stable/StableRefArrayTest.java @@ -0,0 +1,179 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8333791 + * @requires os.arch=="aarch64" | os.arch=="riscv64" | os.arch=="x86_64" | os.arch=="amd64" + * @requires vm.gc.Parallel + * @requires vm.compiler2.enabled + * @summary Check stable field folding and barriers + * @modules java.base/jdk.internal.vm.annotation + * @library /test/lib / + * @run driver compiler.c2.irTests.stable.StableRefArrayTest + */ + +package compiler.c2.irTests.stable; + +import compiler.lib.ir_framework.*; +import jdk.test.lib.Asserts; + +import jdk.internal.vm.annotation.Stable; + +public class StableRefArrayTest { + + public static void main(String[] args) { + TestFramework tf = new TestFramework(); + tf.addTestClassesToBootClassPath(); + tf.addFlags( + "-XX:+UnlockExperimentalVMOptions", + "-XX:CompileThreshold=100", + "-XX:-TieredCompilation", + "-XX:+UseParallelGC" + ); + tf.start(); + } + + static final Integer[] EMPTY_INTEGER = new Integer[] { null }; + static final Integer[] FULL_INTEGER = new Integer[] { 42 }; + + static class Carrier { + @Stable + Integer[] field; + + @ForceInline + public Carrier(int initLevel) { + switch (initLevel) { + case 0: + // Do nothing. + break; + case 1: + field = EMPTY_INTEGER; + break; + case 2: + field = FULL_INTEGER; + break; + default: + throw new IllegalStateException("Unknown level"); + } + } + + @ForceInline + public void initEmpty() { + field = EMPTY_INTEGER; + } + + @ForceInline + public void initFull() { + field = FULL_INTEGER; + } + + } + + static final Carrier BLANK_CARRIER = new Carrier(0); + static final Carrier INIT_EMPTY_CARRIER = new Carrier(1); + static final Carrier INIT_FULL_CARRIER = new Carrier(2); + + @Test + @IR(counts = { IRNode.LOAD, ">0" }) + @IR(failOn = { IRNode.MEMBAR }) + static int testNoFold() { + // Access should not be folded. + // No barriers expected for plain fields. + Integer[] is = BLANK_CARRIER.field; + if (is != null) { + Integer i = is[0]; + if (i != null) { + return i; + } + } + return 0; + } + + @Test + @IR(counts = { IRNode.LOAD, ">0" }) + @IR(failOn = { IRNode.MEMBAR }) + static int testPartialFold() { + // Access should not be folded. + // No barriers expected for plain fields. + Integer[] is = INIT_EMPTY_CARRIER.field; + if (is != null) { + Integer i = is[0]; + if (i != null) { + return i; + } + } + return 0; + } + + + @Test + @IR(failOn = { IRNode.LOAD, IRNode.MEMBAR }) + static int testFold() { + // Access should be completely folded. + Integer[] is = INIT_FULL_CARRIER.field; + if (is != null) { + Integer i = is[0]; + if (i != null) { + return i; + } + } + return 0; + } + + @Test + @IR(counts = { IRNode.MEMBAR_STORESTORE, "1" }) + static Carrier testConstructorBlankInit() { + // Only the header barrier. + return new Carrier(0); + } + + @Test + @IR(counts = { IRNode.MEMBAR_STORESTORE, "1" }) + static Carrier testConstructorEmptyInit() { + // Only the header barrier. + return new Carrier(1); + } + + @Test + @IR(counts = { IRNode.MEMBAR_STORESTORE, "1" }) + static Carrier testConstructorFullInit() { + // Only the header barrier. + return new Carrier(2); + } + + @Test + @IR(failOn = { IRNode.MEMBAR }) + static void testMethodEmptyInit() { + // Reference inits do not have membars. + INIT_EMPTY_CARRIER.initEmpty(); + } + + @Test + @IR(failOn = { IRNode.MEMBAR }) + static void testMethodFullInit() { + // Reference inits do not have membars. + INIT_FULL_CARRIER.initFull(); + } + +} diff --git a/test/hotspot/jtreg/compiler/c2/irTests/stable/StableRefFinalTest.java b/test/hotspot/jtreg/compiler/c2/irTests/stable/StableRefFinalTest.java new file mode 100644 index 0000000000000..405c86a5fc9e2 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/irTests/stable/StableRefFinalTest.java @@ -0,0 +1,97 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8333791 + * @requires os.arch=="aarch64" | os.arch=="riscv64" | os.arch=="x86_64" | os.arch=="amd64" + * @requires vm.gc.Parallel + * @requires vm.compiler2.enabled + * @summary Check stable field folding and barriers + * @modules java.base/jdk.internal.vm.annotation + * @library /test/lib / + * @run driver compiler.c2.irTests.stable.StableRefFinalTest + */ + +package compiler.c2.irTests.stable; + +import compiler.lib.ir_framework.*; +import jdk.test.lib.Asserts; + +import jdk.internal.vm.annotation.Stable; + +public class StableRefFinalTest { + + public static void main(String[] args) { + TestFramework tf = new TestFramework(); + tf.addTestClassesToBootClassPath(); + tf.addFlags( + "-XX:+UnlockExperimentalVMOptions", + "-XX:CompileThreshold=100", + "-XX:-TieredCompilation", + "-XX:+UseParallelGC" + ); + tf.start(); + } + + static final Integer INTEGER = 42; + + static class Carrier { + @Stable + final Integer field; + + @ForceInline + public Carrier(boolean init) { + field = init ? INTEGER : null; + } + } + + static final Carrier BLANK_CARRIER = new Carrier(false); + static final Carrier INIT_CARRIER = new Carrier(true); + + @Test + @IR(counts = { IRNode.LOAD, ">0" }) + @IR(failOn = { IRNode.MEMBAR }) + static int testNoFold() { + // Access should not be folded. + // No barriers expected for plain fields. + Integer i = BLANK_CARRIER.field; + return i != null ? i : 0; + } + + @Test + @IR(failOn = { IRNode.LOAD, IRNode.MEMBAR }) + static int testFold() { + // Access should be completely folded. + Integer i = INIT_CARRIER.field; + return i != null ? i : 0; + } + + @Test + @IR(counts = { IRNode.MEMBAR_STORESTORE, "1" }) + static Carrier testConstructorInit() { + // Only the header+final barrier. + return new Carrier(true); + } + +} diff --git a/test/hotspot/jtreg/compiler/c2/irTests/stable/StableRefPlainTest.java b/test/hotspot/jtreg/compiler/c2/irTests/stable/StableRefPlainTest.java new file mode 100644 index 0000000000000..bd5be32459d9c --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/irTests/stable/StableRefPlainTest.java @@ -0,0 +1,118 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8333791 + * @requires os.arch=="aarch64" | os.arch=="riscv64" | os.arch=="x86_64" | os.arch=="amd64" + * @requires vm.gc.Parallel + * @requires vm.compiler2.enabled + * @summary Check stable field folding and barriers + * @modules java.base/jdk.internal.vm.annotation + * @library /test/lib / + * @run driver compiler.c2.irTests.stable.StableRefPlainTest + */ + +package compiler.c2.irTests.stable; + +import compiler.lib.ir_framework.*; +import jdk.test.lib.Asserts; + +import jdk.internal.vm.annotation.Stable; + +public class StableRefPlainTest { + + public static void main(String[] args) { + TestFramework tf = new TestFramework(); + tf.addTestClassesToBootClassPath(); + tf.addFlags( + "-XX:+UnlockExperimentalVMOptions", + "-XX:CompileThreshold=100", + "-XX:-TieredCompilation", + "-XX:+UseParallelGC" + ); + tf.start(); + } + + static final Integer INTEGER = 42; + + static class Carrier { + @Stable + Integer field; + + @ForceInline + public Carrier(boolean init) { + if (init) { + field = INTEGER; + } + } + + @ForceInline + public void init() { + field = INTEGER; + } + } + + static final Carrier BLANK_CARRIER = new Carrier(false); + static final Carrier INIT_CARRIER = new Carrier(true); + + @Test + @IR(counts = { IRNode.LOAD, ">0" }) + @IR(failOn = { IRNode.MEMBAR }) + static int testNoFold() { + // Access should not be folded. + // No barriers expected for plain fields. + Integer i = BLANK_CARRIER.field; + return i != null ? i : 0; + } + + @Test + @IR(failOn = { IRNode.LOAD, IRNode.MEMBAR }) + static int testFold() { + // Access should be completely folded. + Integer i = INIT_CARRIER.field; + return i != null ? i : 0; + } + + @Test + @IR(counts = { IRNode.MEMBAR_STORESTORE, "1" }) + static Carrier testConstructorBlankInit() { + // Only the header barrier. + return new Carrier(false); + } + + @Test + @IR(counts = { IRNode.MEMBAR_STORESTORE, "1" }) + static Carrier testConstructorFullInit() { + // Only the header barrier. + return new Carrier(true); + } + + @Test + @IR(failOn = { IRNode.MEMBAR }) + static void testMethodInit() { + // Reference inits do not have membars. + INIT_CARRIER.init(); + } + +} diff --git a/test/hotspot/jtreg/compiler/c2/irTests/stable/StableRefVolatileTest.java b/test/hotspot/jtreg/compiler/c2/irTests/stable/StableRefVolatileTest.java new file mode 100644 index 0000000000000..7d7d7fcad7795 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/irTests/stable/StableRefVolatileTest.java @@ -0,0 +1,118 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8333791 + * @requires os.arch=="aarch64" | os.arch=="riscv64" | os.arch=="x86_64" | os.arch=="amd64" + * @requires vm.gc.Parallel + * @requires vm.compiler2.enabled + * @summary Check stable field folding and barriers + * @modules java.base/jdk.internal.vm.annotation + * @library /test/lib / + * @run driver compiler.c2.irTests.stable.StableRefVolatileTest + */ + +package compiler.c2.irTests.stable; + +import compiler.lib.ir_framework.*; +import jdk.test.lib.Asserts; + +import jdk.internal.vm.annotation.Stable; + +public class StableRefVolatileTest { + + public static void main(String[] args) { + TestFramework tf = new TestFramework(); + tf.addTestClassesToBootClassPath(); + tf.addFlags( + "-XX:+UnlockExperimentalVMOptions", + "-XX:CompileThreshold=100", + "-XX:-TieredCompilation", + "-XX:+UseParallelGC" + ); + tf.start(); + } + + static final Integer INTEGER = 42; + + static class Carrier { + @Stable + volatile Integer field; + + @ForceInline + public Carrier(boolean init) { + if (init) { + field = INTEGER; + } + } + + @ForceInline + public void init() { + field = INTEGER; + } + } + + static final Carrier BLANK_CARRIER = new Carrier(false); + static final Carrier INIT_CARRIER = new Carrier(true); + + @Test + @IR(counts = { IRNode.LOAD, ">0" }) + @IR(counts = { IRNode.MEMBAR, ">0" }) + static int testNoFold() { + // Access should not be folded. + // Barriers are expected for volatile field. + Integer i = BLANK_CARRIER.field; + return i != null ? i : 0; + } + + @Test + @IR(failOn = { IRNode.LOAD, IRNode.MEMBAR }) + static int testFold() { + // Access should be completely folded. + Integer i = INIT_CARRIER.field; + return i != null ? i : 0; + } + + @Test + @IR(counts = { IRNode.MEMBAR_STORESTORE, "1" }) + static Carrier testConstructorBlankInit() { + // Only the header barrier. + return new Carrier(false); + } + + @Test + @IR(counts = { IRNode.MEMBAR, ">0" }) + static Carrier testConstructorFullInit() { + // Volatile writes, expect more barriers. + return new Carrier(true); + } + + @Test + @IR(counts = { IRNode.MEMBAR, ">0" }) + static void testMethodInit() { + // Barriers are expected for volatile fields. + INIT_CARRIER.init(); + } + +} From 56dec215b0d056fc23137372ecb3376af2a7b891 Mon Sep 17 00:00:00 2001 From: Sonia Zaldana Calles Date: Thu, 15 Aug 2024 13:28:25 +0000 Subject: [PATCH 314/353] 8338014: Improve usage of @jvms tags in class file API Reviewed-by: darcy, liach, asotona --- .../classes/java/lang/classfile/AnnotationValue.java | 2 +- .../share/classes/java/lang/classfile/Attribute.java | 4 ++-- .../classes/java/lang/classfile/ClassSignature.java | 2 +- .../classes/java/lang/classfile/MethodSignature.java | 2 +- .../share/classes/java/lang/classfile/Opcode.java | 4 ++-- .../share/classes/java/lang/classfile/Signature.java | 2 +- .../classes/java/lang/classfile/TypeAnnotation.java | 10 +++++----- .../attribute/AnnotationDefaultAttribute.java | 4 ++-- .../classfile/attribute/BootstrapMethodsAttribute.java | 4 ++-- .../java/lang/classfile/attribute/CodeAttribute.java | 2 +- .../classfile/attribute/ConstantValueAttribute.java | 4 ++-- .../lang/classfile/attribute/DeprecatedAttribute.java | 4 ++-- .../classfile/attribute/EnclosingMethodAttribute.java | 4 ++-- .../lang/classfile/attribute/ExceptionsAttribute.java | 4 ++-- .../classfile/attribute/InnerClassesAttribute.java | 4 ++-- .../classfile/attribute/LineNumberTableAttribute.java | 4 ++-- .../attribute/LocalVariableTableAttribute.java | 4 ++-- .../attribute/LocalVariableTypeTableAttribute.java | 4 ++-- .../classfile/attribute/MethodParametersAttribute.java | 4 ++-- .../java/lang/classfile/attribute/ModuleAttribute.java | 2 +- .../classfile/attribute/ModuleMainClassAttribute.java | 4 ++-- .../classfile/attribute/ModulePackagesAttribute.java | 4 ++-- .../lang/classfile/attribute/NestHostAttribute.java | 4 ++-- .../lang/classfile/attribute/NestMembersAttribute.java | 4 ++-- .../attribute/PermittedSubclassesAttribute.java | 4 ++-- .../java/lang/classfile/attribute/RecordAttribute.java | 4 ++-- .../RuntimeInvisibleAnnotationsAttribute.java | 4 ++-- .../RuntimeInvisibleParameterAnnotationsAttribute.java | 4 ++-- .../RuntimeInvisibleTypeAnnotationsAttribute.java | 4 ++-- .../attribute/RuntimeVisibleAnnotationsAttribute.java | 4 ++-- .../RuntimeVisibleParameterAnnotationsAttribute.java | 4 ++-- .../RuntimeVisibleTypeAnnotationsAttribute.java | 4 ++-- .../lang/classfile/attribute/SignatureAttribute.java | 4 ++-- .../lang/classfile/attribute/SourceFileAttribute.java | 4 ++-- .../lang/classfile/attribute/StackMapFrameInfo.java | 4 ++-- .../classfile/attribute/StackMapTableAttribute.java | 4 ++-- .../lang/classfile/attribute/SyntheticAttribute.java | 4 ++-- .../classfile/constantpool/ConstantPoolBuilder.java | 2 +- .../lang/classfile/constantpool/MethodHandleEntry.java | 4 ++-- .../lang/classfile/instruction/InvokeInstruction.java | 4 ++-- 40 files changed, 76 insertions(+), 76 deletions(-) diff --git a/src/java.base/share/classes/java/lang/classfile/AnnotationValue.java b/src/java.base/share/classes/java/lang/classfile/AnnotationValue.java index a4a1c218ac12b..04bbcffb8bc9f 100644 --- a/src/java.base/share/classes/java/lang/classfile/AnnotationValue.java +++ b/src/java.base/share/classes/java/lang/classfile/AnnotationValue.java @@ -426,7 +426,7 @@ default ClassDesc classSymbol() { } /** - * {@return the tag character for this type as per {@jvms 4.7.16.1}} + * {@return the tag character for this type as per JVMS {@jvms 4.7.16.1}} */ char tag(); diff --git a/src/java.base/share/classes/java/lang/classfile/Attribute.java b/src/java.base/share/classes/java/lang/classfile/Attribute.java index 718f164e8ef7f..b9e3df8d2a2d3 100644 --- a/src/java.base/share/classes/java/lang/classfile/Attribute.java +++ b/src/java.base/share/classes/java/lang/classfile/Attribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -66,7 +66,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models a classfile attribute {@jvms 4.7}. Many, though not all, subtypes of + * Models a classfile attribute (JVMS {@jvms 4.7}). Many, though not all, subtypes of * {@linkplain Attribute} will implement {@link ClassElement}, {@link * MethodElement}, {@link FieldElement}, or {@link CodeElement}; attributes that * are also elements will be delivered when traversing the elements of the diff --git a/src/java.base/share/classes/java/lang/classfile/ClassSignature.java b/src/java.base/share/classes/java/lang/classfile/ClassSignature.java index 5c55950547eb6..3b6b15f59f839 100644 --- a/src/java.base/share/classes/java/lang/classfile/ClassSignature.java +++ b/src/java.base/share/classes/java/lang/classfile/ClassSignature.java @@ -30,7 +30,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models the generic signature of a class file, as defined by {@jvms 4.7.9}. + * Models the generic signature of a class file, as defined by JVMS {@jvms 4.7.9}. * * @since 22 */ diff --git a/src/java.base/share/classes/java/lang/classfile/MethodSignature.java b/src/java.base/share/classes/java/lang/classfile/MethodSignature.java index 0d5a77faa6cef..5e758b64be3f8 100644 --- a/src/java.base/share/classes/java/lang/classfile/MethodSignature.java +++ b/src/java.base/share/classes/java/lang/classfile/MethodSignature.java @@ -32,7 +32,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models the generic signature of a method, as defined by {@jvms 4.7.9}. + * Models the generic signature of a method, as defined by JVMS {@jvms 4.7.9}. * * @since 22 */ diff --git a/src/java.base/share/classes/java/lang/classfile/Opcode.java b/src/java.base/share/classes/java/lang/classfile/Opcode.java index 6ce231d43d07c..9128a0e79d3ab 100644 --- a/src/java.base/share/classes/java/lang/classfile/Opcode.java +++ b/src/java.base/share/classes/java/lang/classfile/Opcode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +29,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Describes the opcodes of the JVM instruction set, as described in {@jvms 6.5}. + * Describes the opcodes of the JVM instruction set, as described in JVMS {@jvms 6.5}. * As well as a number of pseudo-instructions that may be encountered when * traversing the instructions of a method. * diff --git a/src/java.base/share/classes/java/lang/classfile/Signature.java b/src/java.base/share/classes/java/lang/classfile/Signature.java index 22ca477f4e6a2..739c3f1f3f397 100644 --- a/src/java.base/share/classes/java/lang/classfile/Signature.java +++ b/src/java.base/share/classes/java/lang/classfile/Signature.java @@ -34,7 +34,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models generic Java type signatures, as defined in {@jvms 4.7.9.1}. + * Models generic Java type signatures, as defined in JVMS {@jvms 4.7.9.1}. * * @sealedGraph * @since 22 diff --git a/src/java.base/share/classes/java/lang/classfile/TypeAnnotation.java b/src/java.base/share/classes/java/lang/classfile/TypeAnnotation.java index add1872f6412a..01a2f5fc696c5 100644 --- a/src/java.base/share/classes/java/lang/classfile/TypeAnnotation.java +++ b/src/java.base/share/classes/java/lang/classfile/TypeAnnotation.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -60,7 +60,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models an annotation on a type use, as defined in {@jvms 4.7.19} and {@jvms 4.7.20}. + * Models an annotation on a type use, as defined in JVMS {@jvms 4.7.19} and {@jvms 4.7.20}. * * @see RuntimeVisibleTypeAnnotationsAttribute * @see RuntimeInvisibleTypeAnnotationsAttribute @@ -73,7 +73,7 @@ public sealed interface TypeAnnotation permits UnboundAttribute.UnboundTypeAnnotation { /** - * The kind of target on which the annotation appears, as defined in {@jvms 4.7.20.1}. + * The kind of target on which the annotation appears, as defined in JVMS {@jvms 4.7.20.1}. * * @since 22 */ @@ -773,7 +773,7 @@ sealed interface TypeArgumentTarget extends TargetInfo /** * JVMS: Type_path structure identifies which part of the type is annotated, - * as defined in {@jvms 4.7.20.2} + * as defined in JVMS {@jvms 4.7.20.2} * * @since 22 */ @@ -782,7 +782,7 @@ sealed interface TypePathComponent permits UnboundAttribute.TypePathComponentImpl { /** - * Type path kind, as defined in {@jvms 4.7.20.2} + * Type path kind, as defined in JVMS {@jvms 4.7.20.2} * * @since 22 */ diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/AnnotationDefaultAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/AnnotationDefaultAttribute.java index 16149ff66c522..018fcd65a34a9 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/AnnotationDefaultAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/AnnotationDefaultAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models the {@code AnnotationDefault} attribute {@jvms 4.7.22}, which can + * Models the {@code AnnotationDefault} attribute (JVMS {@jvms 4.7.22}), which can * appear on methods of annotation types, and records the default value * {@jls 9.6.2} for the element corresponding to this method. Delivered as a * {@link MethodElement} when traversing the elements of a {@link MethodModel}. diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/BootstrapMethodsAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/BootstrapMethodsAttribute.java index 436a7f80b1c7f..7cc784af1f413 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/BootstrapMethodsAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/BootstrapMethodsAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,7 +35,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models the {@code BootstrapMethods} attribute {@jvms 4.7.23}, which serves as + * Models the {@code BootstrapMethods} attribute (JVMS {@jvms 4.7.23}), which serves as * an extension to the constant pool of a classfile. Elements of the bootstrap * method table are accessed through {@link ConstantPool}. *

    diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/CodeAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/CodeAttribute.java index 7a4f5886580cc..f0bab0fde110f 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/CodeAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/CodeAttribute.java @@ -32,7 +32,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models the {@code Code} attribute {@jvms 4.7.3}, appears on non-native, + * Models the {@code Code} attribute (JVMS {@jvms 4.7.3}), appears on non-native, * non-abstract methods and contains the bytecode of the method body. Delivered * as a {@link java.lang.classfile.MethodElement} when traversing the elements of a * {@link java.lang.classfile.MethodModel}. diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/ConstantValueAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/ConstantValueAttribute.java index c53b438f35fa8..390320c679c8a 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/ConstantValueAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/ConstantValueAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models the {@code ConstantValue} attribute {@jvms 4.7.2}, which can appear on + * Models the {@code ConstantValue} attribute (JVMS {@jvms 4.7.2}), which can appear on * fields and indicates that the field's value is a constant. Delivered as a * {@link java.lang.classfile.FieldElement} when traversing the elements of a * {@link java.lang.classfile.FieldModel}. diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/DeprecatedAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/DeprecatedAttribute.java index 441271d55ef84..f65f01f4e2a88 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/DeprecatedAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/DeprecatedAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,7 +33,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models the {@code Deprecated} attribute {@jvms 4.7.15}, which can appear on + * Models the {@code Deprecated} attribute (JVMS {@jvms 4.7.15}), which can appear on * classes, methods, and fields. Delivered as a {@link ClassElement}, * {@link MethodElement}, or {@link FieldElement} when traversing the elements * of a corresponding model. diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/EnclosingMethodAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/EnclosingMethodAttribute.java index 3079acee89b93..768019fa1d301 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/EnclosingMethodAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/EnclosingMethodAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,7 +40,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models the {@code EnclosingMethod} attribute {@jvms 4.7.7}, which can appear + * Models the {@code EnclosingMethod} attribute (JVMS {@jvms 4.7.7}), which can appear * on classes, and indicates that the class is a local or anonymous class. * Delivered as a {@link ClassElement} when traversing the elements of a {@link * java.lang.classfile.ClassModel}. diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/ExceptionsAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/ExceptionsAttribute.java index 5af4476c923dc..e12b9eb9fc3c7 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/ExceptionsAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/ExceptionsAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,7 +37,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models the {@code Exceptions} attribute {@jvms 4.7.5}, which can appear on + * Models the {@code Exceptions} attribute (JVMS {@jvms 4.7.5}), which can appear on * methods, and records the exceptions declared to be thrown by this method. * Delivered as a {@link MethodElement} when traversing the elements of a * {@link java.lang.classfile.MethodModel}. diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/InnerClassesAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/InnerClassesAttribute.java index 2089b601e3b30..0746d20b5b823 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/InnerClassesAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/InnerClassesAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models the {@code InnerClasses} attribute {@jvms 4.7.6}, which can + * Models the {@code InnerClasses} attribute (JVMS {@jvms 4.7.6}), which can * appear on classes, and records which classes referenced by this classfile * are inner classes. Delivered as a {@link java.lang.classfile.ClassElement} when * traversing the elements of a {@link java.lang.classfile.ClassModel}. diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/LineNumberTableAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/LineNumberTableAttribute.java index 5b211487c061f..a31f4919688b7 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/LineNumberTableAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/LineNumberTableAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,7 +32,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models the {@code LineNumberTable} attribute {@jvms 4.7.12}, which can appear + * Models the {@code LineNumberTable} attribute (JVMS {@jvms 4.7.12}), which can appear * on a {@code Code} attribute, and records the mapping between indexes into * the code table and line numbers in the source file. * Delivered as a {@link java.lang.classfile.instruction.LineNumber} when traversing the diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/LocalVariableTableAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/LocalVariableTableAttribute.java index 2bcdaddaea936..745b6d8e8e23f 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/LocalVariableTableAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/LocalVariableTableAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,7 +32,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models the {@code LocalVariableTable} attribute {@jvms 4.7.13}, which can appear + * Models the {@code LocalVariableTable} attribute (JVMS {@jvms 4.7.13}), which can appear * on a {@code Code} attribute, and records debug information about local * variables. * Delivered as a {@link java.lang.classfile.instruction.LocalVariable} when traversing the diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/LocalVariableTypeTableAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/LocalVariableTypeTableAttribute.java index abd3d480b9fe4..c2475530e6c53 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/LocalVariableTypeTableAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/LocalVariableTypeTableAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,7 +33,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models the {@code LocalVariableTypeTable} attribute {@jvms 4.7.14}, which can appear + * Models the {@code LocalVariableTypeTable} attribute (JVMS {@jvms 4.7.14}), which can appear * on a {@code Code} attribute, and records debug information about local * variables. * Delivered as a {@link java.lang.classfile.instruction.LocalVariable} when traversing the diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/MethodParametersAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/MethodParametersAttribute.java index d38e5e59797ae..81530086cdf3b 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/MethodParametersAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/MethodParametersAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models the {@code MethodParameters} attribute {@jvms 4.7.24}, which can + * Models the {@code MethodParameters} attribute (JVMS {@jvms 4.7.24}), which can * appear on methods, and records optional information about the method's * parameters. Delivered as a {@link java.lang.classfile.MethodElement} when * traversing the elements of a {@link java.lang.classfile.MethodModel}. diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleAttribute.java index 9a4c58478addb..ec258611c70a1 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleAttribute.java @@ -46,7 +46,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models the {@code Module} attribute {@jvms 4.7.25}, which can + * Models the {@code Module} attribute (JVMS {@jvms 4.7.25}), which can * appear on classes that represent module descriptors. * Delivered as a {@link java.lang.classfile.ClassElement} when * traversing the elements of a {@link java.lang.classfile.ClassModel}. diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleMainClassAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleMainClassAttribute.java index 086017ba9aa0c..91fe3c8f2d79c 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/ModuleMainClassAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/ModuleMainClassAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,7 +35,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models the {@code ModuleMainClass} attribute {@jvms 4.7.27}, which can + * Models the {@code ModuleMainClass} attribute (JVMS {@jvms 4.7.27}), which can * appear on classes that represent module descriptors. * Delivered as a {@link java.lang.classfile.ClassElement} when * traversing the elements of a {@link java.lang.classfile.ClassModel}. diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/ModulePackagesAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/ModulePackagesAttribute.java index 7bf2ac8ce6211..30bc0e9827b5f 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/ModulePackagesAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/ModulePackagesAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,7 +38,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models the {@code ModulePackages} attribute {@jvms 4.7.26}, which can + * Models the {@code ModulePackages} attribute (JVMS {@jvms 4.7.26}), which can * appear on classes that represent module descriptors. * Delivered as a {@link java.lang.classfile.ClassElement} when * traversing the elements of a {@link java.lang.classfile.ClassModel}. diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/NestHostAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/NestHostAttribute.java index 7c60835385a33..0961601e5d46d 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/NestHostAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/NestHostAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,7 +35,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models the {@code NestHost} attribute {@jvms 4.7.28}, which can + * Models the {@code NestHost} attribute (JVMS {@jvms 4.7.28}), which can * appear on classes to indicate that this class is a member of a nest. * Delivered as a {@link java.lang.classfile.ClassElement} when * traversing the elements of a {@link java.lang.classfile.ClassModel}. diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/NestMembersAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/NestMembersAttribute.java index 72d4e8cca7dfc..f184df7fff509 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/NestMembersAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/NestMembersAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,7 +37,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models the {@code NestMembers} attribute {@jvms 4.7.29}, which can + * Models the {@code NestMembers} attribute (JVMS {@jvms 4.7.29}), which can * appear on classes to indicate that this class is the host of a nest. * Delivered as a {@link java.lang.classfile.ClassElement} when * traversing the elements of a {@link java.lang.classfile.ClassModel}. diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/PermittedSubclassesAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/PermittedSubclassesAttribute.java index e6aaa6ad4a679..2d86d4d26e0a0 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/PermittedSubclassesAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/PermittedSubclassesAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,7 +37,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models the {@code PermittedSubclasses} attribute {@jvms 4.7.31}, which can + * Models the {@code PermittedSubclasses} attribute (JVMS {@jvms 4.7.31}), which can * appear on classes to indicate which classes may extend this class. * Delivered as a {@link java.lang.classfile.ClassElement} when * traversing the elements of a {@link java.lang.classfile.ClassModel}. diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/RecordAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/RecordAttribute.java index 16d01943bc3e7..f79538a135cf9 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/RecordAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/RecordAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models the {@code Record} attribute {@jvms 4.7.30}, which can + * Models the {@code Record} attribute (JVMS {@jvms 4.7.30}), which can * appear on classes to indicate that this class is a record class. * Delivered as a {@link java.lang.classfile.ClassElement} when * traversing the elements of a {@link java.lang.classfile.ClassModel}. diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleAnnotationsAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleAnnotationsAttribute.java index 485e4d2af59cf..b467e8504fe06 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleAnnotationsAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleAnnotationsAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,7 +33,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models the {@code RuntimeInvisibleAnnotations} attribute {@jvms 4.7.17}, which + * Models the {@code RuntimeInvisibleAnnotations} attribute (JVMS {@jvms 4.7.17}), which * can appear on classes, methods, and fields. Delivered as a * {@link java.lang.classfile.ClassElement}, {@link java.lang.classfile.FieldElement}, or * {@link java.lang.classfile.MethodElement} when traversing the corresponding model type. diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleParameterAnnotationsAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleParameterAnnotationsAttribute.java index 4865dde341130..af495788afa45 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleParameterAnnotationsAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleParameterAnnotationsAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,7 +37,7 @@ /** * Models the {@code RuntimeInvisibleParameterAnnotations} attribute - * {@jvms 4.7.19}, which can appear on methods. Delivered as a {@link + * (JVMS {@jvms 4.7.19}), which can appear on methods. Delivered as a {@link * java.lang.classfile.MethodElement} when traversing a {@link MethodModel}. *

    * The attribute does not permit multiple instances in a given location. diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleTypeAnnotationsAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleTypeAnnotationsAttribute.java index 830e9778a47ee..46dd2167541d9 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleTypeAnnotationsAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeInvisibleTypeAnnotationsAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,7 +38,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models the {@code RuntimeInvisibleTypeAnnotations} attribute {@jvms 4.7.21}, which + * Models the {@code RuntimeInvisibleTypeAnnotations} attribute (JVMS {@jvms 4.7.21}), which * can appear on classes, methods, fields, and code attributes. Delivered as a * {@link java.lang.classfile.ClassElement}, {@link java.lang.classfile.FieldElement}, * {@link java.lang.classfile.MethodElement}, or {@link CodeElement} when traversing diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleAnnotationsAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleAnnotationsAttribute.java index 77a49b8d13b8e..4454dac62a95f 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleAnnotationsAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleAnnotationsAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,7 +33,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models the {@code RuntimeVisibleAnnotations} attribute {@jvms 4.7.16}, which + * Models the {@code RuntimeVisibleAnnotations} attribute (JVMS {@jvms 4.7.16}), which * can appear on classes, methods, and fields. Delivered as a * {@link java.lang.classfile.ClassElement}, {@link java.lang.classfile.FieldElement}, or * {@link java.lang.classfile.MethodElement} when traversing the corresponding model type. diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleParameterAnnotationsAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleParameterAnnotationsAttribute.java index 7923493499af8..59f648199ca49 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleParameterAnnotationsAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleParameterAnnotationsAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,7 +36,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models the {@code RuntimeVisibleParameterAnnotations} attribute {@jvms 4.7.18}, which + * Models the {@code RuntimeVisibleParameterAnnotations} attribute (JVMS {@jvms 4.7.18}), which * can appear on methods. Delivered as a {@link java.lang.classfile.MethodElement} * when traversing a {@link MethodModel}. * diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleTypeAnnotationsAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleTypeAnnotationsAttribute.java index 3cf38811d5a43..8bdf322803d83 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleTypeAnnotationsAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/RuntimeVisibleTypeAnnotationsAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,7 +38,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models the {@code RuntimeVisibleTypeAnnotations} attribute {@jvms 4.7.20}, which + * Models the {@code RuntimeVisibleTypeAnnotations} attribute (JVMS {@jvms 4.7.20}), which * can appear on classes, methods, fields, and code attributes. Delivered as a * {@link java.lang.classfile.ClassElement}, {@link java.lang.classfile.FieldElement}, * {@link java.lang.classfile.MethodElement}, or {@link CodeElement} when traversing diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/SignatureAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/SignatureAttribute.java index e77382f2fd4c0..783b068c4e64c 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/SignatureAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/SignatureAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,7 +39,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models the {@code Signature} attribute {@jvms 4.7.9}, which + * Models the {@code Signature} attribute (JVMS {@jvms 4.7.9}), which * can appear on classes, methods, or fields. Delivered as a * {@link java.lang.classfile.ClassElement}, {@link java.lang.classfile.FieldElement}, or * {@link java.lang.classfile.MethodElement} when traversing diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/SourceFileAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/SourceFileAttribute.java index 58e1ab4741865..abfa4eb05ffc9 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/SourceFileAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/SourceFileAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,7 +35,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models the {@code SourceFile} attribute {@jvms 4.7.10}, which + * Models the {@code SourceFile} attribute (JVMS {@jvms 4.7.10}), which * can appear on classes. Delivered as a {@link java.lang.classfile.ClassElement} * when traversing a {@link ClassModel}. *

    diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/StackMapFrameInfo.java b/src/java.base/share/classes/java/lang/classfile/attribute/StackMapFrameInfo.java index 08736444442e0..46caa66ef9adf 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/StackMapFrameInfo.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/StackMapFrameInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,7 +36,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models stack map frame of {@code StackMapTable} attribute {@jvms 4.7.4}. + * Models stack map frame of {@code StackMapTable} attribute (JVMS {@jvms 4.7.4}). * * @since 22 */ diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/StackMapTableAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/StackMapTableAttribute.java index d3ec67cab6342..74dd567060eab 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/StackMapTableAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/StackMapTableAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models the {@code StackMapTable} attribute {@jvms 4.7.4}, which can appear + * Models the {@code StackMapTable} attribute (JVMS {@jvms 4.7.4}), which can appear * on a {@code Code} attribute. *

    * The attribute does not permit multiple instances in a given location. diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/SyntheticAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/SyntheticAttribute.java index 6bc9c19b8510e..d1b7b8f0384dc 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/SyntheticAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/SyntheticAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,7 @@ import jdk.internal.javac.PreviewFeature; /** - * Models the {@code Synthetic} attribute {@jvms 4.7.8}, which can appear on + * Models the {@code Synthetic} attribute (JVMS {@jvms 4.7.8}), which can appear on * classes, methods, and fields. Delivered as a {@link ClassElement}, * {@link MethodElement}, or {@link FieldElement} when traversing the elements * of a corresponding model. diff --git a/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantPoolBuilder.java b/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantPoolBuilder.java index db77f8e2e8a17..7334d8e54604e 100644 --- a/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantPoolBuilder.java +++ b/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantPoolBuilder.java @@ -365,7 +365,7 @@ default MethodHandleEntry methodHandleEntry(DirectMethodHandleDesc descriptor) { * it is returned; otherwise, a new entry is added and the new entry is * returned. * - * @param refKind the reference kind of the method handle {@jvms 4.4.8} + * @param refKind the reference kind of the method handle (JVMS {@jvms 4.4.8}) * @param reference the constant pool entry describing the field or method */ MethodHandleEntry methodHandleEntry(int refKind, MemberRefEntry reference); diff --git a/src/java.base/share/classes/java/lang/classfile/constantpool/MethodHandleEntry.java b/src/java.base/share/classes/java/lang/classfile/constantpool/MethodHandleEntry.java index 768991000274d..37ec30648ab6f 100644 --- a/src/java.base/share/classes/java/lang/classfile/constantpool/MethodHandleEntry.java +++ b/src/java.base/share/classes/java/lang/classfile/constantpool/MethodHandleEntry.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,7 +48,7 @@ default ConstantDesc constantValue() { } /** - * {@return the reference kind of this method handle {@jvms 4.4.8}} + * {@return the reference kind of this method handle (JVMS {@jvms 4.4.8})} * @see java.lang.invoke.MethodHandleInfo */ int kind(); diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/InvokeInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/InvokeInstruction.java index 79a2142eb6592..ff68abce3d21e 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/InvokeInstruction.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/InvokeInstruction.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -64,7 +64,7 @@ public sealed interface InvokeInstruction extends Instruction boolean isInterface(); /** - * {@return the {@code count} value of an {@code invokeinterface} instruction, as defined in {@jvms 6.5} + * {@return the {@code count} value of an {@code invokeinterface} instruction, as defined in JVMS {@jvms 6.5} * or {@code 0} for {@code invokespecial}, {@code invokestatic} and {@code invokevirtual} instructions} */ int count(); From 38591315058e6d3b764ca325facc5bf46bf7b16b Mon Sep 17 00:00:00 2001 From: Fei Gao Date: Thu, 15 Aug 2024 15:16:14 +0000 Subject: [PATCH 315/353] 8338442: AArch64: Clean up IndOffXX type and let legitimize_address() fix out-of-range operands Reviewed-by: aph, dlong --- src/hotspot/cpu/aarch64/aarch64.ad | 393 ++++-------------- src/hotspot/cpu/aarch64/aarch64_vector.ad | 16 +- src/hotspot/cpu/aarch64/aarch64_vector_ad.m4 | 2 +- src/hotspot/cpu/aarch64/ad_encode.m4 | 8 +- src/hotspot/cpu/aarch64/gc/x/x_aarch64.ad | 2 +- src/hotspot/cpu/aarch64/gc/z/z_aarch64.ad | 2 +- .../compiler/c2/TestUnalignedAccess.java | 61 ++- 7 files changed, 123 insertions(+), 361 deletions(-) diff --git a/src/hotspot/cpu/aarch64/aarch64.ad b/src/hotspot/cpu/aarch64/aarch64.ad index 66a24a61f29c2..a96c47051f2db 100644 --- a/src/hotspot/cpu/aarch64/aarch64.ad +++ b/src/hotspot/cpu/aarch64/aarch64.ad @@ -2720,7 +2720,7 @@ typedef void (MacroAssembler::* mem_vector_insn)(FloatRegister Rt, { Address addr = mem2address(opcode, base, index, scale, disp); if (addr.getMode() == Address::base_plus_offset) { - /* Fix up any out-of-range offsets. */ + // Fix up any out-of-range offsets. assert_different_registers(rscratch1, base); assert_different_registers(rscratch1, reg); addr = __ legitimize_address(addr, size_in_memory, rscratch1); @@ -2761,7 +2761,11 @@ typedef void (MacroAssembler::* mem_vector_insn)(FloatRegister Rt, int opcode, Register base, int index, int size, int disp) { if (index == -1) { - (masm->*insn)(reg, T, Address(base, disp)); + // Fix up any out-of-range offsets. + assert_different_registers(rscratch1, base); + Address addr = Address(base, disp); + addr = __ legitimize_address(addr, (1 << T), rscratch1); + (masm->*insn)(reg, T, addr); } else { assert(disp == 0, "unsupported address mode"); (masm->*insn)(reg, T, Address(base, as_Register(index), Address::lsl(size))); @@ -2816,7 +2820,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_ldrsbw(iRegI dst, memory1 mem) %{ + enc_class aarch64_enc_ldrsbw(iRegI dst, memory mem) %{ Register dst_reg = as_Register($dst$$reg); loadStore(masm, &MacroAssembler::ldrsbw, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 1); @@ -2824,7 +2828,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_ldrsb(iRegI dst, memory1 mem) %{ + enc_class aarch64_enc_ldrsb(iRegI dst, memory mem) %{ Register dst_reg = as_Register($dst$$reg); loadStore(masm, &MacroAssembler::ldrsb, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 1); @@ -2832,7 +2836,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_ldrb(iRegI dst, memory1 mem) %{ + enc_class aarch64_enc_ldrb(iRegI dst, memory mem) %{ Register dst_reg = as_Register($dst$$reg); loadStore(masm, &MacroAssembler::ldrb, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 1); @@ -2840,7 +2844,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_ldrb(iRegL dst, memory1 mem) %{ + enc_class aarch64_enc_ldrb(iRegL dst, memory mem) %{ Register dst_reg = as_Register($dst$$reg); loadStore(masm, &MacroAssembler::ldrb, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 1); @@ -2848,7 +2852,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_ldrshw(iRegI dst, memory2 mem) %{ + enc_class aarch64_enc_ldrshw(iRegI dst, memory mem) %{ Register dst_reg = as_Register($dst$$reg); loadStore(masm, &MacroAssembler::ldrshw, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 2); @@ -2856,7 +2860,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_ldrsh(iRegI dst, memory2 mem) %{ + enc_class aarch64_enc_ldrsh(iRegI dst, memory mem) %{ Register dst_reg = as_Register($dst$$reg); loadStore(masm, &MacroAssembler::ldrsh, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 2); @@ -2864,7 +2868,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_ldrh(iRegI dst, memory2 mem) %{ + enc_class aarch64_enc_ldrh(iRegI dst, memory mem) %{ Register dst_reg = as_Register($dst$$reg); loadStore(masm, &MacroAssembler::ldrh, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 2); @@ -2872,7 +2876,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_ldrh(iRegL dst, memory2 mem) %{ + enc_class aarch64_enc_ldrh(iRegL dst, memory mem) %{ Register dst_reg = as_Register($dst$$reg); loadStore(masm, &MacroAssembler::ldrh, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 2); @@ -2880,7 +2884,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_ldrw(iRegI dst, memory4 mem) %{ + enc_class aarch64_enc_ldrw(iRegI dst, memory mem) %{ Register dst_reg = as_Register($dst$$reg); loadStore(masm, &MacroAssembler::ldrw, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 4); @@ -2888,7 +2892,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_ldrw(iRegL dst, memory4 mem) %{ + enc_class aarch64_enc_ldrw(iRegL dst, memory mem) %{ Register dst_reg = as_Register($dst$$reg); loadStore(masm, &MacroAssembler::ldrw, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 4); @@ -2896,7 +2900,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_ldrsw(iRegL dst, memory4 mem) %{ + enc_class aarch64_enc_ldrsw(iRegL dst, memory mem) %{ Register dst_reg = as_Register($dst$$reg); loadStore(masm, &MacroAssembler::ldrsw, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 4); @@ -2904,7 +2908,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_ldr(iRegL dst, memory8 mem) %{ + enc_class aarch64_enc_ldr(iRegL dst, memory mem) %{ Register dst_reg = as_Register($dst$$reg); loadStore(masm, &MacroAssembler::ldr, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 8); @@ -2912,7 +2916,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_ldrs(vRegF dst, memory4 mem) %{ + enc_class aarch64_enc_ldrs(vRegF dst, memory mem) %{ FloatRegister dst_reg = as_FloatRegister($dst$$reg); loadStore(masm, &MacroAssembler::ldrs, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 4); @@ -2920,7 +2924,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_ldrd(vRegD dst, memory8 mem) %{ + enc_class aarch64_enc_ldrd(vRegD dst, memory mem) %{ FloatRegister dst_reg = as_FloatRegister($dst$$reg); loadStore(masm, &MacroAssembler::ldrd, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 8); @@ -2928,7 +2932,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_strb(iRegI src, memory1 mem) %{ + enc_class aarch64_enc_strb(iRegI src, memory mem) %{ Register src_reg = as_Register($src$$reg); loadStore(masm, &MacroAssembler::strb, src_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 1); @@ -2936,14 +2940,14 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_strb0(memory1 mem) %{ + enc_class aarch64_enc_strb0(memory mem) %{ loadStore(masm, &MacroAssembler::strb, zr, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 1); %} // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_strh(iRegI src, memory2 mem) %{ + enc_class aarch64_enc_strh(iRegI src, memory mem) %{ Register src_reg = as_Register($src$$reg); loadStore(masm, &MacroAssembler::strh, src_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 2); @@ -2951,14 +2955,14 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_strh0(memory2 mem) %{ + enc_class aarch64_enc_strh0(memory mem) %{ loadStore(masm, &MacroAssembler::strh, zr, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 2); %} // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_strw(iRegI src, memory4 mem) %{ + enc_class aarch64_enc_strw(iRegI src, memory mem) %{ Register src_reg = as_Register($src$$reg); loadStore(masm, &MacroAssembler::strw, src_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 4); @@ -2966,14 +2970,14 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_strw0(memory4 mem) %{ + enc_class aarch64_enc_strw0(memory mem) %{ loadStore(masm, &MacroAssembler::strw, zr, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 4); %} // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_str(iRegL src, memory8 mem) %{ + enc_class aarch64_enc_str(iRegL src, memory mem) %{ Register src_reg = as_Register($src$$reg); // we sometimes get asked to store the stack pointer into the // current thread -- we cannot do that directly on AArch64 @@ -2988,14 +2992,14 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_str0(memory8 mem) %{ + enc_class aarch64_enc_str0(memory mem) %{ loadStore(masm, &MacroAssembler::str, zr, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 8); %} // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_strs(vRegF src, memory4 mem) %{ + enc_class aarch64_enc_strs(vRegF src, memory mem) %{ FloatRegister src_reg = as_FloatRegister($src$$reg); loadStore(masm, &MacroAssembler::strs, src_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 4); @@ -3003,7 +3007,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_strd(vRegD src, memory8 mem) %{ + enc_class aarch64_enc_strd(vRegD src, memory mem) %{ FloatRegister src_reg = as_FloatRegister($src$$reg); loadStore(masm, &MacroAssembler::strd, src_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 8); @@ -3011,7 +3015,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_strb0_ordered(memory4 mem) %{ + enc_class aarch64_enc_strb0_ordered(memory mem) %{ __ membar(Assembler::StoreStore); loadStore(masm, &MacroAssembler::strb, zr, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 1); @@ -3213,7 +3217,7 @@ encode %{ // synchronized read/update encodings - enc_class aarch64_enc_ldaxr(iRegL dst, memory8 mem) %{ + enc_class aarch64_enc_ldaxr(iRegL dst, memory mem) %{ Register dst_reg = as_Register($dst$$reg); Register base = as_Register($mem$$base); int index = $mem$$index; @@ -3241,7 +3245,7 @@ encode %{ } %} - enc_class aarch64_enc_stlxr(iRegLNoSp src, memory8 mem) %{ + enc_class aarch64_enc_stlxr(iRegLNoSp src, memory mem) %{ Register src_reg = as_Register($src$$reg); Register base = as_Register($mem$$base); int index = $mem$$index; @@ -4169,60 +4173,10 @@ operand immIU7() interface(CONST_INTER); %} -// Offset for scaled or unscaled immediate loads and stores +// Offset for immediate loads and stores operand immIOffset() %{ - predicate(Address::offset_ok_for_immed(n->get_int(), 0)); - match(ConI); - - op_cost(0); - format %{ %} - interface(CONST_INTER); -%} - -operand immIOffset1() -%{ - predicate(Address::offset_ok_for_immed(n->get_int(), 0)); - match(ConI); - - op_cost(0); - format %{ %} - interface(CONST_INTER); -%} - -operand immIOffset2() -%{ - predicate(Address::offset_ok_for_immed(n->get_int(), 1)); - match(ConI); - - op_cost(0); - format %{ %} - interface(CONST_INTER); -%} - -operand immIOffset4() -%{ - predicate(Address::offset_ok_for_immed(n->get_int(), 2)); - match(ConI); - - op_cost(0); - format %{ %} - interface(CONST_INTER); -%} - -operand immIOffset8() -%{ - predicate(Address::offset_ok_for_immed(n->get_int(), 3)); - match(ConI); - - op_cost(0); - format %{ %} - interface(CONST_INTER); -%} - -operand immIOffset16() -%{ - predicate(Address::offset_ok_for_immed(n->get_int(), 4)); + predicate(n->get_int() >= -256 && n->get_int() <= 65520); match(ConI); op_cost(0); @@ -4240,56 +4194,6 @@ operand immLOffset() interface(CONST_INTER); %} -operand immLoffset1() -%{ - predicate(Address::offset_ok_for_immed(n->get_long(), 0)); - match(ConL); - - op_cost(0); - format %{ %} - interface(CONST_INTER); -%} - -operand immLoffset2() -%{ - predicate(Address::offset_ok_for_immed(n->get_long(), 1)); - match(ConL); - - op_cost(0); - format %{ %} - interface(CONST_INTER); -%} - -operand immLoffset4() -%{ - predicate(Address::offset_ok_for_immed(n->get_long(), 2)); - match(ConL); - - op_cost(0); - format %{ %} - interface(CONST_INTER); -%} - -operand immLoffset8() -%{ - predicate(Address::offset_ok_for_immed(n->get_long(), 3)); - match(ConL); - - op_cost(0); - format %{ %} - interface(CONST_INTER); -%} - -operand immLoffset16() -%{ - predicate(Address::offset_ok_for_immed(n->get_long(), 4)); - match(ConL); - - op_cost(0); - format %{ %} - interface(CONST_INTER); -%} - // 5 bit signed long integer operand immL5() %{ @@ -5202,21 +5106,7 @@ operand indIndex(iRegP reg, iRegL lreg) %} %} -operand indOffI1(iRegP reg, immIOffset1 off) -%{ - constraint(ALLOC_IN_RC(ptr_reg)); - match(AddP reg off); - op_cost(0); - format %{ "[$reg, $off]" %} - interface(MEMORY_INTER) %{ - base($reg); - index(0xffffffff); - scale(0x0); - disp($off); - %} -%} - -operand indOffI2(iRegP reg, immIOffset2 off) +operand indOffI(iRegP reg, immIOffset off) %{ constraint(ALLOC_IN_RC(ptr_reg)); match(AddP reg off); @@ -5230,105 +5120,7 @@ operand indOffI2(iRegP reg, immIOffset2 off) %} %} -operand indOffI4(iRegP reg, immIOffset4 off) -%{ - constraint(ALLOC_IN_RC(ptr_reg)); - match(AddP reg off); - op_cost(0); - format %{ "[$reg, $off]" %} - interface(MEMORY_INTER) %{ - base($reg); - index(0xffffffff); - scale(0x0); - disp($off); - %} -%} - -operand indOffI8(iRegP reg, immIOffset8 off) -%{ - constraint(ALLOC_IN_RC(ptr_reg)); - match(AddP reg off); - op_cost(0); - format %{ "[$reg, $off]" %} - interface(MEMORY_INTER) %{ - base($reg); - index(0xffffffff); - scale(0x0); - disp($off); - %} -%} - -operand indOffI16(iRegP reg, immIOffset16 off) -%{ - constraint(ALLOC_IN_RC(ptr_reg)); - match(AddP reg off); - op_cost(0); - format %{ "[$reg, $off]" %} - interface(MEMORY_INTER) %{ - base($reg); - index(0xffffffff); - scale(0x0); - disp($off); - %} -%} - -operand indOffL1(iRegP reg, immLoffset1 off) -%{ - constraint(ALLOC_IN_RC(ptr_reg)); - match(AddP reg off); - op_cost(0); - format %{ "[$reg, $off]" %} - interface(MEMORY_INTER) %{ - base($reg); - index(0xffffffff); - scale(0x0); - disp($off); - %} -%} - -operand indOffL2(iRegP reg, immLoffset2 off) -%{ - constraint(ALLOC_IN_RC(ptr_reg)); - match(AddP reg off); - op_cost(0); - format %{ "[$reg, $off]" %} - interface(MEMORY_INTER) %{ - base($reg); - index(0xffffffff); - scale(0x0); - disp($off); - %} -%} - -operand indOffL4(iRegP reg, immLoffset4 off) -%{ - constraint(ALLOC_IN_RC(ptr_reg)); - match(AddP reg off); - op_cost(0); - format %{ "[$reg, $off]" %} - interface(MEMORY_INTER) %{ - base($reg); - index(0xffffffff); - scale(0x0); - disp($off); - %} -%} - -operand indOffL8(iRegP reg, immLoffset8 off) -%{ - constraint(ALLOC_IN_RC(ptr_reg)); - match(AddP reg off); - op_cost(0); - format %{ "[$reg, $off]" %} - interface(MEMORY_INTER) %{ - base($reg); - index(0xffffffff); - scale(0x0); - disp($off); - %} -%} - -operand indOffL16(iRegP reg, immLoffset16 off) +operand indOffL(iRegP reg, immLOffset off) %{ constraint(ALLOC_IN_RC(ptr_reg)); match(AddP reg off); @@ -5704,10 +5496,7 @@ operand iRegL2P(iRegL reg) %{ interface(REG_INTER) %} -opclass vmem2(indirect, indIndex, indOffI2, indOffL2); -opclass vmem4(indirect, indIndex, indOffI4, indOffL4); -opclass vmem8(indirect, indIndex, indOffI8, indOffL8); -opclass vmem16(indirect, indIndex, indOffI16, indOffL16); +opclass vmem(indirect, indIndex, indOffI, indOffL, indOffIN, indOffLN); //----------OPERAND CLASSES---------------------------------------------------- // Operand Classes are groups of operands that are used as to simplify @@ -5719,23 +5508,9 @@ opclass vmem16(indirect, indIndex, indOffI16, indOffL16); // memory is used to define read/write location for load/store // instruction defs. we can turn a memory op into an Address -opclass memory1(indirect, indIndexScaled, indIndexScaledI2L, indIndexI2L, indIndex, indOffI1, indOffL1, - indirectN, indIndexScaledN, indIndexScaledI2LN, indIndexI2LN, indIndexN, indirectX2P, indOffX2P); - -opclass memory2(indirect, indIndexScaled, indIndexScaledI2L, indIndexI2L, indIndex, indOffI2, indOffL2, - indirectN, indIndexScaledN, indIndexScaledI2LN, indIndexI2LN, indIndexN, indirectX2P, indOffX2P); - -opclass memory4(indirect, indIndexScaled, indIndexScaledI2L, indIndexI2L, indIndex, indOffI4, indOffL4, - indirectN, indIndexScaledN, indIndexScaledI2LN, indIndexI2LN, indIndexN, indOffIN, indOffLN, indirectX2P, indOffX2P); - -opclass memory8(indirect, indIndexScaled, indIndexScaledI2L, indIndexI2L, indIndex, indOffI8, indOffL8, - indirectN, indIndexScaledN, indIndexScaledI2LN, indIndexI2LN, indIndexN, indOffIN, indOffLN, indirectX2P, indOffX2P); - -// All of the memory operands. For the pipeline description. -opclass memory(indirect, indIndexScaled, indIndexScaledI2L, indIndexI2L, indIndex, - indOffI1, indOffL1, indOffI2, indOffL2, indOffI4, indOffL4, indOffI8, indOffL8, - indirectN, indIndexScaledN, indIndexScaledI2LN, indIndexI2LN, indIndexN, indOffIN, indOffLN, indirectX2P, indOffX2P); - +opclass memory(indirect, indIndexScaled, indIndexScaledI2L, indIndexI2L, indIndex, indOffI, indOffL, + indirectN, indIndexScaledN, indIndexScaledI2LN, indIndexI2LN, indIndexN, indOffIN, + indOffLN, indirectX2P, indOffX2P); // iRegIorL2I is used for src inputs in rules for 32 bit int (I) // operations. it allows the src to be either an iRegI or a (ConvL2I @@ -6437,7 +6212,7 @@ define %{ // Load Instructions // Load Byte (8 bit signed) -instruct loadB(iRegINoSp dst, memory1 mem) +instruct loadB(iRegINoSp dst, memory mem) %{ match(Set dst (LoadB mem)); predicate(!needs_acquiring_load(n)); @@ -6451,7 +6226,7 @@ instruct loadB(iRegINoSp dst, memory1 mem) %} // Load Byte (8 bit signed) into long -instruct loadB2L(iRegLNoSp dst, memory1 mem) +instruct loadB2L(iRegLNoSp dst, memory mem) %{ match(Set dst (ConvI2L (LoadB mem))); predicate(!needs_acquiring_load(n->in(1))); @@ -6465,7 +6240,7 @@ instruct loadB2L(iRegLNoSp dst, memory1 mem) %} // Load Byte (8 bit unsigned) -instruct loadUB(iRegINoSp dst, memory1 mem) +instruct loadUB(iRegINoSp dst, memory mem) %{ match(Set dst (LoadUB mem)); predicate(!needs_acquiring_load(n)); @@ -6479,7 +6254,7 @@ instruct loadUB(iRegINoSp dst, memory1 mem) %} // Load Byte (8 bit unsigned) into long -instruct loadUB2L(iRegLNoSp dst, memory1 mem) +instruct loadUB2L(iRegLNoSp dst, memory mem) %{ match(Set dst (ConvI2L (LoadUB mem))); predicate(!needs_acquiring_load(n->in(1))); @@ -6493,7 +6268,7 @@ instruct loadUB2L(iRegLNoSp dst, memory1 mem) %} // Load Short (16 bit signed) -instruct loadS(iRegINoSp dst, memory2 mem) +instruct loadS(iRegINoSp dst, memory mem) %{ match(Set dst (LoadS mem)); predicate(!needs_acquiring_load(n)); @@ -6507,7 +6282,7 @@ instruct loadS(iRegINoSp dst, memory2 mem) %} // Load Short (16 bit signed) into long -instruct loadS2L(iRegLNoSp dst, memory2 mem) +instruct loadS2L(iRegLNoSp dst, memory mem) %{ match(Set dst (ConvI2L (LoadS mem))); predicate(!needs_acquiring_load(n->in(1))); @@ -6521,7 +6296,7 @@ instruct loadS2L(iRegLNoSp dst, memory2 mem) %} // Load Char (16 bit unsigned) -instruct loadUS(iRegINoSp dst, memory2 mem) +instruct loadUS(iRegINoSp dst, memory mem) %{ match(Set dst (LoadUS mem)); predicate(!needs_acquiring_load(n)); @@ -6535,7 +6310,7 @@ instruct loadUS(iRegINoSp dst, memory2 mem) %} // Load Short/Char (16 bit unsigned) into long -instruct loadUS2L(iRegLNoSp dst, memory2 mem) +instruct loadUS2L(iRegLNoSp dst, memory mem) %{ match(Set dst (ConvI2L (LoadUS mem))); predicate(!needs_acquiring_load(n->in(1))); @@ -6549,7 +6324,7 @@ instruct loadUS2L(iRegLNoSp dst, memory2 mem) %} // Load Integer (32 bit signed) -instruct loadI(iRegINoSp dst, memory4 mem) +instruct loadI(iRegINoSp dst, memory mem) %{ match(Set dst (LoadI mem)); predicate(!needs_acquiring_load(n)); @@ -6563,7 +6338,7 @@ instruct loadI(iRegINoSp dst, memory4 mem) %} // Load Integer (32 bit signed) into long -instruct loadI2L(iRegLNoSp dst, memory4 mem) +instruct loadI2L(iRegLNoSp dst, memory mem) %{ match(Set dst (ConvI2L (LoadI mem))); predicate(!needs_acquiring_load(n->in(1))); @@ -6577,7 +6352,7 @@ instruct loadI2L(iRegLNoSp dst, memory4 mem) %} // Load Integer (32 bit unsigned) into long -instruct loadUI2L(iRegLNoSp dst, memory4 mem, immL_32bits mask) +instruct loadUI2L(iRegLNoSp dst, memory mem, immL_32bits mask) %{ match(Set dst (AndL (ConvI2L (LoadI mem)) mask)); predicate(!needs_acquiring_load(n->in(1)->in(1)->as_Load())); @@ -6591,7 +6366,7 @@ instruct loadUI2L(iRegLNoSp dst, memory4 mem, immL_32bits mask) %} // Load Long (64 bit signed) -instruct loadL(iRegLNoSp dst, memory8 mem) +instruct loadL(iRegLNoSp dst, memory mem) %{ match(Set dst (LoadL mem)); predicate(!needs_acquiring_load(n)); @@ -6605,7 +6380,7 @@ instruct loadL(iRegLNoSp dst, memory8 mem) %} // Load Range -instruct loadRange(iRegINoSp dst, memory4 mem) +instruct loadRange(iRegINoSp dst, memory mem) %{ match(Set dst (LoadRange mem)); @@ -6618,7 +6393,7 @@ instruct loadRange(iRegINoSp dst, memory4 mem) %} // Load Pointer -instruct loadP(iRegPNoSp dst, memory8 mem) +instruct loadP(iRegPNoSp dst, memory mem) %{ match(Set dst (LoadP mem)); predicate(!needs_acquiring_load(n) && (n->as_Load()->barrier_data() == 0)); @@ -6632,7 +6407,7 @@ instruct loadP(iRegPNoSp dst, memory8 mem) %} // Load Compressed Pointer -instruct loadN(iRegNNoSp dst, memory4 mem) +instruct loadN(iRegNNoSp dst, memory mem) %{ match(Set dst (LoadN mem)); predicate(!needs_acquiring_load(n)); @@ -6646,7 +6421,7 @@ instruct loadN(iRegNNoSp dst, memory4 mem) %} // Load Klass Pointer -instruct loadKlass(iRegPNoSp dst, memory8 mem) +instruct loadKlass(iRegPNoSp dst, memory mem) %{ match(Set dst (LoadKlass mem)); predicate(!needs_acquiring_load(n)); @@ -6660,7 +6435,7 @@ instruct loadKlass(iRegPNoSp dst, memory8 mem) %} // Load Narrow Klass Pointer -instruct loadNKlass(iRegNNoSp dst, memory4 mem) +instruct loadNKlass(iRegNNoSp dst, memory mem) %{ match(Set dst (LoadNKlass mem)); predicate(!needs_acquiring_load(n)); @@ -6674,7 +6449,7 @@ instruct loadNKlass(iRegNNoSp dst, memory4 mem) %} // Load Float -instruct loadF(vRegF dst, memory4 mem) +instruct loadF(vRegF dst, memory mem) %{ match(Set dst (LoadF mem)); predicate(!needs_acquiring_load(n)); @@ -6688,7 +6463,7 @@ instruct loadF(vRegF dst, memory4 mem) %} // Load Double -instruct loadD(vRegD dst, memory8 mem) +instruct loadD(vRegD dst, memory mem) %{ match(Set dst (LoadD mem)); predicate(!needs_acquiring_load(n)); @@ -6892,7 +6667,7 @@ instruct loadConD(vRegD dst, immD con) %{ // Store Instructions // Store CMS card-mark Immediate -instruct storeimmCM0(immI0 zero, memory1 mem) +instruct storeimmCM0(immI0 zero, memory mem) %{ match(Set mem (StoreCM mem zero)); @@ -6907,7 +6682,7 @@ instruct storeimmCM0(immI0 zero, memory1 mem) // Store CMS card-mark Immediate with intervening StoreStore // needed when using CMS with no conditional card marking -instruct storeimmCM0_ordered(immI0 zero, memory1 mem) +instruct storeimmCM0_ordered(immI0 zero, memory mem) %{ match(Set mem (StoreCM mem zero)); @@ -6922,7 +6697,7 @@ instruct storeimmCM0_ordered(immI0 zero, memory1 mem) %} // Store Byte -instruct storeB(iRegIorL2I src, memory1 mem) +instruct storeB(iRegIorL2I src, memory mem) %{ match(Set mem (StoreB mem src)); predicate(!needs_releasing_store(n)); @@ -6936,7 +6711,7 @@ instruct storeB(iRegIorL2I src, memory1 mem) %} -instruct storeimmB0(immI0 zero, memory1 mem) +instruct storeimmB0(immI0 zero, memory mem) %{ match(Set mem (StoreB mem zero)); predicate(!needs_releasing_store(n)); @@ -6950,7 +6725,7 @@ instruct storeimmB0(immI0 zero, memory1 mem) %} // Store Char/Short -instruct storeC(iRegIorL2I src, memory2 mem) +instruct storeC(iRegIorL2I src, memory mem) %{ match(Set mem (StoreC mem src)); predicate(!needs_releasing_store(n)); @@ -6963,7 +6738,7 @@ instruct storeC(iRegIorL2I src, memory2 mem) ins_pipe(istore_reg_mem); %} -instruct storeimmC0(immI0 zero, memory2 mem) +instruct storeimmC0(immI0 zero, memory mem) %{ match(Set mem (StoreC mem zero)); predicate(!needs_releasing_store(n)); @@ -6978,7 +6753,7 @@ instruct storeimmC0(immI0 zero, memory2 mem) // Store Integer -instruct storeI(iRegIorL2I src, memory4 mem) +instruct storeI(iRegIorL2I src, memory mem) %{ match(Set mem(StoreI mem src)); predicate(!needs_releasing_store(n)); @@ -6991,7 +6766,7 @@ instruct storeI(iRegIorL2I src, memory4 mem) ins_pipe(istore_reg_mem); %} -instruct storeimmI0(immI0 zero, memory4 mem) +instruct storeimmI0(immI0 zero, memory mem) %{ match(Set mem(StoreI mem zero)); predicate(!needs_releasing_store(n)); @@ -7005,7 +6780,7 @@ instruct storeimmI0(immI0 zero, memory4 mem) %} // Store Long (64 bit signed) -instruct storeL(iRegL src, memory8 mem) +instruct storeL(iRegL src, memory mem) %{ match(Set mem (StoreL mem src)); predicate(!needs_releasing_store(n)); @@ -7019,7 +6794,7 @@ instruct storeL(iRegL src, memory8 mem) %} // Store Long (64 bit signed) -instruct storeimmL0(immL0 zero, memory8 mem) +instruct storeimmL0(immL0 zero, memory mem) %{ match(Set mem (StoreL mem zero)); predicate(!needs_releasing_store(n)); @@ -7033,7 +6808,7 @@ instruct storeimmL0(immL0 zero, memory8 mem) %} // Store Pointer -instruct storeP(iRegP src, memory8 mem) +instruct storeP(iRegP src, memory mem) %{ match(Set mem (StoreP mem src)); predicate(!needs_releasing_store(n) && n->as_Store()->barrier_data() == 0); @@ -7047,7 +6822,7 @@ instruct storeP(iRegP src, memory8 mem) %} // Store Pointer -instruct storeimmP0(immP0 zero, memory8 mem) +instruct storeimmP0(immP0 zero, memory mem) %{ match(Set mem (StoreP mem zero)); predicate(!needs_releasing_store(n) && n->as_Store()->barrier_data() == 0); @@ -7061,7 +6836,7 @@ instruct storeimmP0(immP0 zero, memory8 mem) %} // Store Compressed Pointer -instruct storeN(iRegN src, memory4 mem) +instruct storeN(iRegN src, memory mem) %{ match(Set mem (StoreN mem src)); predicate(!needs_releasing_store(n)); @@ -7074,7 +6849,7 @@ instruct storeN(iRegN src, memory4 mem) ins_pipe(istore_reg_mem); %} -instruct storeImmN0(immN0 zero, memory4 mem) +instruct storeImmN0(immN0 zero, memory mem) %{ match(Set mem (StoreN mem zero)); predicate(!needs_releasing_store(n)); @@ -7088,7 +6863,7 @@ instruct storeImmN0(immN0 zero, memory4 mem) %} // Store Float -instruct storeF(vRegF src, memory4 mem) +instruct storeF(vRegF src, memory mem) %{ match(Set mem (StoreF mem src)); predicate(!needs_releasing_store(n)); @@ -7105,7 +6880,7 @@ instruct storeF(vRegF src, memory4 mem) // implement storeImmF0 and storeFImmPacked // Store Double -instruct storeD(vRegD src, memory8 mem) +instruct storeD(vRegD src, memory mem) %{ match(Set mem (StoreD mem src)); predicate(!needs_releasing_store(n)); @@ -7119,7 +6894,7 @@ instruct storeD(vRegD src, memory8 mem) %} // Store Compressed Klass Pointer -instruct storeNKlass(iRegN src, memory4 mem) +instruct storeNKlass(iRegN src, memory mem) %{ predicate(!needs_releasing_store(n)); match(Set mem (StoreNKlass mem src)); @@ -7138,7 +6913,7 @@ instruct storeNKlass(iRegN src, memory4 mem) // prefetch instructions // Must be safe to execute with invalid address (cannot fault). -instruct prefetchalloc( memory8 mem ) %{ +instruct prefetchalloc( memory mem ) %{ match(PrefetchAllocation mem); ins_cost(INSN_COST); @@ -7707,7 +7482,7 @@ instruct popCountI(iRegINoSp dst, iRegIorL2I src, vRegF tmp) %{ ins_pipe(pipe_class_default); %} -instruct popCountI_mem(iRegINoSp dst, memory4 mem, vRegF tmp) %{ +instruct popCountI_mem(iRegINoSp dst, memory mem, vRegF tmp) %{ match(Set dst (PopCountI (LoadI mem))); effect(TEMP tmp); ins_cost(INSN_COST * 13); @@ -7748,7 +7523,7 @@ instruct popCountL(iRegINoSp dst, iRegL src, vRegD tmp) %{ ins_pipe(pipe_class_default); %} -instruct popCountL_mem(iRegINoSp dst, memory8 mem, vRegD tmp) %{ +instruct popCountL_mem(iRegINoSp dst, memory mem, vRegD tmp) %{ match(Set dst (PopCountL (LoadL mem))); effect(TEMP tmp); ins_cost(INSN_COST * 13); @@ -16897,7 +16672,7 @@ instruct compressBitsI_reg(iRegINoSp dst, iRegIorL2I src, iRegIorL2I mask, ins_pipe(pipe_slow); %} -instruct compressBitsI_memcon(iRegINoSp dst, memory4 mem, immI mask, +instruct compressBitsI_memcon(iRegINoSp dst, memory mem, immI mask, vRegF tdst, vRegF tsrc, vRegF tmask) %{ match(Set dst (CompressBits (LoadI mem) mask)); effect(TEMP tdst, TEMP tsrc, TEMP tmask); @@ -16934,7 +16709,7 @@ instruct compressBitsL_reg(iRegLNoSp dst, iRegL src, iRegL mask, ins_pipe(pipe_slow); %} -instruct compressBitsL_memcon(iRegLNoSp dst, memory8 mem, immL mask, +instruct compressBitsL_memcon(iRegLNoSp dst, memory mem, immL mask, vRegF tdst, vRegF tsrc, vRegF tmask) %{ match(Set dst (CompressBits (LoadL mem) mask)); effect(TEMP tdst, TEMP tsrc, TEMP tmask); @@ -16971,7 +16746,7 @@ instruct expandBitsI_reg(iRegINoSp dst, iRegIorL2I src, iRegIorL2I mask, ins_pipe(pipe_slow); %} -instruct expandBitsI_memcon(iRegINoSp dst, memory4 mem, immI mask, +instruct expandBitsI_memcon(iRegINoSp dst, memory mem, immI mask, vRegF tdst, vRegF tsrc, vRegF tmask) %{ match(Set dst (ExpandBits (LoadI mem) mask)); effect(TEMP tdst, TEMP tsrc, TEMP tmask); @@ -17009,7 +16784,7 @@ instruct expandBitsL_reg(iRegLNoSp dst, iRegL src, iRegL mask, %} -instruct expandBitsL_memcon(iRegINoSp dst, memory8 mem, immL mask, +instruct expandBitsL_memcon(iRegINoSp dst, memory mem, immL mask, vRegF tdst, vRegF tsrc, vRegF tmask) %{ match(Set dst (ExpandBits (LoadL mem) mask)); effect(TEMP tdst, TEMP tsrc, TEMP tmask); diff --git a/src/hotspot/cpu/aarch64/aarch64_vector.ad b/src/hotspot/cpu/aarch64/aarch64_vector.ad index 1ebc6408a6094..637d3de73af6f 100644 --- a/src/hotspot/cpu/aarch64/aarch64_vector.ad +++ b/src/hotspot/cpu/aarch64/aarch64_vector.ad @@ -345,7 +345,7 @@ source %{ // ------------------------------ Vector load/store ---------------------------- // Load Vector (16 bits) -instruct loadV2(vReg dst, vmem2 mem) %{ +instruct loadV2(vReg dst, vmem mem) %{ predicate(n->as_LoadVector()->memory_size() == 2); match(Set dst (LoadVector mem)); format %{ "loadV2 $dst, $mem\t# vector (16 bits)" %} @@ -354,7 +354,7 @@ instruct loadV2(vReg dst, vmem2 mem) %{ %} // Store Vector (16 bits) -instruct storeV2(vReg src, vmem2 mem) %{ +instruct storeV2(vReg src, vmem mem) %{ predicate(n->as_StoreVector()->memory_size() == 2); match(Set mem (StoreVector mem src)); format %{ "storeV2 $mem, $src\t# vector (16 bits)" %} @@ -363,7 +363,7 @@ instruct storeV2(vReg src, vmem2 mem) %{ %} // Load Vector (32 bits) -instruct loadV4(vReg dst, vmem4 mem) %{ +instruct loadV4(vReg dst, vmem mem) %{ predicate(n->as_LoadVector()->memory_size() == 4); match(Set dst (LoadVector mem)); format %{ "loadV4 $dst, $mem\t# vector (32 bits)" %} @@ -372,7 +372,7 @@ instruct loadV4(vReg dst, vmem4 mem) %{ %} // Store Vector (32 bits) -instruct storeV4(vReg src, vmem4 mem) %{ +instruct storeV4(vReg src, vmem mem) %{ predicate(n->as_StoreVector()->memory_size() == 4); match(Set mem (StoreVector mem src)); format %{ "storeV4 $mem, $src\t# vector (32 bits)" %} @@ -381,7 +381,7 @@ instruct storeV4(vReg src, vmem4 mem) %{ %} // Load Vector (64 bits) -instruct loadV8(vReg dst, vmem8 mem) %{ +instruct loadV8(vReg dst, vmem mem) %{ predicate(n->as_LoadVector()->memory_size() == 8); match(Set dst (LoadVector mem)); format %{ "loadV8 $dst, $mem\t# vector (64 bits)" %} @@ -390,7 +390,7 @@ instruct loadV8(vReg dst, vmem8 mem) %{ %} // Store Vector (64 bits) -instruct storeV8(vReg src, vmem8 mem) %{ +instruct storeV8(vReg src, vmem mem) %{ predicate(n->as_StoreVector()->memory_size() == 8); match(Set mem (StoreVector mem src)); format %{ "storeV8 $mem, $src\t# vector (64 bits)" %} @@ -399,7 +399,7 @@ instruct storeV8(vReg src, vmem8 mem) %{ %} // Load Vector (128 bits) -instruct loadV16(vReg dst, vmem16 mem) %{ +instruct loadV16(vReg dst, vmem mem) %{ predicate(n->as_LoadVector()->memory_size() == 16); match(Set dst (LoadVector mem)); format %{ "loadV16 $dst, $mem\t# vector (128 bits)" %} @@ -408,7 +408,7 @@ instruct loadV16(vReg dst, vmem16 mem) %{ %} // Store Vector (128 bits) -instruct storeV16(vReg src, vmem16 mem) %{ +instruct storeV16(vReg src, vmem mem) %{ predicate(n->as_StoreVector()->memory_size() == 16); match(Set mem (StoreVector mem src)); format %{ "storeV16 $mem, $src\t# vector (128 bits)" %} diff --git a/src/hotspot/cpu/aarch64/aarch64_vector_ad.m4 b/src/hotspot/cpu/aarch64/aarch64_vector_ad.m4 index 29f927723688f..b3403ec82a1fe 100644 --- a/src/hotspot/cpu/aarch64/aarch64_vector_ad.m4 +++ b/src/hotspot/cpu/aarch64/aarch64_vector_ad.m4 @@ -338,7 +338,7 @@ dnl VECTOR_LOAD_STORE($1, $2, $3, $4, $5 ) dnl VECTOR_LOAD_STORE(type, nbytes, arg_name, nbits, size) define(`VECTOR_LOAD_STORE', ` // ifelse(load, $1, Load, Store) Vector ($4 bits) -instruct $1V$2(vReg $3, vmem$2 mem) %{ +instruct $1V$2(vReg $3, vmem mem) %{ predicate(`n->as_'ifelse(load, $1, Load, Store)Vector()->memory_size() == $2); match(Set ifelse(load, $1, dst (LoadVector mem), mem (StoreVector mem src))); format %{ "$1V$2 ifelse(load, $1, `$dst, $mem', `$mem, $src')\t# vector ($4 bits)" %} diff --git a/src/hotspot/cpu/aarch64/ad_encode.m4 b/src/hotspot/cpu/aarch64/ad_encode.m4 index 008dbd2c9369c..e3d8ea661b60a 100644 --- a/src/hotspot/cpu/aarch64/ad_encode.m4 +++ b/src/hotspot/cpu/aarch64/ad_encode.m4 @@ -34,7 +34,7 @@ define(access, ` define(load,` // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_$2($1 dst, memory$5 mem) %{dnl + enc_class aarch64_enc_$2($1 dst, memory mem) %{dnl access(dst,$2,$3,$4,$5)')dnl load(iRegI,ldrsbw,,,1) load(iRegI,ldrsb,,,1) @@ -53,12 +53,12 @@ load(vRegD,ldrd,Float,,8) define(STORE,` // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_$2($1 src, memory$5 mem) %{dnl + enc_class aarch64_enc_$2($1 src, memory mem) %{dnl access(src,$2,$3,$4,$5)')dnl define(STORE0,` // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_$2`'0(memory$4 mem) %{ + enc_class aarch64_enc_$2`'0(memory mem) %{ choose(masm,zr,$2,$mem->opcode(), as_$3Register($mem$$base),$mem$$index,$mem$$scale,$mem$$disp,$4)')dnl STORE(iRegI,strb,,,1) @@ -82,7 +82,7 @@ STORE(vRegD,strd,Float,,8) // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_strb0_ordered(memory4 mem) %{ + enc_class aarch64_enc_strb0_ordered(memory mem) %{ __ membar(Assembler::StoreStore); loadStore(masm, &MacroAssembler::strb, zr, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 1); diff --git a/src/hotspot/cpu/aarch64/gc/x/x_aarch64.ad b/src/hotspot/cpu/aarch64/gc/x/x_aarch64.ad index 6e401724baa82..5e690a8e47b94 100644 --- a/src/hotspot/cpu/aarch64/gc/x/x_aarch64.ad +++ b/src/hotspot/cpu/aarch64/gc/x/x_aarch64.ad @@ -51,7 +51,7 @@ static void x_load_barrier_slow_path(MacroAssembler* masm, const MachNode* node, %} // Load Pointer -instruct xLoadP(iRegPNoSp dst, memory8 mem, rFlagsReg cr) +instruct xLoadP(iRegPNoSp dst, memory mem, rFlagsReg cr) %{ match(Set dst (LoadP mem)); predicate(UseZGC && !ZGenerational && !needs_acquiring_load(n) && (n->as_Load()->barrier_data() != 0)); diff --git a/src/hotspot/cpu/aarch64/gc/z/z_aarch64.ad b/src/hotspot/cpu/aarch64/gc/z/z_aarch64.ad index 56d4538477920..1510b42bfe97d 100644 --- a/src/hotspot/cpu/aarch64/gc/z/z_aarch64.ad +++ b/src/hotspot/cpu/aarch64/gc/z/z_aarch64.ad @@ -100,7 +100,7 @@ static void z_store_barrier(MacroAssembler* masm, const MachNode* node, Address %} // Load Pointer -instruct zLoadP(iRegPNoSp dst, memory8 mem, rFlagsReg cr) +instruct zLoadP(iRegPNoSp dst, memory mem, rFlagsReg cr) %{ match(Set dst (LoadP mem)); predicate(UseZGC && ZGenerational && !needs_acquiring_load(n) && n->as_Load()->barrier_data() != 0); diff --git a/test/hotspot/jtreg/compiler/c2/TestUnalignedAccess.java b/test/hotspot/jtreg/compiler/c2/TestUnalignedAccess.java index d05dbad4a73ba..033ea49e60955 100644 --- a/test/hotspot/jtreg/compiler/c2/TestUnalignedAccess.java +++ b/test/hotspot/jtreg/compiler/c2/TestUnalignedAccess.java @@ -46,20 +46,11 @@ public class TestUnalignedAccess { static final Unsafe UNSAFE = Unsafe.getUnsafe(); static void sink(int x) {} - public static long lseed = 1; - public static int iseed = 2; - public static short sseed = 3; - public static byte bseed = 4; - public static long lres = lseed; - public static int ires = iseed; - public static short sres = sseed; - public static byte bres = bseed; - public static class TestLong { private static final byte[] BYTES = new byte[LEN]; private static final long rawdata = 0xbeef; - private static final long data; + private static final long lseed = 1; static { sink(2); @@ -69,13 +60,10 @@ public static class TestLong { // 1030 can't be encoded as "base + offset" mode into the instruction field. UNSAFE.putLongUnaligned(BYTES, 1030, rawdata); - lres += UNSAFE.getLongUnaligned(BYTES, 1030); // 127 can be encoded into simm9 field. - UNSAFE.putLongUnaligned(BYTES, 127, lres); - lres += UNSAFE.getLongUnaligned(BYTES, 127); + UNSAFE.putLongUnaligned(BYTES, 127, rawdata+lseed); // 1096 can be encoded into uimm12 field. - UNSAFE.putLongUnaligned(BYTES, 1096, lres); - data = UNSAFE.getLongUnaligned(BYTES, 1096); + UNSAFE.putLongUnaligned(BYTES, 1096, rawdata-lseed); } } @@ -84,7 +72,7 @@ public static class TestInt { private static final byte[] BYTES = new byte[LEN]; private static final int rawdata = 0xbeef; - private static final int data; + private static final int iseed = 2; static { sink(2); // Signed immediate byte offset: range -256 to 255 @@ -93,13 +81,10 @@ public static class TestInt { // 274 can't be encoded as "base + offset" mode into the instruction field. UNSAFE.putIntUnaligned(BYTES, 274, rawdata); - ires += UNSAFE.getIntUnaligned(BYTES, 274); // 255 can be encoded into simm9 field. - UNSAFE.putIntUnaligned(BYTES, 255, ires); - ires += UNSAFE.getIntUnaligned(BYTES, 255); + UNSAFE.putIntUnaligned(BYTES, 255, rawdata + iseed); // 528 can be encoded into uimm12 field. - UNSAFE.putIntUnaligned(BYTES, 528, ires); - data = UNSAFE.getIntUnaligned(BYTES, 528); + UNSAFE.putIntUnaligned(BYTES, 528, rawdata - iseed); } } @@ -108,7 +93,7 @@ public static class TestShort { private static final byte[] BYTES = new byte[LEN]; private static final short rawdata = (short)0xbeef; - private static final short data; + private static final short sseed = 3; static { sink(2); // Signed immediate byte offset: range -256 to 255 @@ -117,13 +102,10 @@ public static class TestShort { // 257 can't be encoded as "base + offset" mode into the instruction field. UNSAFE.putShortUnaligned(BYTES, 257, rawdata); - sres = (short) (sres + UNSAFE.getShortUnaligned(BYTES, 257)); // 253 can be encoded into simm9 field. - UNSAFE.putShortUnaligned(BYTES, 253, sres); - sres = (short) (sres + UNSAFE.getShortUnaligned(BYTES, 253)); + UNSAFE.putShortUnaligned(BYTES, 253, (short) (rawdata + sseed)); // 272 can be encoded into uimm12 field. - UNSAFE.putShortUnaligned(BYTES, 272, sres); - data = UNSAFE.getShortUnaligned(BYTES, 272); + UNSAFE.putShortUnaligned(BYTES, 272, (short) (rawdata - sseed)); } } @@ -132,7 +114,7 @@ public static class TestByte { private static final byte[] BYTES = new byte[LEN]; private static final byte rawdata = (byte)0x3f; - private static final byte data; + private static final byte bseed = 4; static { sink(2); // Signed immediate byte offset: range -256 to 255 @@ -141,29 +123,34 @@ public static class TestByte { // 272 can be encoded into simm9 field. UNSAFE.putByte(BYTES, 272, rawdata); - bres = (byte) (bres + UNSAFE.getByte(BYTES, 272)); // 53 can be encoded into simm9 field. - UNSAFE.putByte(BYTES, 53, bres); - bres = (byte) (bres + UNSAFE.getByte(BYTES, 53)); + UNSAFE.putByte(BYTES, 53, (byte) (rawdata + bseed)); // 1027 can be encoded into uimm12 field. - UNSAFE.putByte(BYTES, 1027, bres); - data = UNSAFE.getByte(BYTES, 1027); + UNSAFE.putByte(BYTES, 1027, (byte) (rawdata - bseed)); } } static void test() { TestLong ta = new TestLong(); - Asserts.assertEquals(ta.data, (ta.rawdata + lseed) * 2, "putUnaligned long failed!"); + Asserts.assertEquals(UNSAFE.getLongUnaligned(ta.BYTES, 1030), ta.rawdata, "putUnaligned long failed!"); + Asserts.assertEquals(UNSAFE.getLongUnaligned(ta.BYTES, 127), ta.rawdata + ta.lseed, "putUnaligned long failed!"); + Asserts.assertEquals(UNSAFE.getLongUnaligned(ta.BYTES, 1096), ta.rawdata - ta.lseed, "putUnaligned long failed!"); TestInt tb = new TestInt(); - Asserts.assertEquals(tb.data, (tb.rawdata + iseed) * 2, "putUnaligned int failed!"); + Asserts.assertEquals(UNSAFE.getIntUnaligned(tb.BYTES, 274), tb.rawdata, "putUnaligned int failed!"); + Asserts.assertEquals(UNSAFE.getIntUnaligned(tb.BYTES, 255), tb.rawdata + tb.iseed, "putUnaligned int failed!"); + Asserts.assertEquals(UNSAFE.getIntUnaligned(tb.BYTES, 528), tb.rawdata - tb.iseed, "putUnaligned int failed!"); TestShort tc = new TestShort(); - Asserts.assertEquals(tc.data, (short) (((short) (tc.rawdata + sseed)) * 2), "putUnaligned short failed!"); + Asserts.assertEquals(UNSAFE.getShortUnaligned(tc.BYTES, 257), tc.rawdata, "putUnaligned short failed!"); + Asserts.assertEquals(UNSAFE.getShortUnaligned(tc.BYTES, 253), (short) (tc.rawdata + tc.sseed), "putUnaligned short failed!"); + Asserts.assertEquals(UNSAFE.getShortUnaligned(tc.BYTES, 272), (short) (tc.rawdata - tc.sseed), "putUnaligned short failed!"); TestByte td = new TestByte(); - Asserts.assertEquals(td.data, (byte) (((byte) (td.rawdata + bseed)) * 2), "put byte failed!"); + Asserts.assertEquals(UNSAFE.getByte(td.BYTES, 272), td.rawdata, "put byte failed!"); + Asserts.assertEquals(UNSAFE.getByte(td.BYTES, 53), (byte) (td.rawdata + td.bseed), "put byte failed!"); + Asserts.assertEquals(UNSAFE.getByte(td.BYTES, 1027), (byte) (td.rawdata - td.bseed), "put byte failed!"); } public static void main(String[] strArr) { From 6169613d9f3f0bf019d04a37a1d8f28f1463c17c Mon Sep 17 00:00:00 2001 From: Daniel Fuchs Date: Thu, 15 Aug 2024 15:34:08 +0000 Subject: [PATCH 316/353] 8336655: java/net/httpclient/DigestEchoClient.java IOException: HTTP/1.1 header parser received no bytes Reviewed-by: jpai --- .../jdk/internal/net/http/ConnectionPool.java | 36 +++++++++++++++---- .../jdk/internal/net/http/SocketTube.java | 23 ++++++++++-- .../java/net/httpclient/DigestEchoClient.java | 4 +-- 3 files changed, 52 insertions(+), 11 deletions(-) diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/ConnectionPool.java b/src/java.net.http/share/classes/jdk/internal/net/http/ConnectionPool.java index 0ad7b9d5992c0..edaf53a8a0ddf 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/ConnectionPool.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/ConnectionPool.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,6 +44,7 @@ import jdk.internal.net.http.common.Deadline; import jdk.internal.net.http.common.FlowTube; +import jdk.internal.net.http.common.Log; import jdk.internal.net.http.common.Logger; import jdk.internal.net.http.common.TimeLine; import jdk.internal.net.http.common.TimeSource; @@ -492,13 +493,13 @@ void clear() { // Remove a connection from the pool. // should only be called while holding the ConnectionPool stateLock. - private void removeFromPool(HttpConnection c) { + private boolean removeFromPool(HttpConnection c) { assert stateLock.isHeldByCurrentThread(); if (c instanceof PlainHttpConnection) { - removeFromPool(c, plainPool); + return removeFromPool(c, plainPool); } else { assert c.isSecure() : "connection " + c + " is not secure!"; - removeFromPool(c, sslPool); + return removeFromPool(c, sslPool); } } @@ -529,13 +530,29 @@ void cleanup(HttpConnection c, Throwable error) { debug.log("%s : ConnectionPool.cleanup(%s)", String.valueOf(c.getConnectionFlow()), error); stateLock.lock(); + boolean removed; try { - removeFromPool(c); + removed = removeFromPool(c); expiryList.remove(c); } finally { stateLock.unlock(); } - c.close(); + if (!removed) { + // this should not happen; the cleanup may have consumed + // some data that wasn't supposed to be consumed, so + // the only thing we can do is log it and close the + // connection. + if (Log.errors()) { + Log.logError("WARNING: CleanupTrigger triggered for" + + " a connection not found in the pool: closing {0}", c); + } else if (debug.on()) { + debug.log("WARNING: CleanupTrigger triggered for" + + " a connection not found in the pool: closing %s", c); + } + c.close(new IOException("Unexpected cleanup triggered for non pooled connection")); + } else { + c.close(); + } } /** @@ -549,6 +566,7 @@ private final class CleanupTrigger implements private final HttpConnection connection; private volatile boolean done; + private volatile boolean dropped; public CleanupTrigger(HttpConnection connection) { this.connection = connection; @@ -566,6 +584,7 @@ private void triggerCleanup(Throwable error) { @Override public void onSubscribe(Flow.Subscription subscription) { + if (dropped || done) return; subscription.request(1); } @Override @@ -586,5 +605,10 @@ public void subscribe(Flow.Subscriber> subscriber) { public String toString() { return "CleanupTrigger(" + connection.getConnectionFlow() + ")"; } + + @Override + public void dropSubscription() { + dropped = true; + } } } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/SocketTube.java b/src/java.net.http/share/classes/jdk/internal/net/http/SocketTube.java index cbdf663357603..9317bdf442a51 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/SocketTube.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/SocketTube.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -573,6 +573,8 @@ public void subscribe(Flow.Subscriber> s) { debug.log("read publisher: dropping pending subscriber: " + previous.subscriber); previous.errorRef.compareAndSet(null, errorRef.get()); + // make sure no data will be routed to the old subscriber. + previous.stopReading(); previous.signalOnSubscribe(); if (subscriptionImpl.completed) { previous.signalCompletion(); @@ -606,6 +608,7 @@ final class ReadSubscription implements Flow.Subscription { volatile boolean subscribed; volatile boolean cancelled; volatile boolean completed; + volatile boolean stopped; public ReadSubscription(InternalReadSubscription impl, TubeSubscriber subscriber) { @@ -623,11 +626,11 @@ public void cancel() { @Override public void request(long n) { - if (!cancelled) { + if (!cancelled && !stopped) { impl.request(n); } else { if (debug.on()) - debug.log("subscription cancelled, ignoring request %d", n); + debug.log("subscription stopped or cancelled, ignoring request %d", n); } } @@ -661,6 +664,20 @@ void signalOnSubscribe() { signalCompletion(); } } + + /** + * Called when switching subscriber on the {@link InternalReadSubscription}. + * This subscriber is the old subscriber. Demand on the internal + * subscription will be reset and reading will be paused until the + * new subscriber is subscribed. + * This should ensure that no data is routed to this subscriber + * until the new subscriber is subscribed. + */ + void stopReading() { + stopped = true; + impl.demand.reset(); + impl.pauseReadEvent(); + } } final class InternalReadSubscription implements Flow.Subscription { diff --git a/test/jdk/java/net/httpclient/DigestEchoClient.java b/test/jdk/java/net/httpclient/DigestEchoClient.java index 3b6d1a1773f8d..1450bf09b2d6b 100644 --- a/test/jdk/java/net/httpclient/DigestEchoClient.java +++ b/test/jdk/java/net/httpclient/DigestEchoClient.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -64,7 +64,7 @@ * @test * @summary this test verifies that a client may provides authorization * headers directly when connecting with a server. - * @bug 8087112 + * @bug 8087112 8336655 * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.httpclient.test.lib.common.HttpServerAdapters jdk.test.lib.net.SimpleSSLContext * DigestEchoServer ReferenceTracker DigestEchoClient From 7d1bbff076c063d066951eedb21de7e694e588b3 Mon Sep 17 00:00:00 2001 From: "lawrence.andrews" Date: Thu, 15 Aug 2024 16:36:15 +0000 Subject: [PATCH 317/353] 8328553: Get rid of JApplet in test/jdk/sanity/client/lib/SwingSet2/src/DemoModule.java Reviewed-by: honkar, prr --- .../client/lib/SwingSet2/src/DemoModule.java | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/test/jdk/sanity/client/lib/SwingSet2/src/DemoModule.java b/test/jdk/sanity/client/lib/SwingSet2/src/DemoModule.java index 3511583e932ec..0e7c71083dc14 100644 --- a/test/jdk/sanity/client/lib/SwingSet2/src/DemoModule.java +++ b/test/jdk/sanity/client/lib/SwingSet2/src/DemoModule.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,6 @@ import javax.swing.BoxLayout; import javax.swing.Icon; import javax.swing.ImageIcon; -import javax.swing.JApplet; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.UIManager; @@ -42,10 +41,8 @@ /** * A generic SwingSet2 demo module - * - * @author Jeff Dinkins */ -public class DemoModule extends JApplet { +public class DemoModule extends JPanel { // The preferred size of the demo private int PREFERRED_WIDTH = 680; @@ -214,10 +211,6 @@ public static void main(String[] args) { demo.mainImpl(); } - public void init() { - getContentPane().setLayout(new BorderLayout()); - getContentPane().add(getDemoPanel(), BorderLayout.CENTER); - } - void updateDragEnabled(boolean dragEnabled) {} -} \ No newline at end of file +} + From ef54af39883e76c80a3e012ed91b90973da51bb4 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Thu, 15 Aug 2024 16:45:43 +0000 Subject: [PATCH 318/353] 8338444: Shenandoah: Remove ShenandoahHumongousThreshold tunable Reviewed-by: rkennke, wkemper, ysr --- .../share/gc/shenandoah/shenandoahAsserts.cpp | 2 +- .../gc/shenandoah/shenandoahController.cpp | 4 +- .../share/gc/shenandoah/shenandoahFreeSet.cpp | 5 +- .../share/gc/shenandoah/shenandoahFreeSet.hpp | 4 +- .../gc/shenandoah/shenandoahHeapRegion.cpp | 14 +- .../gc/shenandoah/shenandoahHeapRegion.hpp | 14 +- .../gc/shenandoah/shenandoahInitLogger.cpp | 1 - .../gc/shenandoah/shenandoah_globals.hpp | 7 - .../gc/shenandoah/TestHumongousThreshold.java | 131 ------------------ .../options/TestHumongousThresholdArgs.java | 72 ---------- 10 files changed, 12 insertions(+), 242 deletions(-) delete mode 100644 test/hotspot/jtreg/gc/shenandoah/TestHumongousThreshold.java delete mode 100644 test/hotspot/jtreg/gc/shenandoah/options/TestHumongousThresholdArgs.java diff --git a/src/hotspot/share/gc/shenandoah/shenandoahAsserts.cpp b/src/hotspot/share/gc/shenandoah/shenandoahAsserts.cpp index 5215aa749aea1..5abd7b805f9fc 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahAsserts.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahAsserts.cpp @@ -283,7 +283,7 @@ void ShenandoahAsserts::assert_in_correct_region(void* interior_loc, oop obj, co } size_t alloc_size = obj->size(); - if (alloc_size > ShenandoahHeapRegion::humongous_threshold_words()) { + if (ShenandoahHeapRegion::requires_humongous(alloc_size)) { size_t idx = r->index(); size_t num_regions = ShenandoahHeapRegion::required_regions(alloc_size * HeapWordSize); for (size_t i = idx; i < idx + num_regions; i++) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahController.cpp b/src/hotspot/share/gc/shenandoah/shenandoahController.cpp index 6d6d21c406623..effa4a8f1fc9c 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahController.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahController.cpp @@ -57,7 +57,7 @@ void ShenandoahController::handle_alloc_failure(ShenandoahAllocRequest& req, boo ShenandoahHeap* heap = ShenandoahHeap::heap(); assert(current()->is_Java_thread(), "expect Java thread here"); - bool is_humongous = req.size() > ShenandoahHeapRegion::humongous_threshold_words(); + bool is_humongous = ShenandoahHeapRegion::requires_humongous(req.size()); if (try_set_alloc_failure_gc(is_humongous)) { // Only report the first allocation failure @@ -80,7 +80,7 @@ void ShenandoahController::handle_alloc_failure(ShenandoahAllocRequest& req, boo void ShenandoahController::handle_alloc_failure_evac(size_t words) { ShenandoahHeap* heap = ShenandoahHeap::heap(); - bool is_humongous = (words > ShenandoahHeapRegion::region_size_words()); + bool is_humongous = ShenandoahHeapRegion::requires_humongous(words); if (try_set_alloc_failure_gc(is_humongous)) { // Only report the first allocation failure diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp index b47bb109031c8..3dfc6a7966562 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp @@ -1308,7 +1308,7 @@ void ShenandoahFreeSet::log_status() { HeapWord* ShenandoahFreeSet::allocate(ShenandoahAllocRequest& req, bool& in_new_region) { shenandoah_assert_heaplocked(); - if (req.size() > ShenandoahHeapRegion::humongous_threshold_words()) { + if (ShenandoahHeapRegion::requires_humongous(req.size())) { switch (req.type()) { case ShenandoahAllocRequest::_alloc_shared: case ShenandoahAllocRequest::_alloc_shared_gc: @@ -1317,8 +1317,7 @@ HeapWord* ShenandoahFreeSet::allocate(ShenandoahAllocRequest& req, bool& in_new_ case ShenandoahAllocRequest::_alloc_gclab: case ShenandoahAllocRequest::_alloc_tlab: in_new_region = false; - assert(false, "Trying to allocate TLAB larger than the humongous threshold: " SIZE_FORMAT " > " SIZE_FORMAT, - req.size(), ShenandoahHeapRegion::humongous_threshold_words()); + assert(false, "Trying to allocate TLAB in humongous region: " SIZE_FORMAT, req.size()); return nullptr; default: ShouldNotReachHere(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp index 1975174b78492..e4e2bb4d6e658 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp @@ -277,14 +277,14 @@ class ShenandoahFreeSet : public CHeapObj { // While holding the heap lock, allocate memory for a single object or LAB which is to be entirely contained // within a single HeapRegion as characterized by req. // - // Precondition: req.size() <= ShenandoahHeapRegion::humongous_threshold_words(). + // Precondition: !ShenandoahHeapRegion::requires_humongous(req.size()) HeapWord* allocate_single(ShenandoahAllocRequest& req, bool& in_new_region); // While holding the heap lock, allocate memory for a humongous object which spans one or more regions that // were previously empty. Regions that represent humongous objects are entirely dedicated to the humongous // object. No other objects are packed into these regions. // - // Precondition: req.size() > ShenandoahHeapRegion::humongous_threshold_words(). + // Precondition: ShenandoahHeapRegion::requires_humongous(req.size()) HeapWord* allocate_contiguous(ShenandoahAllocRequest& req); // Change region r from the Mutator partition to the GC's Collector partition. This requires that the region is entirely empty. diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp index 8a94b20670a9f..eceed8dbe433e 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp @@ -51,8 +51,6 @@ size_t ShenandoahHeapRegion::RegionSizeBytesShift = 0; size_t ShenandoahHeapRegion::RegionSizeWordsShift = 0; size_t ShenandoahHeapRegion::RegionSizeBytesMask = 0; size_t ShenandoahHeapRegion::RegionSizeWordsMask = 0; -size_t ShenandoahHeapRegion::HumongousThresholdBytes = 0; -size_t ShenandoahHeapRegion::HumongousThresholdWords = 0; size_t ShenandoahHeapRegion::MaxTLABSizeBytes = 0; size_t ShenandoahHeapRegion::MaxTLABSizeWords = 0; @@ -598,18 +596,8 @@ size_t ShenandoahHeapRegion::setup_sizes(size_t max_heap_size) { RegionCount = align_up(max_heap_size, RegionSizeBytes) / RegionSizeBytes; guarantee(RegionCount >= MIN_NUM_REGIONS, "Should have at least minimum regions"); - guarantee(HumongousThresholdWords == 0, "we should only set it once"); - HumongousThresholdWords = RegionSizeWords * ShenandoahHumongousThreshold / 100; - HumongousThresholdWords = align_down(HumongousThresholdWords, MinObjAlignment); - assert (HumongousThresholdWords <= RegionSizeWords, "sanity"); - - guarantee(HumongousThresholdBytes == 0, "we should only set it once"); - HumongousThresholdBytes = HumongousThresholdWords * HeapWordSize; - assert (HumongousThresholdBytes <= RegionSizeBytes, "sanity"); - guarantee(MaxTLABSizeWords == 0, "we should only set it once"); - MaxTLABSizeWords = MIN2(RegionSizeWords, HumongousThresholdWords); - MaxTLABSizeWords = align_down(MaxTLABSizeWords, MinObjAlignment); + MaxTLABSizeWords = align_down(RegionSizeWords, MinObjAlignment); guarantee(MaxTLABSizeBytes == 0, "we should only set it once"); MaxTLABSizeBytes = MaxTLABSizeWords * HeapWordSize; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp index c5763608582a1..c34c4c232e482 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp @@ -217,8 +217,6 @@ class ShenandoahHeapRegion { static size_t RegionSizeWordsShift; static size_t RegionSizeBytesMask; static size_t RegionSizeWordsMask; - static size_t HumongousThresholdBytes; - static size_t HumongousThresholdWords; static size_t MaxTLABSizeBytes; static size_t MaxTLABSizeWords; @@ -261,6 +259,10 @@ class ShenandoahHeapRegion { return (bytes + ShenandoahHeapRegion::region_size_bytes() - 1) >> ShenandoahHeapRegion::region_size_bytes_shift(); } + inline static bool requires_humongous(size_t words) { + return words > ShenandoahHeapRegion::RegionSizeWords; + } + inline static size_t region_count() { return ShenandoahHeapRegion::RegionCount; } @@ -313,14 +315,6 @@ class ShenandoahHeapRegion { return (jint)ShenandoahHeapRegion::RegionSizeWordsShift; } - inline static size_t humongous_threshold_bytes() { - return ShenandoahHeapRegion::HumongousThresholdBytes; - } - - inline static size_t humongous_threshold_words() { - return ShenandoahHeapRegion::HumongousThresholdWords; - } - inline static size_t max_tlab_size_bytes() { return ShenandoahHeapRegion::MaxTLABSizeBytes; } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahInitLogger.cpp b/src/hotspot/share/gc/shenandoah/shenandoahInitLogger.cpp index db5a68d584e90..baf95a5bdf7e4 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahInitLogger.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahInitLogger.cpp @@ -43,7 +43,6 @@ void ShenandoahInitLogger::print_heap() { log_info(gc, init)("Heap Region Count: " SIZE_FORMAT, ShenandoahHeapRegion::region_count()); log_info(gc, init)("Heap Region Size: " EXACTFMT, EXACTFMTARGS(ShenandoahHeapRegion::region_size_bytes())); log_info(gc, init)("TLAB Size Max: " EXACTFMT, EXACTFMTARGS(ShenandoahHeapRegion::max_tlab_size_bytes())); - log_info(gc, init)("Humongous Object Threshold: " EXACTFMT, EXACTFMTARGS(ShenandoahHeapRegion::humongous_threshold_bytes())); } void ShenandoahInitLogger::print_gc_specific() { diff --git a/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp b/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp index 87702afe98e14..c66e5839d5897 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp @@ -49,13 +49,6 @@ "With automatic region sizing, the regions would be at most " \ "this large.") \ \ - product(intx, ShenandoahHumongousThreshold, 100, EXPERIMENTAL, \ - "Humongous objects are allocated in separate regions. " \ - "This setting defines how large the object should be to be " \ - "deemed humongous. Value is in percents of heap region size. " \ - "This also caps the maximum TLAB size.") \ - range(1, 100) \ - \ product(ccstr, ShenandoahGCMode, "satb", \ "GC mode to use. Among other things, this defines which " \ "barriers are in in use. Possible values are:" \ diff --git a/test/hotspot/jtreg/gc/shenandoah/TestHumongousThreshold.java b/test/hotspot/jtreg/gc/shenandoah/TestHumongousThreshold.java deleted file mode 100644 index 845a6617ebd63..0000000000000 --- a/test/hotspot/jtreg/gc/shenandoah/TestHumongousThreshold.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright (c) 2017, 2018, Red Hat, Inc. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -/* - * @test id=default - * @key randomness - * @requires vm.gc.Shenandoah - * @library /test/lib - * - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -Xmx1g - * -XX:+ShenandoahVerify - * TestHumongousThreshold - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -Xmx1g - * -XX:+ShenandoahVerify -XX:ShenandoahHumongousThreshold=50 - * TestHumongousThreshold - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -Xmx1g - * -XX:+ShenandoahVerify -XX:ShenandoahHumongousThreshold=90 - * TestHumongousThreshold - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -Xmx1g - * -XX:+ShenandoahVerify -XX:ShenandoahHumongousThreshold=99 - * TestHumongousThreshold - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -Xmx1g - * -XX:+ShenandoahVerify -XX:ShenandoahHumongousThreshold=100 - * TestHumongousThreshold - * - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -Xmx1g - * -XX:-UseTLAB -XX:+ShenandoahVerify - * TestHumongousThreshold - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -Xmx1g - * -XX:-UseTLAB -XX:+ShenandoahVerify -XX:ShenandoahHumongousThreshold=50 - * TestHumongousThreshold - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -Xmx1g - * -XX:-UseTLAB -XX:+ShenandoahVerify -XX:ShenandoahHumongousThreshold=90 - * TestHumongousThreshold - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -Xmx1g - * -XX:-UseTLAB -XX:+ShenandoahVerify -XX:ShenandoahHumongousThreshold=99 - * TestHumongousThreshold - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -Xmx1g - * -XX:-UseTLAB -XX:+ShenandoahVerify -XX:ShenandoahHumongousThreshold=100 - * TestHumongousThreshold - * - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -Xmx1g - * -XX:ShenandoahHumongousThreshold=90 -XX:ShenandoahGCHeuristics=aggressive - * TestHumongousThreshold - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -Xmx1g - * -XX:-UseTLAB -XX:ShenandoahHumongousThreshold=90 -XX:ShenandoahGCHeuristics=aggressive - * TestHumongousThreshold - */ - -/* - * @test id=16b - * @key randomness - * @requires vm.gc.Shenandoah - * @requires vm.bits == "64" - * @library /test/lib - * - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -Xmx1g - * -XX:ObjectAlignmentInBytes=16 -XX:+ShenandoahVerify - * TestHumongousThreshold - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -Xmx1g - * -XX:ObjectAlignmentInBytes=16 -XX:+ShenandoahVerify -XX:ShenandoahHumongousThreshold=50 - * TestHumongousThreshold - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -Xmx1g - * -XX:ObjectAlignmentInBytes=16 -XX:+ShenandoahVerify -XX:ShenandoahHumongousThreshold=90 - * TestHumongousThreshold - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -Xmx1g - * -XX:ObjectAlignmentInBytes=16 -XX:+ShenandoahVerify -XX:ShenandoahHumongousThreshold=99 - * TestHumongousThreshold - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -Xmx1g - * -XX:ObjectAlignmentInBytes=16 -XX:+ShenandoahVerify -XX:ShenandoahHumongousThreshold=100 - * TestHumongousThreshold - * - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -Xmx1g - * -XX:-UseTLAB -XX:ObjectAlignmentInBytes=16 -XX:+ShenandoahVerify - * TestHumongousThreshold - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -Xmx1g - * -XX:-UseTLAB -XX:ObjectAlignmentInBytes=16 -XX:+ShenandoahVerify -XX:ShenandoahHumongousThreshold=50 - * TestHumongousThreshold - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -Xmx1g - * -XX:-UseTLAB -XX:ObjectAlignmentInBytes=16 -XX:+ShenandoahVerify -XX:ShenandoahHumongousThreshold=90 - * TestHumongousThreshold - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -Xmx1g - * -XX:-UseTLAB -XX:ObjectAlignmentInBytes=16 -XX:+ShenandoahVerify -XX:ShenandoahHumongousThreshold=99 - * TestHumongousThreshold - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -Xmx1g - * -XX:-UseTLAB -XX:ObjectAlignmentInBytes=16 -XX:+ShenandoahVerify -XX:ShenandoahHumongousThreshold=100 - * TestHumongousThreshold - */ - -import java.util.Random; -import jdk.test.lib.Utils; - -public class TestHumongousThreshold { - - static final long TARGET_MB = Long.getLong("target", 20_000); // 20 Gb allocation - - static volatile Object sink; - - public static void main(String[] args) throws Exception { - final int min = 0; - final int max = 384 * 1024; - long count = TARGET_MB * 1024 * 1024 / (16 + 4 * (min + (max - min) / 2)); - - Random r = Utils.getRandomInstance(); - for (long c = 0; c < count; c++) { - sink = new int[min + r.nextInt(max - min)]; - } - } - -} diff --git a/test/hotspot/jtreg/gc/shenandoah/options/TestHumongousThresholdArgs.java b/test/hotspot/jtreg/gc/shenandoah/options/TestHumongousThresholdArgs.java deleted file mode 100644 index 47d4115ce749f..0000000000000 --- a/test/hotspot/jtreg/gc/shenandoah/options/TestHumongousThresholdArgs.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2017, 2018, Red Hat, Inc. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -/* - * @test - * @summary Test that Shenandoah humongous threshold args are checked - * @requires vm.gc.Shenandoah - * @library /test/lib - * @modules java.base/jdk.internal.misc - * java.management - * @run driver TestHumongousThresholdArgs - */ - -import jdk.test.lib.process.ProcessTools; -import jdk.test.lib.process.OutputAnalyzer; - -public class TestHumongousThresholdArgs { - public static void main(String[] args) throws Exception { - { - OutputAnalyzer output = ProcessTools.executeLimitedTestJava( - "-Xmx128m", - "-XX:+UnlockExperimentalVMOptions", - "-XX:+UseShenandoahGC", - "-version"); - output.shouldHaveExitValue(0); - } - - int[] valid = new int[] {1, 10, 50, 90, 100}; - int[] invalid = new int[] {-100, -1, 0, 101, 1000}; - - for (int v : valid) { - OutputAnalyzer output = ProcessTools.executeLimitedTestJava( - "-Xmx128m", - "-XX:+UnlockExperimentalVMOptions", - "-XX:+UseShenandoahGC", - "-XX:ShenandoahHumongousThreshold=" + v, - "-version"); - output.shouldHaveExitValue(0); - } - - for (int v : invalid) { - OutputAnalyzer output = ProcessTools.executeLimitedTestJava( - "-Xmx128m", - "-XX:+UnlockExperimentalVMOptions", - "-XX:+UseShenandoahGC", - "-XX:ShenandoahHumongousThreshold=" + v, - "-version"); - output.shouldHaveExitValue(1); - } - } -} From e51e40c2b9f51d012c01407e0b8dadaab464753e Mon Sep 17 00:00:00 2001 From: Satyen Subramaniam Date: Thu, 15 Aug 2024 16:47:08 +0000 Subject: [PATCH 319/353] 8336914: Shenandoah: Missing verification steps after JDK-8255765 Reviewed-by: shade --- src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp index 86d6d91f72c9a..0301ef422a629 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp @@ -921,8 +921,11 @@ void ShenandoahConcurrentGC::op_init_updaterefs() { heap->set_evacuation_in_progress(false); heap->set_concurrent_weak_root_in_progress(false); heap->prepare_update_heap_references(true /*concurrent*/); - heap->set_update_refs_in_progress(true); + if (ShenandoahVerify) { + heap->verifier()->verify_before_updaterefs(); + } + heap->set_update_refs_in_progress(true); if (ShenandoahPacing) { heap->pacer()->setup_for_updaterefs(); } From f308b2d59672b39ddca502baff50ab20ab781047 Mon Sep 17 00:00:00 2001 From: Satyen Subramaniam Date: Thu, 15 Aug 2024 16:47:45 +0000 Subject: [PATCH 320/353] 8336915: Shenandoah: Remove unused ShenandoahVerifier::verify_after_evacuation Reviewed-by: shade --- .../share/gc/shenandoah/shenandoahVerifier.cpp | 12 ------------ .../share/gc/shenandoah/shenandoahVerifier.hpp | 1 - 2 files changed, 13 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp index 694736cea426c..23da3d7f63709 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp @@ -856,18 +856,6 @@ void ShenandoahVerifier::verify_during_evacuation() { ); } -void ShenandoahVerifier::verify_after_evacuation() { - verify_at_safepoint( - "After Evacuation", - _verify_forwarded_allow, // objects are still forwarded - _verify_marked_complete, // bitmaps might be stale, but alloc-after-mark should be well - _verify_cset_forwarded, // all cset refs are fully forwarded - _verify_liveness_disable, // no reliable liveness data anymore - _verify_regions_notrash, // trash regions have been recycled already - _verify_gcstate_forwarded // evacuation produced some forwarded objects - ); -} - void ShenandoahVerifier::verify_before_updaterefs() { verify_at_safepoint( "Before Updating References", diff --git a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.hpp b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.hpp index 2bbe5ae68b2a4..dd4eb901a3348 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.hpp @@ -176,7 +176,6 @@ class ShenandoahVerifier : public CHeapObj { void verify_after_concmark(); void verify_before_evacuation(); void verify_during_evacuation(); - void verify_after_evacuation(); void verify_before_updaterefs(); void verify_after_updaterefs(); void verify_before_fullgc(); From 965508270ecd092019f7bea3a1605c5d9f19d81e Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Thu, 15 Aug 2024 17:43:09 +0000 Subject: [PATCH 321/353] 8338330: Fix -Wzero-as-null-pointer-constant warnings from THROW_XXX_0 Reviewed-by: dlong, dholmes, shade --- src/hotspot/share/prims/jvm.cpp | 2 +- src/hotspot/share/runtime/reflection.cpp | 18 +++++++++--------- src/hotspot/share/utilities/exceptions.hpp | 5 ++++- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/hotspot/share/prims/jvm.cpp b/src/hotspot/share/prims/jvm.cpp index e40c11289661e..a26a82debe750 100644 --- a/src/hotspot/share/prims/jvm.cpp +++ b/src/hotspot/share/prims/jvm.cpp @@ -3403,7 +3403,7 @@ JVM_ENTRY_NO_ENV(void*, JVM_LoadLibrary(const char* name, jboolean throwExceptio vmSymbols::java_lang_UnsatisfiedLinkError(), msg, Exceptions::unsafe_to_utf8); - THROW_HANDLE_0(h_exception); + THROW_HANDLE_NULL(h_exception); } else { log_info(library)("Failed to load library %s", name); return load_result; diff --git a/src/hotspot/share/runtime/reflection.cpp b/src/hotspot/share/runtime/reflection.cpp index 865d25fa06b8a..ab3d82ad7e2a4 100644 --- a/src/hotspot/share/runtime/reflection.cpp +++ b/src/hotspot/share/runtime/reflection.cpp @@ -1004,9 +1004,9 @@ static oop invoke(InstanceKlass* klass, // JVMTI internal flag reset is needed in order to report InvocationTargetException JvmtiExport::clear_detected_exception(THREAD); JavaCallArguments args(Handle(THREAD, resolution_exception)); - THROW_ARG_0(vmSymbols::java_lang_reflect_InvocationTargetException(), - vmSymbols::throwable_void_signature(), - &args); + THROW_ARG_NULL(vmSymbols::java_lang_reflect_InvocationTargetException(), + vmSymbols::throwable_void_signature(), + &args); } } else { // if the method can be overridden, we resolve using the vtable index. @@ -1028,9 +1028,9 @@ static oop invoke(InstanceKlass* klass, Handle h_origexception = Exceptions::new_exception(THREAD, vmSymbols::java_lang_AbstractMethodError(), ss.as_string()); JavaCallArguments args(h_origexception); - THROW_ARG_0(vmSymbols::java_lang_reflect_InvocationTargetException(), - vmSymbols::throwable_void_signature(), - &args); + THROW_ARG_NULL(vmSymbols::java_lang_reflect_InvocationTargetException(), + vmSymbols::throwable_void_signature(), + &args); } } } @@ -1117,9 +1117,9 @@ static oop invoke(InstanceKlass* klass, JvmtiExport::clear_detected_exception(THREAD); JavaCallArguments args(Handle(THREAD, target_exception)); - THROW_ARG_0(vmSymbols::java_lang_reflect_InvocationTargetException(), - vmSymbols::throwable_void_signature(), - &args); + THROW_ARG_NULL(vmSymbols::java_lang_reflect_InvocationTargetException(), + vmSymbols::throwable_void_signature(), + &args); } else { if (rtype == T_BOOLEAN || rtype == T_BYTE || rtype == T_CHAR || rtype == T_SHORT) { narrow((jvalue*)result.get_value_addr(), rtype, CHECK_NULL); diff --git a/src/hotspot/share/utilities/exceptions.hpp b/src/hotspot/share/utilities/exceptions.hpp index bddb8d79c1ea3..33eba68d6d9f2 100644 --- a/src/hotspot/share/utilities/exceptions.hpp +++ b/src/hotspot/share/utilities/exceptions.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -311,6 +311,9 @@ class Exceptions { #define THROW_NULL(name) THROW_(name, nullptr) #define THROW_MSG_NULL(name, message) THROW_MSG_(name, message, nullptr) +#define THROW_HANDLE_NULL(e) THROW_HANDLE_(e, nullptr) +#define THROW_ARG_NULL(name, signature, arg) THROW_ARG_(name, signature, arg, nullptr) + // The CATCH macro checks that no exception has been thrown by a function; it is used at // call sites about which is statically known that the callee cannot throw an exception // even though it is declared with TRAPS. From ace496515f4f91e802a51cec43d387eed61bd935 Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Thu, 15 Aug 2024 17:50:34 +0000 Subject: [PATCH 322/353] 8338406: BytecodeHelpers using wrong bootstrap method descriptor for condy Reviewed-by: asotona --- .../classfile/impl/BytecodeHelpers.java | 12 +---- ...Test.java => ConstantDescSymbolsTest.java} | 52 ++++++++++++++----- 2 files changed, 41 insertions(+), 23 deletions(-) rename test/jdk/jdk/classfile/{PrimitiveClassConstantTest.java => ConstantDescSymbolsTest.java} (53%) diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BytecodeHelpers.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BytecodeHelpers.java index f7aa0902bc36b..474189121fd47 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BytecodeHelpers.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BytecodeHelpers.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -275,15 +275,7 @@ static ConstantDynamicEntry handleConstantDescToHandleInfo(ConstantPoolBuilder c List staticArgs = new ArrayList<>(bootstrapArgs.length); for (ConstantDesc bootstrapArg : bootstrapArgs) staticArgs.add(constantPool.loadableConstantEntry(bootstrapArg)); - - var bootstrapDesc = desc.bootstrapMethod(); - ClassEntry bsOwner = constantPool.classEntry(bootstrapDesc.owner()); - NameAndTypeEntry bsNameAndType = constantPool.nameAndTypeEntry(bootstrapDesc.methodName(), - bootstrapDesc.invocationType()); - int bsRefKind = bootstrapDesc.refKind(); - - MemberRefEntry memberRefEntry = toBootstrapMemberRef(constantPool, bsRefKind, bsOwner, bsNameAndType, bootstrapDesc.isOwnerInterface()); - MethodHandleEntry methodHandleEntry = constantPool.methodHandleEntry(bsRefKind, memberRefEntry); + MethodHandleEntry methodHandleEntry = handleDescToHandleInfo(constantPool, desc.bootstrapMethod()); BootstrapMethodEntry bme = constantPool.bsmEntry(methodHandleEntry, staticArgs); return constantPool.constantDynamicEntry(bme, constantPool.nameAndTypeEntry(desc.constantName(), diff --git a/test/jdk/jdk/classfile/PrimitiveClassConstantTest.java b/test/jdk/jdk/classfile/ConstantDescSymbolsTest.java similarity index 53% rename from test/jdk/jdk/classfile/PrimitiveClassConstantTest.java rename to test/jdk/jdk/classfile/ConstantDescSymbolsTest.java index 89cf43751f82f..7c97c9dd5a9b1 100644 --- a/test/jdk/jdk/classfile/PrimitiveClassConstantTest.java +++ b/test/jdk/jdk/classfile/ConstantDescSymbolsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,12 +23,14 @@ /* * @test - * @bug 8304031 - * @summary Testing that primitive class descs are encoded properly as loadable constants. - * @run junit PrimitiveClassConstantTest + * @bug 8304031 8338406 + * @summary Testing handling of various constant descriptors in ClassFile API. + * @run junit ConstantDescSymbolsTest */ import java.lang.constant.ClassDesc; +import java.lang.constant.DynamicConstantDesc; +import java.lang.constant.MethodHandleDesc; import java.lang.constant.MethodTypeDesc; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; @@ -37,18 +39,16 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import static java.lang.constant.ConstantDescs.CD_Class; -import static java.lang.constant.ConstantDescs.CD_Object; -import static java.lang.constant.ConstantDescs.CD_int; -import static java.lang.constant.ConstantDescs.CD_long; -import static java.lang.constant.ConstantDescs.INIT_NAME; -import static java.lang.constant.ConstantDescs.MTD_void; import static java.lang.classfile.ClassFile.ACC_PUBLIC; +import static java.lang.constant.ConstantDescs.*; -public final class PrimitiveClassConstantTest { +import static org.junit.jupiter.api.Assertions.*; +final class ConstantDescSymbolsTest { + + // Testing that primitive class descs are encoded properly as loadable constants. @Test - public void test() throws Throwable { + void testPrimitiveClassDesc() throws Throwable { ClassDesc ape = ClassDesc.of("Ape"); var lookup = MethodHandles.lookup(); Class a = lookup.defineClass(ClassFile.of().build(ape, clb -> { @@ -73,7 +73,33 @@ public void test() throws Throwable { Supplier t = (Supplier) lookup.findConstructor(a, MethodType.methodType(void.class)) .asType(MethodType.methodType(Supplier.class)) .invokeExact(); - Assertions.assertSame(int.class, t.get()); + assertSame(int.class, t.get()); } + // Tests that condy symbols with non-static-method bootstraps are using the right lookup descriptor. + @Test + void testConstantDynamicNonStaticBootstrapMethod() throws Throwable { + record CondyBoot(MethodHandles.Lookup lookup, String name, Class type) {} + var bootClass = CondyBoot.class.describeConstable().orElseThrow(); + var bootMhDesc = MethodHandleDesc.ofConstructor(bootClass, CD_MethodHandles_Lookup, CD_String, CD_Class); + var condyDesc = DynamicConstantDesc.of(bootMhDesc); + + var targetCd = ClassDesc.of("Bat"); + var lookup = MethodHandles.lookup(); + Class a = lookup.defineClass(ClassFile.of().build(targetCd, clb -> { + clb.withInterfaceSymbols(Supplier.class.describeConstable().orElseThrow()) + .withMethodBody(INIT_NAME, MTD_void, ACC_PUBLIC, cob -> cob + .aload(0).invokespecial(CD_Object, INIT_NAME, MTD_void).return_()) + .withMethodBody("get", MethodTypeDesc.of(CD_Object), ACC_PUBLIC, cob -> cob + .loadConstant(condyDesc).areturn()); + })); + @SuppressWarnings("unchecked") + Supplier t = (Supplier) lookup.findConstructor(a, MethodType.methodType(void.class)) + .asType(MethodType.methodType(Supplier.class)).invokeExact(); + var cb = t.get(); + assertEquals(MethodHandles.Lookup.ORIGINAL, cb.lookup.lookupModes() & MethodHandles.Lookup.ORIGINAL); + assertSame(a, cb.lookup.lookupClass()); + assertEquals(DEFAULT_NAME, cb.name); + assertEquals(CondyBoot.class, cb.type); + } } From 52d9d69db5c1853445a95794c5bf21243aefa852 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Thu, 15 Aug 2024 17:50:44 +0000 Subject: [PATCH 323/353] 8338331: Fix -Wzero-as-null-pointer-constant warnings from CHECK_0 in jni.cpp Reviewed-by: dholmes, shade --- src/hotspot/share/prims/jni.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/hotspot/share/prims/jni.cpp b/src/hotspot/share/prims/jni.cpp index 12eba0ff623be..c9357fe0216d8 100644 --- a/src/hotspot/share/prims/jni.cpp +++ b/src/hotspot/share/prims/jni.cpp @@ -1156,7 +1156,7 @@ JNI_ENTRY(ResultType, \ va_start(args, methodID); \ JavaValue jvalue(Tag); \ JNI_ArgumentPusherVaArg ap(methodID, args); \ - jni_invoke_nonstatic(env, &jvalue, obj, JNI_VIRTUAL, methodID, &ap, CHECK_0); \ + jni_invoke_nonstatic(env, &jvalue, obj, JNI_VIRTUAL, methodID, &ap, CHECK_(ResultType{})); \ va_end(args); \ ret = jvalue.get_##ResultType(); \ return ret;\ @@ -1209,7 +1209,7 @@ JNI_ENTRY(ResultType, \ \ JavaValue jvalue(Tag); \ JNI_ArgumentPusherVaArg ap(methodID, args); \ - jni_invoke_nonstatic(env, &jvalue, obj, JNI_VIRTUAL, methodID, &ap, CHECK_0); \ + jni_invoke_nonstatic(env, &jvalue, obj, JNI_VIRTUAL, methodID, &ap, CHECK_(ResultType{})); \ ret = jvalue.get_##ResultType(); \ return ret;\ JNI_END @@ -1260,7 +1260,7 @@ JNI_ENTRY(ResultType, \ \ JavaValue jvalue(Tag); \ JNI_ArgumentPusherArray ap(methodID, args); \ - jni_invoke_nonstatic(env, &jvalue, obj, JNI_VIRTUAL, methodID, &ap, CHECK_0); \ + jni_invoke_nonstatic(env, &jvalue, obj, JNI_VIRTUAL, methodID, &ap, CHECK_(ResultType{})); \ ret = jvalue.get_##ResultType(); \ return ret;\ JNI_END @@ -1353,7 +1353,7 @@ JNI_ENTRY(ResultType, \ va_start(args, methodID); \ JavaValue jvalue(Tag); \ JNI_ArgumentPusherVaArg ap(methodID, args); \ - jni_invoke_nonstatic(env, &jvalue, obj, JNI_NONVIRTUAL, methodID, &ap, CHECK_0); \ + jni_invoke_nonstatic(env, &jvalue, obj, JNI_NONVIRTUAL, methodID, &ap, CHECK_(ResultType{})); \ va_end(args); \ ret = jvalue.get_##ResultType(); \ return ret;\ @@ -1406,7 +1406,7 @@ JNI_ENTRY(ResultType, \ \ JavaValue jvalue(Tag); \ JNI_ArgumentPusherVaArg ap(methodID, args); \ - jni_invoke_nonstatic(env, &jvalue, obj, JNI_NONVIRTUAL, methodID, &ap, CHECK_0); \ + jni_invoke_nonstatic(env, &jvalue, obj, JNI_NONVIRTUAL, methodID, &ap, CHECK_(ResultType{})); \ ret = jvalue.get_##ResultType(); \ return ret;\ JNI_END @@ -1458,7 +1458,7 @@ JNI_ENTRY(ResultType, \ \ JavaValue jvalue(Tag); \ JNI_ArgumentPusherArray ap(methodID, args); \ - jni_invoke_nonstatic(env, &jvalue, obj, JNI_NONVIRTUAL, methodID, &ap, CHECK_0); \ + jni_invoke_nonstatic(env, &jvalue, obj, JNI_NONVIRTUAL, methodID, &ap, CHECK_(ResultType{})); \ ret = jvalue.get_##ResultType(); \ return ret;\ JNI_END @@ -1554,7 +1554,7 @@ JNI_ENTRY(ResultType, \ va_start(args, methodID); \ JavaValue jvalue(Tag); \ JNI_ArgumentPusherVaArg ap(methodID, args); \ - jni_invoke_static(env, &jvalue, nullptr, JNI_STATIC, methodID, &ap, CHECK_0); \ + jni_invoke_static(env, &jvalue, nullptr, JNI_STATIC, methodID, &ap, CHECK_(ResultType{})); \ va_end(args); \ ret = jvalue.get_##ResultType(); \ return ret;\ @@ -1609,8 +1609,8 @@ JNI_ENTRY(ResultType, \ JNI_ArgumentPusherVaArg ap(methodID, args); \ /* Make sure class is initialized before trying to invoke its method */ \ Klass* k = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(cls)); \ - k->initialize(CHECK_0); \ - jni_invoke_static(env, &jvalue, nullptr, JNI_STATIC, methodID, &ap, CHECK_0); \ + k->initialize(CHECK_(ResultType{})); \ + jni_invoke_static(env, &jvalue, nullptr, JNI_STATIC, methodID, &ap, CHECK_(ResultType{})); \ va_end(args); \ ret = jvalue.get_##ResultType(); \ return ret;\ @@ -1663,7 +1663,7 @@ JNI_ENTRY(ResultType, \ \ JavaValue jvalue(Tag); \ JNI_ArgumentPusherArray ap(methodID, args); \ - jni_invoke_static(env, &jvalue, nullptr, JNI_STATIC, methodID, &ap, CHECK_0); \ + jni_invoke_static(env, &jvalue, nullptr, JNI_STATIC, methodID, &ap, CHECK_(ResultType{})); \ ret = jvalue.get_##ResultType(); \ return ret;\ JNI_END From 1cd488436880b00c55fa91f44c115999cf686afd Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Thu, 15 Aug 2024 18:20:20 +0000 Subject: [PATCH 324/353] 8338447: Remove InstanceKlass::_is_marked_dependent Reviewed-by: shade --- src/hotspot/share/oops/instanceKlass.hpp | 4 ---- src/hotspot/share/runtime/vmStructs.cpp | 1 - 2 files changed, 5 deletions(-) diff --git a/src/hotspot/share/oops/instanceKlass.hpp b/src/hotspot/share/oops/instanceKlass.hpp index 6e5d4ac8e7feb..b639b820d10dd 100644 --- a/src/hotspot/share/oops/instanceKlass.hpp +++ b/src/hotspot/share/oops/instanceKlass.hpp @@ -225,10 +225,6 @@ class InstanceKlass: public Klass { volatile u2 _idnum_allocated_count; // JNI/JVMTI: increments with the addition of methods, old ids don't change - // _is_marked_dependent can be set concurrently, thus cannot be part of the - // _misc_flags. - bool _is_marked_dependent; // used for marking during flushing and deoptimization - // Class states are defined as ClassState (see above). // Place the _init_state here to utilize the unused 2-byte after // _idnum_allocated_count. diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index 27dc10d2adb17..913f988e48bea 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -246,7 +246,6 @@ nonstatic_field(InstanceKlass, _nonstatic_oop_map_size, int) \ volatile_nonstatic_field(InstanceKlass, _init_state, InstanceKlass::ClassState) \ volatile_nonstatic_field(InstanceKlass, _init_thread, JavaThread*) \ - nonstatic_field(InstanceKlass, _is_marked_dependent, bool) \ nonstatic_field(InstanceKlass, _itable_len, int) \ nonstatic_field(InstanceKlass, _nest_host_index, u2) \ nonstatic_field(InstanceKlass, _reference_type, u1) \ From d86e99c3ca94ee8705e44fe2830edd3ceb0a7f64 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Thu, 15 Aug 2024 20:52:07 +0000 Subject: [PATCH 325/353] 8293650: Shenandoah: Support archived heap objects Reviewed-by: rkennke, wkemper, iklam --- src/hotspot/share/cds/archiveHeapWriter.hpp | 12 +-- src/hotspot/share/cds/filemap.cpp | 2 +- .../share/gc/shenandoah/shenandoahAsserts.cpp | 14 ++- .../share/gc/shenandoah/shenandoahHeap.cpp | 78 ++++++++++++++++ .../share/gc/shenandoah/shenandoahHeap.hpp | 6 ++ .../gc/shenandoah/shenandoahHeapRegion.cpp | 6 +- .../cds/appcds/TestShenandoahWithCDS.java | 89 +++++++++++++++++++ 7 files changed, 195 insertions(+), 12 deletions(-) create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/TestShenandoahWithCDS.java diff --git a/src/hotspot/share/cds/archiveHeapWriter.hpp b/src/hotspot/share/cds/archiveHeapWriter.hpp index 99d5294007f64..352aeb9a08f7c 100644 --- a/src/hotspot/share/cds/archiveHeapWriter.hpp +++ b/src/hotspot/share/cds/archiveHeapWriter.hpp @@ -112,6 +112,12 @@ class ArchiveHeapWriter : AllStatic { public: static const intptr_t NOCOOPS_REQUESTED_BASE = 0x10000000; + // The minimum region size of all collectors that are supported by CDS in + // ArchiveHeapLoader::can_map() mode. Currently only G1 is supported. G1's region size + // depends on -Xmx, but can never be smaller than 1 * M. + // (TODO: Perhaps change to 256K to be compatible with Shenandoah) + static constexpr int MIN_GC_REGION_ALIGNMENT = 1 * M; + private: class EmbeddedOopRelocator; struct NativePointerInfo { @@ -119,12 +125,6 @@ class ArchiveHeapWriter : AllStatic { int _field_offset; }; - // The minimum region size of all collectors that are supported by CDS in - // ArchiveHeapLoader::can_map() mode. Currently only G1 is supported. G1's region size - // depends on -Xmx, but can never be smaller than 1 * M. - // (TODO: Perhaps change to 256K to be compatible with Shenandoah) - static constexpr int MIN_GC_REGION_ALIGNMENT = 1 * M; - static GrowableArrayCHeap* _buffer; // The number of bytes that have written into _buffer (may be smaller than _buffer->length()). diff --git a/src/hotspot/share/cds/filemap.cpp b/src/hotspot/share/cds/filemap.cpp index c5a9d5cceed53..dc6c7ea097c65 100644 --- a/src/hotspot/share/cds/filemap.cpp +++ b/src/hotspot/share/cds/filemap.cpp @@ -2025,7 +2025,7 @@ void FileMapInfo::map_or_load_heap_region() { // TODO - remove implicit knowledge of G1 log_info(cds)("Cannot use CDS heap data. UseG1GC is required for -XX:-UseCompressedOops"); } else { - log_info(cds)("Cannot use CDS heap data. UseEpsilonGC, UseG1GC, UseSerialGC or UseParallelGC are required."); + log_info(cds)("Cannot use CDS heap data. UseEpsilonGC, UseG1GC, UseSerialGC, UseParallelGC, or UseShenandoahGC are required."); } } } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahAsserts.cpp b/src/hotspot/share/gc/shenandoah/shenandoahAsserts.cpp index 5abd7b805f9fc..8235b59b80e56 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahAsserts.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahAsserts.cpp @@ -254,7 +254,7 @@ void ShenandoahAsserts::assert_correct(void* interior_loc, oop obj, const char* // Do additional checks for special objects: their fields can hold metadata as well. // We want to check class loading/unloading did not corrupt them. - if (java_lang_Class::is_instance(obj)) { + if (Universe::is_fully_initialized() && java_lang_Class::is_instance(obj)) { Metadata* klass = obj->metadata_field(java_lang_Class::klass_offset()); if (klass != nullptr && !Metaspace::contains(klass)) { print_failure(_safe_all, obj, interior_loc, nullptr, "Shenandoah assert_correct failed", @@ -283,10 +283,12 @@ void ShenandoahAsserts::assert_in_correct_region(void* interior_loc, oop obj, co } size_t alloc_size = obj->size(); + HeapWord* obj_end = cast_from_oop(obj) + alloc_size; + if (ShenandoahHeapRegion::requires_humongous(alloc_size)) { size_t idx = r->index(); - size_t num_regions = ShenandoahHeapRegion::required_regions(alloc_size * HeapWordSize); - for (size_t i = idx; i < idx + num_regions; i++) { + size_t end_idx = heap->heap_region_index_containing(obj_end - 1); + for (size_t i = idx; i < end_idx; i++) { ShenandoahHeapRegion* chain_reg = heap->get_region(i); if (i == idx && !chain_reg->is_humongous_start()) { print_failure(_safe_unknown, obj, interior_loc, nullptr, "Shenandoah assert_in_correct_region failed", @@ -299,6 +301,12 @@ void ShenandoahAsserts::assert_in_correct_region(void* interior_loc, oop obj, co file, line); } } + } else { + if (obj_end > r->top()) { + print_failure(_safe_unknown, obj, interior_loc, nullptr, "Shenandoah assert_in_correct_region failed", + "Object end should be within the active area of the region", + file, line); + } } } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index 7904cd5f1cd1d..6f5fce53f85b5 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -72,6 +72,7 @@ #include "gc/shenandoah/shenandoahJfrSupport.hpp" #endif +#include "cds/archiveHeapWriter.hpp" #include "classfile/systemDictionary.hpp" #include "code/codeCache.hpp" #include "memory/classLoaderMetaspace.hpp" @@ -2482,3 +2483,80 @@ bool ShenandoahHeap::requires_barriers(stackChunkOop obj) const { return false; } + +HeapWord* ShenandoahHeap::allocate_loaded_archive_space(size_t size) { +#if INCLUDE_CDS_JAVA_HEAP + // CDS wants a continuous memory range to load a bunch of objects. + // This effectively bypasses normal allocation paths, and requires + // a bit of massaging to unbreak GC invariants. + + ShenandoahAllocRequest req = ShenandoahAllocRequest::for_shared(size); + + // Easy case: a single regular region, no further adjustments needed. + if (!ShenandoahHeapRegion::requires_humongous(size)) { + return allocate_memory(req); + } + + // Hard case: the requested size would cause a humongous allocation. + // We need to make sure it looks like regular allocation to the rest of GC. + + // CDS code would guarantee no objects straddle multiple regions, as long as + // regions are as large as MIN_GC_REGION_ALIGNMENT. It is impractical at this + // point to deal with case when Shenandoah runs with smaller regions. + // TODO: This check can be dropped once MIN_GC_REGION_ALIGNMENT agrees more with Shenandoah. + if (ShenandoahHeapRegion::region_size_bytes() < ArchiveHeapWriter::MIN_GC_REGION_ALIGNMENT) { + return nullptr; + } + + HeapWord* mem = allocate_memory(req); + size_t start_idx = heap_region_index_containing(mem); + size_t num_regions = ShenandoahHeapRegion::required_regions(size * HeapWordSize); + + // Flip humongous -> regular. + { + ShenandoahHeapLocker locker(lock(), false); + for (size_t c = start_idx; c < start_idx + num_regions; c++) { + get_region(c)->make_regular_bypass(); + } + } + + return mem; +#else + assert(false, "Archive heap loader should not be available, should not be here"); + return nullptr; +#endif // INCLUDE_CDS_JAVA_HEAP +} + +void ShenandoahHeap::complete_loaded_archive_space(MemRegion archive_space) { + // Nothing to do here, except checking that heap looks fine. +#ifdef ASSERT + HeapWord* start = archive_space.start(); + HeapWord* end = archive_space.end(); + + // No unclaimed space between the objects. + // Objects are properly allocated in correct regions. + HeapWord* cur = start; + while (cur < end) { + oop oop = cast_to_oop(cur); + shenandoah_assert_in_correct_region(nullptr, oop); + cur += oop->size(); + } + + // No unclaimed tail at the end of archive space. + assert(cur == end, + "Archive space should be fully used: " PTR_FORMAT " " PTR_FORMAT, + p2i(cur), p2i(end)); + + // Region bounds are good. + ShenandoahHeapRegion* begin_reg = heap_region_containing(start); + ShenandoahHeapRegion* end_reg = heap_region_containing(end); + assert(begin_reg->is_regular(), "Must be"); + assert(end_reg->is_regular(), "Must be"); + assert(begin_reg->bottom() == start, + "Must agree: archive-space-start: " PTR_FORMAT ", begin-region-bottom: " PTR_FORMAT, + p2i(start), p2i(begin_reg->bottom())); + assert(end_reg->top() == end, + "Must agree: archive-space-end: " PTR_FORMAT ", end-region-top: " PTR_FORMAT, + p2i(end), p2i(end_reg->top())); +#endif +} diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp index 86bd7b83bbe1b..81b1c3df6f411 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp @@ -539,6 +539,12 @@ class ShenandoahHeap : public CollectedHeap, public ShenandoahSpaceInfo { void sync_pinned_region_status(); void assert_pinned_region_status() NOT_DEBUG_RETURN; +// ---------- CDS archive support + + bool can_load_archived_objects() const override { return UseCompressedOops; } + HeapWord* allocate_loaded_archive_space(size_t size) override; + void complete_loaded_archive_space(MemRegion archive_space) override; + // ---------- Allocation support // private: diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp index eceed8dbe433e..92602871ccde4 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp @@ -100,8 +100,10 @@ void ShenandoahHeapRegion::make_regular_allocation() { void ShenandoahHeapRegion::make_regular_bypass() { shenandoah_assert_heaplocked(); - assert (ShenandoahHeap::heap()->is_full_gc_in_progress() || ShenandoahHeap::heap()->is_degenerated_gc_in_progress(), - "only for full or degen GC"); + assert (!Universe::is_fully_initialized() || + ShenandoahHeap::heap()->is_full_gc_in_progress() || + ShenandoahHeap::heap()->is_degenerated_gc_in_progress(), + "Only for STW GC or when Universe is initializing (CDS)"); switch (_state) { case _empty_uncommitted: diff --git a/test/hotspot/jtreg/runtime/cds/appcds/TestShenandoahWithCDS.java b/test/hotspot/jtreg/runtime/cds/appcds/TestShenandoahWithCDS.java new file mode 100644 index 0000000000000..83442c1e159f7 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/TestShenandoahWithCDS.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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. + */ + +/* + * @test + * @bug 8293650 + * @requires vm.cds + * @requires vm.bits == 64 + * @requires vm.gc.Shenandoah + * @requires vm.gc.G1 + * @requires vm.gc == null + * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds + * @compile test-classes/Hello.java + * @run driver TestShenandoahWithCDS + */ + +import jdk.test.lib.Platform; +import jdk.test.lib.process.OutputAnalyzer; + +public class TestShenandoahWithCDS { + public final static String HELLO = "Hello World"; + static String helloJar; + + public static void main(String... args) throws Exception { + helloJar = JarBuilder.build("hello", "Hello"); + + // Run with the variety of region sizes, and combinations + // of G1/Shenandoah at dump/exec times. "-1" means to use G1. + final int[] regionSizes = { -1, 256, 512, 1024, 2048 }; + + for (int dumpRegionSize : regionSizes) { + for (int execRegionSize : regionSizes) { + test(dumpRegionSize, execRegionSize); + } + } + } + + static void test(int dumpRegionSize, int execRegionSize) throws Exception { + String exp = "-XX:+UnlockExperimentalVMOptions"; + String optDumpGC = (dumpRegionSize != -1) ? "-XX:+UseShenandoahGC" : "-XX:+UseG1GC"; + String optExecGC = (execRegionSize != -1) ? "-XX:+UseShenandoahGC" : "-XX:+UseG1GC"; + String optDumpRegionSize = (dumpRegionSize != -1) ? "-XX:ShenandoahRegionSize=" + dumpRegionSize + "K" : exp; + String optExecRegionSize = (execRegionSize != -1) ? "-XX:ShenandoahRegionSize=" + execRegionSize + "K" : exp; + OutputAnalyzer out; + + System.out.println("0. Dump with " + optDumpGC + " and " + optDumpRegionSize); + out = TestCommon.dump(helloJar, + new String[] {"Hello"}, + exp, + "-Xmx1g", + optDumpGC, + optDumpRegionSize, + "-Xlog:cds"); + out.shouldContain("Dumping shared data to file:"); + out.shouldHaveExitValue(0); + + System.out.println("1. Exec with " + optExecGC + " and " + optExecRegionSize); + out = TestCommon.exec(helloJar, + exp, + "-Xmx1g", + optExecGC, + optExecRegionSize, + "-Xlog:cds", + "Hello"); + out.shouldContain(HELLO); + out.shouldHaveExitValue(0); + } +} From 74066bcca82749722e6fee57469520d418bf3430 Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Thu, 15 Aug 2024 22:57:33 +0000 Subject: [PATCH 326/353] 8338409: Use record to simplify code Reviewed-by: redestad, liach --- src/java.base/share/classes/java/util/Formatter.java | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/java.base/share/classes/java/util/Formatter.java b/src/java.base/share/classes/java/util/Formatter.java index dfdb77cc6ace2..1404892ff2a90 100644 --- a/src/java.base/share/classes/java/util/Formatter.java +++ b/src/java.base/share/classes/java/util/Formatter.java @@ -3021,15 +3021,7 @@ interface FormatString { String toString(); } - private static class FixedString implements FormatString { - private final String s; - private final int start; - private final int end; - FixedString(String s, int start, int end) { - this.s = s; - this.start = start; - this.end = end; - } + private record FixedString(String s, int start, int end) implements FormatString { public int index() { return -2; } public void print(Formatter fmt, Object arg, Locale l) throws IOException { fmt.a.append(s, start, end); } From bd4160cea8b6b0fcf0507199ed76a12f5d0aaba9 Mon Sep 17 00:00:00 2001 From: Axel Boldt-Christmas Date: Fri, 16 Aug 2024 06:20:17 +0000 Subject: [PATCH 327/353] 8315884: New Object to ObjectMonitor mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Erik Österlund Co-authored-by: Stefan Karlsson Co-authored-by: Coleen Phillimore Reviewed-by: rkennke, coleenp, dcubed --- src/hotspot/cpu/aarch64/aarch64.ad | 4 +- .../cpu/aarch64/c1_MacroAssembler_aarch64.cpp | 2 +- .../cpu/aarch64/c2_MacroAssembler_aarch64.cpp | 105 +- .../cpu/aarch64/c2_MacroAssembler_aarch64.hpp | 4 +- .../cpu/aarch64/interp_masm_aarch64.cpp | 14 +- .../cpu/aarch64/macroAssembler_aarch64.cpp | 9 +- .../cpu/aarch64/macroAssembler_aarch64.hpp | 2 +- .../cpu/aarch64/sharedRuntime_aarch64.cpp | 2 +- src/hotspot/cpu/arm/interp_masm_arm.cpp | 10 +- src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp | 6 +- src/hotspot/cpu/ppc/macroAssembler_ppc.cpp | 152 +- .../cpu/riscv/c2_MacroAssembler_riscv.cpp | 114 +- src/hotspot/cpu/riscv/interp_masm_riscv.cpp | 12 +- src/hotspot/cpu/s390/interp_masm_s390.cpp | 13 +- src/hotspot/cpu/s390/macroAssembler_s390.cpp | 108 +- src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp | 14 +- src/hotspot/cpu/x86/c2_CodeStubs_x86.cpp | 13 +- src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp | 128 +- src/hotspot/cpu/x86/interp_masm_x86.cpp | 24 +- src/hotspot/cpu/x86/macroAssembler_x86.cpp | 19 +- src/hotspot/cpu/x86/macroAssembler_x86.hpp | 2 +- src/hotspot/cpu/x86/sharedRuntime_x86.cpp | 8 +- src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp | 3 +- src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp | 2 +- src/hotspot/cpu/zero/zeroInterpreter_zero.cpp | 36 +- src/hotspot/share/c1/c1_Runtime1.cpp | 4 +- .../share/interpreter/interpreterRuntime.cpp | 20 +- .../interpreter/zero/bytecodeInterpreter.cpp | 170 ++- src/hotspot/share/jvmci/vmStructs_jvmci.cpp | 5 +- src/hotspot/share/logging/logTag.hpp | 1 + src/hotspot/share/oops/markWord.cpp | 3 +- src/hotspot/share/oops/markWord.hpp | 13 +- src/hotspot/share/opto/c2_CodeStubs.hpp | 2 + src/hotspot/share/opto/library_call.cpp | 30 +- src/hotspot/share/prims/jvmtiEnvBase.cpp | 10 +- src/hotspot/share/runtime/arguments.cpp | 10 + src/hotspot/share/runtime/basicLock.cpp | 27 +- src/hotspot/share/runtime/basicLock.hpp | 34 +- .../share/runtime/basicLock.inline.hpp | 62 + src/hotspot/share/runtime/deoptimization.cpp | 34 +- src/hotspot/share/runtime/globals.hpp | 11 + src/hotspot/share/runtime/javaThread.cpp | 5 +- src/hotspot/share/runtime/javaThread.hpp | 9 + .../share/runtime/javaThread.inline.hpp | 23 + .../share/runtime/lightweightSynchronizer.cpp | 1223 +++++++++++++++++ .../share/runtime/lightweightSynchronizer.hpp | 80 ++ src/hotspot/share/runtime/lockStack.cpp | 11 + src/hotspot/share/runtime/lockStack.hpp | 33 +- .../share/runtime/lockStack.inline.hpp | 52 + src/hotspot/share/runtime/objectMonitor.cpp | 225 +-- src/hotspot/share/runtime/objectMonitor.hpp | 99 +- .../share/runtime/objectMonitor.inline.hpp | 63 +- src/hotspot/share/runtime/safepoint.cpp | 5 + src/hotspot/share/runtime/serviceThread.cpp | 19 +- src/hotspot/share/runtime/sharedRuntime.cpp | 8 +- src/hotspot/share/runtime/synchronizer.cpp | 496 +++---- src/hotspot/share/runtime/synchronizer.hpp | 17 +- .../share/runtime/synchronizer.inline.hpp | 81 ++ src/hotspot/share/runtime/vframe.cpp | 17 +- src/hotspot/share/runtime/vmStructs.cpp | 4 +- .../classes/sun/jvm/hotspot/oops/Mark.java | 10 + .../sun/jvm/hotspot/runtime/BasicLock.java | 2 +- .../jvm/hotspot/runtime/ObjectMonitor.java | 8 +- .../hotspot/runtime/ObjectSynchronizer.java | 3 + .../gtest/runtime/test_objectMonitor.cpp | 24 +- .../Monitor/UseObjectMonitorTableTest.java | 244 ++++ .../runtime/logging/MonitorInflationTest.java | 2 +- .../org/openjdk/bench/vm/lang/LockUnlock.java | 190 ++- 68 files changed, 3284 insertions(+), 911 deletions(-) create mode 100644 src/hotspot/share/runtime/basicLock.inline.hpp create mode 100644 src/hotspot/share/runtime/lightweightSynchronizer.cpp create mode 100644 src/hotspot/share/runtime/lightweightSynchronizer.hpp create mode 100644 src/hotspot/share/runtime/synchronizer.inline.hpp create mode 100644 test/hotspot/jtreg/runtime/Monitor/UseObjectMonitorTableTest.java diff --git a/src/hotspot/cpu/aarch64/aarch64.ad b/src/hotspot/cpu/aarch64/aarch64.ad index a96c47051f2db..8eb2821cc5744 100644 --- a/src/hotspot/cpu/aarch64/aarch64.ad +++ b/src/hotspot/cpu/aarch64/aarch64.ad @@ -15793,7 +15793,7 @@ instruct cmpFastLockLightweight(rFlagsReg cr, iRegP object, iRegP box, iRegPNoSp format %{ "fastlock $object,$box\t! kills $tmp,$tmp2,$tmp3" %} ins_encode %{ - __ fast_lock_lightweight($object$$Register, $tmp$$Register, $tmp2$$Register, $tmp3$$Register); + __ fast_lock_lightweight($object$$Register, $box$$Register, $tmp$$Register, $tmp2$$Register, $tmp3$$Register); %} ins_pipe(pipe_serial); @@ -15809,7 +15809,7 @@ instruct cmpFastUnlockLightweight(rFlagsReg cr, iRegP object, iRegP box, iRegPNo format %{ "fastunlock $object,$box\t! kills $tmp, $tmp2, $tmp3" %} ins_encode %{ - __ fast_unlock_lightweight($object$$Register, $tmp$$Register, $tmp2$$Register, $tmp3$$Register); + __ fast_unlock_lightweight($object$$Register, $box$$Register, $tmp$$Register, $tmp2$$Register, $tmp3$$Register); %} ins_pipe(pipe_serial); diff --git a/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp index c0455ad1bff69..89624aeffdd04 100644 --- a/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp @@ -81,7 +81,7 @@ int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr } if (LockingMode == LM_LIGHTWEIGHT) { - lightweight_lock(obj, hdr, temp, rscratch2, slow_case); + lightweight_lock(disp_hdr, obj, hdr, temp, rscratch2, slow_case); } else if (LockingMode == LM_LEGACY) { Label done; // Load object header diff --git a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp index 251ea3813ff84..19af03d348806 100644 --- a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp @@ -224,10 +224,10 @@ void C2_MacroAssembler::fast_unlock(Register objectReg, Register boxReg, Registe bind(no_count); } -void C2_MacroAssembler::fast_lock_lightweight(Register obj, Register t1, +void C2_MacroAssembler::fast_lock_lightweight(Register obj, Register box, Register t1, Register t2, Register t3) { assert(LockingMode == LM_LIGHTWEIGHT, "must be"); - assert_different_registers(obj, t1, t2, t3); + assert_different_registers(obj, box, t1, t2, t3); // Handle inflated monitor. Label inflated; @@ -236,6 +236,11 @@ void C2_MacroAssembler::fast_lock_lightweight(Register obj, Register t1, // Finish fast lock unsuccessfully. MUST branch to with flag == NE Label slow_path; + if (UseObjectMonitorTable) { + // Clear cache in case fast locking succeeds. + str(zr, Address(box, BasicLock::object_monitor_cache_offset_in_bytes())); + } + if (DiagnoseSyncOnValueBasedClasses != 0) { load_klass(t1, obj); ldrw(t1, Address(t1, Klass::access_flags_offset())); @@ -244,6 +249,7 @@ void C2_MacroAssembler::fast_lock_lightweight(Register obj, Register t1, } const Register t1_mark = t1; + const Register t3_t = t3; { // Lightweight locking @@ -251,7 +257,6 @@ void C2_MacroAssembler::fast_lock_lightweight(Register obj, Register t1, Label push; const Register t2_top = t2; - const Register t3_t = t3; // Check if lock-stack is full. ldrw(t2_top, Address(rthread, JavaThread::lock_stack_top_offset())); @@ -289,26 +294,71 @@ void C2_MacroAssembler::fast_lock_lightweight(Register obj, Register t1, { // Handle inflated monitor. bind(inflated); - // mark contains the tagged ObjectMonitor*. - const Register t1_tagged_monitor = t1_mark; - const uintptr_t monitor_tag = markWord::monitor_value; + const Register t1_monitor = t1; + + if (!UseObjectMonitorTable) { + assert(t1_monitor == t1_mark, "should be the same here"); + } else { + Label monitor_found; + + // Load cache address + lea(t3_t, Address(rthread, JavaThread::om_cache_oops_offset())); + + const int num_unrolled = 2; + for (int i = 0; i < num_unrolled; i++) { + ldr(t1, Address(t3_t)); + cmp(obj, t1); + br(Assembler::EQ, monitor_found); + increment(t3_t, in_bytes(OMCache::oop_to_oop_difference())); + } + + Label loop; + + // Search for obj in cache. + bind(loop); + + // Check for match. + ldr(t1, Address(t3_t)); + cmp(obj, t1); + br(Assembler::EQ, monitor_found); + + // Search until null encountered, guaranteed _null_sentinel at end. + increment(t3_t, in_bytes(OMCache::oop_to_oop_difference())); + cbnz(t1, loop); + // Cache Miss, NE set from cmp above, cbnz does not set flags + b(slow_path); + + bind(monitor_found); + ldr(t1_monitor, Address(t3_t, OMCache::oop_to_monitor_difference())); + } + const Register t2_owner_addr = t2; const Register t3_owner = t3; + const ByteSize monitor_tag = in_ByteSize(UseObjectMonitorTable ? 0 : checked_cast(markWord::monitor_value)); + const Address owner_address(t1_monitor, ObjectMonitor::owner_offset() - monitor_tag); + const Address recursions_address(t1_monitor, ObjectMonitor::recursions_offset() - monitor_tag); + + Label monitor_locked; // Compute owner address. - lea(t2_owner_addr, Address(t1_tagged_monitor, (in_bytes(ObjectMonitor::owner_offset()) - monitor_tag))); + lea(t2_owner_addr, owner_address); // CAS owner (null => current thread). cmpxchg(t2_owner_addr, zr, rthread, Assembler::xword, /*acquire*/ true, /*release*/ false, /*weak*/ false, t3_owner); - br(Assembler::EQ, locked); + br(Assembler::EQ, monitor_locked); // Check if recursive. cmp(t3_owner, rthread); br(Assembler::NE, slow_path); // Recursive. - increment(Address(t1_tagged_monitor, in_bytes(ObjectMonitor::recursions_offset()) - monitor_tag), 1); + increment(recursions_address, 1); + + bind(monitor_locked); + if (UseObjectMonitorTable) { + str(t1_monitor, Address(box, BasicLock::object_monitor_cache_offset_in_bytes())); + } } bind(locked); @@ -331,13 +381,13 @@ void C2_MacroAssembler::fast_lock_lightweight(Register obj, Register t1, // C2 uses the value of Flags (NE vs EQ) to determine the continuation. } -void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register t1, Register t2, - Register t3) { +void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register box, Register t1, + Register t2, Register t3) { assert(LockingMode == LM_LIGHTWEIGHT, "must be"); - assert_different_registers(obj, t1, t2, t3); + assert_different_registers(obj, box, t1, t2, t3); // Handle inflated monitor. - Label inflated, inflated_load_monitor; + Label inflated, inflated_load_mark; // Finish fast unlock successfully. MUST branch to with flag == EQ Label unlocked; // Finish fast unlock unsuccessfully. MUST branch to with flag == NE @@ -349,13 +399,15 @@ void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register t1, Regis { // Lightweight unlock + Label push_and_slow_path; + // Check if obj is top of lock-stack. ldrw(t2_top, Address(rthread, JavaThread::lock_stack_top_offset())); subw(t2_top, t2_top, oopSize); ldr(t3_t, Address(rthread, t2_top)); cmp(obj, t3_t); // Top of lock stack was not obj. Must be monitor. - br(Assembler::NE, inflated_load_monitor); + br(Assembler::NE, inflated_load_mark); // Pop lock-stack. DEBUG_ONLY(str(zr, Address(rthread, t2_top));) @@ -372,7 +424,10 @@ void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register t1, Regis ldr(t1_mark, Address(obj, oopDesc::mark_offset_in_bytes())); // Check header for monitor (0b10). - tbnz(t1_mark, exact_log2(markWord::monitor_value), inflated); + // Because we got here by popping (meaning we pushed in locked) + // there will be no monitor in the box. So we need to push back the obj + // so that the runtime can fix any potential anonymous owner. + tbnz(t1_mark, exact_log2(markWord::monitor_value), UseObjectMonitorTable ? push_and_slow_path : inflated); // Try to unlock. Transition lock bits 0b00 => 0b01 assert(oopDesc::mark_offset_in_bytes() == 0, "required to avoid lea"); @@ -381,6 +436,7 @@ void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register t1, Regis /*acquire*/ false, /*release*/ true, /*weak*/ false, noreg); br(Assembler::EQ, unlocked); + bind(push_and_slow_path); // Compare and exchange failed. // Restore lock-stack and handle the unlock in runtime. DEBUG_ONLY(str(obj, Address(rthread, t2_top));) @@ -391,7 +447,7 @@ void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register t1, Regis { // Handle inflated monitor. - bind(inflated_load_monitor); + bind(inflated_load_mark); ldr(t1_mark, Address(obj, oopDesc::mark_offset_in_bytes())); #ifdef ASSERT tbnz(t1_mark, exact_log2(markWord::monitor_value), inflated); @@ -412,12 +468,19 @@ void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register t1, Regis bind(check_done); #endif - // mark contains the tagged ObjectMonitor*. - const Register t1_monitor = t1_mark; - const uintptr_t monitor_tag = markWord::monitor_value; + const Register t1_monitor = t1; + + if (!UseObjectMonitorTable) { + assert(t1_monitor == t1_mark, "should be the same here"); - // Untag the monitor. - sub(t1_monitor, t1_mark, monitor_tag); + // Untag the monitor. + add(t1_monitor, t1_mark, -(int)markWord::monitor_value); + } else { + ldr(t1_monitor, Address(box, BasicLock::object_monitor_cache_offset_in_bytes())); + // null check with Flags == NE, no valid pointer below alignof(ObjectMonitor*) + cmp(t1_monitor, checked_cast(alignof(ObjectMonitor*))); + br(Assembler::LO, slow_path); + } const Register t2_recursions = t2; Label not_recursive; diff --git a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp index 1481f975020c9..43e60ae5a48f8 100644 --- a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp @@ -39,8 +39,8 @@ void fast_lock(Register object, Register box, Register tmp, Register tmp2, Register tmp3); void fast_unlock(Register object, Register box, Register tmp, Register tmp2); // Code used by cmpFastLockLightweight and cmpFastUnlockLightweight mach instructions in .ad file. - void fast_lock_lightweight(Register object, Register t1, Register t2, Register t3); - void fast_unlock_lightweight(Register object, Register t1, Register t2, Register t3); + void fast_lock_lightweight(Register object, Register box, Register t1, Register t2, Register t3); + void fast_unlock_lightweight(Register object, Register box, Register t1, Register t2, Register t3); void string_compare(Register str1, Register str2, Register cnt1, Register cnt2, Register result, diff --git a/src/hotspot/cpu/aarch64/interp_masm_aarch64.cpp b/src/hotspot/cpu/aarch64/interp_masm_aarch64.cpp index ca359fea9da77..117168de0c5f0 100644 --- a/src/hotspot/cpu/aarch64/interp_masm_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/interp_masm_aarch64.cpp @@ -696,7 +696,7 @@ void InterpreterMacroAssembler::lock_object(Register lock_reg) } if (LockingMode == LM_LIGHTWEIGHT) { - lightweight_lock(obj_reg, tmp, tmp2, tmp3, slow_case); + lightweight_lock(lock_reg, obj_reg, tmp, tmp2, tmp3, slow_case); b(count); } else if (LockingMode == LM_LEGACY) { // Load (object->mark() | 1) into swap_reg @@ -752,15 +752,9 @@ void InterpreterMacroAssembler::lock_object(Register lock_reg) bind(slow_case); // Call the runtime routine for slow case - if (LockingMode == LM_LIGHTWEIGHT) { - call_VM(noreg, - CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter_obj), - obj_reg); - } else { - call_VM(noreg, - CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), - lock_reg); - } + call_VM(noreg, + CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), + lock_reg); b(done); bind(count); diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp index 9dd4371cf69e2..ead4220add056 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp @@ -6750,9 +6750,9 @@ void MacroAssembler::double_move(VMRegPair src, VMRegPair dst, Register tmp) { // - obj: the object to be locked // - t1, t2, t3: temporary registers, will be destroyed // - slow: branched to if locking fails, absolute offset may larger than 32KB (imm14 encoding). -void MacroAssembler::lightweight_lock(Register obj, Register t1, Register t2, Register t3, Label& slow) { +void MacroAssembler::lightweight_lock(Register basic_lock, Register obj, Register t1, Register t2, Register t3, Label& slow) { assert(LockingMode == LM_LIGHTWEIGHT, "only used with new lightweight locking"); - assert_different_registers(obj, t1, t2, t3, rscratch1); + assert_different_registers(basic_lock, obj, t1, t2, t3, rscratch1); Label push; const Register top = t1; @@ -6763,6 +6763,11 @@ void MacroAssembler::lightweight_lock(Register obj, Register t1, Register t2, Re // instruction emitted as it is part of C1's null check semantics. ldr(mark, Address(obj, oopDesc::mark_offset_in_bytes())); + if (UseObjectMonitorTable) { + // Clear cache in case fast locking succeeds. + str(zr, Address(basic_lock, BasicObjectLock::lock_offset() + in_ByteSize((BasicLock::object_monitor_cache_offset_in_bytes())))); + } + // Check if the lock-stack is full. ldrw(top, Address(rthread, JavaThread::lock_stack_top_offset())); cmpw(top, (unsigned)LockStack::end_offset()); diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp index 3bfd6e70872ce..e49f0c49ef66f 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp @@ -1639,7 +1639,7 @@ class MacroAssembler: public Assembler { // Code for java.lang.Thread::onSpinWait() intrinsic. void spin_wait(); - void lightweight_lock(Register obj, Register t1, Register t2, Register t3, Label& slow); + void lightweight_lock(Register basic_lock, Register obj, Register t1, Register t2, Register t3, Label& slow); void lightweight_unlock(Register obj, Register t1, Register t2, Register t3, Label& slow); private: diff --git a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp index 8ce4230baa2b4..a4dac0ccf6d8c 100644 --- a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp @@ -1811,7 +1811,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, __ br(Assembler::NE, slow_path_lock); } else { assert(LockingMode == LM_LIGHTWEIGHT, "must be"); - __ lightweight_lock(obj_reg, swap_reg, tmp, lock_tmp, slow_path_lock); + __ lightweight_lock(lock_reg, obj_reg, swap_reg, tmp, lock_tmp, slow_path_lock); } __ bind(count); __ increment(Address(rthread, JavaThread::held_monitor_count_offset())); diff --git a/src/hotspot/cpu/arm/interp_masm_arm.cpp b/src/hotspot/cpu/arm/interp_masm_arm.cpp index ba161e360bee4..2874abafc4f69 100644 --- a/src/hotspot/cpu/arm/interp_masm_arm.cpp +++ b/src/hotspot/cpu/arm/interp_masm_arm.cpp @@ -985,15 +985,7 @@ void InterpreterMacroAssembler::lock_object(Register Rlock) { bind(slow_case); // Call the runtime routine for slow case - if (LockingMode == LM_LIGHTWEIGHT) { - // Pass oop, not lock, in fast lock case. call_VM wants R1 though. - push(R1); - mov(R1, Robj); - call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter_obj), R1); - pop(R1); - } else { - call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), Rlock); - } + call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), Rlock); bind(done); } } diff --git a/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp b/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp index cdb8a742dcdf8..3acee737a3add 100644 --- a/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp +++ b/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp @@ -1043,11 +1043,7 @@ void InterpreterMacroAssembler::lock_object(Register monitor, Register object) { // None of the above fast optimizations worked so we have to get into the // slow case of monitor enter. bind(slow_case); - if (LockingMode == LM_LIGHTWEIGHT) { - call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter_obj), object); - } else { - call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), monitor); - } + call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), monitor); b(done); // } align(32, 12); diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp index f9e584a1e6b57..544c0d120d0d7 100644 --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp @@ -2804,32 +2804,39 @@ void MacroAssembler::compiler_fast_lock_lightweight_object(ConditionRegister fla { // Handle inflated monitor. bind(inflated); - // mark contains the tagged ObjectMonitor*. - const Register tagged_monitor = mark; - const uintptr_t monitor_tag = markWord::monitor_value; - const Register owner_addr = tmp2; - - // Compute owner address. - addi(owner_addr, tagged_monitor, in_bytes(ObjectMonitor::owner_offset()) - monitor_tag); - - // CAS owner (null => current thread). - cmpxchgd(/*flag=*/flag, - /*current_value=*/t, - /*compare_value=*/(intptr_t)0, - /*exchange_value=*/R16_thread, - /*where=*/owner_addr, - MacroAssembler::MemBarRel | MacroAssembler::MemBarAcq, - MacroAssembler::cmpxchgx_hint_acquire_lock()); - beq(flag, locked); - - // Check if recursive. - cmpd(flag, t, R16_thread); - bne(flag, slow_path); - - // Recursive. - ld(tmp1, in_bytes(ObjectMonitor::recursions_offset() - ObjectMonitor::owner_offset()), owner_addr); - addi(tmp1, tmp1, 1); - std(tmp1, in_bytes(ObjectMonitor::recursions_offset() - ObjectMonitor::owner_offset()), owner_addr); + if (!UseObjectMonitorTable) { + // mark contains the tagged ObjectMonitor*. + const Register tagged_monitor = mark; + const uintptr_t monitor_tag = markWord::monitor_value; + const Register owner_addr = tmp2; + + // Compute owner address. + addi(owner_addr, tagged_monitor, in_bytes(ObjectMonitor::owner_offset()) - monitor_tag); + + // CAS owner (null => current thread). + cmpxchgd(/*flag=*/flag, + /*current_value=*/t, + /*compare_value=*/(intptr_t)0, + /*exchange_value=*/R16_thread, + /*where=*/owner_addr, + MacroAssembler::MemBarRel | MacroAssembler::MemBarAcq, + MacroAssembler::cmpxchgx_hint_acquire_lock()); + beq(flag, locked); + + // Check if recursive. + cmpd(flag, t, R16_thread); + bne(flag, slow_path); + + // Recursive. + ld(tmp1, in_bytes(ObjectMonitor::recursions_offset() - ObjectMonitor::owner_offset()), owner_addr); + addi(tmp1, tmp1, 1); + std(tmp1, in_bytes(ObjectMonitor::recursions_offset() - ObjectMonitor::owner_offset()), owner_addr); + } else { + // OMCache lookup not supported yet. Take the slowpath. + // Set flag to NE + crxor(flag, Assembler::equal, flag, Assembler::equal); + b(slow_path); + } } bind(locked); @@ -2943,49 +2950,56 @@ void MacroAssembler::compiler_fast_unlock_lightweight_object(ConditionRegister f bind(check_done); #endif - // mark contains the tagged ObjectMonitor*. - const Register monitor = mark; - const uintptr_t monitor_tag = markWord::monitor_value; - - // Untag the monitor. - subi(monitor, mark, monitor_tag); - - const Register recursions = tmp2; - Label not_recursive; - - // Check if recursive. - ld(recursions, in_bytes(ObjectMonitor::recursions_offset()), monitor); - addic_(recursions, recursions, -1); - blt(CCR0, not_recursive); - - // Recursive unlock. - std(recursions, in_bytes(ObjectMonitor::recursions_offset()), monitor); - crorc(CCR0, Assembler::equal, CCR0, Assembler::equal); - b(unlocked); - - bind(not_recursive); - - Label release_; - const Register t2 = tmp2; - - // Check if the entry lists are empty. - ld(t, in_bytes(ObjectMonitor::EntryList_offset()), monitor); - ld(t2, in_bytes(ObjectMonitor::cxq_offset()), monitor); - orr(t, t, t2); - cmpdi(flag, t, 0); - beq(flag, release_); - - // The owner may be anonymous and we removed the last obj entry in - // the lock-stack. This loses the information about the owner. - // Write the thread to the owner field so the runtime knows the owner. - std(R16_thread, in_bytes(ObjectMonitor::owner_offset()), monitor); - b(slow_path); - - bind(release_); - // Set owner to null. - release(); - // t contains 0 - std(t, in_bytes(ObjectMonitor::owner_offset()), monitor); + if (!UseObjectMonitorTable) { + // mark contains the tagged ObjectMonitor*. + const Register monitor = mark; + const uintptr_t monitor_tag = markWord::monitor_value; + + // Untag the monitor. + subi(monitor, mark, monitor_tag); + + const Register recursions = tmp2; + Label not_recursive; + + // Check if recursive. + ld(recursions, in_bytes(ObjectMonitor::recursions_offset()), monitor); + addic_(recursions, recursions, -1); + blt(CCR0, not_recursive); + + // Recursive unlock. + std(recursions, in_bytes(ObjectMonitor::recursions_offset()), monitor); + crorc(CCR0, Assembler::equal, CCR0, Assembler::equal); + b(unlocked); + + bind(not_recursive); + + Label release_; + const Register t2 = tmp2; + + // Check if the entry lists are empty. + ld(t, in_bytes(ObjectMonitor::EntryList_offset()), monitor); + ld(t2, in_bytes(ObjectMonitor::cxq_offset()), monitor); + orr(t, t, t2); + cmpdi(flag, t, 0); + beq(flag, release_); + + // The owner may be anonymous and we removed the last obj entry in + // the lock-stack. This loses the information about the owner. + // Write the thread to the owner field so the runtime knows the owner. + std(R16_thread, in_bytes(ObjectMonitor::owner_offset()), monitor); + b(slow_path); + + bind(release_); + // Set owner to null. + release(); + // t contains 0 + std(t, in_bytes(ObjectMonitor::owner_offset()), monitor); + } else { + // OMCache lookup not supported yet. Take the slowpath. + // Set flag to NE + crxor(flag, Assembler::equal, flag, Assembler::equal); + b(slow_path); + } } bind(unlocked); diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp index d88e4bf320d70..8322b35e20579 100644 --- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp @@ -323,25 +323,30 @@ void C2_MacroAssembler::fast_lock_lightweight(Register obj, Register tmp1, Regis { // Handle inflated monitor. bind(inflated); - // mark contains the tagged ObjectMonitor*. - const Register tmp1_tagged_monitor = tmp1_mark; - const uintptr_t monitor_tag = markWord::monitor_value; - const Register tmp2_owner_addr = tmp2; - const Register tmp3_owner = tmp3; - - // Compute owner address. - la(tmp2_owner_addr, Address(tmp1_tagged_monitor, (in_bytes(ObjectMonitor::owner_offset()) - monitor_tag))); - - // CAS owner (null => current thread). - cmpxchg(/*addr*/ tmp2_owner_addr, /*expected*/ zr, /*new*/ xthread, Assembler::int64, - /*acquire*/ Assembler::aq, /*release*/ Assembler::relaxed, /*result*/ tmp3_owner); - beqz(tmp3_owner, locked); - - // Check if recursive. - bne(tmp3_owner, xthread, slow_path); - - // Recursive. - increment(Address(tmp1_tagged_monitor, in_bytes(ObjectMonitor::recursions_offset()) - monitor_tag), 1, tmp2, tmp3); + if (!UseObjectMonitorTable) { + // mark contains the tagged ObjectMonitor*. + const Register tmp1_tagged_monitor = tmp1_mark; + const uintptr_t monitor_tag = markWord::monitor_value; + const Register tmp2_owner_addr = tmp2; + const Register tmp3_owner = tmp3; + + // Compute owner address. + la(tmp2_owner_addr, Address(tmp1_tagged_monitor, (in_bytes(ObjectMonitor::owner_offset()) - monitor_tag))); + + // CAS owner (null => current thread). + cmpxchg(/*addr*/ tmp2_owner_addr, /*expected*/ zr, /*new*/ xthread, Assembler::int64, + /*acquire*/ Assembler::aq, /*release*/ Assembler::relaxed, /*result*/ tmp3_owner); + beqz(tmp3_owner, locked); + + // Check if recursive. + bne(tmp3_owner, xthread, slow_path); + + // Recursive. + increment(Address(tmp1_tagged_monitor, in_bytes(ObjectMonitor::recursions_offset()) - monitor_tag), 1, tmp2, tmp3); + } else { + // OMCache lookup not supported yet. Take the slowpath. + j(slow_path); + } } bind(locked); @@ -453,49 +458,54 @@ void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register tmp1, Reg bind(check_done); #endif - // mark contains the tagged ObjectMonitor*. - const Register tmp1_monitor = tmp1_mark; - const uintptr_t monitor_tag = markWord::monitor_value; + if (!UseObjectMonitorTable) { + // mark contains the tagged ObjectMonitor*. + const Register tmp1_monitor = tmp1_mark; + const uintptr_t monitor_tag = markWord::monitor_value; - // Untag the monitor. - sub(tmp1_monitor, tmp1_mark, monitor_tag); + // Untag the monitor. + sub(tmp1_monitor, tmp1_mark, monitor_tag); - const Register tmp2_recursions = tmp2; - Label not_recursive; + const Register tmp2_recursions = tmp2; + Label not_recursive; - // Check if recursive. - ld(tmp2_recursions, Address(tmp1_monitor, ObjectMonitor::recursions_offset())); - beqz(tmp2_recursions, not_recursive); + // Check if recursive. + ld(tmp2_recursions, Address(tmp1_monitor, ObjectMonitor::recursions_offset())); + beqz(tmp2_recursions, not_recursive); - // Recursive unlock. - addi(tmp2_recursions, tmp2_recursions, -1); - sd(tmp2_recursions, Address(tmp1_monitor, ObjectMonitor::recursions_offset())); - j(unlocked); + // Recursive unlock. + addi(tmp2_recursions, tmp2_recursions, -1); + sd(tmp2_recursions, Address(tmp1_monitor, ObjectMonitor::recursions_offset())); + j(unlocked); - bind(not_recursive); + bind(not_recursive); - Label release; - const Register tmp2_owner_addr = tmp2; + Label release; + const Register tmp2_owner_addr = tmp2; - // Compute owner address. - la(tmp2_owner_addr, Address(tmp1_monitor, ObjectMonitor::owner_offset())); + // Compute owner address. + la(tmp2_owner_addr, Address(tmp1_monitor, ObjectMonitor::owner_offset())); - // Check if the entry lists are empty. - ld(t0, Address(tmp1_monitor, ObjectMonitor::EntryList_offset())); - ld(tmp3_t, Address(tmp1_monitor, ObjectMonitor::cxq_offset())); - orr(t0, t0, tmp3_t); - beqz(t0, release); + // Check if the entry lists are empty. + ld(t0, Address(tmp1_monitor, ObjectMonitor::EntryList_offset())); + ld(tmp3_t, Address(tmp1_monitor, ObjectMonitor::cxq_offset())); + orr(t0, t0, tmp3_t); + beqz(t0, release); - // The owner may be anonymous and we removed the last obj entry in - // the lock-stack. This loses the information about the owner. - // Write the thread to the owner field so the runtime knows the owner. - sd(xthread, Address(tmp2_owner_addr)); - j(slow_path); + // The owner may be anonymous and we removed the last obj entry in + // the lock-stack. This loses the information about the owner. + // Write the thread to the owner field so the runtime knows the owner. + sd(xthread, Address(tmp2_owner_addr)); + j(slow_path); - bind(release); - // Set owner to null. - membar(MacroAssembler::LoadStore | MacroAssembler::StoreStore); - sd(zr, Address(tmp2_owner_addr)); + bind(release); + // Set owner to null. + membar(MacroAssembler::LoadStore | MacroAssembler::StoreStore); + sd(zr, Address(tmp2_owner_addr)); + } else { + // OMCache lookup not supported yet. Take the slowpath. + j(slow_path); + } } bind(unlocked); diff --git a/src/hotspot/cpu/riscv/interp_masm_riscv.cpp b/src/hotspot/cpu/riscv/interp_masm_riscv.cpp index af6d043d1d63e..17b75b30264a6 100644 --- a/src/hotspot/cpu/riscv/interp_masm_riscv.cpp +++ b/src/hotspot/cpu/riscv/interp_masm_riscv.cpp @@ -792,15 +792,9 @@ void InterpreterMacroAssembler::lock_object(Register lock_reg) bind(slow_case); // Call the runtime routine for slow case - if (LockingMode == LM_LIGHTWEIGHT) { - call_VM(noreg, - CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter_obj), - obj_reg); - } else { - call_VM(noreg, - CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), - lock_reg); - } + call_VM(noreg, + CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), + lock_reg); j(done); bind(count); diff --git a/src/hotspot/cpu/s390/interp_masm_s390.cpp b/src/hotspot/cpu/s390/interp_masm_s390.cpp index 14bb98cea6ac3..0b29c31ec96ef 100644 --- a/src/hotspot/cpu/s390/interp_masm_s390.cpp +++ b/src/hotspot/cpu/s390/interp_masm_s390.cpp @@ -1072,16 +1072,9 @@ void InterpreterMacroAssembler::lock_object(Register monitor, Register object) { // None of the above fast optimizations worked so we have to get into the // slow case of monitor enter. bind(slow_case); - if (LockingMode == LM_LIGHTWEIGHT) { - // for lightweight locking we need to use monitorenter_obj, see interpreterRuntime.cpp - call_VM(noreg, - CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter_obj), - object); - } else { - call_VM(noreg, - CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), - monitor); - } + call_VM(noreg, + CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), + monitor); // } bind(done); diff --git a/src/hotspot/cpu/s390/macroAssembler_s390.cpp b/src/hotspot/cpu/s390/macroAssembler_s390.cpp index 72d10ee80aae1..b72b36eef5351 100644 --- a/src/hotspot/cpu/s390/macroAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/macroAssembler_s390.cpp @@ -6218,26 +6218,33 @@ void MacroAssembler::compiler_fast_lock_lightweight_object(Register obj, Registe { // Handle inflated monitor. bind(inflated); - // mark contains the tagged ObjectMonitor*. - const Register tagged_monitor = mark; - const Register zero = tmp2; - - // Try to CAS m->owner from null to current thread. - // If m->owner is null, then csg succeeds and sets m->owner=THREAD and CR=EQ. - // Otherwise, register zero is filled with the current owner. - z_lghi(zero, 0); - z_csg(zero, Z_thread, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner), tagged_monitor); - z_bre(locked); - - // Check if recursive. - z_cgr(Z_thread, zero); // zero contains the owner from z_csg instruction - z_brne(slow_path); - - // Recursive - z_agsi(Address(tagged_monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions)), 1ll); - z_cgr(zero, zero); - // z_bru(locked); - // Uncomment above line in the future, for now jump address is right next to us. + if (!UseObjectMonitorTable) { + // mark contains the tagged ObjectMonitor*. + const Register tagged_monitor = mark; + const Register zero = tmp2; + + // Try to CAS m->owner from null to current thread. + // If m->owner is null, then csg succeeds and sets m->owner=THREAD and CR=EQ. + // Otherwise, register zero is filled with the current owner. + z_lghi(zero, 0); + z_csg(zero, Z_thread, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner), tagged_monitor); + z_bre(locked); + + // Check if recursive. + z_cgr(Z_thread, zero); // zero contains the owner from z_csg instruction + z_brne(slow_path); + + // Recursive + z_agsi(Address(tagged_monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions)), 1ll); + z_cgr(zero, zero); + // z_bru(locked); + // Uncomment above line in the future, for now jump address is right next to us. + } else { + // OMCache lookup not supported yet. Take the slowpath. + // Set flag to NE + z_ltgr(obj, obj); + z_bru(slow_path); + } } BLOCK_COMMENT("} handle_inflated_monitor_lightweight_locking"); @@ -6364,42 +6371,49 @@ void MacroAssembler::compiler_fast_unlock_lightweight_object(Register obj, Regis bind(check_done); #endif // ASSERT - // mark contains the tagged ObjectMonitor*. - const Register monitor = mark; + if (!UseObjectMonitorTable) { + // mark contains the tagged ObjectMonitor*. + const Register monitor = mark; - NearLabel not_recursive; - const Register recursions = tmp2; + NearLabel not_recursive; + const Register recursions = tmp2; - // Check if recursive. - load_and_test_long(recursions, Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions))); - z_bre(not_recursive); // if 0 then jump, it's not recursive locking + // Check if recursive. + load_and_test_long(recursions, Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions))); + z_bre(not_recursive); // if 0 then jump, it's not recursive locking - // Recursive unlock - z_agsi(Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions)), -1ll); - z_cgr(monitor, monitor); // set the CC to EQUAL - z_bru(unlocked); + // Recursive unlock + z_agsi(Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions)), -1ll); + z_cgr(monitor, monitor); // set the CC to EQUAL + z_bru(unlocked); - bind(not_recursive); + bind(not_recursive); - NearLabel not_ok; - // Check if the entry lists are empty. - load_and_test_long(tmp2, Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(EntryList))); - z_brne(not_ok); - load_and_test_long(tmp2, Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(cxq))); - z_brne(not_ok); + NearLabel not_ok; + // Check if the entry lists are empty. + load_and_test_long(tmp2, Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(EntryList))); + z_brne(not_ok); + load_and_test_long(tmp2, Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(cxq))); + z_brne(not_ok); - z_release(); - z_stg(tmp2 /*=0*/, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner), monitor); + z_release(); + z_stg(tmp2 /*=0*/, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner), monitor); - z_bru(unlocked); // CC = EQ here + z_bru(unlocked); // CC = EQ here - bind(not_ok); + bind(not_ok); - // The owner may be anonymous, and we removed the last obj entry in - // the lock-stack. This loses the information about the owner. - // Write the thread to the owner field so the runtime knows the owner. - z_stg(Z_thread, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner), monitor); - z_bru(slow_path); // CC = NE here + // The owner may be anonymous, and we removed the last obj entry in + // the lock-stack. This loses the information about the owner. + // Write the thread to the owner field so the runtime knows the owner. + z_stg(Z_thread, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner), monitor); + z_bru(slow_path); // CC = NE here + } else { + // OMCache lookup not supported yet. Take the slowpath. + // Set flag to NE + z_ltgr(obj, obj); + z_bru(slow_path); + } } bind(unlocked); diff --git a/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp b/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp index 2374324ca7c13..576592d05aa77 100644 --- a/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp @@ -66,11 +66,13 @@ int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr if (LockingMode == LM_LIGHTWEIGHT) { #ifdef _LP64 const Register thread = r15_thread; + lightweight_lock(disp_hdr, obj, hdr, thread, tmp, slow_case); #else - const Register thread = disp_hdr; - get_thread(thread); + // Implicit null check. + movptr(hdr, Address(obj, oopDesc::mark_offset_in_bytes())); + // Lacking registers and thread on x86_32. Always take slow path. + jmp(slow_case); #endif - lightweight_lock(obj, hdr, thread, tmp, slow_case); } else if (LockingMode == LM_LEGACY) { Label done; // Load object header @@ -139,10 +141,8 @@ void C1_MacroAssembler::unlock_object(Register hdr, Register obj, Register disp_ #ifdef _LP64 lightweight_unlock(obj, disp_hdr, r15_thread, hdr, slow_case); #else - // This relies on the implementation of lightweight_unlock being able to handle - // that the reg_rax and thread Register parameters may alias each other. - get_thread(disp_hdr); - lightweight_unlock(obj, disp_hdr, disp_hdr, hdr, slow_case); + // Lacking registers and thread on x86_32. Always take slow path. + jmp(slow_case); #endif } else if (LockingMode == LM_LEGACY) { // test if object header is pointing to the displaced header, and if so, restore diff --git a/src/hotspot/cpu/x86/c2_CodeStubs_x86.cpp b/src/hotspot/cpu/x86/c2_CodeStubs_x86.cpp index 6dc8d14064ad2..1990488d8a0df 100644 --- a/src/hotspot/cpu/x86/c2_CodeStubs_x86.cpp +++ b/src/hotspot/cpu/x86/c2_CodeStubs_x86.cpp @@ -96,6 +96,7 @@ void C2FastUnlockLightweightStub::emit(C2_MacroAssembler& masm) { { // Restore held monitor count and slow path. __ bind(restore_held_monitor_count_and_slow_path); + __ bind(_slow_path); // Restore held monitor count. __ increment(Address(_thread, JavaThread::held_monitor_count_offset())); // increment will always result in ZF = 0 (no overflows). @@ -112,19 +113,23 @@ void C2FastUnlockLightweightStub::emit(C2_MacroAssembler& masm) { #ifndef _LP64 __ jmpb(restore_held_monitor_count_and_slow_path); #else // _LP64 + const ByteSize monitor_tag = in_ByteSize(UseObjectMonitorTable ? 0 : checked_cast(markWord::monitor_value)); + const Address succ_address(monitor, ObjectMonitor::succ_offset() - monitor_tag); + const Address owner_address(monitor, ObjectMonitor::owner_offset() - monitor_tag); + // successor null check. - __ cmpptr(Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(succ)), NULL_WORD); + __ cmpptr(succ_address, NULL_WORD); __ jccb(Assembler::equal, restore_held_monitor_count_and_slow_path); // Release lock. - __ movptr(Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)), NULL_WORD); + __ movptr(owner_address, NULL_WORD); // Fence. // Instead of MFENCE we use a dummy locked add of 0 to the top-of-stack. __ lock(); __ addl(Address(rsp, 0), 0); // Recheck successor. - __ cmpptr(Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(succ)), NULL_WORD); + __ cmpptr(succ_address, NULL_WORD); // Observed a successor after the release -> fence we have handed off the monitor __ jccb(Assembler::notEqual, fix_zf_and_unlocked); @@ -133,7 +138,7 @@ void C2FastUnlockLightweightStub::emit(C2_MacroAssembler& masm) { // not handle the monitor handoff. Currently only works // due to the responsible thread. __ xorptr(rax, rax); - __ lock(); __ cmpxchgptr(_thread, Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner))); + __ lock(); __ cmpxchgptr(_thread, owner_address); __ jccb (Assembler::equal, restore_held_monitor_count_and_slow_path); #endif diff --git a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp index faab09b7c17b4..5dbfdbc225d75 100644 --- a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp @@ -590,6 +590,11 @@ void C2_MacroAssembler::fast_lock_lightweight(Register obj, Register box, Regist // Finish fast lock unsuccessfully. MUST jump with ZF == 0 Label slow_path; + if (UseObjectMonitorTable) { + // Clear cache in case fast locking succeeds. + movptr(Address(box, BasicLock::object_monitor_cache_offset_in_bytes()), 0); + } + if (DiagnoseSyncOnValueBasedClasses != 0) { load_klass(rax_reg, obj, t); movl(rax_reg, Address(rax_reg, Klass::access_flags_offset())); @@ -603,7 +608,7 @@ void C2_MacroAssembler::fast_lock_lightweight(Register obj, Register box, Regist Label push; - const Register top = box; + const Register top = UseObjectMonitorTable ? rax_reg : box; // Load the mark. movptr(mark, Address(obj, oopDesc::mark_offset_in_bytes())); @@ -630,6 +635,10 @@ void C2_MacroAssembler::fast_lock_lightweight(Register obj, Register box, Regist lock(); cmpxchgptr(mark, Address(obj, oopDesc::mark_offset_in_bytes())); jcc(Assembler::notEqual, slow_path); + if (UseObjectMonitorTable) { + // Need to reload top, clobbered by CAS. + movl(top, Address(thread, JavaThread::lock_stack_top_offset())); + } bind(push); // After successful lock, push object on lock-stack. movptr(Address(thread, top), obj); @@ -640,19 +649,68 @@ void C2_MacroAssembler::fast_lock_lightweight(Register obj, Register box, Regist { // Handle inflated monitor. bind(inflated); - const Register tagged_monitor = mark; + const Register monitor = t; + + if (!UseObjectMonitorTable) { + assert(mark == monitor, "should be the same here"); + } else { + // Uses ObjectMonitorTable. Look for the monitor in the om_cache. + // Fetch ObjectMonitor* from the cache or take the slow-path. + Label monitor_found; + + // Load cache address + lea(t, Address(thread, JavaThread::om_cache_oops_offset())); + + const int num_unrolled = 2; + for (int i = 0; i < num_unrolled; i++) { + cmpptr(obj, Address(t)); + jccb(Assembler::equal, monitor_found); + increment(t, in_bytes(OMCache::oop_to_oop_difference())); + } + + Label loop; + + // Search for obj in cache. + bind(loop); + + // Check for match. + cmpptr(obj, Address(t)); + jccb(Assembler::equal, monitor_found); + + // Search until null encountered, guaranteed _null_sentinel at end. + cmpptr(Address(t), 1); + jcc(Assembler::below, slow_path); // 0 check, but with ZF=0 when *t == 0 + increment(t, in_bytes(OMCache::oop_to_oop_difference())); + jmpb(loop); + + // Cache hit. + bind(monitor_found); + movptr(monitor, Address(t, OMCache::oop_to_monitor_difference())); + } + const ByteSize monitor_tag = in_ByteSize(UseObjectMonitorTable ? 0 : checked_cast(markWord::monitor_value)); + const Address recursions_address(monitor, ObjectMonitor::recursions_offset() - monitor_tag); + const Address owner_address(monitor, ObjectMonitor::owner_offset() - monitor_tag); + + Label monitor_locked; + // Lock the monitor. // CAS owner (null => current thread). xorptr(rax_reg, rax_reg); - lock(); cmpxchgptr(thread, Address(tagged_monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner))); - jccb(Assembler::equal, locked); + lock(); cmpxchgptr(thread, owner_address); + jccb(Assembler::equal, monitor_locked); // Check if recursive. cmpptr(thread, rax_reg); jccb(Assembler::notEqual, slow_path); // Recursive. - increment(Address(tagged_monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions))); + increment(recursions_address); + + bind(monitor_locked); + if (UseObjectMonitorTable) { + // Cache the monitor for unlock + movptr(Address(box, BasicLock::object_monitor_cache_offset_in_bytes()), monitor); + } } bind(locked); @@ -694,7 +752,9 @@ void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register reg_rax, decrement(Address(thread, JavaThread::held_monitor_count_offset())); const Register mark = t; - const Register top = reg_rax; + const Register monitor = t; + const Register top = UseObjectMonitorTable ? t : reg_rax; + const Register box = reg_rax; Label dummy; C2FastUnlockLightweightStub* stub = nullptr; @@ -706,14 +766,17 @@ void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register reg_rax, Label& push_and_slow_path = stub == nullptr ? dummy : stub->push_and_slow_path(); Label& check_successor = stub == nullptr ? dummy : stub->check_successor(); + Label& slow_path = stub == nullptr ? dummy : stub->slow_path(); { // Lightweight Unlock // Load top. movl(top, Address(thread, JavaThread::lock_stack_top_offset())); - // Prefetch mark. - movptr(mark, Address(obj, oopDesc::mark_offset_in_bytes())); + if (!UseObjectMonitorTable) { + // Prefetch mark. + movptr(mark, Address(obj, oopDesc::mark_offset_in_bytes())); + } // Check if obj is top of lock-stack. cmpptr(obj, Address(thread, top, Address::times_1, -oopSize)); @@ -730,6 +793,11 @@ void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register reg_rax, // We elide the monitor check, let the CAS fail instead. + if (UseObjectMonitorTable) { + // Load mark. + movptr(mark, Address(obj, oopDesc::mark_offset_in_bytes())); + } + // Try to unlock. Transition lock bits 0b00 => 0b01 movptr(reg_rax, mark); andptr(reg_rax, ~(int32_t)markWord::lock_mask); @@ -751,6 +819,9 @@ void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register reg_rax, jccb(Assembler::notEqual, inflated_check_lock_stack); stop("Fast Unlock lock on stack"); bind(check_done); + if (UseObjectMonitorTable) { + movptr(mark, Address(obj, oopDesc::mark_offset_in_bytes())); + } testptr(mark, markWord::monitor_value); jccb(Assembler::notZero, inflated); stop("Fast Unlock not monitor"); @@ -758,43 +829,40 @@ void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register reg_rax, bind(inflated); - // mark contains the tagged ObjectMonitor*. - const Register monitor = mark; - -#ifndef _LP64 - // Check if recursive. - xorptr(reg_rax, reg_rax); - orptr(reg_rax, Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions))); - jcc(Assembler::notZero, check_successor); - - // Check if the entry lists are empty. - movptr(reg_rax, Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(EntryList))); - orptr(reg_rax, Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(cxq))); - jcc(Assembler::notZero, check_successor); + if (!UseObjectMonitorTable) { + assert(mark == monitor, "should be the same here"); + } else { + // Uses ObjectMonitorTable. Look for the monitor in our BasicLock on the stack. + movptr(monitor, Address(box, BasicLock::object_monitor_cache_offset_in_bytes())); + // null check with ZF == 0, no valid pointer below alignof(ObjectMonitor*) + cmpptr(monitor, alignof(ObjectMonitor*)); + jcc(Assembler::below, slow_path); + } + const ByteSize monitor_tag = in_ByteSize(UseObjectMonitorTable ? 0 : checked_cast(markWord::monitor_value)); + const Address recursions_address{monitor, ObjectMonitor::recursions_offset() - monitor_tag}; + const Address cxq_address{monitor, ObjectMonitor::cxq_offset() - monitor_tag}; + const Address EntryList_address{monitor, ObjectMonitor::EntryList_offset() - monitor_tag}; + const Address owner_address{monitor, ObjectMonitor::owner_offset() - monitor_tag}; - // Release lock. - movptr(Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)), NULL_WORD); -#else // _LP64 Label recursive; // Check if recursive. - cmpptr(Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions)), 0); + cmpptr(recursions_address, 0); jccb(Assembler::notEqual, recursive); // Check if the entry lists are empty. - movptr(reg_rax, Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(cxq))); - orptr(reg_rax, Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(EntryList))); + movptr(reg_rax, cxq_address); + orptr(reg_rax, EntryList_address); jcc(Assembler::notZero, check_successor); // Release lock. - movptr(Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)), NULL_WORD); + movptr(owner_address, NULL_WORD); jmpb(unlocked); // Recursive unlock. bind(recursive); - decrement(Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions))); + decrement(recursions_address); xorl(t, t); -#endif } bind(unlocked); diff --git a/src/hotspot/cpu/x86/interp_masm_x86.cpp b/src/hotspot/cpu/x86/interp_masm_x86.cpp index 57d77bafd4b73..249506c13ffdf 100644 --- a/src/hotspot/cpu/x86/interp_masm_x86.cpp +++ b/src/hotspot/cpu/x86/interp_masm_x86.cpp @@ -1183,11 +1183,11 @@ void InterpreterMacroAssembler::lock_object(Register lock_reg) { if (LockingMode == LM_LIGHTWEIGHT) { #ifdef _LP64 const Register thread = r15_thread; + lightweight_lock(lock_reg, obj_reg, swap_reg, thread, tmp_reg, slow_case); #else - const Register thread = lock_reg; - get_thread(thread); + // Lacking registers and thread on x86_32. Always take slow path. + jmp(slow_case); #endif - lightweight_lock(obj_reg, swap_reg, thread, tmp_reg, slow_case); } else if (LockingMode == LM_LEGACY) { // Load immediate 1 into swap_reg %rax movl(swap_reg, 1); @@ -1249,15 +1249,9 @@ void InterpreterMacroAssembler::lock_object(Register lock_reg) { bind(slow_case); // Call the runtime routine for slow case - if (LockingMode == LM_LIGHTWEIGHT) { - call_VM(noreg, - CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter_obj), - obj_reg); - } else { - call_VM(noreg, - CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), - lock_reg); - } + call_VM(noreg, + CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), + lock_reg); bind(done); } } @@ -1306,10 +1300,8 @@ void InterpreterMacroAssembler::unlock_object(Register lock_reg) { #ifdef _LP64 lightweight_unlock(obj_reg, swap_reg, r15_thread, header_reg, slow_case); #else - // This relies on the implementation of lightweight_unlock being able to handle - // that the reg_rax and thread Register parameters may alias each other. - get_thread(swap_reg); - lightweight_unlock(obj_reg, swap_reg, swap_reg, header_reg, slow_case); + // Lacking registers and thread on x86_32. Always take slow path. + jmp(slow_case); #endif } else if (LockingMode == LM_LEGACY) { // Load the old header from BasicLock structure diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp index 78bcabb2000b3..a5ad19806eab6 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp @@ -10275,9 +10275,9 @@ void MacroAssembler::check_stack_alignment(Register sp, const char* msg, unsigne // reg_rax: rax // thread: the thread which attempts to lock obj // tmp: a temporary register -void MacroAssembler::lightweight_lock(Register obj, Register reg_rax, Register thread, Register tmp, Label& slow) { +void MacroAssembler::lightweight_lock(Register basic_lock, Register obj, Register reg_rax, Register thread, Register tmp, Label& slow) { assert(reg_rax == rax, ""); - assert_different_registers(obj, reg_rax, thread, tmp); + assert_different_registers(basic_lock, obj, reg_rax, thread, tmp); Label push; const Register top = tmp; @@ -10286,6 +10286,11 @@ void MacroAssembler::lightweight_lock(Register obj, Register reg_rax, Register t // instruction emitted as it is part of C1's null check semantics. movptr(reg_rax, Address(obj, oopDesc::mark_offset_in_bytes())); + if (UseObjectMonitorTable) { + // Clear cache in case fast locking succeeds. + movptr(Address(basic_lock, BasicObjectLock::lock_offset() + in_ByteSize((BasicLock::object_monitor_cache_offset_in_bytes()))), 0); + } + // Load top. movl(top, Address(thread, JavaThread::lock_stack_top_offset())); @@ -10324,13 +10329,9 @@ void MacroAssembler::lightweight_lock(Register obj, Register reg_rax, Register t // reg_rax: rax // thread: the thread // tmp: a temporary register -// -// x86_32 Note: reg_rax and thread may alias each other due to limited register -// availiability. void MacroAssembler::lightweight_unlock(Register obj, Register reg_rax, Register thread, Register tmp, Label& slow) { assert(reg_rax == rax, ""); - assert_different_registers(obj, reg_rax, tmp); - LP64_ONLY(assert_different_registers(obj, reg_rax, thread, tmp);) + assert_different_registers(obj, reg_rax, thread, tmp); Label unlocked, push_and_slow; const Register top = tmp; @@ -10370,10 +10371,6 @@ void MacroAssembler::lightweight_unlock(Register obj, Register reg_rax, Register bind(push_and_slow); // Restore lock-stack and handle the unlock in runtime. - if (thread == reg_rax) { - // On x86_32 we may lose the thread. - get_thread(thread); - } #ifdef ASSERT movl(top, Address(thread, JavaThread::lock_stack_top_offset())); movptr(Address(thread, top), obj); diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.hpp b/src/hotspot/cpu/x86/macroAssembler_x86.hpp index 2ecd2bbe96d49..594f0b95ca3e2 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.hpp @@ -2148,7 +2148,7 @@ class MacroAssembler: public Assembler { void check_stack_alignment(Register sp, const char* msg, unsigned bias = 0, Register tmp = noreg); - void lightweight_lock(Register obj, Register reg_rax, Register thread, Register tmp, Label& slow); + void lightweight_lock(Register basic_lock, Register obj, Register reg_rax, Register thread, Register tmp, Label& slow); void lightweight_unlock(Register obj, Register reg_rax, Register thread, Register tmp, Label& slow); #ifdef _LP64 diff --git a/src/hotspot/cpu/x86/sharedRuntime_x86.cpp b/src/hotspot/cpu/x86/sharedRuntime_x86.cpp index 3ecbb43f7f518..78330962d1a43 100644 --- a/src/hotspot/cpu/x86/sharedRuntime_x86.cpp +++ b/src/hotspot/cpu/x86/sharedRuntime_x86.cpp @@ -62,9 +62,11 @@ void SharedRuntime::inline_check_hashcode_from_object_header(MacroAssembler* mas if (LockingMode == LM_LIGHTWEIGHT) { - // check if monitor - __ testptr(result, markWord::monitor_value); - __ jcc(Assembler::notZero, slowCase); + if (!UseObjectMonitorTable) { + // check if monitor + __ testptr(result, markWord::monitor_value); + __ jcc(Assembler::notZero, slowCase); + } } else { // check if locked __ testptr(result, markWord::unlocked_value); diff --git a/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp b/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp index d313c1b216a40..85c9125a97d1e 100644 --- a/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp +++ b/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp @@ -1686,7 +1686,8 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, __ jcc(Assembler::notEqual, slow_path_lock); } else { assert(LockingMode == LM_LIGHTWEIGHT, "must be"); - __ lightweight_lock(obj_reg, swap_reg, thread, lock_reg, slow_path_lock); + // Lacking registers and thread on x86_32. Always take slow path. + __ jmp(slow_path_lock); } __ bind(count_mon); __ inc_held_monitor_count(); diff --git a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp index d27b1d141fc29..b5362a9942ce7 100644 --- a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp +++ b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp @@ -2266,7 +2266,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, __ jcc(Assembler::notEqual, slow_path_lock); } else { assert(LockingMode == LM_LIGHTWEIGHT, "must be"); - __ lightweight_lock(obj_reg, swap_reg, r15_thread, rscratch1, slow_path_lock); + __ lightweight_lock(lock_reg, obj_reg, swap_reg, r15_thread, rscratch1, slow_path_lock); } __ bind(count_mon); __ inc_held_monitor_count(); diff --git a/src/hotspot/cpu/zero/zeroInterpreter_zero.cpp b/src/hotspot/cpu/zero/zeroInterpreter_zero.cpp index 9e00b1c5b0462..2b53042ef1017 100644 --- a/src/hotspot/cpu/zero/zeroInterpreter_zero.cpp +++ b/src/hotspot/cpu/zero/zeroInterpreter_zero.cpp @@ -37,6 +37,7 @@ #include "oops/method.hpp" #include "oops/oop.inline.hpp" #include "prims/jvmtiExport.hpp" +#include "runtime/basicLock.inline.hpp" #include "runtime/frame.inline.hpp" #include "runtime/handles.inline.hpp" #include "runtime/interfaceSupport.inline.hpp" @@ -44,6 +45,7 @@ #include "runtime/timer.hpp" #include "runtime/timerTrace.hpp" #include "utilities/debug.hpp" +#include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" #include "entry_zero.hpp" @@ -331,23 +333,27 @@ int ZeroInterpreter::native_entry(Method* method, intptr_t UNUSED, TRAPS) { if (method->is_synchronized()) { monitor = (BasicObjectLock*) istate->stack_base(); oop lockee = monitor->obj(); - markWord disp = lockee->mark().set_unlocked(); - monitor->lock()->set_displaced_header(disp); - bool call_vm = (LockingMode == LM_MONITOR); - bool inc_monitor_count = true; - if (call_vm || lockee->cas_set_mark(markWord::from_pointer(monitor), disp) != disp) { - // Is it simple recursive case? - if (!call_vm && thread->is_lock_owned((address) disp.clear_lock_bits().to_pointer())) { - monitor->lock()->set_displaced_header(markWord::from_pointer(nullptr)); - } else { - inc_monitor_count = false; - CALL_VM_NOCHECK(InterpreterRuntime::monitorenter(thread, monitor)); - if (HAS_PENDING_EXCEPTION) - goto unwind_and_return; + bool success = false; + if (LockingMode == LM_LEGACY) { + markWord disp = lockee->mark().set_unlocked(); + monitor->lock()->set_displaced_header(disp); + success = true; + if (lockee->cas_set_mark(markWord::from_pointer(monitor), disp) != disp) { + // Is it simple recursive case? + if (thread->is_lock_owned((address) disp.clear_lock_bits().to_pointer())) { + monitor->lock()->set_displaced_header(markWord::from_pointer(nullptr)); + } else { + success = false; + } + } + if (success) { + THREAD->inc_held_monitor_count(); } } - if (inc_monitor_count) { - THREAD->inc_held_monitor_count(); + if (!success) { + CALL_VM_NOCHECK(InterpreterRuntime::monitorenter(thread, monitor)); + if (HAS_PENDING_EXCEPTION) + goto unwind_and_return; } } diff --git a/src/hotspot/share/c1/c1_Runtime1.cpp b/src/hotspot/share/c1/c1_Runtime1.cpp index 31ae3f6bee09d..8524f37177b45 100644 --- a/src/hotspot/share/c1/c1_Runtime1.cpp +++ b/src/hotspot/share/c1/c1_Runtime1.cpp @@ -757,8 +757,8 @@ JRT_BLOCK_ENTRY(void, Runtime1::monitorenter(JavaThread* current, oopDesc* obj, if (LockingMode == LM_MONITOR) { lock->set_obj(obj); } - assert(LockingMode == LM_LIGHTWEIGHT || obj == lock->obj(), "must match"); - SharedRuntime::monitor_enter_helper(obj, LockingMode == LM_LIGHTWEIGHT ? nullptr : lock->lock(), current); + assert(obj == lock->obj(), "must match"); + SharedRuntime::monitor_enter_helper(obj, lock->lock(), current); JRT_END diff --git a/src/hotspot/share/interpreter/interpreterRuntime.cpp b/src/hotspot/share/interpreter/interpreterRuntime.cpp index 4f2eae023f68d..525258b1ebd0c 100644 --- a/src/hotspot/share/interpreter/interpreterRuntime.cpp +++ b/src/hotspot/share/interpreter/interpreterRuntime.cpp @@ -71,7 +71,7 @@ #include "runtime/sharedRuntime.hpp" #include "runtime/stackWatermarkSet.hpp" #include "runtime/stubRoutines.hpp" -#include "runtime/synchronizer.hpp" +#include "runtime/synchronizer.inline.hpp" #include "runtime/threadCritical.hpp" #include "utilities/align.hpp" #include "utilities/checkedCast.hpp" @@ -725,7 +725,6 @@ void InterpreterRuntime::resolve_get_put(Bytecodes::Code bytecode, int field_ind //%note monitor_1 JRT_ENTRY_NO_ASYNC(void, InterpreterRuntime::monitorenter(JavaThread* current, BasicObjectLock* elem)) - assert(LockingMode != LM_LIGHTWEIGHT, "Should call monitorenter_obj() when using the new lightweight locking"); #ifdef ASSERT current->last_frame().interpreter_frame_verify_monitor(elem); #endif @@ -740,23 +739,6 @@ JRT_ENTRY_NO_ASYNC(void, InterpreterRuntime::monitorenter(JavaThread* current, B #endif JRT_END -// NOTE: We provide a separate implementation for the new lightweight locking to workaround a limitation -// of registers in x86_32. This entry point accepts an oop instead of a BasicObjectLock*. -// The problem is that we would need to preserve the register that holds the BasicObjectLock, -// but we are using that register to hold the thread. We don't have enough registers to -// also keep the BasicObjectLock, but we don't really need it anyway, we only need -// the object. See also InterpreterMacroAssembler::lock_object(). -// As soon as legacy stack-locking goes away we could remove the other monitorenter() entry -// point, and only use oop-accepting entries (same for monitorexit() below). -JRT_ENTRY_NO_ASYNC(void, InterpreterRuntime::monitorenter_obj(JavaThread* current, oopDesc* obj)) - assert(LockingMode == LM_LIGHTWEIGHT, "Should call monitorenter() when not using the new lightweight locking"); - Handle h_obj(current, cast_to_oop(obj)); - assert(Universe::heap()->is_in_or_null(h_obj()), - "must be null or an object"); - ObjectSynchronizer::enter(h_obj, nullptr, current); - return; -JRT_END - JRT_LEAF(void, InterpreterRuntime::monitorexit(BasicObjectLock* elem)) oop obj = elem->obj(); assert(Universe::heap()->is_in(obj), "must be an object"); diff --git a/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp b/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp index 36b01bb0802a9..fbdf8f9ca7145 100644 --- a/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp +++ b/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp @@ -53,7 +53,9 @@ #include "prims/jvmtiExport.hpp" #include "prims/jvmtiThreadState.hpp" #include "runtime/atomic.hpp" +#include "runtime/basicLock.inline.hpp" #include "runtime/frame.inline.hpp" +#include "runtime/globals.hpp" #include "runtime/handles.inline.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/orderAccess.hpp" @@ -61,6 +63,7 @@ #include "runtime/threadCritical.hpp" #include "utilities/debug.hpp" #include "utilities/exceptions.hpp" +#include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" /* @@ -624,23 +627,28 @@ void BytecodeInterpreter::run(interpreterState istate) { BasicObjectLock* mon = &istate->monitor_base()[-1]; mon->set_obj(rcvr); - // Traditional lightweight locking. - markWord displaced = rcvr->mark().set_unlocked(); - mon->lock()->set_displaced_header(displaced); - bool call_vm = (LockingMode == LM_MONITOR); - bool inc_monitor_count = true; - if (call_vm || rcvr->cas_set_mark(markWord::from_pointer(mon), displaced) != displaced) { - // Is it simple recursive case? - if (!call_vm && THREAD->is_lock_owned((address) displaced.clear_lock_bits().to_pointer())) { - mon->lock()->set_displaced_header(markWord::from_pointer(nullptr)); - } else { - inc_monitor_count = false; - CALL_VM(InterpreterRuntime::monitorenter(THREAD, mon), handle_exception); + bool success = false; + if (LockingMode == LM_LEGACY) { + // Traditional fast locking. + markWord displaced = rcvr->mark().set_unlocked(); + mon->lock()->set_displaced_header(displaced); + success = true; + if (rcvr->cas_set_mark(markWord::from_pointer(mon), displaced) != displaced) { + // Is it simple recursive case? + if (THREAD->is_lock_owned((address) displaced.clear_lock_bits().to_pointer())) { + mon->lock()->set_displaced_header(markWord::from_pointer(nullptr)); + } else { + success = false; + } + } + if (success) { + THREAD->inc_held_monitor_count(); } } - if (inc_monitor_count) { - THREAD->inc_held_monitor_count(); + if (!success) { + CALL_VM(InterpreterRuntime::monitorenter(THREAD, mon), handle_exception); } + } THREAD->set_do_not_unlock_if_synchronized(false); @@ -723,23 +731,28 @@ void BytecodeInterpreter::run(interpreterState istate) { assert(entry->obj() == nullptr, "Frame manager didn't allocate the monitor"); entry->set_obj(lockee); - // traditional lightweight locking - markWord displaced = lockee->mark().set_unlocked(); - entry->lock()->set_displaced_header(displaced); - bool call_vm = (LockingMode == LM_MONITOR); - bool inc_monitor_count = true; - if (call_vm || lockee->cas_set_mark(markWord::from_pointer(entry), displaced) != displaced) { - // Is it simple recursive case? - if (!call_vm && THREAD->is_lock_owned((address) displaced.clear_lock_bits().to_pointer())) { - entry->lock()->set_displaced_header(markWord::from_pointer(nullptr)); - } else { - inc_monitor_count = false; - CALL_VM(InterpreterRuntime::monitorenter(THREAD, entry), handle_exception); + bool success = false; + if (LockingMode == LM_LEGACY) { + // Traditional fast locking. + markWord displaced = lockee->mark().set_unlocked(); + entry->lock()->set_displaced_header(displaced); + success = true; + if (lockee->cas_set_mark(markWord::from_pointer(entry), displaced) != displaced) { + // Is it simple recursive case? + if (THREAD->is_lock_owned((address) displaced.clear_lock_bits().to_pointer())) { + entry->lock()->set_displaced_header(markWord::from_pointer(nullptr)); + } else { + success = false; + } + } + if (success) { + THREAD->inc_held_monitor_count(); } } - if (inc_monitor_count) { - THREAD->inc_held_monitor_count(); + if (!success) { + CALL_VM(InterpreterRuntime::monitorenter(THREAD, entry), handle_exception); } + UPDATE_PC_AND_TOS(1, -1); goto run; } @@ -1653,23 +1666,28 @@ void BytecodeInterpreter::run(interpreterState istate) { if (entry != nullptr) { entry->set_obj(lockee); - // traditional lightweight locking - markWord displaced = lockee->mark().set_unlocked(); - entry->lock()->set_displaced_header(displaced); - bool call_vm = (LockingMode == LM_MONITOR); - bool inc_monitor_count = true; - if (call_vm || lockee->cas_set_mark(markWord::from_pointer(entry), displaced) != displaced) { - // Is it simple recursive case? - if (!call_vm && THREAD->is_lock_owned((address) displaced.clear_lock_bits().to_pointer())) { - entry->lock()->set_displaced_header(markWord::from_pointer(nullptr)); - } else { - inc_monitor_count = false; - CALL_VM(InterpreterRuntime::monitorenter(THREAD, entry), handle_exception); + bool success = false; + if (LockingMode == LM_LEGACY) { + // Traditional fast locking. + markWord displaced = lockee->mark().set_unlocked(); + entry->lock()->set_displaced_header(displaced); + success = true; + if (lockee->cas_set_mark(markWord::from_pointer(entry), displaced) != displaced) { + // Is it simple recursive case? + if (THREAD->is_lock_owned((address) displaced.clear_lock_bits().to_pointer())) { + entry->lock()->set_displaced_header(markWord::from_pointer(nullptr)); + } else { + success = false; + } + } + if (success) { + THREAD->inc_held_monitor_count(); } } - if (inc_monitor_count) { - THREAD->inc_held_monitor_count(); + if (!success) { + CALL_VM(InterpreterRuntime::monitorenter(THREAD, entry), handle_exception); } + UPDATE_PC_AND_TOS_AND_CONTINUE(1, -1); } else { istate->set_msg(more_monitors); @@ -1687,23 +1705,27 @@ void BytecodeInterpreter::run(interpreterState istate) { while (most_recent != limit ) { if ((most_recent)->obj() == lockee) { BasicLock* lock = most_recent->lock(); - markWord header = lock->displaced_header(); - most_recent->set_obj(nullptr); - // If it isn't recursive we either must swap old header or call the runtime - bool dec_monitor_count = true; - bool call_vm = (LockingMode == LM_MONITOR); - if (header.to_pointer() != nullptr || call_vm) { - markWord old_header = markWord::encode(lock); - if (call_vm || lockee->cas_set_mark(header, old_header) != old_header) { - // restore object for the slow case - most_recent->set_obj(lockee); - dec_monitor_count = false; - InterpreterRuntime::monitorexit(most_recent); + bool success = false; + if (LockingMode == LM_LEGACY) { + // If it isn't recursive we either must swap old header or call the runtime + most_recent->set_obj(nullptr); + success = true; + markWord header = lock->displaced_header(); + if (header.to_pointer() != nullptr) { + markWord old_header = markWord::encode(lock); + if (lockee->cas_set_mark(header, old_header) != old_header) { + // restore object for the slow case + most_recent->set_obj(lockee); + success = false; + } + } + if (success) { + THREAD->dec_held_monitor_count(); } } - if (dec_monitor_count) { - THREAD->dec_held_monitor_count(); + if (!success) { + InterpreterRuntime::monitorexit(most_recent); } UPDATE_PC_AND_TOS_AND_CONTINUE(1, -1); } @@ -3125,22 +3147,28 @@ void BytecodeInterpreter::run(interpreterState istate) { oop lockee = end->obj(); if (lockee != nullptr) { BasicLock* lock = end->lock(); - markWord header = lock->displaced_header(); - end->set_obj(nullptr); - - // If it isn't recursive we either must swap old header or call the runtime - bool dec_monitor_count = true; - if (header.to_pointer() != nullptr) { - markWord old_header = markWord::encode(lock); - if (lockee->cas_set_mark(header, old_header) != old_header) { - // restore object for the slow case - end->set_obj(lockee); - dec_monitor_count = false; - InterpreterRuntime::monitorexit(end); + + bool success = false; + if (LockingMode == LM_LEGACY) { + markWord header = lock->displaced_header(); + end->set_obj(nullptr); + + // If it isn't recursive we either must swap old header or call the runtime + success = true; + if (header.to_pointer() != nullptr) { + markWord old_header = markWord::encode(lock); + if (lockee->cas_set_mark(header, old_header) != old_header) { + // restore object for the slow case + end->set_obj(lockee); + success = false; + } + } + if (success) { + THREAD->dec_held_monitor_count(); } } - if (dec_monitor_count) { - THREAD->dec_held_monitor_count(); + if (!success) { + InterpreterRuntime::monitorexit(end); } // One error is plenty @@ -3188,7 +3216,7 @@ void BytecodeInterpreter::run(interpreterState istate) { illegal_state_oop = Handle(THREAD, THREAD->pending_exception()); THREAD->clear_pending_exception(); } - } else if (LockingMode == LM_MONITOR) { + } else if (LockingMode != LM_LEGACY) { InterpreterRuntime::monitorexit(base); if (THREAD->has_pending_exception()) { if (!suppress_error) illegal_state_oop = Handle(THREAD, THREAD->pending_exception()); diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp index ac895cc93f2f7..5870e49ac94b5 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -151,7 +151,7 @@ nonstatic_field(Array, _length, int) \ nonstatic_field(Array, _data[0], Klass*) \ \ - volatile_nonstatic_field(BasicLock, _displaced_header, markWord) \ + volatile_nonstatic_field(BasicLock, _metadata, uintptr_t) \ \ static_field(CodeCache, _low_bound, address) \ static_field(CodeCache, _high_bound, address) \ @@ -241,6 +241,7 @@ nonstatic_field(JavaThread, _stack_overflow_state._reserved_stack_activation, address) \ nonstatic_field(JavaThread, _held_monitor_count, intx) \ nonstatic_field(JavaThread, _lock_stack, LockStack) \ + nonstatic_field(JavaThread, _om_cache, OMCache) \ JVMTI_ONLY(nonstatic_field(JavaThread, _is_in_VTMS_transition, bool)) \ JVMTI_ONLY(nonstatic_field(JavaThread, _is_in_tmp_VTMS_transition, bool)) \ JVMTI_ONLY(nonstatic_field(JavaThread, _is_disable_suspend, bool)) \ @@ -531,6 +532,8 @@ \ declare_constant_with_value("CardTable::dirty_card", CardTable::dirty_card_val()) \ declare_constant_with_value("LockStack::_end_offset", LockStack::end_offset()) \ + declare_constant_with_value("OMCache::oop_to_oop_difference", OMCache::oop_to_oop_difference()) \ + declare_constant_with_value("OMCache::oop_to_monitor_difference", OMCache::oop_to_monitor_difference()) \ \ declare_constant(CodeInstaller::VERIFIED_ENTRY) \ declare_constant(CodeInstaller::UNVERIFIED_ENTRY) \ diff --git a/src/hotspot/share/logging/logTag.hpp b/src/hotspot/share/logging/logTag.hpp index b64097311a440..b53a015b0f297 100644 --- a/src/hotspot/share/logging/logTag.hpp +++ b/src/hotspot/share/logging/logTag.hpp @@ -130,6 +130,7 @@ class outputStream; LOG_TAG(module) \ LOG_TAG(monitorinflation) \ LOG_TAG(monitormismatch) \ + LOG_TAG(monitortable) \ LOG_TAG(native) \ LOG_TAG(nestmates) \ LOG_TAG(nmethod) \ diff --git a/src/hotspot/share/oops/markWord.cpp b/src/hotspot/share/oops/markWord.cpp index e861ab8718293..2bbec570fa8e5 100644 --- a/src/hotspot/share/oops/markWord.cpp +++ b/src/hotspot/share/oops/markWord.cpp @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "oops/markWord.hpp" +#include "runtime/basicLock.inline.hpp" #include "runtime/javaThread.hpp" #include "runtime/objectMonitor.inline.hpp" #include "utilities/ostream.hpp" @@ -67,7 +68,7 @@ void markWord::print_on(outputStream* st, bool print_monitor_info) const { } else if (has_monitor()) { // last bits = 10 // have to check has_monitor() before is_locked() st->print(" monitor(" INTPTR_FORMAT ")=", value()); - if (print_monitor_info) { + if (print_monitor_info && !UseObjectMonitorTable) { ObjectMonitor* mon = monitor(); if (mon == nullptr) { st->print("null (this should never be seen!)"); diff --git a/src/hotspot/share/oops/markWord.hpp b/src/hotspot/share/oops/markWord.hpp index 12d6ee73acf94..92577a8b40b01 100644 --- a/src/hotspot/share/oops/markWord.hpp +++ b/src/hotspot/share/oops/markWord.hpp @@ -197,13 +197,17 @@ class markWord { } ObjectMonitor* monitor() const { assert(has_monitor(), "check"); + assert(!UseObjectMonitorTable, "Lightweight locking with OM table does not use markWord for monitors"); // Use xor instead of &~ to provide one extra tag-bit check. return (ObjectMonitor*) (value() ^ monitor_value); } bool has_displaced_mark_helper() const { intptr_t lockbits = value() & lock_mask_in_place; - return LockingMode == LM_LIGHTWEIGHT ? lockbits == monitor_value // monitor? - : (lockbits & unlocked_value) == 0; // monitor | stack-locked? + if (LockingMode == LM_LIGHTWEIGHT) { + return !UseObjectMonitorTable && lockbits == monitor_value; + } + // monitor (0b10) | stack-locked (0b00)? + return (lockbits & unlocked_value) == 0; } markWord displaced_mark_helper() const; void set_displaced_mark_helper(markWord m) const; @@ -223,10 +227,15 @@ class markWord { return from_pointer(lock); } static markWord encode(ObjectMonitor* monitor) { + assert(!UseObjectMonitorTable, "Lightweight locking with OM table does not use markWord for monitors"); uintptr_t tmp = (uintptr_t) monitor; return markWord(tmp | monitor_value); } + markWord set_has_monitor() const { + return markWord((value() & ~lock_mask_in_place) | monitor_value); + } + // used to encode pointers during GC markWord clear_lock_bits() const { return markWord(value() & ~lock_mask_in_place); } diff --git a/src/hotspot/share/opto/c2_CodeStubs.hpp b/src/hotspot/share/opto/c2_CodeStubs.hpp index 1316fa68ed430..5db7596e072dc 100644 --- a/src/hotspot/share/opto/c2_CodeStubs.hpp +++ b/src/hotspot/share/opto/c2_CodeStubs.hpp @@ -103,6 +103,7 @@ class C2FastUnlockLightweightStub : public C2CodeStub { Register _mark; Register _t; Register _thread; + Label _slow_path; Label _push_and_slow_path; Label _check_successor; Label _unlocked_continuation; @@ -111,6 +112,7 @@ class C2FastUnlockLightweightStub : public C2CodeStub { _obj(obj), _mark(mark), _t(t), _thread(thread) {} int max_size() const; void emit(C2_MacroAssembler& masm); + Label& slow_path() { return _slow_path; } Label& push_and_slow_path() { return _push_and_slow_path; } Label& check_successor() { return _check_successor; } Label& unlocked_continuation() { return _unlocked_continuation; } diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index 9660413dd190f..542514b1f7e24 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -4604,21 +4604,23 @@ bool LibraryCallKit::inline_native_hashcode(bool is_virtual, bool is_static) { Node* no_ctrl = nullptr; Node* header = make_load(no_ctrl, header_addr, TypeX_X, TypeX_X->basic_type(), MemNode::unordered); - // Test the header to see if it is safe to read w.r.t. locking. - Node *lock_mask = _gvn.MakeConX(markWord::lock_mask_in_place); - Node *lmasked_header = _gvn.transform(new AndXNode(header, lock_mask)); - if (LockingMode == LM_LIGHTWEIGHT) { - Node *monitor_val = _gvn.MakeConX(markWord::monitor_value); - Node *chk_monitor = _gvn.transform(new CmpXNode(lmasked_header, monitor_val)); - Node *test_monitor = _gvn.transform(new BoolNode(chk_monitor, BoolTest::eq)); - - generate_slow_guard(test_monitor, slow_region); - } else { - Node *unlocked_val = _gvn.MakeConX(markWord::unlocked_value); - Node *chk_unlocked = _gvn.transform(new CmpXNode(lmasked_header, unlocked_val)); - Node *test_not_unlocked = _gvn.transform(new BoolNode(chk_unlocked, BoolTest::ne)); + if (!UseObjectMonitorTable) { + // Test the header to see if it is safe to read w.r.t. locking. + Node *lock_mask = _gvn.MakeConX(markWord::lock_mask_in_place); + Node *lmasked_header = _gvn.transform(new AndXNode(header, lock_mask)); + if (LockingMode == LM_LIGHTWEIGHT) { + Node *monitor_val = _gvn.MakeConX(markWord::monitor_value); + Node *chk_monitor = _gvn.transform(new CmpXNode(lmasked_header, monitor_val)); + Node *test_monitor = _gvn.transform(new BoolNode(chk_monitor, BoolTest::eq)); + + generate_slow_guard(test_monitor, slow_region); + } else { + Node *unlocked_val = _gvn.MakeConX(markWord::unlocked_value); + Node *chk_unlocked = _gvn.transform(new CmpXNode(lmasked_header, unlocked_val)); + Node *test_not_unlocked = _gvn.transform(new BoolNode(chk_unlocked, BoolTest::ne)); - generate_slow_guard(test_not_unlocked, slow_region); + generate_slow_guard(test_not_unlocked, slow_region); + } } // Get the hash value and check to see that it has been properly assigned. diff --git a/src/hotspot/share/prims/jvmtiEnvBase.cpp b/src/hotspot/share/prims/jvmtiEnvBase.cpp index 1a6aec4e438f6..a05d69980931c 100644 --- a/src/hotspot/share/prims/jvmtiEnvBase.cpp +++ b/src/hotspot/share/prims/jvmtiEnvBase.cpp @@ -56,6 +56,7 @@ #include "runtime/osThread.hpp" #include "runtime/signature.hpp" #include "runtime/stackWatermarkSet.inline.hpp" +#include "runtime/synchronizer.inline.hpp" #include "runtime/threads.hpp" #include "runtime/threadSMR.inline.hpp" #include "runtime/vframe.inline.hpp" @@ -1465,7 +1466,6 @@ JvmtiEnvBase::get_object_monitor_usage(JavaThread* calling_thread, jobject objec ThreadsListHandle tlh(current_thread); JavaThread *owning_thread = nullptr; - ObjectMonitor *mon = nullptr; jvmtiMonitorUsage ret = { nullptr, 0, 0, nullptr, 0, nullptr }; @@ -1495,9 +1495,11 @@ JvmtiEnvBase::get_object_monitor_usage(JavaThread* calling_thread, jobject objec ResourceMark rm(current_thread); GrowableArray* wantList = nullptr; - if (mark.has_monitor()) { - mon = mark.monitor(); - assert(mon != nullptr, "must have monitor"); + ObjectMonitor* mon = mark.has_monitor() + ? ObjectSynchronizer::read_monitor(current_thread, hobj(), mark) + : nullptr; + + if (mon != nullptr) { // this object has a heavyweight monitor nWant = mon->contentions(); // # of threads contending for monitor entry, but not re-entry nWait = mon->waiters(); // # of threads waiting for notification, diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index 9086a5f6c7121..81b40e76a31f2 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -1816,8 +1816,18 @@ bool Arguments::check_vm_args_consistency() { FLAG_SET_CMDLINE(LockingMode, LM_LEGACY); warning("New lightweight locking not supported on this platform"); } + if (UseObjectMonitorTable) { + FLAG_SET_CMDLINE(UseObjectMonitorTable, false); + warning("UseObjectMonitorTable not supported on this platform"); + } #endif + if (UseObjectMonitorTable && LockingMode != LM_LIGHTWEIGHT) { + // ObjectMonitorTable requires lightweight locking. + FLAG_SET_CMDLINE(UseObjectMonitorTable, false); + warning("UseObjectMonitorTable requires LM_LIGHTWEIGHT"); + } + #if !defined(X86) && !defined(AARCH64) && !defined(PPC64) && !defined(RISCV64) && !defined(S390) if (LockingMode == LM_MONITOR) { jio_fprintf(defaultStream::error_stream(), diff --git a/src/hotspot/share/runtime/basicLock.cpp b/src/hotspot/share/runtime/basicLock.cpp index 704bea855768e..ec2e66a7d5d6c 100644 --- a/src/hotspot/share/runtime/basicLock.cpp +++ b/src/hotspot/share/runtime/basicLock.cpp @@ -24,16 +24,24 @@ #include "precompiled.hpp" #include "oops/oop.inline.hpp" -#include "runtime/basicLock.hpp" +#include "runtime/basicLock.inline.hpp" +#include "runtime/objectMonitor.hpp" #include "runtime/synchronizer.hpp" void BasicLock::print_on(outputStream* st, oop owner) const { st->print("monitor"); - markWord mark_word = displaced_header(); - if (mark_word.value() != 0) { - // Print monitor info if there's an owning oop and it refers to this BasicLock. - bool print_monitor_info = (owner != nullptr) && (owner->mark() == markWord::from_pointer((void*)this)); - mark_word.print_on(st, print_monitor_info); + if (UseObjectMonitorTable) { + ObjectMonitor* mon = object_monitor_cache(); + if (mon != nullptr) { + mon->print_on(st); + } + } else if (LockingMode == LM_LEGACY) { + markWord mark_word = displaced_header(); + if (mark_word.value() != 0) { + // Print monitor info if there's an owning oop and it refers to this BasicLock. + bool print_monitor_info = (owner != nullptr) && (owner->mark() == markWord::from_pointer((void*)this)); + mark_word.print_on(st, print_monitor_info); + } } } @@ -82,10 +90,15 @@ void BasicLock::move_to(oop obj, BasicLock* dest) { // we can find any flavor mark in the displaced mark. } dest->set_displaced_header(displaced_header()); + } else if (UseObjectMonitorTable) { + // Preserve the ObjectMonitor*, the cache is cleared when a box is reused + // and only read while the lock is held, so no stale ObjectMonitor* is + // encountered. + dest->set_object_monitor_cache(object_monitor_cache()); } #ifdef ASSERT else { - dest->set_displaced_header(markWord(badDispHeaderDeopt)); + dest->set_bad_metadata_deopt(); } #endif } diff --git a/src/hotspot/share/runtime/basicLock.hpp b/src/hotspot/share/runtime/basicLock.hpp index c348fa7f9a20c..193aa63cf8ff4 100644 --- a/src/hotspot/share/runtime/basicLock.hpp +++ b/src/hotspot/share/runtime/basicLock.hpp @@ -28,30 +28,46 @@ #include "oops/markWord.hpp" #include "runtime/atomic.hpp" #include "runtime/handles.hpp" +#include "utilities/globalDefinitions.hpp" #include "utilities/sizes.hpp" class BasicLock { friend class VMStructs; friend class JVMCIVMStructs; private: + // * For LM_MONITOR + // Unused. + // * For LM_LEGACY // This is either the actual displaced header from a locked object, or // a sentinel zero value indicating a recursive stack-lock. - volatile markWord _displaced_header; + // * For LM_LIGHTWEIGHT + // Used as a cache of the ObjectMonitor* used when locking. Must either + // be nullptr or the ObjectMonitor* used when locking. + volatile uintptr_t _metadata; + + uintptr_t get_metadata() const { return Atomic::load(&_metadata); } + void set_metadata(uintptr_t value) { Atomic::store(&_metadata, value); } + static int metadata_offset_in_bytes() { return (int)offset_of(BasicLock, _metadata); } + public: - markWord displaced_header() const { - return Atomic::load(&_displaced_header); - } + // LM_MONITOR + void set_bad_metadata_deopt() { set_metadata(badDispHeaderDeopt); } - void set_displaced_header(markWord header) { - Atomic::store(&_displaced_header, header); - } + // LM_LEGACY + inline markWord displaced_header() const; + inline void set_displaced_header(markWord header); + static int displaced_header_offset_in_bytes() { return metadata_offset_in_bytes(); } + + // LM_LIGHTWEIGHT + inline ObjectMonitor* object_monitor_cache() const; + inline void clear_object_monitor_cache(); + inline void set_object_monitor_cache(ObjectMonitor* mon); + static int object_monitor_cache_offset_in_bytes() { return metadata_offset_in_bytes(); } void print_on(outputStream* st, oop owner) const; // move a basic lock (used during deoptimization) void move_to(oop obj, BasicLock* dest); - - static int displaced_header_offset_in_bytes() { return (int)offset_of(BasicLock, _displaced_header); } }; // A BasicObjectLock associates a specific Java object with a BasicLock. diff --git a/src/hotspot/share/runtime/basicLock.inline.hpp b/src/hotspot/share/runtime/basicLock.inline.hpp new file mode 100644 index 0000000000000..fb1cee8de8f51 --- /dev/null +++ b/src/hotspot/share/runtime/basicLock.inline.hpp @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_RUNTIME_BASICLOCK_INLINE_HPP +#define SHARE_RUNTIME_BASICLOCK_INLINE_HPP + +#include "runtime/basicLock.hpp" + +inline markWord BasicLock::displaced_header() const { + assert(LockingMode == LM_LEGACY, "must be"); + return markWord(get_metadata()); +} + +inline void BasicLock::set_displaced_header(markWord header) { + assert(LockingMode == LM_LEGACY, "must be"); + Atomic::store(&_metadata, header.value()); +} + +inline ObjectMonitor* BasicLock::object_monitor_cache() const { + assert(UseObjectMonitorTable, "must be"); +#if defined(X86) || defined(AARCH64) + return reinterpret_cast(get_metadata()); +#else + // Other platforms do not make use of the cache yet, + // and are not as careful with maintaining the invariant + // that the metadata either is nullptr or ObjectMonitor*. + return nullptr; +#endif +} + +inline void BasicLock::clear_object_monitor_cache() { + assert(UseObjectMonitorTable, "must be"); + set_metadata(0); +} + +inline void BasicLock::set_object_monitor_cache(ObjectMonitor* mon) { + assert(UseObjectMonitorTable, "must be"); + set_metadata(reinterpret_cast(mon)); +} + +#endif // SHARE_RUNTIME_BASICLOCK_INLINE_HPP diff --git a/src/hotspot/share/runtime/deoptimization.cpp b/src/hotspot/share/runtime/deoptimization.cpp index cf82ad7c0277a..7961e56598f25 100644 --- a/src/hotspot/share/runtime/deoptimization.cpp +++ b/src/hotspot/share/runtime/deoptimization.cpp @@ -63,6 +63,7 @@ #include "prims/methodHandles.hpp" #include "prims/vectorSupport.hpp" #include "runtime/atomic.hpp" +#include "runtime/basicLock.inline.hpp" #include "runtime/continuation.hpp" #include "runtime/continuationEntry.inline.hpp" #include "runtime/deoptimization.hpp" @@ -75,6 +76,8 @@ #include "runtime/javaThread.hpp" #include "runtime/jniHandles.inline.hpp" #include "runtime/keepStackGCProcessed.hpp" +#include "runtime/lightweightSynchronizer.hpp" +#include "runtime/lockStack.inline.hpp" #include "runtime/objectMonitor.inline.hpp" #include "runtime/osThread.hpp" #include "runtime/safepointVerifiers.hpp" @@ -84,7 +87,7 @@ #include "runtime/stackValue.hpp" #include "runtime/stackWatermarkSet.hpp" #include "runtime/stubRoutines.hpp" -#include "runtime/synchronizer.hpp" +#include "runtime/synchronizer.inline.hpp" #include "runtime/threadSMR.hpp" #include "runtime/threadWXSetters.inline.hpp" #include "runtime/vframe.hpp" @@ -1634,22 +1637,37 @@ bool Deoptimization::relock_objects(JavaThread* thread, GrowableArraycurrent_waiting_monitor(); if (waiting_monitor != nullptr && waiting_monitor->object() == obj()) { assert(fr.is_deoptimized_frame(), "frame must be scheduled for deoptimization"); - mon_info->lock()->set_displaced_header(markWord::unused_mark()); + if (LockingMode == LM_LEGACY) { + mon_info->lock()->set_displaced_header(markWord::unused_mark()); + } else if (UseObjectMonitorTable) { + mon_info->lock()->clear_object_monitor_cache(); + } +#ifdef ASSERT + else { + assert(LockingMode == LM_MONITOR || !UseObjectMonitorTable, "must be"); + mon_info->lock()->set_bad_metadata_deopt(); + } +#endif JvmtiDeferredUpdates::inc_relock_count_after_wait(deoptee_thread); continue; } } } + BasicLock* lock = mon_info->lock(); if (LockingMode == LM_LIGHTWEIGHT) { // We have lost information about the correct state of the lock stack. - // Inflate the locks instead. Enter then inflate to avoid races with - // deflation. - ObjectSynchronizer::enter_for(obj, nullptr, deoptee_thread); + // Entering may create an invalid lock stack. Inflate the lock if it + // was fast_locked to restore the valid lock stack. + ObjectSynchronizer::enter_for(obj, lock, deoptee_thread); + if (deoptee_thread->lock_stack().contains(obj())) { + LightweightSynchronizer::inflate_fast_locked_object(obj(), ObjectSynchronizer::InflateCause::inflate_cause_vm_internal, + deoptee_thread, thread); + } assert(mon_info->owner()->is_locked(), "object must be locked now"); - ObjectMonitor* mon = ObjectSynchronizer::inflate_for(deoptee_thread, obj(), ObjectSynchronizer::inflate_cause_vm_internal); - assert(mon->owner() == deoptee_thread, "must be"); + assert(obj->mark().has_monitor(), "must be"); + assert(!deoptee_thread->lock_stack().contains(obj()), "must be"); + assert(ObjectSynchronizer::read_monitor(thread, obj(), obj->mark())->owner() == deoptee_thread, "must be"); } else { - BasicLock* lock = mon_info->lock(); ObjectSynchronizer::enter_for(obj, lock, deoptee_thread); assert(mon_info->owner()->is_locked(), "object must be locked now"); } diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp index 61efc0b93764d..d442894798b78 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -1956,6 +1956,17 @@ const int ObjectAlignmentInBytes = 8; "2: monitors & new lightweight locking (LM_LIGHTWEIGHT, default)") \ range(0, 2) \ \ + product(bool, UseObjectMonitorTable, false, DIAGNOSTIC, \ + "With Lightweight Locking mode, use a table to record inflated " \ + "monitors rather than the first word of the object.") \ + \ + product(int, LightweightFastLockingSpins, 13, DIAGNOSTIC, \ + "Specifies the number of times lightweight fast locking will " \ + "attempt to CAS the markWord before inflating. Between each " \ + "CAS it will spin for exponentially more time, resulting in " \ + "a total number of spins on the order of O(2^value)") \ + range(1, 30) \ + \ product(uint, TrimNativeHeapInterval, 0, \ "Interval, in ms, at which the JVM will trim the native heap if " \ "the platform supports that. Lower values will reclaim memory " \ diff --git a/src/hotspot/share/runtime/javaThread.cpp b/src/hotspot/share/runtime/javaThread.cpp index b69ab708afa52..0c00ef75c9216 100644 --- a/src/hotspot/share/runtime/javaThread.cpp +++ b/src/hotspot/share/runtime/javaThread.cpp @@ -504,7 +504,8 @@ JavaThread::JavaThread(MEMFLAGS flags) : _SleepEvent(ParkEvent::Allocate(this)), - _lock_stack(this) { + _lock_stack(this), + _om_cache(this) { set_jni_functions(jni_functions()); #if INCLUDE_JVMCI @@ -803,6 +804,8 @@ void JavaThread::exit(bool destroy_vm, ExitType exit_type) { elapsedTimer _timer_exit_phase3; elapsedTimer _timer_exit_phase4; + om_clear_monitor_cache(); + if (log_is_enabled(Debug, os, thread, timer)) { _timer_exit_phase1.start(); } diff --git a/src/hotspot/share/runtime/javaThread.hpp b/src/hotspot/share/runtime/javaThread.hpp index 755a8268864dd..54a11dad9b832 100644 --- a/src/hotspot/share/runtime/javaThread.hpp +++ b/src/hotspot/share/runtime/javaThread.hpp @@ -61,6 +61,7 @@ class JvmtiSampledObjectAllocEventCollector; class JvmtiThreadState; class Metadata; +class ObjectMonitor; class OopHandleList; class OopStorage; class OSThread; @@ -1165,6 +1166,7 @@ class JavaThread: public Thread { private: LockStack _lock_stack; + OMCache _om_cache; public: LockStack& lock_stack() { return _lock_stack; } @@ -1176,6 +1178,13 @@ class JavaThread: public Thread { static ByteSize lock_stack_top_offset() { return lock_stack_offset() + LockStack::top_offset(); } static ByteSize lock_stack_base_offset() { return lock_stack_offset() + LockStack::base_offset(); } + static ByteSize om_cache_offset() { return byte_offset_of(JavaThread, _om_cache); } + static ByteSize om_cache_oops_offset() { return om_cache_offset() + OMCache::entries_offset(); } + + void om_set_monitor_cache(ObjectMonitor* monitor); + void om_clear_monitor_cache(); + ObjectMonitor* om_get_from_monitor_cache(oop obj); + static OopStorage* thread_oop_storage(); static void verify_cross_modify_fence_failure(JavaThread *thread) PRODUCT_RETURN; diff --git a/src/hotspot/share/runtime/javaThread.inline.hpp b/src/hotspot/share/runtime/javaThread.inline.hpp index a51a30ae577c1..fabb589c2b5ac 100644 --- a/src/hotspot/share/runtime/javaThread.inline.hpp +++ b/src/hotspot/share/runtime/javaThread.inline.hpp @@ -36,7 +36,9 @@ #include "runtime/atomic.hpp" #include "runtime/continuation.hpp" #include "runtime/continuationEntry.inline.hpp" +#include "runtime/lockStack.inline.hpp" #include "runtime/nonJavaThread.hpp" +#include "runtime/objectMonitor.inline.hpp" #include "runtime/orderAccess.hpp" #include "runtime/safepoint.hpp" @@ -239,4 +241,25 @@ inline InstanceKlass* JavaThread::class_to_be_initialized() const { return _class_to_be_initialized; } +inline void JavaThread::om_set_monitor_cache(ObjectMonitor* monitor) { + assert(UseObjectMonitorTable, "must be"); + assert(monitor != nullptr, "use om_clear_monitor_cache to clear"); + assert(this == current() || monitor->owner_raw() == this, "only add owned monitors for other threads"); + assert(this == current() || is_obj_deopt_suspend(), "thread must not run concurrently"); + + _om_cache.set_monitor(monitor); +} + +inline void JavaThread::om_clear_monitor_cache() { + if (UseObjectMonitorTable) { + _om_cache.clear(); + } +} + +inline ObjectMonitor* JavaThread::om_get_from_monitor_cache(oop obj) { + assert(obj != nullptr, "do not look for null objects"); + assert(this == current(), "only get own thread locals"); + return _om_cache.get_monitor(obj); +} + #endif // SHARE_RUNTIME_JAVATHREAD_INLINE_HPP diff --git a/src/hotspot/share/runtime/lightweightSynchronizer.cpp b/src/hotspot/share/runtime/lightweightSynchronizer.cpp new file mode 100644 index 0000000000000..0e360dba97bdd --- /dev/null +++ b/src/hotspot/share/runtime/lightweightSynchronizer.cpp @@ -0,0 +1,1223 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" + +#include "classfile/vmSymbols.hpp" +#include "jfrfiles/jfrEventClasses.hpp" +#include "logging/log.hpp" +#include "memory/allStatic.hpp" +#include "memory/resourceArea.hpp" +#include "nmt/memflags.hpp" +#include "oops/oop.inline.hpp" +#include "runtime/atomic.hpp" +#include "runtime/basicLock.inline.hpp" +#include "runtime/globals_extension.hpp" +#include "runtime/interfaceSupport.inline.hpp" +#include "runtime/javaThread.inline.hpp" +#include "runtime/lightweightSynchronizer.hpp" +#include "runtime/lockStack.inline.hpp" +#include "runtime/mutexLocker.hpp" +#include "runtime/objectMonitor.inline.hpp" +#include "runtime/os.hpp" +#include "runtime/perfData.inline.hpp" +#include "runtime/safepointMechanism.inline.hpp" +#include "runtime/safepointVerifiers.hpp" +#include "runtime/synchronizer.inline.hpp" +#include "runtime/timerTrace.hpp" +#include "runtime/trimNativeHeap.hpp" +#include "utilities/concurrentHashTable.inline.hpp" +#include "utilities/concurrentHashTableTasks.inline.hpp" +#include "utilities/globalDefinitions.hpp" + +// ConcurrentHashTable storing links from objects to ObjectMonitors +class ObjectMonitorTable : AllStatic { + struct Config { + using Value = ObjectMonitor*; + static uintx get_hash(Value const& value, bool* is_dead) { + return (uintx)value->hash(); + } + static void* allocate_node(void* context, size_t size, Value const& value) { + ObjectMonitorTable::inc_items_count(); + return AllocateHeap(size, MEMFLAGS::mtObjectMonitor); + }; + static void free_node(void* context, void* memory, Value const& value) { + ObjectMonitorTable::dec_items_count(); + FreeHeap(memory); + } + }; + using ConcurrentTable = ConcurrentHashTable; + + static ConcurrentTable* _table; + static volatile size_t _items_count; + static size_t _table_size; + static volatile bool _resize; + + class Lookup : public StackObj { + oop _obj; + + public: + explicit Lookup(oop obj) : _obj(obj) {} + + uintx get_hash() const { + uintx hash = _obj->mark().hash(); + assert(hash != 0, "should have a hash"); + return hash; + } + + bool equals(ObjectMonitor** value) { + assert(*value != nullptr, "must be"); + return (*value)->object_refers_to(_obj); + } + + bool is_dead(ObjectMonitor** value) { + assert(*value != nullptr, "must be"); + return false; + } + }; + + class LookupMonitor : public StackObj { + ObjectMonitor* _monitor; + + public: + explicit LookupMonitor(ObjectMonitor* monitor) : _monitor(monitor) {} + + uintx get_hash() const { + return _monitor->hash(); + } + + bool equals(ObjectMonitor** value) { + return (*value) == _monitor; + } + + bool is_dead(ObjectMonitor** value) { + assert(*value != nullptr, "must be"); + return (*value)->object_is_dead(); + } + }; + + static void inc_items_count() { + Atomic::inc(&_items_count); + } + + static void dec_items_count() { + Atomic::dec(&_items_count); + } + + static double get_load_factor() { + return (double)_items_count / (double)_table_size; + } + + static size_t table_size(Thread* current = Thread::current()) { + return ((size_t)1) << _table->get_size_log2(current); + } + + static size_t max_log_size() { + // TODO[OMTable]: Evaluate the max size. + // TODO[OMTable]: Need to fix init order to use Universe::heap()->max_capacity(); + // Using MaxHeapSize directly this early may be wrong, and there + // are definitely rounding errors (alignment). + const size_t max_capacity = MaxHeapSize; + const size_t min_object_size = CollectedHeap::min_dummy_object_size() * HeapWordSize; + const size_t max_objects = max_capacity / MAX2(MinObjAlignmentInBytes, checked_cast(min_object_size)); + const size_t log_max_objects = log2i_graceful(max_objects); + + return MAX2(MIN2(SIZE_BIG_LOG2, log_max_objects), min_log_size()); + } + + static size_t min_log_size() { + // ~= log(AvgMonitorsPerThreadEstimate default) + return 10; + } + + template + static size_t clamp_log_size(V log_size) { + return MAX2(MIN2(log_size, checked_cast(max_log_size())), checked_cast(min_log_size())); + } + + static size_t initial_log_size() { + const size_t estimate = log2i(MAX2(os::processor_count(), 1)) + log2i(MAX2(AvgMonitorsPerThreadEstimate, size_t(1))); + return clamp_log_size(estimate); + } + + static size_t grow_hint () { + return ConcurrentTable::DEFAULT_GROW_HINT; + } + + public: + static void create() { + _table = new ConcurrentTable(initial_log_size(), max_log_size(), grow_hint()); + _items_count = 0; + _table_size = table_size(); + _resize = false; + } + + static void verify_monitor_get_result(oop obj, ObjectMonitor* monitor) { +#ifdef ASSERT + if (SafepointSynchronize::is_at_safepoint()) { + bool has_monitor = obj->mark().has_monitor(); + assert(has_monitor == (monitor != nullptr), + "Inconsistency between markWord and ObjectMonitorTable has_monitor: %s monitor: " PTR_FORMAT, + BOOL_TO_STR(has_monitor), p2i(monitor)); + } +#endif + } + + static ObjectMonitor* monitor_get(Thread* current, oop obj) { + ObjectMonitor* result = nullptr; + Lookup lookup_f(obj); + auto found_f = [&](ObjectMonitor** found) { + assert((*found)->object_peek() == obj, "must be"); + result = *found; + }; + _table->get(current, lookup_f, found_f); + verify_monitor_get_result(obj, result); + return result; + } + + static void try_notify_grow() { + if (!_table->is_max_size_reached() && !Atomic::load(&_resize)) { + Atomic::store(&_resize, true); + if (Service_lock->try_lock()) { + Service_lock->notify(); + Service_lock->unlock(); + } + } + } + + static bool should_shrink() { + // Not implemented; + return false; + } + + static constexpr double GROW_LOAD_FACTOR = 0.75; + + static bool should_grow() { + return get_load_factor() > GROW_LOAD_FACTOR && !_table->is_max_size_reached(); + } + + static bool should_resize() { + return should_grow() || should_shrink() || Atomic::load(&_resize); + } + + template + static bool run_task(JavaThread* current, Task& task, const char* task_name, Args&... args) { + if (task.prepare(current)) { + log_trace(monitortable)("Started to %s", task_name); + TraceTime timer(task_name, TRACETIME_LOG(Debug, monitortable, perf)); + while (task.do_task(current, args...)) { + task.pause(current); + { + ThreadBlockInVM tbivm(current); + } + task.cont(current); + } + task.done(current); + return true; + } + return false; + } + + static bool grow(JavaThread* current) { + ConcurrentTable::GrowTask grow_task(_table); + if (run_task(current, grow_task, "Grow")) { + _table_size = table_size(current); + log_info(monitortable)("Grown to size: %zu", _table_size); + return true; + } + return false; + } + + static bool clean(JavaThread* current) { + ConcurrentTable::BulkDeleteTask clean_task(_table); + auto is_dead = [&](ObjectMonitor** monitor) { + return (*monitor)->object_is_dead(); + }; + auto do_nothing = [&](ObjectMonitor** monitor) {}; + NativeHeapTrimmer::SuspendMark sm("ObjectMonitorTable"); + return run_task(current, clean_task, "Clean", is_dead, do_nothing); + } + + static bool resize(JavaThread* current) { + LogTarget(Info, monitortable) lt; + bool success = false; + + if (should_grow()) { + lt.print("Start growing with load factor %f", get_load_factor()); + success = grow(current); + } else { + if (!_table->is_max_size_reached() && Atomic::load(&_resize)) { + lt.print("WARNING: Getting resize hints with load factor %f", get_load_factor()); + } + lt.print("Start cleaning with load factor %f", get_load_factor()); + success = clean(current); + } + + Atomic::store(&_resize, false); + + return success; + } + + static ObjectMonitor* monitor_put_get(Thread* current, ObjectMonitor* monitor, oop obj) { + // Enter the monitor into the concurrent hashtable. + ObjectMonitor* result = monitor; + Lookup lookup_f(obj); + auto found_f = [&](ObjectMonitor** found) { + assert((*found)->object_peek() == obj, "must be"); + result = *found; + }; + bool grow; + _table->insert_get(current, lookup_f, monitor, found_f, &grow); + verify_monitor_get_result(obj, result); + if (grow) { + try_notify_grow(); + } + return result; + } + + static bool remove_monitor_entry(Thread* current, ObjectMonitor* monitor) { + LookupMonitor lookup_f(monitor); + return _table->remove(current, lookup_f); + } + + static bool contains_monitor(Thread* current, ObjectMonitor* monitor) { + LookupMonitor lookup_f(monitor); + bool result = false; + auto found_f = [&](ObjectMonitor** found) { + result = true; + }; + _table->get(current, lookup_f, found_f); + return result; + } + + static void print_on(outputStream* st) { + auto printer = [&] (ObjectMonitor** entry) { + ObjectMonitor* om = *entry; + oop obj = om->object_peek(); + st->print("monitor=" PTR_FORMAT ", ", p2i(om)); + st->print("object=" PTR_FORMAT, p2i(obj)); + assert(obj->mark().hash() == om->hash(), "hash must match"); + st->cr(); + return true; + }; + if (SafepointSynchronize::is_at_safepoint()) { + _table->do_safepoint_scan(printer); + } else { + _table->do_scan(Thread::current(), printer); + } + } +}; + +ObjectMonitorTable::ConcurrentTable* ObjectMonitorTable::_table = nullptr; +volatile size_t ObjectMonitorTable::_items_count = 0; +size_t ObjectMonitorTable::_table_size = 0; +volatile bool ObjectMonitorTable::_resize = false; + +ObjectMonitor* LightweightSynchronizer::get_or_insert_monitor_from_table(oop object, JavaThread* current, bool* inserted) { + assert(LockingMode == LM_LIGHTWEIGHT, "must be"); + + ObjectMonitor* monitor = get_monitor_from_table(current, object); + if (monitor != nullptr) { + *inserted = false; + return monitor; + } + + ObjectMonitor* alloced_monitor = new ObjectMonitor(object); + alloced_monitor->set_owner_anonymous(); + + // Try insert monitor + monitor = add_monitor(current, alloced_monitor, object); + + *inserted = alloced_monitor == monitor; + if (!*inserted) { + delete alloced_monitor; + } + + return monitor; +} + +static void log_inflate(Thread* current, oop object, ObjectSynchronizer::InflateCause cause) { + if (log_is_enabled(Trace, monitorinflation)) { + ResourceMark rm(current); + log_trace(monitorinflation)("inflate: object=" INTPTR_FORMAT ", mark=" + INTPTR_FORMAT ", type='%s' cause=%s", p2i(object), + object->mark().value(), object->klass()->external_name(), + ObjectSynchronizer::inflate_cause_name(cause)); + } +} + +static void post_monitor_inflate_event(EventJavaMonitorInflate* event, + const oop obj, + ObjectSynchronizer::InflateCause cause) { + assert(event != nullptr, "invariant"); + event->set_monitorClass(obj->klass()); + event->set_address((uintptr_t)(void*)obj); + event->set_cause((u1)cause); + event->commit(); +} + +ObjectMonitor* LightweightSynchronizer::get_or_insert_monitor(oop object, JavaThread* current, ObjectSynchronizer::InflateCause cause) { + assert(UseObjectMonitorTable, "must be"); + + EventJavaMonitorInflate event; + + bool inserted; + ObjectMonitor* monitor = get_or_insert_monitor_from_table(object, current, &inserted); + + if (inserted) { + // Hopefully the performance counters are allocated on distinct + // cache lines to avoid false sharing on MP systems ... + OM_PERFDATA_OP(Inflations, inc()); + log_inflate(current, object, cause); + if (event.should_commit()) { + post_monitor_inflate_event(&event, object, cause); + } + + // The monitor has an anonymous owner so it is safe from async deflation. + ObjectSynchronizer::_in_use_list.add(monitor); + } + + return monitor; +} + +// Add the hashcode to the monitor to match the object and put it in the hashtable. +ObjectMonitor* LightweightSynchronizer::add_monitor(JavaThread* current, ObjectMonitor* monitor, oop obj) { + assert(UseObjectMonitorTable, "must be"); + assert(obj == monitor->object(), "must be"); + + intptr_t hash = obj->mark().hash(); + assert(hash != 0, "must be set when claiming the object monitor"); + monitor->set_hash(hash); + + return ObjectMonitorTable::monitor_put_get(current, monitor, obj); +} + +bool LightweightSynchronizer::remove_monitor(Thread* current, ObjectMonitor* monitor, oop obj) { + assert(UseObjectMonitorTable, "must be"); + assert(monitor->object_peek() == obj, "must be, cleared objects are removed by is_dead"); + + return ObjectMonitorTable::remove_monitor_entry(current, monitor); +} + +void LightweightSynchronizer::deflate_mark_word(oop obj) { + assert(UseObjectMonitorTable, "must be"); + + markWord mark = obj->mark_acquire(); + assert(!mark.has_no_hash(), "obj with inflated monitor must have had a hash"); + + while (mark.has_monitor()) { + const markWord new_mark = mark.clear_lock_bits().set_unlocked(); + mark = obj->cas_set_mark(new_mark, mark); + } +} + +void LightweightSynchronizer::initialize() { + if (!UseObjectMonitorTable) { + return; + } + ObjectMonitorTable::create(); +} + +bool LightweightSynchronizer::needs_resize() { + if (!UseObjectMonitorTable) { + return false; + } + return ObjectMonitorTable::should_resize(); +} + +bool LightweightSynchronizer::resize_table(JavaThread* current) { + if (!UseObjectMonitorTable) { + return true; + } + return ObjectMonitorTable::resize(current); +} + +class LightweightSynchronizer::LockStackInflateContendedLocks : private OopClosure { + private: + oop _contended_oops[LockStack::CAPACITY]; + int _length; + + void do_oop(oop* o) final { + oop obj = *o; + if (obj->mark_acquire().has_monitor()) { + if (_length > 0 && _contended_oops[_length - 1] == obj) { + // Recursive + return; + } + _contended_oops[_length++] = obj; + } + } + + void do_oop(narrowOop* o) final { + ShouldNotReachHere(); + } + + public: + LockStackInflateContendedLocks() : + _contended_oops(), + _length(0) {}; + + void inflate(JavaThread* current) { + assert(current == JavaThread::current(), "must be"); + current->lock_stack().oops_do(this); + for (int i = 0; i < _length; i++) { + LightweightSynchronizer:: + inflate_fast_locked_object(_contended_oops[i], ObjectSynchronizer::inflate_cause_vm_internal, current, current); + } + } +}; + +void LightweightSynchronizer::ensure_lock_stack_space(JavaThread* current) { + assert(current == JavaThread::current(), "must be"); + LockStack& lock_stack = current->lock_stack(); + + // Make room on lock_stack + if (lock_stack.is_full()) { + // Inflate contended objects + LockStackInflateContendedLocks().inflate(current); + if (lock_stack.is_full()) { + // Inflate the oldest object + inflate_fast_locked_object(lock_stack.bottom(), ObjectSynchronizer::inflate_cause_vm_internal, current, current); + } + } +} + +class LightweightSynchronizer::CacheSetter : StackObj { + JavaThread* const _thread; + BasicLock* const _lock; + ObjectMonitor* _monitor; + + NONCOPYABLE(CacheSetter); + + public: + CacheSetter(JavaThread* thread, BasicLock* lock) : + _thread(thread), + _lock(lock), + _monitor(nullptr) {} + + ~CacheSetter() { + // Only use the cache if using the table. + if (UseObjectMonitorTable) { + if (_monitor != nullptr) { + _thread->om_set_monitor_cache(_monitor); + _lock->set_object_monitor_cache(_monitor); + } else { + _lock->clear_object_monitor_cache(); + } + } + } + + void set_monitor(ObjectMonitor* monitor) { + assert(_monitor == nullptr, "only set once"); + _monitor = monitor; + } + +}; + +class LightweightSynchronizer::VerifyThreadState { + bool _no_safepoint; + + public: + VerifyThreadState(JavaThread* locking_thread, JavaThread* current) : _no_safepoint(locking_thread != current) { + assert(current == Thread::current(), "must be"); + assert(locking_thread == current || locking_thread->is_obj_deopt_suspend(), "locking_thread may not run concurrently"); + if (_no_safepoint) { + DEBUG_ONLY(JavaThread::current()->inc_no_safepoint_count();) + } + } + ~VerifyThreadState() { + if (_no_safepoint){ + DEBUG_ONLY(JavaThread::current()->dec_no_safepoint_count();) + } + } +}; + +inline bool LightweightSynchronizer::fast_lock_try_enter(oop obj, LockStack& lock_stack, JavaThread* current) { + markWord mark = obj->mark(); + while (mark.is_unlocked()) { + ensure_lock_stack_space(current); + assert(!lock_stack.is_full(), "must have made room on the lock stack"); + assert(!lock_stack.contains(obj), "thread must not already hold the lock"); + // Try to swing into 'fast-locked' state. + markWord locked_mark = mark.set_fast_locked(); + markWord old_mark = mark; + mark = obj->cas_set_mark(locked_mark, old_mark); + if (old_mark == mark) { + // Successfully fast-locked, push object to lock-stack and return. + lock_stack.push(obj); + return true; + } + } + return false; +} + +bool LightweightSynchronizer::fast_lock_spin_enter(oop obj, LockStack& lock_stack, JavaThread* current, bool observed_deflation) { + assert(UseObjectMonitorTable, "must be"); + // Will spin with exponential backoff with an accumulative O(2^spin_limit) spins. + const int log_spin_limit = os::is_MP() ? LightweightFastLockingSpins : 1; + const int log_min_safepoint_check_interval = 10; + + markWord mark = obj->mark(); + const auto should_spin = [&]() { + if (!mark.has_monitor()) { + // Spin while not inflated. + return true; + } else if (observed_deflation) { + // Spin while monitor is being deflated. + ObjectMonitor* monitor = ObjectSynchronizer::read_monitor(current, obj, mark); + return monitor == nullptr || monitor->is_being_async_deflated(); + } + // Else stop spinning. + return false; + }; + // Always attempt to lock once even when safepoint synchronizing. + bool should_process = false; + for (int i = 0; should_spin() && !should_process && i < log_spin_limit; i++) { + // Spin with exponential backoff. + const int total_spin_count = 1 << i; + const int inner_spin_count = MIN2(1 << log_min_safepoint_check_interval, total_spin_count); + const int outer_spin_count = total_spin_count / inner_spin_count; + for (int outer = 0; outer < outer_spin_count; outer++) { + should_process = SafepointMechanism::should_process(current); + if (should_process) { + // Stop spinning for safepoint. + break; + } + for (int inner = 1; inner < inner_spin_count; inner++) { + SpinPause(); + } + } + + if (fast_lock_try_enter(obj, lock_stack, current)) return true; + } + return false; +} + +void LightweightSynchronizer::enter_for(Handle obj, BasicLock* lock, JavaThread* locking_thread) { + assert(LockingMode == LM_LIGHTWEIGHT, "must be"); + JavaThread* current = JavaThread::current(); + VerifyThreadState vts(locking_thread, current); + + if (obj->klass()->is_value_based()) { + ObjectSynchronizer::handle_sync_on_value_based_class(obj, locking_thread); + } + + locking_thread->inc_held_monitor_count(); + + CacheSetter cache_setter(locking_thread, lock); + + LockStack& lock_stack = locking_thread->lock_stack(); + + ObjectMonitor* monitor = nullptr; + if (lock_stack.contains(obj())) { + monitor = inflate_fast_locked_object(obj(), ObjectSynchronizer::inflate_cause_monitor_enter, locking_thread, current); + bool entered = monitor->enter_for(locking_thread); + assert(entered, "recursive ObjectMonitor::enter_for must succeed"); + } else { + // It is assumed that enter_for must enter on an object without contention. + monitor = inflate_and_enter(obj(), ObjectSynchronizer::inflate_cause_monitor_enter, locking_thread, current); + } + + assert(monitor != nullptr, "LightweightSynchronizer::enter_for must succeed"); + cache_setter.set_monitor(monitor); +} + +void LightweightSynchronizer::enter(Handle obj, BasicLock* lock, JavaThread* current) { + assert(LockingMode == LM_LIGHTWEIGHT, "must be"); + assert(current == JavaThread::current(), "must be"); + + if (obj->klass()->is_value_based()) { + ObjectSynchronizer::handle_sync_on_value_based_class(obj, current); + } + + current->inc_held_monitor_count(); + + CacheSetter cache_setter(current, lock); + + // Used when deflation is observed. Progress here requires progress + // from the deflator. After observing that the deflator is not + // making progress (after two yields), switch to sleeping. + SpinYield spin_yield(0, 2); + bool observed_deflation = false; + + LockStack& lock_stack = current->lock_stack(); + + if (!lock_stack.is_full() && lock_stack.try_recursive_enter(obj())) { + // Recursively fast locked + return; + } + + if (lock_stack.contains(obj())) { + ObjectMonitor* monitor = inflate_fast_locked_object(obj(), ObjectSynchronizer::inflate_cause_monitor_enter, current, current); + bool entered = monitor->enter(current); + assert(entered, "recursive ObjectMonitor::enter must succeed"); + cache_setter.set_monitor(monitor); + return; + } + + while (true) { + // Fast-locking does not use the 'lock' argument. + // Fast-lock spinning to avoid inflating for short critical sections. + // The goal is to only inflate when the extra cost of using ObjectMonitors + // is worth it. + // If deflation has been observed we also spin while deflation is ongoing. + if (fast_lock_try_enter(obj(), lock_stack, current)) { + return; + } else if (UseObjectMonitorTable && fast_lock_spin_enter(obj(), lock_stack, current, observed_deflation)) { + return; + } + + if (observed_deflation) { + spin_yield.wait(); + } + + ObjectMonitor* monitor = inflate_and_enter(obj(), ObjectSynchronizer::inflate_cause_monitor_enter, current, current); + if (monitor != nullptr) { + cache_setter.set_monitor(monitor); + return; + } + + // If inflate_and_enter returns nullptr it is because a deflated monitor + // was encountered. Fallback to fast locking. The deflater is responsible + // for clearing out the monitor and transitioning the markWord back to + // fast locking. + observed_deflation = true; + } +} + +void LightweightSynchronizer::exit(oop object, JavaThread* current) { + assert(LockingMode == LM_LIGHTWEIGHT, "must be"); + assert(current == Thread::current(), "must be"); + + markWord mark = object->mark(); + assert(!mark.is_unlocked(), "must be"); + + LockStack& lock_stack = current->lock_stack(); + if (mark.is_fast_locked()) { + if (lock_stack.try_recursive_exit(object)) { + // This is a recursive exit which succeeded + return; + } + if (lock_stack.is_recursive(object)) { + // Must inflate recursive locks if try_recursive_exit fails + // This happens for un-structured unlocks, could potentially + // fix try_recursive_exit to handle these. + inflate_fast_locked_object(object, ObjectSynchronizer::inflate_cause_vm_internal, current, current); + } + } + + while (mark.is_fast_locked()) { + markWord unlocked_mark = mark.set_unlocked(); + markWord old_mark = mark; + mark = object->cas_set_mark(unlocked_mark, old_mark); + if (old_mark == mark) { + // CAS successful, remove from lock_stack + size_t recursion = lock_stack.remove(object) - 1; + assert(recursion == 0, "Should not have unlocked here"); + return; + } + } + + assert(mark.has_monitor(), "must be"); + // The monitor exists + ObjectMonitor* monitor = ObjectSynchronizer::read_monitor(current, object, mark); + if (monitor->is_owner_anonymous()) { + assert(current->lock_stack().contains(object), "current must have object on its lock stack"); + monitor->set_owner_from_anonymous(current); + monitor->set_recursions(current->lock_stack().remove(object) - 1); + } + + monitor->exit(current); +} + +// LightweightSynchronizer::inflate_locked_or_imse is used to to get an inflated +// ObjectMonitor* with LM_LIGHTWEIGHT. It is used from contexts which require +// an inflated ObjectMonitor* for a monitor, and expects to throw a +// java.lang.IllegalMonitorStateException if it is not held by the current +// thread. Such as notify/wait and jni_exit. LM_LIGHTWEIGHT keeps it invariant +// that it only inflates if it is already locked by the current thread or the +// current thread is in the process of entering. To maintain this invariant we +// need to throw a java.lang.IllegalMonitorStateException before inflating if +// the current thread is not the owner. +// LightweightSynchronizer::inflate_locked_or_imse facilitates this. +ObjectMonitor* LightweightSynchronizer::inflate_locked_or_imse(oop obj, ObjectSynchronizer::InflateCause cause, TRAPS) { + assert(LockingMode == LM_LIGHTWEIGHT, "must be"); + JavaThread* current = THREAD; + + for (;;) { + markWord mark = obj->mark_acquire(); + if (mark.is_unlocked()) { + // No lock, IMSE. + THROW_MSG_(vmSymbols::java_lang_IllegalMonitorStateException(), + "current thread is not owner", nullptr); + } + + if (mark.is_fast_locked()) { + if (!current->lock_stack().contains(obj)) { + // Fast locked by other thread, IMSE. + THROW_MSG_(vmSymbols::java_lang_IllegalMonitorStateException(), + "current thread is not owner", nullptr); + } else { + // Current thread owns the lock, must inflate + return inflate_fast_locked_object(obj, cause, current, current); + } + } + + assert(mark.has_monitor(), "must be"); + ObjectMonitor* monitor = ObjectSynchronizer::read_monitor(current, obj, mark); + if (monitor != nullptr) { + if (monitor->is_owner_anonymous()) { + LockStack& lock_stack = current->lock_stack(); + if (lock_stack.contains(obj)) { + // Current thread owns the lock but someone else inflated it. + // Fix owner and pop lock stack. + monitor->set_owner_from_anonymous(current); + monitor->set_recursions(lock_stack.remove(obj) - 1); + } else { + // Fast locked (and inflated) by other thread, or deflation in progress, IMSE. + THROW_MSG_(vmSymbols::java_lang_IllegalMonitorStateException(), + "current thread is not owner", nullptr); + } + } + return monitor; + } + } +} + +ObjectMonitor* LightweightSynchronizer::inflate_into_object_header(oop object, ObjectSynchronizer::InflateCause cause, JavaThread* inflating_thread, Thread* current) { + + // The JavaThread* inflating_thread parameter is only used by LM_LIGHTWEIGHT and requires + // that the inflating_thread == Thread::current() or is suspended throughout the call by + // some other mechanism. + // Even with LM_LIGHTWEIGHT the thread might be nullptr when called from a non + // JavaThread. (As may still be the case from FastHashCode). However it is only + // important for the correctness of the LM_LIGHTWEIGHT algorithm that the thread + // is set when called from ObjectSynchronizer::enter from the owning thread, + // ObjectSynchronizer::enter_for from any thread, or ObjectSynchronizer::exit. + EventJavaMonitorInflate event; + + for (;;) { + const markWord mark = object->mark_acquire(); + + // The mark can be in one of the following states: + // * inflated - Just return if using stack-locking. + // If using fast-locking and the ObjectMonitor owner + // is anonymous and the inflating_thread owns the + // object lock, then we make the inflating_thread + // the ObjectMonitor owner and remove the lock from + // the inflating_thread's lock stack. + // * fast-locked - Coerce it to inflated from fast-locked. + // * unlocked - Aggressively inflate the object. + + // CASE: inflated + if (mark.has_monitor()) { + ObjectMonitor* inf = mark.monitor(); + markWord dmw = inf->header(); + assert(dmw.is_neutral(), "invariant: header=" INTPTR_FORMAT, dmw.value()); + if (inf->is_owner_anonymous() && + inflating_thread != nullptr && inflating_thread->lock_stack().contains(object)) { + inf->set_owner_from_anonymous(inflating_thread); + size_t removed = inflating_thread->lock_stack().remove(object); + inf->set_recursions(removed - 1); + } + return inf; + } + + // CASE: fast-locked + // Could be fast-locked either by the inflating_thread or by some other thread. + // + // Note that we allocate the ObjectMonitor speculatively, _before_ + // attempting to set the object's mark to the new ObjectMonitor. If + // the inflating_thread owns the monitor, then we set the ObjectMonitor's + // owner to the inflating_thread. Otherwise, we set the ObjectMonitor's owner + // to anonymous. If we lose the race to set the object's mark to the + // new ObjectMonitor, then we just delete it and loop around again. + // + if (mark.is_fast_locked()) { + ObjectMonitor* monitor = new ObjectMonitor(object); + monitor->set_header(mark.set_unlocked()); + bool own = inflating_thread != nullptr && inflating_thread->lock_stack().contains(object); + if (own) { + // Owned by inflating_thread. + monitor->set_owner_from(nullptr, inflating_thread); + } else { + // Owned by somebody else. + monitor->set_owner_anonymous(); + } + markWord monitor_mark = markWord::encode(monitor); + markWord old_mark = object->cas_set_mark(monitor_mark, mark); + if (old_mark == mark) { + // Success! Return inflated monitor. + if (own) { + size_t removed = inflating_thread->lock_stack().remove(object); + monitor->set_recursions(removed - 1); + } + // Once the ObjectMonitor is configured and object is associated + // with the ObjectMonitor, it is safe to allow async deflation: + ObjectSynchronizer::_in_use_list.add(monitor); + + // Hopefully the performance counters are allocated on distinct + // cache lines to avoid false sharing on MP systems ... + OM_PERFDATA_OP(Inflations, inc()); + log_inflate(current, object, cause); + if (event.should_commit()) { + post_monitor_inflate_event(&event, object, cause); + } + return monitor; + } else { + delete monitor; + continue; // Interference -- just retry + } + } + + // CASE: unlocked + // TODO-FIXME: for entry we currently inflate and then try to CAS _owner. + // If we know we're inflating for entry it's better to inflate by swinging a + // pre-locked ObjectMonitor pointer into the object header. A successful + // CAS inflates the object *and* confers ownership to the inflating thread. + // In the current implementation we use a 2-step mechanism where we CAS() + // to inflate and then CAS() again to try to swing _owner from null to current. + // An inflateTry() method that we could call from enter() would be useful. + + assert(mark.is_unlocked(), "invariant: header=" INTPTR_FORMAT, mark.value()); + ObjectMonitor* m = new ObjectMonitor(object); + // prepare m for installation - set monitor to initial state + m->set_header(mark); + + if (object->cas_set_mark(markWord::encode(m), mark) != mark) { + delete m; + m = nullptr; + continue; + // interference - the markword changed - just retry. + // The state-transitions are one-way, so there's no chance of + // live-lock -- "Inflated" is an absorbing state. + } + + // Once the ObjectMonitor is configured and object is associated + // with the ObjectMonitor, it is safe to allow async deflation: + ObjectSynchronizer::_in_use_list.add(m); + + // Hopefully the performance counters are allocated on distinct + // cache lines to avoid false sharing on MP systems ... + OM_PERFDATA_OP(Inflations, inc()); + log_inflate(current, object, cause); + if (event.should_commit()) { + post_monitor_inflate_event(&event, object, cause); + } + return m; + } +} + +ObjectMonitor* LightweightSynchronizer::inflate_fast_locked_object(oop object, ObjectSynchronizer::InflateCause cause, JavaThread* locking_thread, JavaThread* current) { + assert(LockingMode == LM_LIGHTWEIGHT, "only used for lightweight"); + VerifyThreadState vts(locking_thread, current); + assert(locking_thread->lock_stack().contains(object), "locking_thread must have object on its lock stack"); + + ObjectMonitor* monitor; + + if (!UseObjectMonitorTable) { + return inflate_into_object_header(object, cause, locking_thread, current); + } + + // Inflating requires a hash code + ObjectSynchronizer::FastHashCode(current, object); + + markWord mark = object->mark_acquire(); + assert(!mark.is_unlocked(), "Cannot be unlocked"); + + for (;;) { + // Fetch the monitor from the table + monitor = get_or_insert_monitor(object, current, cause); + + // ObjectMonitors are always inserted as anonymously owned, this thread is + // the current holder of the monitor. So unless the entry is stale and + // contains a deflating monitor it must be anonymously owned. + if (monitor->is_owner_anonymous()) { + // The monitor must be anonymously owned if it was added + assert(monitor == get_monitor_from_table(current, object), "The monitor must be found"); + // New fresh monitor + break; + } + + // If the monitor was not anonymously owned then we got a deflating monitor + // from the table. We need to let the deflator make progress and remove this + // entry before we are allowed to add a new one. + os::naked_yield(); + assert(monitor->is_being_async_deflated(), "Should be the reason"); + } + + // Set the mark word; loop to handle concurrent updates to other parts of the mark word + while (mark.is_fast_locked()) { + mark = object->cas_set_mark(mark.set_has_monitor(), mark); + } + + // Indicate that the monitor now has a known owner + monitor->set_owner_from_anonymous(locking_thread); + + // Remove the entry from the thread's lock stack + monitor->set_recursions(locking_thread->lock_stack().remove(object) - 1); + + if (locking_thread == current) { + // Only change the thread local state of the current thread. + locking_thread->om_set_monitor_cache(monitor); + } + + return monitor; +} + +ObjectMonitor* LightweightSynchronizer::inflate_and_enter(oop object, ObjectSynchronizer::InflateCause cause, JavaThread* locking_thread, JavaThread* current) { + assert(LockingMode == LM_LIGHTWEIGHT, "only used for lightweight"); + VerifyThreadState vts(locking_thread, current); + + // Note: In some paths (deoptimization) the 'current' thread inflates and + // enters the lock on behalf of the 'locking_thread' thread. + + ObjectMonitor* monitor = nullptr; + + if (!UseObjectMonitorTable) { + // Do the old inflate and enter. + monitor = inflate_into_object_header(object, cause, locking_thread, current); + + bool entered; + if (locking_thread == current) { + entered = monitor->enter(locking_thread); + } else { + entered = monitor->enter_for(locking_thread); + } + + // enter returns false for deflation found. + return entered ? monitor : nullptr; + } + + NoSafepointVerifier nsv; + + // Lightweight monitors require that hash codes are installed first + ObjectSynchronizer::FastHashCode(locking_thread, object); + + // Try to get the monitor from the thread-local cache. + // There's no need to use the cache if we are locking + // on behalf of another thread. + if (current == locking_thread) { + monitor = current->om_get_from_monitor_cache(object); + } + + // Get or create the monitor + if (monitor == nullptr) { + monitor = get_or_insert_monitor(object, current, cause); + } + + if (monitor->try_enter(locking_thread)) { + return monitor; + } + + // Holds is_being_async_deflated() stable throughout this function. + ObjectMonitorContentionMark contention_mark(monitor); + + /// First handle the case where the monitor from the table is deflated + if (monitor->is_being_async_deflated()) { + // The MonitorDeflation thread is deflating the monitor. The locking thread + // must spin until further progress has been made. + + const markWord mark = object->mark_acquire(); + + if (mark.has_monitor()) { + // Waiting on the deflation thread to remove the deflated monitor from the table. + os::naked_yield(); + + } else if (mark.is_fast_locked()) { + // Some other thread managed to fast-lock the lock, or this is a + // recursive lock from the same thread; yield for the deflation + // thread to remove the deflated monitor from the table. + os::naked_yield(); + + } else { + assert(mark.is_unlocked(), "Implied"); + // Retry immediately + } + + // Retry + return nullptr; + } + + for (;;) { + const markWord mark = object->mark_acquire(); + // The mark can be in one of the following states: + // * inflated - If the ObjectMonitor owner is anonymous + // and the locking_thread owns the object + // lock, then we make the locking_thread + // the ObjectMonitor owner and remove the + // lock from the locking_thread's lock stack. + // * fast-locked - Coerce it to inflated from fast-locked. + // * neutral - Inflate the object. Successful CAS is locked + + // CASE: inflated + if (mark.has_monitor()) { + LockStack& lock_stack = locking_thread->lock_stack(); + if (monitor->is_owner_anonymous() && lock_stack.contains(object)) { + // The lock is fast-locked by the locking thread, + // convert it to a held monitor with a known owner. + monitor->set_owner_from_anonymous(locking_thread); + monitor->set_recursions(lock_stack.remove(object) - 1); + } + + break; // Success + } + + // CASE: fast-locked + // Could be fast-locked either by locking_thread or by some other thread. + // + if (mark.is_fast_locked()) { + markWord old_mark = object->cas_set_mark(mark.set_has_monitor(), mark); + if (old_mark != mark) { + // CAS failed + continue; + } + + // Success! Return inflated monitor. + LockStack& lock_stack = locking_thread->lock_stack(); + if (lock_stack.contains(object)) { + // The lock is fast-locked by the locking thread, + // convert it to a held monitor with a known owner. + monitor->set_owner_from_anonymous(locking_thread); + monitor->set_recursions(lock_stack.remove(object) - 1); + } + + break; // Success + } + + // CASE: neutral (unlocked) + + // Catch if the object's header is not neutral (not locked and + // not marked is what we care about here). + assert(mark.is_neutral(), "invariant: header=" INTPTR_FORMAT, mark.value()); + markWord old_mark = object->cas_set_mark(mark.set_has_monitor(), mark); + if (old_mark != mark) { + // CAS failed + continue; + } + + // Transitioned from unlocked to monitor means locking_thread owns the lock. + monitor->set_owner_from_anonymous(locking_thread); + + return monitor; + } + + if (current == locking_thread) { + // One round of spinning + if (monitor->spin_enter(locking_thread)) { + return monitor; + } + + // Monitor is contended, take the time before entering to fix the lock stack. + LockStackInflateContendedLocks().inflate(current); + } + + // enter can block for safepoints; clear the unhandled object oop + PauseNoSafepointVerifier pnsv(&nsv); + object = nullptr; + + if (current == locking_thread) { + monitor->enter_with_contention_mark(locking_thread, contention_mark); + } else { + monitor->enter_for_with_contention_mark(locking_thread, contention_mark); + } + + return monitor; +} + +void LightweightSynchronizer::deflate_monitor(Thread* current, oop obj, ObjectMonitor* monitor) { + if (obj != nullptr) { + deflate_mark_word(obj); + } + bool removed = remove_monitor(current, monitor, obj); + if (obj != nullptr) { + assert(removed, "Should have removed the entry if obj was alive"); + } +} + +ObjectMonitor* LightweightSynchronizer::get_monitor_from_table(Thread* current, oop obj) { + assert(UseObjectMonitorTable, "must be"); + return ObjectMonitorTable::monitor_get(current, obj); +} + +bool LightweightSynchronizer::contains_monitor(Thread* current, ObjectMonitor* monitor) { + assert(UseObjectMonitorTable, "must be"); + return ObjectMonitorTable::contains_monitor(current, monitor); +} + +bool LightweightSynchronizer::quick_enter(oop obj, BasicLock* lock, JavaThread* current) { + assert(current->thread_state() == _thread_in_Java, "must be"); + assert(obj != nullptr, "must be"); + NoSafepointVerifier nsv; + + // If quick_enter succeeds with entering, the cache should be in a valid initialized state. + CacheSetter cache_setter(current, lock); + + LockStack& lock_stack = current->lock_stack(); + if (lock_stack.is_full()) { + // Always go into runtime if the lock stack is full. + return false; + } + + const markWord mark = obj->mark(); + +#ifndef _LP64 + // Only for 32bit which has limited support for fast locking outside the runtime. + if (lock_stack.try_recursive_enter(obj)) { + // Recursive lock successful. + current->inc_held_monitor_count(); + return true; + } + + if (mark.is_unlocked()) { + markWord locked_mark = mark.set_fast_locked(); + if (obj->cas_set_mark(locked_mark, mark) == mark) { + // Successfully fast-locked, push object to lock-stack and return. + lock_stack.push(obj); + current->inc_held_monitor_count(); + return true; + } + } +#endif + + if (mark.has_monitor()) { + ObjectMonitor* const monitor = UseObjectMonitorTable ? current->om_get_from_monitor_cache(obj) : + ObjectSynchronizer::read_monitor(mark); + + if (monitor == nullptr) { + // Take the slow-path on a cache miss. + return false; + } + + if (monitor->try_enter(current)) { + // ObjectMonitor enter successful. + cache_setter.set_monitor(monitor); + current->inc_held_monitor_count(); + return true; + } + } + + // Slow-path. + return false; +} diff --git a/src/hotspot/share/runtime/lightweightSynchronizer.hpp b/src/hotspot/share/runtime/lightweightSynchronizer.hpp new file mode 100644 index 0000000000000..c546988f7782e --- /dev/null +++ b/src/hotspot/share/runtime/lightweightSynchronizer.hpp @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_RUNTIME_LIGHTWEIGHTSYNCHRONIZER_HPP +#define SHARE_RUNTIME_LIGHTWEIGHTSYNCHRONIZER_HPP + +#include "memory/allStatic.hpp" +#include "runtime/javaThread.hpp" +#include "runtime/objectMonitor.hpp" +#include "runtime/synchronizer.hpp" + +class ObjectMonitorTable; + +class LightweightSynchronizer : AllStatic { + private: + static ObjectMonitor* get_or_insert_monitor_from_table(oop object, JavaThread* current, bool* inserted); + static ObjectMonitor* get_or_insert_monitor(oop object, JavaThread* current, ObjectSynchronizer::InflateCause cause); + + static ObjectMonitor* add_monitor(JavaThread* current, ObjectMonitor* monitor, oop obj); + static bool remove_monitor(Thread* current, ObjectMonitor* monitor, oop obj); + + static void deflate_mark_word(oop object); + + static void ensure_lock_stack_space(JavaThread* current); + + class CacheSetter; + class LockStackInflateContendedLocks; + class VerifyThreadState; + + public: + static void initialize(); + + static bool needs_resize(); + static bool resize_table(JavaThread* current); + + private: + static inline bool fast_lock_try_enter(oop obj, LockStack& lock_stack, JavaThread* current); + static bool fast_lock_spin_enter(oop obj, LockStack& lock_stack, JavaThread* current, bool observed_deflation); + + public: + static void enter_for(Handle obj, BasicLock* lock, JavaThread* locking_thread); + static void enter(Handle obj, BasicLock* lock, JavaThread* current); + static void exit(oop object, JavaThread* current); + + static ObjectMonitor* inflate_into_object_header(oop object, ObjectSynchronizer::InflateCause cause, JavaThread* inflating_thread, Thread* current); + static ObjectMonitor* inflate_locked_or_imse(oop object, ObjectSynchronizer::InflateCause cause, TRAPS); + static ObjectMonitor* inflate_fast_locked_object(oop object, ObjectSynchronizer::InflateCause cause, JavaThread* locking_thread, JavaThread* current); + static ObjectMonitor* inflate_and_enter(oop object, ObjectSynchronizer::InflateCause cause, JavaThread* locking_thread, JavaThread* current); + + static void deflate_monitor(Thread* current, oop obj, ObjectMonitor* monitor); + + static ObjectMonitor* get_monitor_from_table(Thread* current, oop obj); + + static bool contains_monitor(Thread* current, ObjectMonitor* monitor); + + static bool quick_enter(oop obj, BasicLock* Lock, JavaThread* current); +}; + +#endif // SHARE_RUNTIME_LIGHTWEIGHTSYNCHRONIZER_HPP diff --git a/src/hotspot/share/runtime/lockStack.cpp b/src/hotspot/share/runtime/lockStack.cpp index 2f783c97c998c..185fc931b67b2 100644 --- a/src/hotspot/share/runtime/lockStack.cpp +++ b/src/hotspot/share/runtime/lockStack.cpp @@ -29,17 +29,20 @@ #include "oops/markWord.hpp" #include "oops/oop.inline.hpp" #include "runtime/globals.hpp" +#include "runtime/javaThread.inline.hpp" #include "runtime/lockStack.inline.hpp" #include "runtime/objectMonitor.inline.hpp" #include "runtime/safepoint.hpp" #include "runtime/stackWatermark.hpp" #include "runtime/stackWatermarkSet.inline.hpp" +#include "runtime/synchronizer.inline.hpp" #include "runtime/thread.hpp" #include "utilities/copy.hpp" #include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/growableArray.hpp" #include "utilities/ostream.hpp" +#include "utilities/sizes.hpp" #include @@ -114,3 +117,11 @@ void LockStack::print_on(outputStream* st) { } } } + +OMCache::OMCache(JavaThread* jt) : _entries() { + STATIC_ASSERT(std::is_standard_layout::value); + STATIC_ASSERT(std::is_standard_layout::value); + STATIC_ASSERT(offsetof(OMCache, _null_sentinel) == offsetof(OMCache, _entries) + + offsetof(OMCache::OMCacheEntry, _oop) + + OMCache::CAPACITY * in_bytes(oop_to_oop_difference())); +} diff --git a/src/hotspot/share/runtime/lockStack.hpp b/src/hotspot/share/runtime/lockStack.hpp index 064f70a37fbba..de32eb4125975 100644 --- a/src/hotspot/share/runtime/lockStack.hpp +++ b/src/hotspot/share/runtime/lockStack.hpp @@ -32,18 +32,20 @@ #include "utilities/sizes.hpp" class JavaThread; +class ObjectMonitor; class OopClosure; class outputStream; template class GrowableArray; +class Thread; class LockStack { friend class LockStackTest; friend class VMStructs; JVMCI_ONLY(friend class JVMCIVMStructs;) -public: + public: static const int CAPACITY = 8; -private: + private: // TODO: It would be very useful if JavaThread::lock_stack_offset() and friends were constexpr, // but this is currently not the case because we're using offset_of() which is non-constexpr, @@ -73,7 +75,7 @@ class LockStack { // Given an offset (in bytes) calculate the index into the lock-stack. static inline int to_index(uint32_t offset); -public: + public: static ByteSize top_offset() { return byte_offset_of(LockStack, _top); } static ByteSize base_offset() { return byte_offset_of(LockStack, _base); } @@ -123,4 +125,29 @@ class LockStack { void print_on(outputStream* st); }; +class OMCache { + friend class VMStructs; + public: + static constexpr int CAPACITY = 8; + + private: + struct OMCacheEntry { + oop _oop = nullptr; + ObjectMonitor* _monitor = nullptr; + } _entries[CAPACITY]; + const oop _null_sentinel = nullptr; + + public: + static ByteSize entries_offset() { return byte_offset_of(OMCache, _entries); } + static constexpr ByteSize oop_to_oop_difference() { return in_ByteSize(sizeof(OMCacheEntry)); } + static constexpr ByteSize oop_to_monitor_difference() { return in_ByteSize(sizeof(oop)); } + + explicit OMCache(JavaThread* jt); + + inline ObjectMonitor* get_monitor(oop o); + inline void set_monitor(ObjectMonitor* monitor); + inline void clear(); + +}; + #endif // SHARE_RUNTIME_LOCKSTACK_HPP diff --git a/src/hotspot/share/runtime/lockStack.inline.hpp b/src/hotspot/share/runtime/lockStack.inline.hpp index 7a9874a9291d5..515ca94c741e0 100644 --- a/src/hotspot/share/runtime/lockStack.inline.hpp +++ b/src/hotspot/share/runtime/lockStack.inline.hpp @@ -31,6 +31,8 @@ #include "memory/iterator.hpp" #include "runtime/javaThread.hpp" +#include "runtime/lightweightSynchronizer.hpp" +#include "runtime/objectMonitor.inline.hpp" #include "runtime/safepoint.hpp" #include "runtime/stackWatermark.hpp" #include "runtime/stackWatermarkSet.inline.hpp" @@ -222,4 +224,54 @@ inline void LockStack::oops_do(OopClosure* cl) { verify("post-oops-do"); } +inline void OMCache::set_monitor(ObjectMonitor *monitor) { + const int end = OMCache::CAPACITY - 1; + + oop obj = monitor->object_peek(); + assert(obj != nullptr, "must be alive"); + assert(monitor == LightweightSynchronizer::get_monitor_from_table(JavaThread::current(), obj), "must exist in table"); + + OMCacheEntry to_insert = {obj, monitor}; + + for (int i = 0; i < end; ++i) { + if (_entries[i]._oop == obj || + _entries[i]._monitor == nullptr || + _entries[i]._monitor->is_being_async_deflated()) { + // Use stale slot. + _entries[i] = to_insert; + return; + } + // Swap with the most recent value. + ::swap(to_insert, _entries[i]); + } + _entries[end] = to_insert; +} + +inline ObjectMonitor* OMCache::get_monitor(oop o) { + for (int i = 0; i < CAPACITY; ++i) { + if (_entries[i]._oop == o) { + assert(_entries[i]._monitor != nullptr, "monitor must exist"); + if (_entries[i]._monitor->is_being_async_deflated()) { + // Bad monitor + // Shift down rest + for (; i < CAPACITY - 1; ++i) { + _entries[i] = _entries[i + 1]; + } + // Clear end + _entries[i] = {}; + return nullptr; + } + return _entries[i]._monitor; + } + } + return nullptr; +} + +inline void OMCache::clear() { + for (size_t i = 0; i < CAPACITY; ++i) { + // Clear + _entries[i] = {}; + } +} + #endif // SHARE_RUNTIME_LOCKSTACK_INLINE_HPP diff --git a/src/hotspot/share/runtime/objectMonitor.cpp b/src/hotspot/share/runtime/objectMonitor.cpp index c509ed691cdb8..367d79a5283db 100644 --- a/src/hotspot/share/runtime/objectMonitor.cpp +++ b/src/hotspot/share/runtime/objectMonitor.cpp @@ -43,6 +43,7 @@ #include "runtime/handles.inline.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/javaThread.inline.hpp" +#include "runtime/lightweightSynchronizer.hpp" #include "runtime/mutexLocker.hpp" #include "runtime/objectMonitor.hpp" #include "runtime/objectMonitor.inline.hpp" @@ -53,6 +54,7 @@ #include "runtime/safepointMechanism.inline.hpp" #include "runtime/sharedRuntime.hpp" #include "services/threadService.hpp" +#include "utilities/debug.hpp" #include "utilities/dtrace.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" @@ -246,7 +248,7 @@ static void check_object_context() { } ObjectMonitor::ObjectMonitor(oop object) : - _header(markWord::zero()), + _metadata(0), _object(_oop_storage, object), _owner(nullptr), _previous_owner_tid(0), @@ -272,10 +274,6 @@ oop ObjectMonitor::object() const { return _object.resolve(); } -oop ObjectMonitor::object_peek() const { - return _object.peek(); -} - void ObjectMonitor::ExitOnSuspend::operator()(JavaThread* current) { if (current->is_suspended()) { _om->_recursions = 0; @@ -297,109 +295,147 @@ void ObjectMonitor::ClearSuccOnSuspend::operator()(JavaThread* current) { } } +#define assert_mark_word_consistency() \ + assert(UseObjectMonitorTable || object()->mark() == markWord::encode(this), \ + "object mark must match encoded this: mark=" INTPTR_FORMAT \ + ", encoded this=" INTPTR_FORMAT, object()->mark().value(), \ + markWord::encode(this).value()); + // ----------------------------------------------------------------------------- // Enter support -bool ObjectMonitor::enter_for(JavaThread* locking_thread) { +bool ObjectMonitor::enter_is_async_deflating() { + if (is_being_async_deflated()) { + if (!UseObjectMonitorTable) { + const oop l_object = object(); + if (l_object != nullptr) { + // Attempt to restore the header/dmw to the object's header so that + // we only retry once if the deflater thread happens to be slow. + install_displaced_markword_in_object(l_object); + } + } + return true; + } + + return false; +} + +void ObjectMonitor::enter_for_with_contention_mark(JavaThread* locking_thread, ObjectMonitorContentionMark& contention_mark) { // Used by ObjectSynchronizer::enter_for to enter for another thread. // The monitor is private to or already owned by locking_thread which must be suspended. // So this code may only contend with deflation. assert(locking_thread == Thread::current() || locking_thread->is_obj_deopt_suspend(), "must be"); + assert(contention_mark._monitor == this, "must be"); + assert(!is_being_async_deflated(), "must be"); - // Block out deflation as soon as possible. - add_to_contentions(1); + + void* prev_owner = try_set_owner_from(nullptr, locking_thread); bool success = false; - if (!is_being_async_deflated()) { - void* prev_owner = try_set_owner_from(nullptr, locking_thread); - if (prev_owner == nullptr) { - assert(_recursions == 0, "invariant"); - success = true; - } else if (prev_owner == locking_thread) { - _recursions++; - success = true; - } else if (prev_owner == DEFLATER_MARKER) { - // Racing with deflation. - prev_owner = try_set_owner_from(DEFLATER_MARKER, locking_thread); - if (prev_owner == DEFLATER_MARKER) { - // Cancelled deflation. Increment contentions as part of the deflation protocol. - add_to_contentions(1); - success = true; - } else if (prev_owner == nullptr) { - // At this point we cannot race with deflation as we have both incremented - // contentions, seen contention > 0 and seen a DEFLATER_MARKER. - // success will only be false if this races with something other than - // deflation. - prev_owner = try_set_owner_from(nullptr, locking_thread); - success = prev_owner == nullptr; - } - } else if (LockingMode == LM_LEGACY && locking_thread->is_lock_owned((address)prev_owner)) { - assert(_recursions == 0, "must be"); - _recursions = 1; - set_owner_from_BasicLock(prev_owner, locking_thread); + if (prev_owner == nullptr) { + assert(_recursions == 0, "invariant"); + success = true; + } else if (prev_owner == locking_thread) { + _recursions++; + success = true; + } else if (prev_owner == DEFLATER_MARKER) { + // Racing with deflation. + prev_owner = try_set_owner_from(DEFLATER_MARKER, locking_thread); + if (prev_owner == DEFLATER_MARKER) { + // Cancelled deflation. Increment contentions as part of the deflation protocol. + add_to_contentions(1); success = true; + } else if (prev_owner == nullptr) { + // At this point we cannot race with deflation as we have both incremented + // contentions, seen contention > 0 and seen a DEFLATER_MARKER. + // success will only be false if this races with something other than + // deflation. + prev_owner = try_set_owner_from(nullptr, locking_thread); + success = prev_owner == nullptr; } - assert(success, "Failed to enter_for: locking_thread=" INTPTR_FORMAT - ", this=" INTPTR_FORMAT "{owner=" INTPTR_FORMAT "}, observed owner: " INTPTR_FORMAT, - p2i(locking_thread), p2i(this), p2i(owner_raw()), p2i(prev_owner)); - } else { - // Async deflation is in progress and our contentions increment - // above lost the race to async deflation. Undo the work and - // force the caller to retry. - const oop l_object = object(); - if (l_object != nullptr) { - // Attempt to restore the header/dmw to the object's header so that - // we only retry once if the deflater thread happens to be slow. - install_displaced_markword_in_object(l_object); - } + } else if (LockingMode == LM_LEGACY && locking_thread->is_lock_owned((address)prev_owner)) { + assert(_recursions == 0, "must be"); + _recursions = 1; + set_owner_from_BasicLock(prev_owner, locking_thread); + success = true; } + assert(success, "Failed to enter_for: locking_thread=" INTPTR_FORMAT + ", this=" INTPTR_FORMAT "{owner=" INTPTR_FORMAT "}, observed owner: " INTPTR_FORMAT, + p2i(locking_thread), p2i(this), p2i(owner_raw()), p2i(prev_owner)); +} + +bool ObjectMonitor::enter_for(JavaThread* locking_thread) { - add_to_contentions(-1); + // Block out deflation as soon as possible. + ObjectMonitorContentionMark contention_mark(this); - assert(!success || owner_raw() == locking_thread, "must be"); + // Check for deflation. + if (enter_is_async_deflating()) { + return false; + } - return success; + enter_for_with_contention_mark(locking_thread, contention_mark); + assert(owner_raw() == locking_thread, "must be"); + return true; } -bool ObjectMonitor::enter(JavaThread* current) { - assert(current == JavaThread::current(), "must be"); - // The following code is ordered to check the most common cases first - // and to reduce RTS->RTO cache line upgrades on SPARC and IA32 processors. - - void* cur = try_set_owner_from(nullptr, current); - if (cur == nullptr) { +bool ObjectMonitor::try_enter(JavaThread* current) { + // TryLock avoids the CAS + TryLockResult r = TryLock(current); + if (r == TryLockResult::Success) { assert(_recursions == 0, "invariant"); return true; } - if (cur == current) { - // TODO-FIXME: check for integer overflow! BUGID 6557169. + if (r == TryLockResult::HasOwner && owner() == current) { _recursions++; return true; } - if (LockingMode != LM_LIGHTWEIGHT && current->is_lock_owned((address)cur)) { + void* cur = owner_raw(); + if (LockingMode == LM_LEGACY && current->is_lock_owned((address)cur)) { assert(_recursions == 0, "internal state error"); _recursions = 1; set_owner_from_BasicLock(cur, current); // Convert from BasicLock* to Thread*. return true; } + return false; +} + +bool ObjectMonitor::spin_enter(JavaThread* current) { + assert(current == JavaThread::current(), "must be"); + + // Check for recursion. + if (try_enter(current)) { + return true; + } + + // Check for deflation. + if (enter_is_async_deflating()) { + return false; + } + // We've encountered genuine contention. - // Try one round of spinning *before* enqueueing current - // and before going through the awkward and expensive state - // transitions. The following spin is strictly optional ... + // Do one round of spinning. // Note that if we acquire the monitor from an initial spin // we forgo posting JVMTI events and firing DTRACE probes. if (TrySpin(current)) { assert(owner_raw() == current, "must be current: owner=" INTPTR_FORMAT, p2i(owner_raw())); assert(_recursions == 0, "must be 0: recursions=" INTX_FORMAT, _recursions); - assert(object()->mark() == markWord::encode(this), - "object mark must match encoded this: mark=" INTPTR_FORMAT - ", encoded this=" INTPTR_FORMAT, object()->mark().value(), - markWord::encode(this).value()); + assert_mark_word_consistency(); + return true; + } + + return false; +} + +bool ObjectMonitor::enter(JavaThread* current) { + assert(current == JavaThread::current(), "must be"); + + if (spin_enter(current)) { return true; } @@ -408,22 +444,25 @@ bool ObjectMonitor::enter(JavaThread* current) { assert(!SafepointSynchronize::is_at_safepoint(), "invariant"); assert(current->thread_state() != _thread_blocked, "invariant"); - // Keep track of contention for JVM/TI and M&M queries. - add_to_contentions(1); - if (is_being_async_deflated()) { - // Async deflation is in progress and our contentions increment - // above lost the race to async deflation. Undo the work and - // force the caller to retry. - const oop l_object = object(); - if (l_object != nullptr) { - // Attempt to restore the header/dmw to the object's header so that - // we only retry once if the deflater thread happens to be slow. - install_displaced_markword_in_object(l_object); - } - add_to_contentions(-1); + // Keep is_being_async_deflated stable across the rest of enter + ObjectMonitorContentionMark contention_mark(this); + + // Check for deflation. + if (enter_is_async_deflating()) { return false; } + // At this point this ObjectMonitor cannot be deflated, finish contended enter + enter_with_contention_mark(current, contention_mark); + return true; +} + +void ObjectMonitor::enter_with_contention_mark(JavaThread *current, ObjectMonitorContentionMark &cm) { + assert(current == JavaThread::current(), "must be"); + assert(owner_raw() != current, "must be"); + assert(cm._monitor == this, "must be"); + assert(!is_being_async_deflated(), "must be"); + JFR_ONLY(JfrConditionalFlush flush(current);) EventJavaMonitorEnter event; if (event.is_started()) { @@ -480,14 +519,13 @@ bool ObjectMonitor::enter(JavaThread* current) { // the monitor free and clear. } - add_to_contentions(-1); assert(contentions() >= 0, "must not be negative: contentions=%d", contentions()); // Must either set _recursions = 0 or ASSERT _recursions == 0. assert(_recursions == 0, "invariant"); assert(owner_raw() == current, "invariant"); assert(_succ != current, "invariant"); - assert(object()->mark() == markWord::encode(this), "invariant"); + assert_mark_word_consistency(); // The thread -- now the owner -- is back in vm mode. // Report the glorious news via TI,DTrace and jvmstat. @@ -516,7 +554,6 @@ bool ObjectMonitor::enter(JavaThread* current) { event.commit(); } OM_PERFDATA_OP(ContendedLockAttempts, inc()); - return true; } // Caveat: TryLock() is not necessarily serializing if it returns failure. @@ -549,7 +586,7 @@ ObjectMonitor::TryLockResult ObjectMonitor::TryLock(JavaThread* current) { // (contentions < 0) // Contending threads that see that condition know to retry their operation. // -bool ObjectMonitor::deflate_monitor() { +bool ObjectMonitor::deflate_monitor(Thread* current) { if (is_busy()) { // Easy checks are first - the ObjectMonitor is busy so no deflation. return false; @@ -620,7 +657,11 @@ bool ObjectMonitor::deflate_monitor() { p2i(obj), obj->mark().value(), obj->klass()->external_name()); } + } + if (UseObjectMonitorTable) { + LightweightSynchronizer::deflate_monitor(current, obj, this); + } else if (obj != nullptr) { // Install the old mark word if nobody else has already done it. install_displaced_markword_in_object(obj); } @@ -636,6 +677,7 @@ bool ObjectMonitor::deflate_monitor() { // monitor and by other threads that have detected a race with the // deflation process. void ObjectMonitor::install_displaced_markword_in_object(const oop obj) { + assert(!UseObjectMonitorTable, "ObjectMonitorTable has no dmw"); // This function must only be called when (owner == DEFLATER_MARKER // && contentions <= 0), but we can't guarantee that here because // those values could change when the ObjectMonitor gets moved from @@ -972,12 +1014,11 @@ void ObjectMonitor::EnterI(JavaThread* current) { void ObjectMonitor::ReenterI(JavaThread* current, ObjectWaiter* currentNode) { assert(current != nullptr, "invariant"); + assert(current->thread_state() != _thread_blocked, "invariant"); assert(currentNode != nullptr, "invariant"); assert(currentNode->_thread == current, "invariant"); assert(_waiters > 0, "invariant"); - assert(object()->mark() == markWord::encode(this), "invariant"); - - assert(current->thread_state() != _thread_blocked, "invariant"); + assert_mark_word_consistency(); for (;;) { ObjectWaiter::TStates v = currentNode->TState; @@ -1042,7 +1083,7 @@ void ObjectMonitor::ReenterI(JavaThread* current, ObjectWaiter* currentNode) { // In addition, current.TState is stable. assert(owner_raw() == current, "invariant"); - assert(object()->mark() == markWord::encode(this), "invariant"); + assert_mark_word_consistency(); UnlinkAfterAcquire(current, currentNode); if (_succ == current) _succ = nullptr; assert(_succ != current, "invariant"); @@ -1668,7 +1709,7 @@ void ObjectMonitor::wait(jlong millis, bool interruptible, TRAPS) { // Verify a few postconditions assert(owner_raw() == current, "invariant"); assert(_succ != current, "invariant"); - assert(object()->mark() == markWord::encode(this), "invariant"); + assert_mark_word_consistency(); // check if the notification happened if (!WasNotified) { @@ -2185,7 +2226,7 @@ void ObjectMonitor::print() const { print_on(tty); } // Print the ObjectMonitor like a debugger would: // // (ObjectMonitor) 0x00007fdfb6012e40 = { -// _header = 0x0000000000000001 +// _metadata = 0x0000000000000001 // _object = 0x000000070ff45fd0 // _pad_buf0 = { // [0] = '\0' @@ -2214,7 +2255,7 @@ void ObjectMonitor::print() const { print_on(tty); } // void ObjectMonitor::print_debug_style_on(outputStream* st) const { st->print_cr("(ObjectMonitor*) " INTPTR_FORMAT " = {", p2i(this)); - st->print_cr(" _header = " INTPTR_FORMAT, header().value()); + st->print_cr(" _metadata = " INTPTR_FORMAT, _metadata); st->print_cr(" _object = " INTPTR_FORMAT, p2i(object_peek())); st->print_cr(" _pad_buf0 = {"); st->print_cr(" [0] = '\\0'"); diff --git a/src/hotspot/share/runtime/objectMonitor.hpp b/src/hotspot/share/runtime/objectMonitor.hpp index fdc482a3555d6..ef85559c2b6c3 100644 --- a/src/hotspot/share/runtime/objectMonitor.hpp +++ b/src/hotspot/share/runtime/objectMonitor.hpp @@ -33,6 +33,7 @@ #include "utilities/checkedCast.hpp" class ObjectMonitor; +class ObjectMonitorContentionMark; class ParkEvent; // ObjectWaiter serves as a "proxy" or surrogate thread. @@ -69,20 +70,21 @@ class ObjectWaiter : public StackObj { // // ObjectMonitor Layout Overview/Highlights/Restrictions: // -// - The _header field must be at offset 0 because the displaced header +// - The _metadata field must be at offset 0 because the displaced header // from markWord is stored there. We do not want markWord.hpp to include // ObjectMonitor.hpp to avoid exposing ObjectMonitor everywhere. This // means that ObjectMonitor cannot inherit from any other class nor can // it use any virtual member functions. This restriction is critical to // the proper functioning of the VM. -// - The _header and _owner fields should be separated by enough space +// - The _metadata and _owner fields should be separated by enough space // to avoid false sharing due to parallel access by different threads. // This is an advisory recommendation. // - The general layout of the fields in ObjectMonitor is: -// _header +// _metadata // // // _owner +// // // - The VM assumes write ordering and machine word alignment with // respect to the _owner field and the that can @@ -106,20 +108,19 @@ class ObjectWaiter : public StackObj { // in synchronizer.cpp. Also see TEST_VM(SynchronizerTest, sanity) gtest. // // Futures notes: -// - Separating _owner from the by enough space to -// avoid false sharing might be profitable. Given -// http://blogs.oracle.com/dave/entry/cas_and_cache_trivia_invalidate -// we know that the CAS in monitorenter will invalidate the line -// underlying _owner. We want to avoid an L1 data cache miss on that -// same line for monitorexit. Putting these : -// _recursions, _EntryList, _cxq, and _succ, all of which may be -// fetched in the inflated unlock path, on a different cache line -// would make them immune to CAS-based invalidation from the _owner -// field. +// - Separating _owner from the by enough space to +// avoid false sharing might be profitable. Given that the CAS in +// monitorenter will invalidate the line underlying _owner. We want +// to avoid an L1 data cache miss on that same line for monitorexit. +// Putting these : +// _recursions, _EntryList, _cxq, and _succ, all of which may be +// fetched in the inflated unlock path, on a different cache line +// would make them immune to CAS-based invalidation from the _owner +// field. // -// - The _recursions field should be of type int, or int32_t but not -// intptr_t. There's no reason to use a 64-bit type for this field -// in a 64-bit JVM. +// - The _recursions field should be of type int, or int32_t but not +// intptr_t. There's no reason to use a 64-bit type for this field +// in a 64-bit JVM. #define OM_CACHE_LINE_SIZE DEFAULT_CACHE_LINE_SIZE @@ -131,15 +132,19 @@ class ObjectMonitor : public CHeapObj { static OopStorage* _oop_storage; - // The sync code expects the header field to be at offset zero (0). - // Enforced by the assert() in header_addr(). - volatile markWord _header; // displaced object header word - mark + // The sync code expects the metadata field to be at offset zero (0). + // Enforced by the assert() in metadata_addr(). + // * LM_LIGHTWEIGHT with UseObjectMonitorTable: + // Contains the _object's hashCode. + // * LM_LEGACY, LM_MONITOR, LM_LIGHTWEIGHT without UseObjectMonitorTable: + // Contains the displaced object header word - mark + volatile uintptr_t _metadata; // metadata WeakHandle _object; // backward object pointer - // Separate _header and _owner on different cache lines since both can - // have busy multi-threaded access. _header and _object are set at initial + // Separate _metadata and _owner on different cache lines since both can + // have busy multi-threaded access. _metadata and _object are set at initial // inflation. The _object does not change, so it is a good choice to share - // its cache line with _header. - DEFINE_PAD_MINUS_SIZE(0, OM_CACHE_LINE_SIZE, sizeof(volatile markWord) + + // its cache line with _metadata. + DEFINE_PAD_MINUS_SIZE(0, OM_CACHE_LINE_SIZE, sizeof(_metadata) + sizeof(WeakHandle)); // Used by async deflation as a marker in the _owner field. // Note that the choice of the two markers is peculiar: @@ -149,12 +154,13 @@ class ObjectMonitor : public CHeapObj { // and small values encode much better. // - We test for anonymous owner by testing for the lowest bit, therefore // DEFLATER_MARKER must *not* have that bit set. - #define DEFLATER_MARKER reinterpret_cast(2) -public: + static const uintptr_t DEFLATER_MARKER_VALUE = 2; + #define DEFLATER_MARKER reinterpret_cast(DEFLATER_MARKER_VALUE) + public: // NOTE: Typed as uintptr_t so that we can pick it up in SA, via vmStructs. static const uintptr_t ANONYMOUS_OWNER = 1; -private: + private: static void* anon_owner_ptr() { return reinterpret_cast(ANONYMOUS_OWNER); } void* volatile _owner; // pointer to owning thread OR BasicLock @@ -181,10 +187,9 @@ class ObjectMonitor : public CHeapObj { // along with other fields to determine if an ObjectMonitor can be // deflated. It is also used by the async deflation protocol. See // ObjectMonitor::deflate_monitor(). - protected: + ObjectWaiter* volatile _WaitSet; // LL of threads wait()ing on the monitor volatile int _waiters; // number of waiting threads - private: volatile int _WaitSetLock; // protects Wait Queue - simple spinlock public: @@ -213,6 +218,7 @@ class ObjectMonitor : public CHeapObj { static int Knob_SpinLimit; + static ByteSize metadata_offset() { return byte_offset_of(ObjectMonitor, _metadata); } static ByteSize owner_offset() { return byte_offset_of(ObjectMonitor, _owner); } static ByteSize recursions_offset() { return byte_offset_of(ObjectMonitor, _recursions); } static ByteSize cxq_offset() { return byte_offset_of(ObjectMonitor, _cxq); } @@ -233,9 +239,15 @@ class ObjectMonitor : public CHeapObj { #define OM_OFFSET_NO_MONITOR_VALUE_TAG(f) \ ((in_bytes(ObjectMonitor::f ## _offset())) - checked_cast(markWord::monitor_value)) - markWord header() const; - volatile markWord* header_addr(); - void set_header(markWord hdr); + uintptr_t metadata() const; + void set_metadata(uintptr_t value); + volatile uintptr_t* metadata_addr(); + + markWord header() const; + void set_header(markWord hdr); + + intptr_t hash() const; + void set_hash(intptr_t hash); bool is_busy() const { // TODO-FIXME: assert _owner == null implies _recursions = 0 @@ -306,6 +318,8 @@ class ObjectMonitor : public CHeapObj { oop object() const; oop object_peek() const; + bool object_is_dead() const; + bool object_refers_to(oop obj) const; // Returns true if the specified thread owns the ObjectMonitor. Otherwise // returns false and throws IllegalMonitorStateException (IMSE). @@ -328,9 +342,15 @@ class ObjectMonitor : public CHeapObj { ClearSuccOnSuspend(ObjectMonitor* om) : _om(om) {} void operator()(JavaThread* current); }; + + bool enter_is_async_deflating(); public: + void enter_for_with_contention_mark(JavaThread* locking_thread, ObjectMonitorContentionMark& contention_mark); bool enter_for(JavaThread* locking_thread); bool enter(JavaThread* current); + bool try_enter(JavaThread* current); + bool spin_enter(JavaThread* current); + void enter_with_contention_mark(JavaThread* current, ObjectMonitorContentionMark& contention_mark); void exit(JavaThread* current, bool not_suspended = true); void wait(jlong millis, bool interruptible, TRAPS); void notify(TRAPS); @@ -364,8 +384,23 @@ class ObjectMonitor : public CHeapObj { void ExitEpilog(JavaThread* current, ObjectWaiter* Wakee); // Deflation support - bool deflate_monitor(); + bool deflate_monitor(Thread* current); + private: void install_displaced_markword_in_object(const oop obj); }; +// RAII object to ensure that ObjectMonitor::is_being_async_deflated() is +// stable within the context of this mark. +class ObjectMonitorContentionMark : StackObj { + DEBUG_ONLY(friend class ObjectMonitor;) + + ObjectMonitor* _monitor; + + NONCOPYABLE(ObjectMonitorContentionMark); + + public: + explicit ObjectMonitorContentionMark(ObjectMonitor* monitor); + ~ObjectMonitorContentionMark(); +}; + #endif // SHARE_RUNTIME_OBJECTMONITOR_HPP diff --git a/src/hotspot/share/runtime/objectMonitor.inline.hpp b/src/hotspot/share/runtime/objectMonitor.inline.hpp index b371663eeb326..d26c459b1b415 100644 --- a/src/hotspot/share/runtime/objectMonitor.inline.hpp +++ b/src/hotspot/share/runtime/objectMonitor.inline.hpp @@ -29,9 +29,13 @@ #include "logging/log.hpp" #include "oops/access.inline.hpp" +#include "oops/markWord.hpp" #include "runtime/atomic.hpp" +#include "runtime/globals.hpp" #include "runtime/lockStack.inline.hpp" #include "runtime/synchronizer.hpp" +#include "utilities/checkedCast.hpp" +#include "utilities/globalDefinitions.hpp" inline bool ObjectMonitor::is_entered(JavaThread* current) const { if (LockingMode == LM_LIGHTWEIGHT) { @@ -49,16 +53,38 @@ inline bool ObjectMonitor::is_entered(JavaThread* current) const { return false; } -inline markWord ObjectMonitor::header() const { - return Atomic::load(&_header); +inline uintptr_t ObjectMonitor::metadata() const { + return Atomic::load(&_metadata); +} + +inline void ObjectMonitor::set_metadata(uintptr_t value) { + Atomic::store(&_metadata, value); } -inline volatile markWord* ObjectMonitor::header_addr() { - return &_header; +inline volatile uintptr_t* ObjectMonitor::metadata_addr() { + STATIC_ASSERT(std::is_standard_layout::value); + STATIC_ASSERT(offsetof(ObjectMonitor, _metadata) == 0); + return &_metadata; +} + +inline markWord ObjectMonitor::header() const { + assert(!UseObjectMonitorTable, "Lightweight locking with OM table does not use header"); + return markWord(metadata()); } inline void ObjectMonitor::set_header(markWord hdr) { - Atomic::store(&_header, hdr); + assert(!UseObjectMonitorTable, "Lightweight locking with OM table does not use header"); + set_metadata(hdr.value()); +} + +inline intptr_t ObjectMonitor::hash() const { + assert(UseObjectMonitorTable, "Only used by lightweight locking with OM table"); + return metadata(); +} + +inline void ObjectMonitor::set_hash(intptr_t hash) { + assert(UseObjectMonitorTable, "Only used by lightweight locking with OM table"); + set_metadata(hash); } inline int ObjectMonitor::waiters() const { @@ -180,4 +206,31 @@ inline void ObjectMonitor::set_next_om(ObjectMonitor* new_value) { Atomic::store(&_next_om, new_value); } +inline ObjectMonitorContentionMark::ObjectMonitorContentionMark(ObjectMonitor* monitor) + : _monitor(monitor) { + _monitor->add_to_contentions(1); +} + +inline ObjectMonitorContentionMark::~ObjectMonitorContentionMark() { + _monitor->add_to_contentions(-1); +} + +inline oop ObjectMonitor::object_peek() const { + if (_object.is_null()) { + return nullptr; + } + return _object.peek(); +} + +inline bool ObjectMonitor::object_is_dead() const { + return object_peek() == nullptr; +} + +inline bool ObjectMonitor::object_refers_to(oop obj) const { + if (_object.is_null()) { + return false; + } + return _object.peek() == obj; +} + #endif // SHARE_RUNTIME_OBJECTMONITOR_INLINE_HPP diff --git a/src/hotspot/share/runtime/safepoint.cpp b/src/hotspot/share/runtime/safepoint.cpp index 05f59de4a17ef..bea0b68354ee3 100644 --- a/src/hotspot/share/runtime/safepoint.cpp +++ b/src/hotspot/share/runtime/safepoint.cpp @@ -731,6 +731,11 @@ void ThreadSafepointState::account_safe_thread() { DEBUG_ONLY(_thread->set_visited_for_critical_count(SafepointSynchronize::safepoint_counter());) assert(!_safepoint_safe, "Must be unsafe before safe"); _safepoint_safe = true; + + // The oops in the monitor cache are cleared to prevent stale cache entries + // from keeping dead objects alive. Because these oops are always cleared + // before safepoint operations they are not visited in JavaThread::oops_do. + _thread->om_clear_monitor_cache(); } void ThreadSafepointState::restart() { diff --git a/src/hotspot/share/runtime/serviceThread.cpp b/src/hotspot/share/runtime/serviceThread.cpp index a81285ac97c0b..f5653ccd5f482 100644 --- a/src/hotspot/share/runtime/serviceThread.cpp +++ b/src/hotspot/share/runtime/serviceThread.cpp @@ -32,20 +32,21 @@ #include "classfile/vmClasses.hpp" #include "gc/shared/oopStorage.hpp" #include "gc/shared/oopStorageSet.hpp" -#include "memory/universe.hpp" #include "interpreter/oopMapCache.hpp" +#include "memory/universe.hpp" #include "oops/oopHandle.inline.hpp" +#include "prims/jvmtiImpl.hpp" +#include "prims/jvmtiTagMap.hpp" +#include "prims/resolvedMethodTable.hpp" #include "runtime/handles.inline.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/java.hpp" #include "runtime/javaCalls.hpp" #include "runtime/jniHandles.hpp" -#include "runtime/serviceThread.hpp" +#include "runtime/lightweightSynchronizer.hpp" #include "runtime/mutexLocker.hpp" #include "runtime/os.hpp" -#include "prims/jvmtiImpl.hpp" -#include "prims/jvmtiTagMap.hpp" -#include "prims/resolvedMethodTable.hpp" +#include "runtime/serviceThread.hpp" #include "services/diagnosticArgument.hpp" #include "services/diagnosticFramework.hpp" #include "services/finalizerService.hpp" @@ -94,6 +95,7 @@ void ServiceThread::service_thread_entry(JavaThread* jt, TRAPS) { bool cldg_cleanup_work = false; bool jvmti_tagmap_work = false; bool oopmap_cache_work = false; + bool object_monitor_table_work = false; { // Need state transition ThreadBlockInVM so that this thread // will be handled by safepoint correctly when this thread is @@ -121,7 +123,8 @@ void ServiceThread::service_thread_entry(JavaThread* jt, TRAPS) { (oop_handles_to_release = JavaThread::has_oop_handles_to_release()) | (cldg_cleanup_work = ClassLoaderDataGraph::should_clean_metaspaces_and_reset()) | (jvmti_tagmap_work = JvmtiTagMap::has_object_free_events_and_reset()) | - (oopmap_cache_work = OopMapCache::has_cleanup_work()) + (oopmap_cache_work = OopMapCache::has_cleanup_work()) | + (object_monitor_table_work = LightweightSynchronizer::needs_resize()) ) == 0) { // Wait until notified that there is some work to do or timer expires. // Some cleanup requests don't notify the ServiceThread so work needs to be done at periodic intervals. @@ -183,6 +186,10 @@ void ServiceThread::service_thread_entry(JavaThread* jt, TRAPS) { if (oopmap_cache_work) { OopMapCache::cleanup(); } + + if (object_monitor_table_work) { + LightweightSynchronizer::resize_table(jt); + } } } diff --git a/src/hotspot/share/runtime/sharedRuntime.cpp b/src/hotspot/share/runtime/sharedRuntime.cpp index 0eec7e4c34cae..0587032ec5c67 100644 --- a/src/hotspot/share/runtime/sharedRuntime.cpp +++ b/src/hotspot/share/runtime/sharedRuntime.cpp @@ -58,6 +58,7 @@ #include "prims/nativeLookup.hpp" #include "runtime/arguments.hpp" #include "runtime/atomic.hpp" +#include "runtime/basicLock.inline.hpp" #include "runtime/frame.inline.hpp" #include "runtime/handles.inline.hpp" #include "runtime/init.hpp" @@ -69,13 +70,14 @@ #include "runtime/sharedRuntime.hpp" #include "runtime/stackWatermarkSet.hpp" #include "runtime/stubRoutines.hpp" -#include "runtime/synchronizer.hpp" +#include "runtime/synchronizer.inline.hpp" #include "runtime/vframe.inline.hpp" #include "runtime/vframeArray.hpp" #include "runtime/vm_version.hpp" #include "utilities/copy.hpp" #include "utilities/dtrace.hpp" #include "utilities/events.hpp" +#include "utilities/globalDefinitions.hpp" #include "utilities/resourceHash.hpp" #include "utilities/macros.hpp" #include "utilities/xmlstream.hpp" @@ -1883,7 +1885,7 @@ void SharedRuntime::monitor_enter_helper(oopDesc* obj, BasicLock* lock, JavaThre if (!SafepointSynchronize::is_synchronizing()) { // Only try quick_enter() if we're not trying to reach a safepoint // so that the calling thread reaches the safepoint more quickly. - if (ObjectSynchronizer::quick_enter(obj, current, lock)) { + if (ObjectSynchronizer::quick_enter(obj, lock, current)) { return; } } @@ -2945,6 +2947,8 @@ JRT_LEAF(intptr_t*, SharedRuntime::OSR_migration_begin( JavaThread *current) ) // Now the displaced header is free to move because the // object's header no longer refers to it. buf[i] = (intptr_t)lock->displaced_header().value(); + } else if (UseObjectMonitorTable) { + buf[i] = (intptr_t)lock->object_monitor_cache(); } #ifdef ASSERT else { diff --git a/src/hotspot/share/runtime/synchronizer.cpp b/src/hotspot/share/runtime/synchronizer.cpp index b4ff263d455b4..d8fb7a4734abe 100644 --- a/src/hotspot/share/runtime/synchronizer.cpp +++ b/src/hotspot/share/runtime/synchronizer.cpp @@ -35,12 +35,14 @@ #include "oops/markWord.hpp" #include "oops/oop.inline.hpp" #include "runtime/atomic.hpp" +#include "runtime/basicLock.inline.hpp" #include "runtime/frame.inline.hpp" #include "runtime/globals.hpp" #include "runtime/handles.inline.hpp" #include "runtime/handshake.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/javaThread.hpp" +#include "runtime/lightweightSynchronizer.hpp" #include "runtime/lockStack.inline.hpp" #include "runtime/mutexLocker.hpp" #include "runtime/objectMonitor.hpp" @@ -52,7 +54,7 @@ #include "runtime/safepointVerifiers.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/stubRoutines.hpp" -#include "runtime/synchronizer.hpp" +#include "runtime/synchronizer.inline.hpp" #include "runtime/threads.hpp" #include "runtime/timer.hpp" #include "runtime/trimNativeHeap.hpp" @@ -276,6 +278,10 @@ void ObjectSynchronizer::initialize() { // Start the timer for deflations, so it does not trigger immediately. _last_async_deflation_time_ns = os::javaTimeNanos(); + + if (LockingMode == LM_LIGHTWEIGHT) { + LightweightSynchronizer::initialize(); + } } MonitorList ObjectSynchronizer::_in_use_list; @@ -349,7 +355,11 @@ bool ObjectSynchronizer::quick_notify(oopDesc* obj, JavaThread* current, bool al } if (mark.has_monitor()) { - ObjectMonitor* const mon = mark.monitor(); + ObjectMonitor* const mon = read_monitor(current, obj, mark); + if (LockingMode == LM_LIGHTWEIGHT && mon == nullptr) { + // Racing with inflation/deflation go slow path + return false; + } assert(mon->object() == oop(obj), "invariant"); if (mon->owner() != current) return false; // slow-path for IMS exception @@ -376,6 +386,13 @@ bool ObjectSynchronizer::quick_notify(oopDesc* obj, JavaThread* current, bool al return false; } +static bool useHeavyMonitors() { +#if defined(X86) || defined(AARCH64) || defined(PPC64) || defined(RISCV64) || defined(S390) + return LockingMode == LM_MONITOR; +#else + return false; +#endif +} // The LockNode emitted directly at the synchronization site would have // been too big if it were to have included support for the cases of inflated @@ -383,33 +400,24 @@ bool ObjectSynchronizer::quick_notify(oopDesc* obj, JavaThread* current, bool al // Note that we can't safely call AsyncPrintJavaStack() from within // quick_enter() as our thread state remains _in_Java. -bool ObjectSynchronizer::quick_enter(oop obj, JavaThread* current, - BasicLock * lock) { +bool ObjectSynchronizer::quick_enter_legacy(oop obj, BasicLock* lock, JavaThread* current) { assert(current->thread_state() == _thread_in_Java, "invariant"); - NoSafepointVerifier nsv; - if (obj == nullptr) return false; // Need to throw NPE - if (obj->klass()->is_value_based()) { - return false; + if (useHeavyMonitors()) { + return false; // Slow path } if (LockingMode == LM_LIGHTWEIGHT) { - LockStack& lock_stack = current->lock_stack(); - if (lock_stack.is_full()) { - // Always go into runtime if the lock stack is full. - return false; - } - if (lock_stack.try_recursive_enter(obj)) { - // Recursive lock successful. - current->inc_held_monitor_count(); - return true; - } + return LightweightSynchronizer::quick_enter(obj, lock, current); } + assert(LockingMode == LM_LEGACY, "legacy mode below"); + const markWord mark = obj->mark(); if (mark.has_monitor()) { - ObjectMonitor* const m = mark.monitor(); + + ObjectMonitor* const m = read_monitor(mark); // An async deflation or GC can race us before we manage to make // the ObjectMonitor busy by setting the owner below. If we detect // that race we just bail out to the slow-path here. @@ -429,18 +437,16 @@ bool ObjectSynchronizer::quick_enter(oop obj, JavaThread* current, return true; } - if (LockingMode != LM_LIGHTWEIGHT) { - // This Java Monitor is inflated so obj's header will never be - // displaced to this thread's BasicLock. Make the displaced header - // non-null so this BasicLock is not seen as recursive nor as - // being locked. We do this unconditionally so that this thread's - // BasicLock cannot be mis-interpreted by any stack walkers. For - // performance reasons, stack walkers generally first check for - // stack-locking in the object's header, the second check is for - // recursive stack-locking in the displaced header in the BasicLock, - // and last are the inflated Java Monitor (ObjectMonitor) checks. - lock->set_displaced_header(markWord::unused_mark()); - } + // This Java Monitor is inflated so obj's header will never be + // displaced to this thread's BasicLock. Make the displaced header + // non-null so this BasicLock is not seen as recursive nor as + // being locked. We do this unconditionally so that this thread's + // BasicLock cannot be mis-interpreted by any stack walkers. For + // performance reasons, stack walkers generally first check for + // stack-locking in the object's header, the second check is for + // recursive stack-locking in the displaced header in the BasicLock, + // and last are the inflated Java Monitor (ObjectMonitor) checks. + lock->set_displaced_header(markWord::unused_mark()); if (owner == nullptr && m->try_set_owner_from(nullptr, current) == nullptr) { assert(m->_recursions == 0, "invariant"); @@ -508,14 +514,6 @@ void ObjectSynchronizer::handle_sync_on_value_based_class(Handle obj, JavaThread } } -static bool useHeavyMonitors() { -#if defined(X86) || defined(AARCH64) || defined(PPC64) || defined(RISCV64) || defined(S390) - return LockingMode == LM_MONITOR; -#else - return false; -#endif -} - // ----------------------------------------------------------------------------- // Monitor Enter/Exit @@ -524,6 +522,11 @@ void ObjectSynchronizer::enter_for(Handle obj, BasicLock* lock, JavaThread* lock // the locking_thread with respect to the current thread. Currently only used when // deoptimizing and re-locking locks. See Deoptimization::relock_objects assert(locking_thread == Thread::current() || locking_thread->is_obj_deopt_suspend(), "must be"); + + if (LockingMode == LM_LIGHTWEIGHT) { + return LightweightSynchronizer::enter_for(obj, lock, locking_thread); + } + if (!enter_fast_impl(obj, lock, locking_thread)) { // Inflated ObjectMonitor::enter_for is required @@ -540,8 +543,7 @@ void ObjectSynchronizer::enter_for(Handle obj, BasicLock* lock, JavaThread* lock } } -void ObjectSynchronizer::enter(Handle obj, BasicLock* lock, JavaThread* current) { - assert(current == Thread::current(), "must be"); +void ObjectSynchronizer::enter_legacy(Handle obj, BasicLock* lock, JavaThread* current) { if (!enter_fast_impl(obj, lock, current)) { // Inflated ObjectMonitor::enter is required @@ -561,6 +563,7 @@ void ObjectSynchronizer::enter(Handle obj, BasicLock* lock, JavaThread* current) // of this algorithm. Make sure to update that code if the following function is // changed. The implementation is extremely sensitive to race condition. Be careful. bool ObjectSynchronizer::enter_fast_impl(Handle obj, BasicLock* lock, JavaThread* locking_thread) { + assert(LockingMode != LM_LIGHTWEIGHT, "Use LightweightSynchronizer"); if (obj->klass()->is_value_based()) { handle_sync_on_value_based_class(obj, locking_thread); @@ -569,61 +572,7 @@ bool ObjectSynchronizer::enter_fast_impl(Handle obj, BasicLock* lock, JavaThread locking_thread->inc_held_monitor_count(); if (!useHeavyMonitors()) { - if (LockingMode == LM_LIGHTWEIGHT) { - // Fast-locking does not use the 'lock' argument. - LockStack& lock_stack = locking_thread->lock_stack(); - if (lock_stack.is_full()) { - // We unconditionally make room on the lock stack by inflating - // the least recently locked object on the lock stack. - - // About the choice to inflate least recently locked object. - // First we must chose to inflate a lock, either some lock on - // the lock-stack or the lock that is currently being entered - // (which may or may not be on the lock-stack). - // Second the best lock to inflate is a lock which is entered - // in a control flow where there are only a very few locks being - // used, as the costly part of inflated locking is inflation, - // not locking. But this property is entirely program dependent. - // Third inflating the lock currently being entered on when it - // is not present on the lock-stack will result in a still full - // lock-stack. This creates a scenario where every deeper nested - // monitorenter must call into the runtime. - // The rational here is as follows: - // Because we cannot (currently) figure out the second, and want - // to avoid the third, we inflate a lock on the lock-stack. - // The least recently locked lock is chosen as it is the lock - // with the longest critical section. - - log_info(monitorinflation)("LockStack capacity exceeded, inflating."); - ObjectMonitor* monitor = inflate_for(locking_thread, lock_stack.bottom(), inflate_cause_vm_internal); - assert(monitor->owner() == locking_thread, "must be owner=" PTR_FORMAT " locking_thread=" PTR_FORMAT " mark=" PTR_FORMAT, - p2i(monitor->owner()), p2i(locking_thread), monitor->object()->mark_acquire().value()); - assert(!lock_stack.is_full(), "must have made room here"); - } - - markWord mark = obj()->mark_acquire(); - while (mark.is_unlocked()) { - // Retry until a lock state change has been observed. cas_set_mark() may collide with non lock bits modifications. - // Try to swing into 'fast-locked' state. - assert(!lock_stack.contains(obj()), "thread must not already hold the lock"); - const markWord locked_mark = mark.set_fast_locked(); - const markWord old_mark = obj()->cas_set_mark(locked_mark, mark); - if (old_mark == mark) { - // Successfully fast-locked, push object to lock-stack and return. - lock_stack.push(obj()); - return true; - } - mark = old_mark; - } - - if (mark.is_fast_locked() && lock_stack.try_recursive_enter(obj())) { - // Recursive lock successful. - return true; - } - - // Failed to fast lock. - return false; - } else if (LockingMode == LM_LEGACY) { + if (LockingMode == LM_LEGACY) { markWord mark = obj->mark(); if (mark.is_unlocked()) { // Anticipate successful CAS -- the ST of the displaced mark must @@ -656,37 +605,12 @@ bool ObjectSynchronizer::enter_fast_impl(Handle obj, BasicLock* lock, JavaThread return false; } -void ObjectSynchronizer::exit(oop object, BasicLock* lock, JavaThread* current) { - current->dec_held_monitor_count(); +void ObjectSynchronizer::exit_legacy(oop object, BasicLock* lock, JavaThread* current) { + assert(LockingMode != LM_LIGHTWEIGHT, "Use LightweightSynchronizer"); if (!useHeavyMonitors()) { markWord mark = object->mark(); - if (LockingMode == LM_LIGHTWEIGHT) { - // Fast-locking does not use the 'lock' argument. - LockStack& lock_stack = current->lock_stack(); - if (mark.is_fast_locked() && lock_stack.try_recursive_exit(object)) { - // Recursively unlocked. - return; - } - - if (mark.is_fast_locked() && lock_stack.is_recursive(object)) { - // This lock is recursive but is not at the top of the lock stack so we're - // doing an unbalanced exit. We have to fall thru to inflation below and - // let ObjectMonitor::exit() do the unlock. - } else { - while (mark.is_fast_locked()) { - // Retry until a lock state change has been observed. cas_set_mark() may collide with non lock bits modifications. - const markWord unlocked_mark = mark.set_unlocked(); - const markWord old_mark = object->cas_set_mark(unlocked_mark, mark); - if (old_mark == mark) { - size_t recursions = lock_stack.remove(object) - 1; - assert(recursions == 0, "must not be recursive here"); - return; - } - mark = old_mark; - } - } - } else if (LockingMode == LM_LEGACY) { + if (LockingMode == LM_LEGACY) { markWord dhw = lock->displaced_header(); if (dhw.value() == 0) { // If the displaced header is null, then this exit matches up with @@ -708,7 +632,7 @@ void ObjectSynchronizer::exit(oop object, BasicLock* lock, JavaThread* current) // Monitor owner's stack and update the BasicLocks because a // Java Monitor can be asynchronously inflated by a thread that // does not own the Java Monitor. - ObjectMonitor* m = mark.monitor(); + ObjectMonitor* m = read_monitor(mark); assert(m->object()->mark() == mark, "invariant"); assert(m->is_entered(current), "invariant"); } @@ -752,8 +676,16 @@ void ObjectSynchronizer::jni_enter(Handle obj, JavaThread* current) { // enter() can make the ObjectMonitor busy. enter() returns false if // we have lost the race to async deflation and we simply try again. while (true) { - ObjectMonitor* monitor = inflate(current, obj(), inflate_cause_jni_enter); - if (monitor->enter(current)) { + ObjectMonitor* monitor; + bool entered; + if (LockingMode == LM_LIGHTWEIGHT) { + entered = LightweightSynchronizer::inflate_and_enter(obj(), inflate_cause_jni_enter, current, current) != nullptr; + } else { + monitor = inflate(current, obj(), inflate_cause_jni_enter); + entered = monitor->enter(current); + } + + if (entered) { current->inc_held_monitor_count(1, true); break; } @@ -765,9 +697,14 @@ void ObjectSynchronizer::jni_enter(Handle obj, JavaThread* current) { void ObjectSynchronizer::jni_exit(oop obj, TRAPS) { JavaThread* current = THREAD; - // The ObjectMonitor* can't be async deflated until ownership is - // dropped inside exit() and the ObjectMonitor* must be !is_busy(). - ObjectMonitor* monitor = inflate(current, obj, inflate_cause_jni_exit); + ObjectMonitor* monitor; + if (LockingMode == LM_LIGHTWEIGHT) { + monitor = LightweightSynchronizer::inflate_locked_or_imse(obj, inflate_cause_jni_exit, CHECK); + } else { + // The ObjectMonitor* can't be async deflated until ownership is + // dropped inside exit() and the ObjectMonitor* must be !is_busy(). + monitor = inflate(current, obj, inflate_cause_jni_exit); + } // If this thread has locked the object, exit the monitor. We // intentionally do not use CHECK on check_owner because we must exit the // monitor even if an exception was already pending. @@ -800,15 +737,22 @@ ObjectLocker::~ObjectLocker() { // ----------------------------------------------------------------------------- // Wait/Notify/NotifyAll // NOTE: must use heavy weight monitor to handle wait() + int ObjectSynchronizer::wait(Handle obj, jlong millis, TRAPS) { JavaThread* current = THREAD; if (millis < 0) { THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "timeout value is negative"); } - // The ObjectMonitor* can't be async deflated because the _waiters - // field is incremented before ownership is dropped and decremented - // after ownership is regained. - ObjectMonitor* monitor = inflate(current, obj(), inflate_cause_wait); + + ObjectMonitor* monitor; + if (LockingMode == LM_LIGHTWEIGHT) { + monitor = LightweightSynchronizer::inflate_locked_or_imse(obj(), inflate_cause_wait, CHECK_0); + } else { + // The ObjectMonitor* can't be async deflated because the _waiters + // field is incremented before ownership is dropped and decremented + // after ownership is regained. + monitor = inflate(current, obj(), inflate_cause_wait); + } DTRACE_MONITOR_WAIT_PROBE(monitor, obj(), current, millis); monitor->wait(millis, true, THREAD); // Not CHECK as we need following code @@ -825,9 +769,14 @@ void ObjectSynchronizer::waitUninterruptibly(Handle obj, jlong millis, TRAPS) { if (millis < 0) { THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "timeout value is negative"); } - ObjectSynchronizer::inflate(THREAD, - obj(), - inflate_cause_wait)->wait(millis, false, THREAD); + + ObjectMonitor* monitor; + if (LockingMode == LM_LIGHTWEIGHT) { + monitor = LightweightSynchronizer::inflate_locked_or_imse(obj(), inflate_cause_wait, CHECK); + } else { + monitor = inflate(THREAD, obj(), inflate_cause_wait); + } + monitor->wait(millis, false, THREAD); } @@ -846,9 +795,15 @@ void ObjectSynchronizer::notify(Handle obj, TRAPS) { return; } } - // The ObjectMonitor* can't be async deflated until ownership is - // dropped by the calling thread. - ObjectMonitor* monitor = inflate(current, obj(), inflate_cause_notify); + + ObjectMonitor* monitor; + if (LockingMode == LM_LIGHTWEIGHT) { + monitor = LightweightSynchronizer::inflate_locked_or_imse(obj(), inflate_cause_notify, CHECK); + } else { + // The ObjectMonitor* can't be async deflated until ownership is + // dropped by the calling thread. + monitor = inflate(current, obj(), inflate_cause_notify); + } monitor->notify(CHECK); } @@ -868,9 +823,15 @@ void ObjectSynchronizer::notifyall(Handle obj, TRAPS) { return; } } - // The ObjectMonitor* can't be async deflated until ownership is - // dropped by the calling thread. - ObjectMonitor* monitor = inflate(current, obj(), inflate_cause_notify); + + ObjectMonitor* monitor; + if (LockingMode == LM_LIGHTWEIGHT) { + monitor = LightweightSynchronizer::inflate_locked_or_imse(obj(), inflate_cause_notify, CHECK); + } else { + // The ObjectMonitor* can't be async deflated until ownership is + // dropped by the calling thread. + monitor = inflate(current, obj(), inflate_cause_notify); + } monitor->notifyAll(CHECK); } @@ -968,7 +929,7 @@ static markWord read_stable_mark(oop obj) { // There are simple ways to "diffuse" the middle address bits over the // generated hashCode values: -static inline intptr_t get_next_hash(Thread* current, oop obj) { +static intptr_t get_next_hash(Thread* current, oop obj) { intptr_t value = 0; if (hashCode == 0) { // This form uses global Park-Miller RNG. @@ -1008,7 +969,33 @@ static inline intptr_t get_next_hash(Thread* current, oop obj) { return value; } +static intptr_t install_hash_code(Thread* current, oop obj) { + assert(UseObjectMonitorTable && LockingMode == LM_LIGHTWEIGHT, "must be"); + + markWord mark = obj->mark_acquire(); + for (;;) { + intptr_t hash = mark.hash(); + if (hash != 0) { + return hash; + } + + hash = get_next_hash(current, obj); + const markWord old_mark = mark; + const markWord new_mark = old_mark.copy_set_hash(hash); + + mark = obj->cas_set_mark(new_mark, old_mark); + if (old_mark == mark) { + return hash; + } + } +} + intptr_t ObjectSynchronizer::FastHashCode(Thread* current, oop obj) { + if (UseObjectMonitorTable) { + // Since the monitor isn't in the object header, the hash can simply be + // installed in the object header. + return install_hash_code(current, obj); + } while (true) { ObjectMonitor* monitor = nullptr; @@ -1102,7 +1089,7 @@ intptr_t ObjectSynchronizer::FastHashCode(Thread* current, oop obj) { hash = get_next_hash(current, obj); // get a new hash temp = mark.copy_set_hash(hash) ; // merge the hash into header assert(temp.is_neutral(), "invariant: header=" INTPTR_FORMAT, temp.value()); - uintptr_t v = Atomic::cmpxchg((volatile uintptr_t*)monitor->header_addr(), mark.value(), temp.value()); + uintptr_t v = Atomic::cmpxchg(monitor->metadata_addr(), mark.value(), temp.value()); test = markWord(v); if (test != mark) { // The attempt to update the ObjectMonitor's header/dmw field @@ -1114,7 +1101,7 @@ intptr_t ObjectSynchronizer::FastHashCode(Thread* current, oop obj) { assert(test.is_neutral(), "invariant: header=" INTPTR_FORMAT, test.value()); assert(hash != 0, "should only have lost the race to a thread that set a non-zero hash"); } - if (monitor->is_being_async_deflated()) { + if (monitor->is_being_async_deflated() && !UseObjectMonitorTable) { // If we detect that async deflation has occurred, then we // attempt to restore the header/dmw to the object's header // so that we only retry once if the deflater thread happens @@ -1145,11 +1132,25 @@ bool ObjectSynchronizer::current_thread_holds_lock(JavaThread* current, return current->lock_stack().contains(h_obj()); } - if (mark.has_monitor()) { + while (LockingMode == LM_LIGHTWEIGHT && mark.has_monitor()) { + ObjectMonitor* monitor = read_monitor(current, obj, mark); + if (monitor != nullptr) { + return monitor->is_entered(current) != 0; + } + // Racing with inflation/deflation, retry + mark = obj->mark_acquire(); + + if (mark.is_fast_locked()) { + // Some other thread fast_locked, current could not have held the lock + return false; + } + } + + if (LockingMode != LM_LIGHTWEIGHT && mark.has_monitor()) { // Inflated monitor so header points to ObjectMonitor (tagged pointer). // The first stage of async deflation does not affect any field // used by this comparison so the ObjectMonitor* is usable here. - ObjectMonitor* monitor = mark.monitor(); + ObjectMonitor* monitor = read_monitor(mark); return monitor->is_entered(current) != 0; } // Unlocked case, header in place @@ -1173,11 +1174,25 @@ JavaThread* ObjectSynchronizer::get_lock_owner(ThreadsList * t_list, Handle h_ob return Threads::owning_thread_from_object(t_list, h_obj()); } - if (mark.has_monitor()) { + while (LockingMode == LM_LIGHTWEIGHT && mark.has_monitor()) { + ObjectMonitor* monitor = read_monitor(Thread::current(), obj, mark); + if (monitor != nullptr) { + return Threads::owning_thread_from_monitor(t_list, monitor); + } + // Racing with inflation/deflation, retry + mark = obj->mark_acquire(); + + if (mark.is_fast_locked()) { + // Some other thread fast_locked + return Threads::owning_thread_from_object(t_list, h_obj()); + } + } + + if (LockingMode != LM_LIGHTWEIGHT && mark.has_monitor()) { // Inflated monitor so header points to ObjectMonitor (tagged pointer). // The first stage of async deflation does not affect any field // used by this comparison so the ObjectMonitor* is usable here. - ObjectMonitor* monitor = mark.monitor(); + ObjectMonitor* monitor = read_monitor(mark); assert(monitor != nullptr, "monitor should be non-null"); // owning_thread_from_monitor() may also return null here: return Threads::owning_thread_from_monitor(t_list, monitor); @@ -1389,9 +1404,10 @@ static void post_monitor_inflate_event(EventJavaMonitorInflate* event, // Fast path code shared by multiple functions void ObjectSynchronizer::inflate_helper(oop obj) { + assert(LockingMode != LM_LIGHTWEIGHT, "only inflate through enter"); markWord mark = obj->mark_acquire(); if (mark.has_monitor()) { - ObjectMonitor* monitor = mark.monitor(); + ObjectMonitor* monitor = read_monitor(mark); markWord dmw = monitor->header(); assert(dmw.is_neutral(), "sanity check: header=" INTPTR_FORMAT, dmw.value()); return; @@ -1401,39 +1417,25 @@ void ObjectSynchronizer::inflate_helper(oop obj) { ObjectMonitor* ObjectSynchronizer::inflate(Thread* current, oop obj, const InflateCause cause) { assert(current == Thread::current(), "must be"); - if (LockingMode == LM_LIGHTWEIGHT && current->is_Java_thread()) { - return inflate_impl(JavaThread::cast(current), obj, cause); - } - return inflate_impl(nullptr, obj, cause); + assert(LockingMode != LM_LIGHTWEIGHT, "only inflate through enter"); + return inflate_impl(obj, cause); } ObjectMonitor* ObjectSynchronizer::inflate_for(JavaThread* thread, oop obj, const InflateCause cause) { assert(thread == Thread::current() || thread->is_obj_deopt_suspend(), "must be"); - return inflate_impl(thread, obj, cause); -} - -ObjectMonitor* ObjectSynchronizer::inflate_impl(JavaThread* inflating_thread, oop object, const InflateCause cause) { - // The JavaThread* inflating_thread parameter is only used by LM_LIGHTWEIGHT and requires - // that the inflating_thread == Thread::current() or is suspended throughout the call by - // some other mechanism. - // Even with LM_LIGHTWEIGHT the thread might be nullptr when called from a non - // JavaThread. (As may still be the case from FastHashCode). However it is only - // important for the correctness of the LM_LIGHTWEIGHT algorithm that the thread - // is set when called from ObjectSynchronizer::enter from the owning thread, - // ObjectSynchronizer::enter_for from any thread, or ObjectSynchronizer::exit. + assert(LockingMode != LM_LIGHTWEIGHT, "LM_LIGHTWEIGHT cannot use inflate_for"); + return inflate_impl(obj, cause); +} + +ObjectMonitor* ObjectSynchronizer::inflate_impl(oop object, const InflateCause cause) { + assert(LockingMode != LM_LIGHTWEIGHT, "LM_LIGHTWEIGHT cannot use inflate_impl"); EventJavaMonitorInflate event; for (;;) { const markWord mark = object->mark_acquire(); // The mark can be in one of the following states: - // * inflated - Just return if using stack-locking. - // If using fast-locking and the ObjectMonitor owner - // is anonymous and the inflating_thread owns the - // object lock, then we make the inflating_thread - // the ObjectMonitor owner and remove the lock from - // the inflating_thread's lock stack. - // * fast-locked - Coerce it to inflated from fast-locked. + // * inflated - Just return it. // * stack-locked - Coerce it to inflated from stack-locked. // * INFLATING - Busy wait for conversion from stack-locked to // inflated. @@ -1444,80 +1446,18 @@ ObjectMonitor* ObjectSynchronizer::inflate_impl(JavaThread* inflating_thread, oo ObjectMonitor* inf = mark.monitor(); markWord dmw = inf->header(); assert(dmw.is_neutral(), "invariant: header=" INTPTR_FORMAT, dmw.value()); - if (LockingMode == LM_LIGHTWEIGHT && inf->is_owner_anonymous() && - inflating_thread != nullptr && inflating_thread->lock_stack().contains(object)) { - inf->set_owner_from_anonymous(inflating_thread); - size_t removed = inflating_thread->lock_stack().remove(object); - inf->set_recursions(removed - 1); - } return inf; } - if (LockingMode != LM_LIGHTWEIGHT) { - // New lightweight locking does not use INFLATING. - // CASE: inflation in progress - inflating over a stack-lock. - // Some other thread is converting from stack-locked to inflated. - // Only that thread can complete inflation -- other threads must wait. - // The INFLATING value is transient. - // Currently, we spin/yield/park and poll the markword, waiting for inflation to finish. - // We could always eliminate polling by parking the thread on some auxiliary list. - if (mark == markWord::INFLATING()) { - read_stable_mark(object); - continue; - } - } - - // CASE: fast-locked - // Could be fast-locked either by the inflating_thread or by some other thread. - // - // Note that we allocate the ObjectMonitor speculatively, _before_ - // attempting to set the object's mark to the new ObjectMonitor. If - // the inflating_thread owns the monitor, then we set the ObjectMonitor's - // owner to the inflating_thread. Otherwise, we set the ObjectMonitor's owner - // to anonymous. If we lose the race to set the object's mark to the - // new ObjectMonitor, then we just delete it and loop around again. - // - LogStreamHandle(Trace, monitorinflation) lsh; - if (LockingMode == LM_LIGHTWEIGHT && mark.is_fast_locked()) { - ObjectMonitor* monitor = new ObjectMonitor(object); - monitor->set_header(mark.set_unlocked()); - bool own = inflating_thread != nullptr && inflating_thread->lock_stack().contains(object); - if (own) { - // Owned by inflating_thread. - monitor->set_owner_from(nullptr, inflating_thread); - } else { - // Owned by somebody else. - monitor->set_owner_anonymous(); - } - markWord monitor_mark = markWord::encode(monitor); - markWord old_mark = object->cas_set_mark(monitor_mark, mark); - if (old_mark == mark) { - // Success! Return inflated monitor. - if (own) { - size_t removed = inflating_thread->lock_stack().remove(object); - monitor->set_recursions(removed - 1); - } - // Once the ObjectMonitor is configured and object is associated - // with the ObjectMonitor, it is safe to allow async deflation: - _in_use_list.add(monitor); - - // Hopefully the performance counters are allocated on distinct - // cache lines to avoid false sharing on MP systems ... - OM_PERFDATA_OP(Inflations, inc()); - if (log_is_enabled(Trace, monitorinflation)) { - ResourceMark rm; - lsh.print_cr("inflate(has_locker): object=" INTPTR_FORMAT ", mark=" - INTPTR_FORMAT ", type='%s'", p2i(object), - object->mark().value(), object->klass()->external_name()); - } - if (event.should_commit()) { - post_monitor_inflate_event(&event, object, cause); - } - return monitor; - } else { - delete monitor; - continue; // Interference -- just retry - } + // CASE: inflation in progress - inflating over a stack-lock. + // Some other thread is converting from stack-locked to inflated. + // Only that thread can complete inflation -- other threads must wait. + // The INFLATING value is transient. + // Currently, we spin/yield/park and poll the markword, waiting for inflation to finish. + // We could always eliminate polling by parking the thread on some auxiliary list. + if (mark == markWord::INFLATING()) { + read_stable_mark(object); + continue; } // CASE: stack-locked @@ -1531,8 +1471,8 @@ ObjectMonitor* ObjectSynchronizer::inflate_impl(JavaThread* inflating_thread, oo // the odds of inflation contention. If we lose the race to set INFLATING, // then we just delete the ObjectMonitor and loop around again. // + LogStreamHandle(Trace, monitorinflation) lsh; if (LockingMode == LM_LEGACY && mark.has_locker()) { - assert(LockingMode != LM_LIGHTWEIGHT, "cannot happen with new lightweight locking"); ObjectMonitor* m = new ObjectMonitor(object); // Optimistically prepare the ObjectMonitor - anticipate successful CAS // We do this before the CAS in order to minimize the length of time @@ -1664,13 +1604,14 @@ ObjectMonitor* ObjectSynchronizer::inflate_impl(JavaThread* inflating_thread, oo size_t ObjectSynchronizer::deflate_monitor_list(ObjectMonitorDeflationSafepointer* safepointer) { MonitorList::Iterator iter = _in_use_list.iterator(); size_t deflated_count = 0; + Thread* current = Thread::current(); while (iter.has_next()) { if (deflated_count >= (size_t)MonitorDeflationMax) { break; } ObjectMonitor* mid = iter.next(); - if (mid->deflate_monitor()) { + if (mid->deflate_monitor(current)) { deflated_count++; } @@ -1688,6 +1629,11 @@ class HandshakeForDeflation : public HandshakeClosure { void do_thread(Thread* thread) { log_trace(monitorinflation)("HandshakeForDeflation::do_thread: thread=" INTPTR_FORMAT, p2i(thread)); + if (thread->is_Java_thread()) { + // Clear OM cache + JavaThread* jt = JavaThread::cast(thread); + jt->om_clear_monitor_cache(); + } } }; @@ -1834,6 +1780,14 @@ size_t ObjectSynchronizer::deflate_idle_monitors() { GrowableArray delete_list((int)deflated_count); unlinked_count = _in_use_list.unlink_deflated(deflated_count, &delete_list, &safepointer); +#ifdef ASSERT + if (UseObjectMonitorTable) { + for (ObjectMonitor* monitor : delete_list) { + assert(!LightweightSynchronizer::contains_monitor(current, monitor), "Should have been removed"); + } + } +#endif + log.before_handshake(unlinked_count); // A JavaThread needs to handshake in order to safely free the @@ -2042,29 +1996,35 @@ void ObjectSynchronizer::chk_in_use_entry(ObjectMonitor* n, outputStream* out, return; } - if (n->header().value() == 0) { + + if (n->metadata() == 0) { out->print_cr("ERROR: monitor=" INTPTR_FORMAT ": in-use monitor must " - "have non-null _header field.", p2i(n)); + "have non-null _metadata (header/hash) field.", p2i(n)); *error_cnt_p = *error_cnt_p + 1; } + const oop obj = n->object_peek(); - if (obj != nullptr) { - const markWord mark = obj->mark(); - if (!mark.has_monitor()) { - out->print_cr("ERROR: monitor=" INTPTR_FORMAT ": in-use monitor's " - "object does not think it has a monitor: obj=" - INTPTR_FORMAT ", mark=" INTPTR_FORMAT, p2i(n), - p2i(obj), mark.value()); - *error_cnt_p = *error_cnt_p + 1; - } - ObjectMonitor* const obj_mon = mark.monitor(); - if (n != obj_mon) { - out->print_cr("ERROR: monitor=" INTPTR_FORMAT ": in-use monitor's " - "object does not refer to the same monitor: obj=" - INTPTR_FORMAT ", mark=" INTPTR_FORMAT ", obj_mon=" - INTPTR_FORMAT, p2i(n), p2i(obj), mark.value(), p2i(obj_mon)); - *error_cnt_p = *error_cnt_p + 1; - } + if (obj == nullptr) { + return; + } + + const markWord mark = obj->mark(); + if (!mark.has_monitor()) { + out->print_cr("ERROR: monitor=" INTPTR_FORMAT ": in-use monitor's " + "object does not think it has a monitor: obj=" + INTPTR_FORMAT ", mark=" INTPTR_FORMAT, p2i(n), + p2i(obj), mark.value()); + *error_cnt_p = *error_cnt_p + 1; + return; + } + + ObjectMonitor* const obj_mon = read_monitor(Thread::current(), obj, mark); + if (n != obj_mon) { + out->print_cr("ERROR: monitor=" INTPTR_FORMAT ": in-use monitor's " + "object does not refer to the same monitor: obj=" + INTPTR_FORMAT ", mark=" INTPTR_FORMAT ", obj_mon=" + INTPTR_FORMAT, p2i(n), p2i(obj), mark.value(), p2i(obj_mon)); + *error_cnt_p = *error_cnt_p + 1; } } @@ -2087,10 +2047,10 @@ void ObjectSynchronizer::log_in_use_monitor_details(outputStream* out, bool log_ monitors_iterate([&](ObjectMonitor* monitor) { if (is_interesting(monitor)) { const oop obj = monitor->object_peek(); - const markWord mark = monitor->header(); + const intptr_t hash = UseObjectMonitorTable ? monitor->hash() : monitor->header().hash(); ResourceMark rm; out->print(INTPTR_FORMAT " %d%d%d " INTPTR_FORMAT " %s", p2i(monitor), - monitor->is_busy(), mark.hash() != 0, monitor->owner() != nullptr, + monitor->is_busy(), hash != 0, monitor->owner() != nullptr, p2i(obj), obj == nullptr ? "" : obj->klass()->external_name()); if (monitor->is_busy()) { out->print(" (%s)", monitor->is_busy_to_string(&ss)); diff --git a/src/hotspot/share/runtime/synchronizer.hpp b/src/hotspot/share/runtime/synchronizer.hpp index 493303df66124..5b171560ee173 100644 --- a/src/hotspot/share/runtime/synchronizer.hpp +++ b/src/hotspot/share/runtime/synchronizer.hpp @@ -29,6 +29,7 @@ #include "oops/markWord.hpp" #include "runtime/basicLock.hpp" #include "runtime/handles.hpp" +#include "runtime/javaThread.hpp" #include "utilities/resourceHash.hpp" template class GrowableArray; @@ -93,8 +94,9 @@ class ObjectSynchronizer : AllStatic { // deoptimization at monitor exit. Hence, it does not take a Handle argument. // This is the "slow path" version of monitor enter and exit. - static void enter(Handle obj, BasicLock* lock, JavaThread* current); - static void exit(oop obj, BasicLock* lock, JavaThread* current); + static inline void enter(Handle obj, BasicLock* lock, JavaThread* current); + static inline void exit(oop obj, BasicLock* lock, JavaThread* current); + // Used to enter a monitor for another thread. This requires that the // locking_thread is suspended, and that entering on a potential // inflated monitor may only contend with deflation. That is the obj being @@ -106,6 +108,9 @@ class ObjectSynchronizer : AllStatic { // inflated monitor enter. static bool enter_fast_impl(Handle obj, BasicLock* lock, JavaThread* locking_thread); + static bool quick_enter_legacy(oop obj, BasicLock* Lock, JavaThread* current); + static void enter_legacy(Handle obj, BasicLock* Lock, JavaThread* current); + static void exit_legacy(oop obj, BasicLock* lock, JavaThread* current); public: // Used only to handle jni locks or other unmatched monitor enter/exit // Internally they will use heavy weight monitor. @@ -118,7 +123,7 @@ class ObjectSynchronizer : AllStatic { static void notifyall(Handle obj, TRAPS); static bool quick_notify(oopDesc* obj, JavaThread* current, bool All); - static bool quick_enter(oop obj, JavaThread* current, BasicLock* Lock); + static inline bool quick_enter(oop obj, BasicLock* Lock, JavaThread* current); // Special internal-use-only method for use by JVM infrastructure // that needs to wait() on a java-level object but that can't risk @@ -132,13 +137,16 @@ class ObjectSynchronizer : AllStatic { private: // Shared implementation between the different LockingMode. - static ObjectMonitor* inflate_impl(JavaThread* thread, oop obj, const InflateCause cause); + static ObjectMonitor* inflate_impl(oop obj, const InflateCause cause); public: // This version is only for internal use static void inflate_helper(oop obj); static const char* inflate_cause_name(const InflateCause cause); + inline static ObjectMonitor* read_monitor(markWord mark); + inline static ObjectMonitor* read_monitor(Thread* current, oop obj, markWord mark); + // Returns the identity hash value for an oop // NOTE: It may cause monitor inflation static intptr_t FastHashCode(Thread* current, oop obj); @@ -200,6 +208,7 @@ class ObjectSynchronizer : AllStatic { private: friend class SynchronizerTest; + friend class LightweightSynchronizer; static MonitorList _in_use_list; static volatile bool _is_async_deflation_requested; diff --git a/src/hotspot/share/runtime/synchronizer.inline.hpp b/src/hotspot/share/runtime/synchronizer.inline.hpp new file mode 100644 index 0000000000000..53a9f99a39eae --- /dev/null +++ b/src/hotspot/share/runtime/synchronizer.inline.hpp @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_RUNTIME_SYNCHRONIZER_INLINE_HPP +#define SHARE_RUNTIME_SYNCHRONIZER_INLINE_HPP + +#include "runtime/synchronizer.hpp" + +#include "runtime/lightweightSynchronizer.hpp" +#include "runtime/safepointVerifiers.hpp" + +inline ObjectMonitor* ObjectSynchronizer::read_monitor(markWord mark) { + return mark.monitor(); +} + +inline ObjectMonitor* ObjectSynchronizer::read_monitor(Thread* current, oop obj, markWord mark) { + if (!UseObjectMonitorTable) { + return read_monitor(mark); + } else { + return LightweightSynchronizer::get_monitor_from_table(current, obj); + } +} + +inline void ObjectSynchronizer::enter(Handle obj, BasicLock* lock, JavaThread* current) { + assert(current == Thread::current(), "must be"); + + if (LockingMode == LM_LIGHTWEIGHT) { + LightweightSynchronizer::enter(obj, lock, current); + } else { + enter_legacy(obj, lock, current); + } +} + +inline bool ObjectSynchronizer::quick_enter(oop obj, BasicLock* lock, JavaThread* current) { + assert(current->thread_state() == _thread_in_Java, "invariant"); + NoSafepointVerifier nsv; + if (obj == nullptr) return false; // Need to throw NPE + + if (obj->klass()->is_value_based()) { + return false; + } + + if (LockingMode == LM_LIGHTWEIGHT) { + return LightweightSynchronizer::quick_enter(obj, lock, current); + } else { + return quick_enter_legacy(obj, lock, current); + } +} + +inline void ObjectSynchronizer::exit(oop object, BasicLock* lock, JavaThread* current) { + current->dec_held_monitor_count(); + + if (LockingMode == LM_LIGHTWEIGHT) { + LightweightSynchronizer::exit(object, current); + } else { + exit_legacy(object, lock, current); + } +} + +#endif // SHARE_RUNTIME_SYNCHRONIZER_INLINE_HPP diff --git a/src/hotspot/share/runtime/vframe.cpp b/src/hotspot/share/runtime/vframe.cpp index ebd5af5b74e6f..58eead692c6fb 100644 --- a/src/hotspot/share/runtime/vframe.cpp +++ b/src/hotspot/share/runtime/vframe.cpp @@ -50,7 +50,7 @@ #include "runtime/signature.hpp" #include "runtime/stackFrameStream.inline.hpp" #include "runtime/stubRoutines.hpp" -#include "runtime/synchronizer.hpp" +#include "runtime/synchronizer.inline.hpp" #include "runtime/vframe.inline.hpp" #include "runtime/vframeArray.hpp" #include "runtime/vframe_hp.hpp" @@ -247,13 +247,16 @@ void javaVFrame::print_lock_info_on(outputStream* st, int frame_count) { markWord mark = monitor->owner()->mark(); // The first stage of async deflation does not affect any field // used by this comparison so the ObjectMonitor* is usable here. - if (mark.has_monitor() && - ( // we have marked ourself as pending on this monitor - mark.monitor() == thread()->current_pending_monitor() || + if (mark.has_monitor()) { + ObjectMonitor* mon = ObjectSynchronizer::read_monitor(current, monitor->owner(), mark); + if (// if the monitor is null we must be in the process of locking + mon == nullptr || + // we have marked ourself as pending on this monitor + mon == thread()->current_pending_monitor() || // we are not the owner of this monitor - !mark.monitor()->is_entered(thread()) - )) { - lock_state = "waiting to lock"; + !mon->is_entered(thread())) { + lock_state = "waiting to lock"; + } } } print_locked_object_class_name(st, Handle(current, monitor->owner()), lock_state); diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index 913f988e48bea..fe9620586be3b 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -777,11 +777,11 @@ /* Monitors */ \ /************/ \ \ - volatile_nonstatic_field(ObjectMonitor, _header, markWord) \ + volatile_nonstatic_field(ObjectMonitor, _metadata, uintptr_t) \ unchecked_nonstatic_field(ObjectMonitor, _object, sizeof(void *)) /* NOTE: no type */ \ unchecked_nonstatic_field(ObjectMonitor, _owner, sizeof(void *)) /* NOTE: no type */ \ volatile_nonstatic_field(ObjectMonitor, _next_om, ObjectMonitor*) \ - volatile_nonstatic_field(BasicLock, _displaced_header, markWord) \ + volatile_nonstatic_field(BasicLock, _metadata, uintptr_t) \ nonstatic_field(ObjectMonitor, _contentions, int) \ volatile_nonstatic_field(ObjectMonitor, _waiters, int) \ volatile_nonstatic_field(ObjectMonitor, _recursions, intx) \ diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Mark.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Mark.java index 7512257a197a3..a3a06ec73f5f8 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Mark.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Mark.java @@ -156,6 +156,16 @@ public ObjectMonitor monitor() { if (Assert.ASSERTS_ENABLED) { Assert.that(hasMonitor(), "check"); } + if (VM.getVM().getCommandLineFlag("UseObjectMonitorTable").getBool()) { + Iterator it = ObjectSynchronizer.objectMonitorIterator(); + while (it != null && it.hasNext()) { + ObjectMonitor mon = (ObjectMonitor)it.next(); + if (getAddress().equals(mon.object())) { + return mon; + } + } + return null; + } // Use xor instead of &~ to provide one extra tag-bit check. Address monAddr = valueAsAddress().xorWithMask(monitorValue); return new ObjectMonitor(monAddr); diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/BasicLock.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/BasicLock.java index 55e5d0e45987c..4028bae3f5b4f 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/BasicLock.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/BasicLock.java @@ -43,7 +43,7 @@ public void update(Observable o, Object data) { private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { Type type = db.lookupType("BasicLock"); - displacedHeaderField = type.getCIntegerField("_displaced_header"); + displacedHeaderField = type.getCIntegerField("_metadata"); } private static CIntegerField displacedHeaderField; diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ObjectMonitor.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ObjectMonitor.java index 3f3c67fbf26ef..e16982ce43417 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ObjectMonitor.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ObjectMonitor.java @@ -45,8 +45,8 @@ private static synchronized void initialize(TypeDataBase db) throws WrongTypeExc heap = VM.getVM().getObjectHeap(); Type type = db.lookupType("ObjectMonitor"); - sun.jvm.hotspot.types.Field f = type.getField("_header"); - headerFieldOffset = f.getOffset(); + sun.jvm.hotspot.types.Field f = type.getField("_metadata"); + metadataFieldOffset = f.getOffset(); f = type.getField("_object"); objectFieldOffset = f.getOffset(); f = type.getField("_owner"); @@ -65,7 +65,7 @@ public ObjectMonitor(Address addr) { } public Mark header() { - return new Mark(addr.addOffsetTo(headerFieldOffset)); + return new Mark(addr.addOffsetTo(metadataFieldOffset)); } // FIXME @@ -114,7 +114,7 @@ public int contentions() { // vmStructs.cpp because they aren't strongly typed in the VM, or // would confuse the SA's type system. private static ObjectHeap heap; - private static long headerFieldOffset; + private static long metadataFieldOffset; private static long objectFieldOffset; private static long ownerFieldOffset; private static long nextOMFieldOffset; diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ObjectSynchronizer.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ObjectSynchronizer.java index f8e71aa3761b7..a9c97e06a4456 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ObjectSynchronizer.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ObjectSynchronizer.java @@ -55,6 +55,9 @@ public long identityHashValueFor(Oop obj) { // FIXME: can not generate marks in debugging system return mark.hash(); } else if (mark.hasMonitor()) { + if (VM.getVM().getCommandLineFlag("UseObjectMonitorTable").getBool()) { + return mark.hash(); + } ObjectMonitor monitor = mark.monitor(); Mark temp = monitor.header(); return temp.hash(); diff --git a/test/hotspot/gtest/runtime/test_objectMonitor.cpp b/test/hotspot/gtest/runtime/test_objectMonitor.cpp index 62eeba1587aa5..fcdb102fcf7be 100644 --- a/test/hotspot/gtest/runtime/test_objectMonitor.cpp +++ b/test/hotspot/gtest/runtime/test_objectMonitor.cpp @@ -27,20 +27,20 @@ #include "unittest.hpp" TEST_VM(ObjectMonitor, sanity) { - uint cache_line_size = VM_Version::L1_data_cache_line_size(); + uint cache_line_size = VM_Version::L1_data_cache_line_size(); - if (cache_line_size != 0) { - // We were able to determine the L1 data cache line size so - // do some cache line specific sanity checks - EXPECT_EQ((size_t) 0, sizeof (PaddedEnd) % cache_line_size) - << "PaddedEnd size is not a " - << "multiple of a cache line which permits false sharing. " - << "sizeof(PaddedEnd) = " - << sizeof (PaddedEnd) - << "; cache_line_size = " << cache_line_size; + if (cache_line_size != 0) { - EXPECT_GE((size_t) in_bytes(ObjectMonitor::owner_offset()), cache_line_size) - << "the _header and _owner fields are closer " + EXPECT_EQ(in_bytes(ObjectMonitor::metadata_offset()), 0) + << "_metadata at a non 0 offset. metadata_offset = " + << in_bytes(ObjectMonitor::metadata_offset()); + + EXPECT_GE((size_t) in_bytes(ObjectMonitor::owner_offset()), cache_line_size) + << "the _metadata and _owner fields are closer " + << "than a cache line which permits false sharing."; + + EXPECT_GE((size_t) in_bytes(ObjectMonitor::recursions_offset() - ObjectMonitor::owner_offset()), cache_line_size) + << "the _owner and _recursions fields are closer " << "than a cache line which permits false sharing."; } } diff --git a/test/hotspot/jtreg/runtime/Monitor/UseObjectMonitorTableTest.java b/test/hotspot/jtreg/runtime/Monitor/UseObjectMonitorTableTest.java new file mode 100644 index 0000000000000..6af1602e3380b --- /dev/null +++ b/test/hotspot/jtreg/runtime/Monitor/UseObjectMonitorTableTest.java @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test id=NormalDeflation + * @summary A collection of small tests using synchronized, wait, notify to try + * and achieve good cheap coverage of UseObjectMonitorTable. + * @library /test/lib + * @run main/othervm -XX:+UnlockDiagnosticVMOptions + * -XX:+UseObjectMonitorTable + * UseObjectMonitorTableTest + */ + +/** + * @test id=ExtremeDeflation + * @summary Run the same tests but with deflation running constantly. + * @library /test/lib + * @run main/othervm -XX:+UnlockDiagnosticVMOptions + * -XX:GuaranteedAsyncDeflationInterval=1 + * -XX:+UseObjectMonitorTable + * UseObjectMonitorTableTest + */ + +import jdk.test.lib.Utils; + +import java.lang.Runnable; +import java.util.concurrent.BrokenBarrierException; +import java.util.concurrent.CyclicBarrier; +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadFactory; +import java.util.Random; +import java.util.stream.Stream; + +public class UseObjectMonitorTableTest { + static final ThreadFactory TF = Executors.defaultThreadFactory(); + + static class WaitNotifyTest implements Runnable { + static final int ITERATIONS = 10_000; + static final int THREADS = 10; + final WaitNotifySyncChannel startLatchChannel = new WaitNotifySyncChannel(); + final WaitNotifySyncChannel endLatchChannel = new WaitNotifySyncChannel(); + int count = 0; + + static class WaitNotifyCountDownLatch { + int latch; + WaitNotifyCountDownLatch(int count) { + latch = count; + } + synchronized void await() { + while (latch != 0) { + try { + wait(); + } catch (InterruptedException e) { + throw new RuntimeException("WaitNotifyTest: Unexpected interrupt", e); + } + } + } + synchronized void countDown() { + if (latch != 0) { + latch--; + if (latch == 0) { + notifyAll(); + } + } + } + } + static class WaitNotifySyncChannel extends WaitNotifyCountDownLatch { + WaitNotifyCountDownLatch object; + WaitNotifySyncChannel() { super(0); } + synchronized void send(WaitNotifyCountDownLatch object, int count) { + await(); + latch = count; + this.object = object; + notifyAll(); + } + synchronized WaitNotifyCountDownLatch receive() { + while (latch == 0) { + try { + wait(); + } catch (InterruptedException e) { + throw new RuntimeException("WaitNotifyTest: Unexpected interrupt", e); + } + } + countDown(); + return object; + } + } + synchronized int getCount() { + return count; + } + synchronized void increment() { + count++; + } + public void run() { + System.out.println("WaitNotifyTest started."); + for (int t = 0; t < THREADS; t++) { + TF.newThread(() -> { + for (int i = 0; i < ITERATIONS; i++) { + startLatchChannel.receive().await(); + increment(); + endLatchChannel.receive().countDown(); + } + }).start(); + } + for (int i = 0; i < ITERATIONS; i++) { + WaitNotifyCountDownLatch startLatch = new WaitNotifyCountDownLatch(1); + WaitNotifyCountDownLatch endLatch = new WaitNotifyCountDownLatch(THREADS); + int count = getCount(); + if (count != i * THREADS) { + throw new RuntimeException("WaitNotifyTest: Invalid Count " + count + + " pre-iteration " + i); + } + startLatchChannel.send(startLatch, 10); + startLatch.countDown(); + endLatchChannel.send(endLatch, 10); + endLatch.await(); + } + int count = getCount(); + if (count != ITERATIONS * THREADS) { + throw new RuntimeException("WaitNotifyTest: Invalid Count " + count); + } + System.out.println("WaitNotifyTest passed."); + } + } + + static class RandomDepthTest implements Runnable { + static final int THREADS = 10; + static final int ITERATIONS = 10_000; + static final int MAX_DEPTH = 20; + static final int MAX_RECURSION_COUNT = 10; + static final double RECURSION_CHANCE = .25; + final Random random = Utils.getRandomInstance(); + final Locker lockers[] = new Locker[MAX_DEPTH]; + final CyclicBarrier syncBarrier = new CyclicBarrier(THREADS + 1); + int count = 0; + + class Locker { + final int depth; + Locker(int depth) { + this.depth = depth; + } + synchronized int getCount() { + if (depth == MAX_DEPTH) { + return count; + } + return lockers[depth].getCount(); + } + synchronized void increment(int recursion_count) { + if (recursion_count != MAX_RECURSION_COUNT && + random.nextDouble() < RECURSION_CHANCE) { + this.increment(recursion_count + 1); + return; + } + if (depth == MAX_DEPTH) { + count++; + return; + } + lockers[depth + random.nextInt(MAX_DEPTH - depth)].increment(recursion_count); + } + synchronized Locker create() { + if (depth != MAX_DEPTH) { + lockers[depth] = (new Locker(depth + 1)).create(); + } + return this; + } + } + int getCount() { + return lockers[0].getCount(); + } + void increment() { + lockers[random.nextInt(MAX_DEPTH)].increment(0); + } + void create() { + lockers[0] = (new Locker(1)).create(); + } + void syncPoint() { + try { + syncBarrier.await(); + } catch (InterruptedException e) { + throw new RuntimeException("RandomDepthTest: Unexpected interrupt", e); + } catch (BrokenBarrierException e) { + throw new RuntimeException("RandomDepthTest: Unexpected broken barrier", e); + } + } + public void run() { + System.out.println("RandomDepthTest started."); + for (int t = 0; t < THREADS; t++) { + TF.newThread(() -> { + syncPoint(); + for (int i = 0; i < ITERATIONS; i++) { + increment(); + } + syncPoint(); + }).start(); + } + create(); + syncPoint(); + syncPoint(); + int count = getCount(); + if (count != THREADS * ITERATIONS) { + throw new RuntimeException("RandomDepthTest: Invalid Count " + count); + } + System.out.println("RandomDepthTest passed."); + } + } + + public static void main(String[] args) { + Stream.of( + TF.newThread(new WaitNotifyTest()), + TF.newThread(new RandomDepthTest()) + ).map(t -> { + t.start(); + return t; + }).forEach(t -> { + try { + t.join(); + } catch (InterruptedException e) { + throw new RuntimeException("UseObjectMonitorTableTest: Unexpected interrupt", e); + } + }); + + System.out.println("UseObjectMonitorTableTest passed."); + } +} diff --git a/test/hotspot/jtreg/runtime/logging/MonitorInflationTest.java b/test/hotspot/jtreg/runtime/logging/MonitorInflationTest.java index 737c64621e8ca..8666e2ee774a6 100644 --- a/test/hotspot/jtreg/runtime/logging/MonitorInflationTest.java +++ b/test/hotspot/jtreg/runtime/logging/MonitorInflationTest.java @@ -38,7 +38,7 @@ public class MonitorInflationTest { static void analyzeOutputOn(ProcessBuilder pb) throws Exception { OutputAnalyzer output = new OutputAnalyzer(pb.start()); - output.shouldContain("inflate(has_locker):"); + output.shouldContain("inflate:"); output.shouldContain("type='MonitorInflationTest$Waiter'"); output.shouldContain("I've been waiting."); output.shouldHaveExitValue(0); diff --git a/test/micro/org/openjdk/bench/vm/lang/LockUnlock.java b/test/micro/org/openjdk/bench/vm/lang/LockUnlock.java index 49181971768fe..3ed862e8218cd 100644 --- a/test/micro/org/openjdk/bench/vm/lang/LockUnlock.java +++ b/test/micro/org/openjdk/bench/vm/lang/LockUnlock.java @@ -54,6 +54,8 @@ public class LockUnlock { public Object lockObject1; public Object lockObject2; + public volatile Object lockObject3Inflated; + public volatile Object lockObject4Inflated; public int factorial; public int dummyInt1; public int dummyInt2; @@ -62,13 +64,28 @@ public class LockUnlock { public void setup() { lockObject1 = new Object(); lockObject2 = new Object(); + lockObject3Inflated = new Object(); + lockObject4Inflated = new Object(); + + // Inflate the lock to use an ObjectMonitor + try { + synchronized (lockObject3Inflated) { + lockObject3Inflated.wait(1); + } + synchronized (lockObject4Inflated) { + lockObject4Inflated.wait(1); + } + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + dummyInt1 = 47; dummyInt2 = 11; // anything } /** Perform a synchronized on a local object within a loop. */ @Benchmark - public void testSimpleLockUnlock() { + public void testBasicSimpleLockUnlockLocal() { Object localObject = lockObject1; for (int i = 0; i < innerCount; i++) { synchronized (localObject) { @@ -78,9 +95,43 @@ public void testSimpleLockUnlock() { } } + /** Perform a synchronized on an object within a loop. */ + @Benchmark + public void testBasicSimpleLockUnlock() { + for (int i = 0; i < innerCount; i++) { + synchronized (lockObject1) { + dummyInt1++; + dummyInt2++; + } + } + } + + /** Perform a synchronized on a local object within a loop. */ + @Benchmark + public void testInflatedSimpleLockUnlockLocal() { + Object localObject = lockObject3Inflated; + for (int i = 0; i < innerCount; i++) { + synchronized (localObject) { + dummyInt1++; + dummyInt2++; + } + } + } + + /** Perform a synchronized on an object within a loop. */ + @Benchmark + public void testInflatedSimpleLockUnlock() { + for (int i = 0; i < innerCount; i++) { + synchronized (lockObject3Inflated) { + dummyInt1++; + dummyInt2++; + } + } + } + /** Perform a recursive synchronized on a local object within a loop. */ @Benchmark - public void testRecursiveLockUnlock() { + public void testBasicRecursiveLockUnlockLocal() { Object localObject = lockObject1; for (int i = 0; i < innerCount; i++) { synchronized (localObject) { @@ -92,9 +143,22 @@ public void testRecursiveLockUnlock() { } } + /** Perform a recursive synchronized on an object within a loop. */ + @Benchmark + public void testBasicRecursiveLockUnlock() { + for (int i = 0; i < innerCount; i++) { + synchronized (lockObject1) { + synchronized (lockObject1) { + dummyInt1++; + dummyInt2++; + } + } + } + } + /** Perform two synchronized after each other on the same local object. */ @Benchmark - public void testSerialLockUnlock() { + public void testBasicSerialLockUnlockLocal() { Object localObject = lockObject1; for (int i = 0; i < innerCount; i++) { synchronized (localObject) { @@ -106,6 +170,126 @@ public void testSerialLockUnlock() { } } + /** Perform two synchronized after each other on the same object. */ + @Benchmark + public void testBasicSerialLockUnlock() { + for (int i = 0; i < innerCount; i++) { + synchronized (lockObject1) { + dummyInt1++; + } + synchronized (lockObject1) { + dummyInt2++; + } + } + } + + /** Perform two synchronized after each other on the same local object. */ + @Benchmark + public void testInflatedSerialLockUnlockLocal() { + Object localObject = lockObject3Inflated; + for (int i = 0; i < innerCount; i++) { + synchronized (localObject) { + dummyInt1++; + } + synchronized (localObject) { + dummyInt2++; + } + } + } + + /** Perform two synchronized after each other on the same object. */ + @Benchmark + public void testInflatedSerialLockUnlock() { + for (int i = 0; i < innerCount; i++) { + synchronized (lockObject3Inflated) { + dummyInt1++; + } + synchronized (lockObject3Inflated) { + dummyInt2++; + } + } + } + + /** Perform two synchronized after each other on the same object. */ + @Benchmark + public void testInflatedMultipleSerialLockUnlock() { + for (int i = 0; i < innerCount; i++) { + synchronized (lockObject3Inflated) { + dummyInt1++; + } + synchronized (lockObject4Inflated) { + dummyInt2++; + } + } + } + + /** Perform two synchronized after each other on the same object. */ + @Benchmark + public void testInflatedMultipleRecursiveLockUnlock() { + for (int i = 0; i < innerCount; i++) { + synchronized (lockObject3Inflated) { + dummyInt1++; + synchronized (lockObject4Inflated) { + dummyInt2++; + } + } + } + } + + /** Perform a recursive-only synchronized on a local object within a loop. */ + @Benchmark + public void testInflatedRecursiveOnlyLockUnlockLocal() { + Object localObject = lockObject3Inflated; + synchronized (localObject) { + for (int i = 0; i < innerCount; i++) { + synchronized (localObject) { + dummyInt1++; + dummyInt2++; + } + } + } + } + + /** Perform a recursive-only synchronized on an object within a loop. */ + @Benchmark + public void testInflatedRecursiveOnlyLockUnlock() { + synchronized (lockObject3Inflated) { + for (int i = 0; i < innerCount; i++) { + synchronized (lockObject3Inflated) { + dummyInt1++; + dummyInt2++; + } + } + } + } + + /** Perform a recursive-only synchronized on a local object within a loop. */ + @Benchmark + public void testInflatedRecursiveLockUnlockLocal() { + Object localObject = lockObject3Inflated; + for (int i = 0; i < innerCount; i++) { + synchronized (localObject) { + synchronized (localObject) { + dummyInt1++; + dummyInt2++; + } + } + } + } + + /** Perform a recursive-only synchronized on an object within a loop. */ + @Benchmark + public void testInflatedRecursiveLockUnlock() { + for (int i = 0; i < innerCount; i++) { + synchronized (lockObject3Inflated) { + synchronized (lockObject3Inflated) { + dummyInt1++; + dummyInt2++; + } + } + } + } + /** * Performs recursive synchronizations on the same local object. *

    From 60c9b5cd9f18830f0fb1aea6cb3dc43af3908cc5 Mon Sep 17 00:00:00 2001 From: Andrey Turbanov Date: Fri, 16 Aug 2024 08:49:18 +0000 Subject: [PATCH 328/353] 8337839: Make a few fields in MergeCollation static Reviewed-by: jpai, naoto --- src/java.base/share/classes/java/text/MergeCollation.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/java.base/share/classes/java/text/MergeCollation.java b/src/java.base/share/classes/java/text/MergeCollation.java index 1db779e003f60..8cac7871b56a5 100644 --- a/src/java.base/share/classes/java/text/MergeCollation.java +++ b/src/java.base/share/classes/java/text/MergeCollation.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -220,9 +220,9 @@ public PatternEntry getItemAt(int index) { // Using BitSet would make this easier, but it's significantly slower. // private transient byte[] statusArray = new byte[8192]; - private final byte BITARRAYMASK = (byte)0x1; - private final int BYTEPOWER = 3; - private final int BYTEMASK = (1 << BYTEPOWER) - 1; + private static final byte BITARRAYMASK = (byte)0x1; + private static final int BYTEPOWER = 3; + private static final int BYTEMASK = (1 << BYTEPOWER) - 1; /* If the strength is RESET, then just change the lastEntry to From ddbc0b6a39148cb30a8fda80fa7290e90e2a77d6 Mon Sep 17 00:00:00 2001 From: Daniel Fuchs Date: Fri, 16 Aug 2024 11:24:40 +0000 Subject: [PATCH 329/353] 8338495: Revert "8336655: java/net/httpclient/DigestEchoClient.java IOException: HTTP/1.1 header parser received no bytes" Reviewed-by: jpai --- .../jdk/internal/net/http/ConnectionPool.java | 36 ++++--------------- .../jdk/internal/net/http/SocketTube.java | 23 ++---------- .../java/net/httpclient/DigestEchoClient.java | 4 +-- 3 files changed, 11 insertions(+), 52 deletions(-) diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/ConnectionPool.java b/src/java.net.http/share/classes/jdk/internal/net/http/ConnectionPool.java index edaf53a8a0ddf..0ad7b9d5992c0 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/ConnectionPool.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/ConnectionPool.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,7 +44,6 @@ import jdk.internal.net.http.common.Deadline; import jdk.internal.net.http.common.FlowTube; -import jdk.internal.net.http.common.Log; import jdk.internal.net.http.common.Logger; import jdk.internal.net.http.common.TimeLine; import jdk.internal.net.http.common.TimeSource; @@ -493,13 +492,13 @@ void clear() { // Remove a connection from the pool. // should only be called while holding the ConnectionPool stateLock. - private boolean removeFromPool(HttpConnection c) { + private void removeFromPool(HttpConnection c) { assert stateLock.isHeldByCurrentThread(); if (c instanceof PlainHttpConnection) { - return removeFromPool(c, plainPool); + removeFromPool(c, plainPool); } else { assert c.isSecure() : "connection " + c + " is not secure!"; - return removeFromPool(c, sslPool); + removeFromPool(c, sslPool); } } @@ -530,29 +529,13 @@ void cleanup(HttpConnection c, Throwable error) { debug.log("%s : ConnectionPool.cleanup(%s)", String.valueOf(c.getConnectionFlow()), error); stateLock.lock(); - boolean removed; try { - removed = removeFromPool(c); + removeFromPool(c); expiryList.remove(c); } finally { stateLock.unlock(); } - if (!removed) { - // this should not happen; the cleanup may have consumed - // some data that wasn't supposed to be consumed, so - // the only thing we can do is log it and close the - // connection. - if (Log.errors()) { - Log.logError("WARNING: CleanupTrigger triggered for" + - " a connection not found in the pool: closing {0}", c); - } else if (debug.on()) { - debug.log("WARNING: CleanupTrigger triggered for" + - " a connection not found in the pool: closing %s", c); - } - c.close(new IOException("Unexpected cleanup triggered for non pooled connection")); - } else { - c.close(); - } + c.close(); } /** @@ -566,7 +549,6 @@ private final class CleanupTrigger implements private final HttpConnection connection; private volatile boolean done; - private volatile boolean dropped; public CleanupTrigger(HttpConnection connection) { this.connection = connection; @@ -584,7 +566,6 @@ private void triggerCleanup(Throwable error) { @Override public void onSubscribe(Flow.Subscription subscription) { - if (dropped || done) return; subscription.request(1); } @Override @@ -605,10 +586,5 @@ public void subscribe(Flow.Subscriber> subscriber) { public String toString() { return "CleanupTrigger(" + connection.getConnectionFlow() + ")"; } - - @Override - public void dropSubscription() { - dropped = true; - } } } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/SocketTube.java b/src/java.net.http/share/classes/jdk/internal/net/http/SocketTube.java index 9317bdf442a51..cbdf663357603 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/SocketTube.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/SocketTube.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -573,8 +573,6 @@ public void subscribe(Flow.Subscriber> s) { debug.log("read publisher: dropping pending subscriber: " + previous.subscriber); previous.errorRef.compareAndSet(null, errorRef.get()); - // make sure no data will be routed to the old subscriber. - previous.stopReading(); previous.signalOnSubscribe(); if (subscriptionImpl.completed) { previous.signalCompletion(); @@ -608,7 +606,6 @@ final class ReadSubscription implements Flow.Subscription { volatile boolean subscribed; volatile boolean cancelled; volatile boolean completed; - volatile boolean stopped; public ReadSubscription(InternalReadSubscription impl, TubeSubscriber subscriber) { @@ -626,11 +623,11 @@ public void cancel() { @Override public void request(long n) { - if (!cancelled && !stopped) { + if (!cancelled) { impl.request(n); } else { if (debug.on()) - debug.log("subscription stopped or cancelled, ignoring request %d", n); + debug.log("subscription cancelled, ignoring request %d", n); } } @@ -664,20 +661,6 @@ void signalOnSubscribe() { signalCompletion(); } } - - /** - * Called when switching subscriber on the {@link InternalReadSubscription}. - * This subscriber is the old subscriber. Demand on the internal - * subscription will be reset and reading will be paused until the - * new subscriber is subscribed. - * This should ensure that no data is routed to this subscriber - * until the new subscriber is subscribed. - */ - void stopReading() { - stopped = true; - impl.demand.reset(); - impl.pauseReadEvent(); - } } final class InternalReadSubscription implements Flow.Subscription { diff --git a/test/jdk/java/net/httpclient/DigestEchoClient.java b/test/jdk/java/net/httpclient/DigestEchoClient.java index 1450bf09b2d6b..3b6d1a1773f8d 100644 --- a/test/jdk/java/net/httpclient/DigestEchoClient.java +++ b/test/jdk/java/net/httpclient/DigestEchoClient.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -64,7 +64,7 @@ * @test * @summary this test verifies that a client may provides authorization * headers directly when connecting with a server. - * @bug 8087112 8336655 + * @bug 8087112 * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.httpclient.test.lib.common.HttpServerAdapters jdk.test.lib.net.SimpleSSLContext * DigestEchoServer ReferenceTracker DigestEchoClient From 5022109b2a33a8cf2608eb829098b27641b731a4 Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Fri, 16 Aug 2024 13:18:02 +0000 Subject: [PATCH 330/353] 8336856: Efficient hidden class-based string concatenation strategy Co-authored-by: Claes Redestad Reviewed-by: redestad, liach --- .../classes/java/lang/StringConcatHelper.java | 343 ++++++++ .../share/classes/java/lang/System.java | 4 + .../java/lang/invoke/StringConcatFactory.java | 762 +++++++++++++++--- .../jdk/internal/access/JavaLangAccess.java | 2 + .../jdk/internal/util/ClassFileDumper.java | 9 +- .../String/concat/HiddenClassUnloading.java | 69 ++ .../openjdk/bench/java/lang/StringConcat.java | 149 +++- .../bench/java/lang/StringConcatStartup.java | 111 ++- 8 files changed, 1316 insertions(+), 133 deletions(-) create mode 100644 test/jdk/java/lang/String/concat/HiddenClassUnloading.java diff --git a/src/java.base/share/classes/java/lang/StringConcatHelper.java b/src/java.base/share/classes/java/lang/StringConcatHelper.java index 486e115369ea6..ae2b969340905 100644 --- a/src/java.base/share/classes/java/lang/StringConcatHelper.java +++ b/src/java.base/share/classes/java/lang/StringConcatHelper.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, Alibaba Group Holding Limited. All Rights Reserved. * 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 +29,7 @@ import jdk.internal.misc.Unsafe; import jdk.internal.util.DecimalDigits; import jdk.internal.vm.annotation.ForceInline; +import jdk.internal.vm.annotation.Stable; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; @@ -39,6 +41,98 @@ * combinators there. */ final class StringConcatHelper { + static abstract class StringConcatBase { + @Stable + final String[] constants; + final int length; + final byte coder; + + StringConcatBase(String[] constants) { + int length = 0; + byte coder = String.LATIN1; + for (String c : constants) { + length += c.length(); + coder |= c.coder(); + } + this.constants = constants; + this.length = length; + this.coder = coder; + } + } + + static final class Concat1 extends StringConcatBase { + Concat1(String[] constants) { + super(constants); + } + + @ForceInline + String concat0(String value) { + int length = stringSize(this.length, value); + byte coder = (byte) (this.coder | value.coder()); + byte[] buf = newArray(length << coder); + String prefix = constants[0]; + prefix.getBytes(buf, 0, coder); + value.getBytes(buf, prefix.length(), coder); + constants[1].getBytes(buf, prefix.length() + value.length(), coder); + return new String(buf, coder); + } + + @ForceInline + String concat(boolean value) { + int length = stringSize(this.length, value); + String suffix = constants[1]; + length -= suffix.length(); + byte[] buf = newArrayWithSuffix(suffix, length, coder); + prepend(length, coder, buf, value, constants[0]); + return new String(buf, coder); + } + + @ForceInline + String concat(char value) { + int length = stringSize(this.length, value); + byte coder = (byte) (this.coder | stringCoder(value)); + String suffix = constants[1]; + length -= suffix.length(); + byte[] buf = newArrayWithSuffix(suffix, length, coder); + prepend(length, coder, buf, value, constants[0]); + return new String(buf, coder); + } + + @ForceInline + String concat(int value) { + int length = stringSize(this.length, value); + String suffix = constants[1]; + length -= suffix.length(); + byte[] buf = newArrayWithSuffix(suffix, length, coder); + prepend(length, coder, buf, value, constants[0]); + return new String(buf, coder); + } + + @ForceInline + String concat(long value) { + int length = stringSize(this.length, value); + String suffix = constants[1]; + length -= suffix.length(); + byte[] buf = newArrayWithSuffix(suffix, length, coder); + prepend(length, coder, buf, value, constants[0]); + return new String(buf, coder); + } + + @ForceInline + String concat(Object value) { + return concat0(stringOf(value)); + } + + @ForceInline + String concat(float value) { + return concat0(Float.toString(value)); + } + + @ForceInline + String concat(double value) { + return concat0(Double.toString(value)); + } + } private StringConcatHelper() { // no instantiation @@ -375,6 +469,64 @@ static String stringOf(Object value) { private static final Unsafe UNSAFE = Unsafe.getUnsafe(); + static String stringOf(float value) { + return Float.toString(value); + } + + static String stringOf(double value) { + return Double.toString(value); + } + + /** + * return add stringSize of value + * @param length length + * @param value value to add stringSize + * @return new length + */ + static int stringSize(int length, char value) { + return checkOverflow(length + 1); + } + + /** + * return add stringSize of value + * @param length length + * @param value value to add stringSize + * @return new length + */ + static int stringSize(int length, boolean value) { + return checkOverflow(length + (value ? 4 : 5)); + } + + /** + * return add stringSize of value + * @param length length + * @param value value + * @return new length + */ + static int stringSize(int length, int value) { + return checkOverflow(length + DecimalDigits.stringSize(value)); + } + + /** + * return add stringSize of value + * @param length length + * @param value value to add stringSize + * @return new length + */ + static int stringSize(int length, long value) { + return checkOverflow(length + DecimalDigits.stringSize(value)); + } + + /** + * return add stringSize of value + * @param length length + * @param value value to add stringSize + * @return new length + */ + static int stringSize(int length, String value) { + return checkOverflow(length + value.length()); + } + /** * Allocates an uninitialized byte array based on the length and coder * information, then prepends the given suffix string at the end of the @@ -440,4 +592,195 @@ static MethodHandle lookupStatic(String name, MethodType methodType) { } } + /** + * Allocates an uninitialized byte array based on the length and coder + * information, then prepends the given suffix string at the end of the + * byte array before returning it. The calling code must adjust the + * indexCoder so that it's taken the coder of the suffix into account, but + * subtracted the length of the suffix. + * + * @param suffix + * @param indexCoder + * @return the newly allocated byte array + */ + @ForceInline + static byte[] newArrayWithSuffix(String suffix, int index, byte coder) { + byte[] buf = newArray((index + suffix.length()) << coder); + if (coder == String.LATIN1) { + suffix.getBytes(buf, index, String.LATIN1); + } else { + suffix.getBytes(buf, index, String.UTF16); + } + return buf; + } + + /** + * Return the coder for the character. + * @param value character + * @return coder + */ + static byte stringCoder(char value) { + return StringLatin1.canEncode(value) ? String.LATIN1 : String.UTF16; + } + + /** + * Prepends constant and the stringly representation of value into buffer, + * given the coder and final index. Index is measured in chars, not in bytes! + * + * @param index final char index in the buffer + * @param coder coder of the buffer + * @param buf buffer to append to + * @param value boolean value to encode + * @param prefix a constant to prepend before value + * @return updated index + */ + static int prepend(int index, byte coder, byte[] buf, boolean value, String prefix) { + if (coder == String.LATIN1) { + if (value) { + index -= 4; + buf[index] = 't'; + buf[index + 1] = 'r'; + buf[index + 2] = 'u'; + buf[index + 3] = 'e'; + } else { + index -= 5; + buf[index] = 'f'; + buf[index + 1] = 'a'; + buf[index + 2] = 'l'; + buf[index + 3] = 's'; + buf[index + 4] = 'e'; + } + index -= prefix.length(); + prefix.getBytes(buf, index, String.LATIN1); + } else { + if (value) { + index -= 4; + StringUTF16.putChar(buf, index, 't'); + StringUTF16.putChar(buf, index + 1, 'r'); + StringUTF16.putChar(buf, index + 2, 'u'); + StringUTF16.putChar(buf, index + 3, 'e'); + } else { + index -= 5; + StringUTF16.putChar(buf, index, 'f'); + StringUTF16.putChar(buf, index + 1, 'a'); + StringUTF16.putChar(buf, index + 2, 'l'); + StringUTF16.putChar(buf, index + 3, 's'); + StringUTF16.putChar(buf, index + 4, 'e'); + } + index -= prefix.length(); + prefix.getBytes(buf, index, String.UTF16); + } + return index; + } + + /** + * Prepends constant and the stringly representation of value into buffer, + * given the coder and final index. Index is measured in chars, not in bytes! + * + * @param index final char index in the buffer + * @param coder coder of the buffer + * @param buf buffer to append to + * @param value char value to encode + * @param prefix a constant to prepend before value + * @return updated index + */ + static int prepend(int index, byte coder, byte[] buf, char value, String prefix) { + if (coder == String.LATIN1) { + buf[--index] = (byte) (value & 0xFF); + index -= prefix.length(); + prefix.getBytes(buf, index, String.LATIN1); + } else { + StringUTF16.putChar(buf, --index, value); + index -= prefix.length(); + prefix.getBytes(buf, index, String.UTF16); + } + return index; + } + + /** + * Prepends constant and the stringly representation of value into buffer, + * given the coder and final index. Index is measured in chars, not in bytes! + * + * @param index final char index in the buffer + * @param coder coder of the buffer + * @param buf buffer to append to + * @param value int value to encode + * @param prefix a constant to prepend before value + * @return updated index + */ + static int prepend(int index, byte coder, byte[] buf, int value, String prefix) { + if (coder == String.LATIN1) { + index = StringLatin1.getChars(value, index, buf); + index -= prefix.length(); + prefix.getBytes(buf, index, String.LATIN1); + } else { + index = StringUTF16.getChars(value, index, buf); + index -= prefix.length(); + prefix.getBytes(buf, index, String.UTF16); + } + return index; + } + + /** + * Prepends constant and the stringly representation of value into buffer, + * given the coder and final index. Index is measured in chars, not in bytes! + * + * @param index final char index in the buffer + * @param coder coder of the buffer + * @param buf buffer to append to + * @param value long value to encode + * @param prefix a constant to prepend before value + * @return updated index + */ + static int prepend(int index, byte coder, byte[] buf, long value, String prefix) { + if (coder == String.LATIN1) { + index = StringLatin1.getChars(value, index, buf); + index -= prefix.length(); + prefix.getBytes(buf, index, String.LATIN1); + } else { + index = StringUTF16.getChars(value, index, buf); + index -= prefix.length(); + prefix.getBytes(buf, index, String.UTF16); + } + return index; + } + + /** + * Prepends constant and the stringly representation of value into buffer, + * given the coder and final index. Index is measured in chars, not in bytes! + * + * @param index final char index in the buffer + * @param coder coder of the buffer + * @param buf buffer to append to + * @param value boolean value to encode + * @param prefix a constant to prepend before value + * @return updated index + */ + static int prepend(int index, byte coder, byte[] buf, String value, String prefix) { + index -= value.length(); + if (coder == String.LATIN1) { + value.getBytes(buf, index, String.LATIN1); + index -= prefix.length(); + prefix.getBytes(buf, index, String.LATIN1); + } else { + value.getBytes(buf, index, String.UTF16); + index -= prefix.length(); + prefix.getBytes(buf, index, String.UTF16); + } + return index; + } + + /** + * Check for overflow, throw exception on overflow. + * + * @param value + * @return the given parameter value, if valid + */ + @ForceInline + static int checkOverflow(int value) { + if (value >= 0) { + return value; + } + throw new OutOfMemoryError("Overflow: String length out of range"); + } } diff --git a/src/java.base/share/classes/java/lang/System.java b/src/java.base/share/classes/java/lang/System.java index 0947da8ded747..5ff4796505b58 100644 --- a/src/java.base/share/classes/java/lang/System.java +++ b/src/java.base/share/classes/java/lang/System.java @@ -2623,6 +2623,10 @@ public long stringConcatMix(long lengthCoder, char value) { return StringConcatHelper.mix(lengthCoder, value); } + public Object stringConcat1(String[] constants) { + return new StringConcatHelper.Concat1(constants); + } + public int getCharsLatin1(long i, int index, byte[] buf) { return StringLatin1.getChars(i, index, buf); } diff --git a/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java b/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java index cf552c434be53..dd2621935749f 100644 --- a/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java +++ b/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, Alibaba Group Holding Limited. All Rights Reserved. * 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,23 +31,33 @@ import jdk.internal.constant.ConstantUtils; import jdk.internal.misc.VM; import jdk.internal.util.ClassFileDumper; +import jdk.internal.util.ReferenceKey; +import jdk.internal.util.ReferencedKeyMap; import jdk.internal.vm.annotation.Stable; import sun.invoke.util.Wrapper; +import java.lang.classfile.Annotation; import java.lang.classfile.ClassBuilder; import java.lang.classfile.ClassFile; import java.lang.classfile.CodeBuilder; +import java.lang.classfile.MethodBuilder; import java.lang.classfile.TypeKind; +import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute; import java.lang.constant.ClassDesc; -import java.lang.constant.ConstantDescs; import java.lang.constant.MethodTypeDesc; import java.lang.invoke.MethodHandles.Lookup; -import java.lang.reflect.AccessFlag; +import java.lang.ref.SoftReference; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import java.util.function.Consumer; +import java.util.function.Supplier; -import static java.lang.invoke.MethodHandles.Lookup.ClassOption.STRONG; +import static java.lang.classfile.ClassFile.*; +import static java.lang.constant.ConstantDescs.*; import static java.lang.invoke.MethodType.methodType; /** @@ -107,12 +118,15 @@ * @since 9 */ public final class StringConcatFactory { - private static final int HIGH_ARITY_THRESHOLD; + private static final int FORCE_INLINE_THRESHOLD; static { String highArity = VM.getSavedProperty("java.lang.invoke.StringConcat.highArityThreshold"); - HIGH_ARITY_THRESHOLD = highArity != null ? Integer.parseInt(highArity) : 20; + HIGH_ARITY_THRESHOLD = highArity != null ? Integer.parseInt(highArity) : 0; + + String inlineThreshold = VM.getSavedProperty("java.lang.invoke.StringConcat.inlineThreshold"); + FORCE_INLINE_THRESHOLD = inlineThreshold != null ? Integer.parseInt(inlineThreshold) : 16; } /** @@ -371,14 +385,17 @@ public static CallSite makeConcatWithConstants(MethodHandles.Lookup lookup, } try { - if (concatType.parameterCount() <= HIGH_ARITY_THRESHOLD) { - return new ConstantCallSite( - generateMHInlineCopy(concatType, constantStrings) - .viewAsType(concatType, true)); - } else { - return new ConstantCallSite( - SimpleStringBuilderStrategy.generate(lookup, concatType, constantStrings)); + MethodHandle mh = makeSimpleConcat(concatType, constantStrings); + if (mh == null && concatType.parameterCount() <= HIGH_ARITY_THRESHOLD) { + mh = generateMHInlineCopy(concatType, constantStrings); } + + if (mh == null) { + mh = InlineHiddenClassStrategy.generate(lookup, concatType, constantStrings); + } + mh = mh.viewAsType(concatType, true); + + return new ConstantCallSite(mh); } catch (Error e) { // Pass through any error throw e; @@ -427,7 +444,7 @@ private static String[] parseRecipe(MethodType concatType, } // Flush any accumulated characters into a constant - consts[oCount++] = acc.length() > 0 ? acc.toString() : null; + consts[oCount++] = acc.length() > 0 ? acc.toString() : ""; acc.setLength(0); } else { // Not a special character, this is a constant embedded into @@ -443,7 +460,7 @@ private static String[] parseRecipe(MethodType concatType, } // Flush the remaining characters as constant: - consts[oCount] = acc.length() > 0 ? acc.toString() : null; + consts[oCount] = acc.length() > 0 ? acc.toString() : ""; return consts; } @@ -466,14 +483,7 @@ private static StringConcatException constantMismatch(Object[] constants, " are passed"); } - /** - *

    This strategy replicates what StringBuilders are doing: it builds the - * byte[] array on its own and passes that byte[] array to String - * constructor. This strategy requires access to some private APIs in JDK, - * most notably, the private String constructor that accepts byte[] arrays - * without copying. - */ - private static MethodHandle generateMHInlineCopy(MethodType mt, String[] constants) { + private static MethodHandle makeSimpleConcat(MethodType mt, String[] constants) { int paramCount = mt.parameterCount(); String suffix = constants[paramCount]; @@ -484,22 +494,37 @@ private static MethodHandle generateMHInlineCopy(MethodType mt, String[] constan if (paramCount == 1) { String prefix = constants[0]; // Empty constants will be - if (prefix == null) { - if (suffix == null) { + if (prefix.isEmpty()) { + if (suffix.isEmpty()) { return unaryConcat(mt.parameterType(0)); } else if (!mt.hasPrimitives()) { return MethodHandles.insertArguments(simpleConcat(), 1, suffix); } // else fall-through - } else if (suffix == null && !mt.hasPrimitives()) { + } else if (suffix.isEmpty() && !mt.hasPrimitives()) { // Non-primitive argument return MethodHandles.insertArguments(simpleConcat(), 0, prefix); } // fall-through if there's both a prefix and suffix - } - if (paramCount == 2 && !mt.hasPrimitives() && suffix == null - && constants[0] == null && constants[1] == null) { + } else if (paramCount == 2 && !mt.hasPrimitives() && suffix.isEmpty() + && constants[0].isEmpty() && constants[1].isEmpty()) { // Two reference arguments, no surrounding constants return simpleConcat(); } + + return null; + } + + /** + *

    This strategy replicates what StringBuilders are doing: it builds the + * byte[] array on its own and passes that byte[] array to String + * constructor. This strategy requires access to some private APIs in JDK, + * most notably, the private String constructor that accepts byte[] arrays + * without copying. + */ + private static MethodHandle generateMHInlineCopy(MethodType mt, String[] constants) { + int paramCount = mt.parameterCount(); + String suffix = constants[paramCount]; + + // else... fall-through to slow-path // Create filters and obtain filtered parameter types. Filters would be used in the beginning @@ -1043,139 +1068,638 @@ private StringConcatFactory() { } /** - * Bytecode StringBuilder strategy. + * Implement efficient hidden class strategy for String concatenation * - *

    This strategy emits StringBuilder chains as similar as possible - * to what javac would. No exact sizing of parameters or estimates. + *

    This strategy replicates based on the bytecode what StringBuilders are doing: it builds the + * byte[] array on its own and passes that byte[] array to String + * constructor. This strategy requires access to some private APIs in JDK, + * most notably, the private String constructor that accepts byte[] arrays + * without copying. */ - private static final class SimpleStringBuilderStrategy { - static final String METHOD_NAME = "concat"; - static final ClassDesc STRING_BUILDER = ClassDesc.ofDescriptor("Ljava/lang/StringBuilder;"); + private static final class InlineHiddenClassStrategy { + static final String CLASS_NAME = "java.lang.String$$StringConcat"; + static final String METHOD_NAME = "concat"; + static final ClassFileDumper DUMPER = ClassFileDumper.getInstance("java.lang.invoke.StringConcatFactory.dump", "stringConcatClasses"); - static final MethodTypeDesc APPEND_BOOLEAN_TYPE = MethodTypeDesc.of(STRING_BUILDER, ConstantDescs.CD_boolean); - static final MethodTypeDesc APPEND_CHAR_TYPE = MethodTypeDesc.of(STRING_BUILDER, ConstantDescs.CD_char); - static final MethodTypeDesc APPEND_DOUBLE_TYPE = MethodTypeDesc.of(STRING_BUILDER, ConstantDescs.CD_double); - static final MethodTypeDesc APPEND_FLOAT_TYPE = MethodTypeDesc.of(STRING_BUILDER, ConstantDescs.CD_float); - static final MethodTypeDesc APPEND_INT_TYPE = MethodTypeDesc.of(STRING_BUILDER, ConstantDescs.CD_int); - static final MethodTypeDesc APPEND_LONG_TYPE = MethodTypeDesc.of(STRING_BUILDER, ConstantDescs.CD_long); - static final MethodTypeDesc APPEND_OBJECT_TYPE = MethodTypeDesc.of(STRING_BUILDER, ConstantDescs.CD_Object); - static final MethodTypeDesc APPEND_STRING_TYPE = MethodTypeDesc.of(STRING_BUILDER, ConstantDescs.CD_String); - static final MethodTypeDesc INT_CONSTRUCTOR_TYPE = MethodTypeDesc.of(ConstantDescs.CD_void, ConstantDescs.CD_int); - static final MethodTypeDesc TO_STRING_TYPE = MethodTypeDesc.of(ConstantDescs.CD_String); + static final MethodHandles.Lookup STR_LOOKUP = new MethodHandles.Lookup(String.class); + + static final ClassDesc CD_CONCAT = ConstantUtils.binaryNameToDesc(CLASS_NAME); + static final ClassDesc CD_StringConcatHelper = ClassDesc.ofDescriptor("Ljava/lang/StringConcatHelper;"); + static final ClassDesc CD_StringConcatBase = ClassDesc.ofDescriptor("Ljava/lang/StringConcatHelper$StringConcatBase;"); + static final ClassDesc CD_Array_byte = ClassDesc.ofDescriptor("[B"); + static final ClassDesc CD_Array_String = ClassDesc.ofDescriptor("[Ljava/lang/String;"); + + static final MethodTypeDesc MTD_byte_char = MethodTypeDesc.of(CD_byte, CD_char); + static final MethodTypeDesc MTD_byte = MethodTypeDesc.of(CD_byte); + static final MethodTypeDesc MTD_int = MethodTypeDesc.of(CD_int); + static final MethodTypeDesc MTD_int_int_boolean = MethodTypeDesc.of(CD_int, CD_int, CD_boolean); + static final MethodTypeDesc MTD_int_int_char = MethodTypeDesc.of(CD_int, CD_int, CD_char); + static final MethodTypeDesc MTD_int_int_int = MethodTypeDesc.of(CD_int, CD_int, CD_int); + static final MethodTypeDesc MTD_int_int_long = MethodTypeDesc.of(CD_int, CD_int, CD_long); + static final MethodTypeDesc MTD_int_int_String = MethodTypeDesc.of(CD_int, CD_int, CD_String); + static final MethodTypeDesc MTD_String_float = MethodTypeDesc.of(CD_String, CD_float); + static final MethodTypeDesc MTD_String_double = MethodTypeDesc.of(CD_String, CD_double); + static final MethodTypeDesc MTD_String_Object = MethodTypeDesc.of(CD_String, CD_Object); + + static final MethodTypeDesc MTD_INIT = MethodTypeDesc.of(CD_void, CD_Array_String); + static final MethodTypeDesc MTD_NEW_ARRAY_SUFFIX = MethodTypeDesc.of(CD_Array_byte, CD_String, CD_int, CD_byte); + static final MethodTypeDesc MTD_STRING_INIT = MethodTypeDesc.of(CD_void, CD_Array_byte, CD_byte); + + static final MethodTypeDesc PREPEND_int = MethodTypeDesc.of(CD_int, CD_int, CD_byte, CD_Array_byte, CD_int, CD_String); + static final MethodTypeDesc PREPEND_long = MethodTypeDesc.of(CD_int, CD_int, CD_byte, CD_Array_byte, CD_long, CD_String); + static final MethodTypeDesc PREPEND_boolean = MethodTypeDesc.of(CD_int, CD_int, CD_byte, CD_Array_byte, CD_boolean, CD_String); + static final MethodTypeDesc PREPEND_char = MethodTypeDesc.of(CD_int, CD_int, CD_byte, CD_Array_byte, CD_char, CD_String); + static final MethodTypeDesc PREPEND_String = MethodTypeDesc.of(CD_int, CD_int, CD_byte, CD_Array_byte, CD_String, CD_String); + + static final RuntimeVisibleAnnotationsAttribute FORCE_INLINE = RuntimeVisibleAnnotationsAttribute.of(Annotation.of(ClassDesc.ofDescriptor("Ljdk/internal/vm/annotation/ForceInline;"))); + + static final MethodType CONSTRUCTOR_METHOD_TYPE = MethodType.methodType(void.class, String[].class); + static final Consumer CONSTRUCTOR_BUILDER = new Consumer() { + @Override + public void accept(CodeBuilder cb) { + /* + * super(constants); + */ + int thisSlot = cb.receiverSlot(), + constantsSlot = cb.parameterSlot(0); + cb.aload(thisSlot) + .aload(constantsSlot) + .invokespecial(CD_StringConcatBase, INIT_NAME, MTD_INIT, false) + .return_(); + } + }; + + static final ReferencedKeyMap> CACHE = + ReferencedKeyMap.create(true, true, + new Supplier<>() { + @Override + public Map, SoftReference> get() { + return new ConcurrentHashMap<>(64); + } + }); + + private InlineHiddenClassStrategy() { + // no instantiation + } + + private record MethodHandlePair(MethodHandle constructor, MethodHandle concatenator) { }; /** - * Ensure a capacity in the initial StringBuilder to accommodate all - * constants plus this factor times the number of arguments. + * The parameter types are normalized into 7 types: int,long,boolean,char,float,double,Object */ - static final int ARGUMENT_SIZE_FACTOR = 4; + private static MethodType erasedArgs(MethodType args) { + int parameterCount = args.parameterCount(); + var paramTypes = new Class[parameterCount]; + boolean changed = false; + for (int i = 0; i < parameterCount; i++) { + Class cl = args.parameterType(i); + // Use int as the logical type for subword integral types + // (byte and short). char and boolean require special + // handling so don't change the logical type of those + if (cl == byte.class || cl == short.class) { + cl = int.class; + changed = true; + } else if (cl != Object.class && !cl.isPrimitive()) { + cl = Object.class; + changed = true; + } + paramTypes[i] = cl; + } + return changed ? MethodType.methodType(args.returnType(), paramTypes) : args; + } - static final Set SET_OF_STRONG = Set.of(STRONG); + /** + * Construct the MethodType of the prepend method, The parameters only support 5 types: + * int/long/char/boolean/String. Not int/long/char/boolean type, use String type

    + * + * The following is an example of the generated target code: + *

    +         *  int prepend(int length, byte coder, byte[] buff,  String[] constants
    +         *      int arg0, long arg1, boolean arg2, char arg3, String arg5)
    +         * 
    + */ + private static MethodTypeDesc prependArgs(MethodType concatArgs) { + int parameterCount = concatArgs.parameterCount(); + var paramTypes = new ClassDesc[parameterCount + 4]; + paramTypes[0] = CD_int; // length + paramTypes[1] = CD_byte; // coder + paramTypes[2] = CD_Array_byte; // buff + paramTypes[3] = CD_Array_String; // constants + + for (int i = 0; i < parameterCount; i++) { + var cl = concatArgs.parameterType(i); + paramTypes[i + 4] = needStringOf(cl) ? CD_String : ConstantUtils.classDesc(cl); + } + return MethodTypeDesc.of(CD_int, paramTypes); + } - private SimpleStringBuilderStrategy() { - // no instantiation + /** + * Construct the MethodType of the coder method, + * The first parameter is the initialized coder, Only parameter types that can be UTF16 are added. + */ + private static MethodTypeDesc coderArgs(MethodType concatArgs) { + int parameterCount = concatArgs.parameterCount(); + List paramTypes = new ArrayList<>(); + paramTypes.add(CD_int); // init coder + for (int i = 0; i < parameterCount; i++) { + var cl = concatArgs.parameterType(i); + if (maybeUTF16(cl)) { + paramTypes.add(cl == char.class ? CD_char : CD_String); + } + } + return MethodTypeDesc.of(CD_int, paramTypes); + } + + /** + * Construct the MethodType of the length method, + * The first parameter is the initialized length + */ + private static MethodTypeDesc lengthArgs(MethodType concatArgs) { + int parameterCount = concatArgs.parameterCount(); + var paramTypes = new ClassDesc[parameterCount + 1]; + paramTypes[0] = CD_int; // init long + for (int i = 0; i < parameterCount; i++) { + var cl = concatArgs.parameterType(i); + paramTypes[i + 1] = needStringOf(cl) ? CD_String : ConstantUtils.classDesc(cl); + } + return MethodTypeDesc.of(CD_int, paramTypes); } private static MethodHandle generate(Lookup lookup, MethodType args, String[] constants) throws Exception { - String className = getClassName(lookup.lookupClass()); + lookup = STR_LOOKUP; + final MethodType concatArgs = erasedArgs(args); + + // 1 argment use built-in method + if (args.parameterCount() == 1) { + Object concat1 = JLA.stringConcat1(constants); + var handle = lookup.findVirtual(concat1.getClass(), METHOD_NAME, concatArgs); + return handle.bindTo(concat1); + } - byte[] classBytes = ClassFile.of().build(ConstantUtils.binaryNameToDesc(className), + var weakConstructorHandle = CACHE.get(concatArgs); + if (weakConstructorHandle != null) { + MethodHandlePair handlePair = weakConstructorHandle.get(); + if (handlePair != null) { + try { + var instance = handlePair.constructor.invoke(constants); + return handlePair.concatenator.bindTo(instance); + } catch (Throwable e) { + throw new StringConcatException("Exception while utilizing the hidden class", e); + } + } + } + MethodTypeDesc lengthArgs = lengthArgs(concatArgs), + coderArgs = parameterMaybeUTF16(concatArgs) ? coderArgs(concatArgs) : null, + prependArgs = prependArgs(concatArgs); + + byte[] classBytes = ClassFile.of().build(CD_CONCAT, new Consumer() { + final boolean forceInline = concatArgs.parameterCount() < FORCE_INLINE_THRESHOLD; + @Override public void accept(ClassBuilder clb) { - clb.withFlags(AccessFlag.FINAL, AccessFlag.SUPER, AccessFlag.SYNTHETIC) - .withMethodBody(METHOD_NAME, - ConstantUtils.methodTypeDesc(args), - ClassFile.ACC_FINAL | ClassFile.ACC_PRIVATE | ClassFile.ACC_STATIC, - generateMethod(constants, args)); + clb.withSuperclass(CD_StringConcatBase) + .withFlags(ACC_FINAL | ACC_SUPER | ACC_SYNTHETIC) + .withMethodBody(INIT_NAME, MTD_INIT, 0, CONSTRUCTOR_BUILDER) + .withMethod("length", + lengthArgs, + ACC_STATIC | ACC_PRIVATE, + new Consumer() { + public void accept(MethodBuilder mb) { + if (forceInline) { + mb.with(FORCE_INLINE); + } + mb.withCode(generateLengthMethod(lengthArgs)); + } + }) + .withMethod("prepend", + prependArgs, + ACC_STATIC | ACC_PRIVATE, + new Consumer() { + public void accept(MethodBuilder mb) { + if (forceInline) { + mb.with(FORCE_INLINE); + } + mb.withCode(generatePrependMethod(prependArgs)); + } + }) + .withMethod(METHOD_NAME, + ConstantUtils.methodTypeDesc(concatArgs), + ACC_FINAL, + new Consumer() { + public void accept(MethodBuilder mb) { + if (forceInline) { + mb.with(FORCE_INLINE); + } + mb.withCode(generateConcatMethod( + CD_CONCAT, + concatArgs, + lengthArgs, + coderArgs, + prependArgs)); + } + }); + + if (coderArgs != null) { + clb.withMethod("coder", + coderArgs, + ACC_STATIC | ACC_PRIVATE, + new Consumer() { + public void accept(MethodBuilder mb) { + if (forceInline) { + mb.with(FORCE_INLINE); + } + mb.withCode(generateCoderMethod(coderArgs)); + } + }); + } }}); try { - Lookup hiddenLookup = lookup.makeHiddenClassDefiner(className, classBytes, SET_OF_STRONG, DUMPER) - .defineClassAsLookup(true); - Class innerClass = hiddenLookup.lookupClass(); - return hiddenLookup.findStatic(innerClass, METHOD_NAME, args); - } catch (Exception e) { + var hiddenClass = lookup.makeHiddenClassDefiner(CLASS_NAME, classBytes, Set.of(), DUMPER) + .defineClass(true, null); + var constructor = lookup.findConstructor(hiddenClass, CONSTRUCTOR_METHOD_TYPE); + var concat = lookup.findVirtual(hiddenClass, METHOD_NAME, concatArgs); + CACHE.put(concatArgs, new SoftReference<>(new MethodHandlePair(constructor, concat))); + var instance = hiddenClass.cast(constructor.invoke(constants)); + return concat.bindTo(instance); + } catch (Throwable e) { throw new StringConcatException("Exception while spinning the class", e); } } - private static Consumer generateMethod(String[] constants, MethodType args) { + /** + * Generate InlineCopy-based code.

    + * + * The following is an example of the generated target code: + * + *

    +         *  import static java.lang.StringConcatHelper.newArrayWithSuffix;
    +         *  import static java.lang.StringConcatHelper.prepend;
    +         *  import static java.lang.StringConcatHelper.stringCoder;
    +         *  import static java.lang.StringConcatHelper.stringSize;
    +         *
    +         *  class StringConcat extends java.lang.StringConcatHelper.StringConcatBase {
    +         *      // super class defines
    +         *      // String[] constants;
    +         *      // int length;
    +         *      // byte coder;
    +         *
    +         *      StringConcat(String[] constants) {
    +         *          super(constants);
    +         *      }
    +         *
    +         *      String concat(int arg0, long arg1, boolean arg2, char arg3, String arg4,
    +         *          float arg5, double arg6, Object arg7
    +         *      ) {
    +         *          // Types other than byte/short/int/long/boolean/String require a local variable to store
    +         *          String str4 = stringOf(arg4);
    +         *          String str5 = stringOf(arg5);
    +         *          String str6 = stringOf(arg6);
    +         *          String str7 = stringOf(arg7);
    +         *
    +         *          int coder  = coder(this.coder, arg0, arg1, arg2, arg3, str4, str5, str6, str7);
    +         *          int length = length(this.length, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
    +         *          String[] constants = this.constants;
    +         *          byte[] buf = newArrayWithSuffix(constants[paramCount], length. coder);
    +         *
    +         *          prepend(length, coder, buf, constants, arg0, arg1, arg2, arg3, str4, str5, str6, str7);
    +         *
    +         *          return new String(buf, coder);
    +         *      }
    +         *
    +         *      static int length(int length, int arg0, long arg1, boolean arg2, char arg3,
    +         *                       String arg4, String arg5, String arg6, String arg7) {
    +         *          return stringSize(stringSize(stringSize(stringSize(stringSize(stringSize(stringSize(stringSize(
    +         *                      length, arg0), arg1), arg2), arg3), arg4), arg5), arg6), arg7);
    +         *      }
    +         *
    +         *      static int cocder(int coder, char arg3, String str4, String str5, String str6, String str7) {
    +         *          return coder | stringCoder(arg3) | str4.coder() | str5.coder() | str6.coder() | str7.coder();
    +         *      }
    +         *
    +         *      static int prepend(int length, int coder, byte[] buf, String[] constants,
    +         *                     int arg0, long arg1, boolean arg2, char arg3,
    +         *                     String str4, String str5, String str6, String str7) {
    +         *          // StringConcatHelper.prepend
    +         *          return prepend(prepend(prepend(prepend(
    +         *                  prepend(apppend(prepend(prepend(length,
    +         *                       buf, str7, constant[7]), buf, str6, constant[6]),
    +         *                       buf, str5, constant[5]), buf, str4, constant[4]),
    +         *                       buf, arg3, constant[3]), buf, arg2, constant[2]),
    +         *                       buf, arg1, constant[1]), buf, arg0, constant[0]);
    +         *      }
    +         *  }
    +         * 
    + */ + private static Consumer generateConcatMethod( + ClassDesc concatClass, + MethodType concatArgs, + MethodTypeDesc lengthArgs, + MethodTypeDesc coderArgs, + MethodTypeDesc prependArgs + ) { return new Consumer() { @Override public void accept(CodeBuilder cb) { - cb.new_(STRING_BUILDER); - cb.dup(); - - int len = 0; - for (String constant : constants) { - if (constant != null) { - len += constant.length(); + // Compute parameter variable slots + int paramCount = concatArgs.parameterCount(), + thisSlot = cb.receiverSlot(), + lengthSlot = cb.allocateLocal(TypeKind.IntType), + coderSlot = cb.allocateLocal(TypeKind.ByteType), + bufSlot = cb.allocateLocal(TypeKind.ReferenceType), + constantsSlot = cb.allocateLocal(TypeKind.ReferenceType), + suffixSlot = cb.allocateLocal(TypeKind.ReferenceType); + + /* + * Types other than int/long/char/boolean require local variables to store the result of stringOf. + * + * stringSlots stores the slots of parameters relative to local variables + * + * str0 = stringOf(arg0); + * str1 = stringOf(arg1); + * ... + * strN = toString(argN); + */ + int[] stringSlots = new int[paramCount]; + for (int i = 0; i < paramCount; i++) { + var cl = concatArgs.parameterType(i); + if (needStringOf(cl)) { + MethodTypeDesc methodTypeDesc; + if (cl == float.class) { + methodTypeDesc = MTD_String_float; + } else if (cl == double.class) { + methodTypeDesc = MTD_String_double; + } else { + methodTypeDesc = MTD_String_Object; + } + stringSlots[i] = cb.allocateLocal(TypeKind.ReferenceType); + cb.loadLocal(TypeKind.from(cl), cb.parameterSlot(i)) + .invokestatic(CD_StringConcatHelper, "stringOf", methodTypeDesc) + .astore(stringSlots[i]); } } - len += args.parameterCount() * ARGUMENT_SIZE_FACTOR; - cb.loadConstant(len); - cb.invokespecial(STRING_BUILDER, "", INT_CONSTRUCTOR_TYPE); - - // At this point, we have a blank StringBuilder on stack, fill it in with .append calls. - { - int off = 0; - for (int c = 0; c < args.parameterCount(); c++) { - if (constants[c] != null) { - cb.ldc(constants[c]); - cb.invokevirtual(STRING_BUILDER, "append", APPEND_STRING_TYPE); + + /* + * coder = coder(this.coder, arg0, arg1, ... argN); + */ + cb.aload(thisSlot) + .getfield(concatClass, "coder", CD_byte); + if (coderArgs != null) { + for (int i = 0; i < paramCount; i++) { + var cl = concatArgs.parameterType(i); + if (maybeUTF16(cl)) { + if (cl == char.class) { + cb.loadLocal(TypeKind.CharType, cb.parameterSlot(i)); + } else { + cb.aload(stringSlots[i]); + } } - Class cl = args.parameterType(c); - TypeKind kind = TypeKind.from(cl); - cb.loadLocal(kind, off); - off += kind.slotSize(); - MethodTypeDesc desc = getSBAppendDesc(cl); - cb.invokevirtual(STRING_BUILDER, "append", desc); } - if (constants[constants.length - 1] != null) { - cb.ldc(constants[constants.length - 1]); - cb.invokevirtual(STRING_BUILDER, "append", APPEND_STRING_TYPE); + cb.invokestatic(concatClass, "coder", coderArgs); + } + cb.istore(coderSlot); + + /* + * length = length(this.length, arg0, arg1, ..., argN); + */ + cb.aload(thisSlot) + .getfield(concatClass, "length", CD_int); + for (int i = 0; i < paramCount; i++) { + var cl = concatArgs.parameterType(i); + int paramSlot = cb.parameterSlot(i); + if (needStringOf(cl)) { + paramSlot = stringSlots[i]; + cl = String.class; + } + cb.loadLocal(TypeKind.from(cl), paramSlot); + } + cb.invokestatic(concatClass, "length", lengthArgs); + + /* + * String[] constants = this.constants; + * suffix = constants[paranCount]; + * length -= suffix.length(); + */ + cb.aload(thisSlot) + .getfield(concatClass, "constants", CD_Array_String) + .dup() + .astore(constantsSlot) + .ldc(paramCount) + .aaload() + .dup() + .astore(suffixSlot) + .invokevirtual(CD_String, "length", MTD_int) + .isub() + .istore(lengthSlot); + + /* + * Allocate buffer : + * + * buf = newArrayWithSuffix(suffix, length, coder) + */ + cb.aload(suffixSlot) + .iload(lengthSlot) + .iload(coderSlot) + .invokestatic(CD_StringConcatHelper, "newArrayWithSuffix", MTD_NEW_ARRAY_SUFFIX) + .astore(bufSlot); + + /* + * prepend(length, coder, buf, constants, ar0, ar1, ..., argN); + */ + cb.iload(lengthSlot) + .iload(coderSlot) + .aload(bufSlot) + .aload(constantsSlot); + for (int i = 0; i < paramCount; i++) { + var cl = concatArgs.parameterType(i); + int paramSlot = cb.parameterSlot(i); + var kind = TypeKind.from(cl); + if (needStringOf(cl)) { + paramSlot = stringSlots[i]; + kind = TypeKind.ReferenceType; } + cb.loadLocal(kind, paramSlot); } + cb.invokestatic(concatClass, "prepend", prependArgs); + + // return new String(buf, coder); + cb.new_(CD_String) + .dup() + .aload(bufSlot) + .iload(coderSlot) + .invokespecial(CD_String, INIT_NAME, MTD_STRING_INIT) + .areturn(); + } + }; + } - cb.invokevirtual(STRING_BUILDER, "toString", TO_STRING_TYPE); - cb.areturn(); + /** + * Generate length method.

    + * + * The following is an example of the generated target code: + * + *

    +         * import static java.lang.StringConcatHelper.stringSize;
    +         *
    +         * static int length(int length, int arg0, long arg1, boolean arg2, char arg3,
    +         *                  String arg4, String arg5, String arg6, String arg7) {
    +         *     return stringSize(stringSize(stringSize(length, arg0), arg1), ..., arg7);
    +         * }
    +         * 
    + */ + private static Consumer generateLengthMethod(MethodTypeDesc lengthArgs) { + return new Consumer() { + @Override + public void accept(CodeBuilder cb) { + int lengthSlot = cb.parameterSlot(0); + cb.iload(lengthSlot); + for (int i = 1; i < lengthArgs.parameterCount(); i++) { + var cl = lengthArgs.parameterType(i); + MethodTypeDesc methodTypeDesc; + if (cl == CD_char) { + methodTypeDesc = MTD_int_int_char; + } else if (cl == CD_int) { + methodTypeDesc = MTD_int_int_int; + } else if (cl == CD_long) { + methodTypeDesc = MTD_int_int_long; + } else if (cl == CD_boolean) { + methodTypeDesc = MTD_int_int_boolean; + } else { + methodTypeDesc = MTD_int_int_String; + } + cb.loadLocal(TypeKind.from(cl), cb.parameterSlot(i)) + .invokestatic(CD_StringConcatHelper, "stringSize", methodTypeDesc); + } + cb.ireturn(); } }; } /** - * The generated class is in the same package as the host class as - * it's the implementation of the string concatenation for the host - * class. + * Generate coder method.

    + * + * The following is an example of the generated target code: + * + *

    +         * import static java.lang.StringConcatHelper.stringCoder;
    +         *
    +         * static int cocder(int coder, char arg3, String str4, String str5, String str6, String str7) {
    +         *     return coder | stringCoder(arg3) | str4.coder() | str5.coder() | str6.coder() | str7.coder();
    +         * }
    +         * 
    */ - private static String getClassName(Class hostClass) { - String name = hostClass.isHidden() ? hostClass.getName().replace('/', '_') - : hostClass.getName(); - return name + "$$StringConcat"; + private static Consumer generateCoderMethod(MethodTypeDesc coderArgs) { + return new Consumer() { + @Override + public void accept(CodeBuilder cb) { + /* + * return coder | stringCoder(argN) | ... | arg1.coder() | arg0.coder(); + */ + int coderSlot = cb.parameterSlot(0); + cb.iload(coderSlot); + for (int i = 1; i < coderArgs.parameterCount(); i++) { + var cl = coderArgs.parameterType(i); + cb.loadLocal(TypeKind.from(cl), cb.parameterSlot(i)); + if (cl == CD_char) { + cb.invokestatic(CD_StringConcatHelper, "stringCoder", MTD_byte_char); + } else { + cb.invokevirtual(CD_String, "coder", MTD_byte); + } + cb.ior(); + } + cb.ireturn(); + } + }; } - private static MethodTypeDesc getSBAppendDesc(Class cl) { - if (cl.isPrimitive()) { - if (cl == Integer.TYPE || cl == Byte.TYPE || cl == Short.TYPE) { - return APPEND_INT_TYPE; - } else if (cl == Boolean.TYPE) { - return APPEND_BOOLEAN_TYPE; - } else if (cl == Character.TYPE) { - return APPEND_CHAR_TYPE; - } else if (cl == Double.TYPE) { - return APPEND_DOUBLE_TYPE; - } else if (cl == Float.TYPE) { - return APPEND_FLOAT_TYPE; - } else if (cl == Long.TYPE) { - return APPEND_LONG_TYPE; - } else { - throw new IllegalStateException("Unhandled primitive StringBuilder.append: " + cl); + /** + * Generate prepend method.

    + * + * The following is an example of the generated target code: + * + *

    +         * import static java.lang.StringConcatHelper.prepend;
    +         *
    +         * static int prepend(int length, int coder, byte[] buf, String[] constants,
    +         *                int arg0, long arg1, boolean arg2, char arg3,
    +         *                String str4, String str5, String str6, String str7) {
    +         *
    +         *     return prepend(prepend(prepend(prepend(
    +         *             prepend(prepend(prepend(prepend(length,
    +         *                  buf, str7, constant[7]), buf, str6, constant[6]),
    +         *                  buf, str5, constant[5]), buf, str4, constant[4]),
    +         *                  buf, arg3, constant[3]), buf, arg2, constant[2]),
    +         *                  buf, arg1, constant[1]), buf, arg0, constant[0]);
    +         * }
    +         * 
    + */ + private static Consumer generatePrependMethod(MethodTypeDesc prependArgs) { + return new Consumer() { + @Override + public void accept(CodeBuilder cb) { + // Compute parameter variable slots + int lengthSlot = cb.parameterSlot(0), + coderSlot = cb.parameterSlot(1), + bufSlot = cb.parameterSlot(2), + constantsSlot = cb.parameterSlot(3); + /* + * // StringConcatHelper.prepend + * return prepend(prepend(prepend(prepend( + * prepend(apppend(prepend(prepend(length, + * buf, str7, constant[7]), buf, str6, constant[6]), + * buf, str5, constant[5]), buf, arg4, constant[4]), + * buf, arg3, constant[3]), buf, arg2, constant[2]), + * buf, arg1, constant[1]), buf, arg0, constant[0]); + */ + cb.iload(lengthSlot); + for (int i = prependArgs.parameterCount() - 1; i >= 4; i--) { + var cl = prependArgs.parameterType(i); + var kind = TypeKind.from(cl); + + // There are only 5 types of parameters: int, long, boolean, char, String + MethodTypeDesc methodTypeDesc; + if (cl == CD_int) { + methodTypeDesc = PREPEND_int; + } else if (cl == CD_long) { + methodTypeDesc = PREPEND_long; + } else if (cl == CD_boolean) { + methodTypeDesc = PREPEND_boolean; + } else if (cl == CD_char) { + methodTypeDesc = PREPEND_char; + } else { + kind = TypeKind.ReferenceType; + methodTypeDesc = PREPEND_String; + } + + cb.iload(coderSlot) + .aload(bufSlot) + .loadLocal(kind, cb.parameterSlot(i)) + .aload(constantsSlot) + .ldc(i - 4) + .aaload() + .invokestatic(CD_StringConcatHelper, "prepend", methodTypeDesc); + } + cb.ireturn(); + } + }; + } + + static boolean needStringOf(Class cl) { + return cl != int.class && cl != long.class && cl != boolean.class && cl != char.class; + } + + static boolean maybeUTF16(Class cl) { + return cl == char.class || !cl.isPrimitive(); + } + + static boolean parameterMaybeUTF16(MethodType args) { + for (int i = 0; i < args.parameterCount(); i++) { + if (maybeUTF16(args.parameterType(i))) { + return true; } - } else if (cl == String.class) { - return APPEND_STRING_TYPE; - } else { - return APPEND_OBJECT_TYPE; } + return false; } } } 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 24aeabf6d3621..e4d322a20d729 100644 --- a/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java +++ b/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java @@ -446,6 +446,8 @@ public interface JavaLangAccess { */ long stringConcatMix(long lengthCoder, char value); + Object stringConcat1(String[] constants); + /** * Join strings */ diff --git a/src/java.base/share/classes/jdk/internal/util/ClassFileDumper.java b/src/java.base/share/classes/jdk/internal/util/ClassFileDumper.java index afb3d1374ab6c..b104b56ac0e40 100644 --- a/src/java.base/share/classes/jdk/internal/util/ClassFileDumper.java +++ b/src/java.base/share/classes/jdk/internal/util/ClassFileDumper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,6 @@ package jdk.internal.util; import jdk.internal.misc.VM; -import sun.security.action.GetPropertyAction; import java.io.IOException; import java.nio.file.Files; @@ -80,7 +79,11 @@ public static ClassFileDumper getInstance(String key, String path) { private final AtomicInteger counter = new AtomicInteger(); private ClassFileDumper(String key, String path) { - String value = GetPropertyAction.privilegedGetProperty(key); + /* + * GetPropertyAction.privilegedGetProperty cannot be used here, Using VM.getSavedProperty to avoid a bootstrap + * circularity issue in the java/lang/String/concat/WithSecurityManager.java test + */ + String value = VM.getSavedProperty(key); this.key = key; boolean enabled = value != null && value.isEmpty() ? true : Boolean.parseBoolean(value); if (enabled) { diff --git a/test/jdk/java/lang/String/concat/HiddenClassUnloading.java b/test/jdk/java/lang/String/concat/HiddenClassUnloading.java new file mode 100644 index 0000000000000..9e682f38ef552 --- /dev/null +++ b/test/jdk/java/lang/String/concat/HiddenClassUnloading.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2024, Alibaba Group Holding Limited. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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.lang.StringBuilder; + +import java.lang.invoke.*; +import java.lang.management.ManagementFactory; + +/** + * @test + * @summary Test whether the hidden class unloading of StringConcatFactory works + * + * @requires vm.flagless + * @run main/othervm -Xmx8M -Xms8M -Xverify:all HiddenClassUnloading + * @run main/othervm -Xmx8M -Xms8M -Xverify:all -XX:-CompactStrings HiddenClassUnloading + */ +public class HiddenClassUnloading { + public static void main(String[] args) throws Throwable { + var lookup = MethodHandles.lookup(); + var types = new Class[] { + int.class, long.class, double.class, float.class, char.class, boolean.class, String.class, + }; + + long initUnloadedClassCount = ManagementFactory.getClassLoadingMXBean().getUnloadedClassCount(); + + for (int i = 0; i < 2000; i++) { + int radix = types.length; + String str = Integer.toString(i, radix); + int length = str.length(); + var ptypes = new Class[length]; + for (int j = 0; j < length; j++) { + int index = Integer.parseInt(str.substring(j, j + 1), radix); + ptypes[j] = types[index]; + } + StringConcatFactory.makeConcatWithConstants( + lookup, + "concat", + MethodType.methodType(String.class, ptypes), + "\1".repeat(length), // recipe + new Object[0] + ); + } + + long unloadedClassCount = ManagementFactory.getClassLoadingMXBean().getUnloadedClassCount(); + if (initUnloadedClassCount == unloadedClassCount) { + throw new RuntimeException("unloadedClassCount is zero"); + } + } +} diff --git a/test/micro/org/openjdk/bench/java/lang/StringConcat.java b/test/micro/org/openjdk/bench/java/lang/StringConcat.java index 015ad224631f1..e1b8d882dd9c8 100644 --- a/test/micro/org/openjdk/bench/java/lang/StringConcat.java +++ b/test/micro/org/openjdk/bench/java/lang/StringConcat.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, Alibaba Group Holding Limited. All Rights Reserved. * 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,22 +49,40 @@ public class StringConcat { @Param("4711") public int intValue; - + public Integer integerValue = intValue; + public float floatValue = 156456.36435637F + intValue; public String stringValue = String.valueOf(intValue); - public Object objectValue = Long.valueOf(intValue); - public boolean boolValue = true; - + public Boolean booleanValue = Boolean.TRUE; public byte byteValue = (byte)-128; - public String emptyString = ""; + @Benchmark + public String concatConstBool() { + return "string" + boolValue; + } + + @Benchmark + public String concatConstBoolean() { + return "string" + booleanValue; + } + @Benchmark public String concatConstInt() { return "string" + intValue; } + @Benchmark + public String concatConstInteger() { + return "string" + integerValue; + } + + @Benchmark + public String concatConstFloat() { + return "string" + floatValue; + } + @Benchmark public String concatConstString() { return "string" + stringValue; @@ -94,6 +113,31 @@ public String concatMethodConstString() { return "string".concat(stringValue); } + @Benchmark + public String concatConstBoolString() { + return "string" + boolValue + stringValue; + } + + @Benchmark + public String concatConstBooleanString() { + return "string" + booleanValue + stringValue; + } + + @Benchmark + public String concatConstIntString() { + return "string" + intValue + stringValue; + } + + @Benchmark + public String concatConstIntegerString() { + return "string" + integerValue + stringValue; + } + + @Benchmark + public String concatConstFloatString() { + return "string" + floatValue + stringValue; + } + @Benchmark public String concatConstIntConstInt() { return "string" + intValue + "string" + intValue; @@ -104,6 +148,36 @@ public String concatConstStringConstInt() { return "string" + stringValue + "string" + intValue; } + @Benchmark + public String concatConstStringConst() { + return "string" + stringValue + "string"; + } + + @Benchmark + public String concatConstIntConst() { + return "string" + intValue + "string"; + } + + @Benchmark + public String concatConstIntegerConst() { + return "string" + integerValue + "string"; + } + + @Benchmark + public String concatConstFloatConst() { + return "string" + floatValue + "string"; + } + + @Benchmark + public String concatConstObjectConst() { + return "string" + objectValue + "string"; + } + + @Benchmark + public String concatConstBooleanConst() { + return "string" + booleanValue + "string"; + } + @Benchmark public String concatMix4String() { // Investigate "profile pollution" between shared LFs that might eliminate some JIT optimizations @@ -114,6 +188,31 @@ public String concatMix4String() { return s1 + s2 + s3 + s4; } + @Benchmark + public String concat3String() { + return stringValue + stringValue + stringValue; + } + + @Benchmark + public String concatStringBoolString() { + return stringValue + boolValue + stringValue; + } + + @Benchmark + public String concatStringBooleanString() { + return stringValue + booleanValue + stringValue; + } + + @Benchmark + public String concatStringIntString() { + return stringValue + intValue + stringValue; + } + + @Benchmark + public String concatStringIntegerString() { + return stringValue + integerValue + stringValue; + } + @Benchmark public String concatConst4String() { return "string" + stringValue + stringValue + stringValue + stringValue; @@ -176,6 +275,15 @@ public String concat23String() { + f10 + ","+ f11 + ","+ f12 + ","+ f13 + ","+ f14 + ","+ f15 + ","+ f16 + ","+ f17 + ","+ f18 + ","+ f19 + "," + f20 + ","+ f21 + ","+ f22; } + + @Benchmark + public String concat30Mix() { + return f0 + "," + f1 + ","+ f2 + ","+ f3 + ","+ f4 + ","+ f5 + ","+ f6 + ","+ f7 + ","+ f8 + ","+ f9 + "," + +f10 + ","+f11 + ","+f12 + ","+ f13 + ","+ f14 + ","+ f15 + ","+ f16 + ","+ f17 + ","+ f18 + ","+ f19 + "," + +f20 + ","+f21 + ","+f22 + "," + boolValue + "," + booleanValue + "," + intValue + "," + integerValue + + "," + floatValue + "," + byteValue + "," + objectValue; + } + @Benchmark public String concat123String() { return f0 + ","+ f1 + ","+ f2 + ","+ f3 + ","+ f4 + ","+ f5 + ","+ f6 + ","+ f7 + ","+ f8 + ","+ f9 + "," @@ -193,9 +301,38 @@ public String concat123String() { +f120 + ","+f121 + ","+f122; } + @Benchmark + public String concat13StringConst() { + return f0 + f1 + f2 + f3 + f4 + + f5 + f6 + f7 + f8 + f9 + +f10 + f11 + f12 + """ + A really long constant string. Such as a copyright header: + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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. + """; + } + @Benchmark public String concat23StringConst() { - return f0 + f0 + f0 + f0 + f0 + f0 + f0 + f0 + f0 + f0 + f0 + f0 + f0 + f0 + f0 + f0 + f0 + f0 + f0 + f0 + f0 + f0 + f0 + """ + return f0 + f1 + f2 + f3 + f4 + f5 + f6 + f7 + f8 + f9 + f10 + f11 + f12 + f13 + f14 + f15 + f16 + f17 + f18 + f19 + f20 + f21 + f22 + """ A really long constant string. Such as a copyright header: * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. diff --git a/test/micro/org/openjdk/bench/java/lang/StringConcatStartup.java b/test/micro/org/openjdk/bench/java/lang/StringConcatStartup.java index d146fbf9885a9..cb3d09f94ad63 100644 --- a/test/micro/org/openjdk/bench/java/lang/StringConcatStartup.java +++ b/test/micro/org/openjdk/bench/java/lang/StringConcatStartup.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, Alibaba Group Holding Limited. All Rights Reserved. * 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 +28,7 @@ import org.openjdk.jmh.annotations.Fork; 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.State; @@ -44,13 +46,31 @@ public class StringConcatStartup { public static void main(String... args) { - String[] selection = new String[] { "StringLarge", "MixedSmall", "StringSingle", "MixedLarge" }; + String[] selection = { + "StringLarge", + "MixedSmall", + "StringSingle", + "StringThree", + "MixedLarge" + }; if (args.length > 0) { selection = args; } for (String select : selection) { switch (select) { - case "StringSingle" -> new StringSingle().run(); + case "StringSingle" -> { + new StringSingle().constInt(); + new StringSingle().constFloat(); + new StringSingle().constString(); + new StringSingle().const2String(); + new StringSingle().constIntString(); + new StringSingle().constFloatString(); + new StringSingle().constBooleanString(); + } + case "StringThree" -> { + new StringThree().stringIntString(); + new StringThree().stringIntegerString(); + } case "MixedSmall" -> new MixedSmall().run(); case "StringLarge" -> new StringLarge().run(); case "MixedLarge" -> new MixedLarge().run(); @@ -64,14 +84,95 @@ public static void main(String... args) { @Fork(value = 40, warmups = 2) public static class StringSingle { - public String s = "foo"; + @Param("4711") + public int intValue; + public Integer integerValue = intValue; + public float floatValue = 156456.36435637F + intValue; + public String stringValue = String.valueOf(intValue); + public boolean boolValue = true; + public Boolean booleanValue = Boolean.TRUE; @Benchmark - public String run() { - return "" + s; + public String constBool() { + return "string" + boolValue; + } + + @Benchmark + public String constBoolean() { + return "string" + booleanValue; + } + + @Benchmark + public String constInt() { + return "string" + intValue; + } + + @Benchmark + public String constInteger() { + return "string" + integerValue; + } + + @Benchmark + public String constFloat() { + return "string" + floatValue; + } + + @Benchmark + public String constString() { + return "string" + stringValue; + } + + public String const2String() { + return "string" + stringValue + stringValue; + } + + @Benchmark + public String constIntString() { + return "string" + intValue + stringValue; + } + + @Benchmark + public String constIntegerString() { + return "string" + integerValue + stringValue; + } + + @Benchmark + public String constFloatString() { + return "string" + floatValue + stringValue; + } + + @Benchmark + public String constBoolString() { + return "string" + boolValue + stringValue; + } + + @Benchmark + public String constBooleanString() { + return "string" + booleanValue + stringValue; } } + @BenchmarkMode(Mode.SingleShotTime) + @OutputTimeUnit(TimeUnit.MILLISECONDS) + @State(Scope.Thread) + @Fork(value = 40, warmups = 2) + public static class StringThree { + + @Param("4711") + public int intValue; + public Integer integerValue = intValue; + public String stringValue = String.valueOf(intValue); + + @Benchmark + public String stringIntString() { + return stringValue + intValue + stringValue; + } + + @Benchmark + public String stringIntegerString() { + return stringValue + integerValue + stringValue; + } + } @BenchmarkMode(Mode.SingleShotTime) @OutputTimeUnit(TimeUnit.MILLISECONDS) From 07352c67448f3f35827395c83ac95e3ca0e4c6bc Mon Sep 17 00:00:00 2001 From: Pavel Rappo Date: Fri, 16 Aug 2024 14:06:10 +0000 Subject: [PATCH 331/353] 8338398: Trivially fix grammar and typos Reviewed-by: aivanov --- .../share/classes/java/util/concurrent/CompletableFuture.java | 4 ++-- .../share/classes/java/util/concurrent/ForkJoinPool.java | 4 ++-- .../share/classes/java/util/concurrent/ForkJoinTask.java | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/java.base/share/classes/java/util/concurrent/CompletableFuture.java b/src/java.base/share/classes/java/util/concurrent/CompletableFuture.java index 1a43b29d798f3..8adfd106eebb4 100644 --- a/src/java.base/share/classes/java/util/concurrent/CompletableFuture.java +++ b/src/java.base/share/classes/java/util/concurrent/CompletableFuture.java @@ -2805,7 +2805,7 @@ public CompletableFuture completeAsync(Supplier supplier) { /** * Exceptionally completes this CompletableFuture with * a {@link TimeoutException} if not otherwise completed - * before the given timeout. + * before the given timeout elapsed. * * @param timeout how long to wait before completing exceptionally * with a TimeoutException, in units of {@code unit} @@ -2825,7 +2825,7 @@ public CompletableFuture orTimeout(long timeout, TimeUnit unit) { /** * Completes this CompletableFuture with the given value if not - * otherwise completed before the given timeout. + * otherwise completed before the given timeout elapsed. * * @param value the value to use upon timeout * @param timeout how long to wait before completing normally 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 18b2bdeaa4217..cb061813c8a3e 100644 --- a/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java +++ b/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java @@ -670,7 +670,7 @@ public class ForkJoinPool extends AbstractExecutorService { * period given by field keepAlive (default 60sec), which applies * to the first timeout of a quiescent pool. Subsequent cases use * minimal delays such that, if still quiescent, all will be - * released soon therafter. This is checked by setting the + * released soon thereafter. This is checked by setting the * "source" field of signallee to an invalid value, that will * remain invalid only if it did not process any tasks. * @@ -855,7 +855,7 @@ public class ForkJoinPool extends AbstractExecutorService { * non-workers (which comply with Future.get() specs). Internal * usages of ForkJoinTasks ignore interrupt status when executing * or awaiting completion. Otherwise, reporting task results or - * exceptions is preferred to throwing InterruptedExecptions, + * exceptions is preferred to throwing InterruptedExceptions, * which are in turn preferred to timeouts. Similarly, completion * status is preferred to reporting cancellation. Cancellation is * reported as an unchecked exception by join(), and by worker 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 8ca52dc5cb29d..7c1e974aafa0b 100644 --- a/src/java.base/share/classes/java/util/concurrent/ForkJoinTask.java +++ b/src/java.base/share/classes/java/util/concurrent/ForkJoinTask.java @@ -1072,7 +1072,7 @@ public final void quietlyInvoke() { /** * Tries to join this task, returning true if it completed - * (possibly exceptionally) before the given timeout and + * (possibly exceptionally) before the given timeout elapsed and * the current thread has not been interrupted. * * @param timeout the maximum time to wait @@ -1097,7 +1097,7 @@ public final boolean quietlyJoin(long timeout, TimeUnit unit) /** * Tries to join this task, returning true if it completed - * (possibly exceptionally) before the given timeout. + * (possibly exceptionally) before the given timeout elapsed. * * @param timeout the maximum time to wait * @param unit the time unit of the timeout argument From 961e944fa731dc84be2764c01e4b326187474605 Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Fri, 16 Aug 2024 15:48:54 +0000 Subject: [PATCH 332/353] 8336754: Remodel TypeAnnotation to "has" instead of "be" an Annotation Co-authored-by: Alex Buckley Reviewed-by: asotona --- .../java/lang/classfile/Annotation.java | 46 +++++-- .../lang/classfile/AnnotationElement.java | 58 +++++--- .../java/lang/classfile/AnnotationValue.java | 127 ++++++++++-------- .../java/lang/classfile/TypeAnnotation.java | 72 +++------- .../impl/AbstractAttributeMapper.java | 4 +- .../classfile/impl/AnnotationReader.java | 70 +++++++++- .../classfile/impl/ClassPrinterImpl.java | 4 +- .../classfile/impl/ClassRemapperImpl.java | 4 +- .../classfile/impl/UnboundAttribute.java | 73 +--------- .../impl/verifier/ParserVerifier.java | 4 +- .../com/sun/tools/javap/AnnotationWriter.java | 6 +- test/jdk/jdk/classfile/ClassPrinterTest.java | 6 +- test/jdk/jdk/classfile/TransformTests.java | 2 +- .../jdk/classfile/helpers/ClassRecord.java | 2 +- .../helpers/RebuildingTransformation.java | 3 +- .../classfile/ClassfileInspector.java | 8 +- .../classfile/AnonymousClassTest.java | 4 +- .../referenceinfos/ReferenceInfoUtil.java | 4 +- .../tools/javac/patterns/Annotations.java | 4 +- .../javac/records/RecordCompilationTests.java | 2 +- 20 files changed, 260 insertions(+), 243 deletions(-) diff --git a/src/java.base/share/classes/java/lang/classfile/Annotation.java b/src/java.base/share/classes/java/lang/classfile/Annotation.java index 28c3672bf914e..357a7cb77ee83 100644 --- a/src/java.base/share/classes/java/lang/classfile/Annotation.java +++ b/src/java.base/share/classes/java/lang/classfile/Annotation.java @@ -37,43 +37,60 @@ import jdk.internal.javac.PreviewFeature; /** - * Models an annotation on a declaration. + * Models an {@code annotation} structure (JVMS {@jvms 4.7.16}) or part of a {@code + * type_annotation} structure (JVMS {@jvms 4.7.20}). This model indicates the + * interface of the annotation and a set of element-value pairs. + *

    + * This model can reconstruct an annotation, given the location of the modeled structure + * in the class file and the definition of the annotation interface. + *

    + * Two {@code Annotation} objects should be compared using the {@link + * Object#equals(Object) equals} method. + * + * @apiNote + * For Java programs, the location of the modeled structure indicates the source code + * element or type (JLS {@jls 9.7.4}) on which the reconstructed annotation appears, + * and the annotation interface definition determines whether the reconstructed annotation has + * elements with default values (JLS {@jls 9.6.2}), and whether the reconstructed annotation + * is a container annotation for multiple annotations (JLS {@jls 9.7.5}). * * @see AnnotationElement * @see AnnotationValue + * @see TypeAnnotation * @see RuntimeVisibleAnnotationsAttribute * @see RuntimeInvisibleAnnotationsAttribute * @see RuntimeVisibleParameterAnnotationsAttribute * @see RuntimeInvisibleParameterAnnotationsAttribute * - * @sealedGraph * @since 22 */ @PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API) public sealed interface Annotation - permits TypeAnnotation, AnnotationImpl { + permits AnnotationImpl { /** - * {@return the class of the annotation} + * {@return the constant pool entry holding the {@linkplain Class#descriptorString + * descriptor string} of the annotation interface} */ Utf8Entry className(); /** - * {@return the class of the annotation, as a symbolic descriptor} + * {@return the annotation interface, as a symbolic descriptor} */ default ClassDesc classSymbol() { return ClassDesc.ofDescriptor(className().stringValue()); } /** - * {@return the elements of the annotation} + * {@return the element-value pairs of the annotation} */ List elements(); /** * {@return an annotation} - * @param annotationClass the class of the annotation - * @param elements the elements of the annotation + * @param annotationClass the constant pool entry holding the descriptor string + * of the annotation interface + * @param elements the element-value pairs of the annotation */ static Annotation of(Utf8Entry annotationClass, List elements) { @@ -82,8 +99,9 @@ static Annotation of(Utf8Entry annotationClass, /** * {@return an annotation} - * @param annotationClass the class of the annotation - * @param elements the elements of the annotation + * @param annotationClass the constant pool entry holding the descriptor string + * of the annotation interface + * @param elements the element-value pairs of the annotation */ static Annotation of(Utf8Entry annotationClass, AnnotationElement... elements) { @@ -92,8 +110,8 @@ static Annotation of(Utf8Entry annotationClass, /** * {@return an annotation} - * @param annotationClass the class of the annotation - * @param elements the elements of the annotation + * @param annotationClass the descriptor of the annotation interface + * @param elements the element-value pairs of the annotation */ static Annotation of(ClassDesc annotationClass, List elements) { @@ -102,8 +120,8 @@ static Annotation of(ClassDesc annotationClass, /** * {@return an annotation} - * @param annotationClass the class of the annotation - * @param elements the elements of the annotation + * @param annotationClass the descriptor of the annotation interface + * @param elements the element-value pairs of the annotation */ static Annotation of(ClassDesc annotationClass, AnnotationElement... elements) { diff --git a/src/java.base/share/classes/java/lang/classfile/AnnotationElement.java b/src/java.base/share/classes/java/lang/classfile/AnnotationElement.java index 80adb07ec4b2a..33bd410e78dce 100644 --- a/src/java.base/share/classes/java/lang/classfile/AnnotationElement.java +++ b/src/java.base/share/classes/java/lang/classfile/AnnotationElement.java @@ -32,7 +32,13 @@ import jdk.internal.javac.PreviewFeature; /** - * Models a key-value pair of an annotation. + * Models an element-value pair in the {@code element_value_pairs} + * table in the {@code annotation} structure defined in JVMS + * {@jvms 4.7.16} or the {@code type_annotation} structure defined + * in JVMS {@jvms 4.7.20}. + *

    + * Two {@code AnnotationElement} objects should be compared using the + * {@link Object#equals(Object) equals} method. * * @see Annotation * @see AnnotationValue @@ -45,6 +51,12 @@ public sealed interface AnnotationElement /** * {@return the element name} + * + * @apiNote + * In Java source code, by convention, the name of the sole element in a + * single-element annotation interface is {@code value}. (JLS {@jls 9.6.1}) + * This is the case for single-element annotations (JLS {@jls 9.7.3}) and + * container annotations for multiple annotations (JLS {@jls 9.6.3}). */ Utf8Entry name(); @@ -54,7 +66,7 @@ public sealed interface AnnotationElement AnnotationValue value(); /** - * {@return an annotation key-value pair} + * {@return an element-value pair} * @param name the name of the key * @param value the associated value */ @@ -64,7 +76,7 @@ static AnnotationElement of(Utf8Entry name, } /** - * {@return an annotation key-value pair} + * {@return an element-value pair} * @param name the name of the key * @param value the associated value */ @@ -74,9 +86,10 @@ static AnnotationElement of(String name, } /** - * {@return an annotation key-value pair for a class-valued annotation} + * {@return an element-value pair for a class-valued element} * @param name the name of the key * @param value the associated value + * @see AnnotationValue#ofClass(ClassDesc) AnnotationValue::ofClass */ static AnnotationElement ofClass(String name, ClassDesc value) { @@ -84,9 +97,10 @@ static AnnotationElement ofClass(String name, } /** - * {@return an annotation key-value pair for a string-valued annotation} + * {@return an element-value pair for a string-valued element} * @param name the name of the key * @param value the associated value + * @see AnnotationValue#ofString(String) AnnotationValue::ofString */ static AnnotationElement ofString(String name, String value) { @@ -94,9 +108,10 @@ static AnnotationElement ofString(String name, } /** - * {@return an annotation key-value pair for a long-valued annotation} + * {@return an element-value pair for a long-valued element} * @param name the name of the key * @param value the associated value + * @see AnnotationValue#ofLong(long) AnnotationValue::ofLong */ static AnnotationElement ofLong(String name, long value) { @@ -104,9 +119,10 @@ static AnnotationElement ofLong(String name, } /** - * {@return an annotation key-value pair for an int-valued annotation} + * {@return an element-value pair for an int-valued element} * @param name the name of the key * @param value the associated value + * @see AnnotationValue#ofInt(int) AnnotationValue::ofInt */ static AnnotationElement ofInt(String name, int value) { @@ -114,9 +130,10 @@ static AnnotationElement ofInt(String name, } /** - * {@return an annotation key-value pair for a char-valued annotation} + * {@return an element-value pair for a char-valued element} * @param name the name of the key * @param value the associated value + * @see AnnotationValue#ofChar(char) AnnotationValue::ofChar */ static AnnotationElement ofChar(String name, char value) { @@ -124,9 +141,10 @@ static AnnotationElement ofChar(String name, } /** - * {@return an annotation key-value pair for a short-valued annotation} + * {@return an element-value pair for a short-valued element} * @param name the name of the key * @param value the associated value + * @see AnnotationValue#ofShort(short) AnnotationValue::ofShort */ static AnnotationElement ofShort(String name, short value) { @@ -134,29 +152,32 @@ static AnnotationElement ofShort(String name, } /** - * {@return an annotation key-value pair for a byte-valued annotation} + * {@return an element-value pair for a byte-valued element} * @param name the name of the key * @param value the associated value + * @see AnnotationValue#ofByte(byte) AnnotationValue::ofByte */ static AnnotationElement ofByte(String name, - byte value) { + byte value) { return of(name, AnnotationValue.ofByte(value)); } /** - * {@return an annotation key-value pair for a boolean-valued annotation} + * {@return an element-value pair for a boolean-valued element} * @param name the name of the key * @param value the associated value + * @see AnnotationValue#ofBoolean(boolean) AnnotationValue::ofBoolean */ static AnnotationElement ofBoolean(String name, - boolean value) { + boolean value) { return of(name, AnnotationValue.ofBoolean(value)); } /** - * {@return an annotation key-value pair for a double-valued annotation} + * {@return an element-value pair for a double-valued element} * @param name the name of the key * @param value the associated value + * @see AnnotationValue#ofDouble(double) AnnotationValue::ofDouble */ static AnnotationElement ofDouble(String name, double value) { @@ -164,9 +185,10 @@ static AnnotationElement ofDouble(String name, } /** - * {@return an annotation key-value pair for a float-valued annotation} + * {@return an element-value pair for a float-valued element} * @param name the name of the key * @param value the associated value + * @see AnnotationValue#ofFloat(float) AnnotationValue::ofFloat */ static AnnotationElement ofFloat(String name, float value) { @@ -174,9 +196,10 @@ static AnnotationElement ofFloat(String name, } /** - * {@return an annotation key-value pair for an annotation-valued annotation} + * {@return an element-value pair for an annotation-valued element} * @param name the name of the key * @param value the associated value + * @see AnnotationValue#ofAnnotation AnnotationValue::ofAnnotation */ static AnnotationElement ofAnnotation(String name, Annotation value) { @@ -184,9 +207,10 @@ static AnnotationElement ofAnnotation(String name, } /** - * {@return an annotation key-value pair for an array-valued annotation} + * {@return an element-value pair for an array-valued element} * @param name the name of the key * @param values the associated values + * @see AnnotationValue#ofArray(AnnotationValue...) AnnotationValue::ofArray */ static AnnotationElement ofArray(String name, AnnotationValue... values) { diff --git a/src/java.base/share/classes/java/lang/classfile/AnnotationValue.java b/src/java.base/share/classes/java/lang/classfile/AnnotationValue.java index 04bbcffb8bc9f..4decff86ad725 100644 --- a/src/java.base/share/classes/java/lang/classfile/AnnotationValue.java +++ b/src/java.base/share/classes/java/lang/classfile/AnnotationValue.java @@ -41,7 +41,11 @@ import jdk.internal.javac.PreviewFeature; /** - * Models the value of a key-value pair of an annotation. + * Models an {@code element_value} structure, or a value of an element-value + * pair of an annotation, as defined in JVMS {@jvms 4.7.16.1}. + *

    + * Two {@code AnnotationValue} objects should be compared using the {@link + * Object#equals(Object) equals} method. * * @see Annotation * @see AnnotationElement @@ -53,8 +57,8 @@ public sealed interface AnnotationValue { /** - * Models an annotation-valued element. - * The {@linkplain #tag tag} of this element is {@value ClassFile#AEV_ANNOTATION}. + * Models an annotation value of an element-value pair. + * The {@linkplain #tag tag} of this value is {@value ClassFile#AEV_ANNOTATION}. * * @since 22 */ @@ -66,8 +70,8 @@ sealed interface OfAnnotation extends AnnotationValue } /** - * Models an array-valued element. - * The {@linkplain #tag tag} of this element is {@value ClassFile#AEV_ARRAY}. + * Models an array value of an element-value pair. + * The {@linkplain #tag tag} of this value is {@value ClassFile#AEV_ARRAY}. * * @since 22 */ @@ -79,13 +83,15 @@ sealed interface OfArray extends AnnotationValue * * @apiNote * All array elements derived from Java source code have the same type, - * which must not be an array type. ({@jls 9.6.1}) + * which must not be an array type. (JLS {@jls 9.6.1}) If such elements are + * annotations, they have the same annotation interface; if such elements + * are enum, they belong to the same enum class. */ List values(); } /** - * Models a constant-valued element. + * Models a constant value of an element-value pair. * * @sealedGraph * @since 22 @@ -123,8 +129,8 @@ sealed interface OfConstant } /** - * Models a string-valued element. - * The {@linkplain #tag tag} of this element is {@value ClassFile#AEV_STRING}. + * Models a string value of an element-value pair. + * The {@linkplain #tag tag} of this value is {@value ClassFile#AEV_STRING}. * * @since 22 */ @@ -151,8 +157,8 @@ default String resolvedValue() { } /** - * Models a double-valued element. - * The {@linkplain #tag tag} of this element is {@value ClassFile#AEV_DOUBLE}. + * Models a double value of an element-value pair. + * The {@linkplain #tag tag} of this value is {@value ClassFile#AEV_DOUBLE}. * * @since 22 */ @@ -179,8 +185,8 @@ default Double resolvedValue() { } /** - * Models a float-valued element. - * The {@linkplain #tag tag} of this element is {@value ClassFile#AEV_FLOAT}. + * Models a float value of an element-value pair. + * The {@linkplain #tag tag} of this value is {@value ClassFile#AEV_FLOAT}. * * @since 22 */ @@ -207,8 +213,8 @@ default Float resolvedValue() { } /** - * Models a long-valued element. - * The {@linkplain #tag tag} of this element is {@value ClassFile#AEV_LONG}. + * Models a long value of an element-value pair. + * The {@linkplain #tag tag} of this value is {@value ClassFile#AEV_LONG}. * * @since 22 */ @@ -235,8 +241,8 @@ default Long resolvedValue() { } /** - * Models an int-valued element. - * The {@linkplain #tag tag} of this element is {@value ClassFile#AEV_INT}. + * Models an int value of an element-value pair. + * The {@linkplain #tag tag} of this value is {@value ClassFile#AEV_INT}. * * @since 22 */ @@ -263,8 +269,8 @@ default Integer resolvedValue() { } /** - * Models a short-valued element. - * The {@linkplain #tag tag} of this element is {@value ClassFile#AEV_SHORT}. + * Models a short value of an element-value pair. + * The {@linkplain #tag tag} of this value is {@value ClassFile#AEV_SHORT}. * * @since 22 */ @@ -294,8 +300,8 @@ default Short resolvedValue() { } /** - * Models a char-valued element. - * The {@linkplain #tag tag} of this element is {@value ClassFile#AEV_CHAR}. + * Models a char value of an element-value pair. + * The {@linkplain #tag tag} of this value is {@value ClassFile#AEV_CHAR}. * * @since 22 */ @@ -325,8 +331,8 @@ default Character resolvedValue() { } /** - * Models a byte-valued element. - * The {@linkplain #tag tag} of this element is {@value ClassFile#AEV_BYTE}. + * Models a byte value of an element-value pair. + * The {@linkplain #tag tag} of this value is {@value ClassFile#AEV_BYTE}. * * @since 22 */ @@ -356,8 +362,8 @@ default Byte resolvedValue() { } /** - * Models a boolean-valued element. - * The {@linkplain #tag tag} of this element is {@value ClassFile#AEV_BOOLEAN}. + * Models a boolean value of an element-value pair. + * The {@linkplain #tag tag} of this value is {@value ClassFile#AEV_BOOLEAN}. * * @since 22 */ @@ -387,8 +393,8 @@ default Boolean resolvedValue() { } /** - * Models a class-valued element. - * The {@linkplain #tag tag} of this element is {@value ClassFile#AEV_CLASS}. + * Models a class value of an element-value pair. + * The {@linkplain #tag tag} of this value is {@value ClassFile#AEV_CLASS}. * * @since 22 */ @@ -405,8 +411,8 @@ default ClassDesc classSymbol() { } /** - * Models an enum-valued element. - * The {@linkplain #tag tag} of this element is {@value ClassFile#AEV_ENUM}. + * Models an enum value of an element-value pair. + * The {@linkplain #tag tag} of this value is {@value ClassFile#AEV_ENUM}. * * @since 22 */ @@ -426,12 +432,13 @@ default ClassDesc classSymbol() { } /** - * {@return the tag character for this type as per JVMS {@jvms 4.7.16.1}} + * {@return the tag character for this value as per JVMS {@jvms 4.7.16.1}} + * The tag characters have a one-to-one mapping to the types of annotation element values. */ char tag(); /** - * {@return an annotation element for a enum-valued element} + * {@return an enum value for an element-value pair} * @param className the descriptor string of the enum class * @param constantName the name of the enum constant */ @@ -441,7 +448,7 @@ static OfEnum ofEnum(Utf8Entry className, } /** - * {@return an annotation element for a enum-valued element} + * {@return an enum value for an element-value pair} * @param className the descriptor of the enum class * @param constantName the name of the enum constant */ @@ -451,7 +458,7 @@ static OfEnum ofEnum(ClassDesc className, String constantName) { } /** - * {@return an annotation element for a class-valued element} + * {@return a class value for an element-value pair} * @param className the descriptor string of the class */ static OfClass ofClass(Utf8Entry className) { @@ -459,7 +466,7 @@ static OfClass ofClass(Utf8Entry className) { } /** - * {@return an annotation element for a class-valued element} + * {@return a class value for an element-value pair} * @param className the descriptor of the class */ static OfClass ofClass(ClassDesc className) { @@ -467,7 +474,7 @@ static OfClass ofClass(ClassDesc className) { } /** - * {@return an annotation element for a string-valued element} + * {@return a string value for an element-value pair} * @param value the string */ static OfString ofString(Utf8Entry value) { @@ -475,7 +482,7 @@ static OfString ofString(Utf8Entry value) { } /** - * {@return an annotation element for a string-valued element} + * {@return a string value for an element-value pair} * @param value the string */ static OfString ofString(String value) { @@ -483,7 +490,7 @@ static OfString ofString(String value) { } /** - * {@return an annotation element for a double-valued element} + * {@return a double value for an element-value pair} * @param value the double value */ static OfDouble ofDouble(DoubleEntry value) { @@ -491,7 +498,7 @@ static OfDouble ofDouble(DoubleEntry value) { } /** - * {@return an annotation element for a double-valued element} + * {@return a double value for an element-value pair} * @param value the double value */ static OfDouble ofDouble(double value) { @@ -499,7 +506,7 @@ static OfDouble ofDouble(double value) { } /** - * {@return an annotation element for a float-valued element} + * {@return a float value for an element-value pair} * @param value the float value */ static OfFloat ofFloat(FloatEntry value) { @@ -507,7 +514,7 @@ static OfFloat ofFloat(FloatEntry value) { } /** - * {@return an annotation element for a float-valued element} + * {@return a float value for an element-value pair} * @param value the float value */ static OfFloat ofFloat(float value) { @@ -515,7 +522,7 @@ static OfFloat ofFloat(float value) { } /** - * {@return an annotation element for a long-valued element} + * {@return a long value for an element-value pair} * @param value the long value */ static OfLong ofLong(LongEntry value) { @@ -523,7 +530,7 @@ static OfLong ofLong(LongEntry value) { } /** - * {@return an annotation element for a long-valued element} + * {@return a long value for an element-value pair} * @param value the long value */ static OfLong ofLong(long value) { @@ -531,7 +538,7 @@ static OfLong ofLong(long value) { } /** - * {@return an annotation element for an int-valued element} + * {@return an int value for an element-value pair} * @param value the int value */ static OfInt ofInt(IntegerEntry value) { @@ -539,7 +546,7 @@ static OfInt ofInt(IntegerEntry value) { } /** - * {@return an annotation element for an int-valued element} + * {@return an int value for an element-value pair} * @param value the int value */ static OfInt ofInt(int value) { @@ -547,7 +554,7 @@ static OfInt ofInt(int value) { } /** - * {@return an annotation element for a short-valued element} + * {@return a short value for an element-value pair} * @param value the short value */ static OfShort ofShort(IntegerEntry value) { @@ -555,7 +562,7 @@ static OfShort ofShort(IntegerEntry value) { } /** - * {@return an annotation element for a short-valued element} + * {@return a short value for an element-value pair} * @param value the short value */ static OfShort ofShort(short value) { @@ -563,7 +570,7 @@ static OfShort ofShort(short value) { } /** - * {@return an annotation element for a char-valued element} + * {@return a char value for an element-value pair} * @param value the char value */ static OfChar ofChar(IntegerEntry value) { @@ -571,7 +578,7 @@ static OfChar ofChar(IntegerEntry value) { } /** - * {@return an annotation element for a char-valued element} + * {@return a char value for an element-value pair} * @param value the char value */ static OfChar ofChar(char value) { @@ -579,7 +586,7 @@ static OfChar ofChar(char value) { } /** - * {@return an annotation element for a byte-valued element} + * {@return a byte value for an element-value pair} * @param value the byte value */ static OfByte ofByte(IntegerEntry value) { @@ -587,7 +594,7 @@ static OfByte ofByte(IntegerEntry value) { } /** - * {@return an annotation element for a byte-valued element} + * {@return a byte value for an element-value pair} * @param value the byte value */ static OfByte ofByte(byte value) { @@ -595,7 +602,7 @@ static OfByte ofByte(byte value) { } /** - * {@return an annotation element for a boolean-valued element} + * {@return a boolean value for an element-value pair} * @param value the boolean value */ static OfBoolean ofBoolean(IntegerEntry value) { @@ -603,7 +610,7 @@ static OfBoolean ofBoolean(IntegerEntry value) { } /** - * {@return an annotation element for a boolean-valued element} + * {@return a boolean value for an element-value pair} * @param value the boolean value */ static OfBoolean ofBoolean(boolean value) { @@ -612,7 +619,7 @@ static OfBoolean ofBoolean(boolean value) { } /** - * {@return an annotation element for an annotation-valued element} + * {@return an annotation value for an element-value pair} * @param value the annotation */ static OfAnnotation ofAnnotation(Annotation value) { @@ -620,7 +627,12 @@ static OfAnnotation ofAnnotation(Annotation value) { } /** - * {@return an annotation element for an array-valued element} + * {@return an array value for an element-value pair} + * + * @apiNote + * See {@link AnnotationValue.OfArray#values() values()} for conventions + * on array values derived from Java source code. + * * @param values the array elements */ static OfArray ofArray(List values) { @@ -628,7 +640,12 @@ static OfArray ofArray(List values) { } /** - * {@return an annotation element for an array-valued element} + * {@return an array value for an element-value pair} + * + * @apiNote + * See {@link AnnotationValue.OfArray#values() values()} for conventions + * on array values derived from Java source code. + * * @param values the array elements */ static OfArray ofArray(AnnotationValue... values) { diff --git a/src/java.base/share/classes/java/lang/classfile/TypeAnnotation.java b/src/java.base/share/classes/java/lang/classfile/TypeAnnotation.java index 01a2f5fc696c5..b6c9aec76a1a3 100644 --- a/src/java.base/share/classes/java/lang/classfile/TypeAnnotation.java +++ b/src/java.base/share/classes/java/lang/classfile/TypeAnnotation.java @@ -25,12 +25,10 @@ package java.lang.classfile; -import java.lang.constant.ClassDesc; import java.util.List; import java.lang.classfile.attribute.RuntimeInvisibleTypeAnnotationsAttribute; import java.lang.classfile.attribute.RuntimeVisibleTypeAnnotationsAttribute; -import java.lang.classfile.constantpool.Utf8Entry; import jdk.internal.classfile.impl.TargetInfoImpl; import jdk.internal.classfile.impl.UnboundAttribute; @@ -56,12 +54,22 @@ import static java.lang.classfile.ClassFile.TAT_NEW; import static java.lang.classfile.ClassFile.TAT_RESOURCE_VARIABLE; import static java.lang.classfile.ClassFile.TAT_THROWS; -import jdk.internal.classfile.impl.TemporaryConstantPool; import jdk.internal.javac.PreviewFeature; /** - * Models an annotation on a type use, as defined in JVMS {@jvms 4.7.19} and {@jvms 4.7.20}. + * Models a {@code type_annotation} structure (JVMS {@jvms 4.7.20}). This model + * indicates the annotated type within a declaration or expression and the part + * of the indicated type that is annotated, in addition to what is {@linkplain + * #annotation() available} in an {@code Annotation}. + *

    + * This model can reconstruct an annotation on a type or a part of a type, given + * the location of the {@code type_annotation} structure in the class file and + * the definition of the annotation interface. + *

    + * Two {@code TypeAnnotation} objects should be compared using the {@link + * Object#equals(Object) equals} method. * + * @see Annotation * @see RuntimeVisibleTypeAnnotationsAttribute * @see RuntimeInvisibleTypeAnnotationsAttribute * @@ -69,7 +77,6 @@ */ @PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API) public sealed interface TypeAnnotation - extends Annotation permits UnboundAttribute.UnboundTypeAnnotation { /** @@ -170,7 +177,7 @@ public int sizeIfFixed() { /** * {@return information describing precisely which type in a declaration or expression - * is annotated} + * is annotated} This models the {@code target_type} and {@code target_info} items. */ TargetInfo targetInfo(); @@ -180,57 +187,22 @@ public int sizeIfFixed() { List targetPath(); /** - * {@return a type annotation} - * @param targetInfo which type in a declaration or expression is annotated - * @param targetPath which part of the type is annotated - * @param annotationClassUtf8Entry the annotation class - * @param annotationElements the annotation elements - */ - static TypeAnnotation of(TargetInfo targetInfo, List targetPath, - Utf8Entry annotationClassUtf8Entry, - List annotationElements) { - return new UnboundAttribute.UnboundTypeAnnotation(targetInfo, targetPath, - annotationClassUtf8Entry, annotationElements); - } - - /** - * {@return a type annotation} - * @param targetInfo which type in a declaration or expression is annotated - * @param targetPath which part of the type is annotated - * @param annotationClass the annotation class - * @param annotationElements the annotation elements + * {@return the annotation applied to the part indicated by {@link #targetPath()}} + * This models the interface of the annotation and the set of element-value pairs, + * the subset of the {@code type_annotation} structure that is identical to the + * {@code annotation} structure. */ - static TypeAnnotation of(TargetInfo targetInfo, List targetPath, - ClassDesc annotationClass, - AnnotationElement... annotationElements) { - return of(targetInfo, targetPath, annotationClass, List.of(annotationElements)); - } - - /** - * {@return a type annotation} - * @param targetInfo which type in a declaration or expression is annotated - * @param targetPath which part of the type is annotated - * @param annotationClass the annotation class - * @param annotationElements the annotation elements - */ - static TypeAnnotation of(TargetInfo targetInfo, List targetPath, - ClassDesc annotationClass, - List annotationElements) { - return of(targetInfo, targetPath, - TemporaryConstantPool.INSTANCE.utf8Entry(annotationClass.descriptorString()), annotationElements); - } + Annotation annotation(); /** - * {@return a type annotation} + * {@return a {@code type_annotation} structure} * @param targetInfo which type in a declaration or expression is annotated * @param targetPath which part of the type is annotated - * @param annotationClassUtf8Entry the annotation class - * @param annotationElements the annotation elements + * @param annotation the annotation */ static TypeAnnotation of(TargetInfo targetInfo, List targetPath, - Utf8Entry annotationClassUtf8Entry, - AnnotationElement... annotationElements) { - return of(targetInfo, targetPath, annotationClassUtf8Entry, List.of(annotationElements)); + Annotation annotation) { + return new UnboundAttribute.UnboundTypeAnnotation(targetInfo, targetPath, annotation); } /** diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractAttributeMapper.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractAttributeMapper.java index 0029b503d7a2d..8be167cd11928 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractAttributeMapper.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractAttributeMapper.java @@ -657,7 +657,7 @@ public RuntimeInvisibleTypeAnnotationsAttribute readAttribute(AttributedElement @Override protected void writeBody(BufWriter buf, RuntimeInvisibleTypeAnnotationsAttribute attr) { - AnnotationReader.writeAnnotations(buf, attr.annotations()); + AnnotationReader.writeTypeAnnotations(buf, attr.annotations()); } } @@ -714,7 +714,7 @@ public RuntimeVisibleTypeAnnotationsAttribute readAttribute(AttributedElement e, @Override protected void writeBody(BufWriter buf, RuntimeVisibleTypeAnnotationsAttribute attr) { - AnnotationReader.writeAnnotations(buf, attr.annotations()); + AnnotationReader.writeTypeAnnotations(buf, attr.annotations()); } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationReader.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationReader.java index e21938bbc0cd5..6802d6e75aa16 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationReader.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationReader.java @@ -241,10 +241,8 @@ private static TypeAnnotation readTypeAnnotation(ClassReader classReader, int p, }; } // the annotation info for this annotation - Utf8Entry type = classReader.readEntry(p, Utf8Entry.class); - p += 2; - return TypeAnnotation.of(targetInfo, List.of(typePath), type, - readAnnotationElementValuePairs(classReader, p)); + var anno = readAnnotation(classReader, p); + return TypeAnnotation.of(targetInfo, List.of(typePath), anno); } private static List readLocalVarEntries(ClassReader classReader, int p, LabelContext lc, int targetType) { @@ -283,13 +281,11 @@ private static int skipTypeAnnotation(ClassReader classReader, int p) { } public static void writeAnnotation(BufWriterImpl buf, Annotation annotation) { - // handles annotations and type annotations // TODO annotation cleanup later ((Util.Writable) annotation).writeTo(buf); } - public static void writeAnnotations(BufWriter buf, List list) { - // handles annotations and type annotations + public static void writeAnnotations(BufWriter buf, List list) { var internalBuf = (BufWriterImpl) buf; internalBuf.writeU2(list.size()); for (var e : list) { @@ -297,6 +293,66 @@ public static void writeAnnotations(BufWriter buf, List li } } + private static int labelToBci(LabelContext lr, Label label, TypeAnnotation ta) { + //helper method to avoid NPE + if (lr == null) throw new IllegalArgumentException("Illegal targetType '%s' in TypeAnnotation outside of Code attribute".formatted(ta.targetInfo().targetType())); + return lr.labelToBci(label); + } + + public static void writeTypeAnnotation(BufWriterImpl buf, TypeAnnotation ta) { + LabelContext lr = buf.labelContext(); + // target_type + buf.writeU1(ta.targetInfo().targetType().targetTypeValue()); + + // target_info + switch (ta.targetInfo()) { + case TypeAnnotation.TypeParameterTarget tpt -> buf.writeU1(tpt.typeParameterIndex()); + case TypeAnnotation.SupertypeTarget st -> buf.writeU2(st.supertypeIndex()); + case TypeAnnotation.TypeParameterBoundTarget tpbt -> { + buf.writeU1(tpbt.typeParameterIndex()); + buf.writeU1(tpbt.boundIndex()); + } + case TypeAnnotation.EmptyTarget _ -> { + // nothing to write + } + case TypeAnnotation.FormalParameterTarget fpt -> buf.writeU1(fpt.formalParameterIndex()); + case TypeAnnotation.ThrowsTarget tt -> buf.writeU2(tt.throwsTargetIndex()); + case TypeAnnotation.LocalVarTarget lvt -> { + buf.writeU2(lvt.table().size()); + for (var e : lvt.table()) { + int startPc = labelToBci(lr, e.startLabel(), ta); + buf.writeU2(startPc); + buf.writeU2(labelToBci(lr, e.endLabel(), ta) - startPc); + buf.writeU2(e.index()); + } + } + case TypeAnnotation.CatchTarget ct -> buf.writeU2(ct.exceptionTableIndex()); + case TypeAnnotation.OffsetTarget ot -> buf.writeU2(labelToBci(lr, ot.target(), ta)); + case TypeAnnotation.TypeArgumentTarget tat -> { + buf.writeU2(labelToBci(lr, tat.target(), ta)); + buf.writeU1(tat.typeArgumentIndex()); + } + } + + // target_path + buf.writeU1(ta.targetPath().size()); + for (TypeAnnotation.TypePathComponent component : ta.targetPath()) { + buf.writeU1(component.typePathKind().tag()); + buf.writeU1(component.typeArgumentIndex()); + } + + // annotation data + writeAnnotation(buf, ta.annotation()); + } + + public static void writeTypeAnnotations(BufWriter buf, List list) { + var internalBuf = (BufWriterImpl) buf; + internalBuf.writeU2(list.size()); + for (var e : list) { + writeTypeAnnotation(internalBuf, e); + } + } + public static void writeAnnotationValue(BufWriterImpl buf, AnnotationValue value) { // TODO annotation cleanup later ((Util.Writable) value).writeTo(buf); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassPrinterImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassPrinterImpl.java index 75346dd59985f..2a648e27568f1 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassPrinterImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassPrinterImpl.java @@ -1038,9 +1038,9 @@ private static Node annotationsToTree(String name, List annos) { private static Node typeAnnotationsToTree(Style style, String name, List annos) { return new ListNodeImpl(style, name, annos.stream().map(a -> new MapNodeImpl(FLOW, "anno") - .with(leaf("annotation class", a.className().stringValue()), + .with(leaf("annotation class", a.annotation().className().stringValue()), leaf("target info", a.targetInfo().targetType().name())) - .with(elementValuePairsToTree(a.elements())))); + .with(elementValuePairsToTree(a.annotation().elements())))); } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassRemapperImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassRemapperImpl.java index e3f701b2e2adb..9b5e7639fa2a4 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassRemapperImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassRemapperImpl.java @@ -401,9 +401,7 @@ AnnotationValue mapAnnotationValue(AnnotationValue val) { List mapTypeAnnotations(List typeAnnotations) { return typeAnnotations.stream().map(a -> TypeAnnotation.of(a.targetInfo(), - a.targetPath(), map(a.classSymbol()), - a.elements().stream().map(el -> AnnotationElement.of(el.name(), - mapAnnotationValue(el.value()))).toList())).toList(); + a.targetPath(), mapAnnotation(a.annotation()))).toList(); } List mapTypeParams(List typeParams) { diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/UnboundAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/impl/UnboundAttribute.java index 6b64511fd5a13..5ee3759bba334 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/UnboundAttribute.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/UnboundAttribute.java @@ -29,14 +29,12 @@ import java.util.Optional; import java.lang.classfile.Annotation; -import java.lang.classfile.AnnotationElement; import java.lang.classfile.AnnotationValue; import java.lang.classfile.Attribute; import java.lang.classfile.AttributeMapper; import java.lang.classfile.Attributes; import java.lang.classfile.BootstrapMethodEntry; import java.lang.classfile.constantpool.ClassEntry; -import java.lang.classfile.Label; import java.lang.classfile.TypeAnnotation; import java.lang.classfile.attribute.AnnotationDefaultAttribute; import java.lang.classfile.attribute.BootstrapMethodsAttribute; @@ -758,75 +756,10 @@ public UnboundRecordComponentInfo(Utf8Entry name, Utf8Entry descriptor, List targetPath, - Utf8Entry className, - List elements) implements TypeAnnotation, Util.Writable { - - public UnboundTypeAnnotation(TargetInfo targetInfo, List targetPath, - Utf8Entry className, List elements) { - this.targetInfo = targetInfo; - this.targetPath = List.copyOf(targetPath); - this.className = className; - this.elements = List.copyOf(elements); - } - - private int labelToBci(LabelContext lr, Label label) { - //helper method to avoid NPE - if (lr == null) throw new IllegalArgumentException("Illegal targetType '%s' in TypeAnnotation outside of Code attribute".formatted(targetInfo.targetType())); - return lr.labelToBci(label); - } - - @Override - public void writeTo(BufWriterImpl buf) { - LabelContext lr = buf.labelContext(); - // target_type - buf.writeU1(targetInfo.targetType().targetTypeValue()); - - // target_info - switch (targetInfo) { - case TypeParameterTarget tpt -> buf.writeU1(tpt.typeParameterIndex()); - case SupertypeTarget st -> buf.writeU2(st.supertypeIndex()); - case TypeParameterBoundTarget tpbt -> { - buf.writeU1(tpbt.typeParameterIndex()); - buf.writeU1(tpbt.boundIndex()); - } - case EmptyTarget et -> { - // nothing to write - } - case FormalParameterTarget fpt -> buf.writeU1(fpt.formalParameterIndex()); - case ThrowsTarget tt -> buf.writeU2(tt.throwsTargetIndex()); - case LocalVarTarget lvt -> { - buf.writeU2(lvt.table().size()); - for (var e : lvt.table()) { - int startPc = labelToBci(lr, e.startLabel()); - buf.writeU2(startPc); - buf.writeU2(labelToBci(lr, e.endLabel()) - startPc); - buf.writeU2(e.index()); - } - } - case CatchTarget ct -> buf.writeU2(ct.exceptionTableIndex()); - case OffsetTarget ot -> buf.writeU2(labelToBci(lr, ot.target())); - case TypeArgumentTarget tat -> { - buf.writeU2(labelToBci(lr, tat.target())); - buf.writeU1(tat.typeArgumentIndex()); - } - } + Annotation annotation) implements TypeAnnotation { - // target_path - buf.writeU1(targetPath().size()); - for (TypePathComponent component : targetPath()) { - buf.writeU1(component.typePathKind().tag()); - buf.writeU1(component.typeArgumentIndex()); - } - - // type_index - buf.writeIndex(className); - - // element_value_pairs - buf.writeU2(elements.size()); - for (AnnotationElement pair : elements()) { - buf.writeIndex(pair.name()); - AnnotationReader.writeAnnotationValue(buf, pair.value()); - } + public UnboundTypeAnnotation { + targetPath = List.copyOf(targetPath); } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/ParserVerifier.java b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/ParserVerifier.java index 4a2ffd3f25d3f..77f56b322ddf9 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/ParserVerifier.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/ParserVerifier.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -393,7 +393,7 @@ private static int annotationsSize(List ans) { private static int typeAnnotationsSize(List ans) { int l = 2; for (var an : ans) { - l += 2 + an.targetInfo().size() + 2 * an.targetPath().size() + annotationSize(an); + l += 2 + an.targetInfo().size() + 2 * an.targetPath().size() + annotationSize(an.annotation()); } return l; } diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/javap/AnnotationWriter.java b/src/jdk.jdeps/share/classes/com/sun/tools/javap/AnnotationWriter.java index ae5cd2df02451..66b978f252c53 100644 --- a/src/jdk.jdeps/share/classes/com/sun/tools/javap/AnnotationWriter.java +++ b/src/jdk.jdeps/share/classes/com/sun/tools/javap/AnnotationWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -95,13 +95,13 @@ public void write(TypeAnnotation annot, CodeAttribute lr) { write(annot, true, false, lr); println(); indent(+1); - write(annot, true); + write(annot.annotation(), true); indent(-1); } public void write(TypeAnnotation annot, boolean showOffsets, boolean resolveIndices, CodeAttribute lr) { - write(annot, resolveIndices); + write(annot.annotation(), resolveIndices); print(": "); write(annot.targetInfo(), annot.targetPath(), showOffsets, lr); } diff --git a/test/jdk/jdk/classfile/ClassPrinterTest.java b/test/jdk/jdk/classfile/ClassPrinterTest.java index 7668648f82901..bd95075a08e19 100644 --- a/test/jdk/jdk/classfile/ClassPrinterTest.java +++ b/test/jdk/jdk/classfile/ClassPrinterTest.java @@ -66,7 +66,7 @@ ClassModel getClassModel() { RuntimeInvisibleTypeAnnotationsAttribute.of( TypeAnnotation.of(TypeAnnotation.TargetInfo.ofField(), List.of(TypeAnnotation.TypePathComponent.WILDCARD), - ClassDesc.of("Boo"), List.of())))))) + Annotation.of(ClassDesc.of("Boo"), List.of()))))))) .with(RuntimeInvisibleAnnotationsAttribute.of(Annotation.of(ClassDesc.of("Phoo"), AnnotationElement.ofFloat("flfl", 2), AnnotationElement.ofFloat("frfl", 3)))) .with(PermittedSubclassesAttribute.ofSymbols(ClassDesc.of("Boo"), ClassDesc.of("Phoo"))) .withField("f", ConstantDescs.CD_String, fb -> fb @@ -101,7 +101,7 @@ ClassModel getClassModel() { tryb.with(RuntimeInvisibleTypeAnnotationsAttribute.of( TypeAnnotation.of(TypeAnnotation.TargetInfo.ofField(), List.of(TypeAnnotation.TypePathComponent.WILDCARD), - ClassDesc.of("Boo"), List.of()))); + Annotation.of(ClassDesc.of("Boo"), List.of())))); tryb.invokedynamic(DynamicCallSiteDesc.of( MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.STATIC, ClassDesc.of("Phoo"), "phee", MethodTypeDesc.of(ClassDesc.of("Boo"))), "intfMethod", @@ -116,7 +116,7 @@ ClassModel getClassModel() { .with(RuntimeVisibleTypeAnnotationsAttribute.of( TypeAnnotation.of(TypeAnnotation.TargetInfo.ofField(), List.of(TypeAnnotation.TypePathComponent.ARRAY), - ClassDesc.of("Fee"), List.of(AnnotationElement.ofBoolean("yes", false))))) + Annotation.of(ClassDesc.of("Fee"), List.of(AnnotationElement.ofBoolean("yes", false)))))) )))); } diff --git a/test/jdk/jdk/classfile/TransformTests.java b/test/jdk/jdk/classfile/TransformTests.java index fb9f72ba3aacc..b78da8b431154 100644 --- a/test/jdk/jdk/classfile/TransformTests.java +++ b/test/jdk/jdk/classfile/TransformTests.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8336010 8336588 + * @bug 8335935 8336588 * @summary Testing ClassFile transformations. * @run junit TransformTests */ diff --git a/test/jdk/jdk/classfile/helpers/ClassRecord.java b/test/jdk/jdk/classfile/helpers/ClassRecord.java index a62ef1723677f..ce22037ccda6b 100644 --- a/test/jdk/jdk/classfile/helpers/ClassRecord.java +++ b/test/jdk/jdk/classfile/helpers/ClassRecord.java @@ -828,7 +828,7 @@ public static TypeAnnotationRecord ofTypeAnnotation(TypeAnnotation ann, CodeAttr ann.targetInfo().targetType().targetTypeValue(), TargetInfoRecord.ofTargetInfo(ann.targetInfo(), lr, code), ann.targetPath().stream().map(tpc -> TypePathRecord.ofTypePathComponent(tpc)).collect(toSet()), - AnnotationRecord.ofAnnotation(ann)); + AnnotationRecord.ofAnnotation(ann.annotation())); } public interface TargetInfoRecord { diff --git a/test/jdk/jdk/classfile/helpers/RebuildingTransformation.java b/test/jdk/jdk/classfile/helpers/RebuildingTransformation.java index 7667403aaabc7..b769898d785e0 100644 --- a/test/jdk/jdk/classfile/helpers/RebuildingTransformation.java +++ b/test/jdk/jdk/classfile/helpers/RebuildingTransformation.java @@ -179,8 +179,7 @@ static TypeAnnotation[] transformTypeAnnotations(List annotation return annotations.stream().map(ta -> TypeAnnotation.of( transformTargetInfo(ta.targetInfo(), cob, labels), ta.targetPath().stream().map(tpc -> TypeAnnotation.TypePathComponent.of(tpc.typePathKind(), tpc.typeArgumentIndex())).toList(), - ta.classSymbol(), - ta.elements().stream().map(ae -> AnnotationElement.of(ae.name().stringValue(), transformAnnotationValue(ae.value()))).toList())).toArray(TypeAnnotation[]::new); + transformAnnotation(ta.annotation()))).toArray(TypeAnnotation[]::new); } static TypeAnnotation.TargetInfo transformTargetInfo(TypeAnnotation.TargetInfo ti, CodeBuilder cob, HashMap labels) { diff --git a/test/langtools/lib/annotations/annotations/classfile/ClassfileInspector.java b/test/langtools/lib/annotations/annotations/classfile/ClassfileInspector.java index d6219dbff119f..30a5f54ac26d8 100644 --- a/test/langtools/lib/annotations/annotations/classfile/ClassfileInspector.java +++ b/test/langtools/lib/annotations/annotations/classfile/ClassfileInspector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -603,7 +603,7 @@ public void matchAnnotation(TypeAnnotation anno) { } public boolean checkMatch(TypeAnnotation anno) { - boolean matches = checkMatch((Annotation) anno); + boolean matches = checkMatch(anno.annotation()); int boundIdx = Integer.MIN_VALUE, paraIdx = Integer.MIN_VALUE, tIdx = Integer.MIN_VALUE, exIdx = Integer.MIN_VALUE; switch (anno.targetInfo()) { case TypeAnnotation.TypeParameterBoundTarget binfo -> { @@ -1197,8 +1197,8 @@ public void annoMatcher(Attribute attr, ExpectedAnnotation expected) { switch (attr) { case RuntimeVisibleTypeAnnotationsAttribute rvattr -> { if (expected.matchVisibility(true)) { - for(Annotation anno : rvattr.annotations()) { - expected.matchAnnotation(anno); + for(var anno : rvattr.annotations()) { + expected.matchAnnotation(anno.annotation()); } } } diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/classfile/AnonymousClassTest.java b/test/langtools/tools/javac/annotations/typeAnnotations/classfile/AnonymousClassTest.java index 94610ddf05518..eb4b5aa2cf717 100644 --- a/test/langtools/tools/javac/annotations/typeAnnotations/classfile/AnonymousClassTest.java +++ b/test/langtools/tools/javac/annotations/typeAnnotations/classfile/AnonymousClassTest.java @@ -215,7 +215,7 @@ private static String annotationDebugString(ClassModel cm, CodeAttribute cAttr, int offset = info instanceof TypeAnnotation.OffsetTarget offsetInfo? cAttr.labelToBci(offsetInfo.target()): -1; String name; try { - name = annotation.classSymbol().descriptorString(); + name = annotation.annotation().classSymbol().descriptorString(); } catch (Exception e) { throw new AssertionError(e); } @@ -227,7 +227,7 @@ private static String annotationDebugString(ClassModel cm, CodeAttribute cAttr, return String.format( "@%s(%s) %s, offset=%d, location=%s", name, - annotationValueDebugString(cm, annotation), + annotationValueDebugString(cm, annotation.annotation()), info.targetType(), offset, location); diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/referenceinfos/ReferenceInfoUtil.java b/test/langtools/tools/javac/annotations/typeAnnotations/referenceinfos/ReferenceInfoUtil.java index e2e69a01a491c..18e3a3dec56f7 100644 --- a/test/langtools/tools/javac/annotations/typeAnnotations/referenceinfos/ReferenceInfoUtil.java +++ b/test/langtools/tools/javac/annotations/typeAnnotations/referenceinfos/ReferenceInfoUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -97,7 +97,7 @@ private static List generateTADList(List annos, CodeAttribu List result = new ArrayList<>(); for (TypeAnnotation anno: annos) { TAD tad = new TAD(); - tad.annotation = anno.className().stringValue(); + tad.annotation = anno.annotation().className().stringValue(); tad.type = anno.targetInfo().targetType(); switch (anno.targetInfo().targetType()) { case CAST, CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT, METHOD_INVOCATION_TYPE_ARGUMENT -> { diff --git a/test/langtools/tools/javac/patterns/Annotations.java b/test/langtools/tools/javac/patterns/Annotations.java index a471cc57b63e7..a8106a39827ed 100644 --- a/test/langtools/tools/javac/patterns/Annotations.java +++ b/test/langtools/tools/javac/patterns/Annotations.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -74,7 +74,7 @@ void run() throws Exception { StringBuilder actual = new StringBuilder(); for (TypeAnnotation ta: annotations.annotations()) { TypeAnnotation.LocalVarTargetInfo info = ((TypeAnnotation.LocalVarTarget) ta.targetInfo()).table().getFirst(); - actual.append(ta.className().stringValue() + " pos: [" + ta.targetInfo().targetType()); + actual.append(ta.annotation().className().stringValue() + " pos: [" + ta.targetInfo().targetType()); actual.append(", {start_pc=" + codeAttr.labelToBci(info.startLabel()) + ", end_pc=" + codeAttr.labelToBci(info.endLabel())); actual.append(", index=" + info.index()+ "}], "); } diff --git a/test/langtools/tools/javac/records/RecordCompilationTests.java b/test/langtools/tools/javac/records/RecordCompilationTests.java index d80ade50a3b76..a01712fedb37e 100644 --- a/test/langtools/tools/javac/records/RecordCompilationTests.java +++ b/test/langtools/tools/javac/records/RecordCompilationTests.java @@ -1615,7 +1615,7 @@ private void checkTypeAnno(Attribute rtAnnos, } assert tAnno != null; Assert.check(tAnno.targetInfo().targetType().name().equals(positionType)); - String annotationName = tAnno.classSymbol().displayName(); + String annotationName = tAnno.annotation().classSymbol().displayName(); Assert.check(annotationName.startsWith(annoName)); } private void checkAnno(Attribute rAnnos, From 8635642dbdfb74d2ae50a51611fd2c5980fe6e74 Mon Sep 17 00:00:00 2001 From: Chris Plummer Date: Fri, 16 Aug 2024 16:39:36 +0000 Subject: [PATCH 333/353] 8338469: com/sun/jdi/DataDumpTest.java failed with Not a debuggee, or not listening for debugger to attach Reviewed-by: dcubed --- test/jdk/com/sun/jdi/DataDumpTest.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/test/jdk/com/sun/jdi/DataDumpTest.java b/test/jdk/com/sun/jdi/DataDumpTest.java index f46d0d5de4f19..8d7404f58e9c9 100644 --- a/test/jdk/com/sun/jdi/DataDumpTest.java +++ b/test/jdk/com/sun/jdi/DataDumpTest.java @@ -84,6 +84,11 @@ private static void runTest(String jdwpArg) throws Exception { try { p = pb.start(); InputStream is = p.getInputStream(); + + // Read the first character of output to make sure we've waited until the + // debuggee is ready. This will be the debug agent's "Listening..." message. + char firstChar = (char)is.read(); + out = new OutputAnalyzer(p); // Attach a debugger and do the data dump. The data dump output will appear @@ -92,8 +97,8 @@ private static void runTest(String jdwpArg) throws Exception { out.waitFor(); // Wait for the debuggee to exit - System.out.println("Deuggee output:"); - System.out.println(out.getOutput()); + System.out.println("Debuggee output:"); + System.out.println(firstChar + out.getOutput()); // All these strings are part of the debug agent data dump output. out.shouldHaveExitValue(0); From 2f7ba781bf2e4e6d0fa658c19f86c6c05d60358a Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Mon, 19 Aug 2024 04:44:24 +0000 Subject: [PATCH 334/353] 8335150: Test LogGeneratedClassesTest.java fails on rpmbuild mock enviroment Reviewed-by: jpai --- .../lambda/LogGeneratedClassesTest.java | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/test/jdk/java/lang/invoke/lambda/LogGeneratedClassesTest.java b/test/jdk/java/lang/invoke/lambda/LogGeneratedClassesTest.java index 91ea4b932cab1..06aa479717b5b 100644 --- a/test/jdk/java/lang/invoke/lambda/LogGeneratedClassesTest.java +++ b/test/jdk/java/lang/invoke/lambda/LogGeneratedClassesTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,6 +40,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.nio.file.FileStore; import java.nio.file.attribute.PosixFileAttributeView; import jdk.test.lib.compiler.CompilerUtils; @@ -47,6 +48,7 @@ import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; +import org.testng.SkipException; import static java.nio.file.attribute.PosixFilePermissions.*; import static jdk.test.lib.process.ProcessTools.*; @@ -207,15 +209,15 @@ private static boolean isWriteableDirectory(Path p) { @Test public void testDumpDirNotWritable() throws Exception { - if (!Files.getFileStore(Paths.get(".")) - .supportsFileAttributeView(PosixFileAttributeView.class)) { + FileStore fs; + try { + fs = Files.getFileStore(Paths.get(".")); + } catch (IOException e) { + throw new SkipException("WARNING: IOException occurred: " + e + ", Skipping testDumpDirNotWritable test."); + } + if (!fs.supportsFileAttributeView(PosixFileAttributeView.class)) { // No easy way to setup readonly directory without POSIX - // We would like to skip the test with a cause with - // throw new SkipException("Posix not supported"); - // but jtreg will report failure so we just pass the test - // which we can look at if jtreg changed its behavior - System.out.println("WARNING: POSIX is not supported. Skipping testDumpDirNotWritable test."); - return; + throw new SkipException("WARNING: POSIX is not supported. Skipping testDumpDirNotWritable test."); } Path testDir = Path.of("readOnly"); @@ -227,8 +229,7 @@ public void testDumpDirNotWritable() throws Exception { if (isWriteableDirectory(dumpDir)) { // Skipping the test: it's allowed to write into read-only directory // (e.g. current user is super user). - System.out.println("WARNING: The dump directory is writeable. Skipping testDumpDirNotWritable test."); - return; + throw new SkipException("WARNING: The dump directory is writeable. Skipping testDumpDirNotWritable test."); } ProcessBuilder pb = createLimitedTestJavaProcessBuilder( From 56a007dd32061695d7bb0faf47e1793728e86c88 Mon Sep 17 00:00:00 2001 From: Tejesh R Date: Mon, 19 Aug 2024 06:42:51 +0000 Subject: [PATCH 335/353] 8338488: Add screen capture for failure case Reviewed-by: azvegint --- .../java/awt/Checkbox/CheckboxCheckerScalingTest.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/jdk/java/awt/Checkbox/CheckboxCheckerScalingTest.java b/test/jdk/java/awt/Checkbox/CheckboxCheckerScalingTest.java index 5e531e84801cd..a07620dbd38ce 100644 --- a/test/jdk/java/awt/Checkbox/CheckboxCheckerScalingTest.java +++ b/test/jdk/java/awt/Checkbox/CheckboxCheckerScalingTest.java @@ -29,6 +29,10 @@ import java.awt.Rectangle; import java.awt.Robot; import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; + +import javax.imageio.ImageIO; /* * @test @@ -78,6 +82,12 @@ public static void main(String[] args) throws Exception { }); if (!checkmarkFound) { + try { + ImageIO.write(imageAfterChecked, "png", + new File("imageAfterChecked.png")); + } catch (IOException e) { + throw new RuntimeException(e); + } throw new RuntimeException("Checkmark not scaled"); } System.out.println("Test Passed"); From 15b20cb1fd18b849e49c175737dd3826c8d0ceff Mon Sep 17 00:00:00 2001 From: Manukumar V S Date: Mon, 19 Aug 2024 07:17:37 +0000 Subject: [PATCH 336/353] 8337886: java/awt/Frame/MaximizeUndecoratedTest.java fails in OEL due to a slight color difference Reviewed-by: dnguyen, honkar, serb --- test/jdk/java/awt/Frame/MaximizeUndecoratedTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/jdk/java/awt/Frame/MaximizeUndecoratedTest.java b/test/jdk/java/awt/Frame/MaximizeUndecoratedTest.java index 77046ea3e1f32..3e23af76bb6f7 100644 --- a/test/jdk/java/awt/Frame/MaximizeUndecoratedTest.java +++ b/test/jdk/java/awt/Frame/MaximizeUndecoratedTest.java @@ -50,7 +50,7 @@ public class MaximizeUndecoratedTest { private static final int SIZE = 300; - private static final int OFFSET = 2; + private static final int OFFSET = 5; private static Frame frame; private static Robot robot; From f0374a0bc181d0f2a8c0aa9aa032b07998ffaf60 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Mon, 19 Aug 2024 09:00:19 +0000 Subject: [PATCH 337/353] 8337987: Relocate jfr and throw_exception stubs from StubGenerator to SharedRuntime Reviewed-by: fyang, kvn, yzheng --- .../cpu/aarch64/macroAssembler_aarch64.cpp | 2 +- .../cpu/aarch64/methodHandles_aarch64.cpp | 4 +- .../cpu/aarch64/sharedRuntime_aarch64.cpp | 196 ++++++++++++++ .../cpu/aarch64/stubGenerator_aarch64.cpp | 238 +---------------- .../templateInterpreterGenerator_aarch64.cpp | 4 +- src/hotspot/cpu/arm/methodHandles_arm.cpp | 5 +- src/hotspot/cpu/arm/sharedRuntime_arm.cpp | 140 ++++++++++ src/hotspot/cpu/arm/stubGenerator_arm.cpp | 154 ----------- .../arm/templateInterpreterGenerator_arm.cpp | 2 +- src/hotspot/cpu/ppc/macroAssembler_ppc.cpp | 2 +- src/hotspot/cpu/ppc/methodHandles_ppc.cpp | 6 +- src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp | 173 +++++++++++++ src/hotspot/cpu/ppc/stubGenerator_ppc.cpp | 209 +-------------- .../ppc/templateInterpreterGenerator_ppc.cpp | 4 +- .../cpu/riscv/macroAssembler_riscv.cpp | 2 +- src/hotspot/cpu/riscv/methodHandles_riscv.cpp | 4 +- src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp | 195 ++++++++++++++ src/hotspot/cpu/riscv/stubGenerator_riscv.cpp | 239 +---------------- .../templateInterpreterGenerator_riscv.cpp | 4 +- src/hotspot/cpu/s390/macroAssembler_s390.cpp | 2 +- src/hotspot/cpu/s390/methodHandles_s390.cpp | 6 +- src/hotspot/cpu/s390/sharedRuntime_s390.cpp | 94 +++++++ src/hotspot/cpu/s390/stubGenerator_s390.cpp | 122 --------- .../templateInterpreterGenerator_s390.cpp | 6 +- src/hotspot/cpu/x86/macroAssembler_x86.cpp | 2 +- src/hotspot/cpu/x86/methodHandles_x86.cpp | 4 +- src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp | 211 +++++++++++++++ src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp | 193 ++++++++++++++ src/hotspot/cpu/x86/stubGenerator_x86_32.cpp | 239 ----------------- src/hotspot/cpu/x86/stubGenerator_x86_64.cpp | 240 +----------------- src/hotspot/cpu/x86/stubGenerator_x86_64.hpp | 10 - .../x86/templateInterpreterGenerator_x86.cpp | 4 +- src/hotspot/cpu/zero/sharedRuntime_zero.cpp | 21 +- src/hotspot/cpu/zero/stubGenerator_zero.cpp | 16 -- src/hotspot/share/jvmci/jvmciCompilerToVM.hpp | 1 + .../share/jvmci/jvmciCompilerToVMInit.cpp | 2 + src/hotspot/share/jvmci/vmStructs_jvmci.cpp | 4 +- src/hotspot/share/opto/library_call.cpp | 4 +- src/hotspot/share/runtime/init.cpp | 6 + src/hotspot/share/runtime/sharedRuntime.cpp | 68 ++++- src/hotspot/share/runtime/sharedRuntime.hpp | 36 ++- src/hotspot/share/runtime/stubRoutines.cpp | 10 - src/hotspot/share/runtime/stubRoutines.hpp | 53 ++-- 43 files changed, 1392 insertions(+), 1545 deletions(-) diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp index ead4220add056..f8b703fb4daf6 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp @@ -744,7 +744,7 @@ void MacroAssembler::reserved_stack_check() { // We have already removed our own frame. // throw_delayed_StackOverflowError will think that it's been // called by our caller. - lea(rscratch1, RuntimeAddress(StubRoutines::throw_delayed_StackOverflowError_entry())); + lea(rscratch1, RuntimeAddress(SharedRuntime::throw_delayed_StackOverflowError_entry())); br(rscratch1); should_not_reach_here(); diff --git a/src/hotspot/cpu/aarch64/methodHandles_aarch64.cpp b/src/hotspot/cpu/aarch64/methodHandles_aarch64.cpp index ee19079db7d74..68800d04d69ba 100644 --- a/src/hotspot/cpu/aarch64/methodHandles_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/methodHandles_aarch64.cpp @@ -120,7 +120,7 @@ void MethodHandles::jump_from_method_handle(MacroAssembler* _masm, Register meth __ ldr(rscratch1,Address(method, entry_offset)); __ br(rscratch1); __ bind(L_no_such_method); - __ far_jump(RuntimeAddress(StubRoutines::throw_AbstractMethodError_entry())); + __ far_jump(RuntimeAddress(SharedRuntime::throw_AbstractMethodError_entry())); } void MethodHandles::jump_to_lambda_form(MacroAssembler* _masm, @@ -451,7 +451,7 @@ void MethodHandles::generate_method_handle_dispatch(MacroAssembler* _masm, jump_from_method_handle(_masm, rmethod, temp1, for_compiler_entry); if (iid == vmIntrinsics::_linkToInterface) { __ bind(L_incompatible_class_change_error); - __ far_jump(RuntimeAddress(StubRoutines::throw_IncompatibleClassChangeError_entry())); + __ far_jump(RuntimeAddress(SharedRuntime::throw_IncompatibleClassChangeError_entry())); } } } diff --git a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp index a4dac0ccf6d8c..901ae50299960 100644 --- a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp @@ -66,6 +66,12 @@ #define __ masm-> +#ifdef PRODUCT +#define BLOCK_COMMENT(str) /* nothing */ +#else +#define BLOCK_COMMENT(str) __ block_comment(str) +#endif + const int StackAlignmentInSlots = StackAlignmentInBytes / VMRegImpl::stack_slot_size; // FIXME -- this is used by C1 @@ -2764,3 +2770,193 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const cha // frame_size_words or bytes?? return RuntimeStub::new_runtime_stub(name, &buffer, frame_complete, frame_size_in_words, oop_maps, true); } + +// Continuation point for throwing of implicit exceptions that are +// not handled in the current activation. Fabricates an exception +// oop and initiates normal exception dispatching in this +// frame. Since we need to preserve callee-saved values (currently +// only for C2, but done for C1 as well) we need a callee-saved oop +// map and therefore have to make these stubs into RuntimeStubs +// rather than BufferBlobs. If the compiler needs all registers to +// be preserved between the fault point and the exception handler +// then it must assume responsibility for that in +// AbstractCompiler::continuation_for_implicit_null_exception or +// continuation_for_implicit_division_by_zero_exception. All other +// implicit exceptions (e.g., NullPointerException or +// AbstractMethodError on entry) are either at call sites or +// otherwise assume that stack unwinding will be initiated, so +// caller saved registers were assumed volatile in the compiler. + +RuntimeStub* SharedRuntime::generate_throw_exception(const char* name, address runtime_entry) { + // Information about frame layout at time of blocking runtime call. + // Note that we only have to preserve callee-saved registers since + // the compilers are responsible for supplying a continuation point + // if they expect all registers to be preserved. + // n.b. aarch64 asserts that frame::arg_reg_save_area_bytes == 0 + enum layout { + rfp_off = 0, + rfp_off2, + return_off, + return_off2, + framesize // inclusive of return address + }; + + int insts_size = 512; + int locs_size = 64; + + ResourceMark rm; + const char* timer_msg = "SharedRuntime generate_throw_exception"; + TraceTime timer(timer_msg, TRACETIME_LOG(Info, startuptime)); + + CodeBuffer code(name, insts_size, locs_size); + OopMapSet* oop_maps = new OopMapSet(); + MacroAssembler* masm = new MacroAssembler(&code); + + address start = __ pc(); + + // This is an inlined and slightly modified version of call_VM + // which has the ability to fetch the return PC out of + // thread-local storage and also sets up last_Java_sp slightly + // differently than the real call_VM + + __ enter(); // Save FP and LR before call + + assert(is_even(framesize/2), "sp not 16-byte aligned"); + + // lr and fp are already in place + __ sub(sp, rfp, ((uint64_t)framesize-4) << LogBytesPerInt); // prolog + + int frame_complete = __ pc() - start; + + // Set up last_Java_sp and last_Java_fp + address the_pc = __ pc(); + __ set_last_Java_frame(sp, rfp, the_pc, rscratch1); + + __ mov(c_rarg0, rthread); + BLOCK_COMMENT("call runtime_entry"); + __ mov(rscratch1, runtime_entry); + __ blr(rscratch1); + + // Generate oop map + OopMap* map = new OopMap(framesize, 0); + + oop_maps->add_gc_map(the_pc - start, map); + + __ reset_last_Java_frame(true); + + // Reinitialize the ptrue predicate register, in case the external runtime + // call clobbers ptrue reg, as we may return to SVE compiled code. + __ reinitialize_ptrue(); + + __ leave(); + + // check for pending exceptions +#ifdef ASSERT + Label L; + __ ldr(rscratch1, Address(rthread, Thread::pending_exception_offset())); + __ cbnz(rscratch1, L); + __ should_not_reach_here(); + __ bind(L); +#endif // ASSERT + __ far_jump(RuntimeAddress(StubRoutines::forward_exception_entry())); + + // codeBlob framesize is in words (not VMRegImpl::slot_size) + RuntimeStub* stub = + RuntimeStub::new_runtime_stub(name, + &code, + frame_complete, + (framesize >> (LogBytesPerWord - LogBytesPerInt)), + oop_maps, false); + return stub; +} + +#if INCLUDE_JFR + +static void jfr_prologue(address the_pc, MacroAssembler* masm, Register thread) { + __ set_last_Java_frame(sp, rfp, the_pc, rscratch1); + __ mov(c_rarg0, thread); +} + +// The handle is dereferenced through a load barrier. +static void jfr_epilogue(MacroAssembler* masm) { + __ reset_last_Java_frame(true); +} + +// For c2: c_rarg0 is junk, call to runtime to write a checkpoint. +// It returns a jobject handle to the event writer. +// The handle is dereferenced and the return value is the event writer oop. +RuntimeStub* SharedRuntime::generate_jfr_write_checkpoint() { + enum layout { + rbp_off, + rbpH_off, + return_off, + return_off2, + framesize // inclusive of return address + }; + + int insts_size = 1024; + int locs_size = 64; + CodeBuffer code("jfr_write_checkpoint", insts_size, locs_size); + OopMapSet* oop_maps = new OopMapSet(); + MacroAssembler* masm = new MacroAssembler(&code); + + address start = __ pc(); + __ enter(); + int frame_complete = __ pc() - start; + address the_pc = __ pc(); + jfr_prologue(the_pc, masm, rthread); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::write_checkpoint), 1); + jfr_epilogue(masm); + __ resolve_global_jobject(r0, rscratch1, rscratch2); + __ leave(); + __ ret(lr); + + OopMap* map = new OopMap(framesize, 1); // rfp + oop_maps->add_gc_map(the_pc - start, map); + + RuntimeStub* stub = // codeBlob framesize is in words (not VMRegImpl::slot_size) + RuntimeStub::new_runtime_stub("jfr_write_checkpoint", &code, frame_complete, + (framesize >> (LogBytesPerWord - LogBytesPerInt)), + oop_maps, false); + return stub; +} + +// For c2: call to return a leased buffer. +RuntimeStub* SharedRuntime::generate_jfr_return_lease() { + enum layout { + rbp_off, + rbpH_off, + return_off, + return_off2, + framesize // inclusive of return address + }; + + int insts_size = 1024; + int locs_size = 64; + + CodeBuffer code("jfr_return_lease", insts_size, locs_size); + OopMapSet* oop_maps = new OopMapSet(); + MacroAssembler* masm = new MacroAssembler(&code); + + address start = __ pc(); + __ enter(); + int frame_complete = __ pc() - start; + address the_pc = __ pc(); + jfr_prologue(the_pc, masm, rthread); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::return_lease), 1); + jfr_epilogue(masm); + + __ leave(); + __ ret(lr); + + OopMap* map = new OopMap(framesize, 1); // rfp + oop_maps->add_gc_map(the_pc - start, map); + + RuntimeStub* stub = // codeBlob framesize is in words (not VMRegImpl::slot_size) + RuntimeStub::new_runtime_stub("jfr_return_lease", &code, frame_complete, + (framesize >> (LogBytesPerWord - LogBytesPerInt)), + oop_maps, false); + return stub; +} + +#endif // INCLUDE_JFR diff --git a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp index 5e2ef97e4a3ad..b3513a586de35 100644 --- a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp @@ -7045,7 +7045,7 @@ class StubGenerator: public StubCodeGenerator { Label thaw_success; // rscratch2 contains the size of the frames to thaw, 0 if overflow or no more frames __ cbnz(rscratch2, thaw_success); - __ lea(rscratch1, RuntimeAddress(StubRoutines::throw_StackOverflowError_entry())); + __ lea(rscratch1, RuntimeAddress(SharedRuntime::throw_StackOverflowError_entry())); __ br(rscratch1); __ bind(thaw_success); @@ -7305,98 +7305,6 @@ class StubGenerator: public StubCodeGenerator { return start; } -#if INCLUDE_JFR - - static void jfr_prologue(address the_pc, MacroAssembler* _masm, Register thread) { - __ set_last_Java_frame(sp, rfp, the_pc, rscratch1); - __ mov(c_rarg0, thread); - } - - // The handle is dereferenced through a load barrier. - static void jfr_epilogue(MacroAssembler* _masm) { - __ reset_last_Java_frame(true); - } - - // For c2: c_rarg0 is junk, call to runtime to write a checkpoint. - // It returns a jobject handle to the event writer. - // The handle is dereferenced and the return value is the event writer oop. - static RuntimeStub* generate_jfr_write_checkpoint() { - enum layout { - rbp_off, - rbpH_off, - return_off, - return_off2, - framesize // inclusive of return address - }; - - int insts_size = 1024; - int locs_size = 64; - CodeBuffer code("jfr_write_checkpoint", insts_size, locs_size); - OopMapSet* oop_maps = new OopMapSet(); - MacroAssembler* masm = new MacroAssembler(&code); - MacroAssembler* _masm = masm; - - address start = __ pc(); - __ enter(); - int frame_complete = __ pc() - start; - address the_pc = __ pc(); - jfr_prologue(the_pc, _masm, rthread); - __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::write_checkpoint), 1); - jfr_epilogue(_masm); - __ resolve_global_jobject(r0, rscratch1, rscratch2); - __ leave(); - __ ret(lr); - - OopMap* map = new OopMap(framesize, 1); // rfp - oop_maps->add_gc_map(the_pc - start, map); - - RuntimeStub* stub = // codeBlob framesize is in words (not VMRegImpl::slot_size) - RuntimeStub::new_runtime_stub("jfr_write_checkpoint", &code, frame_complete, - (framesize >> (LogBytesPerWord - LogBytesPerInt)), - oop_maps, false); - return stub; - } - - // For c2: call to return a leased buffer. - static RuntimeStub* generate_jfr_return_lease() { - enum layout { - rbp_off, - rbpH_off, - return_off, - return_off2, - framesize // inclusive of return address - }; - - int insts_size = 1024; - int locs_size = 64; - CodeBuffer code("jfr_return_lease", insts_size, locs_size); - OopMapSet* oop_maps = new OopMapSet(); - MacroAssembler* masm = new MacroAssembler(&code); - MacroAssembler* _masm = masm; - - address start = __ pc(); - __ enter(); - int frame_complete = __ pc() - start; - address the_pc = __ pc(); - jfr_prologue(the_pc, _masm, rthread); - __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::return_lease), 1); - jfr_epilogue(_masm); - - __ leave(); - __ ret(lr); - - OopMap* map = new OopMap(framesize, 1); // rfp - oop_maps->add_gc_map(the_pc - start, map); - - RuntimeStub* stub = // codeBlob framesize is in words (not VMRegImpl::slot_size) - RuntimeStub::new_runtime_stub("jfr_return_lease", &code, frame_complete, - (framesize >> (LogBytesPerWord - LogBytesPerInt)), - oop_maps, false); - return stub; - } - -#endif // INCLUDE_JFR - // exception handler for upcall stubs address generate_upcall_stub_exception_handler() { StubCodeMark mark(this, "StubRoutines", "upcall stub exception handler"); @@ -7412,115 +7320,9 @@ class StubGenerator: public StubCodeGenerator { return start; } - // Continuation point for throwing of implicit exceptions that are - // not handled in the current activation. Fabricates an exception - // oop and initiates normal exception dispatching in this - // frame. Since we need to preserve callee-saved values (currently - // only for C2, but done for C1 as well) we need a callee-saved oop - // map and therefore have to make these stubs into RuntimeStubs - // rather than BufferBlobs. If the compiler needs all registers to - // be preserved between the fault point and the exception handler - // then it must assume responsibility for that in - // AbstractCompiler::continuation_for_implicit_null_exception or - // continuation_for_implicit_division_by_zero_exception. All other - // implicit exceptions (e.g., NullPointerException or - // AbstractMethodError on entry) are either at call sites or - // otherwise assume that stack unwinding will be initiated, so - // caller saved registers were assumed volatile in the compiler. - #undef __ #define __ masm-> - address generate_throw_exception(const char* name, - address runtime_entry, - Register arg1 = noreg, - Register arg2 = noreg) { - // Information about frame layout at time of blocking runtime call. - // Note that we only have to preserve callee-saved registers since - // the compilers are responsible for supplying a continuation point - // if they expect all registers to be preserved. - // n.b. aarch64 asserts that frame::arg_reg_save_area_bytes == 0 - enum layout { - rfp_off = 0, - rfp_off2, - return_off, - return_off2, - framesize // inclusive of return address - }; - - int insts_size = 512; - int locs_size = 64; - - CodeBuffer code(name, insts_size, locs_size); - OopMapSet* oop_maps = new OopMapSet(); - MacroAssembler* masm = new MacroAssembler(&code); - - address start = __ pc(); - - // This is an inlined and slightly modified version of call_VM - // which has the ability to fetch the return PC out of - // thread-local storage and also sets up last_Java_sp slightly - // differently than the real call_VM - - __ enter(); // Save FP and LR before call - - assert(is_even(framesize/2), "sp not 16-byte aligned"); - - // lr and fp are already in place - __ sub(sp, rfp, ((uint64_t)framesize-4) << LogBytesPerInt); // prolog - - int frame_complete = __ pc() - start; - - // Set up last_Java_sp and last_Java_fp - address the_pc = __ pc(); - __ set_last_Java_frame(sp, rfp, the_pc, rscratch1); - - // Call runtime - if (arg1 != noreg) { - assert(arg2 != c_rarg1, "clobbered"); - __ mov(c_rarg1, arg1); - } - if (arg2 != noreg) { - __ mov(c_rarg2, arg2); - } - __ mov(c_rarg0, rthread); - BLOCK_COMMENT("call runtime_entry"); - __ mov(rscratch1, runtime_entry); - __ blr(rscratch1); - - // Generate oop map - OopMap* map = new OopMap(framesize, 0); - - oop_maps->add_gc_map(the_pc - start, map); - - __ reset_last_Java_frame(true); - - // Reinitialize the ptrue predicate register, in case the external runtime - // call clobbers ptrue reg, as we may return to SVE compiled code. - __ reinitialize_ptrue(); - - __ leave(); - - // check for pending exceptions -#ifdef ASSERT - Label L; - __ ldr(rscratch1, Address(rthread, Thread::pending_exception_offset())); - __ cbnz(rscratch1, L); - __ should_not_reach_here(); - __ bind(L); -#endif // ASSERT - __ far_jump(RuntimeAddress(StubRoutines::forward_exception_entry())); - - // codeBlob framesize is in words (not VMRegImpl::slot_size) - RuntimeStub* stub = - RuntimeStub::new_runtime_stub(name, - &code, - frame_complete, - (framesize >> (LogBytesPerWord - LogBytesPerInt)), - oop_maps, false); - return stub->entry_point(); - } - class MontgomeryMultiplyGenerator : public MacroAssembler { Register Pa_base, Pb_base, Pn_base, Pm_base, inv, Rlen, Ra, Rb, Rm, Rn, @@ -8363,16 +8165,6 @@ class StubGenerator: public StubCodeGenerator { // is referenced by megamorphic call StubRoutines::_catch_exception_entry = generate_catch_exception(); - // Build this early so it's available for the interpreter. - StubRoutines::_throw_StackOverflowError_entry = - generate_throw_exception("StackOverflowError throw_exception", - CAST_FROM_FN_PTR(address, - SharedRuntime::throw_StackOverflowError)); - StubRoutines::_throw_delayed_StackOverflowError_entry = - generate_throw_exception("delayed StackOverflowError throw_exception", - CAST_FROM_FN_PTR(address, - SharedRuntime::throw_delayed_StackOverflowError)); - // Initialize table for copy memory (arraycopy) check. if (UnsafeMemoryAccess::_table == nullptr) { UnsafeMemoryAccess::create_table(8 + 4); // 8 for copyMemory; 4 for setMemory @@ -8408,41 +8200,13 @@ class StubGenerator: public StubCodeGenerator { StubRoutines::_cont_thaw = generate_cont_thaw(); StubRoutines::_cont_returnBarrier = generate_cont_returnBarrier(); StubRoutines::_cont_returnBarrierExc = generate_cont_returnBarrier_exception(); - - JFR_ONLY(generate_jfr_stubs();) - } - -#if INCLUDE_JFR - void generate_jfr_stubs() { - StubRoutines::_jfr_write_checkpoint_stub = generate_jfr_write_checkpoint(); - StubRoutines::_jfr_write_checkpoint = StubRoutines::_jfr_write_checkpoint_stub->entry_point(); - StubRoutines::_jfr_return_lease_stub = generate_jfr_return_lease(); - StubRoutines::_jfr_return_lease = StubRoutines::_jfr_return_lease_stub->entry_point(); } -#endif // INCLUDE_JFR void generate_final_stubs() { // support for verify_oop (must happen after universe_init) if (VerifyOops) { StubRoutines::_verify_oop_subroutine_entry = generate_verify_oop(); } - StubRoutines::_throw_AbstractMethodError_entry = - generate_throw_exception("AbstractMethodError throw_exception", - CAST_FROM_FN_PTR(address, - SharedRuntime:: - throw_AbstractMethodError)); - - StubRoutines::_throw_IncompatibleClassChangeError_entry = - generate_throw_exception("IncompatibleClassChangeError throw_exception", - CAST_FROM_FN_PTR(address, - SharedRuntime:: - throw_IncompatibleClassChangeError)); - - StubRoutines::_throw_NullPointerException_at_call_entry = - generate_throw_exception("NullPointerException at call throw_exception", - CAST_FROM_FN_PTR(address, - SharedRuntime:: - throw_NullPointerException_at_call)); // arraycopy stubs used by compilers generate_arraycopy_stubs(); diff --git a/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp index ed2450a9110e5..38d48b86f23b0 100644 --- a/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp @@ -752,8 +752,8 @@ void TemplateInterpreterGenerator::generate_stack_overflow_check(void) { // Note: the restored frame is not necessarily interpreted. // Use the shared runtime version of the StackOverflowError. - assert(StubRoutines::throw_StackOverflowError_entry() != nullptr, "stub not yet generated"); - __ far_jump(RuntimeAddress(StubRoutines::throw_StackOverflowError_entry())); + assert(SharedRuntime::throw_StackOverflowError_entry() != nullptr, "stub not yet generated"); + __ far_jump(RuntimeAddress(SharedRuntime::throw_StackOverflowError_entry())); // all done with frame size check __ bind(after_frame_check); diff --git a/src/hotspot/cpu/arm/methodHandles_arm.cpp b/src/hotspot/cpu/arm/methodHandles_arm.cpp index 839392920552e..7fc984afa9997 100644 --- a/src/hotspot/cpu/arm/methodHandles_arm.cpp +++ b/src/hotspot/cpu/arm/methodHandles_arm.cpp @@ -39,6 +39,7 @@ #include "prims/jvmtiExport.hpp" #include "prims/methodHandles.hpp" #include "runtime/frame.inline.hpp" +#include "runtime/sharedRuntime.hpp" #include "runtime/stubRoutines.hpp" #include "utilities/preserveException.hpp" @@ -140,7 +141,7 @@ void MethodHandles::jump_from_method_handle(MacroAssembler* _masm, bool for_comp __ bind(L_no_such_method); // throw exception - __ jump(StubRoutines::throw_AbstractMethodError_entry(), relocInfo::runtime_call_type, Rtemp); + __ jump(SharedRuntime::throw_AbstractMethodError_entry(), relocInfo::runtime_call_type, Rtemp); } void MethodHandles::jump_to_lambda_form(MacroAssembler* _masm, @@ -461,7 +462,7 @@ void MethodHandles::generate_method_handle_dispatch(MacroAssembler* _masm, if (iid == vmIntrinsics::_linkToInterface) { __ bind(L_incompatible_class_change_error); - __ jump(StubRoutines::throw_IncompatibleClassChangeError_entry(), relocInfo::runtime_call_type, Rtemp); + __ jump(SharedRuntime::throw_IncompatibleClassChangeError_entry(), relocInfo::runtime_call_type, Rtemp); } } } diff --git a/src/hotspot/cpu/arm/sharedRuntime_arm.cpp b/src/hotspot/cpu/arm/sharedRuntime_arm.cpp index 1305283aeaeba..f07c1f8e53c45 100644 --- a/src/hotspot/cpu/arm/sharedRuntime_arm.cpp +++ b/src/hotspot/cpu/arm/sharedRuntime_arm.cpp @@ -1728,3 +1728,143 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const cha return RuntimeStub::new_runtime_stub(name, &buffer, frame_complete, frame_size_words, oop_maps, true); } + +//------------------------------------------------------------------------------------------------------------------------ +// Continuation point for throwing of implicit exceptions that are not handled in +// the current activation. Fabricates an exception oop and initiates normal +// exception dispatching in this frame. +RuntimeStub* SharedRuntime::generate_throw_exception(const char* name, address runtime_entry) { + int insts_size = 128; + int locs_size = 32; + + ResourceMark rm; + const char* timer_msg = "SharedRuntime generate_throw_exception"; + TraceTime timer(timer_msg, TRACETIME_LOG(Info, startuptime)); + + CodeBuffer code(name, insts_size, locs_size); + OopMapSet* oop_maps; + int frame_size; + int frame_complete; + + oop_maps = new OopMapSet(); + MacroAssembler* masm = new MacroAssembler(&code); + + address start = __ pc(); + + frame_size = 2; + __ mov(Rexception_pc, LR); + __ raw_push(FP, LR); + + frame_complete = __ pc() - start; + + // Any extra arguments are already supposed to be R1 and R2 + __ mov(R0, Rthread); + + int pc_offset = __ set_last_Java_frame(SP, FP, false, Rtemp); + assert(((__ pc()) - start) == __ offset(), "warning: start differs from code_begin"); + __ call(runtime_entry); + if (pc_offset == -1) { + pc_offset = __ offset(); + } + + // Generate oop map + OopMap* map = new OopMap(frame_size*VMRegImpl::slots_per_word, 0); + oop_maps->add_gc_map(pc_offset, map); + __ reset_last_Java_frame(Rtemp); // Rtemp free since scratched by far call + + __ raw_pop(FP, LR); + __ jump(StubRoutines::forward_exception_entry(), relocInfo::runtime_call_type, Rtemp); + + RuntimeStub* stub = RuntimeStub::new_runtime_stub(name, &code, frame_complete, + frame_size, oop_maps, false); + return stub; +} + +#if INCLUDE_JFR + +// For c2: c_rarg0 is junk, call to runtime to write a checkpoint. +// It returns a jobject handle to the event writer. +// The handle is dereferenced and the return value is the event writer oop. +RuntimeStub* SharedRuntime::generate_jfr_write_checkpoint() { + enum layout { + r1_off, + r2_off, + return_off, + framesize // inclusive of return address + }; + + CodeBuffer code("jfr_write_checkpoint", 512, 64); + MacroAssembler* masm = new MacroAssembler(&code); + + address start = __ pc(); + __ raw_push(R1, R2, LR); + address the_pc = __ pc(); + + int frame_complete = the_pc - start; + + __ set_last_Java_frame(SP, FP, true, Rtemp); + __ mov(c_rarg0, Rthread); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::write_checkpoint), c_rarg0); + __ reset_last_Java_frame(Rtemp); + + // R0 is jobject handle result, unpack and process it through a barrier. + __ resolve_global_jobject(R0, Rtemp, R1); + + __ raw_pop(R1, R2, LR); + __ ret(); + + OopMapSet* oop_maps = new OopMapSet(); + OopMap* map = new OopMap(framesize, 1); + oop_maps->add_gc_map(frame_complete, map); + + RuntimeStub* stub = + RuntimeStub::new_runtime_stub(code.name(), + &code, + frame_complete, + (framesize >> (LogBytesPerWord - LogBytesPerInt)), + oop_maps, + false); + return stub; +} + +// For c2: call to return a leased buffer. +RuntimeStub* SharedRuntime::generate_jfr_return_lease() { + enum layout { + r1_off, + r2_off, + return_off, + framesize // inclusive of return address + }; + + CodeBuffer code("jfr_return_lease", 512, 64); + MacroAssembler* masm = new MacroAssembler(&code); + + address start = __ pc(); + __ raw_push(R1, R2, LR); + address the_pc = __ pc(); + + int frame_complete = the_pc - start; + + __ set_last_Java_frame(SP, FP, true, Rtemp); + __ mov(c_rarg0, Rthread); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::return_lease), c_rarg0); + __ reset_last_Java_frame(Rtemp); + + __ raw_pop(R1, R2, LR); + __ ret(); + + OopMapSet* oop_maps = new OopMapSet(); + OopMap* map = new OopMap(framesize, 1); + oop_maps->add_gc_map(frame_complete, map); + + RuntimeStub* stub = + RuntimeStub::new_runtime_stub(code.name(), + &code, + frame_complete, + (framesize >> (LogBytesPerWord - LogBytesPerInt)), + oop_maps, + false); + return stub; +} + +#endif // INCLUDE_JFR diff --git a/src/hotspot/cpu/arm/stubGenerator_arm.cpp b/src/hotspot/cpu/arm/stubGenerator_arm.cpp index 0d66a2fbb0a51..9b91e02cf07f2 100644 --- a/src/hotspot/cpu/arm/stubGenerator_arm.cpp +++ b/src/hotspot/cpu/arm/stubGenerator_arm.cpp @@ -2961,52 +2961,6 @@ class StubGenerator: public StubCodeGenerator { #undef __ #define __ masm-> - //------------------------------------------------------------------------------------------------------------------------ - // Continuation point for throwing of implicit exceptions that are not handled in - // the current activation. Fabricates an exception oop and initiates normal - // exception dispatching in this frame. - address generate_throw_exception(const char* name, address runtime_entry) { - int insts_size = 128; - int locs_size = 32; - CodeBuffer code(name, insts_size, locs_size); - OopMapSet* oop_maps; - int frame_size; - int frame_complete; - - oop_maps = new OopMapSet(); - MacroAssembler* masm = new MacroAssembler(&code); - - address start = __ pc(); - - frame_size = 2; - __ mov(Rexception_pc, LR); - __ raw_push(FP, LR); - - frame_complete = __ pc() - start; - - // Any extra arguments are already supposed to be R1 and R2 - __ mov(R0, Rthread); - - int pc_offset = __ set_last_Java_frame(SP, FP, false, Rtemp); - assert(((__ pc()) - start) == __ offset(), "warning: start differs from code_begin"); - __ call(runtime_entry); - if (pc_offset == -1) { - pc_offset = __ offset(); - } - - // Generate oop map - OopMap* map = new OopMap(frame_size*VMRegImpl::slots_per_word, 0); - oop_maps->add_gc_map(pc_offset, map); - __ reset_last_Java_frame(Rtemp); // Rtemp free since scratched by far call - - __ raw_pop(FP, LR); - __ jump(StubRoutines::forward_exception_entry(), relocInfo::runtime_call_type, Rtemp); - - RuntimeStub* stub = RuntimeStub::new_runtime_stub(name, &code, frame_complete, - frame_size, oop_maps, false); - return stub->entry_point(); - } - address generate_cont_thaw(const char* label, Continuation::thaw_kind kind) { if (!Continuations::enabled()) return nullptr; Unimplemented(); @@ -3025,95 +2979,6 @@ class StubGenerator: public StubCodeGenerator { return generate_cont_thaw("Cont thaw return barrier exception", Continuation::thaw_return_barrier_exception); } -#if INCLUDE_JFR - - // For c2: c_rarg0 is junk, call to runtime to write a checkpoint. - // It returns a jobject handle to the event writer. - // The handle is dereferenced and the return value is the event writer oop. - static RuntimeStub* generate_jfr_write_checkpoint() { - enum layout { - r1_off, - r2_off, - return_off, - framesize // inclusive of return address - }; - - CodeBuffer code("jfr_write_checkpoint", 512, 64); - MacroAssembler* masm = new MacroAssembler(&code); - - address start = __ pc(); - __ raw_push(R1, R2, LR); - address the_pc = __ pc(); - - int frame_complete = the_pc - start; - - __ set_last_Java_frame(SP, FP, true, Rtemp); - __ mov(c_rarg0, Rthread); - __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::write_checkpoint), c_rarg0); - __ reset_last_Java_frame(Rtemp); - - // R0 is jobject handle result, unpack and process it through a barrier. - __ resolve_global_jobject(R0, Rtemp, R1); - - __ raw_pop(R1, R2, LR); - __ ret(); - - OopMapSet* oop_maps = new OopMapSet(); - OopMap* map = new OopMap(framesize, 1); - oop_maps->add_gc_map(frame_complete, map); - - RuntimeStub* stub = - RuntimeStub::new_runtime_stub(code.name(), - &code, - frame_complete, - (framesize >> (LogBytesPerWord - LogBytesPerInt)), - oop_maps, - false); - return stub; - } - - // For c2: call to return a leased buffer. - static RuntimeStub* generate_jfr_return_lease() { - enum layout { - r1_off, - r2_off, - return_off, - framesize // inclusive of return address - }; - - CodeBuffer code("jfr_return_lease", 512, 64); - MacroAssembler* masm = new MacroAssembler(&code); - - address start = __ pc(); - __ raw_push(R1, R2, LR); - address the_pc = __ pc(); - - int frame_complete = the_pc - start; - - __ set_last_Java_frame(SP, FP, true, Rtemp); - __ mov(c_rarg0, Rthread); - __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::return_lease), c_rarg0); - __ reset_last_Java_frame(Rtemp); - - __ raw_pop(R1, R2, LR); - __ ret(); - - OopMapSet* oop_maps = new OopMapSet(); - OopMap* map = new OopMap(framesize, 1); - oop_maps->add_gc_map(frame_complete, map); - - RuntimeStub* stub = - RuntimeStub::new_runtime_stub(code.name(), - &code, - frame_complete, - (framesize >> (LogBytesPerWord - LogBytesPerInt)), - oop_maps, - false); - return stub; - } - -#endif // INCLUDE_JFR - //--------------------------------------------------------------------------- // Initialization @@ -3132,8 +2997,6 @@ class StubGenerator: public StubCodeGenerator { StubRoutines::_catch_exception_entry = generate_catch_exception(); // stub for throwing stack overflow error used both by interpreter and compiler - StubRoutines::_throw_StackOverflowError_entry = generate_throw_exception("StackOverflowError throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_StackOverflowError)); - if (UnsafeMemoryAccess::_table == nullptr) { UnsafeMemoryAccess::create_table(32 + 4); // 32 for copyMemory; 4 for setMemory } @@ -3155,28 +3018,11 @@ class StubGenerator: public StubCodeGenerator { StubRoutines::_cont_thaw = generate_cont_thaw(); StubRoutines::_cont_returnBarrier = generate_cont_returnBarrier(); StubRoutines::_cont_returnBarrierExc = generate_cont_returnBarrier_exception(); - - JFR_ONLY(generate_jfr_stubs();) } -#if INCLUDE_JFR - void generate_jfr_stubs() { - StubRoutines::_jfr_write_checkpoint_stub = generate_jfr_write_checkpoint(); - StubRoutines::_jfr_write_checkpoint = StubRoutines::_jfr_write_checkpoint_stub->entry_point(); - StubRoutines::_jfr_return_lease_stub = generate_jfr_return_lease(); - StubRoutines::_jfr_return_lease = StubRoutines::_jfr_return_lease_stub->entry_point(); - } -#endif // INCLUDE_JFR - void generate_final_stubs() { // Generates all stubs and initializes the entry points - // These entry points require SharedInfo::stack0 to be set up in non-core builds - // and need to be relocatable, so they each fabricate a RuntimeStub internally. - StubRoutines::_throw_AbstractMethodError_entry = generate_throw_exception("AbstractMethodError throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_AbstractMethodError)); - StubRoutines::_throw_IncompatibleClassChangeError_entry= generate_throw_exception("IncompatibleClassChangeError throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_IncompatibleClassChangeError)); - StubRoutines::_throw_NullPointerException_at_call_entry= generate_throw_exception("NullPointerException at call throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_NullPointerException_at_call)); - //------------------------------------------------------------------------------------------------------------------------ // entry points that are platform specific diff --git a/src/hotspot/cpu/arm/templateInterpreterGenerator_arm.cpp b/src/hotspot/cpu/arm/templateInterpreterGenerator_arm.cpp index efaf78ee568c5..679f07a028e2c 100644 --- a/src/hotspot/cpu/arm/templateInterpreterGenerator_arm.cpp +++ b/src/hotspot/cpu/arm/templateInterpreterGenerator_arm.cpp @@ -560,7 +560,7 @@ void TemplateInterpreterGenerator::generate_stack_overflow_check(void) { __ cmp(Rtemp, R0); __ mov(SP, Rsender_sp, ls); // restore SP - __ b(StubRoutines::throw_StackOverflowError_entry(), ls); + __ b(SharedRuntime::throw_StackOverflowError_entry(), ls); } diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp index 544c0d120d0d7..c7cf678b49ecf 100644 --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp @@ -1501,7 +1501,7 @@ void MacroAssembler::reserved_stack_check(Register return_pc) { call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::enable_stack_reserved_zone), R16_thread); pop_frame(); mtlr(return_pc); - load_const_optimized(R0, StubRoutines::throw_delayed_StackOverflowError_entry()); + load_const_optimized(R0, SharedRuntime::throw_delayed_StackOverflowError_entry()); mtctr(R0); bctr(); diff --git a/src/hotspot/cpu/ppc/methodHandles_ppc.cpp b/src/hotspot/cpu/ppc/methodHandles_ppc.cpp index 6e5ac325e505a..ccec05e710530 100644 --- a/src/hotspot/cpu/ppc/methodHandles_ppc.cpp +++ b/src/hotspot/cpu/ppc/methodHandles_ppc.cpp @@ -158,8 +158,8 @@ void MethodHandles::jump_from_method_handle(MacroAssembler* _masm, Register meth __ bctr(); __ bind(L_no_such_method); - assert(StubRoutines::throw_AbstractMethodError_entry() != nullptr, "not yet generated!"); - __ load_const_optimized(target, StubRoutines::throw_AbstractMethodError_entry()); + assert(SharedRuntime::throw_AbstractMethodError_entry() != nullptr, "not yet generated!"); + __ load_const_optimized(target, SharedRuntime::throw_AbstractMethodError_entry()); __ mtctr(target); __ bctr(); } @@ -489,7 +489,7 @@ void MethodHandles::generate_method_handle_dispatch(MacroAssembler* _masm, if (iid == vmIntrinsics::_linkToInterface) { __ BIND(L_incompatible_class_change_error); - __ load_const_optimized(temp1, StubRoutines::throw_IncompatibleClassChangeError_entry()); + __ load_const_optimized(temp1, SharedRuntime::throw_IncompatibleClassChangeError_entry()); __ mtctr(temp1); __ bctr(); } diff --git a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp index 505f67ab6f952..98610d21b67ba 100644 --- a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp +++ b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp @@ -44,6 +44,7 @@ #include "runtime/sharedRuntime.hpp" #include "runtime/signature.hpp" #include "runtime/stubRoutines.hpp" +#include "runtime/timerTrace.hpp" #include "runtime/vframeArray.hpp" #include "utilities/align.hpp" #include "utilities/macros.hpp" @@ -3404,6 +3405,100 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const cha oop_maps, true); } +// Continuation point for throwing of implicit exceptions that are +// not handled in the current activation. Fabricates an exception +// oop and initiates normal exception dispatching in this +// frame. Only callee-saved registers are preserved (through the +// normal register window / RegisterMap handling). If the compiler +// needs all registers to be preserved between the fault point and +// the exception handler then it must assume responsibility for that +// in AbstractCompiler::continuation_for_implicit_null_exception or +// continuation_for_implicit_division_by_zero_exception. All other +// implicit exceptions (e.g., NullPointerException or +// AbstractMethodError on entry) are either at call sites or +// otherwise assume that stack unwinding will be initiated, so +// caller saved registers were assumed volatile in the compiler. +// +// Note that we generate only this stub into a RuntimeStub, because +// it needs to be properly traversed and ignored during GC, so we +// change the meaning of the "__" macro within this method. +// +// Note: the routine set_pc_not_at_call_for_caller in +// SharedRuntime.cpp requires that this code be generated into a +// RuntimeStub. +RuntimeStub* SharedRuntime::generate_throw_exception(const char* name, address runtime_entry) { + ResourceMark rm; + const char* timer_msg = "SharedRuntime generate_throw_exception"; + TraceTime timer(timer_msg, TRACETIME_LOG(Info, startuptime)); + + CodeBuffer code(name, 1024 DEBUG_ONLY(+ 512), 0); + MacroAssembler* masm = new MacroAssembler(&code); + + OopMapSet* oop_maps = new OopMapSet(); + int frame_size_in_bytes = frame::native_abi_reg_args_size; + OopMap* map = new OopMap(frame_size_in_bytes / sizeof(jint), 0); + + address start = __ pc(); + + __ save_LR(R11_scratch1); + + // Push a frame. + __ push_frame_reg_args(0, R11_scratch1); + + address frame_complete_pc = __ pc(); + + // Note that we always have a runtime stub frame on the top of + // stack by this point. Remember the offset of the instruction + // whose address will be moved to R11_scratch1. + address gc_map_pc = __ get_PC_trash_LR(R11_scratch1); + + __ set_last_Java_frame(/*sp*/R1_SP, /*pc*/R11_scratch1); + + __ mr(R3_ARG1, R16_thread); +#if defined(ABI_ELFv2) + __ call_c(runtime_entry, relocInfo::none); +#else + __ call_c(CAST_FROM_FN_PTR(FunctionDescriptor*, runtime_entry), relocInfo::none); +#endif + + // Set an oopmap for the call site. + oop_maps->add_gc_map((int)(gc_map_pc - start), map); + + __ reset_last_Java_frame(); + +#ifdef ASSERT + // Make sure that this code is only executed if there is a pending + // exception. + { + Label L; + __ ld(R0, + in_bytes(Thread::pending_exception_offset()), + R16_thread); + __ cmpdi(CCR0, R0, 0); + __ bne(CCR0, L); + __ stop("SharedRuntime::throw_exception: no pending exception"); + __ bind(L); + } +#endif + + // Pop frame. + __ pop_frame(); + + __ restore_LR(R11_scratch1); + + __ load_const(R11_scratch1, StubRoutines::forward_exception_entry()); + __ mtctr(R11_scratch1); + __ bctr(); + + // Create runtime stub with OopMap. + RuntimeStub* stub = + RuntimeStub::new_runtime_stub(name, &code, + /*frame_complete=*/ (int)(frame_complete_pc - start), + frame_size_in_bytes/wordSize, + oop_maps, + false); + return stub; +} //------------------------------Montgomery multiplication------------------------ // @@ -3647,3 +3742,81 @@ void SharedRuntime::montgomery_square(jint *a_ints, jint *n_ints, reverse_words(m, (unsigned long *)m_ints, longwords); } + +#if INCLUDE_JFR + +// For c2: c_rarg0 is junk, call to runtime to write a checkpoint. +// It returns a jobject handle to the event writer. +// The handle is dereferenced and the return value is the event writer oop. +RuntimeStub* SharedRuntime::generate_jfr_write_checkpoint() { + CodeBuffer code("jfr_write_checkpoint", 512, 64); + MacroAssembler* masm = new MacroAssembler(&code); + + Register tmp1 = R10_ARG8; + Register tmp2 = R9_ARG7; + + int framesize = frame::native_abi_reg_args_size / VMRegImpl::stack_slot_size; + address start = __ pc(); + __ mflr(tmp1); + __ std(tmp1, _abi0(lr), R1_SP); // save return pc + __ push_frame_reg_args(0, tmp1); + int frame_complete = __ pc() - start; + __ set_last_Java_frame(R1_SP, noreg); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::write_checkpoint), R16_thread); + address calls_return_pc = __ last_calls_return_pc(); + __ reset_last_Java_frame(); + // The handle is dereferenced through a load barrier. + __ resolve_global_jobject(R3_RET, tmp1, tmp2, MacroAssembler::PRESERVATION_NONE); + __ pop_frame(); + __ ld(tmp1, _abi0(lr), R1_SP); + __ mtlr(tmp1); + __ blr(); + + OopMapSet* oop_maps = new OopMapSet(); + OopMap* map = new OopMap(framesize, 0); + oop_maps->add_gc_map(calls_return_pc - start, map); + + RuntimeStub* stub = // codeBlob framesize is in words (not VMRegImpl::slot_size) + RuntimeStub::new_runtime_stub(code.name(), + &code, frame_complete, + (framesize >> (LogBytesPerWord - LogBytesPerInt)), + oop_maps, false); + return stub; +} + +// For c2: call to return a leased buffer. +RuntimeStub* SharedRuntime::generate_jfr_return_lease() { + CodeBuffer code("jfr_return_lease", 512, 64); + MacroAssembler* masm = new MacroAssembler(&code); + + Register tmp1 = R10_ARG8; + Register tmp2 = R9_ARG7; + + int framesize = frame::native_abi_reg_args_size / VMRegImpl::stack_slot_size; + address start = __ pc(); + __ mflr(tmp1); + __ std(tmp1, _abi0(lr), R1_SP); // save return pc + __ push_frame_reg_args(0, tmp1); + int frame_complete = __ pc() - start; + __ set_last_Java_frame(R1_SP, noreg); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::return_lease), R16_thread); + address calls_return_pc = __ last_calls_return_pc(); + __ reset_last_Java_frame(); + __ pop_frame(); + __ ld(tmp1, _abi0(lr), R1_SP); + __ mtlr(tmp1); + __ blr(); + + OopMapSet* oop_maps = new OopMapSet(); + OopMap* map = new OopMap(framesize, 0); + oop_maps->add_gc_map(calls_return_pc - start, map); + + RuntimeStub* stub = // codeBlob framesize is in words (not VMRegImpl::slot_size) + RuntimeStub::new_runtime_stub(code.name(), + &code, frame_complete, + (framesize >> (LogBytesPerWord - LogBytesPerInt)), + oop_maps, false); + return stub; +} + +#endif // INCLUDE_JFR diff --git a/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp b/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp index 8da7cf7e79157..ee3f1911e2082 100644 --- a/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp +++ b/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp @@ -517,109 +517,6 @@ class StubGenerator: public StubCodeGenerator { } #undef __ -#define __ masm-> - // Continuation point for throwing of implicit exceptions that are - // not handled in the current activation. Fabricates an exception - // oop and initiates normal exception dispatching in this - // frame. Only callee-saved registers are preserved (through the - // normal register window / RegisterMap handling). If the compiler - // needs all registers to be preserved between the fault point and - // the exception handler then it must assume responsibility for that - // in AbstractCompiler::continuation_for_implicit_null_exception or - // continuation_for_implicit_division_by_zero_exception. All other - // implicit exceptions (e.g., NullPointerException or - // AbstractMethodError on entry) are either at call sites or - // otherwise assume that stack unwinding will be initiated, so - // caller saved registers were assumed volatile in the compiler. - // - // Note that we generate only this stub into a RuntimeStub, because - // it needs to be properly traversed and ignored during GC, so we - // change the meaning of the "__" macro within this method. - // - // Note: the routine set_pc_not_at_call_for_caller in - // SharedRuntime.cpp requires that this code be generated into a - // RuntimeStub. - address generate_throw_exception(const char* name, address runtime_entry, bool restore_saved_exception_pc, - Register arg1 = noreg, Register arg2 = noreg) { - CodeBuffer code(name, 1024 DEBUG_ONLY(+ 512), 0); - MacroAssembler* masm = new MacroAssembler(&code); - - OopMapSet* oop_maps = new OopMapSet(); - int frame_size_in_bytes = frame::native_abi_reg_args_size; - OopMap* map = new OopMap(frame_size_in_bytes / sizeof(jint), 0); - - address start = __ pc(); - - __ save_LR(R11_scratch1); - - // Push a frame. - __ push_frame_reg_args(0, R11_scratch1); - - address frame_complete_pc = __ pc(); - - if (restore_saved_exception_pc) { - __ unimplemented("StubGenerator::throw_exception with restore_saved_exception_pc"); - } - - // Note that we always have a runtime stub frame on the top of - // stack by this point. Remember the offset of the instruction - // whose address will be moved to R11_scratch1. - address gc_map_pc = __ get_PC_trash_LR(R11_scratch1); - - __ set_last_Java_frame(/*sp*/R1_SP, /*pc*/R11_scratch1); - - __ mr(R3_ARG1, R16_thread); - if (arg1 != noreg) { - __ mr(R4_ARG2, arg1); - } - if (arg2 != noreg) { - __ mr(R5_ARG3, arg2); - } -#if defined(ABI_ELFv2) - __ call_c(runtime_entry, relocInfo::none); -#else - __ call_c(CAST_FROM_FN_PTR(FunctionDescriptor*, runtime_entry), relocInfo::none); -#endif - - // Set an oopmap for the call site. - oop_maps->add_gc_map((int)(gc_map_pc - start), map); - - __ reset_last_Java_frame(); - -#ifdef ASSERT - // Make sure that this code is only executed if there is a pending - // exception. - { - Label L; - __ ld(R0, - in_bytes(Thread::pending_exception_offset()), - R16_thread); - __ cmpdi(CCR0, R0, 0); - __ bne(CCR0, L); - __ stop("StubRoutines::throw_exception: no pending exception"); - __ bind(L); - } -#endif - - // Pop frame. - __ pop_frame(); - - __ restore_LR(R11_scratch1); - - __ load_const(R11_scratch1, StubRoutines::forward_exception_entry()); - __ mtctr(R11_scratch1); - __ bctr(); - - // Create runtime stub with OopMap. - RuntimeStub* stub = - RuntimeStub::new_runtime_stub(name, &code, - /*frame_complete=*/ (int)(frame_complete_pc - start), - frame_size_in_bytes/wordSize, - oop_maps, - false); - return stub->entry_point(); - } -#undef __ #define __ _masm-> @@ -4616,7 +4513,7 @@ address generate_lookup_secondary_supers_table_stub(u1 super_klass_index) { Label thaw_success; __ cmpdi(CCR0, R3_RET, 0); __ bne(CCR0, thaw_success); - __ load_const_optimized(tmp1, (StubRoutines::throw_StackOverflowError_entry()), R0); + __ load_const_optimized(tmp1, (SharedRuntime::throw_StackOverflowError_entry()), R0); __ mtctr(tmp1); __ bctr(); __ bind(thaw_success); @@ -4675,84 +4572,6 @@ address generate_lookup_secondary_supers_table_stub(u1 super_klass_index) { return generate_cont_thaw("Cont thaw return barrier exception", Continuation::thaw_return_barrier_exception); } -#if INCLUDE_JFR - - // For c2: c_rarg0 is junk, call to runtime to write a checkpoint. - // It returns a jobject handle to the event writer. - // The handle is dereferenced and the return value is the event writer oop. - RuntimeStub* generate_jfr_write_checkpoint() { - CodeBuffer code("jfr_write_checkpoint", 512, 64); - MacroAssembler* _masm = new MacroAssembler(&code); - - Register tmp1 = R10_ARG8; - Register tmp2 = R9_ARG7; - - int framesize = frame::native_abi_reg_args_size / VMRegImpl::stack_slot_size; - address start = __ pc(); - __ mflr(tmp1); - __ std(tmp1, _abi0(lr), R1_SP); // save return pc - __ push_frame_reg_args(0, tmp1); - int frame_complete = __ pc() - start; - __ set_last_Java_frame(R1_SP, noreg); - __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::write_checkpoint), R16_thread); - address calls_return_pc = __ last_calls_return_pc(); - __ reset_last_Java_frame(); - // The handle is dereferenced through a load barrier. - __ resolve_global_jobject(R3_RET, tmp1, tmp2, MacroAssembler::PRESERVATION_NONE); - __ pop_frame(); - __ ld(tmp1, _abi0(lr), R1_SP); - __ mtlr(tmp1); - __ blr(); - - OopMapSet* oop_maps = new OopMapSet(); - OopMap* map = new OopMap(framesize, 0); - oop_maps->add_gc_map(calls_return_pc - start, map); - - RuntimeStub* stub = // codeBlob framesize is in words (not VMRegImpl::slot_size) - RuntimeStub::new_runtime_stub(code.name(), - &code, frame_complete, - (framesize >> (LogBytesPerWord - LogBytesPerInt)), - oop_maps, false); - return stub; - } - - // For c2: call to return a leased buffer. - RuntimeStub* generate_jfr_return_lease() { - CodeBuffer code("jfr_return_lease", 512, 64); - MacroAssembler* _masm = new MacroAssembler(&code); - - Register tmp1 = R10_ARG8; - Register tmp2 = R9_ARG7; - - int framesize = frame::native_abi_reg_args_size / VMRegImpl::stack_slot_size; - address start = __ pc(); - __ mflr(tmp1); - __ std(tmp1, _abi0(lr), R1_SP); // save return pc - __ push_frame_reg_args(0, tmp1); - int frame_complete = __ pc() - start; - __ set_last_Java_frame(R1_SP, noreg); - __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::return_lease), R16_thread); - address calls_return_pc = __ last_calls_return_pc(); - __ reset_last_Java_frame(); - __ pop_frame(); - __ ld(tmp1, _abi0(lr), R1_SP); - __ mtlr(tmp1); - __ blr(); - - OopMapSet* oop_maps = new OopMapSet(); - OopMap* map = new OopMap(framesize, 0); - oop_maps->add_gc_map(calls_return_pc - start, map); - - RuntimeStub* stub = // codeBlob framesize is in words (not VMRegImpl::slot_size) - RuntimeStub::new_runtime_stub(code.name(), - &code, frame_complete, - (framesize >> (LogBytesPerWord - LogBytesPerInt)), - oop_maps, false); - return stub; - } - -#endif // INCLUDE_JFR - // exception handler for upcall stubs address generate_upcall_stub_exception_handler() { StubCodeMark mark(this, "StubRoutines", "upcall stub exception handler"); @@ -4786,14 +4605,6 @@ address generate_lookup_secondary_supers_table_stub(u1 super_klass_index) { UnsafeMemoryAccess::create_table(8 + 4); // 8 for copyMemory; 4 for setMemory } - // Build this early so it's available for the interpreter. - StubRoutines::_throw_StackOverflowError_entry = - generate_throw_exception("StackOverflowError throw_exception", - CAST_FROM_FN_PTR(address, SharedRuntime::throw_StackOverflowError), false); - StubRoutines::_throw_delayed_StackOverflowError_entry = - generate_throw_exception("delayed StackOverflowError throw_exception", - CAST_FROM_FN_PTR(address, SharedRuntime::throw_delayed_StackOverflowError), false); - // CRC32 Intrinsics. if (UseCRC32Intrinsics) { StubRoutines::_crc_table_adr = StubRoutines::ppc::generate_crc_constants(REVERSE_CRC32_POLY); @@ -4812,29 +4623,11 @@ address generate_lookup_secondary_supers_table_stub(u1 super_klass_index) { StubRoutines::_cont_thaw = generate_cont_thaw(); StubRoutines::_cont_returnBarrier = generate_cont_returnBarrier(); StubRoutines::_cont_returnBarrierExc = generate_cont_returnBarrier_exception(); - - JFR_ONLY(generate_jfr_stubs();) - } - -#if INCLUDE_JFR - void generate_jfr_stubs() { - StubRoutines::_jfr_write_checkpoint_stub = generate_jfr_write_checkpoint(); - StubRoutines::_jfr_write_checkpoint = StubRoutines::_jfr_write_checkpoint_stub->entry_point(); - StubRoutines::_jfr_return_lease_stub = generate_jfr_return_lease(); - StubRoutines::_jfr_return_lease = StubRoutines::_jfr_return_lease_stub->entry_point(); } -#endif // INCLUDE_JFR void generate_final_stubs() { // Generates all stubs and initializes the entry points - // These entry points require SharedInfo::stack0 to be set up in - // non-core builds - StubRoutines::_throw_AbstractMethodError_entry = generate_throw_exception("AbstractMethodError throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_AbstractMethodError), false); - // Handle IncompatibleClassChangeError in itable stubs. - StubRoutines::_throw_IncompatibleClassChangeError_entry= generate_throw_exception("IncompatibleClassChangeError throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_IncompatibleClassChangeError), false); - StubRoutines::_throw_NullPointerException_at_call_entry= generate_throw_exception("NullPointerException at call throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_NullPointerException_at_call), false); - // support for verify_oop (must happen after universe_init) StubRoutines::_verify_oop_subroutine_entry = generate_verify_oop(); diff --git a/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp b/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp index 4caae20025309..bb746619616ac 100644 --- a/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp +++ b/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp @@ -783,8 +783,8 @@ void TemplateInterpreterGenerator::generate_stack_overflow_check(Register Rmem_f __ bgt(CCR0/*is_stack_overflow*/, done); // The stack overflows. Load target address of the runtime stub and call it. - assert(StubRoutines::throw_StackOverflowError_entry() != nullptr, "generated in wrong order"); - __ load_const_optimized(Rscratch1, (StubRoutines::throw_StackOverflowError_entry()), R0); + assert(SharedRuntime::throw_StackOverflowError_entry() != nullptr, "generated in wrong order"); + __ load_const_optimized(Rscratch1, (SharedRuntime::throw_StackOverflowError_entry()), R0); __ mtctr(Rscratch1); // Restore caller_sp (c2i adapter may exist, but no shrinking of interpreted caller frame). #ifdef ASSERT diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index c6624cb45bb4e..32ccba6b0cebf 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -4144,7 +4144,7 @@ void MacroAssembler::reserved_stack_check() { // We have already removed our own frame. // throw_delayed_StackOverflowError will think that it's been // called by our caller. - la(t0, RuntimeAddress(StubRoutines::throw_delayed_StackOverflowError_entry())); + la(t0, RuntimeAddress(SharedRuntime::throw_delayed_StackOverflowError_entry())); jr(t0); should_not_reach_here(); diff --git a/src/hotspot/cpu/riscv/methodHandles_riscv.cpp b/src/hotspot/cpu/riscv/methodHandles_riscv.cpp index fbb5b91403895..deeb771d83bb8 100644 --- a/src/hotspot/cpu/riscv/methodHandles_riscv.cpp +++ b/src/hotspot/cpu/riscv/methodHandles_riscv.cpp @@ -120,7 +120,7 @@ void MethodHandles::jump_from_method_handle(MacroAssembler* _masm, Register meth __ ld(t0,Address(method, entry_offset)); __ jr(t0); __ bind(L_no_such_method); - __ far_jump(RuntimeAddress(StubRoutines::throw_AbstractMethodError_entry())); + __ far_jump(RuntimeAddress(SharedRuntime::throw_AbstractMethodError_entry())); } void MethodHandles::jump_to_lambda_form(MacroAssembler* _masm, @@ -441,7 +441,7 @@ void MethodHandles::generate_method_handle_dispatch(MacroAssembler* _masm, jump_from_method_handle(_masm, xmethod, temp1, for_compiler_entry); if (iid == vmIntrinsics::_linkToInterface) { __ bind(L_incompatible_class_change_error); - __ far_jump(RuntimeAddress(StubRoutines::throw_IncompatibleClassChangeError_entry())); + __ far_jump(RuntimeAddress(SharedRuntime::throw_IncompatibleClassChangeError_entry())); } } diff --git a/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp b/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp index ad06f688d6a36..bed24e442e887 100644 --- a/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp +++ b/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp @@ -48,6 +48,7 @@ #include "runtime/sharedRuntime.hpp" #include "runtime/signature.hpp" #include "runtime/stubRoutines.hpp" +#include "runtime/timerTrace.hpp" #include "runtime/vframeArray.hpp" #include "utilities/align.hpp" #include "utilities/formatBuffer.hpp" @@ -65,6 +66,12 @@ #define __ masm-> +#ifdef PRODUCT +#define BLOCK_COMMENT(str) /* nothing */ +#else +#define BLOCK_COMMENT(str) __ block_comment(str) +#endif + const int StackAlignmentInSlots = StackAlignmentInBytes / VMRegImpl::stack_slot_size; class RegisterSaver { @@ -2628,3 +2635,191 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const cha // return the blob return RuntimeStub::new_runtime_stub(name, &buffer, frame_complete, frame_size_in_words, oop_maps, true); } + +// Continuation point for throwing of implicit exceptions that are +// not handled in the current activation. Fabricates an exception +// oop and initiates normal exception dispatching in this +// frame. Since we need to preserve callee-saved values (currently +// only for C2, but done for C1 as well) we need a callee-saved oop +// map and therefore have to make these stubs into RuntimeStubs +// rather than BufferBlobs. If the compiler needs all registers to +// be preserved between the fault point and the exception handler +// then it must assume responsibility for that in +// AbstractCompiler::continuation_for_implicit_null_exception or +// continuation_for_implicit_division_by_zero_exception. All other +// implicit exceptions (e.g., NullPointerException or +// AbstractMethodError on entry) are either at call sites or +// otherwise assume that stack unwinding will be initiated, so +// caller saved registers were assumed volatile in the compiler. + +RuntimeStub* SharedRuntime::generate_throw_exception(const char* name, address runtime_entry) { + // Information about frame layout at time of blocking runtime call. + // Note that we only have to preserve callee-saved registers since + // the compilers are responsible for supplying a continuation point + // if they expect all registers to be preserved. + // n.b. riscv asserts that frame::arg_reg_save_area_bytes == 0 + assert_cond(runtime_entry != nullptr); + enum layout { + fp_off = 0, + fp_off2, + return_off, + return_off2, + framesize // inclusive of return address + }; + + const int insts_size = 1024; + const int locs_size = 64; + + ResourceMark rm; + const char* timer_msg = "SharedRuntime generate_throw_exception"; + TraceTime timer(timer_msg, TRACETIME_LOG(Info, startuptime)); + + CodeBuffer code(name, insts_size, locs_size); + OopMapSet* oop_maps = new OopMapSet(); + MacroAssembler* masm = new MacroAssembler(&code); + assert_cond(oop_maps != nullptr && masm != nullptr); + + address start = __ pc(); + + // This is an inlined and slightly modified version of call_VM + // which has the ability to fetch the return PC out of + // thread-local storage and also sets up last_Java_sp slightly + // differently than the real call_VM + + __ enter(); // Save FP and RA before call + + assert(is_even(framesize / 2), "sp not 16-byte aligned"); + + // ra and fp are already in place + __ addi(sp, fp, 0 - ((unsigned)framesize << LogBytesPerInt)); // prolog + + int frame_complete = __ pc() - start; + + // Set up last_Java_sp and last_Java_fp + address the_pc = __ pc(); + __ set_last_Java_frame(sp, fp, the_pc, t0); + + // Call runtime + __ mv(c_rarg0, xthread); + BLOCK_COMMENT("call runtime_entry"); + __ rt_call(runtime_entry); + + // Generate oop map + OopMap* map = new OopMap(framesize, 0); + assert_cond(map != nullptr); + + oop_maps->add_gc_map(the_pc - start, map); + + __ reset_last_Java_frame(true); + + __ leave(); + + // check for pending exceptions +#ifdef ASSERT + Label L; + __ ld(t0, Address(xthread, Thread::pending_exception_offset())); + __ bnez(t0, L); + __ should_not_reach_here(); + __ bind(L); +#endif // ASSERT + __ far_jump(RuntimeAddress(StubRoutines::forward_exception_entry())); + + // codeBlob framesize is in words (not VMRegImpl::slot_size) + RuntimeStub* stub = + RuntimeStub::new_runtime_stub(name, + &code, + frame_complete, + (framesize >> (LogBytesPerWord - LogBytesPerInt)), + oop_maps, false); + assert(stub != nullptr, "create runtime stub fail!"); + return stub; +} + +#if INCLUDE_JFR + +static void jfr_prologue(address the_pc, MacroAssembler* masm, Register thread) { + __ set_last_Java_frame(sp, fp, the_pc, t0); + __ mv(c_rarg0, thread); +} + +static void jfr_epilogue(MacroAssembler* masm) { + __ reset_last_Java_frame(true); +} +// For c2: c_rarg0 is junk, call to runtime to write a checkpoint. +// It returns a jobject handle to the event writer. +// The handle is dereferenced and the return value is the event writer oop. +RuntimeStub* SharedRuntime::generate_jfr_write_checkpoint() { + enum layout { + fp_off, + fp_off2, + return_off, + return_off2, + framesize // inclusive of return address + }; + + int insts_size = 1024; + int locs_size = 64; + CodeBuffer code("jfr_write_checkpoint", insts_size, locs_size); + OopMapSet* oop_maps = new OopMapSet(); + MacroAssembler* masm = new MacroAssembler(&code); + + address start = __ pc(); + __ enter(); + int frame_complete = __ pc() - start; + address the_pc = __ pc(); + jfr_prologue(the_pc, masm, xthread); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::write_checkpoint), 1); + + jfr_epilogue(masm); + __ resolve_global_jobject(x10, t0, t1); + __ leave(); + __ ret(); + + OopMap* map = new OopMap(framesize, 1); + oop_maps->add_gc_map(the_pc - start, map); + + RuntimeStub* stub = // codeBlob framesize is in words (not VMRegImpl::slot_size) + RuntimeStub::new_runtime_stub("jfr_write_checkpoint", &code, frame_complete, + (framesize >> (LogBytesPerWord - LogBytesPerInt)), + oop_maps, false); + return stub; +} + +// For c2: call to return a leased buffer. +RuntimeStub* SharedRuntime::generate_jfr_return_lease() { + enum layout { + fp_off, + fp_off2, + return_off, + return_off2, + framesize // inclusive of return address + }; + + int insts_size = 1024; + int locs_size = 64; + CodeBuffer code("jfr_return_lease", insts_size, locs_size); + OopMapSet* oop_maps = new OopMapSet(); + MacroAssembler* masm = new MacroAssembler(&code); + + address start = __ pc(); + __ enter(); + int frame_complete = __ pc() - start; + address the_pc = __ pc(); + jfr_prologue(the_pc, masm, xthread); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::return_lease), 1); + + jfr_epilogue(masm); + __ leave(); + __ ret(); + + OopMap* map = new OopMap(framesize, 1); + oop_maps->add_gc_map(the_pc - start, map); + + RuntimeStub* stub = // codeBlob framesize is in words (not VMRegImpl::slot_size) + RuntimeStub::new_runtime_stub("jfr_return_lease", &code, frame_complete, + (framesize >> (LogBytesPerWord - LogBytesPerInt)), + oop_maps, false); + return stub; +} + +#endif // INCLUDE_JFR diff --git a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp index 6a2c6c7d6c9bd..f214c489557d6 100644 --- a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp +++ b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp @@ -3774,7 +3774,7 @@ class StubGenerator: public StubCodeGenerator { Label thaw_success; // t1 contains the size of the frames to thaw, 0 if overflow or no more frames __ bnez(t1, thaw_success); - __ la(t0, RuntimeAddress(StubRoutines::throw_StackOverflowError_entry())); + __ la(t0, RuntimeAddress(SharedRuntime::throw_StackOverflowError_entry())); __ jr(t0); __ bind(thaw_success); @@ -5834,97 +5834,6 @@ static const int64_t right_3_bits = right_n_bits(3); return start; } -#if INCLUDE_JFR - - static void jfr_prologue(address the_pc, MacroAssembler* _masm, Register thread) { - __ set_last_Java_frame(sp, fp, the_pc, t0); - __ mv(c_rarg0, thread); - } - - static void jfr_epilogue(MacroAssembler* _masm) { - __ reset_last_Java_frame(true); - } - // For c2: c_rarg0 is junk, call to runtime to write a checkpoint. - // It returns a jobject handle to the event writer. - // The handle is dereferenced and the return value is the event writer oop. - static RuntimeStub* generate_jfr_write_checkpoint() { - enum layout { - fp_off, - fp_off2, - return_off, - return_off2, - framesize // inclusive of return address - }; - - int insts_size = 1024; - int locs_size = 64; - CodeBuffer code("jfr_write_checkpoint", insts_size, locs_size); - OopMapSet* oop_maps = new OopMapSet(); - MacroAssembler* masm = new MacroAssembler(&code); - MacroAssembler* _masm = masm; - - address start = __ pc(); - __ enter(); - int frame_complete = __ pc() - start; - address the_pc = __ pc(); - jfr_prologue(the_pc, _masm, xthread); - __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::write_checkpoint), 1); - - jfr_epilogue(_masm); - __ resolve_global_jobject(x10, t0, t1); - __ leave(); - __ ret(); - - OopMap* map = new OopMap(framesize, 1); - oop_maps->add_gc_map(the_pc - start, map); - - RuntimeStub* stub = // codeBlob framesize is in words (not VMRegImpl::slot_size) - RuntimeStub::new_runtime_stub("jfr_write_checkpoint", &code, frame_complete, - (framesize >> (LogBytesPerWord - LogBytesPerInt)), - oop_maps, false); - return stub; - } - - // For c2: call to return a leased buffer. - static RuntimeStub* generate_jfr_return_lease() { - enum layout { - fp_off, - fp_off2, - return_off, - return_off2, - framesize // inclusive of return address - }; - - int insts_size = 1024; - int locs_size = 64; - CodeBuffer code("jfr_return_lease", insts_size, locs_size); - OopMapSet* oop_maps = new OopMapSet(); - MacroAssembler* masm = new MacroAssembler(&code); - MacroAssembler* _masm = masm; - - address start = __ pc(); - __ enter(); - int frame_complete = __ pc() - start; - address the_pc = __ pc(); - jfr_prologue(the_pc, _masm, xthread); - __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::return_lease), 1); - - jfr_epilogue(_masm); - __ leave(); - __ ret(); - - OopMap* map = new OopMap(framesize, 1); - oop_maps->add_gc_map(the_pc - start, map); - - RuntimeStub* stub = // codeBlob framesize is in words (not VMRegImpl::slot_size) - RuntimeStub::new_runtime_stub("jfr_return_lease", &code, frame_complete, - (framesize >> (LogBytesPerWord - LogBytesPerInt)), - oop_maps, false); - return stub; - } - -#endif // INCLUDE_JFR - // exception handler for upcall stubs address generate_upcall_stub_exception_handler() { StubCodeMark mark(this, "StubRoutines", "upcall stub exception handler"); @@ -5939,114 +5848,6 @@ static const int64_t right_3_bits = right_n_bits(3); return start; } - // Continuation point for throwing of implicit exceptions that are - // not handled in the current activation. Fabricates an exception - // oop and initiates normal exception dispatching in this - // frame. Since we need to preserve callee-saved values (currently - // only for C2, but done for C1 as well) we need a callee-saved oop - // map and therefore have to make these stubs into RuntimeStubs - // rather than BufferBlobs. If the compiler needs all registers to - // be preserved between the fault point and the exception handler - // then it must assume responsibility for that in - // AbstractCompiler::continuation_for_implicit_null_exception or - // continuation_for_implicit_division_by_zero_exception. All other - // implicit exceptions (e.g., NullPointerException or - // AbstractMethodError on entry) are either at call sites or - // otherwise assume that stack unwinding will be initiated, so - // caller saved registers were assumed volatile in the compiler. - -#undef __ -#define __ masm-> - - address generate_throw_exception(const char* name, - address runtime_entry, - Register arg1 = noreg, - Register arg2 = noreg) { - // Information about frame layout at time of blocking runtime call. - // Note that we only have to preserve callee-saved registers since - // the compilers are responsible for supplying a continuation point - // if they expect all registers to be preserved. - // n.b. riscv asserts that frame::arg_reg_save_area_bytes == 0 - assert_cond(runtime_entry != nullptr); - enum layout { - fp_off = 0, - fp_off2, - return_off, - return_off2, - framesize // inclusive of return address - }; - - const int insts_size = 1024; - const int locs_size = 64; - - CodeBuffer code(name, insts_size, locs_size); - OopMapSet* oop_maps = new OopMapSet(); - MacroAssembler* masm = new MacroAssembler(&code); - assert_cond(oop_maps != nullptr && masm != nullptr); - - address start = __ pc(); - - // This is an inlined and slightly modified version of call_VM - // which has the ability to fetch the return PC out of - // thread-local storage and also sets up last_Java_sp slightly - // differently than the real call_VM - - __ enter(); // Save FP and RA before call - - assert(is_even(framesize / 2), "sp not 16-byte aligned"); - - // ra and fp are already in place - __ addi(sp, fp, 0 - ((unsigned)framesize << LogBytesPerInt)); // prolog - - int frame_complete = __ pc() - start; - - // Set up last_Java_sp and last_Java_fp - address the_pc = __ pc(); - __ set_last_Java_frame(sp, fp, the_pc, t0); - - // Call runtime - if (arg1 != noreg) { - assert(arg2 != c_rarg1, "clobbered"); - __ mv(c_rarg1, arg1); - } - if (arg2 != noreg) { - __ mv(c_rarg2, arg2); - } - __ mv(c_rarg0, xthread); - BLOCK_COMMENT("call runtime_entry"); - __ rt_call(runtime_entry); - - // Generate oop map - OopMap* map = new OopMap(framesize, 0); - assert_cond(map != nullptr); - - oop_maps->add_gc_map(the_pc - start, map); - - __ reset_last_Java_frame(true); - - __ leave(); - - // check for pending exceptions -#ifdef ASSERT - Label L; - __ ld(t0, Address(xthread, Thread::pending_exception_offset())); - __ bnez(t0, L); - __ should_not_reach_here(); - __ bind(L); -#endif // ASSERT - __ far_jump(RuntimeAddress(StubRoutines::forward_exception_entry())); - - // codeBlob framesize is in words (not VMRegImpl::slot_size) - RuntimeStub* stub = - RuntimeStub::new_runtime_stub(name, - &code, - frame_complete, - (framesize >> (LogBytesPerWord - LogBytesPerInt)), - oop_maps, false); - assert(stub != nullptr, "create runtime stub fail!"); - return stub->entry_point(); - } - #undef __ // Initialization @@ -6071,16 +5872,6 @@ static const int64_t right_3_bits = right_n_bits(3); // is referenced by megamorphic call StubRoutines::_catch_exception_entry = generate_catch_exception(); - // Build this early so it's available for the interpreter. - StubRoutines::_throw_StackOverflowError_entry = - generate_throw_exception("StackOverflowError throw_exception", - CAST_FROM_FN_PTR(address, - SharedRuntime::throw_StackOverflowError)); - StubRoutines::_throw_delayed_StackOverflowError_entry = - generate_throw_exception("delayed StackOverflowError throw_exception", - CAST_FROM_FN_PTR(address, - SharedRuntime::throw_delayed_StackOverflowError)); - if (UseCRC32Intrinsics) { // set table address before stub generation which use it StubRoutines::_crc_table_adr = (address)StubRoutines::riscv::_crc_table; @@ -6093,42 +5884,14 @@ static const int64_t right_3_bits = right_n_bits(3); StubRoutines::_cont_thaw = generate_cont_thaw(); StubRoutines::_cont_returnBarrier = generate_cont_returnBarrier(); StubRoutines::_cont_returnBarrierExc = generate_cont_returnBarrier_exception(); - - JFR_ONLY(generate_jfr_stubs();) } -#if INCLUDE_JFR - void generate_jfr_stubs() { - StubRoutines::_jfr_write_checkpoint_stub = generate_jfr_write_checkpoint(); - StubRoutines::_jfr_write_checkpoint = StubRoutines::_jfr_write_checkpoint_stub->entry_point(); - StubRoutines::_jfr_return_lease_stub = generate_jfr_return_lease(); - StubRoutines::_jfr_return_lease = StubRoutines::_jfr_return_lease_stub->entry_point(); - } -#endif // INCLUDE_JFR - void generate_final_stubs() { // support for verify_oop (must happen after universe_init) if (VerifyOops) { StubRoutines::_verify_oop_subroutine_entry = generate_verify_oop(); } - StubRoutines::_throw_AbstractMethodError_entry = - generate_throw_exception("AbstractMethodError throw_exception", - CAST_FROM_FN_PTR(address, - SharedRuntime:: - throw_AbstractMethodError)); - - StubRoutines::_throw_IncompatibleClassChangeError_entry = - generate_throw_exception("IncompatibleClassChangeError throw_exception", - CAST_FROM_FN_PTR(address, - SharedRuntime:: - throw_IncompatibleClassChangeError)); - - StubRoutines::_throw_NullPointerException_at_call_entry = - generate_throw_exception("NullPointerException at call throw_exception", - CAST_FROM_FN_PTR(address, - SharedRuntime:: - throw_NullPointerException_at_call)); // arraycopy stubs used by compilers generate_arraycopy_stubs(); diff --git a/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp b/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp index f01945bc6a3d1..1f32488777d57 100644 --- a/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp +++ b/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp @@ -658,8 +658,8 @@ void TemplateInterpreterGenerator::generate_stack_overflow_check(void) { // Note: the restored frame is not necessarily interpreted. // Use the shared runtime version of the StackOverflowError. - assert(StubRoutines::throw_StackOverflowError_entry() != nullptr, "stub not yet generated"); - __ far_jump(RuntimeAddress(StubRoutines::throw_StackOverflowError_entry())); + assert(SharedRuntime::throw_StackOverflowError_entry() != nullptr, "stub not yet generated"); + __ far_jump(RuntimeAddress(SharedRuntime::throw_StackOverflowError_entry())); // all done with frame size check __ bind(after_frame_check); diff --git a/src/hotspot/cpu/s390/macroAssembler_s390.cpp b/src/hotspot/cpu/s390/macroAssembler_s390.cpp index b72b36eef5351..a233934405f78 100644 --- a/src/hotspot/cpu/s390/macroAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/macroAssembler_s390.cpp @@ -2751,7 +2751,7 @@ void MacroAssembler::reserved_stack_check(Register return_pc) { pop_frame(); restore_return_pc(); - load_const_optimized(Z_R1, StubRoutines::throw_delayed_StackOverflowError_entry()); + load_const_optimized(Z_R1, SharedRuntime::throw_delayed_StackOverflowError_entry()); // Don't use call() or z_basr(), they will invalidate Z_R14 which contains the return pc. z_br(Z_R1); diff --git a/src/hotspot/cpu/s390/methodHandles_s390.cpp b/src/hotspot/cpu/s390/methodHandles_s390.cpp index ef8722f2499c0..b42822a6eee16 100644 --- a/src/hotspot/cpu/s390/methodHandles_s390.cpp +++ b/src/hotspot/cpu/s390/methodHandles_s390.cpp @@ -180,8 +180,8 @@ void MethodHandles::jump_from_method_handle(MacroAssembler* _masm, Register meth __ z_br(target); __ bind(L_no_such_method); - assert(StubRoutines::throw_AbstractMethodError_entry() != nullptr, "not yet generated!"); - __ load_const_optimized(target, StubRoutines::throw_AbstractMethodError_entry()); + assert(SharedRuntime::throw_AbstractMethodError_entry() != nullptr, "not yet generated!"); + __ load_const_optimized(target, SharedRuntime::throw_AbstractMethodError_entry()); __ z_br(target); } @@ -543,7 +543,7 @@ void MethodHandles::generate_method_handle_dispatch(MacroAssembler* _masm, __ bind(L_no_such_interface); // Throw exception. - __ load_const_optimized(Z_R1, StubRoutines::throw_IncompatibleClassChangeError_entry()); + __ load_const_optimized(Z_R1, SharedRuntime::throw_IncompatibleClassChangeError_entry()); __ z_br(Z_R1); break; } diff --git a/src/hotspot/cpu/s390/sharedRuntime_s390.cpp b/src/hotspot/cpu/s390/sharedRuntime_s390.cpp index 641b3712a175b..364ef948d915e 100644 --- a/src/hotspot/cpu/s390/sharedRuntime_s390.cpp +++ b/src/hotspot/cpu/s390/sharedRuntime_s390.cpp @@ -3010,6 +3010,85 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const cha } +// Continuation point for throwing of implicit exceptions that are +// not handled in the current activation. Fabricates an exception +// oop and initiates normal exception dispatching in this +// frame. Only callee-saved registers are preserved (through the +// normal RegisterMap handling). If the compiler +// needs all registers to be preserved between the fault point and +// the exception handler then it must assume responsibility for that +// in AbstractCompiler::continuation_for_implicit_null_exception or +// continuation_for_implicit_division_by_zero_exception. All other +// implicit exceptions (e.g., NullPointerException or +// AbstractMethodError on entry) are either at call sites or +// otherwise assume that stack unwinding will be initiated, so +// caller saved registers were assumed volatile in the compiler. + +// Note that we generate only this stub into a RuntimeStub, because +// it needs to be properly traversed and ignored during GC, so we +// change the meaning of the "__" macro within this method. + +// Note: the routine set_pc_not_at_call_for_caller in +// SharedRuntime.cpp requires that this code be generated into a +// RuntimeStub. + +RuntimeStub* SharedRuntime::generate_throw_exception(const char* name, address runtime_entry) { + + int insts_size = 256; + int locs_size = 0; + + ResourceMark rm; + const char* timer_msg = "SharedRuntime generate_throw_exception"; + TraceTime timer(timer_msg, TRACETIME_LOG(Info, startuptime)); + + CodeBuffer code(name, insts_size, locs_size); + MacroAssembler* masm = new MacroAssembler(&code); + int framesize_in_bytes; + address start = __ pc(); + + __ save_return_pc(); + framesize_in_bytes = __ push_frame_abi160(0); + + address frame_complete_pc = __ pc(); + + // Note that we always have a runtime stub frame on the top of stack at this point. + __ get_PC(Z_R1); + __ set_last_Java_frame(/*sp*/Z_SP, /*pc*/Z_R1); + + // Do the call. + BLOCK_COMMENT("call runtime_entry"); + __ call_VM_leaf(runtime_entry, Z_thread); + + __ reset_last_Java_frame(); + +#ifdef ASSERT + // Make sure that this code is only executed if there is a pending exception. + { Label L; + __ z_lg(Z_R0, + in_bytes(Thread::pending_exception_offset()), + Z_thread); + __ z_ltgr(Z_R0, Z_R0); + __ z_brne(L); + __ stop("SharedRuntime::throw_exception: no pending exception"); + __ bind(L); + } +#endif + + __ pop_frame(); + __ restore_return_pc(); + + __ load_const_optimized(Z_R1, StubRoutines::forward_exception_entry()); + __ z_br(Z_R1); + + RuntimeStub* stub = + RuntimeStub::new_runtime_stub(name, &code, + frame_complete_pc - start, + framesize_in_bytes/wordSize, + nullptr /*oop_maps*/, false); + + return stub; +} + //------------------------------Montgomery multiplication------------------------ // @@ -3263,3 +3342,18 @@ extern "C" int SpinPause() { return 0; } + +#if INCLUDE_JFR +RuntimeStub* SharedRuntime::generate_jfr_write_checkpoint() { + if (!Continuations::enabled()) return nullptr; + Unimplemented(); + return nullptr; +} + +RuntimeStub* SharedRuntime::generate_jfr_return_lease() { + if (!Continuations::enabled()) return nullptr; + Unimplemented(); + return nullptr; +} + +#endif // INCLUDE_JFR diff --git a/src/hotspot/cpu/s390/stubGenerator_s390.cpp b/src/hotspot/cpu/s390/stubGenerator_s390.cpp index 556c0d4703d54..d878731cca51f 100644 --- a/src/hotspot/cpu/s390/stubGenerator_s390.cpp +++ b/src/hotspot/cpu/s390/stubGenerator_s390.cpp @@ -572,89 +572,6 @@ class StubGenerator: public StubCodeGenerator { #undef pending_exception_offset } - // Continuation point for throwing of implicit exceptions that are - // not handled in the current activation. Fabricates an exception - // oop and initiates normal exception dispatching in this - // frame. Only callee-saved registers are preserved (through the - // normal RegisterMap handling). If the compiler - // needs all registers to be preserved between the fault point and - // the exception handler then it must assume responsibility for that - // in AbstractCompiler::continuation_for_implicit_null_exception or - // continuation_for_implicit_division_by_zero_exception. All other - // implicit exceptions (e.g., NullPointerException or - // AbstractMethodError on entry) are either at call sites or - // otherwise assume that stack unwinding will be initiated, so - // caller saved registers were assumed volatile in the compiler. - - // Note that we generate only this stub into a RuntimeStub, because - // it needs to be properly traversed and ignored during GC, so we - // change the meaning of the "__" macro within this method. - - // Note: the routine set_pc_not_at_call_for_caller in - // SharedRuntime.cpp requires that this code be generated into a - // RuntimeStub. -#undef __ -#define __ masm-> - - address generate_throw_exception(const char* name, address runtime_entry, - bool restore_saved_exception_pc, - Register arg1 = noreg, Register arg2 = noreg) { - assert_different_registers(arg1, Z_R0_scratch); // would be destroyed by push_frame() - assert_different_registers(arg2, Z_R0_scratch); // would be destroyed by push_frame() - - int insts_size = 256; - int locs_size = 0; - CodeBuffer code(name, insts_size, locs_size); - MacroAssembler* masm = new MacroAssembler(&code); - int framesize_in_bytes; - address start = __ pc(); - - __ save_return_pc(); - framesize_in_bytes = __ push_frame_abi160(0); - - address frame_complete_pc = __ pc(); - if (restore_saved_exception_pc) { - __ unimplemented("StubGenerator::throw_exception", 74); - } - - // Note that we always have a runtime stub frame on the top of stack at this point. - __ get_PC(Z_R1); - __ set_last_Java_frame(/*sp*/Z_SP, /*pc*/Z_R1); - - // Do the call. - BLOCK_COMMENT("call runtime_entry"); - __ call_VM_leaf(runtime_entry, Z_thread, arg1, arg2); - - __ reset_last_Java_frame(); - -#ifdef ASSERT - // Make sure that this code is only executed if there is a pending exception. - { Label L; - __ z_lg(Z_R0, - in_bytes(Thread::pending_exception_offset()), - Z_thread); - __ z_ltgr(Z_R0, Z_R0); - __ z_brne(L); - __ stop("StubRoutines::throw_exception: no pending exception"); - __ bind(L); - } -#endif - - __ pop_frame(); - __ restore_return_pc(); - - __ load_const_optimized(Z_R1, StubRoutines::forward_exception_entry()); - __ z_br(Z_R1); - - RuntimeStub* stub = - RuntimeStub::new_runtime_stub(name, &code, - frame_complete_pc - start, - framesize_in_bytes/wordSize, - nullptr /*oop_maps*/, false); - - return stub->entry_point(); - } - #undef __ #ifdef PRODUCT #define __ _masm-> @@ -3121,21 +3038,6 @@ class StubGenerator: public StubCodeGenerator { return nullptr; } - #if INCLUDE_JFR - RuntimeStub* generate_jfr_write_checkpoint() { - if (!Continuations::enabled()) return nullptr; - Unimplemented(); - return nullptr; - } - - RuntimeStub* generate_jfr_return_lease() { - if (!Continuations::enabled()) return nullptr; - Unimplemented(); - return nullptr; - } - - #endif // INCLUDE_JFR - // exception handler for upcall stubs address generate_upcall_stub_exception_handler() { StubCodeMark mark(this, "StubRoutines", "upcall stub exception handler"); @@ -3164,14 +3066,6 @@ class StubGenerator: public StubCodeGenerator { StubRoutines::_call_stub_entry = generate_call_stub(StubRoutines::_call_stub_return_address); StubRoutines::_catch_exception_entry = generate_catch_exception(); - // Build this early so it's available for the interpreter. - StubRoutines::_throw_StackOverflowError_entry = - generate_throw_exception("StackOverflowError throw_exception", - CAST_FROM_FN_PTR(address, SharedRuntime::throw_StackOverflowError), false); - StubRoutines::_throw_delayed_StackOverflowError_entry = - generate_throw_exception("delayed StackOverflowError throw_exception", - CAST_FROM_FN_PTR(address, SharedRuntime::throw_delayed_StackOverflowError), false); - //---------------------------------------------------------------------- // Entry points that are platform specific. @@ -3196,29 +3090,13 @@ class StubGenerator: public StubCodeGenerator { StubRoutines::_cont_thaw = generate_cont_thaw(); StubRoutines::_cont_returnBarrier = generate_cont_returnBarrier(); StubRoutines::_cont_returnBarrierExc = generate_cont_returnBarrier_exception(); - - JFR_ONLY(generate_jfr_stubs();) } -#if INCLUDE_JFR - void generate_jfr_stubs() { - StubRoutines::_jfr_write_checkpoint_stub = generate_jfr_write_checkpoint(); - StubRoutines::_jfr_write_checkpoint = StubRoutines::_jfr_write_checkpoint_stub->entry_point(); - StubRoutines::_jfr_return_lease_stub = generate_jfr_return_lease(); - StubRoutines::_jfr_return_lease = StubRoutines::_jfr_return_lease_stub->entry_point(); - } -#endif // INCLUDE_JFR - void generate_final_stubs() { // Generates all stubs and initializes the entry points. StubRoutines::zarch::_partial_subtype_check = generate_partial_subtype_check(); - // These entry points require SharedInfo::stack0 to be set up in non-core builds. - StubRoutines::_throw_AbstractMethodError_entry = generate_throw_exception("AbstractMethodError throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_AbstractMethodError), false); - StubRoutines::_throw_IncompatibleClassChangeError_entry= generate_throw_exception("IncompatibleClassChangeError throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_IncompatibleClassChangeError), false); - StubRoutines::_throw_NullPointerException_at_call_entry= generate_throw_exception("NullPointerException at call throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_NullPointerException_at_call), false); - // Support for verify_oop (must happen after universe_init). StubRoutines::_verify_oop_subroutine_entry = generate_verify_oop_subroutine(); diff --git a/src/hotspot/cpu/s390/templateInterpreterGenerator_s390.cpp b/src/hotspot/cpu/s390/templateInterpreterGenerator_s390.cpp index 870258264003a..c16e444904563 100644 --- a/src/hotspot/cpu/s390/templateInterpreterGenerator_s390.cpp +++ b/src/hotspot/cpu/s390/templateInterpreterGenerator_s390.cpp @@ -850,9 +850,9 @@ void TemplateInterpreterGenerator::generate_stack_overflow_check(Register frame_ // Note also that the restored frame is not necessarily interpreted. // Use the shared runtime version of the StackOverflowError. - assert(StubRoutines::throw_StackOverflowError_entry() != nullptr, "stub not yet generated"); - AddressLiteral stub(StubRoutines::throw_StackOverflowError_entry()); - __ load_absolute_address(tmp1, StubRoutines::throw_StackOverflowError_entry()); + assert(SharedRuntime::throw_StackOverflowError_entry() != nullptr, "stub not yet generated"); + AddressLiteral stub(SharedRuntime::throw_StackOverflowError_entry()); + __ load_absolute_address(tmp1, SharedRuntime::throw_StackOverflowError_entry()); __ z_br(tmp1); // If you get to here, then there is enough stack space. diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp index a5ad19806eab6..ba337751d19d1 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp @@ -1303,7 +1303,7 @@ void MacroAssembler::reserved_stack_check() { jcc(Assembler::below, no_reserved_zone_enabling); call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::enable_stack_reserved_zone), thread); - jump(RuntimeAddress(StubRoutines::throw_delayed_StackOverflowError_entry())); + jump(RuntimeAddress(SharedRuntime::throw_delayed_StackOverflowError_entry())); should_not_reach_here(); bind(no_reserved_zone_enabling); diff --git a/src/hotspot/cpu/x86/methodHandles_x86.cpp b/src/hotspot/cpu/x86/methodHandles_x86.cpp index 3a8c104876677..fd738b7333e4f 100644 --- a/src/hotspot/cpu/x86/methodHandles_x86.cpp +++ b/src/hotspot/cpu/x86/methodHandles_x86.cpp @@ -159,7 +159,7 @@ void MethodHandles::jump_from_method_handle(MacroAssembler* _masm, Register meth __ jmp(Address(method, entry_offset)); __ bind(L_no_such_method); - __ jump(RuntimeAddress(StubRoutines::throw_AbstractMethodError_entry())); + __ jump(RuntimeAddress(SharedRuntime::throw_AbstractMethodError_entry())); } void MethodHandles::jump_to_lambda_form(MacroAssembler* _masm, @@ -510,7 +510,7 @@ void MethodHandles::generate_method_handle_dispatch(MacroAssembler* _masm, if (iid == vmIntrinsics::_linkToInterface) { __ bind(L_incompatible_class_change_error); - __ jump(RuntimeAddress(StubRoutines::throw_IncompatibleClassChangeError_entry())); + __ jump(RuntimeAddress(SharedRuntime::throw_IncompatibleClassChangeError_entry())); } } } diff --git a/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp b/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp index 85c9125a97d1e..273bbcc6525de 100644 --- a/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp +++ b/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp @@ -43,6 +43,7 @@ #include "runtime/sharedRuntime.hpp" #include "runtime/signature.hpp" #include "runtime/stubRoutines.hpp" +#include "runtime/timerTrace.hpp" #include "runtime/vframeArray.hpp" #include "runtime/vm_version.hpp" #include "utilities/align.hpp" @@ -56,6 +57,12 @@ #define __ masm-> +#ifdef PRODUCT +#define BLOCK_COMMENT(str) /* nothing */ +#else +#define BLOCK_COMMENT(str) __ block_comment(str) +#endif // PRODUCT + const int StackAlignmentInSlots = StackAlignmentInBytes / VMRegImpl::stack_slot_size; class RegisterSaver { @@ -2631,3 +2638,207 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const cha // frame_size_words or bytes?? return RuntimeStub::new_runtime_stub(name, &buffer, frame_complete, frame_size_words, oop_maps, true); } + + //------------------------------------------------------------------------------------------------------------------------ + // Continuation point for throwing of implicit exceptions that are not handled in + // the current activation. Fabricates an exception oop and initiates normal + // exception dispatching in this frame. + // + // Previously the compiler (c2) allowed for callee save registers on Java calls. + // This is no longer true after adapter frames were removed but could possibly + // be brought back in the future if the interpreter code was reworked and it + // was deemed worthwhile. The comment below was left to describe what must + // happen here if callee saves were resurrected. As it stands now this stub + // could actually be a vanilla BufferBlob and have now oopMap at all. + // Since it doesn't make much difference we've chosen to leave it the + // way it was in the callee save days and keep the comment. + + // If we need to preserve callee-saved values we need a callee-saved oop map and + // therefore have to make these stubs into RuntimeStubs rather than BufferBlobs. + // If the compiler needs all registers to be preserved between the fault + // point and the exception handler then it must assume responsibility for that in + // AbstractCompiler::continuation_for_implicit_null_exception or + // continuation_for_implicit_division_by_zero_exception. All other implicit + // exceptions (e.g., NullPointerException or AbstractMethodError on entry) are + // either at call sites or otherwise assume that stack unwinding will be initiated, + // so caller saved registers were assumed volatile in the compiler. +RuntimeStub* SharedRuntime::generate_throw_exception(const char* name, address runtime_entry) { + + // Information about frame layout at time of blocking runtime call. + // Note that we only have to preserve callee-saved registers since + // the compilers are responsible for supplying a continuation point + // if they expect all registers to be preserved. + enum layout { + thread_off, // last_java_sp + arg1_off, + arg2_off, + rbp_off, // callee saved register + ret_pc, + framesize + }; + + int insts_size = 256; + int locs_size = 32; + + ResourceMark rm; + const char* timer_msg = "SharedRuntime generate_throw_exception"; + TraceTime timer(timer_msg, TRACETIME_LOG(Info, startuptime)); + + CodeBuffer code(name, insts_size, locs_size); + OopMapSet* oop_maps = new OopMapSet(); + MacroAssembler* masm = new MacroAssembler(&code); + + address start = __ pc(); + + // This is an inlined and slightly modified version of call_VM + // which has the ability to fetch the return PC out of + // thread-local storage and also sets up last_Java_sp slightly + // differently than the real call_VM + Register java_thread = rbx; + __ get_thread(java_thread); + + __ enter(); // required for proper stackwalking of RuntimeStub frame + + // pc and rbp, already pushed + __ subptr(rsp, (framesize-2) * wordSize); // prolog + + // Frame is now completed as far as size and linkage. + + int frame_complete = __ pc() - start; + + // push java thread (becomes first argument of C function) + __ movptr(Address(rsp, thread_off * wordSize), java_thread); + // Set up last_Java_sp and last_Java_fp + __ set_last_Java_frame(java_thread, rsp, rbp, nullptr, noreg); + + // Call runtime + BLOCK_COMMENT("call runtime_entry"); + __ call(RuntimeAddress(runtime_entry)); + // Generate oop map + OopMap* map = new OopMap(framesize, 0); + oop_maps->add_gc_map(__ pc() - start, map); + + // restore the thread (cannot use the pushed argument since arguments + // may be overwritten by C code generated by an optimizing compiler); + // however can use the register value directly if it is callee saved. + __ get_thread(java_thread); + + __ reset_last_Java_frame(java_thread, true); + + __ leave(); // required for proper stackwalking of RuntimeStub frame + + // check for pending exceptions +#ifdef ASSERT + Label L; + __ cmpptr(Address(java_thread, Thread::pending_exception_offset()), NULL_WORD); + __ jcc(Assembler::notEqual, L); + __ should_not_reach_here(); + __ bind(L); +#endif /* ASSERT */ + __ jump(RuntimeAddress(StubRoutines::forward_exception_entry())); + + + RuntimeStub* stub = RuntimeStub::new_runtime_stub(name, &code, frame_complete, framesize, oop_maps, false); + return stub; +} + +#if INCLUDE_JFR + +static void jfr_prologue(address the_pc, MacroAssembler* masm) { + Register java_thread = rdi; + __ get_thread(java_thread); + __ set_last_Java_frame(java_thread, rsp, rbp, the_pc, noreg); + __ movptr(Address(rsp, 0), java_thread); +} + +// The handle is dereferenced through a load barrier. +static void jfr_epilogue(MacroAssembler* masm) { + Register java_thread = rdi; + __ get_thread(java_thread); + __ reset_last_Java_frame(java_thread, true); +} + +// For c2: c_rarg0 is junk, call to runtime to write a checkpoint. +// It returns a jobject handle to the event writer. +// The handle is dereferenced and the return value is the event writer oop. +RuntimeStub* SharedRuntime::generate_jfr_write_checkpoint() { + enum layout { + FPUState_off = 0, + rbp_off = FPUStateSizeInWords, + rdi_off, + rsi_off, + rcx_off, + rbx_off, + saved_argument_off, + saved_argument_off2, // 2nd half of double + framesize + }; + + int insts_size = 1024; + int locs_size = 64; + CodeBuffer code("jfr_write_checkpoint", insts_size, locs_size); + OopMapSet* oop_maps = new OopMapSet(); + MacroAssembler* masm = new MacroAssembler(&code); + + address start = __ pc(); + __ enter(); + int frame_complete = __ pc() - start; + address the_pc = __ pc(); + jfr_prologue(the_pc, masm); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::write_checkpoint), 1); + jfr_epilogue(masm); + __ resolve_global_jobject(rax, rdi, rdx); + __ leave(); + __ ret(0); + + OopMap* map = new OopMap(framesize, 1); // rbp + oop_maps->add_gc_map(the_pc - start, map); + + RuntimeStub* stub = // codeBlob framesize is in words (not VMRegImpl::slot_size) + RuntimeStub::new_runtime_stub("jfr_write_checkpoint", &code, frame_complete, + (framesize >> (LogBytesPerWord - LogBytesPerInt)), + oop_maps, false); + return stub; +} + +// For c2: call to return a leased buffer. +RuntimeStub* SharedRuntime::generate_jfr_return_lease() { + enum layout { + FPUState_off = 0, + rbp_off = FPUStateSizeInWords, + rdi_off, + rsi_off, + rcx_off, + rbx_off, + saved_argument_off, + saved_argument_off2, // 2nd half of double + framesize + }; + + int insts_size = 1024; + int locs_size = 64; + CodeBuffer code("jfr_return_lease", insts_size, locs_size); + OopMapSet* oop_maps = new OopMapSet(); + MacroAssembler* masm = new MacroAssembler(&code); + + address start = __ pc(); + __ enter(); + int frame_complete = __ pc() - start; + address the_pc = __ pc(); + jfr_prologue(the_pc, masm); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::return_lease), 1); + jfr_epilogue(masm); + __ leave(); + __ ret(0); + + OopMap* map = new OopMap(framesize, 1); // rbp + oop_maps->add_gc_map(the_pc - start, map); + + RuntimeStub* stub = // codeBlob framesize is in words (not VMRegImpl::slot_size) + RuntimeStub::new_runtime_stub("jfr_return_lease", &code, frame_complete, + (framesize >> (LogBytesPerWord - LogBytesPerInt)), + oop_maps, false); + return stub; +} + +#endif // INCLUDE_JFR diff --git a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp index b5362a9942ce7..05ec85ef09a66 100644 --- a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp +++ b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp @@ -52,6 +52,7 @@ #include "runtime/sharedRuntime.hpp" #include "runtime/signature.hpp" #include "runtime/stubRoutines.hpp" +#include "runtime/timerTrace.hpp" #include "runtime/vframeArray.hpp" #include "runtime/vm_version.hpp" #include "utilities/align.hpp" @@ -70,6 +71,12 @@ #define __ masm-> +#ifdef PRODUCT +#define BLOCK_COMMENT(str) /* nothing */ +#else +#define BLOCK_COMMENT(str) __ block_comment(str) +#endif // PRODUCT + const int StackAlignmentInSlots = StackAlignmentInBytes / VMRegImpl::stack_slot_size; class RegisterSaver { @@ -3210,6 +3217,101 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const cha return RuntimeStub::new_runtime_stub(name, &buffer, frame_complete, frame_size_in_words, oop_maps, true); } +// Continuation point for throwing of implicit exceptions that are +// not handled in the current activation. Fabricates an exception +// oop and initiates normal exception dispatching in this +// frame. Since we need to preserve callee-saved values (currently +// only for C2, but done for C1 as well) we need a callee-saved oop +// map and therefore have to make these stubs into RuntimeStubs +// rather than BufferBlobs. If the compiler needs all registers to +// be preserved between the fault point and the exception handler +// then it must assume responsibility for that in +// AbstractCompiler::continuation_for_implicit_null_exception or +// continuation_for_implicit_division_by_zero_exception. All other +// implicit exceptions (e.g., NullPointerException or +// AbstractMethodError on entry) are either at call sites or +// otherwise assume that stack unwinding will be initiated, so +// caller saved registers were assumed volatile in the compiler. +RuntimeStub* SharedRuntime::generate_throw_exception(const char* name, address runtime_entry) { + // Information about frame layout at time of blocking runtime call. + // Note that we only have to preserve callee-saved registers since + // the compilers are responsible for supplying a continuation point + // if they expect all registers to be preserved. + enum layout { + rbp_off = frame::arg_reg_save_area_bytes/BytesPerInt, + rbp_off2, + return_off, + return_off2, + framesize // inclusive of return address + }; + + int insts_size = 512; + int locs_size = 64; + + ResourceMark rm; + const char* timer_msg = "SharedRuntime generate_throw_exception"; + TraceTime timer(timer_msg, TRACETIME_LOG(Info, startuptime)); + + CodeBuffer code(name, insts_size, locs_size); + OopMapSet* oop_maps = new OopMapSet(); + MacroAssembler* masm = new MacroAssembler(&code); + + address start = __ pc(); + + // This is an inlined and slightly modified version of call_VM + // which has the ability to fetch the return PC out of + // thread-local storage and also sets up last_Java_sp slightly + // differently than the real call_VM + + __ enter(); // required for proper stackwalking of RuntimeStub frame + + assert(is_even(framesize/2), "sp not 16-byte aligned"); + + // return address and rbp are already in place + __ subptr(rsp, (framesize-4) << LogBytesPerInt); // prolog + + int frame_complete = __ pc() - start; + + // Set up last_Java_sp and last_Java_fp + address the_pc = __ pc(); + __ set_last_Java_frame(rsp, rbp, the_pc, rscratch1); + __ andptr(rsp, -(StackAlignmentInBytes)); // Align stack + + // Call runtime + __ movptr(c_rarg0, r15_thread); + BLOCK_COMMENT("call runtime_entry"); + __ call(RuntimeAddress(runtime_entry)); + + // Generate oop map + OopMap* map = new OopMap(framesize, 0); + + oop_maps->add_gc_map(the_pc - start, map); + + __ reset_last_Java_frame(true); + + __ leave(); // required for proper stackwalking of RuntimeStub frame + + // check for pending exceptions +#ifdef ASSERT + Label L; + __ cmpptr(Address(r15_thread, Thread::pending_exception_offset()), NULL_WORD); + __ jcc(Assembler::notEqual, L); + __ should_not_reach_here(); + __ bind(L); +#endif // ASSERT + __ jump(RuntimeAddress(StubRoutines::forward_exception_entry())); + + + // codeBlob framesize is in words (not VMRegImpl::slot_size) + RuntimeStub* stub = + RuntimeStub::new_runtime_stub(name, + &code, + frame_complete, + (framesize >> (LogBytesPerWord - LogBytesPerInt)), + oop_maps, false); + return stub; +} + //------------------------------Montgomery multiplication------------------------ // @@ -3475,3 +3577,94 @@ void SharedRuntime::montgomery_square(jint *a_ints, jint *n_ints, reverse_words(m, (julong *)m_ints, longwords); } +#if INCLUDE_JFR + +// For c2: c_rarg0 is junk, call to runtime to write a checkpoint. +// It returns a jobject handle to the event writer. +// The handle is dereferenced and the return value is the event writer oop. +RuntimeStub* SharedRuntime::generate_jfr_write_checkpoint() { + enum layout { + rbp_off, + rbpH_off, + return_off, + return_off2, + framesize // inclusive of return address + }; + + CodeBuffer code("jfr_write_checkpoint", 1024, 64); + MacroAssembler* masm = new MacroAssembler(&code); + address start = __ pc(); + + __ enter(); + address the_pc = __ pc(); + + int frame_complete = the_pc - start; + + __ set_last_Java_frame(rsp, rbp, the_pc, rscratch1); + __ movptr(c_rarg0, r15_thread); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::write_checkpoint), 1); + __ reset_last_Java_frame(true); + + // rax is jobject handle result, unpack and process it through a barrier. + __ resolve_global_jobject(rax, r15_thread, c_rarg0); + + __ leave(); + __ ret(0); + + OopMapSet* oop_maps = new OopMapSet(); + OopMap* map = new OopMap(framesize, 1); + oop_maps->add_gc_map(frame_complete, map); + + RuntimeStub* stub = + RuntimeStub::new_runtime_stub(code.name(), + &code, + frame_complete, + (framesize >> (LogBytesPerWord - LogBytesPerInt)), + oop_maps, + false); + return stub; +} + +// For c2: call to return a leased buffer. +RuntimeStub* SharedRuntime::generate_jfr_return_lease() { + enum layout { + rbp_off, + rbpH_off, + return_off, + return_off2, + framesize // inclusive of return address + }; + + CodeBuffer code("jfr_return_lease", 1024, 64); + MacroAssembler* masm = new MacroAssembler(&code); + address start = __ pc(); + + __ enter(); + address the_pc = __ pc(); + + int frame_complete = the_pc - start; + + __ set_last_Java_frame(rsp, rbp, the_pc, rscratch2); + __ movptr(c_rarg0, r15_thread); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::return_lease), 1); + __ reset_last_Java_frame(true); + + __ leave(); + __ ret(0); + + OopMapSet* oop_maps = new OopMapSet(); + OopMap* map = new OopMap(framesize, 1); + oop_maps->add_gc_map(frame_complete, map); + + RuntimeStub* stub = + RuntimeStub::new_runtime_stub(code.name(), + &code, + frame_complete, + (framesize >> (LogBytesPerWord - LogBytesPerInt)), + oop_maps, + false); + return stub; +} + +#endif // INCLUDE_JFR + diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_32.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_32.cpp index d8067a39177f1..de13772dcfb0d 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_32.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_32.cpp @@ -3843,121 +3843,8 @@ class StubGenerator: public StubCodeGenerator { return start; } - public: - // Information about frame layout at time of blocking runtime call. - // Note that we only have to preserve callee-saved registers since - // the compilers are responsible for supplying a continuation point - // if they expect all registers to be preserved. - enum layout { - thread_off, // last_java_sp - arg1_off, - arg2_off, - rbp_off, // callee saved register - ret_pc, - framesize - }; - private: -#undef __ -#define __ masm-> - - //------------------------------------------------------------------------------------------------------------------------ - // Continuation point for throwing of implicit exceptions that are not handled in - // the current activation. Fabricates an exception oop and initiates normal - // exception dispatching in this frame. - // - // Previously the compiler (c2) allowed for callee save registers on Java calls. - // This is no longer true after adapter frames were removed but could possibly - // be brought back in the future if the interpreter code was reworked and it - // was deemed worthwhile. The comment below was left to describe what must - // happen here if callee saves were resurrected. As it stands now this stub - // could actually be a vanilla BufferBlob and have now oopMap at all. - // Since it doesn't make much difference we've chosen to leave it the - // way it was in the callee save days and keep the comment. - - // If we need to preserve callee-saved values we need a callee-saved oop map and - // therefore have to make these stubs into RuntimeStubs rather than BufferBlobs. - // If the compiler needs all registers to be preserved between the fault - // point and the exception handler then it must assume responsibility for that in - // AbstractCompiler::continuation_for_implicit_null_exception or - // continuation_for_implicit_division_by_zero_exception. All other implicit - // exceptions (e.g., NullPointerException or AbstractMethodError on entry) are - // either at call sites or otherwise assume that stack unwinding will be initiated, - // so caller saved registers were assumed volatile in the compiler. - address generate_throw_exception(const char* name, address runtime_entry, - Register arg1 = noreg, Register arg2 = noreg) { - - int insts_size = 256; - int locs_size = 32; - - CodeBuffer code(name, insts_size, locs_size); - OopMapSet* oop_maps = new OopMapSet(); - MacroAssembler* masm = new MacroAssembler(&code); - - address start = __ pc(); - - // This is an inlined and slightly modified version of call_VM - // which has the ability to fetch the return PC out of - // thread-local storage and also sets up last_Java_sp slightly - // differently than the real call_VM - Register java_thread = rbx; - __ get_thread(java_thread); - - __ enter(); // required for proper stackwalking of RuntimeStub frame - - // pc and rbp, already pushed - __ subptr(rsp, (framesize-2) * wordSize); // prolog - - // Frame is now completed as far as size and linkage. - - int frame_complete = __ pc() - start; - - // push java thread (becomes first argument of C function) - __ movptr(Address(rsp, thread_off * wordSize), java_thread); - if (arg1 != noreg) { - __ movptr(Address(rsp, arg1_off * wordSize), arg1); - } - if (arg2 != noreg) { - assert(arg1 != noreg, "missing reg arg"); - __ movptr(Address(rsp, arg2_off * wordSize), arg2); - } - - // Set up last_Java_sp and last_Java_fp - __ set_last_Java_frame(java_thread, rsp, rbp, nullptr, noreg); - - // Call runtime - BLOCK_COMMENT("call runtime_entry"); - __ call(RuntimeAddress(runtime_entry)); - // Generate oop map - OopMap* map = new OopMap(framesize, 0); - oop_maps->add_gc_map(__ pc() - start, map); - - // restore the thread (cannot use the pushed argument since arguments - // may be overwritten by C code generated by an optimizing compiler); - // however can use the register value directly if it is callee saved. - __ get_thread(java_thread); - - __ reset_last_Java_frame(java_thread, true); - - __ leave(); // required for proper stackwalking of RuntimeStub frame - - // check for pending exceptions -#ifdef ASSERT - Label L; - __ cmpptr(Address(java_thread, Thread::pending_exception_offset()), NULL_WORD); - __ jcc(Assembler::notEqual, L); - __ should_not_reach_here(); - __ bind(L); -#endif /* ASSERT */ - __ jump(RuntimeAddress(StubRoutines::forward_exception_entry())); - - - RuntimeStub* stub = RuntimeStub::new_runtime_stub(name, &code, frame_complete, framesize, oop_maps, false); - return stub->entry_point(); - } - - void create_control_words() { // Round to nearest, 53-bit mode, exceptions masked StubRoutines::x86::_fpu_cntrl_wrd_std = 0x027F; @@ -3997,109 +3884,6 @@ class StubGenerator: public StubCodeGenerator { return nullptr; } -#if INCLUDE_JFR - - static void jfr_prologue(address the_pc, MacroAssembler* masm) { - Register java_thread = rdi; - __ get_thread(java_thread); - __ set_last_Java_frame(java_thread, rsp, rbp, the_pc, noreg); - __ movptr(Address(rsp, 0), java_thread); - } - - // The handle is dereferenced through a load barrier. - static void jfr_epilogue(MacroAssembler* masm) { - Register java_thread = rdi; - __ get_thread(java_thread); - __ reset_last_Java_frame(java_thread, true); - } - - // For c2: c_rarg0 is junk, call to runtime to write a checkpoint. - // It returns a jobject handle to the event writer. - // The handle is dereferenced and the return value is the event writer oop. - static RuntimeStub* generate_jfr_write_checkpoint() { - enum layout { - FPUState_off = 0, - rbp_off = FPUStateSizeInWords, - rdi_off, - rsi_off, - rcx_off, - rbx_off, - saved_argument_off, - saved_argument_off2, // 2nd half of double - framesize - }; - - int insts_size = 1024; - int locs_size = 64; - CodeBuffer code("jfr_write_checkpoint", insts_size, locs_size); - OopMapSet* oop_maps = new OopMapSet(); - MacroAssembler* masm = new MacroAssembler(&code); - MacroAssembler* _masm = masm; - - address start = __ pc(); - __ enter(); - int frame_complete = __ pc() - start; - address the_pc = __ pc(); - jfr_prologue(the_pc, _masm); - __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::write_checkpoint), 1); - jfr_epilogue(_masm); - __ resolve_global_jobject(rax, rdi, rdx); - __ leave(); - __ ret(0); - - OopMap* map = new OopMap(framesize, 1); // rbp - oop_maps->add_gc_map(the_pc - start, map); - - RuntimeStub* stub = // codeBlob framesize is in words (not VMRegImpl::slot_size) - RuntimeStub::new_runtime_stub("jfr_write_checkpoint", &code, frame_complete, - (framesize >> (LogBytesPerWord - LogBytesPerInt)), - oop_maps, false); - return stub; - } - - // For c2: call to return a leased buffer. - static RuntimeStub* generate_jfr_return_lease() { - enum layout { - FPUState_off = 0, - rbp_off = FPUStateSizeInWords, - rdi_off, - rsi_off, - rcx_off, - rbx_off, - saved_argument_off, - saved_argument_off2, // 2nd half of double - framesize - }; - - int insts_size = 1024; - int locs_size = 64; - CodeBuffer code("jfr_return_lease", insts_size, locs_size); - OopMapSet* oop_maps = new OopMapSet(); - MacroAssembler* masm = new MacroAssembler(&code); - MacroAssembler* _masm = masm; - - address start = __ pc(); - __ enter(); - int frame_complete = __ pc() - start; - address the_pc = __ pc(); - jfr_prologue(the_pc, _masm); - __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::return_lease), 1); - jfr_epilogue(_masm); - __ leave(); - __ ret(0); - - OopMap* map = new OopMap(framesize, 1); // rbp - oop_maps->add_gc_map(the_pc - start, map); - - RuntimeStub* stub = // codeBlob framesize is in words (not VMRegImpl::slot_size) - RuntimeStub::new_runtime_stub("jfr_return_lease", &code, frame_complete, - (framesize >> (LogBytesPerWord - LogBytesPerInt)), - oop_maps, false); - return stub; - } - -#endif // INCLUDE_JFR - //--------------------------------------------------------------------------- // Initialization @@ -4130,12 +3914,6 @@ class StubGenerator: public StubCodeGenerator { StubRoutines::x86::_d2i_wrapper = generate_d2i_wrapper(T_INT, CAST_FROM_FN_PTR(address, SharedRuntime::d2i)); StubRoutines::x86::_d2l_wrapper = generate_d2i_wrapper(T_LONG, CAST_FROM_FN_PTR(address, SharedRuntime::d2l)); - // Build this early so it's available for the interpreter - StubRoutines::_throw_StackOverflowError_entry = generate_throw_exception("StackOverflowError throw_exception", - CAST_FROM_FN_PTR(address, SharedRuntime::throw_StackOverflowError)); - StubRoutines::_throw_delayed_StackOverflowError_entry = generate_throw_exception("delayed StackOverflowError throw_exception", - CAST_FROM_FN_PTR(address, SharedRuntime::throw_delayed_StackOverflowError)); - if (UseCRC32Intrinsics) { // set table address before stub generation which use it StubRoutines::_crc_table_adr = (address)StubRoutines::x86::_crc_table; @@ -4188,28 +3966,11 @@ class StubGenerator: public StubCodeGenerator { StubRoutines::_cont_thaw = generate_cont_thaw(); StubRoutines::_cont_returnBarrier = generate_cont_returnBarrier(); StubRoutines::_cont_returnBarrierExc = generate_cont_returnBarrier_exception(); - - JFR_ONLY(generate_jfr_stubs();) } -#if INCLUDE_JFR - void generate_jfr_stubs() { - StubRoutines::_jfr_write_checkpoint_stub = generate_jfr_write_checkpoint(); - StubRoutines::_jfr_write_checkpoint = StubRoutines::_jfr_write_checkpoint_stub->entry_point(); - StubRoutines::_jfr_return_lease_stub = generate_jfr_return_lease(); - StubRoutines::_jfr_return_lease = StubRoutines::_jfr_return_lease_stub->entry_point(); - } -#endif // INCLUDE_JFR - void generate_final_stubs() { // Generates all stubs and initializes the entry points - // These entry points require SharedInfo::stack0 to be set up in non-core builds - // and need to be relocatable, so they each fabricate a RuntimeStub internally. - StubRoutines::_throw_AbstractMethodError_entry = generate_throw_exception("AbstractMethodError throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_AbstractMethodError)); - StubRoutines::_throw_IncompatibleClassChangeError_entry= generate_throw_exception("IncompatibleClassChangeError throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_IncompatibleClassChangeError)); - StubRoutines::_throw_NullPointerException_at_call_entry= generate_throw_exception("NullPointerException at call throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_NullPointerException_at_call)); - // support for verify_oop (must happen after universe_init) StubRoutines::_verify_oop_subroutine_entry = generate_verify_oop(); diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp index a7404b298f673..2bc4a0a9cba94 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp @@ -45,9 +45,6 @@ #if INCLUDE_JVMCI #include "jvmci/jvmci_globals.hpp" #endif -#if INCLUDE_JFR -#include "jfr/support/jfrIntrinsics.hpp" -#endif // For a more detailed description of the stub routine structure // see the comment in stubRoutines.hpp @@ -3702,7 +3699,7 @@ address StubGenerator::generate_cont_thaw(const char* label, Continuation::thaw_ Label L_thaw_success; __ testptr(rbx, rbx); __ jccb(Assembler::notZero, L_thaw_success); - __ jump(RuntimeAddress(StubRoutines::throw_StackOverflowError_entry())); + __ jump(RuntimeAddress(SharedRuntime::throw_StackOverflowError_entry())); __ bind(L_thaw_success); // Make room for the thawed frames and align the stack. @@ -3778,198 +3775,6 @@ address StubGenerator::generate_cont_returnBarrier_exception() { return generate_cont_thaw("Cont thaw return barrier exception", Continuation::thaw_return_barrier_exception); } -#if INCLUDE_JFR - -// For c2: c_rarg0 is junk, call to runtime to write a checkpoint. -// It returns a jobject handle to the event writer. -// The handle is dereferenced and the return value is the event writer oop. -RuntimeStub* StubGenerator::generate_jfr_write_checkpoint() { - enum layout { - rbp_off, - rbpH_off, - return_off, - return_off2, - framesize // inclusive of return address - }; - - CodeBuffer code("jfr_write_checkpoint", 1024, 64); - MacroAssembler* _masm = new MacroAssembler(&code); - address start = __ pc(); - - __ enter(); - address the_pc = __ pc(); - - int frame_complete = the_pc - start; - - __ set_last_Java_frame(rsp, rbp, the_pc, rscratch1); - __ movptr(c_rarg0, r15_thread); - __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::write_checkpoint), 1); - __ reset_last_Java_frame(true); - - // rax is jobject handle result, unpack and process it through a barrier. - __ resolve_global_jobject(rax, r15_thread, c_rarg0); - - __ leave(); - __ ret(0); - - OopMapSet* oop_maps = new OopMapSet(); - OopMap* map = new OopMap(framesize, 1); - oop_maps->add_gc_map(frame_complete, map); - - RuntimeStub* stub = - RuntimeStub::new_runtime_stub(code.name(), - &code, - frame_complete, - (framesize >> (LogBytesPerWord - LogBytesPerInt)), - oop_maps, - false); - return stub; -} - -// For c2: call to return a leased buffer. -RuntimeStub* StubGenerator::generate_jfr_return_lease() { - enum layout { - rbp_off, - rbpH_off, - return_off, - return_off2, - framesize // inclusive of return address - }; - - CodeBuffer code("jfr_return_lease", 1024, 64); - MacroAssembler* _masm = new MacroAssembler(&code); - address start = __ pc(); - - __ enter(); - address the_pc = __ pc(); - - int frame_complete = the_pc - start; - - __ set_last_Java_frame(rsp, rbp, the_pc, rscratch2); - __ movptr(c_rarg0, r15_thread); - __ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::return_lease), 1); - __ reset_last_Java_frame(true); - - __ leave(); - __ ret(0); - - OopMapSet* oop_maps = new OopMapSet(); - OopMap* map = new OopMap(framesize, 1); - oop_maps->add_gc_map(frame_complete, map); - - RuntimeStub* stub = - RuntimeStub::new_runtime_stub(code.name(), - &code, - frame_complete, - (framesize >> (LogBytesPerWord - LogBytesPerInt)), - oop_maps, - false); - return stub; -} - -#endif // INCLUDE_JFR - -// Continuation point for throwing of implicit exceptions that are -// not handled in the current activation. Fabricates an exception -// oop and initiates normal exception dispatching in this -// frame. Since we need to preserve callee-saved values (currently -// only for C2, but done for C1 as well) we need a callee-saved oop -// map and therefore have to make these stubs into RuntimeStubs -// rather than BufferBlobs. If the compiler needs all registers to -// be preserved between the fault point and the exception handler -// then it must assume responsibility for that in -// AbstractCompiler::continuation_for_implicit_null_exception or -// continuation_for_implicit_division_by_zero_exception. All other -// implicit exceptions (e.g., NullPointerException or -// AbstractMethodError on entry) are either at call sites or -// otherwise assume that stack unwinding will be initiated, so -// caller saved registers were assumed volatile in the compiler. -address StubGenerator::generate_throw_exception(const char* name, - address runtime_entry, - Register arg1, - Register arg2) { - // Information about frame layout at time of blocking runtime call. - // Note that we only have to preserve callee-saved registers since - // the compilers are responsible for supplying a continuation point - // if they expect all registers to be preserved. - enum layout { - rbp_off = frame::arg_reg_save_area_bytes/BytesPerInt, - rbp_off2, - return_off, - return_off2, - framesize // inclusive of return address - }; - - int insts_size = 512; - int locs_size = 64; - - CodeBuffer code(name, insts_size, locs_size); - OopMapSet* oop_maps = new OopMapSet(); - MacroAssembler* _masm = new MacroAssembler(&code); - - address start = __ pc(); - - // This is an inlined and slightly modified version of call_VM - // which has the ability to fetch the return PC out of - // thread-local storage and also sets up last_Java_sp slightly - // differently than the real call_VM - - __ enter(); // required for proper stackwalking of RuntimeStub frame - - assert(is_even(framesize/2), "sp not 16-byte aligned"); - - // return address and rbp are already in place - __ subptr(rsp, (framesize-4) << LogBytesPerInt); // prolog - - int frame_complete = __ pc() - start; - - // Set up last_Java_sp and last_Java_fp - address the_pc = __ pc(); - __ set_last_Java_frame(rsp, rbp, the_pc, rscratch1); - __ andptr(rsp, -(StackAlignmentInBytes)); // Align stack - - // Call runtime - if (arg1 != noreg) { - assert(arg2 != c_rarg1, "clobbered"); - __ movptr(c_rarg1, arg1); - } - if (arg2 != noreg) { - __ movptr(c_rarg2, arg2); - } - __ movptr(c_rarg0, r15_thread); - BLOCK_COMMENT("call runtime_entry"); - __ call(RuntimeAddress(runtime_entry)); - - // Generate oop map - OopMap* map = new OopMap(framesize, 0); - - oop_maps->add_gc_map(the_pc - start, map); - - __ reset_last_Java_frame(true); - - __ leave(); // required for proper stackwalking of RuntimeStub frame - - // check for pending exceptions -#ifdef ASSERT - Label L; - __ cmpptr(Address(r15_thread, Thread::pending_exception_offset()), NULL_WORD); - __ jcc(Assembler::notEqual, L); - __ should_not_reach_here(); - __ bind(L); -#endif // ASSERT - __ jump(RuntimeAddress(StubRoutines::forward_exception_entry())); - - - // codeBlob framesize is in words (not VMRegImpl::slot_size) - RuntimeStub* stub = - RuntimeStub::new_runtime_stub(name, - &code, - frame_complete, - (framesize >> (LogBytesPerWord - LogBytesPerInt)), - oop_maps, false); - return stub->entry_point(); -} - // exception handler for upcall stubs address StubGenerator::generate_upcall_stub_exception_handler() { StubCodeMark mark(this, "StubRoutines", "upcall stub exception handler"); @@ -4087,17 +3892,6 @@ void StubGenerator::generate_initial_stubs() { StubRoutines::x86::_double_sign_mask = generate_fp_mask("double_sign_mask", 0x7FFFFFFFFFFFFFFF); StubRoutines::x86::_double_sign_flip = generate_fp_mask("double_sign_flip", 0x8000000000000000); - // Build this early so it's available for the interpreter. - StubRoutines::_throw_StackOverflowError_entry = - generate_throw_exception("StackOverflowError throw_exception", - CAST_FROM_FN_PTR(address, - SharedRuntime:: - throw_StackOverflowError)); - StubRoutines::_throw_delayed_StackOverflowError_entry = - generate_throw_exception("delayed StackOverflowError throw_exception", - CAST_FROM_FN_PTR(address, - SharedRuntime:: - throw_delayed_StackOverflowError)); if (UseCRC32Intrinsics) { // set table address before stub generation which use it StubRoutines::_crc_table_adr = (address)StubRoutines::x86::_crc_table; @@ -4131,43 +3925,11 @@ void StubGenerator::generate_continuation_stubs() { StubRoutines::_cont_thaw = generate_cont_thaw(); StubRoutines::_cont_returnBarrier = generate_cont_returnBarrier(); StubRoutines::_cont_returnBarrierExc = generate_cont_returnBarrier_exception(); - - JFR_ONLY(generate_jfr_stubs();) } -#if INCLUDE_JFR -void StubGenerator::generate_jfr_stubs() { - StubRoutines::_jfr_write_checkpoint_stub = generate_jfr_write_checkpoint(); - StubRoutines::_jfr_write_checkpoint = StubRoutines::_jfr_write_checkpoint_stub->entry_point(); - StubRoutines::_jfr_return_lease_stub = generate_jfr_return_lease(); - StubRoutines::_jfr_return_lease = StubRoutines::_jfr_return_lease_stub->entry_point(); -} -#endif - void StubGenerator::generate_final_stubs() { // Generates the rest of stubs and initializes the entry points - // These entry points require SharedInfo::stack0 to be set up in - // non-core builds and need to be relocatable, so they each - // fabricate a RuntimeStub internally. - StubRoutines::_throw_AbstractMethodError_entry = - generate_throw_exception("AbstractMethodError throw_exception", - CAST_FROM_FN_PTR(address, - SharedRuntime:: - throw_AbstractMethodError)); - - StubRoutines::_throw_IncompatibleClassChangeError_entry = - generate_throw_exception("IncompatibleClassChangeError throw_exception", - CAST_FROM_FN_PTR(address, - SharedRuntime:: - throw_IncompatibleClassChangeError)); - - StubRoutines::_throw_NullPointerException_at_call_entry = - generate_throw_exception("NullPointerException at call throw_exception", - CAST_FROM_FN_PTR(address, - SharedRuntime:: - throw_NullPointerException_at_call)); - // support for verify_oop (must happen after universe_init) if (VerifyOops) { StubRoutines::_verify_oop_subroutine_entry = generate_verify_oop(); diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp b/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp index 374679750a489..d65c681585d6d 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp @@ -586,16 +586,6 @@ class StubGenerator: public StubCodeGenerator { address generate_cont_returnBarrier(); address generate_cont_returnBarrier_exception(); -#if INCLUDE_JFR - void generate_jfr_stubs(); - // For c2: c_rarg0 is junk, call to runtime to write a checkpoint. - // It returns a jobject handle to the event writer. - // The handle is dereferenced and the return value is the event writer oop. - RuntimeStub* generate_jfr_write_checkpoint(); - // For c2: call to runtime to return a buffer lease. - RuntimeStub* generate_jfr_return_lease(); -#endif // INCLUDE_JFR - // Continuation point for throwing of implicit exceptions that are // not handled in the current activation. Fabricates an exception // oop and initiates normal exception dispatching in this diff --git a/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp b/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp index 3b32d577d4470..76ad498be0e78 100644 --- a/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp +++ b/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp @@ -545,8 +545,8 @@ void TemplateInterpreterGenerator::generate_stack_overflow_check(void) { // Note: the restored frame is not necessarily interpreted. // Use the shared runtime version of the StackOverflowError. - assert(StubRoutines::throw_StackOverflowError_entry() != nullptr, "stub not yet generated"); - __ jump(RuntimeAddress(StubRoutines::throw_StackOverflowError_entry())); + assert(SharedRuntime::throw_StackOverflowError_entry() != nullptr, "stub not yet generated"); + __ jump(RuntimeAddress(SharedRuntime::throw_StackOverflowError_entry())); // all done with frame size check __ bind(after_frame_check_pop); NOT_LP64(__ pop(rsi)); diff --git a/src/hotspot/cpu/zero/sharedRuntime_zero.cpp b/src/hotspot/cpu/zero/sharedRuntime_zero.cpp index 986cee685123b..454f8e5f6323b 100644 --- a/src/hotspot/cpu/zero/sharedRuntime_zero.cpp +++ b/src/hotspot/cpu/zero/sharedRuntime_zero.cpp @@ -89,7 +89,7 @@ JRT_LEAF(void, zero_stub()) ShouldNotCallThis(); JRT_END -static RuntimeStub* generate_empty_runtime_stub(const char* name) { +static RuntimeStub* generate_empty_runtime_stub() { return CAST_FROM_FN_PTR(RuntimeStub*,zero_stub); } @@ -101,7 +101,6 @@ static DeoptimizationBlob* generate_empty_deopt_blob() { return CAST_FROM_FN_PTR(DeoptimizationBlob*,zero_stub); } - void SharedRuntime::generate_deopt_blob() { _deopt_blob = generate_empty_deopt_blob(); } @@ -111,7 +110,11 @@ SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_t } RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const char* name) { - return generate_empty_runtime_stub("resolve_blob"); + return generate_empty_runtime_stub(); +} + +RuntimeStub* SharedRuntime::generate_throw_exception(const char* name, address runtime_entry) { + return generate_empty_runtime_stub(); } int SharedRuntime::c_calling_convention(const BasicType *sig_bt, @@ -127,3 +130,15 @@ int SharedRuntime::vector_calling_convention(VMRegPair *regs, ShouldNotCallThis(); return 0; } + +#if INCLUDE_JFR +RuntimeStub* SharedRuntime::generate_jfr_write_checkpoint() { + return nullptr; +} + +RuntimeStub* SharedRuntime::generate_jfr_return_lease() { + return nullptr; +} + +#endif // INCLUDE_JFR + diff --git a/src/hotspot/cpu/zero/stubGenerator_zero.cpp b/src/hotspot/cpu/zero/stubGenerator_zero.cpp index 5c7772021ea35..b6905791e9884 100644 --- a/src/hotspot/cpu/zero/stubGenerator_zero.cpp +++ b/src/hotspot/cpu/zero/stubGenerator_zero.cpp @@ -203,22 +203,6 @@ class StubGenerator: public StubCodeGenerator { void generate_final_stubs() { // Generates all stubs and initializes the entry points - // These entry points require SharedInfo::stack0 to be set up in - // non-core builds and need to be relocatable, so they each - // fabricate a RuntimeStub internally. - StubRoutines::_throw_AbstractMethodError_entry = - ShouldNotCallThisStub(); - - StubRoutines::_throw_NullPointerException_at_call_entry = - ShouldNotCallThisStub(); - - StubRoutines::_throw_StackOverflowError_entry = - ShouldNotCallThisStub(); - - // support for verify_oop (must happen after universe_init) - StubRoutines::_verify_oop_subroutine_entry = - ShouldNotCallThisStub(); - // arraycopy stubs used by compilers generate_arraycopy_stubs(); diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.hpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.hpp index 8fdb96a303825..fa4b1c75c0573 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.hpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.hpp @@ -50,6 +50,7 @@ class CompilerToVM { static address SharedRuntime_deopt_blob_unpack_with_exception_in_tls; static address SharedRuntime_deopt_blob_uncommon_trap; static address SharedRuntime_polling_page_return_handler; + static address SharedRuntime_throw_delayed_StackOverflowError_entry; static address nmethod_entry_barrier; static int thread_disarmed_guard_value_offset; diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp index 2116133e56e97..26c88abec0f18 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp @@ -68,6 +68,7 @@ address CompilerToVM::Data::SharedRuntime_deopt_blob_unpack; address CompilerToVM::Data::SharedRuntime_deopt_blob_unpack_with_exception_in_tls; address CompilerToVM::Data::SharedRuntime_deopt_blob_uncommon_trap; address CompilerToVM::Data::SharedRuntime_polling_page_return_handler; +address CompilerToVM::Data::SharedRuntime_throw_delayed_StackOverflowError_entry; address CompilerToVM::Data::nmethod_entry_barrier; int CompilerToVM::Data::thread_disarmed_guard_value_offset; @@ -158,6 +159,7 @@ void CompilerToVM::Data::initialize(JVMCI_TRAPS) { SharedRuntime_deopt_blob_unpack_with_exception_in_tls = SharedRuntime::deopt_blob()->unpack_with_exception_in_tls(); SharedRuntime_deopt_blob_uncommon_trap = SharedRuntime::deopt_blob()->uncommon_trap(); SharedRuntime_polling_page_return_handler = SharedRuntime::polling_page_return_handler_blob()->entry_point(); + SharedRuntime_throw_delayed_StackOverflowError_entry = SharedRuntime::throw_delayed_StackOverflowError_entry(); BarrierSetNMethod* bs_nm = BarrierSet::barrier_set()->barrier_set_nmethod(); if (bs_nm != nullptr) { diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp index 5870e49ac94b5..688691fb9765c 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -68,6 +68,8 @@ static_field(CompilerToVM::Data, SharedRuntime_deopt_blob_uncommon_trap, address) \ static_field(CompilerToVM::Data, SharedRuntime_polling_page_return_handler, \ address) \ + static_field(CompilerToVM::Data, SharedRuntime_throw_delayed_StackOverflowError_entry, \ + address) \ \ static_field(CompilerToVM::Data, nmethod_entry_barrier, address) \ static_field(CompilerToVM::Data, thread_disarmed_guard_value_offset, int) \ @@ -328,8 +330,6 @@ \ static_field(StubRoutines, _verify_oop_count, jint) \ \ - static_field(StubRoutines, _throw_delayed_StackOverflowError_entry, address) \ - \ static_field(StubRoutines, _jbyte_arraycopy, address) \ static_field(StubRoutines, _jshort_arraycopy, address) \ static_field(StubRoutines, _jint_arraycopy, address) \ diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index 542514b1f7e24..eced285f8cbdf 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -3167,7 +3167,7 @@ bool LibraryCallKit::inline_native_jvm_commit() { // Make a runtime call, which can safepoint, to return the leased buffer. This updates both the JfrThreadLocal and the Java event writer oop. Node* call_return_lease = make_runtime_call(RC_NO_LEAF, OptoRuntime::void_void_Type(), - StubRoutines::jfr_return_lease(), + SharedRuntime::jfr_return_lease(), "return_lease", TypePtr::BOTTOM); Node* call_return_lease_control = _gvn.transform(new ProjNode(call_return_lease, TypeFunc::Control)); @@ -3366,7 +3366,7 @@ bool LibraryCallKit::inline_native_getEventWriter() { // The call also updates the native thread local thread id and the vthread with the current epoch. Node* call_write_checkpoint = make_runtime_call(RC_NO_LEAF, OptoRuntime::jfr_write_checkpoint_Type(), - StubRoutines::jfr_write_checkpoint(), + SharedRuntime::jfr_write_checkpoint(), "write_checkpoint", TypePtr::BOTTOM); Node* call_write_checkpoint_control = _gvn.transform(new ProjNode(call_write_checkpoint, TypeFunc::Control)); diff --git a/src/hotspot/share/runtime/init.cpp b/src/hotspot/share/runtime/init.cpp index 368f4e62c7692..7f23aca09617d 100644 --- a/src/hotspot/share/runtime/init.cpp +++ b/src/hotspot/share/runtime/init.cpp @@ -126,7 +126,10 @@ jint init_globals() { compilationPolicy_init(); codeCache_init(); VM_Version_init(); // depends on codeCache_init for emitting code + // stub routines in initial blob are referenced by later generated code initial_stubs_init(); + // stack overflow exception blob is referenced by the interpreter + SharedRuntime::generate_initial_stubs(); jint status = universe_init(); // dependent on codeCache_init and // initial_stubs_init and metaspace_init. if (status != JNI_OK) @@ -144,6 +147,9 @@ jint init_globals() { gc_barrier_stubs_init(); // depends on universe_init, must be before interpreter_init continuations_init(); // must precede continuation stub generation continuation_stubs_init(); // depends on continuations_init +#if INCLUDE_JFR + SharedRuntime::generate_jfr_stubs(); +#endif interpreter_init_stub(); // before methods get loaded accessFlags_init(); InterfaceSupport_init(); diff --git a/src/hotspot/share/runtime/sharedRuntime.cpp b/src/hotspot/share/runtime/sharedRuntime.cpp index 0587032ec5c67..f98d031a2cd74 100644 --- a/src/hotspot/share/runtime/sharedRuntime.cpp +++ b/src/hotspot/share/runtime/sharedRuntime.cpp @@ -71,6 +71,7 @@ #include "runtime/stackWatermarkSet.hpp" #include "runtime/stubRoutines.hpp" #include "runtime/synchronizer.inline.hpp" +#include "runtime/timerTrace.hpp" #include "runtime/vframe.inline.hpp" #include "runtime/vframeArray.hpp" #include "runtime/vm_version.hpp" @@ -88,23 +89,42 @@ #include "jfr/jfr.hpp" #endif -// Shared stub locations +// Shared runtime stub routines reside in their own unique blob with a +// single entry point + RuntimeStub* SharedRuntime::_wrong_method_blob; RuntimeStub* SharedRuntime::_wrong_method_abstract_blob; RuntimeStub* SharedRuntime::_ic_miss_blob; RuntimeStub* SharedRuntime::_resolve_opt_virtual_call_blob; RuntimeStub* SharedRuntime::_resolve_virtual_call_blob; RuntimeStub* SharedRuntime::_resolve_static_call_blob; -address SharedRuntime::_resolve_static_call_entry; DeoptimizationBlob* SharedRuntime::_deopt_blob; SafepointBlob* SharedRuntime::_polling_page_vectors_safepoint_handler_blob; SafepointBlob* SharedRuntime::_polling_page_safepoint_handler_blob; SafepointBlob* SharedRuntime::_polling_page_return_handler_blob; +RuntimeStub* SharedRuntime::_throw_AbstractMethodError_blob; +RuntimeStub* SharedRuntime::_throw_IncompatibleClassChangeError_blob; +RuntimeStub* SharedRuntime::_throw_NullPointerException_at_call_blob; +RuntimeStub* SharedRuntime::_throw_StackOverflowError_blob; +RuntimeStub* SharedRuntime::_throw_delayed_StackOverflowError_blob; + +#if INCLUDE_JFR +RuntimeStub* SharedRuntime::_jfr_write_checkpoint_blob = nullptr; +RuntimeStub* SharedRuntime::_jfr_return_lease_blob = nullptr; +#endif + nmethod* SharedRuntime::_cont_doYield_stub; //----------------------------generate_stubs----------------------------------- +void SharedRuntime::generate_initial_stubs() { + // Build this early so it's available for the interpreter. + _throw_StackOverflowError_blob = + generate_throw_exception("StackOverflowError throw_exception", + CAST_FROM_FN_PTR(address, SharedRuntime::throw_StackOverflowError)); +} + void SharedRuntime::generate_stubs() { _wrong_method_blob = generate_resolve_blob(CAST_FROM_FN_PTR(address, SharedRuntime::handle_wrong_method), "wrong_method_stub"); _wrong_method_abstract_blob = generate_resolve_blob(CAST_FROM_FN_PTR(address, SharedRuntime::handle_wrong_method_abstract), "wrong_method_abstract_stub"); @@ -112,7 +132,22 @@ void SharedRuntime::generate_stubs() { _resolve_opt_virtual_call_blob = generate_resolve_blob(CAST_FROM_FN_PTR(address, SharedRuntime::resolve_opt_virtual_call_C), "resolve_opt_virtual_call"); _resolve_virtual_call_blob = generate_resolve_blob(CAST_FROM_FN_PTR(address, SharedRuntime::resolve_virtual_call_C), "resolve_virtual_call"); _resolve_static_call_blob = generate_resolve_blob(CAST_FROM_FN_PTR(address, SharedRuntime::resolve_static_call_C), "resolve_static_call"); - _resolve_static_call_entry = _resolve_static_call_blob->entry_point(); + + _throw_delayed_StackOverflowError_blob = + generate_throw_exception("delayed StackOverflowError throw_exception", + CAST_FROM_FN_PTR(address, SharedRuntime::throw_delayed_StackOverflowError)); + + _throw_AbstractMethodError_blob = + generate_throw_exception("AbstractMethodError throw_exception", + CAST_FROM_FN_PTR(address, SharedRuntime::throw_AbstractMethodError)); + + _throw_IncompatibleClassChangeError_blob = + generate_throw_exception("IncompatibleClassChangeError throw_exception", + CAST_FROM_FN_PTR(address, SharedRuntime::throw_IncompatibleClassChangeError)); + + _throw_NullPointerException_at_call_blob = + generate_throw_exception("NullPointerException at call throw_exception", + CAST_FROM_FN_PTR(address, SharedRuntime::throw_NullPointerException_at_call)); AdapterHandlerLibrary::initialize(); @@ -129,6 +164,19 @@ void SharedRuntime::generate_stubs() { generate_deopt_blob(); } +#if INCLUDE_JFR +//------------------------------generate jfr runtime stubs ------ +void SharedRuntime::generate_jfr_stubs() { + ResourceMark rm; + const char* timer_msg = "SharedRuntime generate_jfr_stubs"; + TraceTime timer(timer_msg, TRACETIME_LOG(Info, startuptime)); + + _jfr_write_checkpoint_blob = generate_jfr_write_checkpoint(); + _jfr_return_lease_blob = generate_jfr_return_lease(); +} + +#endif // INCLUDE_JFR + #include // Implementation of SharedRuntime @@ -867,7 +915,7 @@ address SharedRuntime::continuation_for_implicit_exception(JavaThread* current, // method stack banging. assert(current->deopt_mark() == nullptr, "no stack overflow from deopt blob/uncommon trap"); Events::log_exception(current, "StackOverflowError at " INTPTR_FORMAT, p2i(pc)); - return StubRoutines::throw_StackOverflowError_entry(); + return SharedRuntime::throw_StackOverflowError_entry(); } case IMPLICIT_NULL: { @@ -893,7 +941,7 @@ address SharedRuntime::continuation_for_implicit_exception(JavaThread* current, // Assert that the signal comes from the expected location in stub code. assert(vt_stub->is_null_pointer_exception(pc), "obtained signal from unexpected location in stub code"); - return StubRoutines::throw_NullPointerException_at_call_entry(); + return SharedRuntime::throw_NullPointerException_at_call_entry(); } } else { CodeBlob* cb = CodeCache::find_blob(pc); @@ -914,7 +962,7 @@ address SharedRuntime::continuation_for_implicit_exception(JavaThread* current, } Events::log_exception(current, "NullPointerException in code blob at " INTPTR_FORMAT, p2i(pc)); // There is no handler here, so we will simply unwind. - return StubRoutines::throw_NullPointerException_at_call_entry(); + return SharedRuntime::throw_NullPointerException_at_call_entry(); } // Otherwise, it's a compiled method. Consult its exception handlers. @@ -925,13 +973,13 @@ address SharedRuntime::continuation_for_implicit_exception(JavaThread* current, // is not set up yet) => use return address pushed by // caller => don't push another return address Events::log_exception(current, "NullPointerException in IC check " INTPTR_FORMAT, p2i(pc)); - return StubRoutines::throw_NullPointerException_at_call_entry(); + return SharedRuntime::throw_NullPointerException_at_call_entry(); } if (nm->method()->is_method_handle_intrinsic()) { // exception happened inside MH dispatch code, similar to a vtable stub Events::log_exception(current, "NullPointerException in MH adapter " INTPTR_FORMAT, p2i(pc)); - return StubRoutines::throw_NullPointerException_at_call_entry(); + return SharedRuntime::throw_NullPointerException_at_call_entry(); } #ifndef PRODUCT @@ -1467,7 +1515,7 @@ JRT_BLOCK_ENTRY(address, SharedRuntime::handle_wrong_method_abstract(JavaThread* assert(callerFrame.is_compiled_frame(), "must be"); // Install exception and return forward entry. - address res = StubRoutines::throw_AbstractMethodError_entry(); + address res = SharedRuntime::throw_AbstractMethodError_entry(); JRT_BLOCK methodHandle callee(current, invoke.static_target(current)); if (!callee.is_null()) { @@ -2387,7 +2435,7 @@ void AdapterHandlerLibrary::initialize() { // AbstractMethodError for invalid invocations. address wrong_method_abstract = SharedRuntime::get_handle_wrong_method_abstract_stub(); _abstract_method_handler = AdapterHandlerLibrary::new_entry(new AdapterFingerPrint(0, nullptr), - StubRoutines::throw_AbstractMethodError_entry(), + SharedRuntime::throw_AbstractMethodError_entry(), wrong_method_abstract, wrong_method_abstract); _buffer = BufferBlob::create("adapters", AdapterHandlerLibrary_size); diff --git a/src/hotspot/share/runtime/sharedRuntime.hpp b/src/hotspot/share/runtime/sharedRuntime.hpp index 9eec8e079ec34..00a72f5db1e08 100644 --- a/src/hotspot/share/runtime/sharedRuntime.hpp +++ b/src/hotspot/share/runtime/sharedRuntime.hpp @@ -54,7 +54,6 @@ class SharedRuntime: AllStatic { static RuntimeStub* _resolve_opt_virtual_call_blob; static RuntimeStub* _resolve_virtual_call_blob; static RuntimeStub* _resolve_static_call_blob; - static address _resolve_static_call_entry; static DeoptimizationBlob* _deopt_blob; @@ -64,6 +63,17 @@ class SharedRuntime: AllStatic { static nmethod* _cont_doYield_stub; + static RuntimeStub* _throw_AbstractMethodError_blob; + static RuntimeStub* _throw_IncompatibleClassChangeError_blob; + static RuntimeStub* _throw_NullPointerException_at_call_blob; + static RuntimeStub* _throw_StackOverflowError_blob; + static RuntimeStub* _throw_delayed_StackOverflowError_blob; + +#if INCLUDE_JFR + static RuntimeStub* _jfr_write_checkpoint_blob; + static RuntimeStub* _jfr_return_lease_blob; +#endif + #ifndef PRODUCT // Counters static int64_t _nof_megamorphic_calls; // total # of megamorphic calls (through vtable) @@ -73,9 +83,19 @@ class SharedRuntime: AllStatic { enum { POLL_AT_RETURN, POLL_AT_LOOP, POLL_AT_VECTOR_LOOP }; static SafepointBlob* generate_handler_blob(address call_ptr, int poll_type); static RuntimeStub* generate_resolve_blob(address destination, const char* name); - + static RuntimeStub* generate_throw_exception(const char* name, address runtime_entry); public: + static void generate_initial_stubs(void); static void generate_stubs(void); +#if INCLUDE_JFR + static void generate_jfr_stubs(void); + // For c2: c_rarg0 is junk, call to runtime to write a checkpoint. + // It returns a jobject handle to the event writer. + // The handle is dereferenced and the return value is the event writer oop. + static RuntimeStub* generate_jfr_write_checkpoint(); + // For c2: call to runtime to return a buffer lease. + static RuntimeStub* generate_jfr_return_lease(); +#endif // max bytes for each dtrace string parameter enum { max_dtrace_string_size = 256 }; @@ -241,6 +261,18 @@ class SharedRuntime: AllStatic { return _cont_doYield_stub; } + // Implicit exceptions + static address throw_AbstractMethodError_entry() { return _throw_AbstractMethodError_blob->entry_point(); } + static address throw_IncompatibleClassChangeError_entry() { return _throw_IncompatibleClassChangeError_blob->entry_point(); } + static address throw_NullPointerException_at_call_entry() { return _throw_NullPointerException_at_call_blob->entry_point(); } + static address throw_StackOverflowError_entry() { return _throw_StackOverflowError_blob->entry_point(); } + static address throw_delayed_StackOverflowError_entry() { return _throw_delayed_StackOverflowError_blob->entry_point(); } + +#if INCLUDE_JFR + static address jfr_write_checkpoint() { return _jfr_write_checkpoint_blob->entry_point(); } + static address jfr_return_lease() { return _jfr_return_lease_blob->entry_point(); } +#endif + // Counters #ifndef PRODUCT static address nof_megamorphic_calls_addr() { return (address)&_nof_megamorphic_calls; } diff --git a/src/hotspot/share/runtime/stubRoutines.cpp b/src/hotspot/share/runtime/stubRoutines.cpp index 773f8031e154c..c13f64fca4bed 100644 --- a/src/hotspot/share/runtime/stubRoutines.cpp +++ b/src/hotspot/share/runtime/stubRoutines.cpp @@ -61,11 +61,6 @@ address StubRoutines::_call_stub_entry = nullptr; address StubRoutines::_catch_exception_entry = nullptr; address StubRoutines::_forward_exception_entry = nullptr; -address StubRoutines::_throw_AbstractMethodError_entry = nullptr; -address StubRoutines::_throw_IncompatibleClassChangeError_entry = nullptr; -address StubRoutines::_throw_NullPointerException_at_call_entry = nullptr; -address StubRoutines::_throw_StackOverflowError_entry = nullptr; -address StubRoutines::_throw_delayed_StackOverflowError_entry = nullptr; jint StubRoutines::_verify_oop_count = 0; address StubRoutines::_verify_oop_subroutine_entry = nullptr; address StubRoutines::_atomic_xchg_entry = nullptr; @@ -191,11 +186,6 @@ address StubRoutines::_cont_thaw = nullptr; address StubRoutines::_cont_returnBarrier = nullptr; address StubRoutines::_cont_returnBarrierExc = nullptr; -JFR_ONLY(RuntimeStub* StubRoutines::_jfr_write_checkpoint_stub = nullptr;) -JFR_ONLY(address StubRoutines::_jfr_write_checkpoint = nullptr;) -JFR_ONLY(RuntimeStub* StubRoutines::_jfr_return_lease_stub = nullptr;) -JFR_ONLY(address StubRoutines::_jfr_return_lease = nullptr;) - address StubRoutines::_upcall_stub_exception_handler = nullptr; address StubRoutines::_lookup_secondary_supers_table_slow_path_stub = nullptr; diff --git a/src/hotspot/share/runtime/stubRoutines.hpp b/src/hotspot/share/runtime/stubRoutines.hpp index 762a6edf59075..206a5ec2e992c 100644 --- a/src/hotspot/share/runtime/stubRoutines.hpp +++ b/src/hotspot/share/runtime/stubRoutines.hpp @@ -36,7 +36,34 @@ // StubRoutines provides entry points to assembly routines used by // compiled code and the run-time system. Platform-specific entry -// points are defined in the platform-specific inner class. +// points are defined in the platform-specific inner class. Most +// routines have a single (main) entry point. However, a few routines +// do provide alternative entry points. +// +// Stub routines whose entries are advertised via class StubRoutines +// are generated in batches at well-defined stages during JVM init: +// initial stubs, continuation stubs, compiler stubs, final stubs. +// Each batch is embedded in a single, associated blob (an instance of +// BufferBlob) i.e. the blob to entry relationship is 1-m. +// +// Note that this constrasts with the much smaller number of stub +// routines generated via classes SharedRuntime, c1_Runtime1 and +// OptoRuntime. The latter routines are also generated at well-defined +// points during JVM init. However, each stub routine has its own +// unique blob (various subclasses of RuntimeBlob) i.e. the blob to +// entry relationship is 1-1. The difference arises because +// SharedRuntime routines may need to be relocatable or advertise +// properties such as a frame size via their blob. +// +// Staging of stub routine generation is needed in order to manage +// init dependencies between 1) stubs and other stubs or 2) stubs and +// other runtime components. For example, some exception throw stubs +// need to be generated before compiler stubs (such as the +// deoptimization stub) so that the latter can invoke the thrwo rotine +// in bail-out code. Likewise, stubs that access objects (such as the +// object array copy stub) need to be created after initialization of +// some GC constants and generation of the GC barrier stubs they might +// need to invoke. // // Class scheme: // @@ -49,8 +76,7 @@ // | | // | | // stubRoutines.cpp stubRoutines_.cpp -// stubRoutines_.cpp stubGenerator_.cpp -// stubRoutines_.cpp +// stubGenerator_.cpp // // Note 1: The important thing is a clean decoupling between stub // entry points (interfacing to the whole vm; i.e., 1-to-n @@ -75,6 +101,8 @@ // 3. add a public accessor function to the instance variable // 4. implement the corresponding generator function in the platform-dependent // stubGenerator_.cpp file and call the function in generate_all() of that file +// 5. ensure the entry is generated in the right blob to satisfy initialization +// dependencies between it and other stubs or runtime components. class UnsafeMemoryAccess : public CHeapObj { private: @@ -137,11 +165,6 @@ class StubRoutines: AllStatic { static address _call_stub_entry; static address _forward_exception_entry; static address _catch_exception_entry; - static address _throw_AbstractMethodError_entry; - static address _throw_IncompatibleClassChangeError_entry; - static address _throw_NullPointerException_at_call_entry; - static address _throw_StackOverflowError_entry; - static address _throw_delayed_StackOverflowError_entry; static address _atomic_xchg_entry; static address _atomic_cmpxchg_entry; @@ -269,11 +292,6 @@ class StubRoutines: AllStatic { static address _cont_returnBarrier; static address _cont_returnBarrierExc; - JFR_ONLY(static RuntimeStub* _jfr_write_checkpoint_stub;) - JFR_ONLY(static address _jfr_write_checkpoint;) - JFR_ONLY(static RuntimeStub* _jfr_return_lease_stub;) - JFR_ONLY(static address _jfr_return_lease;) - // Vector Math Routines static address _vector_f_math[VectorSupport::NUM_VEC_SIZES][VectorSupport::NUM_SVML_OP]; static address _vector_d_math[VectorSupport::NUM_VEC_SIZES][VectorSupport::NUM_SVML_OP]; @@ -329,12 +347,6 @@ class StubRoutines: AllStatic { // Exceptions static address forward_exception_entry() { return _forward_exception_entry; } - // Implicit exceptions - static address throw_AbstractMethodError_entry() { return _throw_AbstractMethodError_entry; } - static address throw_IncompatibleClassChangeError_entry(){ return _throw_IncompatibleClassChangeError_entry; } - static address throw_NullPointerException_at_call_entry(){ return _throw_NullPointerException_at_call_entry; } - static address throw_StackOverflowError_entry() { return _throw_StackOverflowError_entry; } - static address throw_delayed_StackOverflowError_entry() { return _throw_delayed_StackOverflowError_entry; } static address atomic_xchg_entry() { return _atomic_xchg_entry; } static address atomic_cmpxchg_entry() { return _atomic_cmpxchg_entry; } @@ -487,9 +499,6 @@ class StubRoutines: AllStatic { static address cont_returnBarrier() { return _cont_returnBarrier; } static address cont_returnBarrierExc(){return _cont_returnBarrierExc; } - JFR_ONLY(static address jfr_write_checkpoint() { return _jfr_write_checkpoint; }) - JFR_ONLY(static address jfr_return_lease() { return _jfr_return_lease; }) - static address upcall_stub_exception_handler() { assert(_upcall_stub_exception_handler != nullptr, "not implemented"); return _upcall_stub_exception_handler; From 6d430f24df9d599fe1e12c6b65117c02773ae5d8 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Mon, 19 Aug 2024 09:08:54 +0000 Subject: [PATCH 338/353] 8338314: JFR: Split JFRCheckpoint VM operation Reviewed-by: mgronlun, egahlin --- .../recorder/service/jfrRecorderService.cpp | 28 ++++++++++++------- .../recorder/service/jfrRecorderService.hpp | 2 ++ src/hotspot/share/runtime/vmOperation.hpp | 3 +- 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp b/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp index 0395b711c6521..9f24bddcd3cd7 100644 --- a/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp +++ b/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp @@ -393,14 +393,22 @@ static u4 write_metadata(JfrChunkWriter& chunkwriter) { return invoke(wm); } -template -class JfrVMOperation : public VM_Operation { +class JfrSafepointClearVMOperation : public VM_Operation { private: - Instance& _instance; + JfrRecorderService& _instance; + public: + JfrSafepointClearVMOperation(JfrRecorderService& instance) : _instance(instance) {} + void doit() { _instance.safepoint_clear(); } + VMOp_Type type() const { return VMOp_JFRSafepointClear; } +}; + +class JfrSafepointWriteVMOperation : public VM_Operation { + private: + JfrRecorderService& _instance; public: - JfrVMOperation(Instance& instance) : _instance(instance) {} - void doit() { (_instance.*func)(); } - VMOp_Type type() const { return VMOp_JFRCheckpoint; } + JfrSafepointWriteVMOperation(JfrRecorderService& instance) : _instance(instance) {} + void doit() { _instance.safepoint_write(); } + VMOp_Type type() const { return VMOp_JFRSafepointWrite; } }; JfrRecorderService::JfrRecorderService() : @@ -470,9 +478,9 @@ void JfrRecorderService::pre_safepoint_clear() { } void JfrRecorderService::invoke_safepoint_clear() { - JfrVMOperation safepoint_task(*this); + JfrSafepointClearVMOperation op(*this); ThreadInVMfromNative transition(JavaThread::current()); - VMThread::execute(&safepoint_task); + VMThread::execute(&op); } void JfrRecorderService::safepoint_clear() { @@ -577,10 +585,10 @@ void JfrRecorderService::pre_safepoint_write() { } void JfrRecorderService::invoke_safepoint_write() { - JfrVMOperation safepoint_task(*this); + JfrSafepointWriteVMOperation op(*this); // can safepoint here ThreadInVMfromNative transition(JavaThread::current()); - VMThread::execute(&safepoint_task); + VMThread::execute(&op); } void JfrRecorderService::safepoint_write() { diff --git a/src/hotspot/share/jfr/recorder/service/jfrRecorderService.hpp b/src/hotspot/share/jfr/recorder/service/jfrRecorderService.hpp index 89c0437dd13bf..e5b4500afc068 100644 --- a/src/hotspot/share/jfr/recorder/service/jfrRecorderService.hpp +++ b/src/hotspot/share/jfr/recorder/service/jfrRecorderService.hpp @@ -35,6 +35,8 @@ class JfrStorage; class JfrStringPool; class JfrRecorderService : public StackObj { + friend class JfrSafepointClearVMOperation; + friend class JfrSafepointWriteVMOperation; private: JfrCheckpointManager& _checkpoint_manager; JfrChunkWriter& _chunkwriter; diff --git a/src/hotspot/share/runtime/vmOperation.hpp b/src/hotspot/share/runtime/vmOperation.hpp index 36aa6d3f28ac8..532a9231b70e8 100644 --- a/src/hotspot/share/runtime/vmOperation.hpp +++ b/src/hotspot/share/runtime/vmOperation.hpp @@ -87,7 +87,8 @@ template(HeapWalkOperation) \ template(HeapIterateOperation) \ template(ReportJavaOutOfMemory) \ - template(JFRCheckpoint) \ + template(JFRSafepointClear) \ + template(JFRSafepointWrite) \ template(ShenandoahFullGC) \ template(ShenandoahInitMark) \ template(ShenandoahFinalMarkStartEvac) \ From e07a5b66267156f55ee1c28579382990e58f15eb Mon Sep 17 00:00:00 2001 From: Erik Gahlin Date: Mon, 19 Aug 2024 10:42:58 +0000 Subject: [PATCH 339/353] 8338512: JFR: Revert changes to TestCodeSweeper Reviewed-by: mgronlun --- test/jdk/ProblemList.txt | 1 + .../jfr/event/compiler/TestCodeSweeper.java | 54 ++++++------------- 2 files changed, 17 insertions(+), 38 deletions(-) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 6cde711138310..bbf594f3bc70b 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -743,6 +743,7 @@ jdk/incubator/vector/LoadJsvmlTest.java 8305390 windows- # jdk_jfr +jdk/jfr/event/compiler/TestCodeSweeper.java 8338127 generic-all jdk/jfr/event/runtime/TestResidentSetSizeEvent.java 8309846 aix-ppc64 jdk/jfr/jvm/TestWaste.java 8282427 generic-all diff --git a/test/jdk/jdk/jfr/event/compiler/TestCodeSweeper.java b/test/jdk/jdk/jfr/event/compiler/TestCodeSweeper.java index df95af5b9be0a..62fb137b1cf03 100644 --- a/test/jdk/jdk/jfr/event/compiler/TestCodeSweeper.java +++ b/test/jdk/jdk/jfr/event/compiler/TestCodeSweeper.java @@ -27,11 +27,9 @@ import java.lang.reflect.Method; import java.time.Instant; import java.util.ArrayList; -import java.util.Collections; import java.util.List; -import jdk.jfr.Event; -import jdk.jfr.consumer.RecordingStream; +import jdk.jfr.Recording; import jdk.jfr.consumer.RecordedEvent; import jdk.test.lib.Asserts; import jdk.test.lib.jfr.EventNames; @@ -41,7 +39,7 @@ import jdk.test.whitebox.code.CodeBlob; /** - * Test for events: jdk.CodeCacheFull jdk.CompilationFailure + * Test for events: vm/code_cache/full vm/compiler/failure * * We verify that we should get at least one of each of the events listed above. * @@ -60,15 +58,13 @@ */ public class TestCodeSweeper { - static class ProvocationEvent extends Event { - } private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); private static final int COMP_LEVEL_SIMPLE = 1; private static final int COMP_LEVEL_FULL_OPTIMIZATION = 4; private static final int SIZE = 1; private static final String METHOD_NAME = "verifyFullEvent"; - private static final String EVENT_CODE_CACHE_FULL = EventNames.CodeCacheFull; - private static final String EVENT_COMPILATION_FAILURE = EventNames.CompilationFailure; + private static final String pathFull = EventNames.CodeCacheFull; + private static final String pathFailure = EventNames.CompilationFailure; public static final long SEGMENT_SIZE = WhiteBox.getWhiteBox().getUintxVMFlag("CodeCacheSegmentSize"); public static final long MIN_BLOCK_LENGTH = WhiteBox.getWhiteBox().getUintxVMFlag("CodeCacheMinBlockLength"); public static final long MIN_ALLOCATION = SEGMENT_SIZE * MIN_BLOCK_LENGTH; @@ -81,41 +77,26 @@ public static void main(String[] args) throws Throwable { System.out.println("This test will warn that the code cache is full."); System.out.println("That is expected and is the purpose of the test."); System.out.println("************************************************"); - List events = Collections.synchronizedList(new ArrayList<>()); - try (RecordingStream rs = new RecordingStream()) { - rs.setReuse(false); - rs.enable(EVENT_CODE_CACHE_FULL); - rs.enable(EVENT_COMPILATION_FAILURE); - rs.onEvent(EVENT_CODE_CACHE_FULL, events::add); - rs.onEvent(EVENT_COMPILATION_FAILURE, events::add); - rs.onEvent(ProvocationEvent.class.getName(), e -> { - if (!events.isEmpty()) { - rs.close(); - return; - } - // Retry if CodeCacheFull or CompilationFailure events weren't provoked - try { - provokeEvents(); - } catch (Exception ex) { - ex.printStackTrace(); - rs.close(); - } - }); - rs.startAsync(); - provokeEvents(); - rs.awaitTermination(); - } + + Recording r = new Recording(); + r.enable(pathFull); + r.enable(pathFailure); + r.start(); + provokeEvents(); + r.stop(); int countEventFull = 0; int countEventFailure = 0; + + List events = Events.fromRecording(r); Events.hasEvents(events); - for (RecordedEvent event : new ArrayList<>(events)) { + for (RecordedEvent event : events) { switch (event.getEventType().getName()) { - case EVENT_CODE_CACHE_FULL: + case pathFull: countEventFull++; verifyFullEvent(event); break; - case EVENT_COMPILATION_FAILURE: + case pathFailure: countEventFailure++; verifyFailureEvent(event); break; @@ -134,8 +115,6 @@ private static boolean canAllocate(double size, long maxSize, MemoryPoolMXBean b } private static void provokeEvents() throws NoSuchMethodException, InterruptedException { - System.out.println("provokeEvents()"); - ProvocationEvent provocationEvent = new ProvocationEvent(); // Prepare for later, since we don't want to trigger any compilation // setting this up. Method method = TestCodeSweeper.class.getDeclaredMethod(METHOD_NAME, new Class[] { RecordedEvent.class }); @@ -180,7 +159,6 @@ private static void provokeEvents() throws NoSuchMethodException, InterruptedExc for (Long blob : blobs) { WHITE_BOX.freeCodeBlob(blob); } - provocationEvent.commit(); } private static void verifyFullEvent(RecordedEvent event) throws Throwable { From 6ff6b0994380276e0096f7b55a0d659803344679 Mon Sep 17 00:00:00 2001 From: Renjith Kannath Pariyangad Date: Mon, 19 Aug 2024 12:40:35 +0000 Subject: [PATCH 340/353] 8290501: Typo in javax.swing.BoundedRangeModel documentation Reviewed-by: aivanov, prr, honkar --- .../share/classes/javax/swing/BoundedRangeModel.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/java.desktop/share/classes/javax/swing/BoundedRangeModel.java b/src/java.desktop/share/classes/javax/swing/BoundedRangeModel.java index bc6a84ac89194..e6a9d08611dc6 100644 --- a/src/java.desktop/share/classes/javax/swing/BoundedRangeModel.java +++ b/src/java.desktop/share/classes/javax/swing/BoundedRangeModel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,7 @@ package javax.swing; -import javax.swing.event.*; +import javax.swing.event.ChangeListener; /** @@ -40,7 +40,7 @@ * range is value,value+extent. The inner range * must lie within the outer one, i.e. value must be * less than or equal to maximum and value+extent - * must greater than or equal to minimum, and maximum + * must be greater than or equal to minimum, and maximum * must be greater than or equal to minimum. * There are a few features of this model that one might find a little * surprising. These quirks exist for the convenience of the @@ -228,7 +228,7 @@ public interface BoundedRangeModel /** - * This method sets all of the model's data with a single method call. + * This method sets all the model's data with a single method call. * The method results in a single change event being generated. This is * convenient when you need to adjust all the model data simultaneously and * do not want individual change events to occur. From f0fe31383aec652ad4e3cc4873cd3ff9b918fef7 Mon Sep 17 00:00:00 2001 From: Adam Sotona Date: Mon, 19 Aug 2024 12:57:17 +0000 Subject: [PATCH 341/353] 8338564: Remove obsolete AbstractNamedEntry::equals method Reviewed-by: liach --- .../jdk/internal/classfile/impl/AbstractPoolEntry.java | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java index c6e6c4dce57a7..c27968eecab4f 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java @@ -534,15 +534,6 @@ public Utf8Entry name() { public String asInternalName() { return ref1.stringValue(); } - - @Override - public boolean equals(Object o) { - if (o == this) { return true; } - if (o instanceof AbstractNamedEntry ne) { - return tag == ne.tag() && name().equals(ref1()); - } - return false; - } } public static final class ClassEntryImpl extends AbstractNamedEntry implements ClassEntry { From 2766b09e29d7c1c31fdef20f016a181eedb2d429 Mon Sep 17 00:00:00 2001 From: Alan Bateman Date: Mon, 19 Aug 2024 12:57:29 +0000 Subject: [PATCH 342/353] 8338452: (dc) DatagramChannelImpl.blockingReceive with timeout may block indefinitely if all datagrams blocked by SecurityManager Reviewed-by: dfuchs --- .../classes/sun/nio/ch/DatagramChannelImpl.java | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/java.base/share/classes/sun/nio/ch/DatagramChannelImpl.java b/src/java.base/share/classes/sun/nio/ch/DatagramChannelImpl.java index 06e79f416ac7a..5fac688b3115e 100644 --- a/src/java.base/share/classes/sun/nio/ch/DatagramChannelImpl.java +++ b/src/java.base/share/classes/sun/nio/ch/DatagramChannelImpl.java @@ -683,14 +683,12 @@ void blockingReceive(DatagramPacket p, long nanos) throws IOException { } long startNanos = System.nanoTime(); + long remainingNanos = nanos; SocketAddress sender = null; try { SocketAddress remote = beginRead(true, false); boolean connected = (remote != null); do { - long remainingNanos = (nanos > 0) - ? nanos - (System.nanoTime() - startNanos) - : 0; ByteBuffer dst = tryBlockingReceive(connected, bufLength, remainingNanos); // if datagram received then get sender and copy to DatagramPacket @@ -711,8 +709,8 @@ void blockingReceive(DatagramPacket p, long nanos) throws IOException { } } - // copy bytes to the DatagramPacket, and set length and sender if (sender != null) { + // copy bytes to the DatagramPacket, and set length and sender synchronized (p) { // re-read p.bufLength in case DatagramPacket changed int len = Math.min(dst.limit(), DatagramPackets.getBufLength(p)); @@ -720,6 +718,14 @@ void blockingReceive(DatagramPacket p, long nanos) throws IOException { DatagramPackets.setLength(p, len); p.setSocketAddress(sender); } + } else { + // need to retry, adjusting timeout if needed + if (nanos > 0) { + remainingNanos = nanos - (System.nanoTime() - startNanos); + if (remainingNanos <= 0) { + throw new SocketTimeoutException("Receive timed out"); + } + } } } finally { Util.offerFirstTemporaryDirectBuffer(dst); @@ -746,6 +752,7 @@ void blockingReceive(DatagramPacket p, long nanos) throws IOException { private ByteBuffer tryBlockingReceive(boolean connected, int len, long nanos) throws IOException { + assert nanos >= 0; long startNanos = System.nanoTime(); ByteBuffer dst = Util.getTemporaryDirectBuffer(len); int n = -1; From 3ca359ad224b07f283c99eb43bed02eb93ef2dc7 Mon Sep 17 00:00:00 2001 From: Daniel Fuchs Date: Mon, 19 Aug 2024 13:47:40 +0000 Subject: [PATCH 343/353] 8335771: Improve stability of java/nio/channels/DatagramChannel tests Reviewed-by: alanb --- .../DatagramChannel/AdaptorMulticasting.java | 32 ++++-- .../DatagramChannel/AfterDisconnect.java | 99 +++++++++++++++---- .../nio/channels/DatagramChannel/Connect.java | 18 +++- .../ManySourcesAndTargets.java | 27 ++++- .../MulticastSendReceiveTests.java | 21 +++- .../channels/DatagramChannel/NotBound.java | 74 ++++++++++---- .../channels/DatagramChannel/Promiscuous.java | 43 ++++---- .../channels/DatagramChannel/ReceiveISA.java | 18 +++- .../DatagramChannel/SelectWhenRefused.java | 60 ++++++++--- .../DatagramChannel/SendReceiveMaxSize.java | 33 ++++++- .../nio/channels/DatagramChannel/Sender.java | 52 ++++++---- 11 files changed, 365 insertions(+), 112 deletions(-) diff --git a/test/jdk/java/nio/channels/DatagramChannel/AdaptorMulticasting.java b/test/jdk/java/nio/channels/DatagramChannel/AdaptorMulticasting.java index 0c8da1ff9d9c9..cab2bc7628562 100644 --- a/test/jdk/java/nio/channels/DatagramChannel/AdaptorMulticasting.java +++ b/test/jdk/java/nio/channels/DatagramChannel/AdaptorMulticasting.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,6 +48,7 @@ import java.util.stream.Collectors; import static java.net.StandardSocketOptions.*; import static java.net.StandardProtocolFamily.*; +import static jdk.test.lib.NetworkConfiguration.isSameInterface; import jdk.test.lib.NetworkConfiguration; import jdk.test.lib.net.IPSupport; @@ -295,8 +296,8 @@ static void testNetworkInterface(MulticastSocket s, // setNetworkInterface s.setNetworkInterface(ni); - assertTrue(s.getNetworkInterface().equals(ni)); - assertTrue(s.getOption(IP_MULTICAST_IF).equals(ni)); + assertTrue(isSameInterface(s.getNetworkInterface(), ni)); + assertTrue(isSameInterface(s.getOption(IP_MULTICAST_IF), ni)); InetAddress address = s.getInterface(); assertTrue(ni.inetAddresses().filter(address::equals).findAny().isPresent()); @@ -315,8 +316,8 @@ static void testNetworkInterface(MulticastSocket s, // setOption(IP_MULTICAST_IF) s.setOption(IP_MULTICAST_IF, ni); - assertTrue(s.getOption(IP_MULTICAST_IF).equals(ni)); - assertTrue(s.getNetworkInterface().equals(ni)); + assertTrue(isSameInterface(s.getOption(IP_MULTICAST_IF), ni)); + assertTrue(isSameInterface(s.getNetworkInterface(), ni)); // bad values for IP_MULTICAST_IF assertThrows(IllegalArgumentException.class, @@ -412,7 +413,8 @@ static void testSendReceive(MulticastSocket s, InetAddress group) throws IOExcep assertTrue(s.getOption(IP_MULTICAST_IF) != null); SocketAddress target = new InetSocketAddress(group, s.getLocalPort()); - byte[] message = "hello".getBytes("UTF-8"); + String msg = "AdaptorMulticasting: " + System.nanoTime(); + byte[] message = msg.getBytes("UTF-8"); // send message to multicast group DatagramPacket p = new DatagramPacket(message, message.length); @@ -421,8 +423,22 @@ static void testSendReceive(MulticastSocket s, InetAddress group) throws IOExcep // receive message s.setSoTimeout(0); - p = new DatagramPacket(new byte[1024], 100); - s.receive(p); + while (true) { + p = new DatagramPacket(new byte[1024], 100); + s.receive(p); + if (p.getPort() == s.getLocalPort()) { + String str = new String(p.getData(), p.getOffset(), p.getLength(), "UTF-8"); + if (Arrays.equals(p.getData(), p.getOffset(), p.getLength(), message, 0, message.length)) { + System.out.format("Got expected message \"%s\" from %s%n", str, p.getSocketAddress()); + break; + } + System.out.println("Unexpected message received. Expected: " + msg); + System.out.println("Received message doesn't match - skipping: " + str); + } else { + System.out.println("Unexpected message received. Expected message from: " + s.getLocalAddress()); + System.out.println("Received message sender doesn't match - skipping: " + p.getSocketAddress()); + } + } assertTrue(p.getLength() == message.length); assertTrue(p.getPort() == s.getLocalPort()); diff --git a/test/jdk/java/nio/channels/DatagramChannel/AfterDisconnect.java b/test/jdk/java/nio/channels/DatagramChannel/AfterDisconnect.java index 6a80d686b305b..de59984dae15f 100644 --- a/test/jdk/java/nio/channels/DatagramChannel/AfterDisconnect.java +++ b/test/jdk/java/nio/channels/DatagramChannel/AfterDisconnect.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,7 @@ */ import java.io.IOException; +import java.net.BindException; import java.net.InetAddress; import java.net.Inet6Address; import java.net.InetSocketAddress; @@ -46,6 +47,7 @@ import java.nio.channels.Selector; import java.util.HashMap; import java.util.Map; +import java.util.function.Predicate; import org.testng.annotations.Test; import static org.testng.Assert.*; @@ -54,6 +56,38 @@ public class AfterDisconnect { + interface RetryableTest { + public void runTest() throws T; + } + + // retry the given lambda (RetryableTest) if an exception + // that satisfies the predicate (retryOn) is caught. + void testWithRetry(RetryableTest test, + Predicate retryOn, + int max) throws T { + for (int i=0; i < max; i++) { + try { + test.runTest(); + break; + } catch (Throwable t) { + if (i < max -1 && retryOn.test(t)) { + System.out.println("Got " + t + "; will retry"); + } else throw t; + } + } + } + + /** + * When calling {@link DatagramChannel#disconnect()} a {@link BindException} + * may occur. In which case we want to retry the test. + */ + class BindExceptionOnDisconnect extends BindException { + BindExceptionOnDisconnect(BindException x) { + super(x.getMessage()); + initCause(x); + } + } + @Test public void execute() throws IOException { IPSupport.throwSkippedExceptionIfNonOperational(); @@ -61,34 +95,41 @@ public void execute() throws IOException { InetAddress lb = InetAddress.getLoopbackAddress(); // test with default protocol family - try (DatagramChannel dc = DatagramChannel.open()) { - System.out.println("Test with default"); - dc.bind(new InetSocketAddress(lb, 0)); - test(dc); - test(dc); - } - - // test with IPv6 socket - if (IPSupport.hasIPv6()) { - System.out.println("Test with IPv6 socket"); - try (DatagramChannel dc = DatagramChannel.open(StandardProtocolFamily.INET6)) { + System.out.println("Test with default"); + testWithRetry(() -> { + try (DatagramChannel dc = DatagramChannel.open()) { dc.bind(new InetSocketAddress(lb, 0)); test(dc); test(dc); } + }, BindExceptionOnDisconnect.class::isInstance, 5); + + // test with IPv6 socket + if (IPSupport.hasIPv6()) { + System.out.println("Test with IPv6 socket"); + testWithRetry(() -> { + try (DatagramChannel dc = DatagramChannel.open(StandardProtocolFamily.INET6)) { + dc.bind(new InetSocketAddress(lb, 0)); + test(dc); + test(dc); + } + }, BindExceptionOnDisconnect.class::isInstance, 5); } // test with IPv4 socket if (IPSupport.hasIPv4() && !preferIPv6) { System.out.println("Test with IPv4 socket"); - try (DatagramChannel dc = DatagramChannel.open(StandardProtocolFamily.INET)) { - dc.bind(new InetSocketAddress(lb, 0)); - test(dc); - test(dc); - } + testWithRetry(() -> { + try (DatagramChannel dc = DatagramChannel.open(StandardProtocolFamily.INET)) { + dc.bind(new InetSocketAddress(lb, 0)); + test(dc); + test(dc); + } + }, BindExceptionOnDisconnect.class::isInstance, 5); } } + void test(DatagramChannel dc) throws IOException { testLocalAddress(dc); testSocketOptions(dc); @@ -111,7 +152,11 @@ void testLocalAddress(DatagramChannel dc) throws IOException { assertEquals(dc.getLocalAddress(), local); assertEquals(dc.getRemoteAddress(), remote); - dc.disconnect(); + try { + dc.disconnect(); + } catch (BindException x) { + throw new BindExceptionOnDisconnect(x); + } assertFalse(dc.isConnected()); assertEquals(dc.getLocalAddress(), local); assertTrue(dc.getRemoteAddress() == null); @@ -134,7 +179,11 @@ void testSocketOptions(DatagramChannel dc) throws IOException { Map, Object> map = options(dc); dc.connect(dc.getLocalAddress()); - dc.disconnect(); + try { + dc.disconnect(); + } catch (BindException x) { + throw new BindExceptionOnDisconnect(x); + } // check socket options have not changed assertEquals(map, options(dc)); @@ -168,7 +217,11 @@ void testSelectorRegistration(DatagramChannel dc) throws IOException { sel.selectNow(); dc.connect(dc.getLocalAddress()); - dc.disconnect(); + try { + dc.disconnect(); + } catch (BindException x) { + throw new BindExceptionOnDisconnect(x); + } // selection key should still be valid assertTrue(key.isValid()); @@ -210,7 +263,11 @@ void testMulticastGroups(DatagramChannel dc) throws IOException { MembershipKey key = dc.join(group, ni); dc.connect(dc.getLocalAddress()); - dc.disconnect(); + try { + dc.disconnect(); + } catch (BindException x) { + throw new BindExceptionOnDisconnect(x); + } // membership key should still be valid assertTrue(key.isValid()); diff --git a/test/jdk/java/nio/channels/DatagramChannel/Connect.java b/test/jdk/java/nio/channels/DatagramChannel/Connect.java index 082a3234cc5a7..41c172b33284d 100644 --- a/test/jdk/java/nio/channels/DatagramChannel/Connect.java +++ b/test/jdk/java/nio/channels/DatagramChannel/Connect.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,8 @@ /* @test * @bug 4313882 7183800 + * @library /test/lib + * @build jdk.test.lib.Platform Connect * @run main/othervm Connect * @summary Test DatagramChannel's send and receive methods */ @@ -38,6 +40,8 @@ import java.util.concurrent.CompletionException; import java.util.stream.Stream; +import jdk.test.lib.Platform; + import static java.nio.charset.StandardCharsets.US_ASCII; public class Connect { @@ -114,9 +118,21 @@ public void run() { ByteBuffer bb = ByteBuffer.allocateDirect(MAX); bb.put(bytes); bb.flip(); + // When connecting an unbound datagram channel, the underlying + // socket will first be bound to the wildcard address. On macOS, + // the system may allocate the same port on which another socket + // is already bound with a more specific address. This may prevent + // datagrams directed at the connected socket to reach it. + // To avoid this, when on macOS, we preemptively bind `dc` to the + // specific address instead of letting it bind to the wildcard. + if (Platform.isOSX()) { + dc.bind(new InetSocketAddress(((InetSocketAddress)connectSocketAddress).getAddress(), 0)); + err.println("Initiator bound to: " + connectSocketAddress); + } err.println("Initiator connecting to: " + connectSocketAddress); dc.connect(connectSocketAddress); err.println("Initiator bound to: " + dc.getLocalAddress()); + assert !connectSocketAddress.equals(dc.getLocalAddress()); // Send a message err.println("Initiator attempting to write to Responder at " + connectSocketAddress); diff --git a/test/jdk/java/nio/channels/DatagramChannel/ManySourcesAndTargets.java b/test/jdk/java/nio/channels/DatagramChannel/ManySourcesAndTargets.java index ed4e9c0c02e04..18a18fcba0a38 100644 --- a/test/jdk/java/nio/channels/DatagramChannel/ManySourcesAndTargets.java +++ b/test/jdk/java/nio/channels/DatagramChannel/ManySourcesAndTargets.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,7 @@ /* @test * @bug 8234805 8235193 * @summary Test DatagramChannel send/receive and that receive returns the expected - * sender address + * sender address. * @run main/othervm ManySourcesAndTargets * @run main/othervm -Djava.net.preferIPv4Stack=true ManySourcesAndTargets */ @@ -63,6 +63,7 @@ public static void main(String[] args) throws Exception { try (DatagramChannel reader = DatagramChannel.open()) { // bind reader to wildcard address so it can receive from any address reader.bind(new InetSocketAddress(0)); + System.out.println("\nReader bound to: " + reader.getLocalAddress()); for (InetAddress address : addresses) { System.out.format("%n-- %s --%n", address.getHostAddress()); @@ -75,6 +76,7 @@ public static void main(String[] args) throws Exception { try (DatagramChannel sender = DatagramChannel.open()) { // bind sender to wildcard address so it can send to any address sender.bind(new InetSocketAddress(0)); + System.out.println("\nSender bound to: " + sender.getLocalAddress()); for (InetAddress address : addresses) { System.out.format("%n-- %s --%n", address.getHostAddress()); @@ -97,6 +99,11 @@ static void testSend(int count, InetAddress address, DatagramChannel reader) thr sender.bind(new InetSocketAddress(address, 0)); SocketAddress local = sender.getLocalAddress(); + System.out.println("Sender bound to: " + local); + if (((InetSocketAddress)local).getPort() == remotePort) { + System.out.println("testSend: Sender and reader have same port: skipping"); + return; + } byte[] bytes = serialize(local); SocketAddress previousSource = null; @@ -105,6 +112,8 @@ static void testSend(int count, InetAddress address, DatagramChannel reader) thr sender.send(ByteBuffer.wrap(bytes), remote); ByteBuffer bb = ByteBuffer.allocate(1000); + System.out.format("testSend: reader waiting to receive at: %s%n", + reader.getLocalAddress()); SocketAddress source = reader.receive(bb); System.out.format("received datagram from %s%n", source); @@ -138,11 +147,18 @@ static void testReceive(int count, DatagramChannel sender, InetAddress address) SocketAddress remote = reader.getLocalAddress(); + System.out.println("Reader bound to: " + remote); + if (((InetSocketAddress)local).getPort() == ((InetSocketAddress)remote).getPort()) { + System.out.println("testReceive: Sender and reader have same port: skipping"); + return; + } for (int i = 0; i < count; i++) { System.out.format("send %s -> %s%n", local, remote); sender.send(ByteBuffer.allocate(32), remote); ByteBuffer bb = ByteBuffer.allocate(1000); + System.out.format("testReceive: reader waiting to receive at: %s%n", + reader.getLocalAddress()); SocketAddress source = reader.receive(bb); System.out.format("received datagram from %s%n", source); } @@ -165,7 +181,12 @@ private static SocketAddress deserialize(byte[] bytes) throws Exception { private static Optional networkInterface(InetAddress ia) { try { - return Optional.ofNullable(NetworkInterface.getByInetAddress(ia)); + NetworkInterface nif = NetworkInterface.getByInetAddress(ia); + if (nif != null) { + System.out.format("Selecting interface %s[%d]%n\twith addresses:%n\t%s%n", + nif.getDisplayName(), nif.getIndex(), nif.inetAddresses().toList()); + } + return Optional.ofNullable(nif); } catch (SocketException e) { return Optional.empty(); } diff --git a/test/jdk/java/nio/channels/DatagramChannel/MulticastSendReceiveTests.java b/test/jdk/java/nio/channels/DatagramChannel/MulticastSendReceiveTests.java index c1ea04ba2160d..87aedc8efd91a 100644 --- a/test/jdk/java/nio/channels/DatagramChannel/MulticastSendReceiveTests.java +++ b/test/jdk/java/nio/channels/DatagramChannel/MulticastSendReceiveTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -99,15 +99,25 @@ static void receiveDatagram(DatagramChannel dc, ByteBuffer buf = ByteBuffer.allocateDirect(100); try { + long elapsed = 0; for (;;) { System.out.println("Waiting to receive message"); + long start = System.nanoTime(); sel.select(5*1000); + long waited = (System.nanoTime() - start) / 1000_000; + elapsed += waited; + buf.clear(); SocketAddress sa = dc.receive(buf); // no datagram received if (sa == null) { if (expectedSender != null) { - throw new RuntimeException("Expected message not received"); + if (elapsed > 4800) { + throw new RuntimeException("Expected message not received"); + } else { + sel.selectedKeys().clear(); + continue; + } } System.out.println("No message received (correct)"); return; @@ -123,8 +133,8 @@ static void receiveDatagram(DatagramChannel dc, int receivedId = -1; try { receivedId = Integer.parseInt(s); - System.out.format("Received message from %s (id=0x%x)\n", - sender, receivedId); + System.out.format("Received message from %s (id=0x%x, length=%s)\n", + sender, receivedId, bytes.length); } catch (NumberFormatException x) { System.out.format("Received message from %s (msg=%s)\n", sender, s); } @@ -142,7 +152,6 @@ static void receiveDatagram(DatagramChannel dc, } sel.selectedKeys().clear(); - buf.rewind(); } } finally { sel.close(); @@ -160,6 +169,8 @@ static void test(ProtocolFamily family, throws IOException { System.out.format("\nTest DatagramChannel to %s socket\n", family.name()); + System.out.format("With interface=%s[%s]%n\twith bound addresses:%n\t%s%n", + nif.getDisplayName(), nif.getIndex(), nif.inetAddresses().toList()); try (DatagramChannel dc = (family == UNSPEC) ? DatagramChannel.open() : DatagramChannel.open(family)) { dc.setOption(StandardSocketOptions.SO_REUSEADDR, true) diff --git a/test/jdk/java/nio/channels/DatagramChannel/NotBound.java b/test/jdk/java/nio/channels/DatagramChannel/NotBound.java index 4cd9a03033642..bcd73591bf967 100644 --- a/test/jdk/java/nio/channels/DatagramChannel/NotBound.java +++ b/test/jdk/java/nio/channels/DatagramChannel/NotBound.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,19 +24,26 @@ /* @test * @bug 4512723 6621689 * @summary Test that connect/send/receive with unbound DatagramChannel causes - * the channel's socket to be bound to a local address + * the channel's socket to be bound to a local address. + * @run main/othervm NotBound */ import java.net.*; import java.nio.ByteBuffer; import java.nio.channels.DatagramChannel; import java.io.IOException; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; public class NotBound { + static final CountDownLatch received = new CountDownLatch(1); + static void checkBound(DatagramChannel dc) throws IOException { if (dc.getLocalAddress() == null) throw new RuntimeException("Not bound??"); + System.out.println("Bound to: " + dc.getLocalAddress()); } // starts a thread to send a datagram to the given channel once the channel @@ -51,19 +58,44 @@ public void run() { Thread.sleep(50); local = (InetSocketAddress)dc.getLocalAddress(); } while (local == null); + System.out.format("receiver bound to: %s%n", local); - // send message to channel to wakeup receiver - DatagramChannel sender = DatagramChannel.open(); - try { - ByteBuffer bb = ByteBuffer.wrap("hello".getBytes()); - InetAddress lh = InetAddress.getLocalHost(); - SocketAddress target = - new InetSocketAddress(lh, local.getPort()); - sender.send(bb, target); - } finally { - sender.close(); + boolean isAnyLocal = local.getAddress().isAnyLocalAddress(); + int maxAttempts = 5; + int localPort = 0; + List llh = isAnyLocal + ? List.of(InetAddress.getLocalHost(), InetAddress.getLoopbackAddress()) + : List.of(local.getAddress()); + SocketAddress target = null; + for (int i = 0 ; i < maxAttempts ; i++) { + InetAddress lh = llh.get(i % llh.size()); + target = new InetSocketAddress(lh, local.getPort()); + // send message to channel to wakeup receiver + try (DatagramChannel sender = DatagramChannel.open()) { + ByteBuffer bb = ByteBuffer.wrap("NotBound: hello".getBytes()); + sender.send(bb, target); + System.out.format("Woke up receiver: sent datagram to %s from %s%n", + target, sender.getLocalAddress()); + localPort = ((InetSocketAddress)sender.getLocalAddress()).getPort(); + } + if (received.await(250, TimeUnit.MILLISECONDS)) { + // The datagram has been received: no need to continue + // sending + break; + } + // if sender port and destination port were identical, which + // could happen on some systems, the receiver might not receive + // the datagram. So in that case we try again, bailing out if + // we had to retry too many times + if (localPort == local.getPort()) { + System.out.println("Local port and peer port are identical. Retrying..."); + } else { + System.out.println("Datagram not received after 250ms. Retrying..."); + } + } + if (localPort == local.getPort()) { + System.out.println("Couldn't find a port to send to " + target); } - } catch (Exception x) { x.printStackTrace(); } @@ -77,14 +109,12 @@ public static void main(String[] args) throws IOException { // connect dc = DatagramChannel.open(); try { - DatagramChannel peer = DatagramChannel.open() - .bind(new InetSocketAddress(0)); - int peerPort = ((InetSocketAddress)(peer.getLocalAddress())).getPort(); - try { + System.out.println("Check that connect() binds the socket"); + try (DatagramChannel peer = DatagramChannel.open()) { + peer.bind(new InetSocketAddress(0)); + int peerPort = ((InetSocketAddress)(peer.getLocalAddress())).getPort(); dc.connect(new InetSocketAddress(InetAddress.getLocalHost(), peerPort)); checkBound(dc); - } finally { - peer.close(); } } finally { dc.close(); @@ -93,7 +123,8 @@ public static void main(String[] args) throws IOException { // send dc = DatagramChannel.open(); try { - ByteBuffer bb = ByteBuffer.wrap("ignore this".getBytes()); + System.out.println("Check that send() binds the socket"); + ByteBuffer bb = ByteBuffer.wrap("NotBound: ignore this".getBytes()); SocketAddress target = new InetSocketAddress(InetAddress.getLocalHost(), 5000); dc.send(bb, target); @@ -105,9 +136,11 @@ public static void main(String[] args) throws IOException { // receive (blocking) dc = DatagramChannel.open(); try { + System.out.println("Check that blocking receive() binds the socket"); ByteBuffer bb = ByteBuffer.allocateDirect(128); wakeupWhenBound(dc); SocketAddress sender = dc.receive(bb); + received.countDown(); if (sender == null) throw new RuntimeException("Sender should not be null"); checkBound(dc); @@ -118,6 +151,7 @@ public static void main(String[] args) throws IOException { // receive (non-blocking) dc = DatagramChannel.open(); try { + System.out.println("Check that non-blocking receive() binds the socket"); dc.configureBlocking(false); ByteBuffer bb = ByteBuffer.allocateDirect(128); SocketAddress sender = dc.receive(bb); diff --git a/test/jdk/java/nio/channels/DatagramChannel/Promiscuous.java b/test/jdk/java/nio/channels/DatagramChannel/Promiscuous.java index 8db9c60c0b558..a8a5772b87b4f 100644 --- a/test/jdk/java/nio/channels/DatagramChannel/Promiscuous.java +++ b/test/jdk/java/nio/channels/DatagramChannel/Promiscuous.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -71,9 +71,11 @@ static int sendDatagram(NetworkInterface nif, dc.setOption(StandardSocketOptions.IP_MULTICAST_IF, nif); byte[] msg = Integer.toString(id).getBytes("UTF-8"); ByteBuffer buf = ByteBuffer.wrap(msg); - System.out.format("Send message -> group %s (id=0x%x)\n", - group.getHostAddress(), id); + System.out.format("Send message -> group [%s]:%d (id=0x%x) nif:%s[%s]%n", + group.getHostAddress(), port, id, nif.getDisplayName(), nif.getIndex()); + System.out.format("bound address before send: %s%n", dc.getLocalAddress()); dc.send(buf, new InetSocketAddress(group, port)); + System.out.format("bound address after send: %s%n", dc.getLocalAddress()); } return id; } @@ -97,15 +99,26 @@ static void receiveDatagram(DatagramChannel dc, ByteBuffer buf = ByteBuffer.allocateDirect(100); try { + long elapsed = 0; for (;;) { System.out.println("Waiting to receive message"); + long start = System.nanoTime(); sel.select(5*1000); + long waited = (System.nanoTime() - start) / 1000_000; + elapsed += waited; + buf.clear(); SocketAddress sa = dc.receive(buf); // no datagram received if (sa == null) { if (datagramExpected) { - throw new RuntimeException("Expected message not received"); + if (elapsed > 4800) { + throw new RuntimeException("Expected message not received"); + } else { + sel.selectedKeys().clear(); + // We haven't waited long enough, + continue; + } } System.out.println("No message received (correct)"); return; @@ -121,8 +134,8 @@ static void receiveDatagram(DatagramChannel dc, int receivedId = -1; try { receivedId = Integer.parseInt(s); - System.out.format("Received message from %s (id=0x%x)\n", - sender, receivedId); + System.out.format("Received message from %s (id=0x%x, length=%s)\n", + sender, receivedId, bytes.length); } catch (NumberFormatException x) { System.out.format("Received message from %s (msg=%s)\n", sender, s); } @@ -140,7 +153,6 @@ static void receiveDatagram(DatagramChannel dc, } sel.selectedKeys().clear(); - buf.rewind(); } } finally { sel.close(); @@ -155,13 +167,14 @@ static void test(ProtocolFamily family, { System.out.format("%nTest family=%s%n", family.name()); + System.out.format("With interface=%s[%s]%n\twith bound addresses:%n\t%s%n", + nif.getDisplayName(), nif.getIndex(), nif.inetAddresses().toList()); - DatagramChannel dc1 = (family == UNSPEC) ? - DatagramChannel.open() : DatagramChannel.open(family); - DatagramChannel dc2 = (family == UNSPEC) ? - DatagramChannel.open() : DatagramChannel.open(family); + try (DatagramChannel dc1 = (family == UNSPEC) ? + DatagramChannel.open() : DatagramChannel.open(family); + DatagramChannel dc2 = (family == UNSPEC) ? + DatagramChannel.open() : DatagramChannel.open(family)) { - try { dc1.setOption(StandardSocketOptions.SO_REUSEADDR, true); dc2.setOption(StandardSocketOptions.SO_REUSEADDR, true); @@ -184,12 +197,8 @@ static void test(ProtocolFamily family, id = sendDatagram(nif, group2, port); - receiveDatagram(dc1, "dc1", false, id); receiveDatagram(dc2, "dc2", true, id); - - } finally { - dc1.close(); - dc2.close(); + receiveDatagram(dc1, "dc1", false, id); } } diff --git a/test/jdk/java/nio/channels/DatagramChannel/ReceiveISA.java b/test/jdk/java/nio/channels/DatagramChannel/ReceiveISA.java index 69df204e91557..ef764c85d711e 100644 --- a/test/jdk/java/nio/channels/DatagramChannel/ReceiveISA.java +++ b/test/jdk/java/nio/channels/DatagramChannel/ReceiveISA.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,10 +27,19 @@ * @summary Check that DatagramChannel.receive returns a new SocketAddress * when it receives a packet from the same source address but * different endpoint. + * @library /test/lib + * @build jdk.test.lib.NetworkConfiguration + * jdk.test.lib.Platform + * ReceiveISA + * @run main/othervm ReceiveISA + * */ import java.nio.*; import java.nio.channels.*; import java.net.*; + +import jdk.test.lib.Platform; + import static java.lang.System.out; public class ReceiveISA { @@ -44,10 +53,13 @@ public static void main(String args[]) throws Exception { DatagramChannel dc3 = DatagramChannel.open(); DatagramChannel dc4 = DatagramChannel.open()) { // client - dc3.socket().bind((SocketAddress) null); // bind server to any port + InetAddress lh = InetAddress.getLocalHost(); + InetSocketAddress dest = Platform.isOSX() + ? new InetSocketAddress(lh, 0) + : null; + dc3.socket().bind(dest); // bind server to any port // get server address - InetAddress lh = InetAddress.getLocalHost(); InetSocketAddress isa = new InetSocketAddress(lh, dc3.socket().getLocalPort()); ByteBuffer bb = ByteBuffer.allocateDirect(100); diff --git a/test/jdk/java/nio/channels/DatagramChannel/SelectWhenRefused.java b/test/jdk/java/nio/channels/DatagramChannel/SelectWhenRefused.java index d851e4f2b8148..58ccf9d0b80f9 100644 --- a/test/jdk/java/nio/channels/DatagramChannel/SelectWhenRefused.java +++ b/test/jdk/java/nio/channels/DatagramChannel/SelectWhenRefused.java @@ -39,8 +39,8 @@ import static org.junit.jupiter.api.Assertions.assertNotEquals; public class SelectWhenRefused { - static final int MAX_TRIES = 3; - static final String GREETINGS_MESSAGE = "Greetings from SelectWhenRefused!"; + static final int MAX_TRIES = 10; + static final String GREETINGS_MESSAGE = System.nanoTime() + ": Greetings from SelectWhenRefused!"; @Test public void test() throws IOException { @@ -49,9 +49,39 @@ public void test() throws IOException { // datagram sent to this address should be refused SocketAddress refuser = new InetSocketAddress(InetAddress.getLocalHost(), port); + System.err.println("Refuser is: " + refuser); - DatagramChannel dc = DatagramChannel.open().bind(new InetSocketAddress(0)); + DatagramChannel dc = null; + for (int i=0; i < MAX_TRIES; i++) { + dc = DatagramChannel.open(); + try { + dc.bind(new InetSocketAddress(0)); + } catch (Throwable t) { + dc.close(); + throw t; + } + + // check the port assigned to dc + if (((InetSocketAddress)dc.getLocalAddress()).getPort() != port) { + // We got a good port. Do not retry + break; + } + + // We bound to the same port that the refuser is using, This will not + // work. Retry binding if possible. + if (i < MAX_TRIES - 1) { + // we will retry... + System.err.format("Refuser port has been reused by dc: %s, retrying...%n", + dc.getLocalAddress()); + } else { + // that was the last attempt... Skip the test + System.err.format("Skipping test: refuser port has been reused by dc: %s%n", + dc.getLocalAddress()); + return; + } + } dc1.close(); + assert dc != null; Selector sel = Selector.open(); try { @@ -88,7 +118,7 @@ public void test() throws IOException { } } catch (BindException e) { // Do nothing, some other test has used this port - System.out.println("Skipping test: refuser port has been reused: " + e); + System.err.println("Skipping test: refuser port has been reused: " + e); } finally { sel.close(); dc.close(); @@ -119,7 +149,9 @@ static boolean testNoPUEBeforeConnection(DatagramChannel dc, // BindException will be thrown if another service is using // our expected refuser port, cannot run just exit. - DatagramChannel.open().bind(refuser).close(); + try (DatagramChannel dc2 = DatagramChannel.open()) { + dc2.bind(refuser); + } throw new RuntimeException("Unexpected wakeup"); } return true; // test passed @@ -151,7 +183,7 @@ static boolean testPUEOnConnect(DatagramChannel dc, byte[] bytes = new byte[buf.remaining()]; buf.get(bytes); String message = new String(bytes); - System.out.format("received %s at %s from %s%n", message, dc.getLocalAddress(), sa); + System.err.format("received %s at %s from %s%n", message, dc.getLocalAddress(), sa); // If any received data contains the message from sendDatagram then throw exception if (message.contains(GREETINGS_MESSAGE)) { @@ -166,10 +198,12 @@ static boolean testPUEOnConnect(DatagramChannel dc, // BindException will be thrown if another service is using // our expected refuser port, cannot run just exit. - DatagramChannel.open().bind(refuser).close(); + try (DatagramChannel dc2 = DatagramChannel.open()) { + dc2.bind(refuser); + } throw new RuntimeException("PortUnreachableException not raised"); } catch (PortUnreachableException pue) { - System.out.println("Got expected PortUnreachableException " + pue); + System.err.println("Got expected PortUnreachableException " + pue); } } return true; // test passed @@ -215,16 +249,16 @@ static void sendDatagram(DatagramChannel dc, SocketAddress remote) * */ static boolean checkUnexpectedWakeup(Set selectedKeys) { - System.out.format("Received %d keys%n", selectedKeys.size()); + System.err.format("Received %d keys%n", selectedKeys.size()); for (SelectionKey key : selectedKeys) { if (!key.isValid() || !key.isReadable()) { - System.out.println("Invalid or unreadable key: " + key); + System.err.println("Invalid or unreadable key: " + key); continue; } try { - System.out.println("Attempting to read datagram from key: " + key); + System.err.println("Attempting to read datagram from key: " + key); DatagramChannel datagramChannel = (DatagramChannel) key.channel(); ByteBuffer buf = ByteBuffer.allocate(100); SocketAddress sa = datagramChannel.receive(buf); @@ -234,7 +268,7 @@ static boolean checkUnexpectedWakeup(Set selectedKeys) { byte[] bytes = new byte[buf.remaining()]; buf.get(bytes); String message = new String(bytes); - System.out.format("received %s at %s from %s%n", message, datagramChannel.getLocalAddress(), sa); + System.err.format("received %s at %s from %s%n", message, datagramChannel.getLocalAddress(), sa); // If any received data contains the message from sendDatagram then return false if (message.contains(GREETINGS_MESSAGE)) { @@ -243,7 +277,7 @@ static boolean checkUnexpectedWakeup(Set selectedKeys) { } } catch (IOException io) { - System.out.println("Unable to read from datagram " + io); + System.err.println("Unable to read from datagram " + io); } } return true; diff --git a/test/jdk/java/nio/channels/DatagramChannel/SendReceiveMaxSize.java b/test/jdk/java/nio/channels/DatagramChannel/SendReceiveMaxSize.java index 31407ecb49359..8d74fd8a387a3 100644 --- a/test/jdk/java/nio/channels/DatagramChannel/SendReceiveMaxSize.java +++ b/test/jdk/java/nio/channels/DatagramChannel/SendReceiveMaxSize.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,6 +37,7 @@ import jdk.test.lib.NetworkConfiguration; import jdk.test.lib.Platform; import jdk.test.lib.net.IPSupport; +import org.testng.Assert; import org.testng.annotations.BeforeTest; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; @@ -46,6 +47,7 @@ import java.net.Inet6Address; import java.net.InetAddress; import java.net.InetSocketAddress; +import java.net.SocketAddress; import java.nio.ByteBuffer; import java.nio.channels.DatagramChannel; import java.util.ArrayList; @@ -139,7 +141,9 @@ public void testSendReceiveMaxSize(DatagramChannelSupplier supplier, int capacit var addr = new InetSocketAddress(host, port); try (var sender = supplier.open()) { - sender.bind(null); + sender.bind(new InetSocketAddress(host, 0)); + System.out.format("testSendReceiveMaxSize: sender: %s -> receiver: %s%n", + sender.getLocalAddress(), receiver.getLocalAddress()); if (!Platform.isOSX()) { if (sender.getOption(SO_SNDBUF) < capacity) sender.setOption(SO_SNDBUF, capacity); @@ -150,7 +154,18 @@ public void testSendReceiveMaxSize(DatagramChannelSupplier supplier, int capacit var sendBuf = ByteBuffer.wrap(testData); sender.send(sendBuf, addr); var receiveBuf = ByteBuffer.allocate(capacity); - receiver.receive(receiveBuf); + SocketAddress src; + int count = 0; + do { + receiveBuf.clear(); + src = receiver.receive(receiveBuf); + if (sender.getLocalAddress().equals(src)) break; + System.out.println("step1: received unexpected datagram from: " + src); + System.out.println("\texpected: " + sender.getLocalAddress()); + if (++count > 10) { + throw new AssertionError("too many unexpected messages"); + } + } while (true); sendBuf.flip(); receiveBuf.flip(); @@ -167,7 +182,17 @@ public void testSendReceiveMaxSize(DatagramChannelSupplier supplier, int capacit sendBuf = ByteBuffer.wrap(testData); sender.send(sendBuf, addr); receiveBuf = ByteBuffer.allocate(capacity - 1); - receiver.receive(receiveBuf); + count = 0; + do { + receiveBuf.clear(); + src = receiver.receive(receiveBuf); + if (sender.getLocalAddress().equals(src)) break; + System.out.println("step1: received unexpected datagram from: " + src); + System.out.println("\texpected: " + sender.getLocalAddress()); + if (++count > 10) { + throw new AssertionError("too many unexpected messages"); + } + } while (true); sendBuf.flip(); receiveBuf.flip(); diff --git a/test/jdk/java/nio/channels/DatagramChannel/Sender.java b/test/jdk/java/nio/channels/DatagramChannel/Sender.java index 8ab4268e3a47a..fcecdf9d79aa9 100644 --- a/test/jdk/java/nio/channels/DatagramChannel/Sender.java +++ b/test/jdk/java/nio/channels/DatagramChannel/Sender.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,9 @@ /* @test * @bug 4669040 8130394 * @summary Test DatagramChannel subsequent receives with no datagram ready + * @library /test/lib + * @build jdk.test.lib.Platform Sender + * @run main Sender * @author Mike McCloskey */ @@ -36,6 +39,8 @@ import java.nio.ByteOrder; import java.nio.channels.DatagramChannel; +import jdk.test.lib.Platform; + public class Sender { static PrintStream log = System.err; @@ -46,25 +51,26 @@ public static void main(String[] args) throws Exception { } static void test() throws Exception { - Server server = new Server(); - Client client = new Client(server.port()); + try (Server server = new Server()) { + Client client = new Client(server.port()); - Thread serverThread = new Thread(server); - serverThread.start(); + Thread serverThread = new Thread(server); + serverThread.start(); - Thread clientThread = new Thread(client); - clientThread.start(); + Thread clientThread = new Thread(client); + clientThread.start(); - serverThread.join(); - clientThread.join(); + serverThread.join(); + clientThread.join(); - server.throwException(); - client.throwException(); + server.throwException(); + client.throwException(); + } } public static class Client implements Runnable { final int port; - Exception e = null; + volatile Exception e = null; Client(int port) { this.port = port; @@ -76,14 +82,17 @@ void throwException() throws Exception { } public void run() { - try { - DatagramChannel dc = DatagramChannel.open(); + try (DatagramChannel dc = DatagramChannel.open()) { ByteBuffer bb = ByteBuffer.allocateDirect(12); bb.order(ByteOrder.BIG_ENDIAN); bb.putInt(1).putLong(1); bb.flip(); InetAddress address = InetAddress.getLocalHost(); InetSocketAddress isa = new InetSocketAddress(address, port); + if (Platform.isOSX()) { + // avoid binding on wildcard on macOS + dc.bind(new InetSocketAddress(address, 0)); + } dc.connect(isa); clientISA = dc.getLocalAddress(); dc.write(bb); @@ -93,12 +102,16 @@ public void run() { } } - public static class Server implements Runnable { + public static class Server implements Runnable, AutoCloseable { final DatagramChannel dc; - Exception e = null; + volatile Exception e = null; Server() throws IOException { - dc = DatagramChannel.open().bind(new InetSocketAddress(0)); + // avoid binding to wildcard address on macOS + InetSocketAddress lo = Platform.isOSX() + ? new InetSocketAddress(InetAddress.getLocalHost(), 0) + : new InetSocketAddress(0); + dc = DatagramChannel.open().bind(lo); } int port() { @@ -149,6 +162,11 @@ public void run() { e = ex; } } + + @Override + public void close() throws IOException { + dc.close(); + } } } From 6460b300487071bcf98f5ac70d9c0a6fd6b94083 Mon Sep 17 00:00:00 2001 From: Damon Nguyen Date: Mon, 19 Aug 2024 16:43:43 +0000 Subject: [PATCH 344/353] 8321140: Add comment to note difference in Metal's JButton margins Reviewed-by: honkar, aivanov --- .../swing/plaf/basic/BasicLookAndFeel.java | 4 +- .../swing/plaf/metal/MetalLookAndFeel.java | 51 ++++++++++++++----- 2 files changed, 42 insertions(+), 13 deletions(-) diff --git a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicLookAndFeel.java b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicLookAndFeel.java index 999e7f923c744..4041bfca71435 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicLookAndFeel.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicLookAndFeel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -727,6 +727,8 @@ public Object createValue(UIDefaults table) { "Button.highlight", controlLtHighlight, "Button.border", buttonBorder, "Button.margin", new InsetsUIResource(2, 14, 2, 14), + // The above margin has vastly larger horizontal values when + // compared to other look and feels that don't rely on these values "Button.textIconGap", 4, "Button.textShiftOffset", zero, "Button.focusInputMap", new UIDefaults.LazyInputMap(new Object[] { 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 98747bbd2dc95..e46091c523cb6 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,28 +25,53 @@ package javax.swing.plaf.metal; -import java.awt.*; +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Frame; +import java.awt.Insets; +import java.awt.Toolkit; +import java.awt.Window; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; -import javax.swing.plaf.*; -import javax.swing.*; -import javax.swing.plaf.basic.*; -import javax.swing.text.DefaultEditorKit; - -import java.awt.Color; import java.lang.ref.ReferenceQueue; import java.lang.ref.WeakReference; - import java.security.AccessController; -import sun.awt.*; +import javax.swing.ButtonModel; +import javax.swing.DefaultButtonModel; +import javax.swing.Icon; +import javax.swing.ImageIcon; +import javax.swing.JComponent; +import javax.swing.JDialog; +import javax.swing.JFrame; +import javax.swing.JRootPane; +import javax.swing.JTextField; +import javax.swing.JToggleButton; +import javax.swing.LayoutStyle; +import javax.swing.LookAndFeel; +import javax.swing.SwingConstants; +import javax.swing.SwingUtilities; +import javax.swing.UIDefaults; +import javax.swing.UIManager; +import javax.swing.plaf.BorderUIResource; +import javax.swing.plaf.ColorUIResource; +import javax.swing.plaf.FontUIResource; +import javax.swing.plaf.InsetsUIResource; +import javax.swing.plaf.UIResource; +import javax.swing.plaf.basic.BasicLookAndFeel; +import javax.swing.text.DefaultEditorKit; + +import sun.awt.AppContext; +import sun.awt.OSInfo; +import sun.awt.SunToolkit; import sun.security.action.GetPropertyAction; import sun.swing.DefaultLayoutStyle; -import static javax.swing.UIDefaults.LazyValue; - import sun.swing.SwingAccessor; import sun.swing.SwingUtilities2; +import static javax.swing.UIDefaults.LazyValue; + /** * The Java Look and Feel, otherwise known as Metal. *

    @@ -782,6 +807,8 @@ protected void initComponentDefaults(UIDefaults table) { "SPACE", "pressed", "released SPACE", "released" }), + // Button default margin is (2, 14, 2, 14), defined in + // BasicLookAndFeel via "Button.margin" UI property. "CheckBox.disabledText", inactiveControlTextColor, "Checkbox.select", controlShadow, From c7690c34c2d7bff11501188266b7be7a486c1bd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Walln=C3=B6fer?= Date: Mon, 19 Aug 2024 17:47:25 +0000 Subject: [PATCH 345/353] 8338190: TOC vertical offsets not updated when document size changes Reviewed-by: jjg --- .../doclets/formats/html/resources/script.js.template | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script.js.template b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script.js.template index 71ef847670822..633f453bc43b1 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script.js.template +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script.js.template @@ -461,7 +461,7 @@ document.addEventListener("DOMContentLoaded", function(e) { }) } // Resize handler - function handleResize(e) { + new ResizeObserver((entries) => { if (expanded) { if (windowWidth !== window.innerWidth) { collapse(); @@ -475,7 +475,5 @@ document.addEventListener("DOMContentLoaded", function(e) { handleScroll(); } setTopMargin(); - } - window.addEventListener("orientationchange", handleResize); - window.addEventListener("resize", handleResize); + }).observe(document.body); }); From 55851a312baaea5af14c04fb1b436313fe0deac7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Walln=C3=B6fer?= Date: Mon, 19 Aug 2024 18:05:37 +0000 Subject: [PATCH 346/353] 8281533: Odd "preview" label in link/linkplain Reviewed-by: jjg --- .../doclets/formats/html/HtmlLinkFactory.java | 88 +++++++++++-------- .../formats/html/taglets/LinkTaglet.java | 1 + .../doclet/testPreview/TestPreview.java | 17 +++- .../doclet/testPreview/api/preview/Core.java | 9 +- 4 files changed, 73 insertions(+), 42 deletions(-) diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlLinkFactory.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlLinkFactory.java index 8e0c010dd1ae4..494d5e22d6e10 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlLinkFactory.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlLinkFactory.java @@ -52,6 +52,7 @@ import jdk.javadoc.internal.html.Content; import jdk.javadoc.internal.html.ContentBuilder; import jdk.javadoc.internal.html.Entity; +import jdk.javadoc.internal.html.HtmlId; import jdk.javadoc.internal.html.HtmlTag; import jdk.javadoc.internal.html.HtmlTree; import jdk.javadoc.internal.html.Text; @@ -296,26 +297,12 @@ protected Content getClassLink(HtmlLinkInfo linkInfo) { Content link = new ContentBuilder(); if (utils.isIncluded(typeElement)) { if (configuration.isGeneratedDoc(typeElement) && !utils.hasHiddenTag(typeElement)) { - DocPath filename = getPath(linkInfo); + DocPath fileName = getPath(linkInfo); if (linkInfo.linkToSelf() || typeElement != m_writer.getCurrentPageElement()) { link.add(m_writer.links.createLink( - filename.fragment(linkInfo.getFragment()), - label, - linkInfo.getStyle(), - title)); - Content spacer = Text.EMPTY; - if (flags.contains(ElementFlag.PREVIEW)) { - link.add(HtmlTree.SUP(m_writer.links.createLink( - filename.fragment(m_writer.htmlIds.forPreviewSection(previewTarget).name()), - m_writer.contents.previewMark))); - spacer = Entity.NO_BREAK_SPACE; - } - if (flags.contains(ElementFlag.RESTRICTED)) { - link.add(spacer); - link.add(HtmlTree.SUP(m_writer.links.createLink( - filename.fragment(m_writer.htmlIds.forRestrictedSection(restrictedTarget).name()), - m_writer.contents.restrictedMark))); - } + fileName.fragment(linkInfo.getFragment()), + label, linkInfo.getStyle(), title)); + addSuperscript(link, flags, fileName, null, previewTarget, restrictedTarget); return link; } } @@ -325,38 +312,61 @@ protected Content getClassLink(HtmlLinkInfo linkInfo) { label, linkInfo.getStyle(), true); if (crossLink != null) { link.add(crossLink); - Content spacer = Text.EMPTY; - if (flags.contains(ElementFlag.PREVIEW)) { - link.add(HtmlTree.SUP(m_writer.getCrossClassLink( - typeElement, - m_writer.htmlIds.forPreviewSection(previewTarget).name(), - m_writer.contents.previewMark, - null, false))); - spacer = Entity.NO_BREAK_SPACE; - } - if (flags.contains(ElementFlag.RESTRICTED)) { - link.add(spacer); - link.add(HtmlTree.SUP(m_writer.getCrossClassLink( - typeElement, - m_writer.htmlIds.forRestrictedSection(restrictedTarget).name(), - m_writer.contents.restrictedMark, - null, false))); - } + addSuperscript(link, flags, null, typeElement, previewTarget, restrictedTarget); return link; } } // Can't link so just write label. link.add(label); + addSuperscript(link, flags, null, null, previewTarget, restrictedTarget); + return link; + } + + /** + * Adds PREVIEW and RESTRICTED superscript labels. Depending on the parameter values, + * labels will be formatted as local or external links or plain text. + * + * @param content the content to add to + * @param flags the flags + * @param fileName file name to link to, or null if no local link target + * @param typeElement external type to link to, or null if no external link + * @param previewTarget preview link target element + * @param restrictedTarget restricted link target element + */ + private void addSuperscript(Content content, Set flags, DocPath fileName, TypeElement typeElement, + Element previewTarget, ExecutableElement restrictedTarget) { Content spacer = Text.EMPTY; if (flags.contains(ElementFlag.PREVIEW)) { - link.add(HtmlTree.SUP(m_writer.contents.previewMark)); + content.add(HtmlTree.SUP(getSuperscript(fileName, typeElement, + m_writer.htmlIds.forPreviewSection(previewTarget), + m_writer.contents.previewMark))); spacer = Entity.NO_BREAK_SPACE; } if (flags.contains(ElementFlag.RESTRICTED)) { - link.add(spacer); - link.add(HtmlTree.SUP(m_writer.contents.restrictedMark)); + content.add(spacer); + content.add(HtmlTree.SUP(getSuperscript(fileName, typeElement, + m_writer.htmlIds.forRestrictedSection(restrictedTarget), + m_writer.contents.restrictedMark))); + } + } + + /** + * Returns PREVIEW or RESTRICTED superscript as either local or external link or as plain text. + * + * @param fileName local file name to link to, or null if no local link target + * @param typeElement external type to link to, or null if no external link + * @param id the id fragment to link to + * @param label the label content + * @return superscript content + */ + private Content getSuperscript(DocPath fileName, TypeElement typeElement, HtmlId id, Content label) { + if (fileName != null) { + return m_writer.links.createLink(fileName.fragment(id.name()), label); + } else if (typeElement != null) { + return (m_writer.getCrossClassLink(typeElement, id.name(), label, null, false)); + } else { + return label; } - return link; } /** diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/LinkTaglet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/LinkTaglet.java index b16a1490b6303..15e88da5baeb5 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/LinkTaglet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/LinkTaglet.java @@ -224,6 +224,7 @@ Content linkSeeReferenceOutput(Element holder, labelContent = plainOrCode(isPlain, Text.of(utils.getSimpleName(refClass))); } return htmlWriter.getLink(new HtmlLinkInfo(config, HtmlLinkInfo.Kind.PLAIN, refClass) + .skipPreview(isPlain) .label(labelContent)); } else if (refMem == null) { // This is a fragment reference since refClass and refFragment are not null but refMem is null. diff --git a/test/langtools/jdk/javadoc/doclet/testPreview/TestPreview.java b/test/langtools/jdk/javadoc/doclet/testPreview/TestPreview.java index a59e68d25a063..369312d690a17 100644 --- a/test/langtools/jdk/javadoc/doclet/testPreview/TestPreview.java +++ b/test/langtools/jdk/javadoc/doclet/testPreview/TestPreview.java @@ -24,7 +24,7 @@ /* * @test * @bug 8250768 8261976 8277300 8282452 8287597 8325325 8325874 8297879 - * 8331947 + * 8331947 8281533 * @summary test generated docs for items declared using preview * @library ../../lib * @modules jdk.javadoc/jdk.javadoc.internal.tool @@ -156,7 +156,20 @@ public void testPreviewAPIJavadoc() {

  • java.base
  • preview
  • Core
  • - """); + """, + """ + """, + """ +
  • CoreRecord<\ + /a>PREVIEW<\ + /li> +
  • core record
  • """); // 8331947: Support preview features without JEP should not be included in Preview API page checkOutput("preview-list.html", false, "supportMethod"); diff --git a/test/langtools/jdk/javadoc/doclet/testPreview/api/preview/Core.java b/test/langtools/jdk/javadoc/doclet/testPreview/api/preview/Core.java index d2cf31c2e898b..1b23d20228523 100644 --- a/test/langtools/jdk/javadoc/doclet/testPreview/api/preview/Core.java +++ b/test/langtools/jdk/javadoc/doclet/testPreview/api/preview/Core.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,13 @@ import jdk.internal.javac.PreviewFeature; import jdk.internal.javac.PreviewFeature.Feature; +/** + * Preview feature. Links: {@link CoreRecord}, {@link CoreRecord core record}, + * {@linkplain CoreRecord}, {@linkplain CoreRecord core record}. + * + * @see CoreRecord + * @see CoreRecord core record + */ @PreviewFeature(feature=Feature.TEST) public class Core { } From 68d1f5c33bf3f64f44f8a10c2f9e4007cfd07d2b Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Tue, 20 Aug 2024 05:43:04 +0000 Subject: [PATCH 347/353] 8338543: ClassBuilder withMethod builders should cache the method type symbol Reviewed-by: asotona --- .../classes/java/lang/classfile/ClassBuilder.java | 5 +---- .../internal/classfile/impl/ChainedClassBuilder.java | 10 ++++++++++ .../internal/classfile/impl/DirectClassBuilder.java | 8 ++++++++ 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/java.base/share/classes/java/lang/classfile/ClassBuilder.java b/src/java.base/share/classes/java/lang/classfile/ClassBuilder.java index 7ad6e94df3fce..98371c9e15a61 100644 --- a/src/java.base/share/classes/java/lang/classfile/ClassBuilder.java +++ b/src/java.base/share/classes/java/lang/classfile/ClassBuilder.java @@ -276,10 +276,7 @@ default ClassBuilder withMethodBody(String name, MethodTypeDesc descriptor, int methodFlags, Consumer handler) { - return withMethodBody(constantPool().utf8Entry(name), - constantPool().utf8Entry(descriptor), - methodFlags, - handler); + return withMethod(name, descriptor, methodFlags, mb -> mb.withCode(handler)); } /** diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedClassBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedClassBuilder.java index d31debf6f35a5..50c1590e8a271 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedClassBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedClassBuilder.java @@ -24,6 +24,7 @@ */ package jdk.internal.classfile.impl; +import java.lang.constant.MethodTypeDesc; import java.util.function.Consumer; import java.lang.classfile.*; @@ -78,6 +79,15 @@ public ClassBuilder withMethod(Utf8Entry name, Utf8Entry descriptor, int flags, return this; } + @Override + public ClassBuilder withMethod(String name, MethodTypeDesc descriptor, int flags, Consumer handler) { + var mb = new BufferedMethodBuilder(terminal.constantPool, terminal.context, + constantPool().utf8Entry(name), constantPool().utf8Entry(descriptor), flags, null); + mb.mDesc = descriptor; + consumer.accept(mb.run(handler).toModel()); + return this; + } + @Override public ClassBuilder transformMethod(MethodModel method, MethodTransform transform) { BufferedMethodBuilder builder = new BufferedMethodBuilder(terminal.constantPool, terminal.context, diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectClassBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectClassBuilder.java index 21fde0f6002df..0d61895fe9f7f 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectClassBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectClassBuilder.java @@ -26,6 +26,7 @@ package jdk.internal.classfile.impl; import java.lang.constant.ConstantDescs; +import java.lang.constant.MethodTypeDesc; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -106,6 +107,13 @@ public ClassBuilder withMethod(Utf8Entry name, .run(handler)); } + @Override + public ClassBuilder withMethod(String name, MethodTypeDesc descriptor, int flags, Consumer handler) { + var method = new DirectMethodBuilder(constantPool, context, constantPool.utf8Entry(name), constantPool.utf8Entry(descriptor), flags, null); + method.mDesc = descriptor; + return withMethod(method.run(handler)); + } + @Override public ClassBuilder transformMethod(MethodModel method, MethodTransform transform) { DirectMethodBuilder builder = new DirectMethodBuilder(constantPool, context, method.methodName(), From 9775d57168695dc0d758e017fe5069d93d593f3e Mon Sep 17 00:00:00 2001 From: Stefan Karlsson Date: Tue, 20 Aug 2024 06:15:56 +0000 Subject: [PATCH 348/353] 8338139: {ClassLoading,Memory}MXBean::isVerbose methods are inconsistent with their setVerbose methods Co-authored-by: David Holmes Reviewed-by: lmesnik, dcubed, dholmes --- .../share/services/classLoadingService.cpp | 18 +++- .../share/services/classLoadingService.hpp | 4 +- src/hotspot/share/services/memoryService.cpp | 17 +++- src/hotspot/share/services/memoryService.hpp | 4 +- .../TestVerboseClassLoading.java | 84 +++++++++++++++++++ .../MemoryMXBean/TestVerboseMemory.java | 79 +++++++++++++++++ 6 files changed, 200 insertions(+), 6 deletions(-) create mode 100644 test/jdk/java/lang/management/ClassLoadingMXBean/TestVerboseClassLoading.java create mode 100644 test/jdk/java/lang/management/MemoryMXBean/TestVerboseMemory.java diff --git a/src/hotspot/share/services/classLoadingService.cpp b/src/hotspot/share/services/classLoadingService.cpp index 2df8d12278d9a..09da45dc079d2 100644 --- a/src/hotspot/share/services/classLoadingService.cpp +++ b/src/hotspot/share/services/classLoadingService.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -128,6 +128,22 @@ bool ClassLoadingService::set_verbose(bool verbose) { return verbose; } +bool ClassLoadingService::get_verbose() { + for (LogTagSet* ts = LogTagSet::first(); ts != nullptr; ts = ts->next()) { + // set_verbose looks for a non-exact match for class+load, + // so look for all tag sets that match class+load* + if (ts->contains(LogTag::_class) && + ts->contains(LogTag::_load)) { + LogLevelType l = ts->level_for(LogConfiguration::StdoutLog); + if (l != LogLevel::Info && l != LogLevel::Debug && l != LogLevel::Trace) { + return false; + } + } + } + + return true; +} + // 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"); diff --git a/src/hotspot/share/services/classLoadingService.hpp b/src/hotspot/share/services/classLoadingService.hpp index f9db3da50918b..3aeb3f556a5e2 100644 --- a/src/hotspot/share/services/classLoadingService.hpp +++ b/src/hotspot/share/services/classLoadingService.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -53,6 +53,7 @@ class ClassLoadingService : public AllStatic { public: static void init() NOT_MANAGEMENT_RETURN; static bool set_verbose(bool verbose) NOT_MANAGEMENT_RETURN_(false); + static bool get_verbose() NOT_MANAGEMENT_RETURN_(false); static void reset_trace_class_unloading() NOT_MANAGEMENT_RETURN; static jlong loaded_class_count() NOT_MANAGEMENT_RETURN_(0L); static jlong unloaded_class_count() NOT_MANAGEMENT_RETURN_(0L); @@ -63,7 +64,6 @@ class ClassLoadingService : public AllStatic { 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/memoryService.cpp b/src/hotspot/share/services/memoryService.cpp index 21b773e204e63..de30bee12bdd3 100644 --- a/src/hotspot/share/services/memoryService.cpp +++ b/src/hotspot/share/services/memoryService.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -202,6 +202,21 @@ bool MemoryService::set_verbose(bool verbose) { return verbose; } +bool MemoryService::get_verbose() { + for (LogTagSet* ts = LogTagSet::first(); ts != nullptr; ts = ts->next()) { + // set_verbose only sets gc and not gc*, so check for an exact match + const bool is_gc_exact_match = ts->contains(LogTag::_gc) && ts->ntags() == 1; + if (is_gc_exact_match) { + LogLevelType l = ts->level_for(LogConfiguration::StdoutLog); + if (l == LogLevel::Info || l == LogLevel::Debug || l == LogLevel::Trace) { + return true; + } + } + } + + return false; +} + Handle MemoryService::create_MemoryUsage_obj(MemoryUsage usage, TRAPS) { InstanceKlass* ik = Management::java_lang_management_MemoryUsage_klass(CHECK_NH); diff --git a/src/hotspot/share/services/memoryService.hpp b/src/hotspot/share/services/memoryService.hpp index 2d28f25c69519..d10c3d2e9d96e 100644 --- a/src/hotspot/share/services/memoryService.hpp +++ b/src/hotspot/share/services/memoryService.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -106,8 +106,8 @@ class MemoryService : public AllStatic { GCCause::Cause cause, bool allMemoryPoolsAffected, const char* notificationMessage = nullptr); - static bool get_verbose() { return log_is_enabled(Info, gc); } static bool set_verbose(bool verbose); + static bool get_verbose(); // Create an instance of java/lang/management/MemoryUsage static Handle create_MemoryUsage_obj(MemoryUsage usage, TRAPS); diff --git a/test/jdk/java/lang/management/ClassLoadingMXBean/TestVerboseClassLoading.java b/test/jdk/java/lang/management/ClassLoadingMXBean/TestVerboseClassLoading.java new file mode 100644 index 0000000000000..4e865f24b2901 --- /dev/null +++ b/test/jdk/java/lang/management/ClassLoadingMXBean/TestVerboseClassLoading.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8338139 + * @summary Basic unit test of ClassLoadingMXBean.set/isVerbose() when + * related unified logging is enabled. + * + * @run main/othervm -Xlog:class+load=trace:file=vm.log TestVerboseClassLoading false + * @run main/othervm -Xlog:class+load=debug:file=vm.log TestVerboseClassLoading false + * @run main/othervm -Xlog:class+load=info:file=vm.log TestVerboseClassLoading false + * + * @run main/othervm -Xlog:class+load=trace TestVerboseClassLoading false + * @run main/othervm -Xlog:class+load=debug TestVerboseClassLoading false + * @run main/othervm -Xlog:class+load=info TestVerboseClassLoading false + * @run main/othervm -Xlog:class+load=warning TestVerboseClassLoading false + * @run main/othervm -Xlog:class+load=error TestVerboseClassLoading false + * @run main/othervm -Xlog:class+load=off TestVerboseClassLoading false + * + * @run main/othervm -Xlog:class+load*=trace TestVerboseClassLoading true + * @run main/othervm -Xlog:class+load*=debug TestVerboseClassLoading true + * @run main/othervm -Xlog:class+load*=info TestVerboseClassLoading true + * @run main/othervm -Xlog:class+load*=warning TestVerboseClassLoading false + * @run main/othervm -Xlog:class+load*=error TestVerboseClassLoading false + * @run main/othervm -Xlog:class+load*=off TestVerboseClassLoading false + * + * @run main/othervm -Xlog:class+load*=info,class+load+cause=trace TestVerboseClassLoading true + * @run main/othervm -Xlog:class+load*=info,class+load+cause=debug TestVerboseClassLoading true + * @run main/othervm -Xlog:class+load*=info,class+load+cause=info TestVerboseClassLoading true + * @run main/othervm -Xlog:class+load*=info,class+load+cause=warning TestVerboseClassLoading false + * @run main/othervm -Xlog:class+load*=info,class+load+cause=error TestVerboseClassLoading false + * @run main/othervm -Xlog:class+load*=info,class+load+cause=off TestVerboseClassLoading false + * + * @run main/othervm -Xlog:all=trace:file=vm.log TestVerboseClassLoading false + */ + +import java.lang.management.ManagementFactory; +import java.lang.management.ClassLoadingMXBean; + +public class TestVerboseClassLoading { + + public static void main(String[] args) throws Exception { + ClassLoadingMXBean mxBean = ManagementFactory.getClassLoadingMXBean(); + boolean expected = Boolean.parseBoolean(args[0]); + boolean initial = mxBean.isVerbose(); + if (expected != initial) { + throw new Error("Initial verbosity setting was unexpectedly " + initial); + } + mxBean.setVerbose(false); + if (mxBean.isVerbose()) { + throw new Error("Verbosity was still enabled"); + } + mxBean.setVerbose(true); + if (!mxBean.isVerbose()) { + throw new Error("Verbosity was still disabled"); + } + // Turn off again as a double-check and also to avoid excessive logging + mxBean.setVerbose(false); + if (mxBean.isVerbose()) { + throw new Error("Verbosity was still enabled"); + } + } +} diff --git a/test/jdk/java/lang/management/MemoryMXBean/TestVerboseMemory.java b/test/jdk/java/lang/management/MemoryMXBean/TestVerboseMemory.java new file mode 100644 index 0000000000000..7d34c45036b18 --- /dev/null +++ b/test/jdk/java/lang/management/MemoryMXBean/TestVerboseMemory.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8338139 + * @summary Basic unit test of TestVerboseMemory.set/isVerbose() when + * related unified logging is enabled. + * + * @run main/othervm -Xlog:gc=trace:file=vm.log TestVerboseMemory false + * @run main/othervm -Xlog:gc=debug:file=vm.log TestVerboseMemory false + * @run main/othervm -Xlog:gc=info:file=vm.log TestVerboseMemory false + * + * @run main/othervm -Xlog:gc=off TestVerboseMemory false + * @run main/othervm -Xlog:gc=error TestVerboseMemory false + * @run main/othervm -Xlog:gc=warning TestVerboseMemory false + * + * @run main/othervm -Xlog:gc=info TestVerboseMemory true + * @run main/othervm -Xlog:gc=trace TestVerboseMemory true + * @run main/othervm -Xlog:gc=debug TestVerboseMemory true + * + * @run main/othervm -Xlog:gc*=info TestVerboseMemory true + * @run main/othervm -Xlog:gc*=debug TestVerboseMemory true + * @run main/othervm -Xlog:gc*=trace TestVerboseMemory true + * + * @run main/othervm -Xlog:gc=info,gc+init=off TestVerboseMemory true + * @run main/othervm -Xlog:gc=off,gc+init=info TestVerboseMemory false + * @run main/othervm -Xlog:gc,gc+init TestVerboseMemory true + * + * @run main/othervm -Xlog:all=trace:file=vm.log TestVerboseMemory false + */ + +import java.lang.management.ManagementFactory; +import java.lang.management.MemoryMXBean; + +public class TestVerboseMemory { + + public static void main(String[] args) throws Exception { + MemoryMXBean mxBean = ManagementFactory.getMemoryMXBean(); + boolean expected = Boolean.parseBoolean(args[0]); + boolean initial = mxBean.isVerbose(); + if (expected != initial) { + throw new Error("Initial verbosity setting was unexpectedly " + initial); + } + mxBean.setVerbose(false); + if (mxBean.isVerbose()) { + throw new Error("Verbosity was still enabled"); + } + mxBean.setVerbose(true); + if (!mxBean.isVerbose()) { + throw new Error("Verbosity was still disabled"); + } + // Turn off again as a double-check and also to avoid excessive logging + mxBean.setVerbose(false); + if (mxBean.isVerbose()) { + throw new Error("Verbosity was still enabled"); + } + } +} From b9d49dcef22ab81a087d890bbac0329a5244a2ef Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Tue, 20 Aug 2024 08:40:45 +0000 Subject: [PATCH 349/353] 8337981: ShenandoahHeap::is_in should check for alive regions Reviewed-by: rkennke, wkemper --- .../share/gc/shenandoah/shenandoahAsserts.cpp | 46 ++++++++++++------- .../share/gc/shenandoah/shenandoahAsserts.hpp | 16 +++---- .../shenandoahCollectionSet.inline.hpp | 4 +- .../gc/shenandoah/shenandoahConcurrentGC.cpp | 2 +- .../shenandoahForwarding.inline.hpp | 2 +- .../share/gc/shenandoah/shenandoahHeap.cpp | 15 ++++-- .../share/gc/shenandoah/shenandoahHeap.hpp | 2 + .../gc/shenandoah/shenandoahMarkBitMap.cpp | 2 +- .../shenandoah/shenandoahMarkingContext.hpp | 4 +- .../shenandoahMarkingContext.inline.hpp | 12 ++++- .../shenandoahReferenceProcessor.cpp | 31 +++++++++---- .../gc/shenandoah/shenandoahVerifier.cpp | 35 ++++++++------ 12 files changed, 111 insertions(+), 60 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahAsserts.cpp b/src/hotspot/share/gc/shenandoah/shenandoahAsserts.cpp index 8235b59b80e56..1539c7c2c5daa 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahAsserts.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahAsserts.cpp @@ -37,7 +37,7 @@ void print_raw_memory(ShenandoahMessageBuffer &msg, void* loc) { // should be in heap, in known committed region, within that region. ShenandoahHeap* heap = ShenandoahHeap::heap(); - if (!heap->is_in(loc)) return; + if (!heap->is_in_reserved(loc)) return; ShenandoahHeapRegion* r = heap->heap_region_containing(loc); if (r != nullptr && r->is_committed()) { @@ -77,7 +77,7 @@ void ShenandoahAsserts::print_obj(ShenandoahMessageBuffer& msg, oop obj) { void ShenandoahAsserts::print_non_obj(ShenandoahMessageBuffer& msg, void* loc) { ShenandoahHeap* heap = ShenandoahHeap::heap(); - if (heap->is_in(loc)) { + if (heap->is_in_reserved(loc)) { msg.append(" inside Java heap\n"); ShenandoahHeapRegion *r = heap->heap_region_containing(loc); stringStream ss; @@ -96,7 +96,7 @@ void ShenandoahAsserts::print_non_obj(ShenandoahMessageBuffer& msg, void* loc) { void ShenandoahAsserts::print_obj_safe(ShenandoahMessageBuffer& msg, void* loc) { ShenandoahHeap* heap = ShenandoahHeap::heap(); msg.append(" " PTR_FORMAT " - safe print, no details\n", p2i(loc)); - if (heap->is_in(loc)) { + if (heap->is_in_reserved(loc)) { ShenandoahHeapRegion* r = heap->heap_region_containing(loc); if (r != nullptr) { stringStream ss; @@ -113,7 +113,7 @@ void ShenandoahAsserts::print_failure(SafeLevel level, oop obj, void* interior_l ShenandoahHeap* heap = ShenandoahHeap::heap(); ResourceMark rm; - bool loc_in_heap = (loc != nullptr && heap->is_in(loc)); + bool loc_in_heap = (loc != nullptr && heap->is_in_reserved(loc)); ShenandoahMessageBuffer msg("%s; %s\n\n", phase, label); @@ -166,22 +166,22 @@ void ShenandoahAsserts::print_failure(SafeLevel level, oop obj, void* interior_l report_vm_error(file, line, msg.buffer()); } -void ShenandoahAsserts::assert_in_heap(void* interior_loc, oop obj, const char *file, int line) { +void ShenandoahAsserts::assert_in_heap_bounds(void* interior_loc, oop obj, const char *file, int line) { ShenandoahHeap* heap = ShenandoahHeap::heap(); - if (!heap->is_in(obj)) { - print_failure(_safe_unknown, obj, interior_loc, nullptr, "Shenandoah assert_in_heap failed", - "oop must point to a heap address", + if (!heap->is_in_reserved(obj)) { + print_failure(_safe_unknown, obj, interior_loc, nullptr, "Shenandoah assert_in_heap_bounds failed", + "oop must be in heap bounds", file, line); } } -void ShenandoahAsserts::assert_in_heap_or_null(void* interior_loc, oop obj, const char *file, int line) { +void ShenandoahAsserts::assert_in_heap_bounds_or_null(void* interior_loc, oop obj, const char *file, int line) { ShenandoahHeap* heap = ShenandoahHeap::heap(); - if (obj != nullptr && !heap->is_in(obj)) { - print_failure(_safe_unknown, obj, interior_loc, nullptr, "Shenandoah assert_in_heap_or_null failed", - "oop must point to a heap address", + if (obj != nullptr && !heap->is_in_reserved(obj)) { + print_failure(_safe_unknown, obj, interior_loc, nullptr, "Shenandoah assert_in_heap_bounds_or_null failed", + "oop must be in heap bounds", file, line); } } @@ -191,9 +191,9 @@ void ShenandoahAsserts::assert_correct(void* interior_loc, oop obj, const char* // Step 1. Check that obj is correct. // After this step, it is safe to call heap_region_containing(). - if (!heap->is_in(obj)) { + if (!heap->is_in_reserved(obj)) { print_failure(_safe_unknown, obj, interior_loc, nullptr, "Shenandoah assert_correct failed", - "oop must point to a heap address", + "oop must be in heap bounds", file, line); } @@ -210,6 +210,12 @@ void ShenandoahAsserts::assert_correct(void* interior_loc, oop obj, const char* file,line); } + if (!heap->is_in(obj)) { + print_failure(_safe_unknown, obj, interior_loc, nullptr, "Shenandoah assert_correct failed", + "Object should be in active region area", + file, line); + } + oop fwd = ShenandoahForwarding::get_forwardee_raw_unchecked(obj); if (obj != fwd) { @@ -223,9 +229,9 @@ void ShenandoahAsserts::assert_correct(void* interior_loc, oop obj, const char* } // Step 2. Check that forwardee is correct - if (!heap->is_in(fwd)) { + if (!heap->is_in_reserved(fwd)) { print_failure(_safe_oop, obj, interior_loc, nullptr, "Shenandoah assert_correct failed", - "Forwardee must point to a heap address", + "Forwardee must be in heap bounds", file, line); } @@ -236,9 +242,15 @@ void ShenandoahAsserts::assert_correct(void* interior_loc, oop obj, const char* } // Step 3. Check that forwardee points to correct region + if (!heap->is_in(fwd)) { + print_failure(_safe_oop, obj, interior_loc, nullptr, "Shenandoah assert_correct failed", + "Forwardee should be in active region area", + file, line); + } + if (heap->heap_region_index_containing(fwd) == heap->heap_region_index_containing(obj)) { print_failure(_safe_all, obj, interior_loc, nullptr, "Shenandoah assert_correct failed", - "Non-trivial forwardee should in another region", + "Non-trivial forwardee should be in another region", file, line); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahAsserts.hpp b/src/hotspot/share/gc/shenandoah/shenandoahAsserts.hpp index c730eafb89d01..154edebcf3edc 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahAsserts.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahAsserts.hpp @@ -53,8 +53,8 @@ class ShenandoahAsserts { static void print_rp_failure(const char *label, BoolObjectClosure* actual, const char *file, int line); - static void assert_in_heap(void* interior_loc, oop obj, const char* file, int line); - static void assert_in_heap_or_null(void* interior_loc, oop obj, const char* file, int line); + static void assert_in_heap_bounds(void* interior_loc, oop obj, const char* file, int line); + static void assert_in_heap_bounds_or_null(void* interior_loc, oop obj, const char* file, int line); static void assert_in_correct_region(void* interior_loc, oop obj, const char* file, int line); static void assert_correct(void* interior_loc, oop obj, const char* file, int line); @@ -74,10 +74,10 @@ class ShenandoahAsserts { static void assert_heaplocked_or_safepoint(const char* file, int line); #ifdef ASSERT -#define shenandoah_assert_in_heap(interior_loc, obj) \ - ShenandoahAsserts::assert_in_heap(interior_loc, obj, __FILE__, __LINE__) -#define shenandoah_assert_in_heap_or_null(interior_loc, obj) \ - ShenandoahAsserts::assert_in_heap_or_null(interior_loc, obj, __FILE__, __LINE__) +#define shenandoah_assert_in_heap_bounds(interior_loc, obj) \ + ShenandoahAsserts::assert_in_heap_bounds(interior_loc, obj, __FILE__, __LINE__) +#define shenandoah_assert_in_heap_bounds_or_null(interior_loc, obj) \ + ShenandoahAsserts::assert_in_heap_bounds_or_null(interior_loc, obj, __FILE__, __LINE__) #define shenandoah_assert_in_correct_region(interior_loc, obj) \ ShenandoahAsserts::assert_in_correct_region(interior_loc, obj, __FILE__, __LINE__) @@ -164,8 +164,8 @@ class ShenandoahAsserts { #define shenandoah_assert_heaplocked_or_safepoint() \ ShenandoahAsserts::assert_heaplocked_or_safepoint(__FILE__, __LINE__) #else -#define shenandoah_assert_in_heap(interior_loc, obj) -#define shenandoah_assert_in_heap_or_null(interior_loc, obj) +#define shenandoah_assert_in_heap_bounds(interior_loc, obj) +#define shenandoah_assert_in_heap_bounds_or_null(interior_loc, obj) #define shenandoah_assert_in_correct_region(interior_loc, obj) #define shenandoah_assert_correct_if(interior_loc, obj, condition) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahCollectionSet.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahCollectionSet.inline.hpp index 6eb026561e46e..cceebae0b1c63 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahCollectionSet.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahCollectionSet.inline.hpp @@ -41,12 +41,12 @@ bool ShenandoahCollectionSet::is_in(ShenandoahHeapRegion* r) const { } bool ShenandoahCollectionSet::is_in(oop p) const { - shenandoah_assert_in_heap_or_null(nullptr, p); + shenandoah_assert_in_heap_bounds_or_null(nullptr, p); return is_in_loc(cast_from_oop(p)); } bool ShenandoahCollectionSet::is_in_loc(void* p) const { - assert(p == nullptr || _heap->is_in(p), "Must be in the heap"); + assert(p == nullptr || _heap->is_in_reserved(p), "Must be in the heap"); uintx index = ((uintx) p) >> _region_size_bytes_shift; // no need to subtract the bottom of the heap from p, // _biased_cset_map is biased diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp index 0301ef422a629..0e18b59103746 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp @@ -718,7 +718,7 @@ void ShenandoahEvacUpdateCleanupOopStorageRootsClosure::do_oop(oop* p) { const oop obj = RawAccess<>::oop_load(p); if (!CompressedOops::is_null(obj)) { if (!_mark_context->is_marked(obj)) { - shenandoah_assert_correct(p, obj); + // Note: The obj is dead here. Do not touch it, just clear. ShenandoahHeap::atomic_clear_oop(p, obj); } else if (_evac_in_progress && _heap->in_collection_set(obj)) { oop resolved = ShenandoahBarrierSet::resolve_forwarded_not_null(obj); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahForwarding.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahForwarding.inline.hpp index cf69eb67e4754..01294f9c8908b 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahForwarding.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahForwarding.inline.hpp @@ -32,7 +32,7 @@ #include "runtime/javaThread.hpp" inline oop ShenandoahForwarding::get_forwardee_raw(oop obj) { - shenandoah_assert_in_heap(nullptr, obj); + shenandoah_assert_in_heap_bounds(nullptr, obj); return get_forwardee_raw_unchecked(obj); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index 6f5fce53f85b5..a587cc417e319 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -730,9 +730,18 @@ size_t ShenandoahHeap::initial_capacity() const { } bool ShenandoahHeap::is_in(const void* p) const { - HeapWord* heap_base = (HeapWord*) base(); - HeapWord* last_region_end = heap_base + ShenandoahHeapRegion::region_size_words() * num_regions(); - return p >= heap_base && p < last_region_end; + if (is_in_reserved(p)) { + if (is_full_gc_move_in_progress()) { + // Full GC move is running, we do not have a consistent region + // information yet. But we know the pointer is in heap. + return true; + } + // Now check if we point to a live section in active region. + ShenandoahHeapRegion* r = heap_region_containing(p); + return (r->is_active() && p < r->top()); + } else { + return false; + } } void ShenandoahHeap::maybe_uncommit(double shrink_before, size_t shrink_until) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp index 81b1c3df6f411..1ee1f9dfc88be 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp @@ -493,6 +493,8 @@ class ShenandoahHeap : public CollectedHeap, public ShenandoahSpaceInfo { public: bool is_maximal_no_gc() const override shenandoah_not_implemented_return(false); + // Check the pointer is in active part of Java heap. + // Use is_in_reserved to check if object is within heap bounds. bool is_in(const void* p) const override; bool requires_barriers(stackChunkOop obj) const override; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMarkBitMap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahMarkBitMap.cpp index 30389b4e95cdd..fa2e15a98c74b 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMarkBitMap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMarkBitMap.cpp @@ -122,7 +122,7 @@ void ShenandoahMarkBitMap::clear_range_large(MemRegion mr) { #ifdef ASSERT void ShenandoahMarkBitMap::check_mark(HeapWord* addr) const { - assert(ShenandoahHeap::heap()->is_in(addr), + assert(ShenandoahHeap::heap()->is_in_reserved(addr), "Trying to access bitmap " PTR_FORMAT " for address " PTR_FORMAT " not in the heap.", p2i(this), p2i(addr)); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMarkingContext.hpp b/src/hotspot/share/gc/shenandoah/shenandoahMarkingContext.hpp index d58117c02e2d6..62baf3e61eaef 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMarkingContext.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMarkingContext.hpp @@ -63,8 +63,10 @@ class ShenandoahMarkingContext : public CHeapObj { inline bool mark_weak(oop obj); // Simple versions of marking accessors, to be used outside of marking (e.g. no possible concurrent updates) - inline bool is_marked(oop) const; + inline bool is_marked(oop obj) const; + inline bool is_marked(HeapWord* raw_obj) const; inline bool is_marked_strong(oop obj) const; + inline bool is_marked_strong(HeapWord* raw_obj) const; inline bool is_marked_weak(oop obj) const; inline HeapWord* get_next_marked_addr(HeapWord* addr, HeapWord* limit) const; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMarkingContext.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahMarkingContext.inline.hpp index 34b8288f47673..1ba3caf26b72b 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMarkingContext.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMarkingContext.inline.hpp @@ -38,11 +38,19 @@ inline bool ShenandoahMarkingContext::mark_weak(oop obj) { } inline bool ShenandoahMarkingContext::is_marked(oop obj) const { - return allocated_after_mark_start(obj) || _mark_bit_map.is_marked(cast_from_oop(obj)); + return is_marked(cast_from_oop(obj)); +} + +inline bool ShenandoahMarkingContext::is_marked(HeapWord* raw_obj) const { + return allocated_after_mark_start(raw_obj) || _mark_bit_map.is_marked(raw_obj); } inline bool ShenandoahMarkingContext::is_marked_strong(oop obj) const { - return allocated_after_mark_start(obj) || _mark_bit_map.is_marked_strong(cast_from_oop(obj)); + return is_marked_strong(cast_from_oop(obj)); +} + +inline bool ShenandoahMarkingContext::is_marked_strong(HeapWord* raw_obj) const { + return allocated_after_mark_start(raw_obj) || _mark_bit_map.is_marked_strong(raw_obj); } inline bool ShenandoahMarkingContext::is_marked_weak(oop obj) const { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.cpp b/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.cpp index f395119d46a35..42c8d0ad27112 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.cpp @@ -83,10 +83,21 @@ static volatile T* reference_referent_addr(oop reference) { return (volatile T*)java_lang_ref_Reference::referent_addr_raw(reference); } +inline oop reference_coop_decode_raw(narrowOop v) { + return CompressedOops::is_null(v) ? nullptr : CompressedOops::decode_raw(v); +} + +inline oop reference_coop_decode_raw(oop v) { + return v; +} + +// Raw referent, it can be dead. You cannot treat it as oop without additional safety +// checks, this is why it is HeapWord*. The decoding uses a special-case inlined +// CompressedOops::decode method that bypasses normal oop-ness checks. template -static oop reference_referent(oop reference) { - T heap_oop = Atomic::load(reference_referent_addr(reference)); - return CompressedOops::decode(heap_oop); +static HeapWord* reference_referent_raw(oop reference) { + T raw_oop = Atomic::load(reference_referent_addr(reference)); + return cast_from_oop(reference_coop_decode_raw(raw_oop)); } static void reference_clear_referent(oop reference) { @@ -278,8 +289,8 @@ bool ShenandoahReferenceProcessor::should_discover(oop reference, ReferenceType template bool ShenandoahReferenceProcessor::should_drop(oop reference, ReferenceType type) const { - const oop referent = reference_referent(reference); - if (referent == nullptr) { + HeapWord* raw_referent = reference_referent_raw(reference); + if (raw_referent == nullptr) { // Reference has been cleared, by a call to Reference.enqueue() // or Reference.clear() from the application, which means we // should drop the reference. @@ -289,9 +300,9 @@ bool ShenandoahReferenceProcessor::should_drop(oop reference, ReferenceType type // Check if the referent is still alive, in which case we should // drop the reference. if (type == REF_PHANTOM) { - return ShenandoahHeap::heap()->complete_marking_context()->is_marked(referent); + return ShenandoahHeap::heap()->complete_marking_context()->is_marked(raw_referent); } else { - return ShenandoahHeap::heap()->complete_marking_context()->is_marked_strong(referent); + return ShenandoahHeap::heap()->complete_marking_context()->is_marked_strong(raw_referent); } } @@ -303,7 +314,7 @@ void ShenandoahReferenceProcessor::make_inactive(oop reference, ReferenceType ty // next field. An application can't call FinalReference.enqueue(), so there is // no race to worry about when setting the next field. assert(reference_next(reference) == nullptr, "Already inactive"); - assert(ShenandoahHeap::heap()->marking_context()->is_marked(reference_referent(reference)), "only make inactive final refs with alive referents"); + assert(ShenandoahHeap::heap()->marking_context()->is_marked(reference_referent_raw(reference)), "only make inactive final refs with alive referents"); reference_set_next(reference, reference); } else { // Clear referent @@ -376,8 +387,8 @@ oop ShenandoahReferenceProcessor::drop(oop reference, ReferenceType type) { log_trace(gc, ref)("Dropped Reference: " PTR_FORMAT " (%s)", p2i(reference), reference_type_name(type)); #ifdef ASSERT - oop referent = reference_referent(reference); - assert(referent == nullptr || ShenandoahHeap::heap()->marking_context()->is_marked(referent), + HeapWord* raw_referent = reference_referent_raw(reference); + assert(raw_referent == nullptr || ShenandoahHeap::heap()->marking_context()->is_marked(raw_referent), "only drop references with alive referents"); #endif diff --git a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp index 23da3d7f63709..4834ecba54390 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp @@ -51,13 +51,6 @@ static bool is_instance_ref_klass(Klass* k) { return k->is_instance_klass() && InstanceKlass::cast(k)->reference_type() != REF_NONE; } -class ShenandoahIgnoreReferenceDiscoverer : public ReferenceDiscoverer { -public: - virtual bool discover_reference(oop obj, ReferenceType type) { - return true; - } -}; - class ShenandoahVerifyOopClosure : public BasicOopIterateClosure { private: const char* _phase; @@ -68,6 +61,7 @@ class ShenandoahVerifyOopClosure : public BasicOopIterateClosure { ShenandoahLivenessData* _ld; void* _interior_loc; oop _loc; + ReferenceIterationMode _ref_mode; public: ShenandoahVerifyOopClosure(ShenandoahVerifierStack* stack, MarkBitMap* map, ShenandoahLivenessData* ld, @@ -82,10 +76,20 @@ class ShenandoahVerifyOopClosure : public BasicOopIterateClosure { _loc(nullptr) { if (options._verify_marked == ShenandoahVerifier::_verify_marked_complete_except_references || options._verify_marked == ShenandoahVerifier::_verify_marked_disable) { - set_ref_discoverer_internal(new ShenandoahIgnoreReferenceDiscoverer()); + // Unknown status for Reference.referent field. Do not touch it, it might be dead. + // Normally, barriers would prevent us from seeing the dead referents, but verifier + // runs with barriers disabled. + _ref_mode = DO_FIELDS_EXCEPT_REFERENT; + } else { + // Otherwise do all fields. + _ref_mode = DO_FIELDS; } } + ReferenceIterationMode reference_iteration_mode() override { + return _ref_mode; + } + private: void check(ShenandoahAsserts::SafeLevel level, oop obj, bool test, const char* label) { if (!test) { @@ -119,8 +123,8 @@ class ShenandoahVerifyOopClosure : public BasicOopIterateClosure { // that failure report would not try to touch something that was not yet verified to be // safe to process. - check(ShenandoahAsserts::_safe_unknown, obj, _heap->is_in(obj), - "oop must be in heap"); + check(ShenandoahAsserts::_safe_unknown, obj, _heap->is_in_reserved(obj), + "oop must be in heap bounds"); check(ShenandoahAsserts::_safe_unknown, obj, is_object_aligned(obj), "oop must be aligned"); @@ -177,8 +181,8 @@ class ShenandoahVerifyOopClosure : public BasicOopIterateClosure { ShenandoahHeapRegion* fwd_reg = nullptr; if (obj != fwd) { - check(ShenandoahAsserts::_safe_oop, obj, _heap->is_in(fwd), - "Forwardee must be in heap"); + check(ShenandoahAsserts::_safe_oop, obj, _heap->is_in_reserved(fwd), + "Forwardee must be in heap bounds"); check(ShenandoahAsserts::_safe_oop, obj, !CompressedOops::is_null(fwd), "Forwardee is set"); check(ShenandoahAsserts::_safe_oop, obj, is_object_aligned(fwd), @@ -195,6 +199,9 @@ class ShenandoahVerifyOopClosure : public BasicOopIterateClosure { fwd_reg = _heap->heap_region_containing(fwd); + check(ShenandoahAsserts::_safe_oop, obj, fwd_reg->is_active(), + "Forwardee should be in active region"); + // Verify that forwardee is not in the dead space: check(ShenandoahAsserts::_safe_oop, obj, !fwd_reg->is_humongous(), "Should have no humongous forwardees"); @@ -324,8 +331,8 @@ class ShenandoahVerifyOopClosure : public BasicOopIterateClosure { _loc = nullptr; } - virtual void do_oop(oop* p) { do_oop_work(p); } - virtual void do_oop(narrowOop* p) { do_oop_work(p); } + virtual void do_oop(oop* p) override { do_oop_work(p); } + virtual void do_oop(narrowOop* p) override { do_oop_work(p); } }; class ShenandoahCalculateRegionStatsClosure : public ShenandoahHeapRegionClosure { From 89ca5b6fbd82f00375b4f96b2f3526078088d3f9 Mon Sep 17 00:00:00 2001 From: Amit Kumar Date: Tue, 20 Aug 2024 09:54:20 +0000 Subject: [PATCH 350/353] 8338365: [PPC64, s390] Out-of-bounds array access in secondary_super_cache Reviewed-by: mdoerr, aph, rrich --- src/hotspot/cpu/ppc/macroAssembler_ppc.cpp | 6 ++---- src/hotspot/cpu/s390/macroAssembler_s390.cpp | 4 ++-- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp index c7cf678b49ecf..3b48b4020ccb3 100644 --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp @@ -2170,7 +2170,6 @@ do { \ (result == R8_ARG6 || result == noreg), "registers must match ppc64.ad"); \ } while(0) -// Return true: we succeeded in generating this code void MacroAssembler::lookup_secondary_supers_table(Register r_sub_klass, Register r_super_klass, Register temp1, @@ -2292,9 +2291,8 @@ void MacroAssembler::lookup_secondary_supers_table_slow_path(Register r_super_kl // The bitmap is full to bursting. // Implicit invariant: BITMAP_FULL implies (length > 0) - assert(Klass::SECONDARY_SUPERS_BITMAP_FULL == ~uintx(0), ""); - cmpdi(CCR0, r_bitmap, -1); - beq(CCR0, L_huge); + cmpwi(CCR0, r_array_length, (int32_t)Klass::SECONDARY_SUPERS_TABLE_SIZE - 2); + bgt(CCR0, L_huge); // NB! Our caller has checked bits 0 and 1 in the bitmap. The // current slot (at secondary_supers[r_array_index]) has not yet diff --git a/src/hotspot/cpu/s390/macroAssembler_s390.cpp b/src/hotspot/cpu/s390/macroAssembler_s390.cpp index a233934405f78..b31d08f9fde10 100644 --- a/src/hotspot/cpu/s390/macroAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/macroAssembler_s390.cpp @@ -3320,8 +3320,8 @@ void MacroAssembler::lookup_secondary_supers_table_slow_path(Register r_super_kl NearLabel L_huge; // The bitmap is full to bursting. - z_cghi(r_bitmap, Klass::SECONDARY_SUPERS_BITMAP_FULL); - z_bre(L_huge); + z_chi(r_array_length, Klass::SECONDARY_SUPERS_BITMAP_FULL - 2); + z_brh(L_huge); // NB! Our caller has checked bits 0 and 1 in the bitmap. The // current slot (at secondary_supers[r_array_index]) has not yet From 7933e45cda7e3eaeabd3b3fa81492ade8e1cc2dc Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Tue, 20 Aug 2024 10:43:16 +0000 Subject: [PATCH 351/353] 8338550: Do libubsan1 installation in test container only if requested Reviewed-by: sgehwolf --- .../jdk/test/lib/containers/docker/DockerTestUtils.java | 9 +++++---- .../jdk/test/lib/containers/docker/DockerfileConfig.java | 5 +++++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java b/test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java index c87796da47e7e..4a8915d463102 100644 --- a/test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java +++ b/test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java @@ -321,10 +321,11 @@ private static String limitLines(String buffer, int nrOfLines) { private static void generateDockerFile(Path dockerfile, String baseImage, String baseImageVersion) throws Exception { - String template = - "FROM %s:%s\n" + - "RUN apt-get install libubsan1\n" + - "COPY /jdk /jdk\n" + + String template = "FROM %s:%s\n"; + if (baseImage.contains("ubuntu") && DockerfileConfig.isUbsan()) { + template += "RUN apt-get update && apt-get install -y libubsan1\n"; + } + template = template + "COPY /jdk /jdk\n" + "ENV JAVA_HOME=/jdk\n" + "CMD [\"/bin/bash\"]\n"; String dockerFileStr = String.format(template, baseImage, baseImageVersion); diff --git a/test/lib/jdk/test/lib/containers/docker/DockerfileConfig.java b/test/lib/jdk/test/lib/containers/docker/DockerfileConfig.java index 9d73ad185f1f5..caa4a5a76ccf7 100644 --- a/test/lib/jdk/test/lib/containers/docker/DockerfileConfig.java +++ b/test/lib/jdk/test/lib/containers/docker/DockerfileConfig.java @@ -37,6 +37,11 @@ // Note: base image version should not be an empty string. Use "latest" to get the latest version. public class DockerfileConfig { + + public static boolean isUbsan() { + return Boolean.getBoolean("jdk.test.docker.image.isUbsan"); + } + public static String getBaseImageName() { String name = System.getProperty("jdk.test.docker.image.name"); if (name != null) { From 01d03e07c7642e148e4e17848d28686858ea37a7 Mon Sep 17 00:00:00 2001 From: Darragh Clarke Date: Tue, 20 Aug 2024 11:10:18 +0000 Subject: [PATCH 352/353] 8324209: Check implementation of Expect: 100-continue in the java.net.http.HttpClient Reviewed-by: dfuchs, jpai --- .../jdk/internal/net/http/Exchange.java | 75 ++++++++++++------- .../jdk/internal/net/http/ExchangeImpl.java | 10 +++ .../classes/jdk/internal/net/http/Stream.java | 22 +++++- .../net/httpclient/ExpectContinueTest.java | 41 +++++++--- 4 files changed, 109 insertions(+), 39 deletions(-) diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/Exchange.java b/src/java.net.http/share/classes/jdk/internal/net/http/Exchange.java index e643b05422afd..eb30dc85e9c8e 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/Exchange.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/Exchange.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,6 +39,8 @@ import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import java.util.function.Function; import java.net.http.HttpClient; import java.net.http.HttpHeaders; @@ -453,32 +455,55 @@ private CompletableFuture checkFor407(ExchangeImpl ex, Throwable t, // for the 100-Continue response private CompletableFuture expectContinue(ExchangeImpl ex) { assert request.expectContinue(); + + long responseTimeoutMillis = 5000; + if (request.timeout().isPresent()) { + final long timeoutMillis = request.timeout().get().toMillis(); + responseTimeoutMillis = Math.min(responseTimeoutMillis, timeoutMillis); + } + return ex.getResponseAsync(parentExecutor) + .completeOnTimeout(null, responseTimeoutMillis, TimeUnit.MILLISECONDS) .thenCompose((Response r1) -> { - Log.logResponse(r1::toString); - int rcode = r1.statusCode(); - if (rcode == 100) { - Log.logTrace("Received 100-Continue: sending body"); - if (debug.on()) debug.log("Received 100-Continue for %s", r1); - CompletableFuture cf = - exchImpl.sendBodyAsync() - .thenCompose(exIm -> exIm.getResponseAsync(parentExecutor)); - cf = wrapForUpgrade(cf); - cf = wrapForLog(cf); - return cf; - } else { - Log.logTrace("Expectation failed: Received {0}", - rcode); - if (debug.on()) debug.log("Expect-Continue failed (%d) for: %s", rcode, r1); - if (upgrading && rcode == 101) { - IOException failed = new IOException( - "Unable to handle 101 while waiting for 100"); - return MinimalFuture.failedFuture(failed); - } - exchImpl.expectContinueFailed(rcode); - return MinimalFuture.completedFuture(r1); - } - }); + // The response will only be null if there was a timeout + // send body regardless + if (r1 == null) { + if (debug.on()) + debug.log("Setting ExpectTimeoutRaised and sending request body"); + exchImpl.setExpectTimeoutRaised(); + CompletableFuture cf = + exchImpl.sendBodyAsync() + .thenCompose(exIm -> exIm.getResponseAsync(parentExecutor)); + cf = wrapForUpgrade(cf); + cf = wrapForLog(cf); + return cf; + } + + Log.logResponse(r1::toString); + int rcode = r1.statusCode(); + if (rcode == 100) { + Log.logTrace("Received 100-Continue: sending body"); + if (debug.on()) + debug.log("Received 100-Continue for %s", r1); + CompletableFuture cf = + exchImpl.sendBodyAsync() + .thenCompose(exIm -> exIm.getResponseAsync(parentExecutor)); + cf = wrapForUpgrade(cf); + cf = wrapForLog(cf); + return cf; + } else { + Log.logTrace("Expectation failed: Received {0}", rcode); + if (debug.on()) + debug.log("Expect-Continue failed (%d) for: %s", rcode, r1); + if (upgrading && rcode == 101) { + IOException failed = new IOException( + "Unable to handle 101 while waiting for 100"); + return MinimalFuture.failedFuture(failed); + } + exchImpl.expectContinueFailed(rcode); + return MinimalFuture.completedFuture(r1); + } + }); } // After sending the request headers, if no ProxyAuthorizationRequired diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/ExchangeImpl.java b/src/java.net.http/share/classes/jdk/internal/net/http/ExchangeImpl.java index 404f970cc59ef..f393b021cd436 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/ExchangeImpl.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/ExchangeImpl.java @@ -58,6 +58,8 @@ abstract class ExchangeImpl { final Exchange exchange; + private volatile boolean expectTimeoutRaised; + // this will be set to true only when the peer explicitly states (through a GOAWAY frame or // a relevant error code in reset frame) that the corresponding stream (id) wasn't processed private volatile boolean unprocessedByPeer; @@ -71,6 +73,14 @@ final Exchange getExchange() { return exchange; } + final void setExpectTimeoutRaised() { + expectTimeoutRaised = true; + } + + final boolean expectTimeoutRaised() { + return expectTimeoutRaised; + } + HttpClientImpl client() { return exchange.client(); } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/Stream.java b/src/java.net.http/share/classes/jdk/internal/net/http/Stream.java index 1a007e82adcdc..4563362292329 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/Stream.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/Stream.java @@ -1200,11 +1200,17 @@ CompletableFuture getResponseAsync(Executor executor) { try { if (!response_cfs.isEmpty()) { // This CompletableFuture was created by completeResponse(). - // it will be already completed. - cf = response_cfs.remove(0); + // it will be already completed, unless the expect continue + // timeout fired + cf = response_cfs.get(0); + if (cf.isDone()) { + cf = response_cfs.remove(0); + } + // if we find a cf here it should be already completed. // finding a non completed cf should not happen. just assert it. - assert cf.isDone() : "Removing uncompleted response: could cause code to hang!"; + assert cf.isDone() || request.expectContinue && expectTimeoutRaised() + : "Removing uncompleted response: could cause code to hang!"; } else { // getResponseAsync() is called first. Create a CompletableFuture // that will be completed by completeResponse() when @@ -1239,7 +1245,7 @@ void completeResponse(Response resp) { int cfs_len = response_cfs.size(); for (int i=0; i resp, boolean exceptionally, Throwable testThrowable) { + private void verifyRequest(String path, int expectedStatusCode, HttpResponse resp, boolean exceptionally, Throwable testThrowable) { + if (!exceptionally) { + err.printf("Response code %s received for path %s %n", resp.statusCode(), path); + } if (exceptionally && testThrowable != null) { - err.println(testThrowable); + err.println("Finished exceptionally Test throwable: " + testThrowable); assertEquals(IOException.class, testThrowable.getClass()); } else if (exceptionally) { throw new TestException("Expected case to finish with an IOException but testException is null"); } else if (resp != null) { assertEquals(resp.statusCode(), expectedStatusCode); - err.println("Request completed successfully"); + err.println("Request completed successfully for path " + path); err.println("Response Headers: " + resp.headers()); err.println("Response Status Code: " + resp.statusCode()); } From 686eb233d59ab72e872b8dc32cb14bf74519efc5 Mon Sep 17 00:00:00 2001 From: Jaikiran Pai Date: Tue, 20 Aug 2024 12:28:56 +0000 Subject: [PATCH 353/353] 8336817: Several methods on DatagramSocket and MulticastSocket do not specify behaviour when already closed or connected Reviewed-by: dfuchs, alanb --- .../classes/java/net/DatagramSocket.java | 69 +++++++++++-------- .../classes/java/net/MulticastSocket.java | 29 ++++---- 2 files changed, 57 insertions(+), 41 deletions(-) diff --git a/src/java.base/share/classes/java/net/DatagramSocket.java b/src/java.base/share/classes/java/net/DatagramSocket.java index 9e94d1d8b6209..655b00bb8b6e1 100644 --- a/src/java.base/share/classes/java/net/DatagramSocket.java +++ b/src/java.base/share/classes/java/net/DatagramSocket.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -395,7 +395,7 @@ public DatagramSocket(int port, InetAddress laddr) throws SocketException { * * @param addr The address and port to bind to. * @throws SocketException if any error happens during the bind, or if the - * socket is already bound. + * socket is already bound or is closed. * @throws SecurityException if a security manager exists and its * {@code checkListen} method doesn't allow the operation. * @throws IllegalArgumentException if addr is a SocketAddress subclass @@ -422,6 +422,11 @@ public void bind(SocketAddress addr) throws SocketException { * call to send or receive may throw a PortUnreachableException. Note, * there is no guarantee that the exception will be thrown. * + *

    If this socket is already connected, then this method will attempt to + * connect to the given address. If this connect fails then the state of + * this socket is unknown - it may or may not be connected to the address + * that it was previously connected to. + * *

    If a security manager has been installed then it is invoked to check * access to the remote address. Specifically, if the given {@code address} * is a {@link InetAddress#isMulticastAddress multicast address}, @@ -461,7 +466,7 @@ public void bind(SocketAddress addr) throws SocketException { * not permit access to the given remote address * * @throws UncheckedIOException - * may be thrown if connect fails, for example, if the + * if the port is 0 or connect fails, for example, if the * destination address is non-routable * * @see #disconnect @@ -484,6 +489,11 @@ public void connect(InetAddress address, int port) { * have not been {@linkplain #receive(DatagramPacket) received} before invoking * this method, may be discarded. * + *

    If this socket is already connected, then this method will attempt to + * connect to the given address. If this connect fails then the state of + * this socket is unknown - it may or may not be connected to the address + * that it was previously connected to. + * * @param addr The remote address. * * @throws SocketException @@ -643,7 +653,7 @@ public SocketAddress getLocalSocketAddress() { * * @param p the {@code DatagramPacket} to be sent. * - * @throws IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs, or the socket is closed. * @throws SecurityException if a security manager exists and its * {@code checkMulticast} or {@code checkConnect} * method doesn't allow the send. @@ -702,7 +712,7 @@ public void send(DatagramPacket p) throws IOException { * * @param p the {@code DatagramPacket} into which to place * the incoming data. - * @throws IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs, or the socket is closed. * @throws SocketTimeoutException if setSoTimeout was previously called * and the timeout has expired. * @throws PortUnreachableException may be thrown if the socket is connected @@ -770,7 +780,8 @@ public int getLocalPort() { * operation to have effect. * * @param timeout the specified timeout in milliseconds. - * @throws SocketException if there is an error in the underlying protocol, such as an UDP error. + * @throws SocketException if there is an error in the underlying protocol, + * such as an UDP error, or the socket is closed. * @throws IllegalArgumentException if {@code timeout} is negative * @since 1.1 * @see #getSoTimeout() @@ -784,7 +795,8 @@ public void setSoTimeout(int timeout) throws SocketException { * option is disabled (i.e., timeout of infinity). * * @return the setting for SO_TIMEOUT - * @throws SocketException if there is an error in the underlying protocol, such as an UDP error. + * @throws SocketException if there is an error in the underlying protocol, + * such as an UDP error, or the socket is closed. * @since 1.1 * @see #setSoTimeout(int) */ @@ -820,8 +832,8 @@ public int getSoTimeout() throws SocketException { * @param size the size to which to set the send buffer * size, in bytes. This value must be greater than 0. * - * @throws SocketException if there is an error - * in the underlying protocol, such as an UDP error. + * @throws SocketException if there is an error in the underlying protocol, + * such as an UDP error, or the socket is closed. * @throws IllegalArgumentException if the value is 0 or is * negative. * @see #getSendBufferSize() @@ -841,8 +853,8 @@ public void setSendBufferSize(int size) throws SocketException { * getOption(StandardSocketOptions.SO_SNDBUF)}. * * @return the value of the SO_SNDBUF option for this {@code DatagramSocket} - * @throws SocketException if there is an error in - * the underlying protocol, such as an UDP error. + * @throws SocketException if there is an error in the underlying protocol, + * such as an UDP error, or the socket is closed. * @see #setSendBufferSize * @see StandardSocketOptions#SO_SNDBUF * @since 1.2 @@ -878,8 +890,8 @@ public int getSendBufferSize() throws SocketException { * @param size the size to which to set the receive buffer * size, in bytes. This value must be greater than 0. * - * @throws SocketException if there is an error in - * the underlying protocol, such as an UDP error. + * @throws SocketException if there is an error in the underlying protocol, + * such as an UDP error, or the socket is closed. * @throws IllegalArgumentException if the value is 0 or is * negative. * @see #getReceiveBufferSize() @@ -899,7 +911,8 @@ public void setReceiveBufferSize(int size) throws SocketException { * getOption(StandardSocketOptions.SO_RCVBUF)}. * * @return the value of the SO_RCVBUF option for this {@code DatagramSocket} - * @throws SocketException if there is an error in the underlying protocol, such as an UDP error. + * @throws SocketException if there is an error in the underlying protocol, + * such as an UDP error, or the socket is closed. * @see #setReceiveBufferSize(int) * @see StandardSocketOptions#SO_RCVBUF * @since 1.2 @@ -959,8 +972,8 @@ public void setReuseAddress(boolean on) throws SocketException { * getOption(StandardSocketOptions.SO_REUSEADDR)}. * * @return a {@code boolean} indicating whether or not SO_REUSEADDR is enabled. - * @throws SocketException if there is an error - * in the underlying protocol, such as an UDP error. + * @throws SocketException if there is an error in the underlying protocol, + * such as an UDP error, or the socket is closed. * @since 1.4 * @see #setReuseAddress(boolean) * @see StandardSocketOptions#SO_REUSEADDR @@ -983,9 +996,8 @@ public boolean getReuseAddress() throws SocketException { * @param on * whether or not to have broadcast turned on. * - * @throws SocketException - * if there is an error in the underlying protocol, such as an UDP - * error. + * @throws SocketException if there is an error in the underlying protocol, + * such as an UDP error, or the socket is closed. * * @since 1.4 * @see #getBroadcast() @@ -1003,8 +1015,8 @@ public void setBroadcast(boolean on) throws SocketException { * getOption(StandardSocketOptions.SO_BROADCAST)}. * * @return a {@code boolean} indicating whether or not SO_BROADCAST is enabled. - * @throws SocketException if there is an error - * in the underlying protocol, such as an UDP error. + * @throws SocketException if there is an error in the underlying protocol, + * such as an UDP error, or the socket is closed. * @since 1.4 * @see #setBroadcast(boolean) * @see StandardSocketOptions#SO_BROADCAST @@ -1049,8 +1061,8 @@ public boolean getBroadcast() throws SocketException { * setOption(StandardSocketOptions.IP_TOS, tc)}. * * @param tc an {@code int} value for the bitset. - * @throws SocketException if there is an error setting the - * traffic class or type-of-service + * @throws SocketException if there is an error setting the traffic class or type-of-service, + * or the socket is closed. * @since 1.4 * @see #getTrafficClass * @see StandardSocketOptions#IP_TOS @@ -1074,8 +1086,8 @@ public void setTrafficClass(int tc) throws SocketException { * getOption(StandardSocketOptions.IP_TOS)}. * * @return the traffic class or type-of-service already set - * @throws SocketException if there is an error obtaining the - * traffic class or type-of-service value. + * @throws SocketException if there is an error obtaining the traffic class + * or type-of-service value, or the socket is closed. * @since 1.4 * @see #setTrafficClass(int) * @see StandardSocketOptions#IP_TOS @@ -1092,6 +1104,9 @@ public int getTrafficClass() throws SocketException { * *

    If this socket has an associated channel then the channel is closed * as well. + * + *

    Once closed, several of the methods defined by this class will throw + * an exception if invoked on the closed socket. */ public void close() { delegate().close(); @@ -1299,7 +1314,7 @@ public Set> supportedOptions() { * datagram packets, or {@code null}. * @throws IOException if there is an error joining, or when the address * is not a multicast address, or the platform does not support - * multicasting + * multicasting, or the socket is closed * @throws SecurityException if a security manager exists and its * {@code checkMulticast} method doesn't allow the join. * @throws IllegalArgumentException if mcastaddr is {@code null} or is a @@ -1343,7 +1358,7 @@ public void joinGroup(SocketAddress mcastaddr, NetworkInterface netIf) * is unspecified: any interface may be selected or the operation * may fail with a {@code SocketException}. * @throws IOException if there is an error leaving or when the address - * is not a multicast address. + * is not a multicast address, or the socket is closed. * @throws SecurityException if a security manager exists and its * {@code checkMulticast} method doesn't allow the operation. * @throws IllegalArgumentException if mcastaddr is {@code null} or is a diff --git a/src/java.base/share/classes/java/net/MulticastSocket.java b/src/java.base/share/classes/java/net/MulticastSocket.java index 9a9d57118c0f1..46757a6b4077e 100644 --- a/src/java.base/share/classes/java/net/MulticastSocket.java +++ b/src/java.base/share/classes/java/net/MulticastSocket.java @@ -221,7 +221,7 @@ public MulticastSocket(SocketAddress bindaddr) throws IOException { * * @param ttl the time-to-live * @throws IOException if an I/O exception occurs - * while setting the default time-to-live value + * while setting the default time-to-live value, or the socket is closed. * @deprecated use the {@link #setTimeToLive(int)} method instead, which uses * int instead of byte as the type for ttl. * @see #getTTL() @@ -250,7 +250,7 @@ public void setTTL(byte ttl) throws IOException { * * @throws IOException * if an I/O exception occurs while setting the - * default time-to-live value + * default time-to-live value, or the socket is closed. * * @see #getTimeToLive() * @see StandardSocketOptions#IP_MULTICAST_TTL @@ -265,7 +265,7 @@ public void setTimeToLive(int ttl) throws IOException { * the socket. * * @throws IOException if an I/O exception occurs - * while getting the default time-to-live value + * while getting the default time-to-live value, or the socket is closed. * @return the default time-to-live value * @deprecated use the {@link #getTimeToLive()} method instead, * which returns an int instead of a byte. @@ -285,7 +285,7 @@ public byte getTTL() throws IOException { * getOption(StandardSocketOptions.IP_MULTICAST_TTL)}. * * @throws IOException if an I/O exception occurs while - * getting the default time-to-live value + * getting the default time-to-live value, or the socket is closed. * @return the default time-to-live value * @see #setTimeToLive(int) * @see StandardSocketOptions#IP_MULTICAST_TTL @@ -311,7 +311,7 @@ public int getTimeToLive() throws IOException { * @param mcastaddr is the multicast address to join * @throws IOException if there is an error joining, * or when the address is not a multicast address, - * or the platform does not support multicasting + * or the platform does not support multicasting, or the socket is closed. * @throws SecurityException if a security manager exists and its * {@code checkMulticast} method doesn't allow the join. * @deprecated This method does not accept the network interface on @@ -339,7 +339,7 @@ public void joinGroup(InetAddress mcastaddr) throws IOException { * * @param mcastaddr is the multicast address to leave * @throws IOException if there is an error leaving - * or when the address is not a multicast address. + * or when the address is not a multicast address, or the socket is closed. * @throws SecurityException if a security manager exists and its * {@code checkMulticast} method doesn't allow the operation. * @deprecated This method does not accept the network interface on which @@ -393,7 +393,7 @@ public void leaveGroup(SocketAddress mcastaddr, NetworkInterface netIf) * * @param inf the InetAddress * @throws SocketException if there is an error in - * the underlying protocol, such as a TCP error. + * the underlying protocol, such as a TCP error, or the socket is closed. * @deprecated The InetAddress may not uniquely identify * the network interface. Use * {@link #setNetworkInterface(NetworkInterface)} instead. @@ -413,7 +413,7 @@ public void setInterface(InetAddress inf) throws SocketException { * or if no interface has been set, an {@code InetAddress} * representing any local address. * @throws SocketException if there is an error in the - * underlying protocol, such as a TCP error. + * underlying protocol, such as a TCP error, or the socket is closed. * @deprecated The network interface may not be uniquely identified by * the InetAddress returned. * Use {@link #getNetworkInterface()} instead. @@ -434,7 +434,7 @@ public InetAddress getInterface() throws SocketException { * * @param netIf the interface * @throws SocketException if there is an error in - * the underlying protocol, such as a TCP error. + * the underlying protocol, such as a TCP error, or the socket is closed. * @see #getNetworkInterface() * @see StandardSocketOptions#IP_MULTICAST_IF * @since 1.4 @@ -454,7 +454,7 @@ public void setNetworkInterface(NetworkInterface netIf) * getOption(StandardSocketOptions.IP_MULTICAST_IF)}. * * @throws SocketException if there is an error in - * the underlying protocol, such as a TCP error. + * the underlying protocol, such as a TCP error, or the socket is closed. * @return The multicast {@code NetworkInterface} currently set. A placeholder * NetworkInterface is returned when there is no interface set; it has * a single InetAddress to represent any local address. @@ -476,7 +476,8 @@ public NetworkInterface getNetworkInterface() throws SocketException { * verify what loopback mode is set to should call * {@link #getLoopbackMode()} * @param disable {@code true} to disable the LoopbackMode - * @throws SocketException if an error occurs while setting the value + * @throws SocketException if an error occurs while setting the value, or + * the socket is closed. * @since 1.4 * @deprecated Use {@link #setOption(SocketOption, Object)} with * {@link java.net.StandardSocketOptions#IP_MULTICAST_LOOP} @@ -493,7 +494,8 @@ public void setLoopbackMode(boolean disable) throws SocketException { /** * Get the setting for local loopback of multicast datagrams. * - * @throws SocketException if an error occurs while getting the value + * @throws SocketException if an error occurs while getting the value, or + * the socket is closed. * @return true if the LoopbackMode has been disabled * @since 1.4 * @deprecated Use {@link #getOption(SocketOption)} with @@ -534,8 +536,7 @@ public boolean getLoopbackMode() throws SocketException { * @param ttl optional time to live for multicast packet. * default ttl is 1. * - * @throws IOException is raised if an error occurs i.e - * error while setting ttl. + * @throws IOException if an I/O error occurs, or the socket is closed. * @throws SecurityException if a security manager exists and its * {@code checkMulticast} or {@code checkConnect} * method doesn't allow the send.