From 1383b8ef87bcf3b2b498c883c81434bab8fe68fd Mon Sep 17 00:00:00 2001 From: Volkan Yazici Date: Wed, 20 Aug 2025 13:14:04 +0000 Subject: [PATCH 01/54] 8362243: Devkit creation for Fedora base OS is broken Reviewed-by: ihse, erikj, shade --- doc/building.html | 12 ++++++------ doc/building.md | 8 ++++---- make/devkit/Makefile | 4 ++-- make/devkit/Tools.gmk | 17 ++++++++++++++--- 4 files changed, 26 insertions(+), 15 deletions(-) diff --git a/doc/building.html b/doc/building.html index f7af2648592..99eb3e0c473 100644 --- a/doc/building.html +++ b/doc/building.html @@ -1451,10 +1451,10 @@ of a cross-compiling toolchain and a sysroot environment which can easily be used together with the --with-devkit configure option to cross compile the JDK. On Linux/x86_64, the following command:

-
bash configure --with-devkit=<devkit-path> --openjdk-target=ppc64-linux-gnu && make
-

will configure and build the JDK for Linux/ppc64 assuming that -<devkit-path> points to a Linux/x86_64 to Linux/ppc64 -devkit.

+
bash configure --with-devkit=<devkit-path> --openjdk-target=ppc64le-linux-gnu && make
+

will configure and build the JDK for Linux/ppc64le assuming that +<devkit-path> points to a Linux/x86_64 to +Linux/ppc64le devkit.

Devkits can be created from the make/devkit directory by executing:

make [ TARGETS="<TARGET_TRIPLET>+" ] [ BASE_OS=<OS> ] [ BASE_OS_VERSION=<VER> ]
@@ -1481,10 +1481,10 @@ following targets are known to work:

arm-linux-gnueabihf -ppc64-linux-gnu +ppc64le-linux-gnu -ppc64le-linux-gnu +riscv64-linux-gnu s390x-linux-gnu diff --git a/doc/building.md b/doc/building.md index 32c6ae46540..047255d1848 100644 --- a/doc/building.md +++ b/doc/building.md @@ -1258,11 +1258,11 @@ toolchain and a sysroot environment which can easily be used together with the following command: ``` -bash configure --with-devkit= --openjdk-target=ppc64-linux-gnu && make +bash configure --with-devkit= --openjdk-target=ppc64le-linux-gnu && make ``` -will configure and build the JDK for Linux/ppc64 assuming that `` -points to a Linux/x86_64 to Linux/ppc64 devkit. +will configure and build the JDK for Linux/ppc64le assuming that `` +points to a Linux/x86_64 to Linux/ppc64le devkit. Devkits can be created from the `make/devkit` directory by executing: @@ -1281,8 +1281,8 @@ at least the following targets are known to work: | x86_64-linux-gnu | | aarch64-linux-gnu | | arm-linux-gnueabihf | -| ppc64-linux-gnu | | ppc64le-linux-gnu | +| riscv64-linux-gnu | | s390x-linux-gnu | `BASE_OS` must be one of `OL` for Oracle Enterprise Linux or `Fedora`. If the diff --git a/make/devkit/Makefile b/make/devkit/Makefile index 5ffa5265aa3..d2167bf33fa 100644 --- a/make/devkit/Makefile +++ b/make/devkit/Makefile @@ -39,7 +39,7 @@ # # make TARGETS="aarch64-linux-gnu" BASE_OS=Fedora # or -# make TARGETS="arm-linux-gnueabihf ppc64-linux-gnu" BASE_OS=Fedora BASE_OS_VERSION=17 +# make TARGETS="arm-linux-gnueabihf ppc64le-linux-gnu" BASE_OS=Fedora BASE_OS_VERSION=17 # # to build several devkits for a specific OS version at once. # You can find the final results under ../../build/devkit/result/-to- @@ -50,7 +50,7 @@ # makefile again for cross compilation. Ex: # # PATH=$PWD/../../build/devkit/result/x86_64-linux-gnu-to-x86_64-linux-gnu/bin:$PATH \ -# make TARGETS="arm-linux-gnueabihf,ppc64-linux-gnu" BASE_OS=Fedora +# make TARGETS="arm-linux-gnueabihf ppc64le-linux-gnu" BASE_OS=Fedora # # This is the makefile which iterates over all host and target platforms. # diff --git a/make/devkit/Tools.gmk b/make/devkit/Tools.gmk index 1b9240df49c..f27d47b822c 100644 --- a/make/devkit/Tools.gmk +++ b/make/devkit/Tools.gmk @@ -69,15 +69,26 @@ else ifeq ($(BASE_OS), Fedora) ifeq ($(BASE_OS_VERSION), ) BASE_OS_VERSION := $(DEFAULT_OS_VERSION) endif + ifeq ($(filter aarch64 armhfp ppc64le riscv64 s390x x86_64, $(ARCH)), ) + $(error Only "aarch64 armhfp ppc64le riscv64 s390x x86_64" architectures are supported for Fedora, but "$(ARCH)" was requested) + endif ifeq ($(ARCH), riscv64) + ifeq ($(filter 38 39 40 41, $(BASE_OS_VERSION)), ) + $(error Only Fedora 38-41 are supported for "$(ARCH)", but Fedora $(BASE_OS_VERSION) was requested) + endif BASE_URL := http://fedora.riscv.rocks/repos-dist/f$(BASE_OS_VERSION)/latest/$(ARCH)/Packages/ else - LATEST_ARCHIVED_OS_VERSION := 35 - ifeq ($(filter x86_64 armhfp, $(ARCH)), ) + LATEST_ARCHIVED_OS_VERSION := 36 + ifeq ($(filter aarch64 armhfp x86_64, $(ARCH)), ) FEDORA_TYPE := fedora-secondary else FEDORA_TYPE := fedora/linux endif + ifeq ($(ARCH), armhfp) + ifneq ($(BASE_OS_VERSION), 36) + $(error Fedora 36 is the last release supporting "armhfp", but $(BASE_OS) was requested) + endif + endif NOT_ARCHIVED := $(shell [ $(BASE_OS_VERSION) -gt $(LATEST_ARCHIVED_OS_VERSION) ] && echo true) ifeq ($(NOT_ARCHIVED),true) BASE_URL := https://dl.fedoraproject.org/pub/$(FEDORA_TYPE)/releases/$(BASE_OS_VERSION)/Everything/$(ARCH)/os/Packages/ @@ -464,7 +475,7 @@ ifeq ($(ARCH), armhfp) $(BUILDDIR)/$(gcc_ver)/Makefile : CONFIG += --with-float=hard endif -ifneq ($(filter riscv64 ppc64 ppc64le s390x, $(ARCH)), ) +ifneq ($(filter riscv64 ppc64le s390x, $(ARCH)), ) # We only support 64-bit on these platforms anyway CONFIG += --disable-multilib endif From e912977a6687917ed45520c4d8558ebe630e3f52 Mon Sep 17 00:00:00 2001 From: Afshin Zafari Date: Wed, 20 Aug 2025 13:40:13 +0000 Subject: [PATCH 02/54] 8353444: NMT: rename 'category' to 'MemTag' in malloc tracker Reviewed-by: jsjolen --- src/hotspot/share/nmt/mallocLimit.cpp | 37 +++++++++---------- src/hotspot/share/nmt/mallocLimit.hpp | 8 ++-- .../share/nmt/mallocTracker.inline.hpp | 4 +- .../gtest/nmt/test_nmt_malloclimit.cpp | 6 +-- test/hotspot/gtest/nmt/test_nmt_totals.cpp | 4 +- 5 files changed, 29 insertions(+), 30 deletions(-) diff --git a/src/hotspot/share/nmt/mallocLimit.cpp b/src/hotspot/share/nmt/mallocLimit.cpp index ed479725cf9..2bce2e459e0 100644 --- a/src/hotspot/share/nmt/mallocLimit.cpp +++ b/src/hotspot/share/nmt/mallocLimit.cpp @@ -61,7 +61,7 @@ public: // Check if string at position matches a malloclimit_mode_t. // Advance position on match. - bool match_mode_flag(MallocLimitMode* out) { + bool match_mode(MallocLimitMode* out) { if (eof()) { return false; } @@ -77,9 +77,9 @@ public: return false; } - // Check if string at position matches a category name. + // Check if string at position matches a MemTag name. // Advances position on match. - bool match_category(MemTag* out) { + bool match_mem_tag(MemTag* out) { if (eof()) { return false; } @@ -130,9 +130,9 @@ void MallocLimitSet::set_global_limit(size_t s, MallocLimitMode flag) { _glob.sz = s; _glob.mode = flag; } -void MallocLimitSet::set_category_limit(MemTag mem_tag, size_t s, MallocLimitMode flag) { +void MallocLimitSet::set_category_limit(MemTag mem_tag, size_t s, MallocLimitMode mode) { const int i = NMTUtil::tag_to_index(mem_tag); - _cat[i].sz = s; _cat[i].mode = flag; + _mtag[i].sz = s; _mtag[i].mode = mode; } void MallocLimitSet::reset() { @@ -144,16 +144,15 @@ void MallocLimitSet::reset() { } void MallocLimitSet::print_on(outputStream* st) const { - static const char* flagnames[] = { MODE_FATAL, MODE_OOM }; if (_glob.sz > 0) { st->print_cr("MallocLimit: total limit: " PROPERFMT " (%s)", PROPERFMTARGS(_glob.sz), mode_to_name(_glob.mode)); } else { for (int i = 0; i < mt_number_of_tags; i++) { - if (_cat[i].sz > 0) { + if (_mtag[i].sz > 0) { st->print_cr("MallocLimit: category \"%s\" limit: " PROPERFMT " (%s)", NMTUtil::tag_to_enum_name(NMTUtil::index_to_tag(i)), - PROPERFMTARGS(_cat[i].sz), mode_to_name(_cat[i].mode)); + PROPERFMTARGS(_mtag[i].sz), mode_to_name(_mtag[i].mode)); } } } @@ -164,10 +163,10 @@ bool MallocLimitSet::parse_malloclimit_option(const char* v, const char** err) { #define BAIL_UNLESS(condition, errormessage) if (!(condition)) { *err = errormessage; return false; } // Global form: - // MallocLimit=[:flag] + // MallocLimit=[:mode] - // Category-specific form: - // MallocLimit=:[:flag][,:[:flag]...] + // MemTag-specific form: + // MallocLimit=:[:mode][,:[:mode]...] reset(); @@ -177,29 +176,29 @@ bool MallocLimitSet::parse_malloclimit_option(const char* v, const char** err) { // Global form? if (sst.match_size(&_glob.sz)) { - // Match optional mode flag (e.g. 1g:oom) + // Match optional mode (e.g. 1g:oom) if (!sst.eof()) { BAIL_UNLESS(sst.match_char(':'), "Expected colon"); - BAIL_UNLESS(sst.match_mode_flag(&_glob.mode), "Expected flag"); + BAIL_UNLESS(sst.match_mode(&_glob.mode), "Expected mode"); } } - // Category-specific form? + // MemTag-specific form? else { while (!sst.eof()) { MemTag mem_tag; - // Match category, followed by : - BAIL_UNLESS(sst.match_category(&mem_tag), "Expected category name"); + // Match MemTag, followed by : + BAIL_UNLESS(sst.match_mem_tag(&mem_tag), "Expected category name"); BAIL_UNLESS(sst.match_char(':'), "Expected colon following category"); - malloclimit* const modified_limit = &_cat[NMTUtil::tag_to_index(mem_tag)]; + malloclimit* const modified_limit = &_mtag[NMTUtil::tag_to_index(mem_tag)]; // Match size BAIL_UNLESS(sst.match_size(&modified_limit->sz), "Expected size"); - // Match optional flag + // Match optional mode if (!sst.eof() && sst.match_char(':')) { - BAIL_UNLESS(sst.match_mode_flag(&modified_limit->mode), "Expected flag"); + BAIL_UNLESS(sst.match_mode(&modified_limit->mode), "Expected mode"); } // More to come? diff --git a/src/hotspot/share/nmt/mallocLimit.hpp b/src/hotspot/share/nmt/mallocLimit.hpp index ec6799b41a3..d41eaabea46 100644 --- a/src/hotspot/share/nmt/mallocLimit.hpp +++ b/src/hotspot/share/nmt/mallocLimit.hpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2023 SAP SE. All rights reserved. - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,7 +46,7 @@ class outputStream; class MallocLimitSet { malloclimit _glob; // global limit - malloclimit _cat[mt_number_of_tags]; // per-category limit + malloclimit _mtag[mt_number_of_tags]; // per-memtag limit public: MallocLimitSet(); @@ -57,7 +57,7 @@ public: void set_category_limit(MemTag mem_tag, size_t s, MallocLimitMode mode); const malloclimit* global_limit() const { return &_glob; } - const malloclimit* category_limit(MemTag mem_tag) const { return &_cat[(int)mem_tag]; } + const malloclimit* mem_tag_limit(MemTag mem_tag) const { return &_mtag[(int)mem_tag]; } void print_on(outputStream* st) const; }; @@ -69,7 +69,7 @@ class MallocLimitHandler : public AllStatic { public: static const malloclimit* global_limit() { return _limits.global_limit(); } - static const malloclimit* category_limit(MemTag mem_tag) { return _limits.category_limit(mem_tag); } + static const malloclimit* mem_tag_limit(MemTag mem_tag) { return _limits.mem_tag_limit(mem_tag); } static void initialize(const char* options); static void print_on(outputStream* st); diff --git a/src/hotspot/share/nmt/mallocTracker.inline.hpp b/src/hotspot/share/nmt/mallocTracker.inline.hpp index b2aec345eff..51a7f28cf99 100644 --- a/src/hotspot/share/nmt/mallocTracker.inline.hpp +++ b/src/hotspot/share/nmt/mallocTracker.inline.hpp @@ -49,8 +49,8 @@ inline bool MallocMemorySummary::check_exceeds_limit(size_t s, MemTag mem_tag) { return total_limit_reached(s, so_far, l); } } else { - // Category Limit? - l = MallocLimitHandler::category_limit(mem_tag); + // MemTag Limit? + l = MallocLimitHandler::mem_tag_limit(mem_tag); if (l->sz > 0) { const MallocMemory* mm = as_snapshot()->by_tag(mem_tag); size_t so_far = mm->malloc_size() + mm->arena_size(); diff --git a/test/hotspot/gtest/nmt/test_nmt_malloclimit.cpp b/test/hotspot/gtest/nmt/test_nmt_malloclimit.cpp index 83d4bd6235b..da357285148 100644 --- a/test/hotspot/gtest/nmt/test_nmt_malloclimit.cpp +++ b/test/hotspot/gtest/nmt/test_nmt_malloclimit.cpp @@ -42,8 +42,8 @@ static bool compare_limits(const malloclimit* a, const malloclimit* b) { static bool compare_sets(const MallocLimitSet* a, const MallocLimitSet* b) { if (compare_limits(a->global_limit(), b->global_limit())) { for (int i = 0; i < mt_number_of_tags; i++) { - if (!compare_limits(a->category_limit(NMTUtil::index_to_tag(i)), - b->category_limit(NMTUtil::index_to_tag(i)))) { + if (!compare_limits(a->mem_tag_limit(NMTUtil::index_to_tag(i)), + b->mem_tag_limit(NMTUtil::index_to_tag(i)))) { return false; } } @@ -92,7 +92,7 @@ TEST(NMT, MallocLimitPerCategory) { test("metaspace:1m,compiler:2m:oom,thread:3m:oom,threadstack:4m:oom,class:5m,classshared:6m", expected); } -TEST(NMT, MallocLimitCategoryEnumNames) { +TEST(NMT, MallocLimitMemTagEnumNames) { MallocLimitSet expected; stringStream option; for (int i = 0; i < mt_number_of_tags; i++) { diff --git a/test/hotspot/gtest/nmt/test_nmt_totals.cpp b/test/hotspot/gtest/nmt/test_nmt_totals.cpp index 61c591fa0bb..690751ede54 100644 --- a/test/hotspot/gtest/nmt/test_nmt_totals.cpp +++ b/test/hotspot/gtest/nmt/test_nmt_totals.cpp @@ -88,8 +88,8 @@ TEST_VM(NMTNumbers, totals) { void* p[NUM_ALLOCS]; for (int i = 0; i < NUM_ALLOCS; i ++) { // spread over categories - int category = i % (mt_number_of_tags - 1); - p[i] = NEW_C_HEAP_ARRAY(char, ALLOC_SIZE, (MemTag)category); + int mtag = i % (mt_number_of_tags - 1); + p[i] = NEW_C_HEAP_ARRAY(char, ALLOC_SIZE, (MemTag)mtag); } const totals_t t2 = get_totals(); From ebf5ae8435e27e4315e43237b1167a1e99150393 Mon Sep 17 00:00:00 2001 From: Patricio Chilano Mateo Date: Wed, 20 Aug 2025 14:49:16 +0000 Subject: [PATCH 03/54] 8359222: [asan] jvmti/vthread/ToggleNotifyJvmtiTest/ToggleNotifyJvmtiTest triggers stack-buffer-overflow error Reviewed-by: dholmes, fbredberg, coleenp --- .../continuationFreezeThaw_aarch64.inline.hpp | 16 +++++++--- .../arm/continuationFreezeThaw_arm.inline.hpp | 4 +++ .../ppc/continuationFreezeThaw_ppc.inline.hpp | 3 ++ .../continuationFreezeThaw_riscv.inline.hpp | 3 ++ .../continuationFreezeThaw_s390.inline.hpp | 4 +++ .../x86/continuationFreezeThaw_x86.inline.hpp | 16 +++++++--- .../continuationFreezeThaw_zero.inline.hpp | 4 +++ .../share/runtime/continuationFreezeThaw.cpp | 29 ++++++++++++++++--- .../share/runtime/continuationHelper.hpp | 5 +++- 9 files changed, 71 insertions(+), 13 deletions(-) diff --git a/src/hotspot/cpu/aarch64/continuationFreezeThaw_aarch64.inline.hpp b/src/hotspot/cpu/aarch64/continuationFreezeThaw_aarch64.inline.hpp index e82162df4ab..1fd59b81d9e 100644 --- a/src/hotspot/cpu/aarch64/continuationFreezeThaw_aarch64.inline.hpp +++ b/src/hotspot/cpu/aarch64/continuationFreezeThaw_aarch64.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * 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,9 +101,12 @@ frame FreezeBase::new_heap_frame(frame& f, frame& caller) { *hf.addr_at(frame::interpreter_frame_locals_offset) = locals_offset; return hf; } else { - // We need to re-read fp out of the frame because it may be an oop and we might have - // had a safepoint in finalize_freeze, after constructing f. - fp = *(intptr_t**)(f.sp() - frame::sender_sp_offset); + // For a compiled frame we need to re-read fp out of the frame because it may be an + // oop and we might have had a safepoint in finalize_freeze, after constructing f. + // For stub/native frames the value is not used while frozen, and will be constructed again + // when thawing the frame (see ThawBase::new_stack_frame). We use a special bad address to + // help with debugging, particularly when inspecting frames and identifying invalid accesses. + fp = FKind::compiled ? *(intptr_t**)(f.sp() - frame::sender_sp_offset) : (intptr_t*)badAddressVal; int fsize = FKind::size(f); sp = caller.unextended_sp() - fsize; @@ -192,6 +195,11 @@ inline void FreezeBase::patch_pd(frame& hf, const frame& caller) { } } +inline void FreezeBase::patch_pd_unused(intptr_t* sp) { + intptr_t* fp_addr = sp - frame::sender_sp_offset; + *fp_addr = badAddressVal; +} + //////// Thaw // Fast path diff --git a/src/hotspot/cpu/arm/continuationFreezeThaw_arm.inline.hpp b/src/hotspot/cpu/arm/continuationFreezeThaw_arm.inline.hpp index b276a7d70b6..389cf4dc936 100644 --- a/src/hotspot/cpu/arm/continuationFreezeThaw_arm.inline.hpp +++ b/src/hotspot/cpu/arm/continuationFreezeThaw_arm.inline.hpp @@ -60,6 +60,10 @@ inline void FreezeBase::patch_pd(frame& hf, const frame& caller) { Unimplemented(); } +inline void FreezeBase::patch_pd_unused(intptr_t* sp) { + Unimplemented(); +} + inline void FreezeBase::patch_stack_pd(intptr_t* frame_sp, intptr_t* heap_sp) { Unimplemented(); } diff --git a/src/hotspot/cpu/ppc/continuationFreezeThaw_ppc.inline.hpp b/src/hotspot/cpu/ppc/continuationFreezeThaw_ppc.inline.hpp index 8eb33c3cd0b..fa878b07d43 100644 --- a/src/hotspot/cpu/ppc/continuationFreezeThaw_ppc.inline.hpp +++ b/src/hotspot/cpu/ppc/continuationFreezeThaw_ppc.inline.hpp @@ -334,6 +334,9 @@ inline void FreezeBase::patch_pd(frame& hf, const frame& caller) { #endif } +inline void FreezeBase::patch_pd_unused(intptr_t* sp) { +} + //////// Thaw // Fast path diff --git a/src/hotspot/cpu/riscv/continuationFreezeThaw_riscv.inline.hpp b/src/hotspot/cpu/riscv/continuationFreezeThaw_riscv.inline.hpp index 78975b8df89..461dc19f383 100644 --- a/src/hotspot/cpu/riscv/continuationFreezeThaw_riscv.inline.hpp +++ b/src/hotspot/cpu/riscv/continuationFreezeThaw_riscv.inline.hpp @@ -194,6 +194,9 @@ inline void FreezeBase::patch_pd(frame& hf, const frame& caller) { } } +inline void FreezeBase::patch_pd_unused(intptr_t* sp) { +} + //////// Thaw // Fast path diff --git a/src/hotspot/cpu/s390/continuationFreezeThaw_s390.inline.hpp b/src/hotspot/cpu/s390/continuationFreezeThaw_s390.inline.hpp index bee7bb72cbf..d39821bd034 100644 --- a/src/hotspot/cpu/s390/continuationFreezeThaw_s390.inline.hpp +++ b/src/hotspot/cpu/s390/continuationFreezeThaw_s390.inline.hpp @@ -60,6 +60,10 @@ inline void FreezeBase::patch_pd(frame& hf, const frame& caller) { Unimplemented(); } +inline void FreezeBase::patch_pd_unused(intptr_t* sp) { + Unimplemented(); +} + inline void FreezeBase::patch_stack_pd(intptr_t* frame_sp, intptr_t* heap_sp) { Unimplemented(); } diff --git a/src/hotspot/cpu/x86/continuationFreezeThaw_x86.inline.hpp b/src/hotspot/cpu/x86/continuationFreezeThaw_x86.inline.hpp index 9591c9f2c96..126f4043cad 100644 --- a/src/hotspot/cpu/x86/continuationFreezeThaw_x86.inline.hpp +++ b/src/hotspot/cpu/x86/continuationFreezeThaw_x86.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -98,9 +98,12 @@ frame FreezeBase::new_heap_frame(frame& f, frame& caller) { *hf.addr_at(frame::interpreter_frame_locals_offset) = locals_offset; return hf; } else { - // We need to re-read fp out of the frame because it may be an oop and we might have - // had a safepoint in finalize_freeze, after constructing f. - fp = *(intptr_t**)(f.sp() - frame::sender_sp_offset); + // For a compiled frame we need to re-read fp out of the frame because it may be an + // oop and we might have had a safepoint in finalize_freeze, after constructing f. + // For stub/native frames the value is not used while frozen, and will be constructed again + // when thawing the frame (see ThawBase::new_stack_frame). We use a special bad address to + // help with debugging, particularly when inspecting frames and identifying invalid accesses. + fp = FKind::compiled ? *(intptr_t**)(f.sp() - frame::sender_sp_offset) : (intptr_t*)badAddressVal; int fsize = FKind::size(f); sp = caller.unextended_sp() - fsize; @@ -183,6 +186,11 @@ inline void FreezeBase::patch_pd(frame& hf, const frame& caller) { } } +inline void FreezeBase::patch_pd_unused(intptr_t* sp) { + intptr_t* fp_addr = sp - frame::sender_sp_offset; + *fp_addr = badAddressVal; +} + //////// Thaw // Fast path diff --git a/src/hotspot/cpu/zero/continuationFreezeThaw_zero.inline.hpp b/src/hotspot/cpu/zero/continuationFreezeThaw_zero.inline.hpp index de2769fb376..eb6be8772f9 100644 --- a/src/hotspot/cpu/zero/continuationFreezeThaw_zero.inline.hpp +++ b/src/hotspot/cpu/zero/continuationFreezeThaw_zero.inline.hpp @@ -60,6 +60,10 @@ inline void FreezeBase::patch_pd(frame& hf, const frame& caller) { Unimplemented(); } +inline void FreezeBase::patch_pd_unused(intptr_t* sp) { + Unimplemented(); +} + inline void FreezeBase::patch_stack_pd(intptr_t* frame_sp, intptr_t* heap_sp) { Unimplemented(); } diff --git a/src/hotspot/share/runtime/continuationFreezeThaw.cpp b/src/hotspot/share/runtime/continuationFreezeThaw.cpp index a928b0443ee..1027b4447c5 100644 --- a/src/hotspot/share/runtime/continuationFreezeThaw.cpp +++ b/src/hotspot/share/runtime/continuationFreezeThaw.cpp @@ -460,6 +460,7 @@ private: template frame new_heap_frame(frame& f, frame& caller); inline void set_top_frame_metadata_pd(const frame& hf); inline void patch_pd(frame& callee, const frame& caller); + inline void patch_pd_unused(intptr_t* sp); void adjust_interpreted_frame_unextended_sp(frame& f); static inline void prepare_freeze_interpreted_top_frame(frame& f); static inline void relativize_interpreted_frame_metadata(const frame& f, const frame& hf); @@ -783,9 +784,24 @@ void FreezeBase::freeze_fast_copy(stackChunkOop chunk, int chunk_start_sp CONT_J log_develop_trace(continuations)("freeze_fast start: " INTPTR_FORMAT " sp: %d chunk_top: " INTPTR_FORMAT, p2i(chunk->start_address()), chunk_new_sp, p2i(chunk_top)); - intptr_t* from = _cont_stack_top - frame::metadata_words_at_bottom; - intptr_t* to = chunk_top - frame::metadata_words_at_bottom; - copy_to_chunk(from, to, cont_size() + frame::metadata_words_at_bottom); + + int adjust = frame::metadata_words_at_bottom; +#if INCLUDE_ASAN && defined(AARCH64) + // Reading at offset frame::metadata_words_at_bottom from _cont_stack_top + // will accesss memory at the callee frame, which on preemption cases will + // be the VM native method being called. The Arm 64-bit ABI doesn't specify + // a location where the frame record (returnpc+fp) has to be stored within + // a stack frame, and GCC currently chooses to save it at the top of the + // frame (lowest address). ASan treats this memory access in the callee as + // an overflow access to one of the locals stored in that frame. For these + // preemption cases we don't need to read these words anyways so we avoid it. + if (_preempt) { + adjust = 0; + } +#endif + intptr_t* from = _cont_stack_top - adjust; + intptr_t* to = chunk_top - adjust; + copy_to_chunk(from, to, cont_size() + adjust); // Because we're not patched yet, the chunk is now in a bad state // patch return pc of the bottom-most frozen frame (now in the chunk) @@ -816,6 +832,11 @@ void FreezeBase::freeze_fast_copy(stackChunkOop chunk, int chunk_start_sp CONT_J address last_pc = _last_frame.pc(); ContinuationHelper::patch_return_address_at(chunk_top - frame::sender_sp_ret_address_offset(), last_pc); chunk->set_pc(last_pc); + // For stub/native frames the fp is not used while frozen, and will be constructed + // again when thawing the frame (see ThawBase::handle_preempted_continuation). We + // patch it with a special bad address to help with debugging, particularly when + // inspecting frames and identifying invalid accesses. + patch_pd_unused(chunk_top); } else { chunk->set_pc(ContinuationHelper::return_address_at( _cont_stack_top - frame::sender_sp_ret_address_offset())); @@ -2484,7 +2505,7 @@ intptr_t* ThawBase::handle_preempted_continuation(intptr_t* sp, Continuation::pr if (fast_case) { // If we thawed in the slow path the runtime stub/native wrapper frame already // has the correct fp (see ThawBase::new_stack_frame). On the fast path though, - // we copied the original fp at the time of freeze which now will have to be fixed. + // we copied the fp patched during freeze, which will now have to be fixed. assert(top.is_runtime_frame() || top.is_native_frame(), ""); int fsize = top.cb()->frame_size(); patch_pd(top, sp + fsize); diff --git a/src/hotspot/share/runtime/continuationHelper.hpp b/src/hotspot/share/runtime/continuationHelper.hpp index 0b3e6c72452..dffbf333bcc 100644 --- a/src/hotspot/share/runtime/continuationHelper.hpp +++ b/src/hotspot/share/runtime/continuationHelper.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -65,6 +65,7 @@ public: class ContinuationHelper::Frame : public AllStatic { public: static const bool interpreted = false; + static const bool compiled = false; static const bool stub = false; static const bool native = false; @@ -127,6 +128,8 @@ public: class ContinuationHelper::CompiledFrame : public ContinuationHelper::NonInterpretedFrame { public: + static const bool compiled = true; + static bool is_instance(const frame& f); #ifdef ASSERT From 5ca8d7c2a79ed3d9a6def61ba0fbd0acd5d404dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Walln=C3=B6fer?= Date: Wed, 20 Aug 2025 14:52:04 +0000 Subject: [PATCH 04/54] 8284499: Add the ability to right-click and open in new tab JavaDoc Search results Reviewed-by: liach --- .../doclets/formats/html/resources/search.js.template | 10 ++++++++-- .../doclets/formats/html/resources/stylesheet.css | 10 ++++++---- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/search.js.template b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/search.js.template index 5a36ee06819..16ae5a4d221 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/search.js.template +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/search.js.template @@ -423,7 +423,8 @@ $.widget("custom.catcomplete", $.ui.autocomplete, { var label = getResultLabel(item); var resultDesc = getResultDescription(item); return $("
  • ") - .append($("
    ") + .append($("") + .attr("href", item.indexItem ? pathtoroot + getURL(item.indexItem, item.category) : null) .append($("").addClass("search-result-label").html(label)) .append($("").addClass("search-result-desc").html(resultDesc))) .appendTo(ul); @@ -515,7 +516,7 @@ $(function() { this.menu.previousFilter = "_"; this.menu.filterTimer = this.menu._delay(function() { delete this.previousFilter; - }, 1000); + }, 500); return doSearch(request, response); }, response: function(event, ui) { @@ -531,6 +532,11 @@ $(function() { collision: "flip" }, select: function(event, ui) { + for (var e = event.originalEvent; e != null; e = e.originalEvent) { + if (e.type === "click") { + return; + } + } if (ui.item.indexItem) { var url = getURL(ui.item.indexItem, ui.item.category); window.location.href = pathtoroot + url; 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 587121ad582..778ee5f03b3 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 @@ -1235,11 +1235,11 @@ li.ui-static-link a, li.ui-static-link a:visited { grid-template-columns: auto auto; } .ui-autocomplete > li, -.ui-autocomplete > li > div { +.ui-autocomplete > li > a { grid-column: 1 / 3; } .ui-autocomplete > li.result-item, -.ui-autocomplete > li.result-item > div { +.ui-autocomplete > li.result-item > a { display: grid; grid-template-columns: subgrid; } @@ -1250,6 +1250,7 @@ li.ui-static-link a, li.ui-static-link a:visited { } .ui-autocomplete .search-result-label { padding: 1px 4px; + color: var(--block-text-color); overflow: hidden; text-overflow: ellipsis; } @@ -1263,6 +1264,7 @@ li.ui-static-link a, li.ui-static-link a:visited { .ui-autocomplete .result-highlight { font-weight:bold; } +.ui-menu .ui-state-active .search-result-label, .ui-menu .ui-state-active .search-result-desc { color: var(--selected-text-color); } @@ -1843,9 +1845,9 @@ table.striped > tbody > tr > th { grid-template-columns: none; } .ui-autocomplete > li, - .ui-autocomplete > li > div, + .ui-autocomplete > li > a, .ui-autocomplete > li.result-item, - .ui-autocomplete > li.result-item > div { + .ui-autocomplete > li.result-item > a { grid-column: unset; display: block; grid-template-columns: none; From 3e60ab51fea17098d852931a06f4f5a827ae0e78 Mon Sep 17 00:00:00 2001 From: Archie Cobbs Date: Wed, 20 Aug 2025 15:04:48 +0000 Subject: [PATCH 05/54] 8348611: Eliminate DeferredLintHandler and emit warnings after attribution 8224228: No way to locally suppress lint warnings in parser/tokenizer or preview features 8353758: Missing calls to Log.useSource() in JavacTrees Reviewed-by: mcimadamore, vromero, jlahoda --- .../sun/tools/javac/api/JavacTaskImpl.java | 7 +- .../sun/tools/javac/api/JavacTaskPool.java | 2 + .../com/sun/tools/javac/api/JavacTrees.java | 13 +- .../tools/javac/code/DeferredLintHandler.java | 176 --------- .../com/sun/tools/javac/code/Lint.java | 26 +- .../com/sun/tools/javac/code/LintMapper.java | 328 +++++++++++++++++ .../com/sun/tools/javac/code/Preview.java | 8 +- .../com/sun/tools/javac/comp/Annotate.java | 60 +--- .../com/sun/tools/javac/comp/Attr.java | 40 +-- .../com/sun/tools/javac/comp/Check.java | 180 ++++------ .../com/sun/tools/javac/comp/Flow.java | 335 ++++++++---------- .../com/sun/tools/javac/comp/MemberEnter.java | 44 +-- .../com/sun/tools/javac/comp/Modules.java | 33 +- .../tools/javac/comp/ThisEscapeAnalyzer.java | 86 ++--- .../com/sun/tools/javac/comp/TypeEnter.java | 32 +- .../sun/tools/javac/file/BaseFileManager.java | 2 +- .../com/sun/tools/javac/file/Locations.java | 23 +- .../com/sun/tools/javac/jvm/ClassReader.java | 17 +- .../com/sun/tools/javac/main/Arguments.java | 29 +- .../sun/tools/javac/main/JavaCompiler.java | 10 + .../sun/tools/javac/parser/JavaTokenizer.java | 40 +-- .../sun/tools/javac/parser/JavacParser.java | 29 +- .../com/sun/tools/javac/parser/Lexer.java | 12 +- .../sun/tools/javac/parser/ParserFactory.java | 5 +- .../com/sun/tools/javac/parser/Scanner.java | 9 +- .../tools/javac/parser/ScannerFactory.java | 5 +- .../sun/tools/javac/parser/VirtualParser.java | 10 +- .../tools/javac/processing/JavacFiler.java | 27 +- .../JavacProcessingEnvironment.java | 29 +- .../tools/javac/resources/compiler.properties | 42 ++- .../sun/tools/javac/util/JCDiagnostic.java | 34 ++ .../classes/com/sun/tools/javac/util/Log.java | 169 ++++++++- .../tools/javac/6304921/TestLog.java | 13 +- test/langtools/tools/javac/ImportModule.java | 2 +- .../OverrideChecks/6400189/T6400189a.out | 2 +- .../OverrideChecks/6400189/T6400189b.out | 2 +- .../DanglingDocCommentsClass.enabled.out | 4 +- .../DanglingDocCommentsClass_Line.enabled.out | 4 +- ...DanglingDocCommentsClass_Mixed.enabled.out | 2 +- .../DanglingDocCommentsEnum.enabled.out | 6 +- .../generics/diamond/7188968/T7188968.out | 6 +- .../tools/javac/lambda/TargetType22.out | 2 +- .../tools/javac/lint/LexicalLintNesting.java | 170 +++++++++ .../tools/javac/lint/LexicalLintNesting.out | 10 + .../tools/javac/lint/TextBlockSuppress.java | 61 ++++ .../tools/javac/lint/TextBlockSuppress.out | 5 + .../mandatoryWarnings/deprecated/Test5.out | 2 +- .../mandatoryWarnings/deprecated/Test5b.out | 2 +- .../javac/modules/AnnotationsOnModules.java | 4 +- .../tools/javac/preview/PreviewErrors.java | 6 +- .../tools/javac/preview/PreviewTest.java | 97 ++++- .../tools/javac/varargs/7097436/T7097436.out | 4 +- .../javac/warnings/6594914/T6594914a.out | 2 +- .../tools/javac/warnings/7090499/T7090499.out | 8 +- .../UnneededStrictfpWarningToolBox.java | 4 +- .../javac/warnings/suppress/T6480588.out | 12 +- 56 files changed, 1344 insertions(+), 948 deletions(-) delete mode 100644 src/jdk.compiler/share/classes/com/sun/tools/javac/code/DeferredLintHandler.java create mode 100644 src/jdk.compiler/share/classes/com/sun/tools/javac/code/LintMapper.java create mode 100644 test/langtools/tools/javac/lint/LexicalLintNesting.java create mode 100644 test/langtools/tools/javac/lint/LexicalLintNesting.out create mode 100644 test/langtools/tools/javac/lint/TextBlockSuppress.java create mode 100644 test/langtools/tools/javac/lint/TextBlockSuppress.out diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java index 980ce060c33..65ce640ef76 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -412,6 +412,7 @@ public class JavacTaskImpl extends BasicJavacTask { f.run(compiler.todo, classes); } } finally { + compiler.log.reportOutstandingWarnings(); compiler.log.flush(); } return results; @@ -483,8 +484,10 @@ public class JavacTaskImpl extends BasicJavacTask { } } finally { - if (compiler != null) + if (compiler != null) { + compiler.log.reportOutstandingWarnings(); compiler.log.flush(); + } } return results; } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTaskPool.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTaskPool.java index 6214c3775d3..65772cdccb3 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTaskPool.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTaskPool.java @@ -55,6 +55,7 @@ import com.sun.source.util.TaskEvent.Kind; import com.sun.source.util.TaskListener; import com.sun.source.util.TreeScanner; import com.sun.tools.javac.code.Kinds; +import com.sun.tools.javac.code.LintMapper; import com.sun.tools.javac.code.Preview; import com.sun.tools.javac.code.Symbol; import com.sun.tools.javac.code.Symtab; @@ -268,6 +269,7 @@ public class JavacTaskPool { if (ht.get(Log.logKey) instanceof ReusableLog) { //log already inited - not first round Log.instance(this).clear(); + LintMapper.instance(this).clear(); Enter.instance(this).newRound(); ((ReusableJavaCompiler)ReusableJavaCompiler.instance(this)).clear(); Types.instance(this).newRound(); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java index 4ced466d938..2eca26de838 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java @@ -360,9 +360,14 @@ public class JavacTrees extends DocTrees { Log.DeferredDiagnosticHandler deferredDiagnosticHandler = log.new DeferredDiagnosticHandler(); try { Env env = getAttrContext(path.getTreePath()); - Type t = attr.attribType(dcReference.qualifierExpression, env); - if (t != null && !t.isErroneous()) { - return t; + JavaFileObject prevSource = log.useSource(env.toplevel.sourcefile); + try { + Type t = attr.attribType(dcReference.qualifierExpression, env); + if (t != null && !t.isErroneous()) { + return t; + } + } finally { + log.useSource(prevSource); } } catch (Abort e) { // may be thrown by Check.completionError in case of bad class file return null; @@ -388,6 +393,7 @@ public class JavacTrees extends DocTrees { return null; } Log.DeferredDiagnosticHandler deferredDiagnosticHandler = log.new DeferredDiagnosticHandler(); + JavaFileObject prevSource = log.useSource(env.toplevel.sourcefile); try { final TypeSymbol tsym; final Name memberName; @@ -509,6 +515,7 @@ public class JavacTrees extends DocTrees { } catch (Abort e) { // may be thrown by Check.completionError in case of bad class file return null; } finally { + log.useSource(prevSource); log.popDiagnosticHandler(deferredDiagnosticHandler); } } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/DeferredLintHandler.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/DeferredLintHandler.java deleted file mode 100644 index 11544b92b7f..00000000000 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/DeferredLintHandler.java +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.tools.javac.code; - -import java.util.ArrayDeque; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Optional; -import java.util.function.Consumer; - -import com.sun.tools.javac.tree.JCTree; -import com.sun.tools.javac.tree.JCTree.Tag; -import com.sun.tools.javac.util.Assert; -import com.sun.tools.javac.util.Context; - -/** - * Holds pending {@link Lint} warnings until the {@lint Lint} instance associated with the containing - * module, package, class, method, or variable declaration is known so that {@link @SupressWarnings} - * suppressions may be applied. - * - *

    - * Warnings are regsistered at any time prior to attribution via {@link #report}. The warning will be - * associated with the declaration placed in context by the most recent invocation of {@link #push push()} - * not yet {@link #pop}'d. Warnings are actually emitted later, during attribution, via {@link #flush}. - * - *

    - * There is also an "immediate" mode, where warnings are emitted synchronously; see {@link #pushImmediate}. - * - *

    - * Deferred warnings are grouped by the innermost containing module, package, class, method, or variable - * declaration (represented by {@link JCTree} nodes), so that the corresponding {@link Lint} configuration - * can be applied when the warning is eventually generated. - * - *

    This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public class DeferredLintHandler { - - protected static final Context.Key deferredLintHandlerKey = new Context.Key<>(); - - public static DeferredLintHandler instance(Context context) { - DeferredLintHandler instance = context.get(deferredLintHandlerKey); - if (instance == null) - instance = new DeferredLintHandler(context); - return instance; - } - - /** - * Registered {@link LintLogger}s grouped by the innermost containing module, package, class, - * method, or variable declaration. - */ - private final HashMap> deferralMap = new HashMap<>(); - - /** - * The current "reporter" stack, reflecting calls to {@link #push} and {@link #pop}. - * - *

    - * The top of the stack determines how calls to {@link #report} are handled. - */ - private final ArrayDeque> reporterStack = new ArrayDeque<>(); - - @SuppressWarnings("this-escape") - protected DeferredLintHandler(Context context) { - context.put(deferredLintHandlerKey, this); - Lint rootLint = Lint.instance(context); - pushImmediate(rootLint); // default to "immediate" mode - } - -// LintLogger - - /**An interface for deferred lint reporting - loggers passed to - * {@link #report(LintLogger) } will be called when - * {@link #flush(DiagnosticPosition) } is invoked. - */ - public interface LintLogger { - - /** - * Generate a warning if appropriate. - * - * @param lint the applicable lint configuration - */ - void report(Lint lint); - } - -// Reporter Stack - - /** - * Defer {@link #report}ed warnings until the given declaration is flushed. - * - * @param decl module, package, class, method, or variable declaration - * @see #pop - */ - public void push(JCTree decl) { - Assert.check(decl.getTag() == Tag.MODULEDEF - || decl.getTag() == Tag.PACKAGEDEF - || decl.getTag() == Tag.CLASSDEF - || decl.getTag() == Tag.METHODDEF - || decl.getTag() == Tag.VARDEF); - reporterStack.push(logger -> deferralMap - .computeIfAbsent(decl, s -> new ArrayList<>()) - .add(logger)); - } - - /** - * Enter "immediate" mode so that {@link #report}ed warnings are emitted synchonously. - * - * @param lint lint configuration to use for reported warnings - */ - public void pushImmediate(Lint lint) { - reporterStack.push(logger -> logger.report(lint)); - } - - /** - * Revert to the previous configuration in effect prior to the most recent invocation - * of {@link #push} or {@link #pushImmediate}. - * - * @see #pop - */ - public void pop() { - Assert.check(reporterStack.size() > 1); // the bottom stack entry should never be popped - reporterStack.pop(); - } - - /** - * Report a warning. - * - *

    - * In immediate mode, the warning is emitted synchronously. Otherwise, the warning is emitted later - * when the current declaration is flushed. - */ - public void report(LintLogger logger) { - Assert.check(!reporterStack.isEmpty()); - reporterStack.peek().accept(logger); - } - -// Warning Flush - - /** - * Emit deferred warnings encompassed by the given declaration. - * - * @param decl module, package, class, method, or variable declaration - * @param lint lint configuration corresponding to {@code decl} - */ - public void flush(JCTree decl, Lint lint) { - Optional.of(decl) - .map(deferralMap::remove) - .stream() - .flatMap(ArrayList::stream) - .forEach(logger -> logger.report(lint)); - } -} diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Lint.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Lint.java index 6d83f95fce4..8eab238f82a 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Lint.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Lint.java @@ -374,11 +374,8 @@ public class Lint { /** * Warn about issues relating to use of text blocks - * - *

    - * This category is not supported by {@code @SuppressWarnings} (yet - see JDK-8224228). */ - TEXT_BLOCKS("text-blocks", false), + TEXT_BLOCKS("text-blocks"), /** * Warn about possible 'this' escapes before subclass instance is fully initialized. @@ -476,27 +473,6 @@ public class Lint { return suppressedValues.contains(lc); } - /** - * Helper method. Log a lint warning if its lint category is enabled. - * - * @param warning key for the localized warning message - */ - public void logIfEnabled(LintWarning warning) { - logIfEnabled(null, warning); - } - - /** - * Helper method. Log a lint warning if its lint category is enabled. - * - * @param pos source position at which to report the warning - * @param warning key for the localized warning message - */ - public void logIfEnabled(DiagnosticPosition pos, LintWarning warning) { - if (isEnabled(warning.getLintCategory())) { - log.warning(pos, warning); - } - } - /** * Obtain the set of recognized lint warning categories suppressed at the given symbol's declaration. * diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/LintMapper.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/LintMapper.java new file mode 100644 index 00000000000..b15ddae02e1 --- /dev/null +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/LintMapper.java @@ -0,0 +1,328 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.tools.javac.code; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.function.Consumer; +import java.util.stream.Stream; + +import javax.tools.DiagnosticListener; +import javax.tools.JavaFileObject; + +import com.sun.tools.javac.tree.EndPosTable; +import com.sun.tools.javac.tree.JCTree; +import com.sun.tools.javac.tree.JCTree.*; +import com.sun.tools.javac.tree.TreeInfo; +import com.sun.tools.javac.tree.TreeScanner; +import com.sun.tools.javac.util.Assert; +import com.sun.tools.javac.util.Context; +import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; + +/** + * Maps source code positions to the applicable {@link Lint} instance. + * + *

    + * Because {@code @SuppressWarnings} is a Java symbol, in general this mapping can't be + * calculated until after attribution. As each top-level declaration (class, package, or module) + * is attributed, this singleton is notified and the {@link Lint}s that apply to every source + * position within that top-level declaration are calculated. + * + *

    + * The method {@link #lintAt} returns the {@link Lint} instance applicable to source position; + * if it can't be determined yet, an empty {@link Optional} is returned. + * + *

    This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + */ +public class LintMapper { + + // The key for the context singleton + private static final Context.Key CONTEXT_KEY = new Context.Key<>(); + + // Per-source file information. Note: during the parsing of a file, an entry exists but the FileInfo value is null + private final Map fileInfoMap = new HashMap<>(); + + // Compiler context + private final Context context; + + // These are initialized lazily; see initializeIfNeeded() + private Lint rootLint; + + /** + * Obtain the {@link LintMapper} context singleton. + */ + public static LintMapper instance(Context context) { + LintMapper instance = context.get(CONTEXT_KEY); + if (instance == null) + instance = new LintMapper(context); + return instance; + } + + /** + * Constructor. + */ + @SuppressWarnings("this-escape") + protected LintMapper(Context context) { + context.put(CONTEXT_KEY, this); + this.context = context; + } + + // Lazy initialization to avoid dependency loops + private void initializeIfNeeded() { + if (rootLint == null) + rootLint = Lint.instance(context); + } + +// Lint Operations + + /** + * Determine if the given file is known to this instance. + * + * @param sourceFile source file + * @return true if file is recognized + */ + public boolean isKnown(JavaFileObject sourceFile) { + return fileInfoMap.containsKey(sourceFile); + } + + /** + * Obtain the {@link Lint} configuration that applies at the given position, if known. + * + * @param sourceFile source file + * @param pos source position + * @return the applicable {@link Lint}, if known, otherwise empty + */ + public Optional lintAt(JavaFileObject sourceFile, DiagnosticPosition pos) { + initializeIfNeeded(); + return Optional.of(sourceFile) + .map(fileInfoMap::get) + .flatMap(fileInfo -> fileInfo.lintAt(pos)); + } + + /** + * Calculate {@lint Lint} configurations for all positions within the given top-level declaration. + * + * @param sourceFile source file + * @param tree top-level declaration (class, package, or module) + */ + public void calculateLints(JavaFileObject sourceFile, JCTree tree, EndPosTable endPositions) { + Assert.check(rootLint != null); + fileInfoMap.get(sourceFile).afterAttr(tree, endPositions); + } + + /** + * Reset this instance. + */ + public void clear() { + fileInfoMap.clear(); + } + +// Parsing Notifications + + /** + * Invoked when file parsing starts to create an entry for the new file (but with a null value). + */ + public void startParsingFile(JavaFileObject sourceFile) { + initializeIfNeeded(); + fileInfoMap.put(sourceFile, null); + } + + /** + * Invoked when file parsing completes to put in place a corresponding {@link FileInfo}. + */ + public void finishParsingFile(JCCompilationUnit tree) { + Assert.check(rootLint != null); + fileInfoMap.put(tree.sourcefile, new FileInfo(rootLint, tree)); + } + +// FileInfo + + /** + * Holds {@link Lint} information for a fully parsed source file. + * + *

    + * Initially (immediately after parsing), "unmappedDecls" contains a {@link Span} corresponding to each + * top-level declaration in the source file. As each top-level declaration is attributed, the corresponding + * {@link Span} is removed and the corresponding {@link LintRange} subtree is populated under "rootRange". + */ + private static class FileInfo { + + final LintRange rootRange; // the root LintRange (covering the entire source file) + final List unmappedDecls = new ArrayList<>(); // unmapped top-level declarations awaiting attribution + + // After parsing: Add top-level declarations to our "unmappedDecls" list + FileInfo(Lint rootLint, JCCompilationUnit tree) { + rootRange = new LintRange(rootLint); + tree.defs.stream() + .filter(this::isTopLevelDecl) + .map(decl -> new Span(decl, tree.endPositions)) + .forEach(unmappedDecls::add); + } + + // After attribution: Discard the span from "unmappedDecls" and populate the declaration's subtree under "rootRange" + void afterAttr(JCTree tree, EndPosTable endPositions) { + for (Iterator i = unmappedDecls.iterator(); i.hasNext(); ) { + if (i.next().contains(tree.pos())) { + rootRange.populateSubtree(tree, endPositions); + i.remove(); + return; + } + } + throw new AssertionError("top-level declaration not found"); + } + + // Find the most specific Lint configuration applying to the given position, unless the position has not been mapped yet + Optional lintAt(DiagnosticPosition pos) { + boolean mapped = unmappedDecls.stream().noneMatch(span -> span.contains(pos)); + return mapped ? Optional.of(rootRange.bestMatch(pos).lint) : Optional.empty(); + } + + boolean isTopLevelDecl(JCTree tree) { + return tree.getTag() == Tag.MODULEDEF + || tree.getTag() == Tag.PACKAGEDEF + || tree.getTag() == Tag.CLASSDEF; + } + } + +// Span + + /** + * A lexical range. + */ + private record Span(int startPos, int endPos) { + + static final Span MAXIMAL = new Span(Integer.MIN_VALUE, Integer.MAX_VALUE); + + Span(JCTree tree, EndPosTable endPositions) { + this(TreeInfo.getStartPos(tree), TreeInfo.getEndPos(tree, endPositions)); + } + + boolean contains(DiagnosticPosition pos) { + int offset = pos.getLintPosition(); + return offset == startPos || (offset > startPos && offset < endPos); + } + + boolean contains(Span that) { + return this.startPos <= that.startPos && this.endPos >= that.endPos; + } + } + +// LintRange + + /** + * A tree of nested lexical ranges and the {@link Lint} configurations that apply therein. + */ + private record LintRange( + Span span, // declaration's lexical range + Lint lint, // the Lint configuration that applies at this declaration + List children // the nested declarations one level below this node + ) { + + // Create a node representing the entire file, using the root lint configuration + LintRange(Lint rootLint) { + this(Span.MAXIMAL, rootLint, new ArrayList<>()); + } + + // Create a node representing the given declaration and its corresponding Lint configuration + LintRange(JCTree tree, EndPosTable endPositions, Lint lint) { + this(new Span(tree, endPositions), lint, new ArrayList<>()); + } + + // Find the most specific node in this tree (including me) that contains the given position, if any + LintRange bestMatch(DiagnosticPosition pos) { + return children.stream() + .map(child -> child.bestMatch(pos)) + .filter(Objects::nonNull) + .reduce((a, b) -> a.span.contains(b.span) ? b : a) + .orElseGet(() -> span.contains(pos) ? this : null); + } + + // Populate a sparse subtree corresponding to the given nested declaration. + // Only when the Lint configuration differs from the parent is a node added. + void populateSubtree(JCTree tree, EndPosTable endPositions) { + new TreeScanner() { + + private LintRange currentNode = LintRange.this; + + @Override + public void visitModuleDef(JCModuleDecl tree) { + scanDecl(tree, tree.sym, super::visitModuleDef); + } + @Override + public void visitPackageDef(JCPackageDecl tree) { + scanDecl(tree, tree.packge, super::visitPackageDef); + } + @Override + public void visitClassDef(JCClassDecl tree) { + scanDecl(tree, tree.sym, super::visitClassDef); + } + @Override + public void visitMethodDef(JCMethodDecl tree) { + scanDecl(tree, tree.sym, super::visitMethodDef); + } + @Override + public void visitVarDef(JCVariableDecl tree) { + scanDecl(tree, tree.sym, super::visitVarDef); + } + + private void scanDecl(T tree, Symbol symbol, Consumer recursor) { + + // The "symbol" can be null if there were earlier errors; skip this declaration if so + if (symbol == null) { + recursor.accept(tree); + return; + } + + // Update the Lint using the declaration; if there's no change, then we don't need a new node here + Lint newLint = currentNode.lint.augment(symbol); + if (newLint == currentNode.lint) { // note: lint.augment() returns the same instance if there's no change + recursor.accept(tree); + return; + } + + // Add a new node here and proceed + final LintRange previousNode = currentNode; + currentNode = new LintRange(tree, endPositions, newLint); + previousNode.children.add(currentNode); + try { + recursor.accept(tree); + } finally { + currentNode = previousNode; + } + } + }.scan(tree); + } + } +} diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java index e11a9c6754e..1c93c37698a 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java @@ -67,9 +67,6 @@ public class Preview { /** flag: are preview features enabled */ private final boolean enabled; - /** flag: is the "preview" lint category enabled? */ - private final boolean verbose; - /** test flag: should all features be considered as preview features? */ private final boolean forcePreview; @@ -100,7 +97,6 @@ public class Preview { enabled = options.isSet(PREVIEW); log = Log.instance(context); source = Source.instance(context); - verbose = Lint.instance(context).isEnabled(LintCategory.PREVIEW); forcePreview = options.isSet("forcePreview"); majorVersionToSource = initMajorVersionToSourceMap(); } @@ -184,9 +180,7 @@ public class Preview { */ public void warnPreview(JavaFileObject classfile, int majorVersion) { Assert.check(isEnabled()); - if (verbose) { - log.warning(LintWarnings.PreviewFeatureUseClassfile(classfile, majorVersionToSource.get(majorVersion).name)); - } + log.warning(LintWarnings.PreviewFeatureUseClassfile(classfile, majorVersionToSource.get(majorVersion).name)); } /** diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java index 3da83248436..9f56bec4cca 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java @@ -89,9 +89,7 @@ public class Annotate { private final Attr attr; private final Check chk; private final ConstFold cfolder; - private final DeferredLintHandler deferredLintHandler; private final Enter enter; - private final Lint lint; private final Log log; private final Names names; private final Resolve resolve; @@ -110,10 +108,8 @@ public class Annotate { attr = Attr.instance(context); chk = Check.instance(context); cfolder = ConstFold.instance(context); - deferredLintHandler = DeferredLintHandler.instance(context); enter = Enter.instance(context); log = Log.instance(context); - lint = Lint.instance(context); make = TreeMaker.instance(context); names = Names.instance(context); resolve = Resolve.instance(context); @@ -235,10 +231,8 @@ public class Annotate { * @param annotations the list of JCAnnotations to attribute and enter * @param localEnv the enclosing env * @param s the Symbol on which to enter the annotations - * @param deferDecl enclosing declaration for DeferredLintHandler, or null for no deferral */ - public void annotateLater(List annotations, Env localEnv, - Symbol s, JCTree deferDecl) + public void annotateLater(List annotations, Env localEnv, Symbol s) { if (annotations.isEmpty()) { return; @@ -256,8 +250,6 @@ public class Annotate { // been handled, meaning that the set of annotations pending completion is now empty. Assert.check(s.kind == PCK || s.annotationsPendingCompletion()); JavaFileObject prev = log.useSource(localEnv.toplevel.sourcefile); - Assert.check(deferDecl != null); - deferredLintHandler.push(deferDecl); try { if (s.hasAnnotations() && annotations.nonEmpty()) log.error(annotations.head.pos, Errors.AlreadyAnnotated(Kinds.kindName(s), s)); @@ -268,7 +260,6 @@ public class Annotate { // never called for a type parameter annotateNow(s, annotations, localEnv, false, false); } finally { - deferredLintHandler.pop(); log.useSource(prev); } }); @@ -285,16 +276,13 @@ public class Annotate { /** Queue processing of an attribute default value. */ - public void annotateDefaultValueLater(JCExpression defaultValue, Env localEnv, - MethodSymbol m, JCTree deferDecl) + public void annotateDefaultValueLater(JCExpression defaultValue, Env localEnv, MethodSymbol m) { normal(() -> { JavaFileObject prev = log.useSource(localEnv.toplevel.sourcefile); - deferredLintHandler.push(deferDecl); try { enterDefaultValue(defaultValue, localEnv, m); } finally { - deferredLintHandler.pop(); log.useSource(prev); } }); @@ -682,7 +670,7 @@ public class Annotate { // Scan the annotation element value and then attribute nested annotations if present if (tree.type != null && tree.type.tsym != null) { - queueScanTreeAndTypeAnnotate(tree, env, tree.type.tsym, null); + queueScanTreeAndTypeAnnotate(tree, env, tree.type.tsym); } result = cfolder.coerce(result, expectedElementType); @@ -1034,20 +1022,14 @@ public class Annotate { /** * Attribute the list of annotations and enter them onto s. */ - public void enterTypeAnnotations(List annotations, Env env, - Symbol s, JCTree deferDecl, boolean isTypeParam) + public void enterTypeAnnotations(List annotations, Env env, Symbol s, boolean isTypeParam) { Assert.checkNonNull(s, "Symbol argument to actualEnterTypeAnnotations is nul/"); JavaFileObject prev = log.useSource(env.toplevel.sourcefile); - if (deferDecl != null) { - deferredLintHandler.push(deferDecl); - } try { annotateNow(s, annotations, env, true, isTypeParam); } finally { - if (deferDecl != null) - deferredLintHandler.pop(); log.useSource(prev); } } @@ -1055,10 +1037,10 @@ public class Annotate { /** * Enqueue tree for scanning of type annotations, attaching to the Symbol sym. */ - public void queueScanTreeAndTypeAnnotate(JCTree tree, Env env, Symbol sym, JCTree deferDecl) + public void queueScanTreeAndTypeAnnotate(JCTree tree, Env env, Symbol sym) { Assert.checkNonNull(sym); - normal(() -> tree.accept(new TypeAnnotate(env, sym, deferDecl))); + normal(() -> tree.accept(new TypeAnnotate(env, sym))); } /** @@ -1093,32 +1075,30 @@ public class Annotate { private class TypeAnnotate extends TreeScanner { private final Env env; private final Symbol sym; - private JCTree deferDecl; - public TypeAnnotate(Env env, Symbol sym, JCTree deferDecl) { + public TypeAnnotate(Env env, Symbol sym) { this.env = env; this.sym = sym; - this.deferDecl = deferDecl; } @Override public void visitAnnotatedType(JCAnnotatedType tree) { - enterTypeAnnotations(tree.annotations, env, sym, deferDecl, false); + enterTypeAnnotations(tree.annotations, env, sym, false); scan(tree.underlyingType); } @Override public void visitTypeParameter(JCTypeParameter tree) { - enterTypeAnnotations(tree.annotations, env, sym, deferDecl, true); + enterTypeAnnotations(tree.annotations, env, sym, true); scan(tree.bounds); } @Override public void visitNewArray(JCNewArray tree) { - enterTypeAnnotations(tree.annotations, env, sym, deferDecl, false); + enterTypeAnnotations(tree.annotations, env, sym, false); for (List dimAnnos : tree.dimAnnotations) - enterTypeAnnotations(dimAnnos, env, sym, deferDecl, false); + enterTypeAnnotations(dimAnnos, env, sym, false); scan(tree.elemtype); scan(tree.elems); } @@ -1137,19 +1117,13 @@ public class Annotate { @Override public void visitVarDef(JCVariableDecl tree) { - JCTree prevDecl = deferDecl; - deferDecl = tree; - try { - if (sym != null && sym.kind == VAR) { - // Don't visit a parameter once when the sym is the method - // and once when the sym is the parameter. - scan(tree.mods); - scan(tree.vartype); - } - scan(tree.init); - } finally { - deferDecl = prevDecl; + if (sym != null && sym.kind == VAR) { + // Don't visit a parameter once when the sym is the method + // and once when the sym is the parameter. + scan(tree.mods); + scan(tree.vartype); } + scan(tree.init); } @Override 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 ea3b08e0338..45ece909ad7 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 @@ -41,6 +41,7 @@ import com.sun.source.tree.TreeVisitor; import com.sun.source.util.SimpleTreeVisitor; import com.sun.tools.javac.code.*; import com.sun.tools.javac.code.Lint.LintCategory; +import com.sun.tools.javac.code.LintMapper; import com.sun.tools.javac.code.Scope.WriteableScope; import com.sun.tools.javac.code.Source.Feature; import com.sun.tools.javac.code.Symbol.*; @@ -98,6 +99,7 @@ public class Attr extends JCTree.Visitor { final Names names; final Log log; + final LintMapper lintMapper; final Symtab syms; final Resolve rs; final Operators operators; @@ -116,7 +118,6 @@ public class Attr extends JCTree.Visitor { final Preview preview; final JCDiagnostic.Factory diags; final TypeAnnotations typeAnnotations; - final DeferredLintHandler deferredLintHandler; final TypeEnvs typeEnvs; final Dependencies dependencies; final Annotate annotate; @@ -137,6 +138,7 @@ public class Attr extends JCTree.Visitor { names = Names.instance(context); log = Log.instance(context); + lintMapper = LintMapper.instance(context); syms = Symtab.instance(context); rs = Resolve.instance(context); operators = Operators.instance(context); @@ -156,7 +158,6 @@ public class Attr extends JCTree.Visitor { diags = JCDiagnostic.Factory.instance(context); annotate = Annotate.instance(context); typeAnnotations = TypeAnnotations.instance(context); - deferredLintHandler = DeferredLintHandler.instance(context); typeEnvs = TypeEnvs.instance(context); dependencies = Dependencies.instance(context); argumentAttr = ArgumentAttr.instance(context); @@ -853,7 +854,6 @@ public class Attr extends JCTree.Visitor { Env enclosingEnv, JCVariableDecl variable, Type type) { - deferredLintHandler.push(variable); final JavaFileObject prevSource = log.useSource(env.toplevel.sourcefile); try { doQueueScanTreeAndTypeAnnotateForVarInit(variable, enclosingEnv); @@ -869,7 +869,6 @@ public class Attr extends JCTree.Visitor { } } finally { log.useSource(prevSource); - deferredLintHandler.pop(); } } @@ -998,7 +997,6 @@ public class Attr extends JCTree.Visitor { Assert.check(!env.info.ctorPrologue); MethodSymbol prevMethod = chk.setMethod(m); try { - deferredLintHandler.flush(tree, lint); chk.checkDeprecatedAnnotation(tree.pos(), m); @@ -1233,7 +1231,7 @@ public class Attr extends JCTree.Visitor { } // Attribute all type annotations in the body - annotate.queueScanTreeAndTypeAnnotate(tree.body, localEnv, m, null); + annotate.queueScanTreeAndTypeAnnotate(tree.body, localEnv, m); annotate.flush(); // Start of constructor prologue (if not in java.lang.Object constructor) @@ -1297,7 +1295,6 @@ public class Attr extends JCTree.Visitor { try { v.getConstValue(); // ensure compile-time constant initializer is evaluated - deferredLintHandler.flush(tree, lint); chk.checkDeprecatedAnnotation(tree.pos(), v); if (tree.init != null) { @@ -1342,7 +1339,7 @@ public class Attr extends JCTree.Visitor { env.info.scope.owner.kind != MTH && env.info.scope.owner.kind != VAR) { tree.mods.flags |= Flags.FIELD_INIT_TYPE_ANNOTATIONS_QUEUED; // Field initializer expression need to be entered. - annotate.queueScanTreeAndTypeAnnotate(tree.init, env, tree.sym, tree); + annotate.queueScanTreeAndTypeAnnotate(tree.init, env, tree.sym); annotate.flush(); } } @@ -1439,7 +1436,7 @@ public class Attr extends JCTree.Visitor { if ((tree.flags & STATIC) != 0) localEnv.info.staticLevel++; // Attribute all type annotations in the block - annotate.queueScanTreeAndTypeAnnotate(tree, localEnv, localEnv.info.scope.owner, null); + annotate.queueScanTreeAndTypeAnnotate(tree, localEnv, localEnv.info.scope.owner); annotate.flush(); attribStats(tree.stats, localEnv); @@ -1952,7 +1949,7 @@ public class Attr extends JCTree.Visitor { public void visitSynchronized(JCSynchronized tree) { chk.checkRefType(tree.pos(), attribExpr(tree.lock, env)); if (tree.lock.type != null && tree.lock.type.isValueBased()) { - env.info.lint.logIfEnabled(tree.pos(), LintWarnings.AttemptToSynchronizeOnInstanceOfValueBasedClass); + log.warning(tree.pos(), LintWarnings.AttemptToSynchronizeOnInstanceOfValueBasedClass); } attribStat(tree.body, env); result = null; @@ -2054,7 +2051,7 @@ public class Attr extends JCTree.Visitor { if (close.kind == MTH && close.overrides(syms.autoCloseableClose, resource.tsym, types, true) && chk.isHandled(syms.interruptedExceptionType, types.memberType(resource, close).getThrownTypes())) { - env.info.lint.logIfEnabled(pos, LintWarnings.TryResourceThrowsInterruptedExc(resource)); + log.warning(pos, LintWarnings.TryResourceThrowsInterruptedExc(resource)); } } } @@ -4226,9 +4223,9 @@ public class Attr extends JCTree.Visitor { setSyntheticVariableType(tree.var, type == Type.noType ? syms.errType : type); } - annotate.annotateLater(tree.var.mods.annotations, env, v, tree.var); + annotate.annotateLater(tree.var.mods.annotations, env, v); if (!tree.var.isImplicitlyTyped()) { - annotate.queueScanTreeAndTypeAnnotate(tree.var.vartype, env, v, tree.var); + annotate.queueScanTreeAndTypeAnnotate(tree.var.vartype, env, v); } annotate.flush(); result = tree.type; @@ -4466,7 +4463,7 @@ public class Attr extends JCTree.Visitor { sym.kind == MTH && sym.name.equals(names.close) && sym.overrides(syms.autoCloseableClose, sitesym.type.tsym, types, true)) { - env.info.lint.logIfEnabled(tree, LintWarnings.TryExplicitCloseCall); + log.warning(tree, LintWarnings.TryExplicitCloseCall); } // Disallow selecting a type from an expression @@ -4493,9 +4490,9 @@ public class Attr extends JCTree.Visitor { // If the qualified item is not a type and the selected item is static, report // a warning. Make allowance for the class of an array type e.g. Object[].class) if (!sym.owner.isAnonymous()) { - chk.lint.logIfEnabled(tree, LintWarnings.StaticNotQualifiedByType(sym.kind.kindName(), sym.owner)); + log.warning(tree, LintWarnings.StaticNotQualifiedByType(sym.kind.kindName(), sym.owner)); } else { - chk.lint.logIfEnabled(tree, LintWarnings.StaticNotQualifiedByType2(sym.kind.kindName())); + log.warning(tree, LintWarnings.StaticNotQualifiedByType2(sym.kind.kindName())); } } @@ -5297,6 +5294,9 @@ public class Attr extends JCTree.Visitor { } annotate.flush(); + + // Now that this tree is attributed, we can calculate the Lint configuration everywhere within it + lintMapper.calculateLints(env.toplevel.sourcefile, env.tree, env.toplevel.endPositions); } public void attribPackage(DiagnosticPosition pos, PackageSymbol p) { @@ -5339,7 +5339,6 @@ public class Attr extends JCTree.Visitor { JavaFileObject prev = log.useSource(env.toplevel.sourcefile); try { - deferredLintHandler.flush(env.tree, lint); attrib.accept(env); } finally { log.useSource(prev); @@ -5523,7 +5522,6 @@ public class Attr extends JCTree.Visitor { } } - deferredLintHandler.flush(env.tree, env.info.lint); env.info.returnResult = null; // java.lang.Enum may not be subclassed by a non-enum if (st.tsym == syms.enumSym && @@ -5569,11 +5567,9 @@ public class Attr extends JCTree.Visitor { ModuleSymbol msym = tree.sym; Lint lint = env.outer.info.lint = env.outer.info.lint.augment(msym); Lint prevLint = chk.setLint(lint); - chk.checkModuleName(tree); - chk.checkDeprecatedAnnotation(tree, msym); - try { - deferredLintHandler.flush(tree, lint); + chk.checkModuleName(tree); + chk.checkDeprecatedAnnotation(tree, msym); } finally { chk.setLint(prevLint); } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java index ec328f391f9..3d9eff107da 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java @@ -121,7 +121,7 @@ public class Check { // The set of lint options currently in effect. It is initialized // from the context, and then is set/reset as needed by Attr as it // visits all the various parts of the trees during attribution. - Lint lint; + private Lint lint; // The method being analyzed in Attr - it is set/reset as needed by // Attr as it visits new method declarations. @@ -164,8 +164,6 @@ public class Check { profile = Profile.instance(context); preview = Preview.instance(context); - deferredLintHandler = DeferredLintHandler.instance(context); - allowModules = Feature.MODULES.allowedInSource(source); allowRecords = Feature.RECORDS.allowedInSource(source); allowSealed = Feature.SEALED_CLASSES.allowedInSource(source); @@ -180,10 +178,6 @@ public class Check { */ private Map,ClassSymbol> compiled = new HashMap<>(); - /** A handler for deferred lint warnings. - */ - private DeferredLintHandler deferredLintHandler; - /** Are modules allowed */ private final boolean allowModules; @@ -229,24 +223,15 @@ public class Check { * @param sym The deprecated symbol. */ void warnDeprecated(DiagnosticPosition pos, Symbol sym) { - LintWarning warningKey = null; - if (sym.isDeprecatedForRemoval()) { - if (!lint.isSuppressed(LintCategory.REMOVAL)) { - if (sym.kind == MDL) { - warningKey = LintWarnings.HasBeenDeprecatedForRemovalModule(sym); - } else { - warningKey = LintWarnings.HasBeenDeprecatedForRemoval(sym, sym.location()); - } - } - } else if (!lint.isSuppressed(LintCategory.DEPRECATION)) { - if (sym.kind == MDL) { - warningKey = LintWarnings.HasBeenDeprecatedModule(sym); - } else { - warningKey = LintWarnings.HasBeenDeprecated(sym, sym.location()); - } - } - if (warningKey != null) - log.warning(pos, warningKey); + Assert.check(!importSuppression); + LintWarning warningKey = sym.isDeprecatedForRemoval() ? + (sym.kind == MDL ? + LintWarnings.HasBeenDeprecatedForRemovalModule(sym) : + LintWarnings.HasBeenDeprecatedForRemoval(sym, sym.location())) : + (sym.kind == MDL ? + LintWarnings.HasBeenDeprecatedModule(sym) : + LintWarnings.HasBeenDeprecated(sym, sym.location())); + log.warning(pos, warningKey); } /** Log a preview warning. @@ -254,25 +239,16 @@ public class Check { * @param msg A Warning describing the problem. */ public void warnPreviewAPI(DiagnosticPosition pos, LintWarning warnKey) { - if (!importSuppression && !lint.isSuppressed(LintCategory.PREVIEW)) + if (!importSuppression) log.warning(pos, warnKey); } - /** Log a preview warning. - * @param pos Position to be used for error reporting. - * @param msg A Warning describing the problem. - */ - public void warnRestrictedAPI(DiagnosticPosition pos, Symbol sym) { - lint.logIfEnabled(pos, LintWarnings.RestrictedMethod(sym.enclClass(), sym)); - } - /** Warn about unchecked operation. * @param pos Position to be used for error reporting. * @param msg A string describing the problem. */ public void warnUnchecked(DiagnosticPosition pos, LintWarning warnKey) { - if (!lint.isSuppressed(LintCategory.UNCHECKED)) - log.warning(pos, warnKey); + log.warning(pos, warnKey); } /** Report a failure to complete a class. @@ -608,9 +584,7 @@ public class Check { && types.isSameType(tree.expr.type, tree.clazz.type) && !(ignoreAnnotatedCasts && TreeInfo.containsTypeAnnotation(tree.clazz)) && !is292targetTypeCast(tree)) { - deferredLintHandler.report(_l -> { - lint.logIfEnabled(tree.pos(), LintWarnings.RedundantCast(tree.clazz.type)); - }); + log.warning(tree.pos(), LintWarnings.RedundantCast(tree.clazz.type)); } } //where @@ -914,7 +888,7 @@ public class Check { } } else if (hasTrustMeAnno && varargElemType != null && types.isReifiable(varargElemType)) { - lint.logIfEnabled(tree, LintWarnings.VarargsRedundantTrustmeAnno( + log.warning(tree.pos(), LintWarnings.VarargsRedundantTrustmeAnno( syms.trustMeType.tsym, diags.fragment(Fragments.VarargsTrustmeOnReifiableVarargs(varargElemType)))); } @@ -1173,7 +1147,7 @@ public class Check { mask = MethodFlags; } if ((flags & STRICTFP) != 0) { - warnOnExplicitStrictfp(tree); + log.warning(tree.pos(), LintWarnings.Strictfp); } // Imply STRICTFP if owner has STRICTFP set. if (((flags|implicit) & Flags.ABSTRACT) == 0 || @@ -1217,7 +1191,7 @@ public class Check { implicit |= FINAL; } if ((flags & STRICTFP) != 0) { - warnOnExplicitStrictfp(tree); + log.warning(tree.pos(), LintWarnings.Strictfp); } // Imply STRICTFP if owner has STRICTFP set. implicit |= sym.owner.flags_field & STRICTFP; @@ -1281,16 +1255,6 @@ public class Check { return flags & (mask | ~ExtendedStandardFlags) | implicit; } - private void warnOnExplicitStrictfp(JCTree tree) { - deferredLintHandler.push(tree); - try { - deferredLintHandler.report(_ -> lint.logIfEnabled(tree.pos(), LintWarnings.Strictfp)); - } finally { - deferredLintHandler.pop(); - } - } - - /** Determine if this enum should be implicitly final. * * If the enum has no specialized enum constants, it is final. @@ -1503,7 +1467,7 @@ public class Check { !TreeInfo.isDiamond(tree) && !withinAnonConstr(env) && tree.type.isRaw()) { - lint.logIfEnabled(tree.pos(), LintWarnings.RawClassUse(tree.type, tree.type.tsym.type)); + log.warning(tree.pos(), LintWarnings.RawClassUse(tree.type, tree.type.tsym.type)); } } //where @@ -1827,7 +1791,7 @@ public class Check { // Optional warning if varargs don't agree if ((((m.flags() ^ other.flags()) & Flags.VARARGS) != 0)) { - lint.logIfEnabled(TreeInfo.diagnosticPositionFor(m, tree), + log.warning(TreeInfo.diagnosticPositionFor(m, tree), ((m.flags() & Flags.VARARGS) != 0) ? LintWarnings.OverrideVarargsMissing(varargsOverrides(m, other)) : LintWarnings.OverrideVarargsExtra(varargsOverrides(m, other))); @@ -1841,12 +1805,7 @@ public class Check { // Warn if a deprecated method overridden by a non-deprecated one. if (!isDeprecatedOverrideIgnorable(other, origin)) { - Lint prevLint = setLint(lint.augment(m)); - try { - checkDeprecated(() -> TreeInfo.diagnosticPositionFor(m, tree), m, other); - } finally { - setLint(prevLint); - } + checkDeprecated(() -> TreeInfo.diagnosticPositionFor(m, tree), m, other); } } // where @@ -2915,42 +2874,33 @@ public class Check { // Apply special flag "-XDwarnOnAccessToMembers" which turns on just this particular warning for all types of access void checkAccessFromSerializableElement(final JCTree tree, boolean isLambda) { - final Lint prevLint = setLint(warnOnAnyAccessToMembers ? lint.enable(LintCategory.SERIAL) : lint); - try { - if (warnOnAnyAccessToMembers || isLambda) - checkAccessFromSerializableElementInner(tree, isLambda); - } finally { - setLint(prevLint); - } + if (warnOnAnyAccessToMembers || isLambda) + checkAccessFromSerializableElementInner(tree, isLambda); } private void checkAccessFromSerializableElementInner(final JCTree tree, boolean isLambda) { - if (lint.isEnabled(LintCategory.SERIAL)) { - Symbol sym = TreeInfo.symbol(tree); - if (!sym.kind.matches(KindSelector.VAL_MTH)) { + Symbol sym = TreeInfo.symbol(tree); + if (!sym.kind.matches(KindSelector.VAL_MTH)) { + return; + } + + if (sym.kind == VAR) { + if ((sym.flags() & PARAMETER) != 0 || + sym.isDirectlyOrIndirectlyLocal() || + sym.name == names._this || + sym.name == names._super) { return; } + } - if (sym.kind == VAR) { - if ((sym.flags() & PARAMETER) != 0 || - sym.isDirectlyOrIndirectlyLocal() || - sym.name == names._this || - sym.name == names._super) { - return; - } - } - - if (!types.isSubtype(sym.owner.type, syms.serializableType) && - isEffectivelyNonPublic(sym)) { - if (isLambda) { - if (belongsToRestrictedPackage(sym)) { - log.warning(tree.pos(), - LintWarnings.AccessToMemberFromSerializableLambda(sym)); - } - } else { - log.warning(tree.pos(), - LintWarnings.AccessToMemberFromSerializableElement(sym)); + if (!types.isSubtype(sym.owner.type, syms.serializableType) && isEffectivelyNonPublic(sym)) { + DiagnosticFlag flag = warnOnAnyAccessToMembers ? DiagnosticFlag.DEFAULT_ENABLED : null; + if (isLambda) { + if (belongsToRestrictedPackage(sym)) { + log.warning(flag, tree.pos(), LintWarnings.AccessToMemberFromSerializableLambda(sym)); } + } else { + log.warning(flag, tree.pos(), LintWarnings.AccessToMemberFromSerializableElement(sym)); } } } @@ -3737,8 +3687,7 @@ public class Check { // Note: @Deprecated has no effect on local variables, parameters and package decls. if (lint.isEnabled(LintCategory.DEPRECATION) && !s.isDeprecatableViaAnnotation()) { if (!syms.deprecatedType.isErroneous() && s.attribute(syms.deprecatedType.tsym) != null) { - log.warning(pos, - LintWarnings.DeprecatedAnnotationHasNoEffect(Kinds.kindName(s))); + log.warning(pos, LintWarnings.DeprecatedAnnotationHasNoEffect(Kinds.kindName(s))); } } } @@ -3752,15 +3701,13 @@ public class Check { && (s.isDeprecatedForRemoval() || s.isDeprecated() && !other.isDeprecated()) && (s.outermostClass() != other.outermostClass() || s.outermostClass() == null) && s.kind != Kind.PCK) { - deferredLintHandler.report(_l -> warnDeprecated(pos.get(), s)); + warnDeprecated(pos.get(), s); } } void checkSunAPI(final DiagnosticPosition pos, final Symbol s) { if ((s.flags() & PROPRIETARY) != 0) { - deferredLintHandler.report(_l -> { - log.warning(pos, Warnings.SunProprietary(s)); - }); + log.warning(pos, Warnings.SunProprietary(s)); } } @@ -3817,7 +3764,7 @@ public class Check { void checkRestricted(DiagnosticPosition pos, Symbol s) { if (s.kind == MTH && (s.flags() & RESTRICTED) != 0) { - deferredLintHandler.report(_l -> warnRestrictedAPI(pos, s)); + log.warning(pos, LintWarnings.RestrictedMethod(s.enclClass(), s)); } } @@ -4089,7 +4036,7 @@ public class Check { int opc = ((OperatorSymbol)operator).opcode; if (opc == ByteCodes.idiv || opc == ByteCodes.imod || opc == ByteCodes.ldiv || opc == ByteCodes.lmod) { - deferredLintHandler.report(_ -> lint.logIfEnabled(pos, LintWarnings.DivZero)); + log.warning(pos, LintWarnings.DivZero); } } } @@ -4102,8 +4049,7 @@ public class Check { */ void checkLossOfPrecision(final DiagnosticPosition pos, Type found, Type req) { if (found.isNumeric() && req.isNumeric() && !types.isAssignable(found, req)) { - deferredLintHandler.report(_ -> - lint.logIfEnabled(pos, LintWarnings.PossibleLossOfPrecision(found, req))); + log.warning(pos, LintWarnings.PossibleLossOfPrecision(found, req)); } } @@ -4112,7 +4058,7 @@ public class Check { */ void checkEmptyIf(JCIf tree) { if (tree.thenpart.hasTag(SKIP) && tree.elsepart == null) { - lint.logIfEnabled(tree.thenpart.pos(), LintWarnings.EmptyIf); + log.warning(tree.thenpart.pos(), LintWarnings.EmptyIf); } } @@ -4259,8 +4205,7 @@ public class Check { rs.isAccessible(env, c) && !fileManager.isSameFile(c.sourcefile, env.toplevel.sourcefile)) { - lint.logIfEnabled(pos, - LintWarnings.AuxiliaryClassAccessedFromOutsideOfItsSourceFile(c, c.sourcefile)); + log.warning(pos, LintWarnings.AuxiliaryClassAccessedFromOutsideOfItsSourceFile(c, c.sourcefile)); } } @@ -4302,8 +4247,7 @@ public class Check { // Warning may be suppressed by // annotations; check again for being // enabled in the deferred context. - deferredLintHandler.report(_ -> - lint.logIfEnabled(pos, LintWarnings.MissingExplicitCtor(c, pkg, modle))); + log.warning(pos, LintWarnings.MissingExplicitCtor(c, pkg, modle)); } else { return; } @@ -4339,7 +4283,7 @@ public class Check { method.attribute(syms.trustMeType.tsym) != null && isTrustMeAllowedOnMethod(method) && !types.isReifiable(method.type.getParameterTypes().last())) { - Check.this.lint.logIfEnabled(pos(), LintWarnings.VarargsUnsafeUseVarargsParam(method.params.last())); + log.warning(pos(), LintWarnings.VarargsUnsafeUseVarargsParam(method.params.last())); } break; default: @@ -4637,28 +4581,24 @@ public class Check { void checkModuleExists(final DiagnosticPosition pos, ModuleSymbol msym) { if (msym.kind != MDL) { - deferredLintHandler.report(_ -> - lint.logIfEnabled(pos, LintWarnings.ModuleNotFound(msym))); + log.warning(pos, LintWarnings.ModuleNotFound(msym)); } } void checkPackageExistsForOpens(final DiagnosticPosition pos, PackageSymbol packge) { if (packge.members().isEmpty() && ((packge.flags() & Flags.HAS_RESOURCE) == 0)) { - deferredLintHandler.report(_ -> - lint.logIfEnabled(pos, LintWarnings.PackageEmptyOrNotFound(packge))); + log.warning(pos, LintWarnings.PackageEmptyOrNotFound(packge)); } } void checkModuleRequires(final DiagnosticPosition pos, final RequiresDirective rd) { if ((rd.module.flags() & Flags.AUTOMATIC_MODULE) != 0) { - deferredLintHandler.report(_ -> { - if (rd.isTransitive() && lint.isEnabled(LintCategory.REQUIRES_TRANSITIVE_AUTOMATIC)) { - log.warning(pos, LintWarnings.RequiresTransitiveAutomatic); - } else { - lint.logIfEnabled(pos, LintWarnings.RequiresAutomatic); - } - }); + if (rd.isTransitive()) { // see comment in Log.applyLint() for special logic that applies + log.warning(pos, LintWarnings.RequiresTransitiveAutomatic); + } else { + log.warning(pos, LintWarnings.RequiresAutomatic); + } } } @@ -5693,14 +5633,14 @@ public class Check { VarSymbol lastParam = ms.params.head; for (VarSymbol param: ms.params) { if ((param.flags_field & REQUIRES_IDENTITY) != 0 && argExps.head.type.isValueBased()) { - lint.logIfEnabled(argExps.head.pos(), LintWarnings.AttemptToUseValueBasedWhereIdentityExpected); + log.warning(argExps.head.pos(), LintWarnings.AttemptToUseValueBasedWhereIdentityExpected); } lastParam = param; argExps = argExps.tail; } while (argExps != null && !argExps.isEmpty() && lastParam != null) { if ((lastParam.flags_field & REQUIRES_IDENTITY) != 0 && argExps.head.type.isValueBased()) { - lint.logIfEnabled(argExps.head.pos(), LintWarnings.AttemptToUseValueBasedWhereIdentityExpected); + log.warning(argExps.head.pos(), LintWarnings.AttemptToUseValueBasedWhereIdentityExpected); } argExps = argExps.tail; } @@ -5727,7 +5667,7 @@ public class Check { // we need to avoid recursion due to self referencing type vars or captures, this is why we need a set requiresIdentityVisitor.visit(t, new HashSet<>()); if (requiresIdentityVisitor.requiresWarning) { - lint.logIfEnabled(pos, LintWarnings.AttemptToUseValueBasedWhereIdentityExpected); + log.warning(pos, LintWarnings.AttemptToUseValueBasedWhereIdentityExpected); return true; } } @@ -5804,7 +5744,7 @@ public class Check { .filter(ta -> isRequiresIdentityAnnotation(ta.type.tsym) && typeParamTrees.get(ta.position.parameter_index).type != null && typeParamTrees.get(ta.position.parameter_index).type.isValueBased()) - .forEach(ta -> lint.logIfEnabled(typeParamTrees.get(ta.position.parameter_index).pos(), + .forEach(ta -> log.warning(typeParamTrees.get(ta.position.parameter_index).pos(), CompilerProperties.LintWarnings.AttemptToUseValueBasedWhereIdentityExpected)); } } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java index e685f139b68..3bbd007c66a 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java @@ -214,7 +214,6 @@ public class Flow { private final Resolve rs; private final JCDiagnostic.Factory diags; private Env attrEnv; - private Lint lint; private final Infer infer; public static Flow instance(Context context) { @@ -337,7 +336,6 @@ public class Flow { syms = Symtab.instance(context); types = Types.instance(context); chk = Check.instance(context); - lint = Lint.instance(context); infer = Infer.instance(context); rs = Resolve.instance(context); diags = JCDiagnostic.Factory.instance(context); @@ -562,10 +560,8 @@ public class Flow { if (tree.sym == null) return; Liveness alivePrev = alive; ListBuffer pendingExitsPrev = pendingExits; - Lint lintPrev = lint; pendingExits = new ListBuffer<>(); - lint = lint.augment(tree.sym); try { // process all the nested classes @@ -596,30 +592,22 @@ public class Flow { } finally { pendingExits = pendingExitsPrev; alive = alivePrev; - lint = lintPrev; } } public void visitMethodDef(JCMethodDecl tree) { if (tree.body == null) return; - Lint lintPrev = lint; - - lint = lint.augment(tree.sym); Assert.check(pendingExits.isEmpty()); - try { - alive = Liveness.ALIVE; - scanStat(tree.body); - tree.completesNormally = alive != Liveness.DEAD; + alive = Liveness.ALIVE; + scanStat(tree.body); + tree.completesNormally = alive != Liveness.DEAD; - if (alive == Liveness.ALIVE && !tree.sym.type.getReturnType().hasTag(VOID)) - log.error(TreeInfo.diagEndPos(tree.body), Errors.MissingRetStmt); + if (alive == Liveness.ALIVE && !tree.sym.type.getReturnType().hasTag(VOID)) + log.error(TreeInfo.diagEndPos(tree.body), Errors.MissingRetStmt); - clearPendingExits(true); - } finally { - lint = lintPrev; - } + clearPendingExits(true); } private void clearPendingExits(boolean inMethod) { @@ -634,15 +622,7 @@ public class Flow { } public void visitVarDef(JCVariableDecl tree) { - if (tree.init != null) { - Lint lintPrev = lint; - lint = lint.augment(tree.sym); - try{ - scan(tree.init); - } finally { - lint = lintPrev; - } - } + scan(tree.init); } public void visitBlock(JCBlock tree) { @@ -724,8 +704,7 @@ public class Flow { // Warn about fall-through if lint switch fallthrough enabled. if (alive == Liveness.ALIVE && c.stats.nonEmpty() && l.tail.nonEmpty()) - lint.logIfEnabled(l.tail.head.pos(), - LintWarnings.PossibleFallThroughIntoCase); + log.warning(l.tail.head.pos(), LintWarnings.PossibleFallThroughIntoCase); } tree.isExhaustive = tree.hasUnconditionalPattern || TreeInfo.isErrorEnumSwitch(tree.selector, tree.cases); @@ -1232,7 +1211,7 @@ public class Flow { scanStat(tree.finalizer); tree.finallyCanCompleteNormally = alive != Liveness.DEAD; if (alive == Liveness.DEAD) { - lint.logIfEnabled(TreeInfo.diagEndPos(tree.finalizer), + log.warning(TreeInfo.diagEndPos(tree.finalizer), LintWarnings.FinallyCannotComplete); } else { while (exits.nonEmpty()) { @@ -1453,7 +1432,6 @@ public class Flow { List thrownPrev = thrown; List caughtPrev = caught; ListBuffer pendingExitsPrev = pendingExits; - Lint lintPrev = lint; boolean anonymousClass = tree.name == names.empty; pendingExits = new ListBuffer<>(); if (!anonymousClass) { @@ -1461,7 +1439,6 @@ public class Flow { } classDef = tree; thrown = List.nil(); - lint = lint.augment(tree.sym); try { // process all the nested classes @@ -1510,7 +1487,6 @@ public class Flow { pendingExits = pendingExitsPrev; caught = caughtPrev; classDef = classDefPrev; - lint = lintPrev; } } @@ -1519,9 +1495,6 @@ public class Flow { List caughtPrev = caught; List mthrown = tree.sym.type.getThrownTypes(); - Lint lintPrev = lint; - - lint = lint.augment(tree.sym); Assert.check(pendingExits.isEmpty()); @@ -1554,20 +1527,11 @@ public class Flow { } } finally { caught = caughtPrev; - lint = lintPrev; } } public void visitVarDef(JCVariableDecl tree) { - if (tree.init != null) { - Lint lintPrev = lint; - lint = lint.augment(tree.sym); - try{ - scan(tree.init); - } finally { - lint = lintPrev; - } - } + scan(tree.init); } public void visitBlock(JCBlock tree) { @@ -2387,82 +2351,76 @@ public class Flow { return; } - Lint lintPrev = lint; - lint = lint.augment(tree.sym); + JCClassDecl classDefPrev = classDef; + int firstadrPrev = firstadr; + int nextadrPrev = nextadr; + ListBuffer pendingExitsPrev = pendingExits; + + pendingExits = new ListBuffer<>(); + if (tree.name != names.empty) { + firstadr = nextadr; + } + classDef = tree; try { - JCClassDecl classDefPrev = classDef; - int firstadrPrev = firstadr; - int nextadrPrev = nextadr; - ListBuffer pendingExitsPrev = pendingExits; - - pendingExits = new ListBuffer<>(); - if (tree.name != names.empty) { - firstadr = nextadr; + // define all the static fields + for (List l = tree.defs; l.nonEmpty(); l = l.tail) { + if (l.head.hasTag(VARDEF)) { + JCVariableDecl def = (JCVariableDecl)l.head; + if ((def.mods.flags & STATIC) != 0) { + VarSymbol sym = def.sym; + if (trackable(sym)) { + newVar(def); + } + } + } } - classDef = tree; - try { - // define all the static fields - for (List l = tree.defs; l.nonEmpty(); l = l.tail) { - if (l.head.hasTag(VARDEF)) { - JCVariableDecl def = (JCVariableDecl)l.head; - if ((def.mods.flags & STATIC) != 0) { - VarSymbol sym = def.sym; - if (trackable(sym)) { - newVar(def); - } + + // process all the static initializers + forEachInitializer(tree, true, def -> { + scan(def); + clearPendingExits(false); + }); + + // verify all static final fields got initialized + for (int i = firstadr; i < nextadr; i++) { + JCVariableDecl vardecl = vardecls[i]; + VarSymbol var = vardecl.sym; + if (var.owner == classDef.sym && var.isStatic()) { + checkInit(TreeInfo.diagnosticPositionFor(var, vardecl), var); + } + } + + // define all the instance fields + for (List l = tree.defs; l.nonEmpty(); l = l.tail) { + if (l.head.hasTag(VARDEF)) { + JCVariableDecl def = (JCVariableDecl)l.head; + if ((def.mods.flags & STATIC) == 0) { + VarSymbol sym = def.sym; + if (trackable(sym)) { + newVar(def); } } } + } - // process all the static initializers - forEachInitializer(tree, true, def -> { - scan(def); - clearPendingExits(false); - }); - - // verify all static final fields got initialized - for (int i = firstadr; i < nextadr; i++) { - JCVariableDecl vardecl = vardecls[i]; - VarSymbol var = vardecl.sym; - if (var.owner == classDef.sym && var.isStatic()) { - checkInit(TreeInfo.diagnosticPositionFor(var, vardecl), var); - } + // process all the methods + for (List l = tree.defs; l.nonEmpty(); l = l.tail) { + if (l.head.hasTag(METHODDEF)) { + scan(l.head); } + } - // define all the instance fields - for (List l = tree.defs; l.nonEmpty(); l = l.tail) { - if (l.head.hasTag(VARDEF)) { - JCVariableDecl def = (JCVariableDecl)l.head; - if ((def.mods.flags & STATIC) == 0) { - VarSymbol sym = def.sym; - if (trackable(sym)) { - newVar(def); - } - } - } + // process all the nested classes + for (List l = tree.defs; l.nonEmpty(); l = l.tail) { + if (l.head.hasTag(CLASSDEF)) { + scan(l.head); } - - // process all the methods - for (List l = tree.defs; l.nonEmpty(); l = l.tail) { - if (l.head.hasTag(METHODDEF)) { - scan(l.head); - } - } - - // process all the nested classes - for (List l = tree.defs; l.nonEmpty(); l = l.tail) { - if (l.head.hasTag(CLASSDEF)) { - scan(l.head); - } - } - } finally { - pendingExits = pendingExitsPrev; - nextadr = nextadrPrev; - firstadr = firstadrPrev; - classDef = classDefPrev; } } finally { - lint = lintPrev; + pendingExits = pendingExitsPrev; + nextadr = nextadrPrev; + firstadr = firstadrPrev; + classDef = classDefPrev; } } @@ -2477,87 +2435,81 @@ public class Flow { return; } - Lint lintPrev = lint; - lint = lint.augment(tree.sym); + final Bits initsPrev = new Bits(inits); + final Bits uninitsPrev = new Bits(uninits); + int nextadrPrev = nextadr; + int firstadrPrev = firstadr; + int returnadrPrev = returnadr; + + Assert.check(pendingExits.isEmpty()); + boolean isConstructorPrev = isConstructor; try { - final Bits initsPrev = new Bits(inits); - final Bits uninitsPrev = new Bits(uninits); - int nextadrPrev = nextadr; - int firstadrPrev = firstadr; - int returnadrPrev = returnadr; + isConstructor = TreeInfo.isConstructor(tree); - Assert.check(pendingExits.isEmpty()); - boolean isConstructorPrev = isConstructor; - try { - isConstructor = TreeInfo.isConstructor(tree); + // We only track field initialization inside constructors + if (!isConstructor) { + firstadr = nextadr; + } - // We only track field initialization inside constructors - if (!isConstructor) { - firstadr = nextadr; - } + // Mark all method parameters as DA + for (List l = tree.params; l.nonEmpty(); l = l.tail) { + JCVariableDecl def = l.head; + scan(def); + Assert.check((def.sym.flags() & PARAMETER) != 0, "Method parameter without PARAMETER flag"); + /* If we are executing the code from Gen, then there can be + * synthetic or mandated variables, ignore them. + */ + initParam(def); + } + // else we are in an instance initializer block; + // leave caught unchanged. + scan(tree.body); - // Mark all method parameters as DA - for (List l = tree.params; l.nonEmpty(); l = l.tail) { - JCVariableDecl def = l.head; - scan(def); - Assert.check((def.sym.flags() & PARAMETER) != 0, "Method parameter without PARAMETER flag"); - /* If we are executing the code from Gen, then there can be - * synthetic or mandated variables, ignore them. - */ - initParam(def); - } - // else we are in an instance initializer block; - // leave caught unchanged. - scan(tree.body); - - boolean isCompactOrGeneratedRecordConstructor = (tree.sym.flags() & Flags.COMPACT_RECORD_CONSTRUCTOR) != 0 || - (tree.sym.flags() & (GENERATEDCONSTR | RECORD)) == (GENERATEDCONSTR | RECORD); - if (isConstructor) { - boolean isSynthesized = (tree.sym.flags() & - GENERATEDCONSTR) != 0; - for (int i = firstadr; i < nextadr; i++) { - JCVariableDecl vardecl = vardecls[i]; - VarSymbol var = vardecl.sym; - if (var.owner == classDef.sym && !var.isStatic()) { - // choose the diagnostic position based on whether - // the ctor is default(synthesized) or not - if (isSynthesized && !isCompactOrGeneratedRecordConstructor) { - checkInit(TreeInfo.diagnosticPositionFor(var, vardecl), - var, Errors.VarNotInitializedInDefaultConstructor(var)); - } else if (isCompactOrGeneratedRecordConstructor) { - boolean isInstanceRecordField = var.enclClass().isRecord() && - (var.flags_field & (Flags.PRIVATE | Flags.FINAL | Flags.GENERATED_MEMBER | Flags.RECORD)) != 0 && - var.owner.kind == TYP; - if (isInstanceRecordField) { - boolean notInitialized = !inits.isMember(var.adr); - if (notInitialized && uninits.isMember(var.adr) && tree.completesNormally) { - /* this way we indicate Lower that it should generate an initialization for this field - * in the compact constructor - */ - var.flags_field |= UNINITIALIZED_FIELD; - } else { - checkInit(TreeInfo.diagEndPos(tree.body), var); - } + boolean isCompactOrGeneratedRecordConstructor = (tree.sym.flags() & Flags.COMPACT_RECORD_CONSTRUCTOR) != 0 || + (tree.sym.flags() & (GENERATEDCONSTR | RECORD)) == (GENERATEDCONSTR | RECORD); + if (isConstructor) { + boolean isSynthesized = (tree.sym.flags() & + GENERATEDCONSTR) != 0; + for (int i = firstadr; i < nextadr; i++) { + JCVariableDecl vardecl = vardecls[i]; + VarSymbol var = vardecl.sym; + if (var.owner == classDef.sym && !var.isStatic()) { + // choose the diagnostic position based on whether + // the ctor is default(synthesized) or not + if (isSynthesized && !isCompactOrGeneratedRecordConstructor) { + checkInit(TreeInfo.diagnosticPositionFor(var, vardecl), + var, Errors.VarNotInitializedInDefaultConstructor(var)); + } else if (isCompactOrGeneratedRecordConstructor) { + boolean isInstanceRecordField = var.enclClass().isRecord() && + (var.flags_field & (Flags.PRIVATE | Flags.FINAL | Flags.GENERATED_MEMBER | Flags.RECORD)) != 0 && + var.owner.kind == TYP; + if (isInstanceRecordField) { + boolean notInitialized = !inits.isMember(var.adr); + if (notInitialized && uninits.isMember(var.adr) && tree.completesNormally) { + /* this way we indicate Lower that it should generate an initialization for this field + * in the compact constructor + */ + var.flags_field |= UNINITIALIZED_FIELD; } else { - checkInit(TreeInfo.diagnosticPositionFor(var, vardecl), var); + checkInit(TreeInfo.diagEndPos(tree.body), var); } } else { - checkInit(TreeInfo.diagEndPos(tree.body), var); + checkInit(TreeInfo.diagnosticPositionFor(var, vardecl), var); } + } else { + checkInit(TreeInfo.diagEndPos(tree.body), var); } } } - clearPendingExits(true); - } finally { - inits.assign(initsPrev); - uninits.assign(uninitsPrev); - nextadr = nextadrPrev; - firstadr = firstadrPrev; - returnadr = returnadrPrev; - isConstructor = isConstructorPrev; } + clearPendingExits(true); } finally { - lint = lintPrev; + inits.assign(initsPrev); + uninits.assign(uninitsPrev); + nextadr = nextadrPrev; + firstadr = firstadrPrev; + returnadr = returnadrPrev; + isConstructor = isConstructorPrev; } } @@ -2585,21 +2537,15 @@ public class Flow { } public void visitVarDef(JCVariableDecl tree) { - Lint lintPrev = lint; - lint = lint.augment(tree.sym); - try{ - boolean track = trackable(tree.sym); - if (track && (tree.sym.owner.kind == MTH || tree.sym.owner.kind == VAR)) { - newVar(tree); + boolean track = trackable(tree.sym); + if (track && (tree.sym.owner.kind == MTH || tree.sym.owner.kind == VAR)) { + newVar(tree); + } + if (tree.init != null) { + scanExpr(tree.init); + if (track) { + letInit(tree.pos(), tree.sym); } - if (tree.init != null) { - scanExpr(tree.init); - if (track) { - letInit(tree.pos(), tree.sym); - } - } - } finally { - lint = lintPrev; } } @@ -2851,8 +2797,7 @@ public class Flow { final Bits uninitsEnd = new Bits(uninits); int nextadrCatch = nextadr; - if (!resourceVarDecls.isEmpty() && - lint.isEnabled(Lint.LintCategory.TRY)) { + if (!resourceVarDecls.isEmpty()) { for (JCVariableDecl resVar : resourceVarDecls) { if (unrefdResources.includes(resVar.sym) && !resVar.sym.isUnnamedVariable()) { log.warning(resVar.pos(), diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java index b726cc7a61d..d63ba1677d6 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java @@ -66,7 +66,6 @@ public class MemberEnter extends JCTree.Visitor { private final Annotate annotate; private final Types types; private final Names names; - private final DeferredLintHandler deferredLintHandler; public static MemberEnter instance(Context context) { MemberEnter instance = context.get(memberEnterKey); @@ -87,7 +86,6 @@ public class MemberEnter extends JCTree.Visitor { types = Types.instance(context); source = Source.instance(context); names = Names.instance(context); - deferredLintHandler = DeferredLintHandler.instance(context); } /** Construct method type from method signature. @@ -194,16 +192,11 @@ public class MemberEnter extends JCTree.Visitor { } Env localEnv = methodEnv(tree, env); - deferredLintHandler.push(tree); - try { - // Compute the method type - m.type = signature(m, tree.typarams, tree.params, - tree.restype, tree.recvparam, - tree.thrown, - localEnv); - } finally { - deferredLintHandler.pop(); - } + // Compute the method type + m.type = signature(m, tree.typarams, tree.params, + tree.restype, tree.recvparam, + tree.thrown, + localEnv); if (types.isSignaturePolymorphic(m)) { m.flags_field |= SIGNATURE_POLYMORPHIC; @@ -227,14 +220,14 @@ public class MemberEnter extends JCTree.Visitor { enclScope.enter(m); } - annotate.annotateLater(tree.mods.annotations, localEnv, m, tree); + annotate.annotateLater(tree.mods.annotations, localEnv, m); // Visit the signature of the method. Note that // TypeAnnotate doesn't descend into the body. - annotate.queueScanTreeAndTypeAnnotate(tree, localEnv, m, tree); + annotate.queueScanTreeAndTypeAnnotate(tree, localEnv, m); if (tree.defaultValue != null) { m.defaultValue = annotate.unfinishedDefaultValue(); // set it to temporary sentinel for now - annotate.annotateDefaultValueLater(tree.defaultValue, localEnv, m, tree); + annotate.annotateDefaultValueLater(tree.defaultValue, localEnv, m); } } @@ -263,18 +256,13 @@ public class MemberEnter extends JCTree.Visitor { localEnv = env.dup(tree, env.info.dup()); localEnv.info.staticLevel++; } - deferredLintHandler.push(tree); - try { - if (TreeInfo.isEnumInit(tree)) { - attr.attribIdentAsEnumType(localEnv, (JCIdent)tree.vartype); - } else if (!tree.isImplicitlyTyped()) { - attr.attribType(tree.vartype, localEnv); - if (TreeInfo.isReceiverParam(tree)) - checkReceiver(tree, localEnv); - } - } finally { - deferredLintHandler.pop(); + if (TreeInfo.isEnumInit(tree)) { + attr.attribIdentAsEnumType(localEnv, (JCIdent)tree.vartype); + } else if (!tree.isImplicitlyTyped()) { + attr.attribType(tree.vartype, localEnv); + if (TreeInfo.isReceiverParam(tree)) + checkReceiver(tree, localEnv); } if ((tree.mods.flags & VARARGS) != 0) { @@ -315,9 +303,9 @@ public class MemberEnter extends JCTree.Visitor { } } - annotate.annotateLater(tree.mods.annotations, localEnv, v, tree); + annotate.annotateLater(tree.mods.annotations, localEnv, v); if (!tree.isImplicitlyTyped()) { - annotate.queueScanTreeAndTypeAnnotate(tree.vartype, localEnv, v, tree); + annotate.queueScanTreeAndTypeAnnotate(tree.vartype, localEnv, v); } v.pos = tree.pos; diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Modules.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Modules.java index 4d0af014d83..0cef9cc6602 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Modules.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Modules.java @@ -52,7 +52,6 @@ import javax.tools.JavaFileObject.Kind; import javax.tools.StandardLocation; import com.sun.source.tree.ModuleTree.ModuleKind; -import com.sun.tools.javac.code.DeferredLintHandler; import com.sun.tools.javac.code.Directive; import com.sun.tools.javac.code.Directive.ExportsDirective; import com.sun.tools.javac.code.Directive.ExportsFlag; @@ -141,7 +140,6 @@ public class Modules extends JCTree.Visitor { private final Attr attr; private final Check chk; private final Preview preview; - private final DeferredLintHandler deferredLintHandler; private final TypeEnvs typeEnvs; private final Types types; private final JavaFileManager fileManager; @@ -169,8 +167,6 @@ public class Modules extends JCTree.Visitor { private final String moduleVersionOpt; private final boolean sourceLauncher; - private final boolean lintOptions; - private Set rootModules = null; private final Set warnedMissing = new HashSet<>(); @@ -193,7 +189,6 @@ public class Modules extends JCTree.Visitor { attr = Attr.instance(context); chk = Check.instance(context); preview = Preview.instance(context); - deferredLintHandler = DeferredLintHandler.instance(context); typeEnvs = TypeEnvs.instance(context); moduleFinder = ModuleFinder.instance(context); types = Types.instance(context); @@ -205,8 +200,6 @@ public class Modules extends JCTree.Visitor { allowAccessIntoSystem = options.isUnset(Option.RELEASE); - lintOptions = !options.isLintDisabled(LintCategory.OPTIONS); - multiModuleMode = fileManager.hasLocation(StandardLocation.MODULE_SOURCE_PATH); ClassWriter classWriter = ClassWriter.instance(context); classWriter.multiModuleMode = multiModuleMode; @@ -746,7 +739,6 @@ public class Modules extends JCTree.Visitor { ModuleVisitor v = new ModuleVisitor(); JavaFileObject prev = log.useSource(tree.sourcefile); JCModuleDecl moduleDecl = tree.getModuleDecl(); - deferredLintHandler.push(moduleDecl); try { moduleDecl.accept(v); @@ -754,7 +746,6 @@ public class Modules extends JCTree.Visitor { checkCyclicDependencies(moduleDecl); } finally { log.useSource(prev); - deferredLintHandler.pop(); msym.flags_field &= ~UNATTRIBUTED; } } @@ -991,13 +982,11 @@ public class Modules extends JCTree.Visitor { UsesProvidesVisitor v = new UsesProvidesVisitor(msym, env); JavaFileObject prev = log.useSource(env.toplevel.sourcefile); JCModuleDecl decl = env.toplevel.getModuleDecl(); - deferredLintHandler.push(decl); try { decl.accept(v); } finally { log.useSource(prev); - deferredLintHandler.pop(); } }; } @@ -1263,12 +1252,9 @@ public class Modules extends JCTree.Visitor { } observable = computeTransitiveClosure(limitMods, rootModules, null); observable.addAll(rootModules); - if (lintOptions) { - for (ModuleSymbol msym : limitMods) { - if (!observable.contains(msym)) { - log.warning( - LintWarnings.ModuleForOptionNotFound(Option.LIMIT_MODULES, msym)); - } + for (ModuleSymbol msym : limitMods) { + if (!observable.contains(msym)) { + log.warning(LintWarnings.ModuleForOptionNotFound(Option.LIMIT_MODULES, msym)); } } } @@ -1721,10 +1707,7 @@ public class Modules extends JCTree.Visitor { } if (!unknownModules.contains(msym)) { - if (lintOptions) { - log.warning( - LintWarnings.ModuleForOptionNotFound(Option.ADD_EXPORTS, msym)); - } + log.warning(LintWarnings.ModuleForOptionNotFound(Option.ADD_EXPORTS, msym)); unknownModules.add(msym); } return false; @@ -1760,9 +1743,7 @@ public class Modules extends JCTree.Visitor { ModuleSymbol msym = syms.enterModule(names.fromString(sourceName)); if (!allModules.contains(msym)) { - if (lintOptions) { - log.warning(LintWarnings.ModuleForOptionNotFound(Option.ADD_READS, msym)); - } + log.warning(LintWarnings.ModuleForOptionNotFound(Option.ADD_READS, msym)); continue; } @@ -1780,9 +1761,7 @@ public class Modules extends JCTree.Visitor { continue; targetModule = syms.enterModule(names.fromString(targetName)); if (!allModules.contains(targetModule)) { - if (lintOptions) { - log.warning(LintWarnings.ModuleForOptionNotFound(Option.ADD_READS, targetModule)); - } + log.warning(LintWarnings.ModuleForOptionNotFound(Option.ADD_READS, targetModule)); continue; } } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ThisEscapeAnalyzer.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ThisEscapeAnalyzer.java index 9119278660f..6fb1feed08d 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ThisEscapeAnalyzer.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ThisEscapeAnalyzer.java @@ -45,6 +45,7 @@ import java.util.stream.Stream; import com.sun.tools.javac.code.Directive; import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.code.Lint; +import com.sun.tools.javac.code.LintMapper; import com.sun.tools.javac.code.Symbol; import com.sun.tools.javac.code.Symbol.*; import com.sun.tools.javac.code.Symtab; @@ -57,6 +58,7 @@ import com.sun.tools.javac.tree.TreeInfo; import com.sun.tools.javac.tree.TreeScanner; import com.sun.tools.javac.util.Assert; import com.sun.tools.javac.util.Context; +import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; import com.sun.tools.javac.util.JCDiagnostic.LintWarning; import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.Log; @@ -67,6 +69,7 @@ import static com.sun.tools.javac.code.Kinds.Kind.*; import static com.sun.tools.javac.code.Lint.LintCategory.THIS_ESCAPE; import static com.sun.tools.javac.code.TypeTag.*; import static com.sun.tools.javac.tree.JCTree.Tag.*; +import static com.sun.tools.javac.util.Position.NOPOS; /** * Looks for possible 'this' escapes and generates corresponding warnings. @@ -156,7 +159,7 @@ public class ThisEscapeAnalyzer extends TreeScanner { private final Types types; private final Resolve rs; private final Log log; - private Lint lint; + private final LintMapper lintMapper; // These fields are scoped to the entire compilation unit @@ -168,10 +171,6 @@ public class ThisEscapeAnalyzer extends TreeScanner { */ private final Map methodMap = new LinkedHashMap<>(); - /** Contains symbols of fields and constructors that have warnings suppressed. - */ - private final Set suppressed = new HashSet<>(); - /** Contains classes whose outer instance (if any) is non-public. */ private final Set nonPublicOuters = new HashSet<>(); @@ -231,7 +230,7 @@ public class ThisEscapeAnalyzer extends TreeScanner { syms = Symtab.instance(context); types = Types.instance(context); rs = Resolve.instance(context); - lint = Lint.instance(context); + lintMapper = LintMapper.instance(context); } // @@ -262,8 +261,8 @@ public class ThisEscapeAnalyzer extends TreeScanner { Assert.check(checkInvariants(false, false)); Assert.check(methodMap.isEmpty()); // we are not prepared to be used more than once - // Short circuit if warnings are totally disabled - if (!lint.isEnabled(THIS_ESCAPE)) + // Short circuit if this calculation is unnecessary + if (!lintMapper.lintAt(env.toplevel.sourcefile, env.tree.pos()).get().isEnabled(THIS_ESCAPE)) return; // Determine which packages are exported by the containing module, if any. @@ -278,11 +277,9 @@ public class ThisEscapeAnalyzer extends TreeScanner { // Build a mapping from symbols of methods to their declarations. // Classify all ctors and methods as analyzable and/or invokable. - // Track which constructors and fields have warnings suppressed. // Record classes whose outer instance (if any) is non-public. new TreeScanner() { - private Lint lint = ThisEscapeAnalyzer.this.lint; private JCClassDecl currentClass; private boolean nonPublicOuter; @@ -290,8 +287,6 @@ public class ThisEscapeAnalyzer extends TreeScanner { public void visitClassDef(JCClassDecl tree) { JCClassDecl currentClassPrev = currentClass; boolean nonPublicOuterPrev = nonPublicOuter; - Lint lintPrev = lint; - lint = lint.augment(tree.sym); try { currentClass = tree; @@ -306,57 +301,29 @@ public class ThisEscapeAnalyzer extends TreeScanner { } finally { currentClass = currentClassPrev; nonPublicOuter = nonPublicOuterPrev; - lint = lintPrev; - } - } - - @Override - public void visitVarDef(JCVariableDecl tree) { - Lint lintPrev = lint; - lint = lint.augment(tree.sym); - try { - - // Track warning suppression of fields - if (tree.sym.owner.kind == TYP && !lint.isEnabled(THIS_ESCAPE)) - suppressed.add(tree.sym); - - // Recurse - super.visitVarDef(tree); - } finally { - lint = lintPrev; } } @Override public void visitMethodDef(JCMethodDecl tree) { - Lint lintPrev = lint; - lint = lint.augment(tree.sym); - try { - // Track warning suppression of constructors - if (TreeInfo.isConstructor(tree) && !lint.isEnabled(THIS_ESCAPE)) - suppressed.add(tree.sym); + // Gather some useful info + boolean constructor = TreeInfo.isConstructor(tree); + boolean extendableClass = currentClassIsExternallyExtendable(); + boolean nonPrivate = (tree.sym.flags() & (Flags.PUBLIC | Flags.PROTECTED)) != 0; + boolean finalish = (tree.mods.flags & (Flags.STATIC | Flags.PRIVATE | Flags.FINAL)) != 0; - // Gather some useful info - boolean constructor = TreeInfo.isConstructor(tree); - boolean extendableClass = currentClassIsExternallyExtendable(); - boolean nonPrivate = (tree.sym.flags() & (Flags.PUBLIC | Flags.PROTECTED)) != 0; - boolean finalish = (tree.mods.flags & (Flags.STATIC | Flags.PRIVATE | Flags.FINAL)) != 0; + // Determine if this is a constructor we should analyze + boolean analyzable = extendableClass && constructor && nonPrivate; - // Determine if this is a constructor we should analyze - boolean analyzable = extendableClass && constructor && nonPrivate; + // Determine if it's safe to "invoke" the method in an analysis (i.e., it can't be overridden) + boolean invokable = !extendableClass || constructor || finalish; - // Determine if it's safe to "invoke" the method in an analysis (i.e., it can't be overridden) - boolean invokable = !extendableClass || constructor || finalish; + // Add this method or constructor to our map + methodMap.put(tree.sym, new MethodInfo(currentClass, tree, constructor, analyzable, invokable)); - // Add this method or constructor to our map - methodMap.put(tree.sym, new MethodInfo(currentClass, tree, constructor, analyzable, invokable)); - - // Recurse - super.visitMethodDef(tree); - } finally { - lint = lintPrev; - } + // Recurse + super.visitMethodDef(tree); } // Determines if the current class could be extended in some other package/module @@ -401,7 +368,7 @@ public class ThisEscapeAnalyzer extends TreeScanner { for (Warning warning : warningList) { LintWarning key = LintWarnings.PossibleThisEscape; for (StackFrame frame : warning.stack) { - log.warning(frame.site.pos(), key); + log.warning(frame.warningPos(), key); key = LintWarnings.PossibleThisEscapeLocation; } } @@ -1746,9 +1713,16 @@ public class ThisEscapeAnalyzer extends TreeScanner { this.suppressible = initializer != null || (method.constructor && method.declaringClass == targetClass); } + DiagnosticPosition warningPos() { + return site.pos().withLintPosition(NOPOS); // disable normal Lint suppression + } + + Lint lint() { + return lintMapper.lintAt(topLevelEnv.toplevel.sourcefile, site.pos()).get(); + } + boolean isSuppressed() { - return suppressible && - suppressed.contains(initializer instanceof JCVariableDecl v ? v.sym : method.declaration.sym); + return suppressible && !lint().isEnabled(THIS_ESCAPE); } int comparePos(StackFrame that) { diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java index eb4ab96dfd2..8648b929a04 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java @@ -34,7 +34,6 @@ import javax.tools.JavaFileObject; import com.sun.tools.javac.code.*; import com.sun.tools.javac.code.Directive.ExportsDirective; import com.sun.tools.javac.code.Directive.RequiresDirective; -import com.sun.tools.javac.code.Lint.LintCategory; import com.sun.tools.javac.code.Scope.ImportFilter; import com.sun.tools.javac.code.Scope.NamedImportScope; import com.sun.tools.javac.code.Scope.StarImportScope; @@ -108,8 +107,6 @@ public class TypeEnter implements Completer { private final Annotate annotate; private final TypeAnnotations typeAnnotations; private final Types types; - private final DeferredLintHandler deferredLintHandler; - private final Lint lint; private final TypeEnvs typeEnvs; private final Dependencies dependencies; @@ -135,8 +132,6 @@ public class TypeEnter implements Completer { annotate = Annotate.instance(context); typeAnnotations = TypeAnnotations.instance(context); types = Types.instance(context); - deferredLintHandler = DeferredLintHandler.instance(context); - lint = Lint.instance(context); typeEnvs = TypeEnvs.instance(context); dependencies = Dependencies.instance(context); Source source = Source.instance(context); @@ -274,7 +269,6 @@ public class TypeEnter implements Completer { queue.add(env); JavaFileObject prev = log.useSource(env.toplevel.sourcefile); - deferredLintHandler.push(tree); try { dependencies.push(env.enclClass.sym, phaseName); runPhase(env); @@ -282,7 +276,6 @@ public class TypeEnter implements Completer { chk.completionError(tree.pos(), ex); } finally { dependencies.pop(); - deferredLintHandler.pop(); log.useSource(prev); } } @@ -351,8 +344,6 @@ public class TypeEnter implements Completer { ImportFilter prevStaticImportFilter = staticImportFilter; ImportFilter prevTypeImportFilter = typeImportFilter; - deferredLintHandler.pushImmediate(lint); - Lint prevLint = chk.setLint(lint); Env prevEnv = this.env; try { this.env = env; @@ -376,20 +367,13 @@ public class TypeEnter implements Completer { handleImports(tree.getImports()); if (decl != null) { - deferredLintHandler.push(decl); - try { - //check @Deprecated: - markDeprecated(decl.sym, decl.mods.annotations, env); - } finally { - deferredLintHandler.pop(); - } + //check for @Deprecated annotations + markDeprecated(decl.sym, decl.mods.annotations, env); // process module annotations - annotate.annotateLater(decl.mods.annotations, env, env.toplevel.modle, decl); + annotate.annotateLater(decl.mods.annotations, env, env.toplevel.modle); } } finally { this.env = prevEnv; - chk.setLint(prevLint); - deferredLintHandler.pop(); this.staticImportFilter = prevStaticImportFilter; this.typeImportFilter = prevTypeImportFilter; } @@ -422,7 +406,7 @@ public class TypeEnter implements Completer { } } // process package annotations - annotate.annotateLater(tree.annotations, env, env.toplevel.packge, tree); + annotate.annotateLater(tree.annotations, env, env.toplevel.packge); } private void doImport(JCImport tree, boolean fromModuleImport) { @@ -914,9 +898,9 @@ public class TypeEnter implements Completer { Env baseEnv = baseEnv(tree, env); if (tree.extending != null) - annotate.queueScanTreeAndTypeAnnotate(tree.extending, baseEnv, sym, tree); + annotate.queueScanTreeAndTypeAnnotate(tree.extending, baseEnv, sym); for (JCExpression impl : tree.implementing) - annotate.queueScanTreeAndTypeAnnotate(impl, baseEnv, sym, tree); + annotate.queueScanTreeAndTypeAnnotate(impl, baseEnv, sym); annotate.flush(); attribSuperTypes(env, baseEnv); @@ -931,11 +915,11 @@ public class TypeEnter implements Completer { chk.checkNotRepeated(iface.pos(), types.erasure(it), interfaceSet); } - annotate.annotateLater(tree.mods.annotations, baseEnv, sym, tree); + annotate.annotateLater(tree.mods.annotations, baseEnv, sym); attr.attribTypeVariables(tree.typarams, baseEnv, false); for (JCTypeParameter tp : tree.typarams) - annotate.queueScanTreeAndTypeAnnotate(tp, baseEnv, sym, tree); + annotate.queueScanTreeAndTypeAnnotate(tp, baseEnv, sym); // check that no package exists with same fully qualified name, // but admit classes in the unnamed package which have the same diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/file/BaseFileManager.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/file/BaseFileManager.java index 73f86239713..5964c16c151 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/file/BaseFileManager.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/file/BaseFileManager.java @@ -92,7 +92,7 @@ public abstract class BaseFileManager implements JavaFileManager { options = Options.instance(context); // Initialize locations - locations.update(log, lint, FSInfo.instance(context)); + locations.update(log, FSInfo.instance(context)); // Apply options options.whenReady(this::applyOptions); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/file/Locations.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/file/Locations.java index ff02de705fb..c4573b9a364 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/file/Locations.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/file/Locations.java @@ -77,12 +77,11 @@ import javax.tools.StandardJavaFileManager; import javax.tools.StandardJavaFileManager.PathFactory; import javax.tools.StandardLocation; -import com.sun.tools.javac.code.Lint; -import com.sun.tools.javac.resources.CompilerProperties.LintWarnings; import jdk.internal.jmod.JmodFile; import com.sun.tools.javac.main.Option; import com.sun.tools.javac.resources.CompilerProperties.Errors; +import com.sun.tools.javac.resources.CompilerProperties.LintWarnings; import com.sun.tools.javac.util.DefinedBy; import com.sun.tools.javac.util.DefinedBy.Api; import com.sun.tools.javac.util.ListBuffer; @@ -123,11 +122,6 @@ public class Locations { */ private FSInfo fsInfo; - /** - * The root {@link Lint} instance. - */ - private Lint lint; - private ModuleNameReader moduleNameReader; private PathFactory pathFactory = Paths::get; @@ -168,9 +162,8 @@ public class Locations { } } - void update(Log log, Lint lint, FSInfo fsInfo) { + void update(Log log, FSInfo fsInfo) { this.log = log; - this.lint = lint; this.fsInfo = fsInfo; } @@ -221,7 +214,7 @@ public class Locations { try { entries.add(getPath(s)); } catch (IllegalArgumentException e) { - lint.logIfEnabled(LintWarnings.InvalidPath(s)); + log.warning(LintWarnings.InvalidPath(s)); } } } @@ -316,7 +309,7 @@ public class Locations { private void addDirectory(Path dir, boolean warn) { if (!Files.isDirectory(dir)) { if (warn) { - lint.logIfEnabled(LintWarnings.DirPathElementNotFound(dir)); + log.warning(LintWarnings.DirPathElementNotFound(dir)); } return; } @@ -361,7 +354,7 @@ public class Locations { if (!fsInfo.exists(file)) { /* No such file or directory exists */ if (warn) { - lint.logIfEnabled(LintWarnings.PathElementNotFound(file)); + log.warning(LintWarnings.PathElementNotFound(file)); } super.add(file); return; @@ -383,12 +376,12 @@ public class Locations { try { FileSystems.newFileSystem(file, (ClassLoader)null).close(); if (warn) { - lint.logIfEnabled(LintWarnings.UnexpectedArchiveFile(file)); + log.warning(LintWarnings.UnexpectedArchiveFile(file)); } } catch (IOException | ProviderNotFoundException e) { // FIXME: include e.getLocalizedMessage in warning if (warn) { - lint.logIfEnabled(LintWarnings.InvalidArchiveFile(file)); + log.warning(LintWarnings.InvalidArchiveFile(file)); } return; } @@ -1651,7 +1644,7 @@ public class Locations { void add(Map> map, Path prefix, Path suffix) { if (!Files.isDirectory(prefix)) { - lint.logIfEnabled(Files.exists(prefix) ? + log.warning(Files.exists(prefix) ? LintWarnings.DirPathElementNotDirectory(prefix) : LintWarnings.DirPathElementNotFound(prefix)); return; 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 cf751ff6b30..6f1ad28586d 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 @@ -51,7 +51,6 @@ import com.sun.tools.javac.comp.Annotate; import com.sun.tools.javac.comp.Annotate.AnnotationTypeCompleter; import com.sun.tools.javac.code.*; import com.sun.tools.javac.code.Directive.*; -import com.sun.tools.javac.code.Lint.LintCategory; import com.sun.tools.javac.code.Scope.WriteableScope; import com.sun.tools.javac.code.Symbol.*; import com.sun.tools.javac.code.Symtab; @@ -139,9 +138,6 @@ public class ClassReader { /** The symbol table. */ Symtab syms; - /** The root Lint config. */ - Lint lint; - Types types; /** The name table. */ @@ -303,8 +299,6 @@ public class ClassReader { typevars = WriteableScope.create(syms.noSymbol); - lint = Lint.instance(context); - initAttributeReaders(); } @@ -854,8 +848,7 @@ public class ClassReader { if (!warnedAttrs.contains(name)) { JavaFileObject prev = log.useSource(currentClassFile); try { - lint.logIfEnabled( - LintWarnings.FutureAttr(name, version.major, version.minor, majorVersion, minorVersion)); + log.warning(LintWarnings.FutureAttr(name, version.major, version.minor, majorVersion, minorVersion)); } finally { log.useSource(prev); } @@ -1609,7 +1602,7 @@ public class ClassReader { } else if (parameterAnnotations.length != numParameters) { //the RuntimeVisibleParameterAnnotations and RuntimeInvisibleParameterAnnotations //provide annotations for a different number of parameters, ignore: - lint.logIfEnabled(LintWarnings.RuntimeVisibleInvisibleParamAnnotationsMismatch(currentClassFile)); + log.warning(LintWarnings.RuntimeVisibleInvisibleParamAnnotationsMismatch(currentClassFile)); for (int pnum = 0; pnum < numParameters; pnum++) { readAnnotations(); } @@ -2075,9 +2068,9 @@ public class ClassReader { JavaFileObject prevSource = log.useSource(requestingOwner.classfile); try { if (failure == null) { - lint.logIfEnabled(LintWarnings.AnnotationMethodNotFound(container, name)); + log.warning(LintWarnings.AnnotationMethodNotFound(container, name)); } else { - lint.logIfEnabled(LintWarnings.AnnotationMethodNotFoundReason(container, + log.warning(LintWarnings.AnnotationMethodNotFoundReason(container, name, failure.getDetailValue()));//diagnostic, if present } @@ -2954,7 +2947,7 @@ public class ClassReader { private void dropParameterAnnotations() { parameterAnnotations = null; - lint.logIfEnabled(LintWarnings.RuntimeInvisibleParameterAnnotations(currentClassFile)); + log.warning(LintWarnings.RuntimeInvisibleParameterAnnotations(currentClassFile)); } /** * Creates the parameter at the position {@code mpIndex} in the parameter list of the owning method. diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Arguments.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Arguments.java index 7aa1cc473b5..58beee78af2 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Arguments.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Arguments.java @@ -52,7 +52,6 @@ import javax.tools.StandardJavaFileManager; import javax.tools.StandardLocation; import com.sun.tools.doclint.DocLint; -import com.sun.tools.javac.code.Lint.LintCategory; import com.sun.tools.javac.code.Source; import com.sun.tools.javac.file.BaseFileManager; import com.sun.tools.javac.file.JavacFileManager; @@ -503,12 +502,9 @@ public class Arguments { } } else { // single-module or legacy mode - boolean lintPaths = !options.isLintDisabled(LintCategory.PATH); - if (lintPaths) { - Path outDirParent = outDir.getParent(); - if (outDirParent != null && Files.exists(outDirParent.resolve("module-info.class"))) { - log.warning(LintWarnings.OutdirIsInExplodedModule(outDir)); - } + Path outDirParent = outDir.getParent(); + if (outDirParent != null && Files.exists(outDirParent.resolve("module-info.class"))) { + log.warning(LintWarnings.OutdirIsInExplodedModule(outDir)); } } } @@ -576,15 +572,14 @@ public class Arguments { reportDiag(Errors.SourcepathModulesourcepathConflict); } - boolean lintOptions = !options.isLintDisabled(LintCategory.OPTIONS); - if (lintOptions && source.compareTo(Source.DEFAULT) < 0 && !options.isSet(Option.RELEASE)) { + if (source.compareTo(Source.DEFAULT) < 0 && !options.isSet(Option.RELEASE)) { if (fm instanceof BaseFileManager baseFileManager) { if (source.compareTo(Source.JDK8) <= 0) { - if (baseFileManager.isDefaultBootClassPath()) + if (baseFileManager.isDefaultBootClassPath()) { log.warning(LintWarnings.SourceNoBootclasspath(source.name, releaseNote(source, targetString))); - } else { - if (baseFileManager.isDefaultSystemModulesPath()) - log.warning(LintWarnings.SourceNoSystemModulesPath(source.name, releaseNote(source, targetString))); + } + } else if (baseFileManager.isDefaultSystemModulesPath()) { + log.warning(LintWarnings.SourceNoSystemModulesPath(source.name, releaseNote(source, targetString))); } } } @@ -593,14 +588,14 @@ public class Arguments { if (source.compareTo(Source.MIN) < 0) { log.error(Errors.OptionRemovedSource(source.name, Source.MIN.name)); - } else if (source == Source.MIN && lintOptions) { + } else if (source == Source.MIN) { log.warning(LintWarnings.OptionObsoleteSource(source.name)); obsoleteOptionFound = true; } if (target.compareTo(Target.MIN) < 0) { log.error(Errors.OptionRemovedTarget(target, Target.MIN)); - } else if (target == Target.MIN && lintOptions) { + } else if (target == Target.MIN) { log.warning(LintWarnings.OptionObsoleteTarget(target)); obsoleteOptionFound = true; } @@ -634,7 +629,7 @@ public class Arguments { log.error(Errors.ProcessorpathNoProcessormodulepath); } - if (obsoleteOptionFound && lintOptions) { + if (obsoleteOptionFound) { log.warning(LintWarnings.OptionObsoleteSuppression); } @@ -645,7 +640,7 @@ public class Arguments { validateLimitModules(sv); validateDefaultModuleForCreatedFiles(sv); - if (lintOptions && options.isSet(Option.ADD_OPENS)) { + if (options.isSet(Option.ADD_OPENS)) { log.warning(LintWarnings.AddopensIgnored); } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java index 83106ff2278..ee11304dce9 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java @@ -258,6 +258,10 @@ public class JavaCompiler { */ protected JNIWriter jniWriter; + /** The Lint mapper. + */ + protected LintMapper lintMapper; + /** The module for the symbol table entry phases. */ protected Enter enter; @@ -384,6 +388,7 @@ public class JavaCompiler { names = Names.instance(context); log = Log.instance(context); + lintMapper = LintMapper.instance(context); diagFactory = JCDiagnostic.Factory.instance(context); finder = ClassFinder.instance(context); reader = ClassReader.instance(context); @@ -575,6 +580,7 @@ public class JavaCompiler { /** The number of errors reported so far. */ public int errorCount() { + log.reportOutstandingWarnings(); if (werror && log.nerrors == 0 && log.nwarnings > 0) { log.error(Errors.WarningsAndWerror); } @@ -625,6 +631,7 @@ public class JavaCompiler { private JCCompilationUnit parse(JavaFileObject filename, CharSequence content, boolean silent) { long msec = now(); JCCompilationUnit tree = make.TopLevel(List.nil()); + lintMapper.startParsingFile(filename); if (content != null) { if (verbose) { log.printVerbose("parsing.started", filename); @@ -644,6 +651,7 @@ public class JavaCompiler { } tree.sourcefile = filename; + lintMapper.finishParsingFile(tree); if (content != null && !taskListener.isEmpty() && !silent) { TaskEvent e = new TaskEvent(TaskEvent.Kind.PARSE, tree); @@ -1843,6 +1851,7 @@ public class JavaCompiler { else log.warning(Warnings.ProcUseProcOrImplicit); } + log.reportOutstandingWarnings(); log.reportOutstandingNotes(); if (log.compressedOutput) { log.note(Notes.CompressedDiags); @@ -1916,6 +1925,7 @@ public class JavaCompiler { attr = null; chk = null; gen = null; + lintMapper = null; flow = null; transTypes = null; lower = null; diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java index f3d0837398c..f40cb0fb6b7 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java @@ -25,8 +25,6 @@ package com.sun.tools.javac.parser; -import com.sun.tools.javac.code.Lint; -import com.sun.tools.javac.code.Lint.LintCategory; import com.sun.tools.javac.code.Preview; import com.sun.tools.javac.code.Source; import com.sun.tools.javac.code.Source.Feature; @@ -83,7 +81,7 @@ public class JavaTokenizer extends UnicodeReader { /** * The log to be used for error reporting. Copied from scanner factory. */ - private final Log log; + protected final Log log; /** * The token factory. Copied from scanner factory. @@ -135,13 +133,6 @@ public class JavaTokenizer extends UnicodeReader { */ protected boolean hasEscapeSequences; - /** - * The set of lint options currently in effect. It is initialized - * from the context, and then is set/reset as needed by Attr as it - * visits all the various parts of the trees during attribution. - */ - protected final Lint lint; - /** * Construct a Java token scanner from the input character buffer. * @@ -168,7 +159,6 @@ public class JavaTokenizer extends UnicodeReader { this.source = fac.source; this.preview = fac.preview; this.enableLineDocComments = fac.enableLineDocComments; - this.lint = fac.lint; this.sb = new StringBuilder(256); } @@ -205,17 +195,6 @@ public class JavaTokenizer extends UnicodeReader { errPos = pos; } - /** - * Report a warning at the given position using the provided arguments. - * - * @param pos position in input buffer. - * @param key error key to report. - */ - protected void lexWarning(int pos, JCDiagnostic.LintWarning key) { - DiagnosticPosition dp = new SimpleDiagnosticPosition(pos) ; - log.warning(dp, key); - } - /** * Add a character to the literal buffer. * @@ -1060,17 +1039,12 @@ public class JavaTokenizer extends UnicodeReader { // If a text block. if (isTextBlock) { // Verify that the incidental indentation is consistent. - if (lint.isEnabled(LintCategory.TEXT_BLOCKS)) { - Set checks = - TextBlockSupport.checkWhitespace(string); - if (checks.contains(TextBlockSupport.WhitespaceChecks.INCONSISTENT)) { - lexWarning(pos, - LintWarnings.InconsistentWhiteSpaceIndentation); - } - if (checks.contains(TextBlockSupport.WhitespaceChecks.TRAILING)) { - lexWarning(pos, - LintWarnings.TrailingWhiteSpaceWillBeRemoved); - } + Set checks = TextBlockSupport.checkWhitespace(string); + if (checks.contains(TextBlockSupport.WhitespaceChecks.INCONSISTENT)) { + log.warning(pos, LintWarnings.InconsistentWhiteSpaceIndentation); + } + if (checks.contains(TextBlockSupport.WhitespaceChecks.TRAILING)) { + log.warning(pos, LintWarnings.TrailingWhiteSpaceWillBeRemoved); } // Remove incidental indentation. try { 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 b63374d9c6d..4a990701315 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 @@ -116,8 +116,6 @@ public class JavacParser implements Parser { /** A map associating "other nearby documentation comments" * with the preferred documentation comment for a declaration. */ protected Map> danglingComments = new HashMap<>(); - /** Handler for deferred diagnostics. */ - protected final DeferredLintHandler deferredLintHandler; // Because of javac's limited lookahead, some contexts are ambiguous in // the presence of type annotations even though they are not ambiguous @@ -190,7 +188,6 @@ public class JavacParser implements Parser { this.names = fac.names; this.source = fac.source; this.preview = fac.preview; - this.deferredLintHandler = fac.deferredLintHandler; this.allowStringFolding = fac.options.getBoolean("allowStringFolding", true); this.keepDocComments = keepDocComments; this.parseModuleInfo = parseModuleInfo; @@ -216,7 +213,6 @@ public class JavacParser implements Parser { this.names = parser.names; this.source = parser.source; this.preview = parser.preview; - this.deferredLintHandler = parser.deferredLintHandler; this.allowStringFolding = parser.allowStringFolding; this.keepDocComments = parser.keepDocComments; this.parseModuleInfo = false; @@ -591,8 +587,7 @@ public class JavacParser implements Parser { * 4. When the tree node for the declaration is finally * available, and the primary comment, if any, * is "attached", (in {@link #attach}) any related - * dangling comments are also attached to the tree node - * by registering them using the {@link #deferredLintHandler}. + * dangling comments are reported to the log as warnings. * 5. (Later) Warnings may be generated for the dangling * comments, subject to the {@code -Xlint} and * {@code @SuppressWarnings}. @@ -653,32 +648,22 @@ public class JavacParser implements Parser { void reportDanglingComments(JCTree tree, Comment dc) { var list = danglingComments.remove(dc); if (list != null) { - deferredLintHandler.push(tree); - try { - list.forEach(this::reportDanglingDocComment); - } finally { - deferredLintHandler.pop(); - } + list.forEach(c -> reportDanglingDocComment(tree, c)); } } /** - * Reports an individual dangling comment using the {@link #deferredLintHandler}. + * Reports an individual dangling comment as a warning to the log. * The comment may or not may generate an actual diagnostic, depending on * the settings for {@code -Xlint} and/or {@code @SuppressWarnings}. * * @param c the comment */ - void reportDanglingDocComment(Comment c) { + void reportDanglingDocComment(JCTree tree, Comment c) { var pos = c.getPos(); - if (pos != null) { - deferredLintHandler.report(lint -> { - if (lint.isEnabled(Lint.LintCategory.DANGLING_DOC_COMMENTS) && - !shebang(c, pos)) { - log.warning( - pos, LintWarnings.DanglingDocComment); - } - }); + if (pos != null && !shebang(c, pos)) { + pos = pos.withLintPosition(tree.getStartPosition()); + S.lintWarning(pos, LintWarnings.DanglingDocComment); } } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/Lexer.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/Lexer.java index bff4e027db7..1d1e08194f7 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/Lexer.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/Lexer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,8 @@ package com.sun.tools.javac.parser; import java.util.Queue; import com.sun.tools.javac.parser.Tokens.*; +import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; +import com.sun.tools.javac.util.JCDiagnostic.LintWarning; import com.sun.tools.javac.util.Position.LineMap; /** @@ -103,4 +105,12 @@ public interface Lexer { * token. */ Queue getDocComments(); + + /** + * Report a warning that is subject to possible suppression by {@code @SuppressWarnings}. + * + * @param pos the lexical position at which the warning occurs + * @param key the warning to report + */ + void lintWarning(DiagnosticPosition pos, LintWarning key); } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/ParserFactory.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/ParserFactory.java index c873c6f31b7..f9e187315ba 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/ParserFactory.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/ParserFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,6 @@ package com.sun.tools.javac.parser; import java.util.Locale; import com.sun.tools.javac.api.JavacTrees; -import com.sun.tools.javac.code.DeferredLintHandler; import com.sun.tools.javac.code.Lint; import com.sun.tools.javac.code.Preview; import com.sun.tools.javac.code.Source; @@ -70,7 +69,6 @@ public class ParserFactory { final Options options; final ScannerFactory scannerFactory; final Locale locale; - final DeferredLintHandler deferredLintHandler; private final JavacTrees trees; @@ -88,7 +86,6 @@ public class ParserFactory { this.options = Options.instance(context); this.scannerFactory = ScannerFactory.instance(context); this.locale = context.get(Locale.class); - this.deferredLintHandler = DeferredLintHandler.instance(context); this.trees = JavacTrees.instance(context); } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/Scanner.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/Scanner.java index a24e73a4141..7fcb87eac7a 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/Scanner.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/Scanner.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. * 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,8 @@ import java.util.List; import java.util.ArrayList; import java.util.Queue; +import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; +import com.sun.tools.javac.util.JCDiagnostic.LintWarning; import com.sun.tools.javac.util.Position.LineMap; import static com.sun.tools.javac.parser.Tokens.*; @@ -150,6 +152,11 @@ public class Scanner implements Lexer { return docComments; } + @Override + public void lintWarning(DiagnosticPosition pos, LintWarning key) { + tokenizer.log.warning(pos, key); + } + public int errPos() { return tokenizer.errPos(); } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/ScannerFactory.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/ScannerFactory.java index 188fe838b18..66f2b66fabf 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/ScannerFactory.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/ScannerFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ package com.sun.tools.javac.parser; import java.nio.CharBuffer; -import com.sun.tools.javac.code.Lint; import com.sun.tools.javac.code.Preview; import com.sun.tools.javac.code.Source; import com.sun.tools.javac.main.Option; @@ -62,7 +61,6 @@ public class ScannerFactory { final Source source; final Preview preview; final Tokens tokens; - final Lint lint; final boolean enableLineDocComments; /** Create a new scanner factory. */ @@ -74,7 +72,6 @@ public class ScannerFactory { this.source = Source.instance(context); this.preview = Preview.instance(context); this.tokens = Tokens.instance(context); - this.lint = Lint.instance(context); var options = Options.instance(context); this.enableLineDocComments = !options.isSet(Option.DISABLE_LINE_DOC_COMMENTS); } 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 ec3a373ab4e..2a819152eed 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,6 +30,7 @@ import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.JCErroneous; import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; import com.sun.tools.javac.util.JCDiagnostic.Error; +import com.sun.tools.javac.util.JCDiagnostic.LintWarning; import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.Position.LineMap; @@ -167,10 +168,9 @@ public class VirtualParser extends JavacParser { return S.getLineMap(); } - public void commit() { - for (int i = 0 ; i < offset ; i++) { - S.nextToken(); // advance underlying lexer until position matches - } + @Override + public void lintWarning(DiagnosticPosition pos, LintWarning key) { + // ignore } } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacFiler.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacFiler.java index 012ac628ecd..dc25de30b36 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacFiler.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacFiler.java @@ -51,7 +51,6 @@ import javax.tools.JavaFileManager.Location; import static javax.tools.StandardLocation.SOURCE_OUTPUT; import static javax.tools.StandardLocation.CLASS_OUTPUT; -import com.sun.tools.javac.code.Lint; import com.sun.tools.javac.code.Symbol.ClassSymbol; import com.sun.tools.javac.code.Symbol.ModuleSymbol; import com.sun.tools.javac.code.Symtab; @@ -62,7 +61,6 @@ import com.sun.tools.javac.resources.CompilerProperties.Warnings; import com.sun.tools.javac.util.*; import com.sun.tools.javac.util.DefinedBy.Api; -import static com.sun.tools.javac.code.Lint.LintCategory.PROCESSING; import com.sun.tools.javac.code.Symbol.PackageSymbol; import com.sun.tools.javac.main.Option; @@ -338,7 +336,6 @@ public class JavacFiler implements Filer, Closeable { JavaFileManager fileManager; JavacElements elementUtils; Log log; - Lint lint; Modules modules; Names names; Symtab syms; @@ -421,8 +418,6 @@ public class JavacFiler implements Filer, Closeable { aggregateGeneratedClassNames = new LinkedHashSet<>(); initialClassNames = new LinkedHashSet<>(); - lint = Lint.instance(context); - Options options = Options.instance(context); defaultTargetModule = options.get(Option.DEFAULT_MODULE_FOR_CREATED_FILES); @@ -486,14 +481,12 @@ public class JavacFiler implements Filer, Closeable { private JavaFileObject createSourceOrClassFile(ModuleSymbol mod, boolean isSourceFile, String name, Element... originatingElements) throws IOException { Assert.checkNonNull(mod); - if (lint.isEnabled(PROCESSING)) { - int periodIndex = name.lastIndexOf("."); - if (periodIndex != -1) { - String base = name.substring(periodIndex); - String extn = (isSourceFile ? ".java" : ".class"); - if (base.equals(extn)) - log.warning(LintWarnings.ProcSuspiciousClassName(name, extn)); - } + int periodIndex = name.lastIndexOf("."); + if (periodIndex != -1) { + String base = name.substring(periodIndex); + String extn = (isSourceFile ? ".java" : ".class"); + if (base.equals(extn)) + log.warning(LintWarnings.ProcSuspiciousClassName(name, extn)); } checkNameAndExistence(mod, name, isSourceFile); Location loc = (isSourceFile ? SOURCE_OUTPUT : CLASS_OUTPUT); @@ -707,7 +700,7 @@ public class JavacFiler implements Filer, Closeable { private void checkName(String name, boolean allowUnnamedPackageInfo) throws FilerException { if (!SourceVersion.isName(name) && !isPackageInfo(name, allowUnnamedPackageInfo)) { - lint.logIfEnabled(LintWarnings.ProcIllegalFileName(name)); + log.warning(LintWarnings.ProcIllegalFileName(name)); throw new FilerException("Illegal name " + name); } } @@ -735,11 +728,11 @@ public class JavacFiler implements Filer, Closeable { initialClassNames.contains(typename) || containedInInitialInputs(typename); if (alreadySeen) { - lint.logIfEnabled(LintWarnings.ProcTypeRecreate(typename)); + log.warning(LintWarnings.ProcTypeRecreate(typename)); throw new FilerException("Attempt to recreate a file for type " + typename); } if (existing != null) { - lint.logIfEnabled(LintWarnings.ProcTypeAlreadyExists(typename)); + log.warning(LintWarnings.ProcTypeAlreadyExists(typename)); } if (!mod.isUnnamed() && !typename.contains(".")) { throw new FilerException("Attempt to create a type in unnamed package of a named module: " + typename); @@ -768,7 +761,7 @@ public class JavacFiler implements Filer, Closeable { */ private void checkFileReopening(FileObject fileObject, boolean forWriting) throws FilerException { if (isInFileObjectHistory(fileObject, forWriting)) { - lint.logIfEnabled(LintWarnings.ProcFileReopening(fileObject.getName())); + log.warning(LintWarnings.ProcFileReopening(fileObject.getName())); throw new FilerException("Attempt to reopen a file for path " + fileObject.getName()); } if (forWriting) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java index 7bc538a1d1e..b28f19bd3af 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java @@ -123,7 +123,6 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea private final Modules modules; private final Types types; private final Annotate annotate; - private final Lint lint; /** * Holds relevant state history of which processors have been @@ -206,7 +205,6 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea printProcessorInfo = options.isSet(Option.XPRINTPROCESSORINFO); printRounds = options.isSet(Option.XPRINTROUNDS); verbose = options.isSet(Option.VERBOSE); - lint = Lint.instance(context); compiler = JavaCompiler.instance(context); if (options.isSet(Option.PROC, "only") || options.isSet(Option.XPRINT)) { compiler.shouldStopPolicyIfNoError = CompileState.PROCESS; @@ -626,7 +624,7 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea private Set supportedOptionNames; ProcessorState(Processor p, Log log, Source source, DeferredCompletionFailureHandler dcfh, - boolean allowModules, ProcessingEnvironment env, Lint lint) { + boolean allowModules, ProcessingEnvironment env) { processor = p; contributed = false; @@ -647,10 +645,9 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea boolean patternAdded = supportedAnnotationStrings.add(annotationPattern); supportedAnnotationPatterns. - add(importStringToPattern(allowModules, annotationPattern, - processor, log, lint)); + add(importStringToPattern(allowModules, annotationPattern, processor, log)); if (!patternAdded) { - lint.logIfEnabled(LintWarnings.ProcDuplicateSupportedAnnotation(annotationPattern, + log.warning(LintWarnings.ProcDuplicateSupportedAnnotation(annotationPattern, p.getClass().getName())); } } @@ -663,7 +660,7 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea // and "foo.bar.*". if (supportedAnnotationPatterns.contains(MatchingUtils.validImportStringToPattern("*")) && supportedAnnotationPatterns.size() > 1) { - lint.logIfEnabled(LintWarnings.ProcRedundantTypesWithWildcard(p.getClass().getName())); + log.warning(LintWarnings.ProcRedundantTypesWithWildcard(p.getClass().getName())); } supportedOptionNames = new LinkedHashSet<>(); @@ -671,8 +668,7 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea if (checkOptionName(optionName, log)) { boolean optionAdded = supportedOptionNames.add(optionName); if (!optionAdded) { - lint.logIfEnabled(LintWarnings.ProcDuplicateOptionName(optionName, - p.getClass().getName())); + log.warning(LintWarnings.ProcDuplicateOptionName(optionName, p.getClass().getName())); } } } @@ -759,8 +755,7 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea ProcessorState ps = new ProcessorState(psi.processorIterator.next(), log, source, dcfh, Feature.MODULES.allowedInSource(source), - JavacProcessingEnvironment.this, - lint); + JavacProcessingEnvironment.this); psi.procStateList.add(ps); return ps; } else @@ -888,7 +883,7 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea } unmatchedAnnotations.remove(""); - if (lint.isEnabled(PROCESSING) && unmatchedAnnotations.size() > 0) { + if (unmatchedAnnotations.size() > 0) { // Remove annotations processed by javac unmatchedAnnotations.keySet().removeAll(platformAnnotations); if (unmatchedAnnotations.size() > 0) { @@ -1649,7 +1644,7 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea * regex matching that string. If the string is not a valid * import-style string, return a regex that won't match anything. */ - private static Pattern importStringToPattern(boolean allowModules, String s, Processor p, Log log, Lint lint) { + private static Pattern importStringToPattern(boolean allowModules, String s, Processor p, Log log) { String module; String pkg; int slash = s.indexOf('/'); @@ -1662,7 +1657,7 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea } else { String moduleName = s.substring(0, slash); if (!SourceVersion.isName(moduleName)) { - return warnAndNoMatches(s, p, log, lint); + return warnAndNoMatches(s, p, log); } module = Pattern.quote(moduleName + "/"); // And warn if module is specified if modules aren't supported, conditional on -Xlint:proc? @@ -1671,12 +1666,12 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea if (MatchingUtils.isValidImportString(pkg)) { return Pattern.compile(module + MatchingUtils.validImportStringToPatternString(pkg)); } else { - return warnAndNoMatches(s, p, log, lint); + return warnAndNoMatches(s, p, log); } } - private static Pattern warnAndNoMatches(String s, Processor p, Log log, Lint lint) { - lint.logIfEnabled(LintWarnings.ProcMalformedSupportedString(s, p.getClass().getName())); + private static Pattern warnAndNoMatches(String s, Processor p, Log log) { + log.warning(LintWarnings.ProcMalformedSupportedString(s, p.getClass().getName())); return noMatches; // won't match any valid identifier } 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 7dde6cc963f..a226b2f5960 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 @@ -1600,6 +1600,7 @@ compiler.err.multi-module.outdir.cannot.be.exploded.module=\ # 0: path # lint: path +# flags: default-enabled compiler.warn.outdir.is.in.exploded.module=\ the output directory is within an exploded module: {0} @@ -1924,19 +1925,19 @@ compiler.warn.incubating.modules=\ # 0: symbol, 1: symbol # lint: deprecation -# flags: aggregate, mandatory +# flags: aggregate, mandatory, default-enabled compiler.warn.has.been.deprecated=\ {0} in {1} has been deprecated # 0: symbol, 1: symbol # lint: removal -# flags: aggregate, mandatory +# flags: aggregate, mandatory, default-enabled compiler.warn.has.been.deprecated.for.removal=\ {0} in {1} has been deprecated and marked for removal # 0: symbol # lint: preview -# flags: aggregate, mandatory +# flags: aggregate, mandatory, default-enabled compiler.warn.is.preview=\ {0} is a preview API and may be removed in a future release. @@ -1947,7 +1948,7 @@ compiler.err.is.preview=\ # 0: symbol # lint: preview -# flags: aggregate, mandatory +# flags: aggregate, mandatory, default-enabled compiler.warn.is.preview.reflective=\ {0} is a reflective preview API and may be removed in a future release. @@ -1959,13 +1960,13 @@ compiler.warn.restricted.method=\ # 0: symbol # lint: deprecation -# flags: aggregate, mandatory +# flags: aggregate, mandatory, default-enabled compiler.warn.has.been.deprecated.module=\ module {0} has been deprecated # 0: symbol # lint: removal -# flags: aggregate, mandatory +# flags: aggregate, mandatory, default-enabled compiler.warn.has.been.deprecated.for.removal.module=\ module {0} has been deprecated and marked for removal @@ -2194,11 +2195,13 @@ compiler.warn.static.not.qualified.by.type2=\ # 0: string, 1: fragment # lint: options +# flags: default-enabled compiler.warn.source.no.bootclasspath=\ bootstrap class path is not set in conjunction with -source {0}\n{1} # 0: string, 1: fragment # lint: options +# flags: default-enabled compiler.warn.source.no.system.modules.path=\ location of system modules is not set in conjunction with -source {0}\n{1} @@ -2224,11 +2227,13 @@ compiler.misc.source.no.system.modules.path.with.target=\ # 0: string # lint: options +# flags: default-enabled compiler.warn.option.obsolete.source=\ source value {0} is obsolete and will be removed in a future release # 0: target # lint: options +# flags: default-enabled compiler.warn.option.obsolete.target=\ target value {0} is obsolete and will be removed in a future release @@ -2241,6 +2246,7 @@ compiler.err.option.removed.target=\ Target option {0} is no longer supported. Use {1} or later. # lint: options +# flags: default-enabled compiler.warn.option.obsolete.suppression=\ To suppress warnings about obsolete options, use -Xlint:-options. @@ -2365,13 +2371,13 @@ compiler.warn.unchecked.assign=\ # 0: symbol, 1: type # lint: unchecked -# flags: aggregate, mandatory +# flags: aggregate, mandatory, default-enabled compiler.warn.unchecked.assign.to.var=\ unchecked assignment to variable {0} as member of raw type {1} # 0: symbol, 1: type # lint: unchecked -# flags: aggregate, mandatory +# flags: aggregate, mandatory, default-enabled compiler.warn.unchecked.call.mbr.of.raw.type=\ unchecked call to {0} as a member of the raw type {1} @@ -2381,7 +2387,7 @@ compiler.warn.unchecked.cast.to.type=\ # 0: kind name, 1: name, 2: object, 3: object, 4: kind name, 5: symbol # lint: unchecked -# flags: aggregate, mandatory +# flags: aggregate, mandatory, default-enabled compiler.warn.unchecked.meth.invocation.applied=\ unchecked method invocation: {0} {1} in {4} {5} is applied to given types\n\ required: {2}\n\ @@ -2389,13 +2395,13 @@ compiler.warn.unchecked.meth.invocation.applied=\ # 0: type # lint: unchecked -# flags: aggregate, mandatory +# flags: aggregate, mandatory, default-enabled compiler.warn.unchecked.generic.array.creation=\ unchecked generic array creation for varargs parameter of type {0} # 0: type # lint: unchecked -# flags: aggregate, mandatory +# flags: aggregate, mandatory, default-enabled compiler.warn.unchecked.varargs.non.reifiable.type=\ Possible heap pollution from parameterized vararg type {0} @@ -2794,7 +2800,7 @@ compiler.misc.prob.found.req=\ # 0: message segment, 1: type, 2: type # lint: unchecked -# flags: aggregate, mandatory +# flags: aggregate, mandatory, default-enabled compiler.warn.prob.found.req=\ {0}\n\ required: {2}\n\ @@ -3191,14 +3197,14 @@ compiler.err.override.incompatible.ret=\ # 0: message segment, 1: type, 2: type # lint: unchecked -# flags: aggregate, mandatory +# flags: aggregate, mandatory, default-enabled compiler.warn.override.unchecked.ret=\ {0}\n\ return type requires unchecked conversion from {1} to {2} # 0: message segment, 1: type # lint: unchecked -# flags: aggregate, mandatory +# flags: aggregate, mandatory, default-enabled compiler.warn.override.unchecked.thrown=\ {0}\n\ overridden method does not throw {1} @@ -3302,13 +3308,13 @@ compiler.err.preview.feature.disabled.classfile=\ # 0: message segment (feature) # lint: preview -# flags: aggregate, mandatory +# flags: aggregate, mandatory, default-enabled compiler.warn.preview.feature.use=\ {0} is a preview feature and may be removed in a future release. # 0: message segment (feature) # lint: preview -# flags: aggregate, mandatory +# flags: aggregate, mandatory, default-enabled compiler.warn.preview.feature.use.plural=\ {0} are a preview feature and may be removed in a future release. @@ -3879,6 +3885,7 @@ compiler.err.bad.name.for.option=\ # 0: option name, 1: symbol # lint: options +# flags: default-enabled compiler.warn.module.for.option.not.found=\ module name in {0} option not found: {1} @@ -3895,6 +3902,7 @@ compiler.err.add.reads.with.release=\ adding read edges for system module {0} is not allowed with --release # lint: options +# flags: default-enabled compiler.warn.addopens.ignored=\ --add-opens has no effect at compile time @@ -4272,7 +4280,7 @@ compiler.err.incorrect.number.of.nested.patterns=\ # 0: kind name, 1: symbol # lint: preview -# flags: aggregate, mandatory +# flags: aggregate, mandatory, default-enabled compiler.warn.declared.using.preview=\ {0} {1} is declared using a preview feature, which may be removed in a future release. diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/JCDiagnostic.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/JCDiagnostic.java index 06a1d9fc7a3..c9f529eae55 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/JCDiagnostic.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/JCDiagnostic.java @@ -368,6 +368,36 @@ public class JCDiagnostic implements Diagnostic { * the end position of the tree node. Otherwise, just returns the * same as getPreferredPosition(). */ int getEndPosition(EndPosTable endPosTable); + /** Get the position that determines which Lint configuration applies. */ + default int getLintPosition() { + return getStartPosition(); + } + /** Create a new instance from this instance and the given lint position. */ + default DiagnosticPosition withLintPosition(int lintPos) { + DiagnosticPosition orig = this; + return new DiagnosticPosition() { + @Override + public JCTree getTree() { + return orig.getTree(); + } + @Override + public int getStartPosition() { + return orig.getStartPosition(); + } + @Override + public int getPreferredPosition() { + return orig.getPreferredPosition(); + } + @Override + public int getEndPosition(EndPosTable endPosTable) { + return orig.getEndPosition(endPosTable); + } + @Override + public int getLintPosition() { + return lintPos; + } + }; + } } /** @@ -405,6 +435,10 @@ public class JCDiagnostic implements Diagnostic { RECOVERABLE, NON_DEFERRABLE, COMPRESSED, + /** Flag for lint diagnostics that should be emitted even when their category + * is not explicitly enabled, as long as it is not explicitly suppressed. + */ + DEFAULT_ENABLED, /** Flags mandatory warnings that should pass through a mandatory warning aggregator. */ AGGREGATE, diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Log.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Log.java index 576344a3d2a..95458f339a1 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Log.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Log.java @@ -32,29 +32,45 @@ import java.util.Comparator; import java.util.EnumMap; import java.util.EnumSet; import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Predicate; import javax.tools.DiagnosticListener; import javax.tools.JavaFileObject; import com.sun.tools.javac.api.DiagnosticFormatter; +import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.code.Lint; import com.sun.tools.javac.code.Lint.LintCategory; +import com.sun.tools.javac.code.LintMapper; import com.sun.tools.javac.code.Source; +import com.sun.tools.javac.code.Symbol; +import com.sun.tools.javac.comp.AttrContext; +import com.sun.tools.javac.comp.Env; import com.sun.tools.javac.main.Main; import com.sun.tools.javac.main.Option; import com.sun.tools.javac.tree.EndPosTable; -import com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag; +import com.sun.tools.javac.tree.JCTree; +import com.sun.tools.javac.tree.JCTree.*; +import com.sun.tools.javac.tree.TreeInfo; +import com.sun.tools.javac.tree.TreeScanner; import com.sun.tools.javac.util.JCDiagnostic.DiagnosticInfo; import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; import com.sun.tools.javac.util.JCDiagnostic.DiagnosticType; +import com.sun.tools.javac.util.JCDiagnostic.LintWarning; import static com.sun.tools.javac.main.Option.*; import static com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag.*; +import static com.sun.tools.javac.code.Lint.LintCategory.*; +import static com.sun.tools.javac.resources.CompilerProperties.LintWarnings.RequiresAutomatic; +import static com.sun.tools.javac.resources.CompilerProperties.LintWarnings.RequiresTransitiveAutomatic; +import static com.sun.tools.javac.tree.JCTree.Tag.*; /** A class for error logs. Reports errors and warnings, and * keeps track of error numbers and positions. @@ -103,6 +119,11 @@ public class Log extends AbstractLog { */ protected final DiagnosticHandler prev; + /** + * Diagnostics waiting for an applicable {@link Lint} instance. + */ + protected Map> lintWaitersMap = new LinkedHashMap<>(); + /** * Install this diagnostic handler as the current one, * recording the previous one. @@ -113,9 +134,92 @@ public class Log extends AbstractLog { } /** - * Handle a diagnostic. + * Step 1: Handle a diagnostic for which the applicable Lint instance (if any) may not be known yet. */ - public abstract void report(JCDiagnostic diag); + public final void report(JCDiagnostic diag) { + Lint lint = null; + LintCategory category = diag.getLintCategory(); + if (category != null) { // this is a lint warning; find the applicable Lint + DiagnosticPosition pos = diag.getDiagnosticPosition(); + if (pos != null && category.annotationSuppression) { // we should apply the Lint from the warning's position + if ((lint = lintFor(diag)) == null) { + addLintWaiter(currentSourceFile(), diag); // ...but we don't know it yet, so defer + return; + } + } else // we should apply the root Lint + lint = rootLint(); + } + reportWithLint(diag, lint); + } + + /** + * Step 2: Handle a diagnostic for which the applicable Lint instance (if any) is known and provided. + */ + public final void reportWithLint(JCDiagnostic diag, Lint lint) { + + // Apply hackery for REQUIRES_TRANSITIVE_AUTOMATIC (see also Check.checkModuleRequires()) + if (diag.getCode().equals(RequiresTransitiveAutomatic.key()) && !lint.isEnabled(REQUIRES_TRANSITIVE_AUTOMATIC)) { + reportWithLint( + diags.warning(null, diag.getDiagnosticSource(), diag.getDiagnosticPosition(), RequiresAutomatic), lint); + return; + } + + // Apply the lint configuration (if any) and discard the warning if it gets filtered out + if (lint != null) { + LintCategory category = diag.getLintCategory(); + boolean emit = !diag.isFlagSet(DEFAULT_ENABLED) ? // is the warning not enabled by default? + lint.isEnabled(category) : // then emit if the category is enabled + category.annotationSuppression ? // else emit if the category is not suppressed, where + !lint.isSuppressed(category) : // ...suppression happens via @SuppressWarnings + !options.isLintDisabled(category); // ...suppression happens via -Xlint:-category + if (!emit) + return; + } + + // Proceed + reportReady(diag); + } + + /** + * Step 3: Handle a diagnostic to which the applicable Lint instance (if any) has been applied. + */ + protected abstract void reportReady(JCDiagnostic diag); + + protected void addLintWaiter(JavaFileObject sourceFile, JCDiagnostic diagnostic) { + lintWaitersMap.computeIfAbsent(sourceFile, s -> new LinkedList<>()).add(diagnostic); + } + + /** + * Flush any lint waiters whose {@link Lint} configurations are now known. + */ + public void flushLintWaiters() { + lintWaitersMap.entrySet().removeIf(entry -> { + + // Is the source file no longer recognized? If so, discard warnings (e.g., this can happen with JShell) + JavaFileObject sourceFile = entry.getKey(); + if (!lintMapper.isKnown(sourceFile)) + return true; + + // Flush those diagnostics for which we now know the applicable Lint + List diagnosticList = entry.getValue(); + JavaFileObject prevSourceFile = useSource(sourceFile); + try { + diagnosticList.removeIf(diag -> { + Lint lint = lintFor(diag); + if (lint != null) { + reportWithLint(diag, lint); + return true; + } + return false; + }); + } finally { + useSource(prevSourceFile); + } + + // Discard list if empty + return diagnosticList.isEmpty(); + }); + } } /** @@ -124,7 +228,10 @@ public class Log extends AbstractLog { public class DiscardDiagnosticHandler extends DiagnosticHandler { @Override - public void report(JCDiagnostic diag) { } + protected void addLintWaiter(JavaFileObject sourceFile, JCDiagnostic diagnostic) { } + + @Override + protected void reportReady(JCDiagnostic diag) { } } /** @@ -157,11 +264,20 @@ public class Log extends AbstractLog { } @Override - public void report(JCDiagnostic diag) { + protected void reportReady(JCDiagnostic diag) { if (deferrable(diag)) { deferred.add(diag); } else { - prev.report(diag); + prev.reportReady(diag); + } + } + + @Override + protected void addLintWaiter(JavaFileObject sourceFile, JCDiagnostic diag) { + if (deferrable(diag)) { + super.addLintWaiter(sourceFile, diag); + } else { + prev.addLintWaiter(sourceFile, diag); } } @@ -182,6 +298,13 @@ public class Log extends AbstractLog { .filter(accepter) .forEach(prev::report); deferred = null; // prevent accidental ongoing use + + // Flush matching Lint waiters to the previous handler + lintWaitersMap.forEach( + (sourceFile, diagnostics) -> diagnostics.stream() + .filter(accepter) + .forEach(diagnostic -> prev.addLintWaiter(sourceFile, diagnostic))); + lintWaitersMap = null; // prevent accidental ongoing use } /** Report all deferred diagnostics in the specified order. */ @@ -247,6 +370,16 @@ public class Log extends AbstractLog { */ private final Context context; + /** + * The {@link Options} singleton. + */ + private final Options options; + + /** + * The lint positions table. + */ + private final LintMapper lintMapper; + /** * The root {@link Lint} singleton. */ @@ -350,6 +483,8 @@ public class Log extends AbstractLog { super(JCDiagnostic.Factory.instance(context)); context.put(logKey, this); this.context = context; + this.options = Options.instance(context); + this.lintMapper = LintMapper.instance(context); this.writers = writers; @SuppressWarnings("unchecked") // FIXME @@ -369,7 +504,6 @@ public class Log extends AbstractLog { this.diagFormatter = new BasicDiagnosticFormatter(messages); // Once Options is ready, complete the initialization - final Options options = Options.instance(context); options.whenReady(this::initOptions); } // where @@ -689,6 +823,21 @@ public class Log extends AbstractLog { diagnosticHandler.report(diagnostic); } +// Deferred Lint Calculation + + /** + * Report unreported lint warnings for which the applicable {@link Lint} configuration is now known. + */ + public void reportOutstandingWarnings() { + diagnosticHandler.flushLintWaiters(); + } + + // Get the Lint config for the given warning (if known) + private Lint lintFor(JCDiagnostic diag) { + Assert.check(diag.getLintCategory() != null); + return lintMapper.lintAt(diag.getSource(), diag.getDiagnosticPosition()).orElse(null); + } + // Obtain root Lint singleton lazily to avoid init loops private Lint rootLint() { if (rootLint == null) @@ -756,7 +905,7 @@ public class Log extends AbstractLog { private class DefaultDiagnosticHandler extends DiagnosticHandler { @Override - public void report(JCDiagnostic diagnostic) { + protected void reportReady(JCDiagnostic diagnostic) { if (expectDiagKeys != null) expectDiagKeys.remove(diagnostic.getCode()); @@ -783,13 +932,13 @@ public class Log extends AbstractLog { // Apply the appropriate mandatory warning aggregator, if needed if (diagnostic.isFlagSet(AGGREGATE)) { LintCategory category = diagnostic.getLintCategory(); - boolean verbose = rootLint().isEnabled(category); + boolean verbose = lintFor(diagnostic).isEnabled(category); if (!aggregatorFor(category).aggregate(diagnostic, verbose)) return; } // Strict warnings are always emitted - if (diagnostic.isFlagSet(DiagnosticFlag.STRICT)) { + if (diagnostic.isFlagSet(STRICT)) { writeDiagnostic(diagnostic); nwarnings++; return; diff --git a/test/langtools/tools/javac/6304921/TestLog.java b/test/langtools/tools/javac/6304921/TestLog.java index 41695554a88..8f00a14b9e2 100644 --- a/test/langtools/tools/javac/6304921/TestLog.java +++ b/test/langtools/tools/javac/6304921/TestLog.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ import javax.tools.SimpleJavaFileObject; import com.sun.tools.javac.file.JavacFileManager; import com.sun.tools.javac.parser.Parser; import com.sun.tools.javac.parser.ParserFactory; -import com.sun.tools.javac.resources.CompilerProperties.LintWarnings; +import com.sun.tools.javac.resources.CompilerProperties.Warnings; import com.sun.tools.javac.tree.EndPosTable; import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.TreeScanner; @@ -130,10 +130,11 @@ public class TestLog log.error(tree.pos(), Errors.NotStmt); log.error(nil, Errors.NotStmt); - log.warning(LintWarnings.DivZero); - log.warning(tree.pos, LintWarnings.DivZero); - log.warning(tree.pos(), LintWarnings.DivZero); - log.warning(nil, LintWarnings.DivZero); + // some warnings that will be emitted during parsing + log.warning(Warnings.ExtraneousSemicolon); + log.warning(tree.pos, Warnings.ExtraneousSemicolon); + log.warning(tree.pos(), Warnings.ExtraneousSemicolon); + log.warning(nil, Warnings.ExtraneousSemicolon); } private Log log; diff --git a/test/langtools/tools/javac/ImportModule.java b/test/langtools/tools/javac/ImportModule.java index f088dbef658..d26b73c0289 100644 --- a/test/langtools/tools/javac/ImportModule.java +++ b/test/langtools/tools/javac/ImportModule.java @@ -730,8 +730,8 @@ public class ImportModule extends TestRunner { .getOutputLines(Task.OutputKind.DIRECT); List expectedErrors = List.of( - "module-info.java:3:18: compiler.warn.module.not.found: M1", "module-info.java:6:9: compiler.err.cant.resolve: kindname.class, A, , ", + "module-info.java:3:18: compiler.warn.module.not.found: M1", "1 error", "1 warning" ); diff --git a/test/langtools/tools/javac/OverrideChecks/6400189/T6400189a.out b/test/langtools/tools/javac/OverrideChecks/6400189/T6400189a.out index 2a12111fe40..23dcddc1e93 100644 --- a/test/langtools/tools/javac/OverrideChecks/6400189/T6400189a.out +++ b/test/langtools/tools/javac/OverrideChecks/6400189/T6400189a.out @@ -1,4 +1,4 @@ -T6400189a.java:14:35: compiler.warn.unchecked.call.mbr.of.raw.type: getAnnotation(java.lang.Class), java.lang.reflect.Constructor T6400189a.java:14:35: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.annotation.Annotation, java.lang.annotation.Documented) +T6400189a.java:14:35: compiler.warn.unchecked.call.mbr.of.raw.type: getAnnotation(java.lang.Class), java.lang.reflect.Constructor 1 error 1 warning diff --git a/test/langtools/tools/javac/OverrideChecks/6400189/T6400189b.out b/test/langtools/tools/javac/OverrideChecks/6400189/T6400189b.out index 904cd3e677f..91e34b5beca 100644 --- a/test/langtools/tools/javac/OverrideChecks/6400189/T6400189b.out +++ b/test/langtools/tools/javac/OverrideChecks/6400189/T6400189b.out @@ -1,4 +1,4 @@ -T6400189b.java:24:24: compiler.warn.unchecked.call.mbr.of.raw.type: m(T6400189b), T6400189b.B T6400189b.java:24:24: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.Object, java.lang.Integer) +T6400189b.java:24:24: compiler.warn.unchecked.call.mbr.of.raw.type: m(T6400189b), T6400189b.B 1 error 1 warning diff --git a/test/langtools/tools/javac/danglingDocComments/DanglingDocCommentsClass.enabled.out b/test/langtools/tools/javac/danglingDocComments/DanglingDocCommentsClass.enabled.out index 78285aa45d9..b2dde3ff0ef 100644 --- a/test/langtools/tools/javac/danglingDocComments/DanglingDocCommentsClass.enabled.out +++ b/test/langtools/tools/javac/danglingDocComments/DanglingDocCommentsClass.enabled.out @@ -1,7 +1,7 @@ +DanglingDocCommentsClass.java:15:5: compiler.warn.dangling.doc.comment +DanglingDocCommentsClass.java:19:5: compiler.warn.dangling.doc.comment DanglingDocCommentsClass.java:10:1: compiler.warn.dangling.doc.comment DanglingDocCommentsClass.java:13:1: compiler.warn.dangling.doc.comment DanglingDocCommentsClass.java:14:8: compiler.warn.dangling.doc.comment DanglingDocCommentsClass.java:14:69: compiler.warn.dangling.doc.comment -DanglingDocCommentsClass.java:15:5: compiler.warn.dangling.doc.comment -DanglingDocCommentsClass.java:19:5: compiler.warn.dangling.doc.comment 6 warnings diff --git a/test/langtools/tools/javac/danglingDocComments/DanglingDocCommentsClass_Line.enabled.out b/test/langtools/tools/javac/danglingDocComments/DanglingDocCommentsClass_Line.enabled.out index 3ed89c5f5bc..e97bd630ad8 100644 --- a/test/langtools/tools/javac/danglingDocComments/DanglingDocCommentsClass_Line.enabled.out +++ b/test/langtools/tools/javac/danglingDocComments/DanglingDocCommentsClass_Line.enabled.out @@ -1,7 +1,7 @@ +DanglingDocCommentsClass_Line.java:21:5: compiler.warn.dangling.doc.comment +DanglingDocCommentsClass_Line.java:26:5: compiler.warn.dangling.doc.comment DanglingDocCommentsClass_Line.java:11:1: compiler.warn.dangling.doc.comment DanglingDocCommentsClass_Line.java:15:1: compiler.warn.dangling.doc.comment DanglingDocCommentsClass_Line.java:17:5: compiler.warn.dangling.doc.comment DanglingDocCommentsClass_Line.java:19:9: compiler.warn.dangling.doc.comment -DanglingDocCommentsClass_Line.java:21:5: compiler.warn.dangling.doc.comment -DanglingDocCommentsClass_Line.java:26:5: compiler.warn.dangling.doc.comment 6 warnings diff --git a/test/langtools/tools/javac/danglingDocComments/DanglingDocCommentsClass_Mixed.enabled.out b/test/langtools/tools/javac/danglingDocComments/DanglingDocCommentsClass_Mixed.enabled.out index 1eda729da19..13e15493579 100644 --- a/test/langtools/tools/javac/danglingDocComments/DanglingDocCommentsClass_Mixed.enabled.out +++ b/test/langtools/tools/javac/danglingDocComments/DanglingDocCommentsClass_Mixed.enabled.out @@ -1,4 +1,4 @@ -DanglingDocCommentsClass_Mixed.java:13:1: compiler.warn.dangling.doc.comment DanglingDocCommentsClass_Mixed.java:17:5: compiler.warn.dangling.doc.comment DanglingDocCommentsClass_Mixed.java:21:5: compiler.warn.dangling.doc.comment +DanglingDocCommentsClass_Mixed.java:13:1: compiler.warn.dangling.doc.comment 3 warnings diff --git a/test/langtools/tools/javac/danglingDocComments/DanglingDocCommentsEnum.enabled.out b/test/langtools/tools/javac/danglingDocComments/DanglingDocCommentsEnum.enabled.out index ddf1b2964de..33938e86078 100644 --- a/test/langtools/tools/javac/danglingDocComments/DanglingDocCommentsEnum.enabled.out +++ b/test/langtools/tools/javac/danglingDocComments/DanglingDocCommentsEnum.enabled.out @@ -1,8 +1,8 @@ +DanglingDocCommentsEnum.java:16:5: compiler.warn.dangling.doc.comment +DanglingDocCommentsEnum.java:22:5: compiler.warn.dangling.doc.comment +DanglingDocCommentsEnum.java:28:5: compiler.warn.dangling.doc.comment DanglingDocCommentsEnum.java:10:1: compiler.warn.dangling.doc.comment DanglingDocCommentsEnum.java:13:1: compiler.warn.dangling.doc.comment DanglingDocCommentsEnum.java:14:8: compiler.warn.dangling.doc.comment DanglingDocCommentsEnum.java:14:67: compiler.warn.dangling.doc.comment -DanglingDocCommentsEnum.java:16:5: compiler.warn.dangling.doc.comment -DanglingDocCommentsEnum.java:22:5: compiler.warn.dangling.doc.comment -DanglingDocCommentsEnum.java:28:5: compiler.warn.dangling.doc.comment 7 warnings diff --git a/test/langtools/tools/javac/generics/diamond/7188968/T7188968.out b/test/langtools/tools/javac/generics/diamond/7188968/T7188968.out index efceb84c8c7..3c93e1711d6 100644 --- a/test/langtools/tools/javac/generics/diamond/7188968/T7188968.out +++ b/test/langtools/tools/javac/generics/diamond/7188968/T7188968.out @@ -1,11 +1,11 @@ T7188968.java:20:20: compiler.err.cant.resolve.location: kindname.variable, unknown, , , (compiler.misc.location: kindname.class, T7188968, null) -T7188968.java:20:9: compiler.warn.unchecked.call.mbr.of.raw.type: T7188968.Foo(java.util.List,java.lang.Object), T7188968.Foo T7188968.java:21:20: compiler.err.cant.resolve.location: kindname.variable, unknown, , , (compiler.misc.location: kindname.class, T7188968, null) -T7188968.java:21:29: compiler.warn.unchecked.call.mbr.of.raw.type: T7188968.Foo(java.util.List,java.lang.Object), T7188968.Foo T7188968.java:22:22: compiler.err.cant.resolve.location: kindname.variable, unknown, , , (compiler.misc.location: kindname.class, T7188968, null) +T7188968.java:23:24: compiler.err.cant.resolve.location: kindname.variable, unknown, , , (compiler.misc.location: kindname.class, T7188968, null) +T7188968.java:20:9: compiler.warn.unchecked.call.mbr.of.raw.type: T7188968.Foo(java.util.List,java.lang.Object), T7188968.Foo +T7188968.java:21:29: compiler.warn.unchecked.call.mbr.of.raw.type: T7188968.Foo(java.util.List,java.lang.Object), T7188968.Foo T7188968.java:22:9: compiler.warn.unchecked.meth.invocation.applied: kindname.constructor, , java.util.List,java.lang.Object, java.util.List,unknown, kindname.class, T7188968.Foo T7188968.java:22:19: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.util.List, java.util.List -T7188968.java:23:24: compiler.err.cant.resolve.location: kindname.variable, unknown, , , (compiler.misc.location: kindname.class, T7188968, null) T7188968.java:23:20: compiler.warn.unchecked.meth.invocation.applied: kindname.method, makeFoo, java.util.List,java.lang.Object, java.util.List,unknown, kindname.class, T7188968.Foo T7188968.java:23:21: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.util.List, java.util.List 4 errors diff --git a/test/langtools/tools/javac/lambda/TargetType22.out b/test/langtools/tools/javac/lambda/TargetType22.out index d94b2cc60b3..c19aef2411f 100644 --- a/test/langtools/tools/javac/lambda/TargetType22.out +++ b/test/langtools/tools/javac/lambda/TargetType22.out @@ -1,4 +1,4 @@ -TargetType22.java:29:21: compiler.warn.unchecked.varargs.non.reifiable.type: A TargetType22.java:40:9: compiler.err.ref.ambiguous: call, kindname.method, call(TargetType22.Sam1), TargetType22, kindname.method, call(TargetType22.SamX), TargetType22 +TargetType22.java:29:21: compiler.warn.unchecked.varargs.non.reifiable.type: A 1 error 1 warning diff --git a/test/langtools/tools/javac/lint/LexicalLintNesting.java b/test/langtools/tools/javac/lint/LexicalLintNesting.java new file mode 100644 index 00000000000..f167921df81 --- /dev/null +++ b/test/langtools/tools/javac/lint/LexicalLintNesting.java @@ -0,0 +1,170 @@ +/* + * @test /nodynamiccopyright/ + * @bug 8224228 + * @summary Verify lexical lint warnings handle nested declarations with SuppressWarnings correctly + * @compile/fail/ref=LexicalLintNesting.out -XDrawDiagnostics -Xlint:text-blocks -Werror LexicalLintNesting.java + */ + +//@SuppressWarnings("text-blocks") +public class LexicalLintNesting { + + //@SuppressWarnings("text-blocks") + /* WARNING HERE */ String s1 = """ + trailing space here:\u0020 + """; + + @SuppressWarnings("text-blocks") + String s2 = """ + trailing space here:\u0020 + """; + + //@SuppressWarnings("text-blocks") + public static class Nested1 { + + @SuppressWarnings("text-blocks") + String s3 = """ + trailing space here:\u0020 + """; + + //@SuppressWarnings("text-blocks") + /* WARNING HERE */ String s4 = """ + trailing space here:\u0020 + """; + + @SuppressWarnings("text-blocks") + public static class Nested1A { + + //@SuppressWarnings("text-blocks") + String s5 = """ + trailing space here:\u0020 + """; + + @SuppressWarnings("text-blocks") + String s6 = """ + trailing space here:\u0020 + """; + + } + + @SuppressWarnings("text-blocks") + String s7 = """ + trailing space here:\u0020 + """; + + //@SuppressWarnings("text-blocks") + /* WARNING HERE */ String s8 = """ + trailing space here:\u0020 + """; + + //@SuppressWarnings("text-blocks") + public static class Nested1B { + + @SuppressWarnings("text-blocks") + String s9 = """ + trailing space here:\u0020 + """; + + //@SuppressWarnings("text-blocks") + /* WARNING HERE */ String s10 = """ + trailing space here:\u0020 + """; + + } + + @SuppressWarnings("text-blocks") + String s11 = """ + trailing space here:\u0020 + """; + + //@SuppressWarnings("text-blocks") + /* WARNING HERE */ String s12 = """ + trailing space here:\u0020 + """; + + } + + @SuppressWarnings("text-blocks") + String s13 = """ + trailing space here:\u0020 + """; + + //@SuppressWarnings("text-blocks") + /* WARNING HERE */ String s14 = """ + trailing space here:\u0020 + """; + + @SuppressWarnings("text-blocks") + public static class Nested2 { + + @SuppressWarnings("text-blocks") + String s15 = """ + trailing space here:\u0020 + """; + + //@SuppressWarnings("text-blocks") + String s16 = """ + trailing space here:\u0020 + """; + + @SuppressWarnings("text-blocks") + public static class Nested2A { + + //@SuppressWarnings("text-blocks") + String s17 = """ + trailing space here:\u0020 + """; + + @SuppressWarnings("text-blocks") + String s18 = """ + trailing space here:\u0020 + """; // SHOULD NOT get a warning here + + } + + @SuppressWarnings("text-blocks") + String s19 = """ + trailing space here:\u0020 + """; + + //@SuppressWarnings("text-blocks") + String s20 = """ + trailing space here:\u0020 + """; + + //@SuppressWarnings("text-blocks") + public static class Nested2B { + + @SuppressWarnings("text-blocks") + String s21 = """ + trailing space here:\u0020 + """; + + //@SuppressWarnings("text-blocks") + String s22 = """ + trailing space here:\u0020 + """; + + } + + @SuppressWarnings("text-blocks") + String s23 = """ + trailing space here:\u0020 + """; + + //@SuppressWarnings("text-blocks") + String s24 = """ + trailing space here:\u0020 + """; + + } + + //@SuppressWarnings("text-blocks") + /* WARNING HERE */ String s25 = """ + trailing space here:\u0020 + """; + + @SuppressWarnings("text-blocks") + String s26 = """ + trailing space here:\u0020 + """; +} diff --git a/test/langtools/tools/javac/lint/LexicalLintNesting.out b/test/langtools/tools/javac/lint/LexicalLintNesting.out new file mode 100644 index 00000000000..b16db47cf52 --- /dev/null +++ b/test/langtools/tools/javac/lint/LexicalLintNesting.out @@ -0,0 +1,10 @@ +LexicalLintNesting.java:12:36: compiler.warn.trailing.white.space.will.be.removed +LexicalLintNesting.java:30:40: compiler.warn.trailing.white.space.will.be.removed +LexicalLintNesting.java:55:40: compiler.warn.trailing.white.space.will.be.removed +LexicalLintNesting.java:68:45: compiler.warn.trailing.white.space.will.be.removed +LexicalLintNesting.java:80:41: compiler.warn.trailing.white.space.will.be.removed +LexicalLintNesting.java:92:37: compiler.warn.trailing.white.space.will.be.removed +LexicalLintNesting.java:162:37: compiler.warn.trailing.white.space.will.be.removed +- compiler.err.warnings.and.werror +1 error +7 warnings diff --git a/test/langtools/tools/javac/lint/TextBlockSuppress.java b/test/langtools/tools/javac/lint/TextBlockSuppress.java new file mode 100644 index 00000000000..05019be6bc2 --- /dev/null +++ b/test/langtools/tools/javac/lint/TextBlockSuppress.java @@ -0,0 +1,61 @@ +/* + * @test /nodynamiccopyright/ + * @bug 8224228 + * @summary Verify SuppressWarnings works for LintCategore.TEXT_BLOCKS + * @compile/fail/ref=TextBlockSuppress.out -XDrawDiagnostics -Xlint:text-blocks -Werror TextBlockSuppress.java + */ + +public class TextBlockSuppress { + + public static class Example1 { + public void method() { + String s = """ + trailing space here:\u0020 + """; // SHOULD get a warning here + } + } + + @SuppressWarnings("text-blocks") + public static class Example2 { + public void method() { + String s = """ + trailing space here:\u0020 + """; // SHOULD NOT get a warning here + } + } + + public static class Example3 { + @SuppressWarnings("text-blocks") + public void method() { + String s = """ + trailing space here:\u0020 + """; // SHOULD NOT get a warning here + } + } + + public static class Example4 { + { + String s = """ + trailing space here:\u0020 + """; // SHOULD get a warning here + } + } + + @SuppressWarnings("text-blocks") + public static class Example5 { + { + String s = """ + trailing space here:\u0020 + """; // SHOULD NOT get a warning here + } + } + + public static class Example6 { + public void method() { + @SuppressWarnings("text-blocks") + String s = """ + trailing space here:\u0020 + """; // SHOULD NOT get a warning here + } + } +} diff --git a/test/langtools/tools/javac/lint/TextBlockSuppress.out b/test/langtools/tools/javac/lint/TextBlockSuppress.out new file mode 100644 index 00000000000..d16f080a133 --- /dev/null +++ b/test/langtools/tools/javac/lint/TextBlockSuppress.out @@ -0,0 +1,5 @@ +TextBlockSuppress.java:12:24: compiler.warn.trailing.white.space.will.be.removed +TextBlockSuppress.java:38:24: compiler.warn.trailing.white.space.will.be.removed +- compiler.err.warnings.and.werror +1 error +2 warnings diff --git a/test/langtools/tools/javac/mandatoryWarnings/deprecated/Test5.out b/test/langtools/tools/javac/mandatoryWarnings/deprecated/Test5.out index 6fe57b8979d..1656d8eeff5 100644 --- a/test/langtools/tools/javac/mandatoryWarnings/deprecated/Test5.out +++ b/test/langtools/tools/javac/mandatoryWarnings/deprecated/Test5.out @@ -1,4 +1,4 @@ -Q.java:7:10: compiler.warn.has.been.deprecated: bar(), Q2 P.java:10:18: compiler.warn.has.been.deprecated: foo(), Q +Q.java:7:10: compiler.warn.has.been.deprecated: bar(), Q2 Q.java:17:25: compiler.warn.has.been.deprecated: foo(), Q 3 warnings diff --git a/test/langtools/tools/javac/mandatoryWarnings/deprecated/Test5b.out b/test/langtools/tools/javac/mandatoryWarnings/deprecated/Test5b.out index fe4a91e2584..5dee9c1414c 100644 --- a/test/langtools/tools/javac/mandatoryWarnings/deprecated/Test5b.out +++ b/test/langtools/tools/javac/mandatoryWarnings/deprecated/Test5b.out @@ -1,4 +1,4 @@ -Q.java:7:10: compiler.warn.has.been.deprecated: bar(), Q2 P.java:10:18: compiler.warn.has.been.deprecated: foo(), Q +Q.java:7:10: compiler.warn.has.been.deprecated: bar(), Q2 - compiler.note.deprecated.filename.additional: Q.java 2 warnings diff --git a/test/langtools/tools/javac/modules/AnnotationsOnModules.java b/test/langtools/tools/javac/modules/AnnotationsOnModules.java index 6d9bfaad406..f9858a105eb 100644 --- a/test/langtools/tools/javac/modules/AnnotationsOnModules.java +++ b/test/langtools/tools/javac/modules/AnnotationsOnModules.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -599,8 +599,8 @@ public class AnnotationsOnModules extends ModuleTestBase { "1 warning"); } else if (suppress.equals(DEPRECATED_JAVADOC)) { expected = Arrays.asList( - "module-info.java:1:19: compiler.warn.missing.deprecated.annotation", "module-info.java:2:14: compiler.warn.has.been.deprecated.module: m1x", + "module-info.java:1:19: compiler.warn.missing.deprecated.annotation", "2 warnings"); } else { expected = Arrays.asList(""); diff --git a/test/langtools/tools/javac/preview/PreviewErrors.java b/test/langtools/tools/javac/preview/PreviewErrors.java index eab5b2af9bf..db17aabbd42 100644 --- a/test/langtools/tools/javac/preview/PreviewErrors.java +++ b/test/langtools/tools/javac/preview/PreviewErrors.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -324,7 +324,9 @@ public class PreviewErrors extends ComboInstance { ok = true; switch (elementType) { case LANGUAGE -> { - if (lint == Lint.ENABLE_PREVIEW) { + if (suppress == Suppress.YES) { + expected = Set.of(); + } else if (lint == Lint.ENABLE_PREVIEW) { expected = Set.of("5:41:compiler.warn.preview.feature.use"); } else { expected = Set.of("-1:-1:compiler.note.preview.filename", diff --git a/test/langtools/tools/javac/preview/PreviewTest.java b/test/langtools/tools/javac/preview/PreviewTest.java index 36f1e70acd0..e681f3f837e 100644 --- a/test/langtools/tools/javac/preview/PreviewTest.java +++ b/test/langtools/tools/javac/preview/PreviewTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -587,12 +587,12 @@ public class PreviewTest extends TestRunner { "Test.java:19:11: compiler.err.is.preview: test()", "Test.java:20:11: compiler.err.is.preview: test()", "Test.java:21:11: compiler.err.is.preview: test()", - "Test.java:24:11: compiler.warn.is.preview.reflective: test()", "Test.java:29:16: compiler.err.is.preview: preview.api.Preview", "Test.java:32:21: compiler.err.is.preview: test()", "Test.java:36:21: compiler.err.is.preview: test()", "Test.java:40:13: compiler.err.is.preview: test()", "Test.java:41:21: compiler.err.is.preview: FIELD", + "Test.java:24:11: compiler.warn.is.preview.reflective: test()", "17 errors", "1 warning"); @@ -792,6 +792,99 @@ public class PreviewTest extends TestRunner { throw new Exception("expected output not found" + log); } + @Test //JDK-8224228: + public void testSuppressWarnings(Path base) throws Exception { + Path apiSrc = base.resolve("api-src"); + tb.writeJavaFiles(apiSrc, + """ + package preview.api; + @jdk.internal.javac.PreviewFeature(feature=jdk.internal.javac.PreviewFeature.Feature.TEST) + public class Preview { + public static int test() { + return 0; + } + } + """); + Path apiClasses = base.resolve("api-classes"); + + new JavacTask(tb, Task.Mode.CMDLINE) + .outdir(apiClasses) + .options("--patch-module", "java.base=" + apiSrc.toString(), + "-Werror") + .files(tb.findJavaFiles(apiSrc)) + .run() + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + + Path testSrc = base.resolve("test-src"); + tb.writeJavaFiles(testSrc, + """ + package test; + import preview.api.Preview; + public class Test { + + public static class Example1 { + public void method() { + Preview.test(); // SHOULD get a warning here + } + } + + @SuppressWarnings("preview") + public static class Example2 { + public void method() { + Preview.test(); // SHOULD NOT get a warning here + } + } + + public static class Example3 { + @SuppressWarnings("preview") + public void method() { + Preview.test(); // SHOULD NOT get a warning here + } + } + + public static class Example4 { + { + Preview.test(); // SHOULD get a warning here + } + } + + @SuppressWarnings("preview") + public static class Example5 { + { + Preview.test(); // SHOULD NOT get a warning here + } + } + + public static class Example6 { + @SuppressWarnings("preview") + int x = Preview.test(); // SHOULD NOT get a warning here + } + } + """); + Path testClasses = base.resolve("test-classes"); + List log = new JavacTask(tb, Task.Mode.CMDLINE) + .outdir(testClasses) + .options("--patch-module", "java.base=" + apiClasses.toString(), + "--add-exports", "java.base/preview.api=ALL-UNNAMED", + "--enable-preview", + "-Xlint:preview", + "-source", String.valueOf(Runtime.version().feature()), + "-XDrawDiagnostics") + .files(tb.findJavaFiles(testSrc)) + .run(Task.Expect.SUCCESS) + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + + List expected = + List.of("Test.java:7:11: compiler.warn.is.preview: preview.api.Preview", + "Test.java:27:11: compiler.warn.is.preview: preview.api.Preview", + "2 warnings"); + + if (!log.equals(expected)) + throw new Exception("expected output not found: " + log); + } + @Test //JDK-8343540: public void nonPreviewImplementsPreview5(Path base) throws Exception { Path apiSrc = base.resolve("api-src"); diff --git a/test/langtools/tools/javac/varargs/7097436/T7097436.out b/test/langtools/tools/javac/varargs/7097436/T7097436.out index 5e35910d2fa..392869f3b9f 100644 --- a/test/langtools/tools/javac/varargs/7097436/T7097436.out +++ b/test/langtools/tools/javac/varargs/7097436/T7097436.out @@ -1,6 +1,6 @@ -T7097436.java:13:20: compiler.warn.varargs.unsafe.use.varargs.param: ls -T7097436.java:14:25: compiler.warn.varargs.unsafe.use.varargs.param: ls T7097436.java:15:20: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.util.List[], java.lang.String) T7097436.java:16:26: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.util.List[], java.lang.Integer[]) +T7097436.java:13:20: compiler.warn.varargs.unsafe.use.varargs.param: ls +T7097436.java:14:25: compiler.warn.varargs.unsafe.use.varargs.param: ls 2 errors 2 warnings diff --git a/test/langtools/tools/javac/warnings/6594914/T6594914a.out b/test/langtools/tools/javac/warnings/6594914/T6594914a.out index 62f99072a7a..d3d759ca044 100644 --- a/test/langtools/tools/javac/warnings/6594914/T6594914a.out +++ b/test/langtools/tools/javac/warnings/6594914/T6594914a.out @@ -1,7 +1,7 @@ T6594914a.java:11:5: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package T6594914a.java:16:16: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package +T6594914a.java:16:52: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package T6594914a.java:16:33: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package T6594914a.java:17:20: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package -T6594914a.java:16:52: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package T6594914a.java:24:9: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package 6 warnings diff --git a/test/langtools/tools/javac/warnings/7090499/T7090499.out b/test/langtools/tools/javac/warnings/7090499/T7090499.out index 1ff9e164e48..2241c0a04bb 100644 --- a/test/langtools/tools/javac/warnings/7090499/T7090499.out +++ b/test/langtools/tools/javac/warnings/7090499/T7090499.out @@ -1,14 +1,14 @@ +T7090499.java:26:10: compiler.err.improperly.formed.type.inner.raw.param +T7090499.java:27:10: compiler.err.improperly.formed.type.inner.raw.param +T7090499.java:28:17: compiler.err.improperly.formed.type.inner.raw.param +T7090499.java:28:10: compiler.err.improperly.formed.type.inner.raw.param T7090499.java:18:5: compiler.warn.raw.class.use: T7090499, T7090499 T7090499.java:18:22: compiler.warn.raw.class.use: T7090499, T7090499 T7090499.java:20:10: compiler.warn.raw.class.use: T7090499.A.X, T7090499.A.X T7090499.java:21:10: compiler.warn.raw.class.use: T7090499.A.Z, T7090499.A.Z T7090499.java:24:17: compiler.warn.raw.class.use: T7090499.B, T7090499.B -T7090499.java:26:10: compiler.err.improperly.formed.type.inner.raw.param -T7090499.java:27:10: compiler.err.improperly.formed.type.inner.raw.param T7090499.java:28:18: compiler.warn.raw.class.use: T7090499.B, T7090499.B -T7090499.java:28:17: compiler.err.improperly.formed.type.inner.raw.param T7090499.java:28:11: compiler.warn.raw.class.use: T7090499.B, T7090499.B -T7090499.java:28:10: compiler.err.improperly.formed.type.inner.raw.param T7090499.java:30:32: compiler.warn.raw.class.use: T7090499.B, T7090499.B T7090499.java:33:13: compiler.warn.raw.class.use: T7090499.A, T7090499.A T7090499.java:33:24: compiler.warn.raw.class.use: T7090499.A, T7090499.A diff --git a/test/langtools/tools/javac/warnings/UnneededStrictfpWarningToolBox.java b/test/langtools/tools/javac/warnings/UnneededStrictfpWarningToolBox.java index b5062a9b63f..a9101b47e42 100644 --- a/test/langtools/tools/javac/warnings/UnneededStrictfpWarningToolBox.java +++ b/test/langtools/tools/javac/warnings/UnneededStrictfpWarningToolBox.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -116,8 +116,8 @@ public class UnneededStrictfpWarningToolBox extends TestRunner { var expected = List.of("UnneededStrictfpWarning1.java:1:17: compiler.warn.strictfp", "UnneededStrictfpWarning1.java:10:10: compiler.warn.strictfp", "UnneededStrictfpWarning1.java:12:29: compiler.warn.strictfp", - "UnneededStrictfpWarning1.java:16:28: compiler.warn.strictfp", "UnneededStrictfpWarning1.java:18:21: compiler.warn.strictfp", + "UnneededStrictfpWarning1.java:16:28: compiler.warn.strictfp", "5 warnings"); checkLog(log, expected); } diff --git a/test/langtools/tools/javac/warnings/suppress/T6480588.out b/test/langtools/tools/javac/warnings/suppress/T6480588.out index 630ba55523d..267ef32c964 100644 --- a/test/langtools/tools/javac/warnings/suppress/T6480588.out +++ b/test/langtools/tools/javac/warnings/suppress/T6480588.out @@ -1,19 +1,19 @@ T6480588.java:16:24: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package T6480588.java:16:51: compiler.warn.has.been.deprecated: DeprecatedInterface, compiler.misc.unnamed.package T6480588.java:15:2: compiler.warn.has.been.deprecated: DeprecatedAnnotation, compiler.misc.unnamed.package +T6480588.java:18:35: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package T6480588.java:18:12: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package T6480588.java:18:65: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package +T6480588.java:30:5: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package +T6480588.java:33:25: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package +T6480588.java:33:52: compiler.warn.has.been.deprecated: DeprecatedInterface, compiler.misc.unnamed.package +T6480588.java:32:6: compiler.warn.has.been.deprecated: DeprecatedAnnotation, compiler.misc.unnamed.package T6480588.java:17:6: compiler.warn.has.been.deprecated: DeprecatedAnnotation, compiler.misc.unnamed.package -T6480588.java:18:35: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package +T6480588.java:29:6: compiler.warn.has.been.deprecated: DeprecatedAnnotation, compiler.misc.unnamed.package T6480588.java:19:9: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package T6480588.java:19:34: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package T6480588.java:21:9: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package T6480588.java:21:25: compiler.warn.deprecated.annotation.has.no.effect: kindname.variable T6480588.java:21:35: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package -T6480588.java:30:5: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package -T6480588.java:29:6: compiler.warn.has.been.deprecated: DeprecatedAnnotation, compiler.misc.unnamed.package T6480588.java:30:33: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package -T6480588.java:33:25: compiler.warn.has.been.deprecated: DeprecatedClass, compiler.misc.unnamed.package -T6480588.java:33:52: compiler.warn.has.been.deprecated: DeprecatedInterface, compiler.misc.unnamed.package -T6480588.java:32:6: compiler.warn.has.been.deprecated: DeprecatedAnnotation, compiler.misc.unnamed.package 18 warnings From 9041f4c47f3c9b90abe825f652f572351060c96a Mon Sep 17 00:00:00 2001 From: Chris Plummer Date: Wed, 20 Aug 2025 15:32:17 +0000 Subject: [PATCH 06/54] 8309400: JDI spec needs to clarify when OpaqueFrameException and NativeMethodException are thrown Reviewed-by: sspitsyn, alanb, amenkov --- .../classes/com/sun/jdi/ThreadReference.java | 10 ++--- .../com/sun/tools/jdi/StackFrameImpl.java | 39 ++++++++----------- .../sun/tools/jdi/ThreadReferenceImpl.java | 6 +-- 3 files changed, 25 insertions(+), 30 deletions(-) diff --git a/src/jdk.jdi/share/classes/com/sun/jdi/ThreadReference.java b/src/jdk.jdi/share/classes/com/sun/jdi/ThreadReference.java index bccdf4cc8bf..67b8e391bf3 100644 --- a/src/jdk.jdi/share/classes/com/sun/jdi/ThreadReference.java +++ b/src/jdk.jdi/share/classes/com/sun/jdi/ThreadReference.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -402,8 +402,8 @@ public interface ThreadReference extends ObjectReference { * @throws java.lang.IllegalArgumentException if frame * is not on this thread's call stack. * - * @throws OpaqueFrameException if this thread is a suspended virtual thread and the - * target VM was unable to pop the frames. + * @throws OpaqueFrameException if the target VM is unable to pop this frame + * (e.g. a virtual thread is suspended, but not at an event). * * @throws NativeMethodException if one of the frames that would be * popped is that of a native method or if the frame previous to @@ -484,8 +484,8 @@ public interface ThreadReference extends ObjectReference { * @throws IncompatibleThreadStateException if this * thread is not suspended. * - * @throws OpaqueFrameException if this thread is a suspended virtual thread and the - * target VM is unable to force the method to return. + * @throws OpaqueFrameException if the target VM is unable to force the method to return + * (e.g. a virtual thread is suspended, but not at an event). * * @throws NativeMethodException if the frame to be returned from * is that of a native method. diff --git a/src/jdk.jdi/share/classes/com/sun/tools/jdi/StackFrameImpl.java b/src/jdk.jdi/share/classes/com/sun/tools/jdi/StackFrameImpl.java index e242bd7313b..a36e5695f69 100644 --- a/src/jdk.jdi/share/classes/com/sun/tools/jdi/StackFrameImpl.java +++ b/src/jdk.jdi/share/classes/com/sun/tools/jdi/StackFrameImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. * 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,29 +395,24 @@ public class StackFrameImpl extends MirrorImpl } catch (JDWPException exc) { switch (exc.errorCode()) { case JDWP.Error.OPAQUE_FRAME: - if (thread.isVirtual()) { - // We first need to find out if the current frame is native, or if the - // previous frame is native, in which case we throw NativeMethodException - for (int i = 0; i < 2; i++) { - StackFrameImpl sf; - try { - sf = (StackFrameImpl)thread.frame(i); - } catch (IndexOutOfBoundsException e) { - // This should never happen, but we need to check for it. - break; - } - sf.validateStackFrame(); - MethodImpl meth = (MethodImpl)sf.location().method(); - if (meth.isNative()) { - throw new NativeMethodException(); - } + // We first need to find out if the current frame is native, or if the + // previous frame is native, in which case we throw NativeMethodException + for (int i = 0; i < 2; i++) { + StackFrame sf; + try { + sf = thread.frame(i); + } catch (IndexOutOfBoundsException e) { + // This should never happen, but we need to check for it. + break; + } + Method meth = sf.location().method(); + if (meth.isNative()) { + throw new NativeMethodException(); } - // No native frames involved. Must have been due to thread - // not being mounted. - throw new OpaqueFrameException(); - } else { - throw new NativeMethodException(); } + // No native frames involved. Must have been due to virtual thread + // not being mounted or some other reason such as failure to deopt. + throw new OpaqueFrameException(); case JDWP.Error.THREAD_NOT_SUSPENDED: throw new IncompatibleThreadStateException( "Thread not current or suspended"); diff --git a/src/jdk.jdi/share/classes/com/sun/tools/jdi/ThreadReferenceImpl.java b/src/jdk.jdi/share/classes/com/sun/tools/jdi/ThreadReferenceImpl.java index 0f99fe99871..e5dce0718f4 100644 --- a/src/jdk.jdi/share/classes/com/sun/tools/jdi/ThreadReferenceImpl.java +++ b/src/jdk.jdi/share/classes/com/sun/tools/jdi/ThreadReferenceImpl.java @@ -597,10 +597,10 @@ public class ThreadReferenceImpl extends ObjectReferenceImpl } catch (JDWPException exc) { switch (exc.errorCode()) { case JDWP.Error.OPAQUE_FRAME: - if (isVirtual() && !meth.isNative()) { - throw new OpaqueFrameException(); - } else { + if (meth.isNative()) { throw new NativeMethodException(); + } else { + throw new OpaqueFrameException(); } case JDWP.Error.THREAD_NOT_SUSPENDED: throw new IncompatibleThreadStateException( From be6c15ecb490e86bafc15b5cd552784f7aa3ee69 Mon Sep 17 00:00:00 2001 From: Alan Bateman Date: Wed, 20 Aug 2025 16:07:38 +0000 Subject: [PATCH 07/54] 8365671: Typo in Joiner.allUntil example Reviewed-by: liach --- .../classes/java/util/concurrent/StructuredTaskScope.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/java.base/share/classes/java/util/concurrent/StructuredTaskScope.java b/src/java.base/share/classes/java/util/concurrent/StructuredTaskScope.java index fb16e0a615e..0088e486d4a 100644 --- a/src/java.base/share/classes/java/util/concurrent/StructuredTaskScope.java +++ b/src/java.base/share/classes/java/util/concurrent/StructuredTaskScope.java @@ -700,12 +700,12 @@ public sealed interface StructuredTaskScope * } * } * - * var joiner = Joiner.all(new CancelAfterTwoFailures()); + * var joiner = Joiner.allUntil(new CancelAfterTwoFailures()); * } * *

    The following example uses {@code allUntil} to wait for all subtasks to * complete without any cancellation. This is similar to {@link #awaitAll()} - * except that it yields a stream of the completed subtasks. + * except that it yields a list of the completed subtasks. * {@snippet lang=java : * List> invokeAll(Collection> tasks) throws InterruptedException { * try (var scope = StructuredTaskScope.open(Joiner.allUntil(_ -> false))) { From ed7d5fe840fed853b8a7db3347d6400f142ad154 Mon Sep 17 00:00:00 2001 From: Francesco Andreuzzi Date: Wed, 20 Aug 2025 17:16:38 +0000 Subject: [PATCH 08/54] 8360304: Redundant condition in LibraryCallKit::inline_vector_nary_operation Reviewed-by: shade, vlivanov --- src/hotspot/share/opto/vectorIntrinsics.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/opto/vectorIntrinsics.cpp b/src/hotspot/share/opto/vectorIntrinsics.cpp index 10430a09e72..43ca51fca67 100644 --- a/src/hotspot/share/opto/vectorIntrinsics.cpp +++ b/src/hotspot/share/opto/vectorIntrinsics.cpp @@ -383,7 +383,7 @@ bool LibraryCallKit::inline_vector_nary_operation(int n) { // When using mask, mask use type needs to be VecMaskUseLoad. VectorMaskUseType mask_use_type = is_vector_mask(vbox_klass) ? VecMaskUseAll : is_masked_op ? VecMaskUseLoad : VecMaskNotUsed; - if ((sopc != 0) && !arch_supports_vector(sopc, num_elem, elem_bt, mask_use_type)) { + if (!arch_supports_vector(sopc, num_elem, elem_bt, mask_use_type)) { log_if_needed(" ** not supported: arity=%d opc=%d vlen=%d etype=%s ismask=%d is_masked_op=%d", n, sopc, num_elem, type2name(elem_bt), is_vector_mask(vbox_klass) ? 1 : 0, is_masked_op ? 1 : 0); @@ -391,7 +391,7 @@ bool LibraryCallKit::inline_vector_nary_operation(int n) { } // Return true if current platform has implemented the masked operation with predicate feature. - bool use_predicate = is_masked_op && sopc != 0 && arch_supports_vector(sopc, num_elem, elem_bt, VecMaskUsePred); + bool use_predicate = is_masked_op && arch_supports_vector(sopc, num_elem, elem_bt, VecMaskUsePred); if (is_masked_op && !use_predicate && !arch_supports_vector(Op_VectorBlend, num_elem, elem_bt, VecMaskUseLoad)) { log_if_needed(" ** not supported: arity=%d opc=%d vlen=%d etype=%s ismask=0 is_masked_op=1", n, sopc, num_elem, type2name(elem_bt)); From ecab52c09b078201ebeb8d45c0982b0481e15dc3 Mon Sep 17 00:00:00 2001 From: Francesco Andreuzzi Date: Wed, 20 Aug 2025 17:21:22 +0000 Subject: [PATCH 09/54] 8365610: Sort share/jfr includes Reviewed-by: shade, mgronlun --- src/hotspot/share/jfr/dcmd/jfrDcmds.cpp | 2 +- .../instrumentation/jfrClassTransformer.cpp | 2 +- src/hotspot/share/jfr/jfr.cpp | 6 ++---- src/hotspot/share/jfr/jni/jfrJavaSupport.cpp | 5 ++--- src/hotspot/share/jfr/jni/jfrJniMethod.cpp | 20 +++++++++---------- .../jfr/leakprofiler/chains/bfsClosure.cpp | 2 +- .../jfr/leakprofiler/chains/edgeQueue.hpp | 2 +- .../chains/pathToGcRootsOperation.cpp | 6 ++---- .../leakprofiler/checkpoint/eventEmitter.hpp | 2 +- .../checkpoint/objectSampleCheckpoint.cpp | 2 +- .../checkpoint/objectSampleCheckpoint.hpp | 2 +- .../checkpoint/objectSampleWriter.cpp | 2 +- .../leakprofiler/checkpoint/rootResolver.cpp | 4 ++-- .../share/jfr/leakprofiler/leakProfiler.cpp | 4 ++-- .../leakprofiler/sampling/objectSampler.cpp | 4 ++-- .../share/jfr/metadata/jfrSerializer.hpp | 2 +- .../jfr/periodic/jfrNetworkUtilization.cpp | 2 +- .../share/jfr/periodic/jfrPeriodic.cpp | 6 +++--- .../jfr/periodic/jfrThreadCPULoadEvent.cpp | 4 ++-- .../sampling/jfrCPUTimeThreadSampler.cpp | 5 ++--- .../periodic/sampling/jfrThreadSampler.cpp | 4 ++-- .../recorder/checkpoint/jfrMetadataEvent.cpp | 2 +- .../checkpoint/types/jfrThreadState.cpp | 2 +- .../types/traceid/jfrTraceId.inline.hpp | 2 +- .../types/traceid/jfrTraceIdLoadBarrier.cpp | 2 +- .../share/jfr/recorder/jfrEventSetting.hpp | 2 +- .../share/jfr/recorder/jfrRecorder.cpp | 6 +++--- .../recorder/service/jfrEventThrottler.hpp | 2 +- .../recorder/service/jfrRecorderService.cpp | 8 ++++---- .../recorder/service/jfrRecorderThread.cpp | 2 +- .../service/jfrRecorderThreadLoop.cpp | 1 - .../stacktrace/jfrStackFilterRegistry.hpp | 2 +- .../share/jfr/recorder/storage/jfrStorage.cpp | 2 +- .../jfr/recorder/storage/jfrStorageUtils.hpp | 2 +- .../jfr/recorder/stringpool/jfrStringPool.cpp | 2 +- .../stringpool/jfrStringPoolWriter.hpp | 2 +- .../share/jfr/support/jfrAdaptiveSampler.cpp | 1 + .../support/jfrAnnotationElementIterator.hpp | 2 +- .../jfr/support/jfrDeprecationEventWriter.cpp | 2 +- .../jfr/support/jfrDeprecationEventWriter.hpp | 2 +- .../jfr/support/jfrDeprecationManager.cpp | 7 +++---- .../jfr/support/jfrDeprecationManager.hpp | 2 +- src/hotspot/share/jfr/support/jfrFlush.cpp | 2 +- .../share/jfr/support/jfrResolution.cpp | 3 +-- .../share/jfr/support/jfrStackTraceMark.hpp | 4 ++-- .../methodtracer/jfrClassFilterClosure.hpp | 4 ++-- .../jfr/support/methodtracer/jfrFilter.hpp | 2 +- .../support/methodtracer/jfrFilterManager.hpp | 2 +- .../support/methodtracer/jfrMethodTracer.hpp | 2 +- .../jfr/utilities/jfrEpochQueue.inline.hpp | 1 + src/hotspot/share/jfr/utilities/jfrSet.hpp | 2 +- .../share/jfr/utilities/jfrTimeConverter.cpp | 2 +- .../share/jfr/utilities/jfrTryLock.hpp | 2 +- .../writers/jfrStreamWriterHost.inline.hpp | 3 ++- .../jtreg/sources/TestIncludesAreSorted.java | 1 + 55 files changed, 84 insertions(+), 89 deletions(-) diff --git a/src/hotspot/share/jfr/dcmd/jfrDcmds.cpp b/src/hotspot/share/jfr/dcmd/jfrDcmds.cpp index e7ba0e8f7ca..d18136e1570 100644 --- a/src/hotspot/share/jfr/dcmd/jfrDcmds.cpp +++ b/src/hotspot/share/jfr/dcmd/jfrDcmds.cpp @@ -24,8 +24,8 @@ #include "classfile/javaClasses.inline.hpp" #include "classfile/vmSymbols.hpp" -#include "jfr/jfr.hpp" #include "jfr/dcmd/jfrDcmds.hpp" +#include "jfr/jfr.hpp" #include "jfr/jni/jfrJavaSupport.hpp" #include "jfr/recorder/jfrRecorder.hpp" #include "jfr/recorder/service/jfrOptionSet.hpp" diff --git a/src/hotspot/share/jfr/instrumentation/jfrClassTransformer.cpp b/src/hotspot/share/jfr/instrumentation/jfrClassTransformer.cpp index b9bedff0f9d..aa3b14e32f1 100644 --- a/src/hotspot/share/jfr/instrumentation/jfrClassTransformer.cpp +++ b/src/hotspot/share/jfr/instrumentation/jfrClassTransformer.cpp @@ -28,8 +28,8 @@ #include "classfile/javaClasses.inline.hpp" #include "classfile/symbolTable.hpp" #include "jfr/instrumentation/jfrClassTransformer.hpp" -#include "jfr/recorder/service/jfrOptionSet.hpp" #include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp" +#include "jfr/recorder/service/jfrOptionSet.hpp" #include "logging/log.hpp" #include "memory/allocation.inline.hpp" #include "memory/resourceArea.hpp" diff --git a/src/hotspot/share/jfr/jfr.cpp b/src/hotspot/share/jfr/jfr.cpp index a273df61922..7abf5c89945 100644 --- a/src/hotspot/share/jfr/jfr.cpp +++ b/src/hotspot/share/jfr/jfr.cpp @@ -26,18 +26,16 @@ #include "jfr/jfr.hpp" #include "jfr/jni/jfrJavaSupport.hpp" #include "jfr/leakprofiler/leakProfiler.hpp" -#include "jfr/recorder/jfrRecorder.hpp" #include "jfr/recorder/checkpoint/jfrCheckpointManager.hpp" +#include "jfr/recorder/jfrRecorder.hpp" #include "jfr/recorder/repository/jfrEmergencyDump.hpp" -#include "jfr/recorder/service/jfrOptionSet.hpp" -#include "jfr/recorder/service/jfrOptionSet.hpp" #include "jfr/recorder/repository/jfrRepository.hpp" +#include "jfr/recorder/service/jfrOptionSet.hpp" #include "jfr/support/jfrKlassExtension.hpp" #include "jfr/support/jfrResolution.hpp" #include "jfr/support/jfrThreadLocal.hpp" #include "jfr/support/methodtracer/jfrMethodTracer.hpp" #include "jfr/support/methodtracer/jfrTraceTagging.hpp" -#include "oops/instanceKlass.hpp" #include "oops/instanceKlass.inline.hpp" #include "oops/klass.hpp" #include "runtime/java.hpp" diff --git a/src/hotspot/share/jfr/jni/jfrJavaSupport.cpp b/src/hotspot/share/jfr/jni/jfrJavaSupport.cpp index 3b566868f07..59a9d8a9090 100644 --- a/src/hotspot/share/jfr/jni/jfrJavaSupport.cpp +++ b/src/hotspot/share/jfr/jni/jfrJavaSupport.cpp @@ -39,11 +39,11 @@ #include "memory/resourceArea.hpp" #include "oops/instanceOop.hpp" #include "oops/klass.inline.hpp" -#include "oops/oop.inline.hpp" #include "oops/objArrayKlass.hpp" #include "oops/objArrayOop.inline.hpp" -#include "runtime/handles.inline.hpp" +#include "oops/oop.inline.hpp" #include "runtime/fieldDescriptor.inline.hpp" +#include "runtime/handles.inline.hpp" #include "runtime/java.hpp" #include "runtime/javaCalls.hpp" #include "runtime/javaThread.hpp" @@ -52,7 +52,6 @@ #include "runtime/synchronizer.hpp" #include "runtime/threadSMR.hpp" #include "utilities/growableArray.hpp" -#include "classfile/vmSymbols.hpp" #ifdef ASSERT static void check_java_thread_state(JavaThread* t, JavaThreadState state) { diff --git a/src/hotspot/share/jfr/jni/jfrJniMethod.cpp b/src/hotspot/share/jfr/jni/jfrJniMethod.cpp index a09da529b1b..1d1f3a62866 100644 --- a/src/hotspot/share/jfr/jni/jfrJniMethod.cpp +++ b/src/hotspot/share/jfr/jni/jfrJniMethod.cpp @@ -22,19 +22,24 @@ * */ +#include "jfr/instrumentation/jfrEventClassTransformer.hpp" +#include "jfr/instrumentation/jfrJvmtiAgent.hpp" #include "jfr/jfr.hpp" #include "jfr/jfrEvents.hpp" +#include "jfr/jni/jfrJavaSupport.hpp" +#include "jfr/jni/jfrJniMethodRegistration.hpp" +#include "jfr/leakprofiler/leakProfiler.hpp" #include "jfr/periodic/sampling/jfrCPUTimeThreadSampler.hpp" #include "jfr/periodic/sampling/jfrThreadSampler.hpp" -#include "jfr/recorder/jfrEventSetting.hpp" -#include "jfr/recorder/jfrRecorder.hpp" #include "jfr/recorder/checkpoint/jfrMetadataEvent.hpp" #include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp" +#include "jfr/recorder/jfrEventSetting.hpp" +#include "jfr/recorder/jfrRecorder.hpp" #include "jfr/recorder/repository/jfrChunk.hpp" -#include "jfr/recorder/repository/jfrRepository.hpp" #include "jfr/recorder/repository/jfrChunkRotation.hpp" #include "jfr/recorder/repository/jfrChunkWriter.hpp" #include "jfr/recorder/repository/jfrEmergencyDump.hpp" +#include "jfr/recorder/repository/jfrRepository.hpp" #include "jfr/recorder/service/jfrEventThrottler.hpp" #include "jfr/recorder/service/jfrOptionSet.hpp" #include "jfr/recorder/service/jfrRecorderService.hpp" @@ -42,18 +47,13 @@ #include "jfr/recorder/stacktrace/jfrStackFilterRegistry.hpp" #include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp" #include "jfr/recorder/stringpool/jfrStringPool.hpp" -#include "jfr/jni/jfrJavaSupport.hpp" -#include "jfr/jni/jfrJniMethodRegistration.hpp" -#include "jfr/instrumentation/jfrEventClassTransformer.hpp" -#include "jfr/instrumentation/jfrJvmtiAgent.hpp" -#include "jfr/leakprofiler/leakProfiler.hpp" #include "jfr/support/jfrDeprecationManager.hpp" #include "jfr/support/jfrJdkJfrEvent.hpp" #include "jfr/support/jfrKlassUnloading.hpp" #include "jfr/support/methodtracer/jfrMethodTracer.hpp" #include "jfr/utilities/jfrJavaLog.hpp" -#include "jfr/utilities/jfrTimeConverter.hpp" #include "jfr/utilities/jfrTime.hpp" +#include "jfr/utilities/jfrTimeConverter.hpp" #include "jfr/writers/jfrJavaEventWriter.hpp" #include "jfrfiles/jfrPeriodic.hpp" #include "jfrfiles/jfrTypes.hpp" @@ -67,8 +67,8 @@ #include "runtime/os.hpp" #include "utilities/debug.hpp" #ifdef LINUX -#include "osContainer_linux.hpp" #include "os_linux.hpp" +#include "osContainer_linux.hpp" #endif #define NO_TRANSITION(result_type, header) extern "C" { result_type JNICALL header { diff --git a/src/hotspot/share/jfr/leakprofiler/chains/bfsClosure.cpp b/src/hotspot/share/jfr/leakprofiler/chains/bfsClosure.cpp index 45fd4a7dc57..5bdddc4fd68 100644 --- a/src/hotspot/share/jfr/leakprofiler/chains/bfsClosure.cpp +++ b/src/hotspot/share/jfr/leakprofiler/chains/bfsClosure.cpp @@ -24,8 +24,8 @@ #include "jfr/leakprofiler/chains/bfsClosure.hpp" #include "jfr/leakprofiler/chains/dfsClosure.hpp" #include "jfr/leakprofiler/chains/edge.hpp" -#include "jfr/leakprofiler/chains/edgeStore.hpp" #include "jfr/leakprofiler/chains/edgeQueue.hpp" +#include "jfr/leakprofiler/chains/edgeStore.hpp" #include "jfr/leakprofiler/chains/jfrbitset.hpp" #include "jfr/leakprofiler/utilities/granularTimer.hpp" #include "jfr/leakprofiler/utilities/unifiedOopRef.inline.hpp" diff --git a/src/hotspot/share/jfr/leakprofiler/chains/edgeQueue.hpp b/src/hotspot/share/jfr/leakprofiler/chains/edgeQueue.hpp index 774bd10d353..18cee5de7f2 100644 --- a/src/hotspot/share/jfr/leakprofiler/chains/edgeQueue.hpp +++ b/src/hotspot/share/jfr/leakprofiler/chains/edgeQueue.hpp @@ -25,9 +25,9 @@ #ifndef SHARE_JFR_LEAKPROFILER_CHAINS_EDGEQUEUE_HPP #define SHARE_JFR_LEAKPROFILER_CHAINS_EDGEQUEUE_HPP -#include "memory/allocation.hpp" #include "jfr/leakprofiler/chains/edge.hpp" #include "jfr/leakprofiler/utilities/unifiedOopRef.hpp" +#include "memory/allocation.hpp" class JfrVirtualMemory; diff --git a/src/hotspot/share/jfr/leakprofiler/chains/pathToGcRootsOperation.cpp b/src/hotspot/share/jfr/leakprofiler/chains/pathToGcRootsOperation.cpp index ca7650d6876..83dc71f3827 100644 --- a/src/hotspot/share/jfr/leakprofiler/chains/pathToGcRootsOperation.cpp +++ b/src/hotspot/share/jfr/leakprofiler/chains/pathToGcRootsOperation.cpp @@ -24,7 +24,6 @@ #include "gc/shared/collectedHeap.hpp" #include "gc/shared/gc_globals.hpp" -#include "jfr/leakprofiler/leakProfiler.hpp" #include "jfr/leakprofiler/chains/bfsClosure.hpp" #include "jfr/leakprofiler/chains/dfsClosure.hpp" #include "jfr/leakprofiler/chains/edge.hpp" @@ -32,12 +31,11 @@ #include "jfr/leakprofiler/chains/edgeStore.hpp" #include "jfr/leakprofiler/chains/jfrbitset.hpp" #include "jfr/leakprofiler/chains/objectSampleMarker.hpp" -#include "jfr/leakprofiler/chains/rootSetClosure.hpp" -#include "jfr/leakprofiler/chains/edgeStore.hpp" -#include "jfr/leakprofiler/chains/objectSampleMarker.hpp" #include "jfr/leakprofiler/chains/pathToGcRootsOperation.hpp" +#include "jfr/leakprofiler/chains/rootSetClosure.hpp" #include "jfr/leakprofiler/checkpoint/eventEmitter.hpp" #include "jfr/leakprofiler/checkpoint/objectSampleCheckpoint.hpp" +#include "jfr/leakprofiler/leakProfiler.hpp" #include "jfr/leakprofiler/sampling/objectSample.hpp" #include "jfr/leakprofiler/sampling/objectSampler.hpp" #include "jfr/leakprofiler/utilities/granularTimer.hpp" diff --git a/src/hotspot/share/jfr/leakprofiler/checkpoint/eventEmitter.hpp b/src/hotspot/share/jfr/leakprofiler/checkpoint/eventEmitter.hpp index 1d40c001c43..3965d0c0ff7 100644 --- a/src/hotspot/share/jfr/leakprofiler/checkpoint/eventEmitter.hpp +++ b/src/hotspot/share/jfr/leakprofiler/checkpoint/eventEmitter.hpp @@ -25,8 +25,8 @@ #ifndef SHARE_JFR_LEAKPROFILER_CHECKPOINT_EVENTEMITTER_HPP #define SHARE_JFR_LEAKPROFILER_CHECKPOINT_EVENTEMITTER_HPP -#include "memory/allocation.hpp" #include "jfr/utilities/jfrTime.hpp" +#include "memory/allocation.hpp" typedef u8 traceid; diff --git a/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.cpp b/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.cpp index 300786daf05..d8834e65b60 100644 --- a/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.cpp +++ b/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.cpp @@ -39,8 +39,8 @@ #include "jfr/support/jfrKlassUnloading.hpp" #include "jfr/support/jfrMethodLookup.hpp" #include "jfr/utilities/jfrHashtable.hpp" -#include "jfr/utilities/jfrSet.hpp" #include "jfr/utilities/jfrRelation.hpp" +#include "jfr/utilities/jfrSet.hpp" #include "memory/resourceArea.inline.hpp" #include "oops/instanceKlass.inline.hpp" #include "runtime/interfaceSupport.inline.hpp" diff --git a/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.hpp b/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.hpp index 2ab2e12302f..63e251d3b67 100644 --- a/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.hpp +++ b/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.hpp @@ -25,8 +25,8 @@ #ifndef SHARE_JFR_LEAKPROFILER_CHECKPOINT_OBJECTSAMPLECHECKPOINT_HPP #define SHARE_JFR_LEAKPROFILER_CHECKPOINT_OBJECTSAMPLECHECKPOINT_HPP -#include "memory/allStatic.hpp" #include "jfr/utilities/jfrTypes.hpp" +#include "memory/allStatic.hpp" class EdgeStore; class InstanceKlass; diff --git a/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleWriter.cpp b/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleWriter.cpp index ff1f9efd017..5b7ee3ddb3d 100644 --- a/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleWriter.cpp +++ b/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleWriter.cpp @@ -22,7 +22,6 @@ * */ -#include "jfrfiles/jfrTypes.hpp" #include "jfr/leakprofiler/chains/edge.hpp" #include "jfr/leakprofiler/chains/edgeStore.hpp" #include "jfr/leakprofiler/chains/edgeUtils.hpp" @@ -34,6 +33,7 @@ #include "jfr/leakprofiler/utilities/unifiedOopRef.inline.hpp" #include "jfr/metadata/jfrSerializer.hpp" #include "jfr/writers/jfrTypeWriterHost.hpp" +#include "jfrfiles/jfrTypes.hpp" #include "oops/oop.inline.hpp" #include "oops/symbol.hpp" #include "utilities/growableArray.hpp" diff --git a/src/hotspot/share/jfr/leakprofiler/checkpoint/rootResolver.cpp b/src/hotspot/share/jfr/leakprofiler/checkpoint/rootResolver.cpp index cf94293f0a3..4d7ccba5262 100644 --- a/src/hotspot/share/jfr/leakprofiler/checkpoint/rootResolver.cpp +++ b/src/hotspot/share/jfr/leakprofiler/checkpoint/rootResolver.cpp @@ -27,13 +27,13 @@ #include "gc/shared/oopStorage.inline.hpp" #include "gc/shared/oopStorageSet.hpp" #include "gc/shared/strongRootsScope.hpp" -#include "jfr/leakprofiler/utilities/unifiedOopRef.inline.hpp" #include "jfr/leakprofiler/checkpoint/rootResolver.hpp" +#include "jfr/leakprofiler/utilities/unifiedOopRef.inline.hpp" #include "jfr/utilities/jfrThreadIterator.hpp" #include "memory/iterator.hpp" -#include "prims/jvmtiDeferredUpdates.hpp" #include "oops/klass.hpp" #include "oops/oop.hpp" +#include "prims/jvmtiDeferredUpdates.hpp" #include "prims/jvmtiThreadState.hpp" #include "runtime/frame.inline.hpp" #include "runtime/jniHandles.hpp" diff --git a/src/hotspot/share/jfr/leakprofiler/leakProfiler.cpp b/src/hotspot/share/jfr/leakprofiler/leakProfiler.cpp index a5b4babb2b1..e8ad79783c0 100644 --- a/src/hotspot/share/jfr/leakprofiler/leakProfiler.cpp +++ b/src/hotspot/share/jfr/leakprofiler/leakProfiler.cpp @@ -22,11 +22,11 @@ * */ +#include "jfr/leakprofiler/checkpoint/eventEmitter.hpp" #include "jfr/leakprofiler/leakProfiler.hpp" +#include "jfr/leakprofiler/sampling/objectSampler.hpp" #include "jfr/leakprofiler/startOperation.hpp" #include "jfr/leakprofiler/stopOperation.hpp" -#include "jfr/leakprofiler/checkpoint/eventEmitter.hpp" -#include "jfr/leakprofiler/sampling/objectSampler.hpp" #include "jfr/recorder/service/jfrOptionSet.hpp" #include "logging/log.hpp" #include "memory/iterator.hpp" diff --git a/src/hotspot/share/jfr/leakprofiler/sampling/objectSampler.cpp b/src/hotspot/share/jfr/leakprofiler/sampling/objectSampler.cpp index 86b8712698b..83873e2e500 100644 --- a/src/hotspot/share/jfr/leakprofiler/sampling/objectSampler.cpp +++ b/src/hotspot/share/jfr/leakprofiler/sampling/objectSampler.cpp @@ -31,11 +31,11 @@ #include "jfr/leakprofiler/sampling/objectSampler.hpp" #include "jfr/leakprofiler/sampling/sampleList.hpp" #include "jfr/leakprofiler/sampling/samplePriorityQueue.hpp" -#include "jfr/recorder/jfrEventSetting.inline.hpp" #include "jfr/recorder/checkpoint/jfrCheckpointManager.hpp" +#include "jfr/recorder/jfrEventSetting.inline.hpp" #include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp" -#include "jfr/utilities/jfrSignal.hpp" #include "jfr/support/jfrThreadLocal.hpp" +#include "jfr/utilities/jfrSignal.hpp" #include "jfr/utilities/jfrTime.hpp" #include "jfr/utilities/jfrTryLock.hpp" #include "logging/log.hpp" diff --git a/src/hotspot/share/jfr/metadata/jfrSerializer.hpp b/src/hotspot/share/jfr/metadata/jfrSerializer.hpp index 57ae3554b0d..34ea94acbe8 100644 --- a/src/hotspot/share/jfr/metadata/jfrSerializer.hpp +++ b/src/hotspot/share/jfr/metadata/jfrSerializer.hpp @@ -25,9 +25,9 @@ #ifndef SHARE_JFR_METADATA_JFRSERIALIZER_HPP #define SHARE_JFR_METADATA_JFRSERIALIZER_HPP -#include "memory/allocation.hpp" #include "jfr/recorder/checkpoint/jfrCheckpointWriter.hpp" #include "jfrfiles/jfrTypes.hpp" +#include "memory/allocation.hpp" /* * A "type" in Jfr is a binary relation defined by enumerating a set of ordered pairs: diff --git a/src/hotspot/share/jfr/periodic/jfrNetworkUtilization.cpp b/src/hotspot/share/jfr/periodic/jfrNetworkUtilization.cpp index c18248e1056..11e211f6505 100644 --- a/src/hotspot/share/jfr/periodic/jfrNetworkUtilization.cpp +++ b/src/hotspot/share/jfr/periodic/jfrNetworkUtilization.cpp @@ -22,13 +22,13 @@ * */ -#include "logging/log.hpp" #include "jfr/jfrEvents.hpp" #include "jfr/metadata/jfrSerializer.hpp" #include "jfr/periodic/jfrNetworkUtilization.hpp" #include "jfr/periodic/jfrOSInterface.hpp" #include "jfr/utilities/jfrTime.hpp" #include "jfr/utilities/jfrTypes.hpp" +#include "logging/log.hpp" #include "runtime/os_perf.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/growableArray.hpp" diff --git a/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp index 0be1c32728c..49669d1675d 100644 --- a/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp +++ b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp @@ -38,11 +38,11 @@ #include "jfr/periodic/jfrCompilerQueueUtilization.hpp" #include "jfr/periodic/jfrFinalizerStatisticsEvent.hpp" #include "jfr/periodic/jfrModuleEvent.hpp" +#include "jfr/periodic/jfrNativeMemoryEvent.hpp" +#include "jfr/periodic/jfrNetworkUtilization.hpp" #include "jfr/periodic/jfrOSInterface.hpp" #include "jfr/periodic/jfrThreadCPULoadEvent.hpp" #include "jfr/periodic/jfrThreadDumpEvent.hpp" -#include "jfr/periodic/jfrNativeMemoryEvent.hpp" -#include "jfr/periodic/jfrNetworkUtilization.hpp" #include "jfr/recorder/jfrRecorder.hpp" #include "jfr/utilities/jfrThreadIterator.hpp" #include "jfr/utilities/jfrTime.hpp" @@ -61,8 +61,8 @@ #include "runtime/os_perf.hpp" #include "runtime/thread.inline.hpp" #include "runtime/threads.hpp" -#include "runtime/vmThread.hpp" #include "runtime/vm_version.hpp" +#include "runtime/vmThread.hpp" #include "services/classLoadingService.hpp" #include "services/management.hpp" #include "services/memoryPool.hpp" diff --git a/src/hotspot/share/jfr/periodic/jfrThreadCPULoadEvent.cpp b/src/hotspot/share/jfr/periodic/jfrThreadCPULoadEvent.cpp index 1863b1af800..e2c92af2fb3 100644 --- a/src/hotspot/share/jfr/periodic/jfrThreadCPULoadEvent.cpp +++ b/src/hotspot/share/jfr/periodic/jfrThreadCPULoadEvent.cpp @@ -22,14 +22,14 @@ * */ -#include "logging/log.hpp" #include "jfr/jfrEvents.hpp" #include "jfr/periodic/jfrThreadCPULoadEvent.hpp" #include "jfr/utilities/jfrThreadIterator.hpp" #include "jfr/utilities/jfrTime.hpp" -#include "utilities/globalDefinitions.hpp" +#include "logging/log.hpp" #include "runtime/javaThread.hpp" #include "runtime/os.hpp" +#include "utilities/globalDefinitions.hpp" jlong JfrThreadCPULoadEvent::get_wallclock_time() { return os::javaTimeNanos(); diff --git a/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.cpp b/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.cpp index 2793a1fb984..db3ca758cc1 100644 --- a/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.cpp +++ b/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.cpp @@ -29,8 +29,8 @@ #if defined(LINUX) #include "jfr/periodic/sampling/jfrThreadSampling.hpp" #include "jfr/support/jfrThreadLocal.hpp" -#include "jfr/utilities/jfrTime.hpp" #include "jfr/utilities/jfrThreadIterator.hpp" +#include "jfr/utilities/jfrTime.hpp" #include "jfr/utilities/jfrTypes.hpp" #include "jfrfiles/jfrEventClasses.hpp" #include "memory/resourceArea.hpp" @@ -41,9 +41,8 @@ #include "runtime/threadSMR.hpp" #include "runtime/vmOperation.hpp" #include "runtime/vmThread.hpp" -#include "utilities/ticks.hpp" - #include "signals_posix.hpp" +#include "utilities/ticks.hpp" static const int64_t RECOMPUTE_INTERVAL_MS = 100; diff --git a/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp b/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp index 4c44c43772d..6347abd654f 100644 --- a/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp +++ b/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp @@ -23,11 +23,11 @@ */ #include "jfr/metadata/jfrSerializer.hpp" -#include "jfr/recorder/service/jfrOptionSet.hpp" #include "jfr/periodic/sampling/jfrSampleMonitor.hpp" #include "jfr/periodic/sampling/jfrSampleRequest.hpp" -#include "jfr/periodic/sampling/jfrThreadSampling.hpp" #include "jfr/periodic/sampling/jfrThreadSampler.hpp" +#include "jfr/periodic/sampling/jfrThreadSampling.hpp" +#include "jfr/recorder/service/jfrOptionSet.hpp" #include "jfr/utilities/jfrTime.hpp" #include "jfr/utilities/jfrTryLock.hpp" #include "jfr/utilities/jfrTypes.hpp" diff --git a/src/hotspot/share/jfr/recorder/checkpoint/jfrMetadataEvent.cpp b/src/hotspot/share/jfr/recorder/checkpoint/jfrMetadataEvent.cpp index 20e9c1e6798..937a0ca58c7 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/jfrMetadataEvent.cpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/jfrMetadataEvent.cpp @@ -25,8 +25,8 @@ #include "jfr/jni/jfrJavaSupport.hpp" #include "jfr/jni/jfrUpcalls.hpp" #include "jfr/recorder/checkpoint/jfrMetadataEvent.hpp" -#include "jfr/recorder/repository/jfrChunkWriter.hpp" #include "jfr/recorder/jfrEventSetting.inline.hpp" +#include "jfr/recorder/repository/jfrChunkWriter.hpp" #include "oops/klass.inline.hpp" #include "oops/oop.inline.hpp" #include "oops/typeArrayOop.inline.hpp" diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrThreadState.cpp b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrThreadState.cpp index cdd7adebe4f..ed7e7d8195e 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrThreadState.cpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrThreadState.cpp @@ -23,8 +23,8 @@ */ #include "classfile/javaClasses.inline.hpp" -#include "jfr/recorder/checkpoint/types/jfrThreadState.hpp" #include "jfr/recorder/checkpoint/jfrCheckpointWriter.hpp" +#include "jfr/recorder/checkpoint/types/jfrThreadState.hpp" #include "jfr/support/jfrThreadLocal.hpp" #include "jvmtifiles/jvmti.h" #include "runtime/javaThread.hpp" diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp index 03647bdeae2..2af1080820f 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp @@ -27,9 +27,9 @@ #include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.hpp" -#include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdLoadBarrier.inline.hpp" #include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdBits.inline.hpp" #include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdEpoch.hpp" +#include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdLoadBarrier.inline.hpp" #include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdMacros.hpp" #include "jfr/support/jfrKlassExtension.hpp" #include "oops/instanceKlass.hpp" diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdLoadBarrier.cpp b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdLoadBarrier.cpp index 8f600431333..12a73fd76c5 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdLoadBarrier.cpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdLoadBarrier.cpp @@ -22,8 +22,8 @@ * */ -#include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdLoadBarrier.inline.hpp" #include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdKlassQueue.hpp" +#include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdLoadBarrier.inline.hpp" #include "jfr/recorder/service/jfrOptionSet.hpp" #include "jfr/support/jfrThreadLocal.hpp" #include "jfr/utilities/jfrEpochQueue.inline.hpp" diff --git a/src/hotspot/share/jfr/recorder/jfrEventSetting.hpp b/src/hotspot/share/jfr/recorder/jfrEventSetting.hpp index e935dff3b27..3b2888bf505 100644 --- a/src/hotspot/share/jfr/recorder/jfrEventSetting.hpp +++ b/src/hotspot/share/jfr/recorder/jfrEventSetting.hpp @@ -25,9 +25,9 @@ #ifndef SHARE_JFR_RECORDER_JFREVENTSETTING_HPP #define SHARE_JFR_RECORDER_JFREVENTSETTING_HPP -#include "jni.h" #include "jfr/utilities/jfrAllocation.hpp" #include "jfrfiles/jfrEventControl.hpp" +#include "jni.h" // // Native event settings as an associative array using the event id as key. diff --git a/src/hotspot/share/jfr/recorder/jfrRecorder.cpp b/src/hotspot/share/jfr/recorder/jfrRecorder.cpp index 4ef278ab522..f5214ff7942 100644 --- a/src/hotspot/share/jfr/recorder/jfrRecorder.cpp +++ b/src/hotspot/share/jfr/recorder/jfrRecorder.cpp @@ -31,17 +31,17 @@ #include "jfr/periodic/jfrOSInterface.hpp" #include "jfr/periodic/sampling/jfrCPUTimeThreadSampler.hpp" #include "jfr/periodic/sampling/jfrThreadSampler.hpp" -#include "jfr/recorder/jfrRecorder.hpp" #include "jfr/recorder/checkpoint/jfrCheckpointManager.hpp" #include "jfr/recorder/checkpoint/types/jfrThreadGroupManager.hpp" +#include "jfr/recorder/jfrRecorder.hpp" #include "jfr/recorder/repository/jfrRepository.hpp" #include "jfr/recorder/service/jfrEventThrottler.hpp" #include "jfr/recorder/service/jfrOptionSet.hpp" #include "jfr/recorder/service/jfrPostBox.hpp" #include "jfr/recorder/service/jfrRecorderService.hpp" #include "jfr/recorder/service/jfrRecorderThread.hpp" -#include "jfr/recorder/storage/jfrStorage.hpp" #include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp" +#include "jfr/recorder/storage/jfrStorage.hpp" #include "jfr/recorder/stringpool/jfrStringPool.hpp" #include "jfr/support/jfrThreadLocal.hpp" #include "jfr/utilities/jfrTime.hpp" @@ -49,8 +49,8 @@ #include "logging/log.hpp" #include "logging/logStream.hpp" #include "memory/resourceArea.inline.hpp" -#include "runtime/handles.inline.hpp" #include "runtime/globals_extension.hpp" +#include "runtime/handles.inline.hpp" #include "utilities/growableArray.hpp" #ifdef ASSERT #include "prims/jvmtiEnvBase.hpp" diff --git a/src/hotspot/share/jfr/recorder/service/jfrEventThrottler.hpp b/src/hotspot/share/jfr/recorder/service/jfrEventThrottler.hpp index b3c56183630..be6f8127205 100644 --- a/src/hotspot/share/jfr/recorder/service/jfrEventThrottler.hpp +++ b/src/hotspot/share/jfr/recorder/service/jfrEventThrottler.hpp @@ -26,8 +26,8 @@ #ifndef SHARE_JFR_RECORDER_SERVICE_JFREVENTTHROTTLER_HPP #define SHARE_JFR_RECORDER_SERVICE_JFREVENTTHROTTLER_HPP -#include "jfrfiles/jfrEventIds.hpp" #include "jfr/support/jfrAdaptiveSampler.hpp" +#include "jfrfiles/jfrEventIds.hpp" class JfrEventThrottler : public JfrAdaptiveSampler { friend class JfrRecorder; diff --git a/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp b/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp index 7784148aee5..e8a3ea935de 100644 --- a/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp +++ b/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp @@ -22,14 +22,13 @@ * */ -#include "jfrfiles/jfrEventClasses.hpp" #include "jfr/jni/jfrJavaSupport.hpp" -#include "jfr/leakprofiler/leakProfiler.hpp" #include "jfr/leakprofiler/checkpoint/objectSampleCheckpoint.hpp" +#include "jfr/leakprofiler/leakProfiler.hpp" #include "jfr/leakprofiler/sampling/objectSampler.hpp" -#include "jfr/recorder/jfrRecorder.hpp" #include "jfr/recorder/checkpoint/jfrCheckpointManager.hpp" #include "jfr/recorder/checkpoint/jfrMetadataEvent.hpp" +#include "jfr/recorder/jfrRecorder.hpp" #include "jfr/recorder/repository/jfrChunkRotation.hpp" #include "jfr/recorder/repository/jfrChunkWriter.hpp" #include "jfr/recorder/repository/jfrRepository.hpp" @@ -43,8 +42,9 @@ #include "jfr/utilities/jfrAllocation.hpp" #include "jfr/utilities/jfrThreadIterator.hpp" #include "jfr/utilities/jfrTime.hpp" -#include "jfr/writers/jfrJavaEventWriter.hpp" #include "jfr/utilities/jfrTypes.hpp" +#include "jfr/writers/jfrJavaEventWriter.hpp" +#include "jfrfiles/jfrEventClasses.hpp" #include "logging/log.hpp" #include "runtime/atomic.hpp" #include "runtime/interfaceSupport.inline.hpp" diff --git a/src/hotspot/share/jfr/recorder/service/jfrRecorderThread.cpp b/src/hotspot/share/jfr/recorder/service/jfrRecorderThread.cpp index aa594ea6d1f..a63a55386a0 100644 --- a/src/hotspot/share/jfr/recorder/service/jfrRecorderThread.cpp +++ b/src/hotspot/share/jfr/recorder/service/jfrRecorderThread.cpp @@ -33,8 +33,8 @@ #include "memory/universe.hpp" #include "runtime/handles.inline.hpp" #include "runtime/javaThread.hpp" -#include "utilities/preserveException.hpp" #include "utilities/macros.hpp" +#include "utilities/preserveException.hpp" static Thread* start_thread(instanceHandle thread_oop, ThreadFunction proc, TRAPS) { assert(thread_oop.not_null(), "invariant"); diff --git a/src/hotspot/share/jfr/recorder/service/jfrRecorderThreadLoop.cpp b/src/hotspot/share/jfr/recorder/service/jfrRecorderThreadLoop.cpp index 8aeb745b35e..de015e9a502 100644 --- a/src/hotspot/share/jfr/recorder/service/jfrRecorderThreadLoop.cpp +++ b/src/hotspot/share/jfr/recorder/service/jfrRecorderThreadLoop.cpp @@ -27,7 +27,6 @@ #include "jfr/recorder/service/jfrPostBox.hpp" #include "jfr/recorder/service/jfrRecorderService.hpp" #include "jfr/recorder/service/jfrRecorderThread.hpp" -#include "jfr/recorder/jfrRecorder.hpp" #include "logging/log.hpp" #include "runtime/handles.hpp" #include "runtime/interfaceSupport.inline.hpp" diff --git a/src/hotspot/share/jfr/recorder/stacktrace/jfrStackFilterRegistry.hpp b/src/hotspot/share/jfr/recorder/stacktrace/jfrStackFilterRegistry.hpp index e35fb90938f..a3564506924 100644 --- a/src/hotspot/share/jfr/recorder/stacktrace/jfrStackFilterRegistry.hpp +++ b/src/hotspot/share/jfr/recorder/stacktrace/jfrStackFilterRegistry.hpp @@ -25,8 +25,8 @@ #ifndef SHARE_JFR_RECORDER_STACKTRACE_JFRSTCKFILTERREGISTRY_HPP #define SHARE_JFR_RECORDER_STACKTRACE_JFRSTCKFILTERREGISTRY_HPP -#include "jni.h" #include "jfr/utilities/jfrAllocation.hpp" +#include "jni.h" class JavaThread; class JfrStackFilter; diff --git a/src/hotspot/share/jfr/recorder/storage/jfrStorage.cpp b/src/hotspot/share/jfr/recorder/storage/jfrStorage.cpp index ca54b297b38..934d2ba9d28 100644 --- a/src/hotspot/share/jfr/recorder/storage/jfrStorage.cpp +++ b/src/hotspot/share/jfr/recorder/storage/jfrStorage.cpp @@ -24,8 +24,8 @@ #include "jfr/jfrEvents.hpp" #include "jfr/jni/jfrJavaSupport.hpp" -#include "jfr/recorder/jfrRecorder.hpp" #include "jfr/recorder/checkpoint/jfrCheckpointManager.hpp" +#include "jfr/recorder/jfrRecorder.hpp" #include "jfr/recorder/repository/jfrChunkWriter.hpp" #include "jfr/recorder/service/jfrOptionSet.hpp" #include "jfr/recorder/service/jfrPostBox.hpp" diff --git a/src/hotspot/share/jfr/recorder/storage/jfrStorageUtils.hpp b/src/hotspot/share/jfr/recorder/storage/jfrStorageUtils.hpp index fdfd32d1f90..690a5730804 100644 --- a/src/hotspot/share/jfr/recorder/storage/jfrStorageUtils.hpp +++ b/src/hotspot/share/jfr/recorder/storage/jfrStorageUtils.hpp @@ -25,8 +25,8 @@ #ifndef SHARE_JFR_RECORDER_STORAGE_JFRSTORAGEUTILS_HPP #define SHARE_JFR_RECORDER_STORAGE_JFRSTORAGEUTILS_HPP -#include "jfr/recorder/storage/jfrBuffer.hpp" #include "jfr/recorder/repository/jfrChunkWriter.hpp" +#include "jfr/recorder/storage/jfrBuffer.hpp" #include "jfr/utilities/jfrAllocation.hpp" #include "jfr/utilities/jfrTypes.hpp" #include "runtime/javaThread.hpp" diff --git a/src/hotspot/share/jfr/recorder/stringpool/jfrStringPool.cpp b/src/hotspot/share/jfr/recorder/stringpool/jfrStringPool.cpp index dc28818b0f9..e1733b0ed5a 100644 --- a/src/hotspot/share/jfr/recorder/stringpool/jfrStringPool.cpp +++ b/src/hotspot/share/jfr/recorder/stringpool/jfrStringPool.cpp @@ -27,9 +27,9 @@ #include "classfile/systemDictionary.hpp" #include "classfile/vmSymbols.hpp" #include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdEpoch.hpp" +#include "jfr/recorder/repository/jfrChunkWriter.hpp" #include "jfr/recorder/service/jfrOptionSet.hpp" #include "jfr/recorder/storage/jfrMemorySpace.inline.hpp" -#include "jfr/recorder/repository/jfrChunkWriter.hpp" #include "jfr/recorder/storage/jfrStorageUtils.inline.hpp" #include "jfr/recorder/stringpool/jfrStringPool.hpp" #include "jfr/recorder/stringpool/jfrStringPoolWriter.hpp" diff --git a/src/hotspot/share/jfr/recorder/stringpool/jfrStringPoolWriter.hpp b/src/hotspot/share/jfr/recorder/stringpool/jfrStringPoolWriter.hpp index c91b6e585ce..5fc41550b66 100644 --- a/src/hotspot/share/jfr/recorder/stringpool/jfrStringPoolWriter.hpp +++ b/src/hotspot/share/jfr/recorder/stringpool/jfrStringPoolWriter.hpp @@ -25,11 +25,11 @@ #ifndef SHARE_JFR_RECORDER_STRINGPOOL_JFRSTRINGPOOLWRITER_HPP #define SHARE_JFR_RECORDER_STRINGPOOL_JFRSTRINGPOOLWRITER_HPP -#include "memory/allocation.hpp" #include "jfr/recorder/stringpool/jfrStringPoolBuffer.hpp" #include "jfr/writers/jfrEventWriterHost.hpp" #include "jfr/writers/jfrMemoryWriterHost.hpp" #include "jfr/writers/jfrStorageAdapter.hpp" +#include "memory/allocation.hpp" class Thread; diff --git a/src/hotspot/share/jfr/support/jfrAdaptiveSampler.cpp b/src/hotspot/share/jfr/support/jfrAdaptiveSampler.cpp index aa351a81ff3..769a6b4a3e8 100644 --- a/src/hotspot/share/jfr/support/jfrAdaptiveSampler.cpp +++ b/src/hotspot/share/jfr/support/jfrAdaptiveSampler.cpp @@ -32,6 +32,7 @@ #include "logging/log.hpp" #include "runtime/atomic.hpp" #include "utilities/globalDefinitions.hpp" + #include JfrSamplerWindow::JfrSamplerWindow() : diff --git a/src/hotspot/share/jfr/support/jfrAnnotationElementIterator.hpp b/src/hotspot/share/jfr/support/jfrAnnotationElementIterator.hpp index 9d8b35080fb..289f0ead2fe 100644 --- a/src/hotspot/share/jfr/support/jfrAnnotationElementIterator.hpp +++ b/src/hotspot/share/jfr/support/jfrAnnotationElementIterator.hpp @@ -26,8 +26,8 @@ #define SHARE_JFR_SUPPORT_JFRANNOTATIONELEMENTITERATOR_HPP #include "jni.h" -#include "utilities/globalDefinitions.hpp" #include "memory/allocation.hpp" +#include "utilities/globalDefinitions.hpp" class InstanceKlass; class Symbol; diff --git a/src/hotspot/share/jfr/support/jfrDeprecationEventWriter.cpp b/src/hotspot/share/jfr/support/jfrDeprecationEventWriter.cpp index 49b5e20e49a..7225dd60182 100644 --- a/src/hotspot/share/jfr/support/jfrDeprecationEventWriter.cpp +++ b/src/hotspot/share/jfr/support/jfrDeprecationEventWriter.cpp @@ -22,13 +22,13 @@ * */ -#include "jfrfiles/jfrEventIds.hpp" #include "jfr/recorder/checkpoint/jfrCheckpointWriter.hpp" #include "jfr/recorder/jfrEventSetting.inline.hpp" #include "jfr/recorder/repository/jfrChunkWriter.hpp" #include "jfr/support/jfrDeprecationEventWriter.hpp" #include "jfr/support/jfrDeprecationManager.hpp" #include "jfr/utilities/jfrTypes.hpp" +#include "jfrfiles/jfrEventIds.hpp" #include "runtime/thread.inline.hpp" // This dual state machine for the level setting is because when multiple recordings are running, diff --git a/src/hotspot/share/jfr/support/jfrDeprecationEventWriter.hpp b/src/hotspot/share/jfr/support/jfrDeprecationEventWriter.hpp index 1d73d4dc3a3..85a7ba51732 100644 --- a/src/hotspot/share/jfr/support/jfrDeprecationEventWriter.hpp +++ b/src/hotspot/share/jfr/support/jfrDeprecationEventWriter.hpp @@ -25,9 +25,9 @@ #ifndef SHARE_JFR_SUPPORT_JFRDEPRECATIONEVENTWRITER_HPP #define SHARE_JFR_SUPPORT_JFRDEPRECATIONEVENTWRITER_HPP -#include "memory/allocation.hpp" #include "jfr/utilities/jfrBlob.hpp" #include "jfr/utilities/jfrTime.hpp" +#include "memory/allocation.hpp" class JfrCheckpointWriter; class JfrChunkWriter; diff --git a/src/hotspot/share/jfr/support/jfrDeprecationManager.cpp b/src/hotspot/share/jfr/support/jfrDeprecationManager.cpp index 8fc35ca8dc1..5d2e180cae9 100644 --- a/src/hotspot/share/jfr/support/jfrDeprecationManager.cpp +++ b/src/hotspot/share/jfr/support/jfrDeprecationManager.cpp @@ -24,12 +24,11 @@ #include "classfile/moduleEntry.hpp" #include "interpreter/bytecodes.hpp" -#include "jfrfiles/jfrEventIds.hpp" #include "jfr/jni/jfrJavaSupport.hpp" -#include "jfr/recorder/jfrRecorder.hpp" -#include "jfr/recorder/jfrEventSetting.inline.hpp" #include "jfr/recorder/checkpoint/jfrCheckpointWriter.hpp" #include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp" +#include "jfr/recorder/jfrEventSetting.inline.hpp" +#include "jfr/recorder/jfrRecorder.hpp" #include "jfr/recorder/repository/jfrChunkWriter.hpp" #include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp" #include "jfr/recorder/storage/jfrReferenceCountedStorage.hpp" @@ -41,6 +40,7 @@ #include "jfr/utilities/jfrBlob.hpp" #include "jfr/utilities/jfrLinkedList.inline.hpp" #include "jfr/utilities/jfrTime.hpp" +#include "jfrfiles/jfrEventIds.hpp" #include "logging/log.hpp" #include "memory/resourceArea.inline.hpp" #include "oops/instanceKlass.inline.hpp" @@ -49,7 +49,6 @@ #include "runtime/interfaceSupport.inline.hpp" #include "runtime/thread.inline.hpp" -// for strstr #include static bool _enqueue_klasses = false; diff --git a/src/hotspot/share/jfr/support/jfrDeprecationManager.hpp b/src/hotspot/share/jfr/support/jfrDeprecationManager.hpp index d156679521a..86fe3cd35df 100644 --- a/src/hotspot/share/jfr/support/jfrDeprecationManager.hpp +++ b/src/hotspot/share/jfr/support/jfrDeprecationManager.hpp @@ -25,9 +25,9 @@ #ifndef SHARE_JFR_SUPPORT_JFRDEPRECATIONMANAGER_HPP #define SHARE_JFR_SUPPORT_JFRDEPRECATIONMANAGER_HPP -#include "memory/allocation.hpp" #include "jfr/utilities/jfrBlob.hpp" #include "jfr/utilities/jfrTypes.hpp" +#include "memory/allocation.hpp" class JavaThread; class JfrCheckpointWriter; diff --git a/src/hotspot/share/jfr/support/jfrFlush.cpp b/src/hotspot/share/jfr/support/jfrFlush.cpp index 0179cde3d4a..a8ad2f531fd 100644 --- a/src/hotspot/share/jfr/support/jfrFlush.cpp +++ b/src/hotspot/share/jfr/support/jfrFlush.cpp @@ -23,8 +23,8 @@ */ #include "jfr/recorder/jfrEventSetting.inline.hpp" -#include "jfr/recorder/storage/jfrStorage.hpp" #include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp" +#include "jfr/recorder/storage/jfrStorage.hpp" #include "jfr/support/jfrFlush.hpp" #include "jfr/support/jfrThreadLocal.hpp" #include "runtime/javaThread.hpp" diff --git a/src/hotspot/share/jfr/support/jfrResolution.cpp b/src/hotspot/share/jfr/support/jfrResolution.cpp index 4027de2fb3d..3a00d24d455 100644 --- a/src/hotspot/share/jfr/support/jfrResolution.cpp +++ b/src/hotspot/share/jfr/support/jfrResolution.cpp @@ -26,8 +26,8 @@ #include "ci/ciMethod.hpp" #include "classfile/vmSymbols.hpp" #include "interpreter/linkResolver.hpp" -#include "jfr/recorder/jfrRecorder.hpp" #include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdMacros.hpp" +#include "jfr/recorder/jfrRecorder.hpp" #include "jfr/recorder/stacktrace/jfrStackTrace.hpp" #include "jfr/support/jfrDeprecationManager.hpp" #include "jfr/support/jfrResolution.hpp" @@ -42,7 +42,6 @@ #include "opto/parse.hpp" #endif - // for strstr #include // The following packages are internal implmentation details used by reflection. diff --git a/src/hotspot/share/jfr/support/jfrStackTraceMark.hpp b/src/hotspot/share/jfr/support/jfrStackTraceMark.hpp index e56dc64e400..1429c48a278 100644 --- a/src/hotspot/share/jfr/support/jfrStackTraceMark.hpp +++ b/src/hotspot/share/jfr/support/jfrStackTraceMark.hpp @@ -25,9 +25,9 @@ #ifndef SHARE_JFR_SUPPORT_JFRSTACKTRACEMARK_HPP #define SHARE_JFR_SUPPORT_JFRSTACKTRACEMARK_HPP -#include "memory/allocation.hpp" -#include "jfrfiles/jfrEventIds.hpp" #include "jfr/utilities/jfrTypes.hpp" +#include "jfrfiles/jfrEventIds.hpp" +#include "memory/allocation.hpp" class Thread; diff --git a/src/hotspot/share/jfr/support/methodtracer/jfrClassFilterClosure.hpp b/src/hotspot/share/jfr/support/methodtracer/jfrClassFilterClosure.hpp index 6cf1b321f1e..2febb43ce3a 100644 --- a/src/hotspot/share/jfr/support/methodtracer/jfrClassFilterClosure.hpp +++ b/src/hotspot/share/jfr/support/methodtracer/jfrClassFilterClosure.hpp @@ -25,11 +25,11 @@ #ifndef SHARE_JFR_SUPPORT_METHODTRACER_JFRFILTERCLASSCLOSURE_HPP #define SHARE_JFR_SUPPORT_METHODTRACER_JFRFILTERCLASSCLOSURE_HPP -#include "jni.h" -#include "memory/iterator.hpp" #include "jfr/support/methodtracer/jfrInstrumentedClass.hpp" #include "jfr/utilities/jfrRelation.hpp" #include "jfr/utilities/jfrTypes.hpp" +#include "jni.h" +#include "memory/iterator.hpp" class JavaThread; class JfrFilter; diff --git a/src/hotspot/share/jfr/support/methodtracer/jfrFilter.hpp b/src/hotspot/share/jfr/support/methodtracer/jfrFilter.hpp index 665a2cafad3..d4c2414fa84 100644 --- a/src/hotspot/share/jfr/support/methodtracer/jfrFilter.hpp +++ b/src/hotspot/share/jfr/support/methodtracer/jfrFilter.hpp @@ -25,8 +25,8 @@ #ifndef SHARE_JFR_SUPPORT_METHODTRACER_JFRFILTER_HPP #define SHARE_JFR_SUPPORT_METHODTRACER_JFRFILTER_HPP -#include "jni.h" #include "jfr/utilities/jfrAllocation.hpp" +#include "jni.h" #include "oops/annotations.hpp" class InstanceKlass; diff --git a/src/hotspot/share/jfr/support/methodtracer/jfrFilterManager.hpp b/src/hotspot/share/jfr/support/methodtracer/jfrFilterManager.hpp index 904c8447a2e..687e2d700bc 100644 --- a/src/hotspot/share/jfr/support/methodtracer/jfrFilterManager.hpp +++ b/src/hotspot/share/jfr/support/methodtracer/jfrFilterManager.hpp @@ -25,8 +25,8 @@ #ifndef SHARE_JFR_SUPPORT_METHODTRACER_JFRFILTERMANAGER_HPP #define SHARE_JFR_SUPPORT_METHODTRACER_JFRFILTERMANAGER_HPP -#include "jni.h" #include "jfr/utilities/jfrAllocation.hpp" +#include "jni.h" class JfrFilter; class JavaThread; diff --git a/src/hotspot/share/jfr/support/methodtracer/jfrMethodTracer.hpp b/src/hotspot/share/jfr/support/methodtracer/jfrMethodTracer.hpp index d67de9daa59..8a214ab675b 100644 --- a/src/hotspot/share/jfr/support/methodtracer/jfrMethodTracer.hpp +++ b/src/hotspot/share/jfr/support/methodtracer/jfrMethodTracer.hpp @@ -25,10 +25,10 @@ #ifndef SHARE_JFR_SUPPORT_METHODTRACER_JFRMETHODTRACER_HPP #define SHARE_JFR_SUPPORT_METHODTRACER_JFRMETHODTRACER_HPP -#include "jni.h" #include "jfr/support/methodtracer/jfrInstrumentedClass.hpp" #include "jfr/support/methodtracer/jfrTracedMethod.hpp" #include "jfr/utilities/jfrTypes.hpp" +#include "jni.h" #include "memory/allocation.hpp" class ClassFileParser; diff --git a/src/hotspot/share/jfr/utilities/jfrEpochQueue.inline.hpp b/src/hotspot/share/jfr/utilities/jfrEpochQueue.inline.hpp index cc2274408ec..553d61582c0 100644 --- a/src/hotspot/share/jfr/utilities/jfrEpochQueue.inline.hpp +++ b/src/hotspot/share/jfr/utilities/jfrEpochQueue.inline.hpp @@ -26,6 +26,7 @@ #define SHARE_JFR_UTILITIES_JFREPOCHQUEUE_INLINE_HPP #include "jfr/utilities/jfrEpochQueue.hpp" + #include "jfr/recorder/storage/jfrEpochStorage.inline.hpp" #include "jfr/recorder/storage/jfrStorageUtils.inline.hpp" #include "runtime/javaThread.hpp" diff --git a/src/hotspot/share/jfr/utilities/jfrSet.hpp b/src/hotspot/share/jfr/utilities/jfrSet.hpp index b6458d3f9a4..1432d40e4b2 100644 --- a/src/hotspot/share/jfr/utilities/jfrSet.hpp +++ b/src/hotspot/share/jfr/utilities/jfrSet.hpp @@ -25,8 +25,8 @@ #ifndef SHARE_JFR_UTILITIES_JFRSET_HPP #define SHARE_JFR_UTILITIES_JFRSET_HPP -#include "memory/allocation.hpp" #include "jfr/utilities/jfrTypes.hpp" +#include "memory/allocation.hpp" template class JfrSetConfig : public AllStatic { diff --git a/src/hotspot/share/jfr/utilities/jfrTimeConverter.cpp b/src/hotspot/share/jfr/utilities/jfrTimeConverter.cpp index 2ea0fd383d6..d03a15b31b5 100644 --- a/src/hotspot/share/jfr/utilities/jfrTimeConverter.cpp +++ b/src/hotspot/share/jfr/utilities/jfrTimeConverter.cpp @@ -22,8 +22,8 @@ * */ -#include "jfr/utilities/jfrTimeConverter.hpp" #include "jfr/utilities/jfrTime.hpp" +#include "jfr/utilities/jfrTimeConverter.hpp" #include "runtime/os.inline.hpp" static double ft_counter_to_nanos_factor = .0; diff --git a/src/hotspot/share/jfr/utilities/jfrTryLock.hpp b/src/hotspot/share/jfr/utilities/jfrTryLock.hpp index 5c76fa66321..513e550348b 100644 --- a/src/hotspot/share/jfr/utilities/jfrTryLock.hpp +++ b/src/hotspot/share/jfr/utilities/jfrTryLock.hpp @@ -26,8 +26,8 @@ #define SHARE_JFR_UTILITIES_JFRTRYLOCK_HPP #include "runtime/atomic.hpp" -#include "runtime/orderAccess.hpp" #include "runtime/mutexLocker.hpp" +#include "runtime/orderAccess.hpp" #include "utilities/debug.hpp" class JfrTryLock { diff --git a/src/hotspot/share/jfr/writers/jfrStreamWriterHost.inline.hpp b/src/hotspot/share/jfr/writers/jfrStreamWriterHost.inline.hpp index 72fd3485aa3..83451148c70 100644 --- a/src/hotspot/share/jfr/writers/jfrStreamWriterHost.inline.hpp +++ b/src/hotspot/share/jfr/writers/jfrStreamWriterHost.inline.hpp @@ -25,8 +25,9 @@ #ifndef SHARE_JFR_WRITERS_JFRSTREAMWRITERHOST_INLINE_HPP #define SHARE_JFR_WRITERS_JFRSTREAMWRITERHOST_INLINE_HPP -#include "jfr/jni/jfrJavaSupport.hpp" #include "jfr/writers/jfrStreamWriterHost.hpp" + +#include "jfr/jni/jfrJavaSupport.hpp" #include "runtime/os.hpp" template diff --git a/test/hotspot/jtreg/sources/TestIncludesAreSorted.java b/test/hotspot/jtreg/sources/TestIncludesAreSorted.java index 7460a160ee6..5d8c60e23e0 100644 --- a/test/hotspot/jtreg/sources/TestIncludesAreSorted.java +++ b/test/hotspot/jtreg/sources/TestIncludesAreSorted.java @@ -51,6 +51,7 @@ public class TestIncludesAreSorted { "share/code", "share/compiler", "share/interpreter", + "share/jfr", "share/jvmci", "share/libadt", "share/metaprogramming", From 2e06a917659d76fa1b4c63f38894564679209625 Mon Sep 17 00:00:00 2001 From: Dingli Zhang Date: Thu, 21 Aug 2025 01:20:16 +0000 Subject: [PATCH 10/54] 8365841: RISC-V: Several IR verification tests fail after JDK-8350960 without Zvfh Reviewed-by: fyang, fjiang, mli --- src/hotspot/cpu/riscv/riscv_v.ad | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hotspot/cpu/riscv/riscv_v.ad b/src/hotspot/cpu/riscv/riscv_v.ad index 8b5759ce11c..f2845ee2a6c 100644 --- a/src/hotspot/cpu/riscv/riscv_v.ad +++ b/src/hotspot/cpu/riscv/riscv_v.ad @@ -110,6 +110,7 @@ source %{ if (vlen < 4) { return false; } + break; case Op_VectorCastHF2F: case Op_VectorCastF2HF: case Op_AddVHF: From 78d50c02152d3d02953cc468d50c7c40c43c1527 Mon Sep 17 00:00:00 2001 From: Amit Kumar Date: Thu, 21 Aug 2025 03:53:30 +0000 Subject: [PATCH 11/54] 8358756: [s390x] Test StartupOutput.java crash due to CodeCache size Reviewed-by: lucy, dfenacci --- test/hotspot/jtreg/compiler/startup/StartupOutput.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/compiler/startup/StartupOutput.java b/test/hotspot/jtreg/compiler/startup/StartupOutput.java index 22f2887a266..14897f7ab87 100644 --- a/test/hotspot/jtreg/compiler/startup/StartupOutput.java +++ b/test/hotspot/jtreg/compiler/startup/StartupOutput.java @@ -36,6 +36,7 @@ package compiler.startup; +import jdk.test.lib.Platform; import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools; import jdk.test.lib.Utils; @@ -60,8 +61,11 @@ public class StartupOutput { throw new Exception("VM crashed with exit code " + exitCode); } + // On s390x, generated code is ~6x larger in fastdebug and ~1.4x in release builds vs. other archs, + // hence we require slightly more minimum space. + int minInitialSize = 800 + (Platform.isS390x() ? 800 : 0); for (int i = 0; i < 200; i++) { - int initialCodeCacheSizeInKb = 800 + rand.nextInt(400); + int initialCodeCacheSizeInKb = minInitialSize + rand.nextInt(400); int reservedCodeCacheSizeInKb = initialCodeCacheSizeInKb + rand.nextInt(200); pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:InitialCodeCacheSize=" + initialCodeCacheSizeInKb + "K", "-XX:ReservedCodeCacheSize=" + reservedCodeCacheSizeInKb + "k", "-version"); out = new OutputAnalyzer(pb.start()); From c74c60fb8b8aa5c917fc4e1c157cc8083f5797a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20H=C3=A4ssig?= Date: Thu, 21 Aug 2025 07:09:25 +0000 Subject: [PATCH 12/54] 8308094: Add a compilation timeout flag to catch long running compilations Co-authored-by: Dean Long Reviewed-by: dlong, chagedorn --- .../os/linux/compilerThreadTimeout_linux.cpp | 128 ++++++++++++++++++ .../os/linux/compilerThreadTimeout_linux.hpp | 51 +++++++ src/hotspot/os/linux/globals_linux.hpp | 5 + src/hotspot/share/compiler/compileBroker.cpp | 6 + src/hotspot/share/compiler/compilerThread.cpp | 2 + src/hotspot/share/compiler/compilerThread.hpp | 33 ++++- .../arguments/TestCompileTaskTimeout.java | 56 ++++++++ .../jtreg/runtime/signal/TestSigalrm.java | 4 +- 8 files changed, 282 insertions(+), 3 deletions(-) create mode 100644 src/hotspot/os/linux/compilerThreadTimeout_linux.cpp create mode 100644 src/hotspot/os/linux/compilerThreadTimeout_linux.hpp create mode 100644 test/hotspot/jtreg/compiler/arguments/TestCompileTaskTimeout.java diff --git a/src/hotspot/os/linux/compilerThreadTimeout_linux.cpp b/src/hotspot/os/linux/compilerThreadTimeout_linux.cpp new file mode 100644 index 00000000000..609c78616f3 --- /dev/null +++ b/src/hotspot/os/linux/compilerThreadTimeout_linux.cpp @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 "compiler/compilerThread.hpp" +#include "compiler/compileTask.hpp" +#include "compilerThreadTimeout_linux.hpp" +#include "oops/method.hpp" +#include "runtime/osThread.hpp" +#include "signals_posix.hpp" +#include "utilities/globalDefinitions.hpp" + +#include + +#ifdef ASSERT +void compiler_signal_handler(int signo, siginfo_t* info, void* context) { + CompilerThread::current()->timeout()->compiler_signal_handler(signo, info, context); +} + +void CompilerThreadTimeoutLinux::compiler_signal_handler(int signo, siginfo_t* info, void* context) { + switch (signo) { + case TIMEOUT_SIGNAL: { + CompileTask* task = CompilerThread::current()->task(); + const int SIZE = 512; + char method_name_buf[SIZE]; + task->method()->name_and_sig_as_C_string(method_name_buf, SIZE); + assert(false, "compile task %d (%s) timed out after %zd ms", + task->compile_id(), method_name_buf, CompileTaskTimeout); + } + default: { + assert(false, "unexpected signal %d", signo); + } + } +} +#endif // ASSERT + +void CompilerThreadTimeoutLinux::arm() { +#ifdef ASSERT + if (CompileTaskTimeout == 0) { + return; + } + + const intx sec = (CompileTaskTimeout * NANOSECS_PER_MILLISEC) / NANOSECS_PER_SEC; + const intx nsec = (CompileTaskTimeout * NANOSECS_PER_MILLISEC) % NANOSECS_PER_SEC; + const struct timespec ts = {.tv_sec = sec, .tv_nsec = nsec}; + const struct itimerspec its {.it_interval = ts, .it_value = ts}; + + // Start the timer. + timer_settime(_timer, 0, &its, nullptr); +#endif // ASSERT +} + +void CompilerThreadTimeoutLinux::disarm() { +#ifdef ASSERT + if (CompileTaskTimeout == 0) { + return; + } + + // Reset the timer by setting it to zero. + const struct itimerspec its { + .it_interval = {.tv_sec = 0, .tv_nsec=0}, + .it_value = {.tv_sec = 0, .tv_nsec=0} + }; + timer_settime(_timer, 0, &its, nullptr); +#endif // ASSERT +} + +bool CompilerThreadTimeoutLinux::init_timeout() { +#ifdef ASSERT + if (CompileTaskTimeout == 0) { + return true; + } + + JavaThread* thread = JavaThread::current(); + + // Create a POSIX timer sending SIGALRM to this thread only. + sigevent_t sev; + sev.sigev_value.sival_ptr = nullptr; + sev.sigev_signo = TIMEOUT_SIGNAL; + sev.sigev_notify = SIGEV_THREAD_ID; + #ifdef MUSL_LIBC + sev.sigev_notify_thread_id = thread->osthread()->thread_id(); + #else + sev._sigev_un._tid = thread->osthread()->thread_id(); + #endif // MUSL_LIBC + clockid_t clock; + int err = pthread_getcpuclockid(thread->osthread()->pthread_id(), &clock); + if (err != 0) { + return false; + } + err = timer_create(clock, &sev, &_timer); + if (err != 0) { + return false; + } + + // Install the signal handler and check that we do not have a conflicting handler. + struct sigaction sigact, sigact_old; + err = PosixSignals::install_sigaction_signal_handler(&sigact, + &sigact_old, + TIMEOUT_SIGNAL, + (sa_sigaction_t)::compiler_signal_handler); + if (err != 0 || (sigact_old.sa_sigaction != sigact.sa_sigaction && + sigact_old.sa_handler != SIG_DFL && sigact_old.sa_handler != SIG_IGN)) { + return false; + } +#endif // ASSERT + return true; +} diff --git a/src/hotspot/os/linux/compilerThreadTimeout_linux.hpp b/src/hotspot/os/linux/compilerThreadTimeout_linux.hpp new file mode 100644 index 00000000000..2dc6fa7b9c9 --- /dev/null +++ b/src/hotspot/os/linux/compilerThreadTimeout_linux.hpp @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 LINUX_COMPILER_THREAD_TIMEOUT_LINUX_HPP +#define LINUX_COMPILER_THREAD_TIMEOUT_LINUX_HPP + +#include "memory/allocation.hpp" +#include "nmt/memTag.hpp" +#include "utilities/macros.hpp" + +#include +#include + +class CompilerThreadTimeoutLinux : public CHeapObj { +#ifdef ASSERT + public: + static const int TIMEOUT_SIGNAL = SIGALRM; + void compiler_signal_handler(int signo, siginfo_t* info, void* context); + private: + timer_t _timer; +#endif // ASSERT + public: + CompilerThreadTimeoutLinux() DEBUG_ONLY(: _timer(nullptr)) {}; + + bool init_timeout(); + void arm(); + void disarm(); +}; + +#endif //LINUX_COMPILER_THREAD_TIMEOUT_LINUX_HPP diff --git a/src/hotspot/os/linux/globals_linux.hpp b/src/hotspot/os/linux/globals_linux.hpp index 542e034f59f..90e1e5e5f3f 100644 --- a/src/hotspot/os/linux/globals_linux.hpp +++ b/src/hotspot/os/linux/globals_linux.hpp @@ -89,6 +89,11 @@ product(bool, PrintMemoryMapAtExit, false, DIAGNOSTIC, \ "Print an annotated memory map at exit") \ \ + develop(intx, CompileTaskTimeout, 0, \ + "Set the timeout for compile tasks' CPU time in milliseconds."\ + " 0 = no timeout (default)") \ + range(0,1000000) \ + \ // end of RUNTIME_OS_FLAGS // diff --git a/src/hotspot/share/compiler/compileBroker.cpp b/src/hotspot/share/compiler/compileBroker.cpp index 36663ab1088..432b0e6a346 100644 --- a/src/hotspot/share/compiler/compileBroker.cpp +++ b/src/hotspot/share/compiler/compileBroker.cpp @@ -218,6 +218,7 @@ CompileTaskWrapper::CompileTaskWrapper(CompileTask* task) { CompilerThread* thread = CompilerThread::current(); thread->set_task(task); CompileLog* log = thread->log(); + thread->timeout()->arm(); if (log != nullptr && !task->is_unloaded()) task->log_task_start(log); } @@ -228,6 +229,7 @@ CompileTaskWrapper::~CompileTaskWrapper() { if (log != nullptr && !task->is_unloaded()) task->log_task_done(log); thread->set_task(nullptr); thread->set_env(nullptr); + thread->timeout()->disarm(); if (task->is_blocking()) { bool free_task = false; { @@ -1925,6 +1927,10 @@ void CompileBroker::compiler_thread_loop() { log->end_elem(); } + if (!thread->init_compilation_timeout()) { + return; + } + // If compiler thread/runtime initialization fails, exit the compiler thread if (!init_compiler_runtime()) { return; diff --git a/src/hotspot/share/compiler/compilerThread.cpp b/src/hotspot/share/compiler/compilerThread.cpp index 4034e63bc10..7cf494aad56 100644 --- a/src/hotspot/share/compiler/compilerThread.cpp +++ b/src/hotspot/share/compiler/compilerThread.cpp @@ -40,6 +40,7 @@ CompilerThread::CompilerThread(CompileQueue* queue, _can_call_java = false; _compiler = nullptr; _arena_stat = nullptr; + _timeout = nullptr; #ifndef PRODUCT _ideal_graph_printer = nullptr; @@ -49,6 +50,7 @@ CompilerThread::CompilerThread(CompileQueue* queue, CompilerThread::~CompilerThread() { // Delete objects which were allocated on heap. delete _counters; + delete _timeout; // arenastat should have been deleted at the end of the compilation assert(_arena_stat == nullptr, "Should be null"); } diff --git a/src/hotspot/share/compiler/compilerThread.hpp b/src/hotspot/share/compiler/compilerThread.hpp index e20e3017d1f..e4641780a12 100644 --- a/src/hotspot/share/compiler/compilerThread.hpp +++ b/src/hotspot/share/compiler/compilerThread.hpp @@ -25,7 +25,14 @@ #ifndef SHARE_COMPILER_COMPILERTHREAD_HPP #define SHARE_COMPILER_COMPILERTHREAD_HPP +#include "memory/allocation.hpp" +#include "nmt/memTag.hpp" #include "runtime/javaThread.hpp" +#include "utilities/macros.hpp" + +#ifdef LINUX +#include "compilerThreadTimeout_linux.hpp" +#endif //LINUX class AbstractCompiler; class ArenaStatCounter; @@ -38,10 +45,27 @@ class CompileQueue; class CompilerCounters; class IdealGraphPrinter; +#ifndef LINUX +class CompilerThreadTimeoutGeneric : public CHeapObj { + public: + CompilerThreadTimeoutGeneric() {}; + void arm() {}; + void disarm() {}; + bool init_timeout() { return true; }; +}; +#endif // !LINUX + // A thread used for Compilation. class CompilerThread : public JavaThread { friend class VMStructs; JVMCI_ONLY(friend class CompilerThreadCanCallJava;) + +#ifdef LINUX + typedef CompilerThreadTimeoutLinux Timeout; +#else // LINUX + typedef CompilerThreadTimeoutGeneric Timeout; +#endif // LINUX + private: CompilerCounters* _counters; @@ -57,6 +81,7 @@ class CompilerThread : public JavaThread { ArenaStatCounter* _arena_stat; + Timeout* _timeout; public: static CompilerThread* current() { @@ -113,7 +138,13 @@ class CompilerThread : public JavaThread { public: IdealGraphPrinter *ideal_graph_printer() { return _ideal_graph_printer; } void set_ideal_graph_printer(IdealGraphPrinter *n) { _ideal_graph_printer = n; } -#endif +#endif // !PRODUCT + + Timeout* timeout() const { return _timeout; }; + bool init_compilation_timeout() { + _timeout = new Timeout(); + return _timeout->init_timeout(); + }; // Get/set the thread's current task CompileTask* task() { return _task; } diff --git a/test/hotspot/jtreg/compiler/arguments/TestCompileTaskTimeout.java b/test/hotspot/jtreg/compiler/arguments/TestCompileTaskTimeout.java new file mode 100644 index 00000000000..42f13744cae --- /dev/null +++ b/test/hotspot/jtreg/compiler/arguments/TestCompileTaskTimeout.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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.arguments; + +/* + * @test TestCompileTaskTimeout + * @bug 8308094 + * @requires vm.debug & vm.flagless & os.name == "Linux" + * @summary Check functionality of CompileTaskTimeout + * @library /test/lib + * @run driver compiler.arguments.TestCompileTaskTimeout + */ + +import jdk.test.lib.process.ProcessTools; + +public class TestCompileTaskTimeout { + + public static void main(String[] args) throws Throwable { + ProcessTools.executeTestJava("-Xcomp", "-XX:CompileTaskTimeout=1", "--version") + .shouldHaveExitValue(134) + .shouldContain("timed out after"); + + ProcessTools.executeTestJava("-Xcomp", "-XX:CompileTaskTimeout=1", "-XX:TieredStopAtLevel=3", "--version") + .shouldHaveExitValue(134) + .shouldContain("timed out after"); + + ProcessTools.executeTestJava("-Xcomp", "-XX:CompileTaskTimeout=1", "-XX:-TieredCompilation", "--version") + .shouldHaveExitValue(134) + .shouldContain("timed out after"); + + ProcessTools.executeTestJava("-Xcomp", "-XX:CompileTaskTimeout=200", "--version") + .shouldHaveExitValue(0) + .shouldContain("java version"); + } +} \ No newline at end of file diff --git a/test/hotspot/jtreg/runtime/signal/TestSigalrm.java b/test/hotspot/jtreg/runtime/signal/TestSigalrm.java index b9a3c3e5060..2e485a46cf9 100644 --- a/test/hotspot/jtreg/runtime/signal/TestSigalrm.java +++ b/test/hotspot/jtreg/runtime/signal/TestSigalrm.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * 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 - * @requires os.family != "windows" & os.family != "aix" + * @requires os.family != "windows" & os.family != "aix" & vm.flagless * * @summary converted from VM testbase runtime/signal/sigalrm01. * VM testbase keywords: [signal, runtime, linux, macosx] From a7c0f4b845c314099966f5669bfc7947bdf28004 Mon Sep 17 00:00:00 2001 From: Fredrik Bredberg Date: Thu, 21 Aug 2025 07:47:26 +0000 Subject: [PATCH 13/54] 8365146: Remove LockingMode related code from ppc64 Reviewed-by: aboldtch, mdoerr --- src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp | 48 +--- src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp | 76 +---- src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp | 220 ++------------- src/hotspot/cpu/ppc/macroAssembler_ppc.cpp | 266 ------------------ src/hotspot/cpu/ppc/macroAssembler_ppc.hpp | 8 - src/hotspot/cpu/ppc/ppc.ad | 37 +-- src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp | 21 +- .../ppc/templateInterpreterGenerator_ppc.cpp | 2 +- 8 files changed, 50 insertions(+), 628 deletions(-) diff --git a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp index b548444bb48..73509c22134 100644 --- a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp @@ -228,11 +228,7 @@ int LIR_Assembler::emit_unwind_handler() { if (method()->is_synchronized()) { monitor_address(0, FrameMap::R4_opr); stub = new MonitorExitStub(FrameMap::R4_opr, true, 0); - if (LockingMode == LM_MONITOR) { - __ b(*stub->entry()); - } else { - __ unlock_object(R5, R6, R4, *stub->entry()); - } + __ unlock_object(R5, R6, R4, *stub->entry()); __ bind(*stub->continuation()); } @@ -2618,44 +2614,20 @@ void LIR_Assembler::emit_lock(LIR_OpLock* op) { // Obj may not be an oop. if (op->code() == lir_lock) { MonitorEnterStub* stub = (MonitorEnterStub*)op->stub(); - if (LockingMode != LM_MONITOR) { - assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header"); - // Add debug info for NullPointerException only if one is possible. - if (op->info() != nullptr) { - if (!os::zero_page_read_protected() || !ImplicitNullChecks) { - explicit_null_check(obj, op->info()); - } else { - add_debug_info_for_null_check_here(op->info()); - } - } - __ lock_object(hdr, obj, lock, op->scratch_opr()->as_register(), *op->stub()->entry()); - } else { - // always do slow locking - // note: The slow locking code could be inlined here, however if we use - // slow locking, speed doesn't matter anyway and this solution is - // simpler and requires less duplicated code - additionally, the - // slow locking code is the same in either case which simplifies - // debugging. - if (op->info() != nullptr) { + assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header"); + // Add debug info for NullPointerException only if one is possible. + if (op->info() != nullptr) { + if (!os::zero_page_read_protected() || !ImplicitNullChecks) { + explicit_null_check(obj, op->info()); + } else { add_debug_info_for_null_check_here(op->info()); - __ null_check(obj); } - __ b(*op->stub()->entry()); } + __ lock_object(hdr, obj, lock, op->scratch_opr()->as_register(), *op->stub()->entry()); } else { assert (op->code() == lir_unlock, "Invalid code, expected lir_unlock"); - if (LockingMode != LM_MONITOR) { - assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header"); - __ unlock_object(hdr, obj, lock, *op->stub()->entry()); - } else { - // always do slow unlocking - // note: The slow unlocking code could be inlined here, however if we use - // slow unlocking, speed doesn't matter anyway and this solution is - // simpler and requires less duplicated code - additionally, the - // slow unlocking code is the same in either case which simplifies - // debugging. - __ b(*op->stub()->entry()); - } + assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header"); + __ unlock_object(hdr, obj, lock, *op->stub()->entry()); } __ bind(*op->stub()->continuation()); } diff --git a/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp index 23050bff453..04af473c99b 100644 --- a/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp @@ -82,59 +82,13 @@ void C1_MacroAssembler::lock_object(Register Rmark, Register Roop, Register Rbox // Save object being locked into the BasicObjectLock... std(Roop, in_bytes(BasicObjectLock::obj_offset()), Rbox); - if (LockingMode == LM_LIGHTWEIGHT) { - lightweight_lock(Rbox, Roop, Rmark, Rscratch, slow_int); - } else if (LockingMode == LM_LEGACY) { - - if (DiagnoseSyncOnValueBasedClasses != 0) { - load_klass(Rscratch, Roop); - lbz(Rscratch, in_bytes(Klass::misc_flags_offset()), Rscratch); - testbitdi(CR0, R0, Rscratch, exact_log2(KlassFlags::_misc_is_value_based_class)); - bne(CR0, slow_int); - } - - // ... and mark it unlocked. - ori(Rmark, Rmark, markWord::unlocked_value); - - // Save unlocked object header into the displaced header location on the stack. - std(Rmark, BasicLock::displaced_header_offset_in_bytes(), Rbox); - - // Compare object markWord with Rmark and if equal exchange Rscratch with object markWord. - assert(oopDesc::mark_offset_in_bytes() == 0, "cas must take a zero displacement"); - cmpxchgd(/*flag=*/CR0, - /*current_value=*/Rscratch, - /*compare_value=*/Rmark, - /*exchange_value=*/Rbox, - /*where=*/Roop/*+0==mark_offset_in_bytes*/, - MacroAssembler::MemBarRel | MacroAssembler::MemBarAcq, - MacroAssembler::cmpxchgx_hint_acquire_lock(), - noreg, - &cas_failed, - /*check without membar and ldarx first*/true); - // If compare/exchange succeeded we found an unlocked object and we now have locked it - // hence we are done. - } else { - assert(false, "Unhandled LockingMode:%d", LockingMode); - } + lightweight_lock(Rbox, Roop, Rmark, Rscratch, slow_int); b(done); bind(slow_int); b(slow_case); // far - if (LockingMode == LM_LEGACY) { - bind(cas_failed); - // We did not find an unlocked object so see if this is a recursive case. - sub(Rscratch, Rscratch, R1_SP); - load_const_optimized(R0, (~(os::vm_page_size()-1) | markWord::lock_mask_in_place)); - and_(R0/*==0?*/, Rscratch, R0); - std(R0/*==0, perhaps*/, BasicLock::displaced_header_offset_in_bytes(), Rbox); - bne(CR0, slow_int); - } - bind(done); - if (LockingMode == LM_LEGACY) { - inc_held_monitor_count(Rmark /*tmp*/); - } } @@ -146,43 +100,17 @@ void C1_MacroAssembler::unlock_object(Register Rmark, Register Roop, Register Rb Address mark_addr(Roop, oopDesc::mark_offset_in_bytes()); assert(mark_addr.disp() == 0, "cas must take a zero displacement"); - if (LockingMode != LM_LIGHTWEIGHT) { - // Test first if it is a fast recursive unlock. - ld(Rmark, BasicLock::displaced_header_offset_in_bytes(), Rbox); - cmpdi(CR0, Rmark, 0); - beq(CR0, done); - } - // Load object. ld(Roop, in_bytes(BasicObjectLock::obj_offset()), Rbox); verify_oop(Roop, FILE_AND_LINE); - if (LockingMode == LM_LIGHTWEIGHT) { - lightweight_unlock(Roop, Rmark, slow_int); - } else if (LockingMode == LM_LEGACY) { - // Check if it is still a light weight lock, this is is true if we see - // the stack address of the basicLock in the markWord of the object. - cmpxchgd(/*flag=*/CR0, - /*current_value=*/R0, - /*compare_value=*/Rbox, - /*exchange_value=*/Rmark, - /*where=*/Roop, - MacroAssembler::MemBarRel, - MacroAssembler::cmpxchgx_hint_release_lock(), - noreg, - &slow_int); - } else { - assert(false, "Unhandled LockingMode:%d", LockingMode); - } + lightweight_unlock(Roop, Rmark, slow_int); b(done); bind(slow_int); b(slow_case); // far // Done bind(done); - if (LockingMode == LM_LEGACY) { - dec_held_monitor_count(Rmark /*tmp*/); - } } diff --git a/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp b/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp index 29fb54250c2..8df2cc5d273 100644 --- a/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp +++ b/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp @@ -946,121 +946,20 @@ void InterpreterMacroAssembler::leave_jfr_critical_section() { // object - Address of the object to be locked. // void InterpreterMacroAssembler::lock_object(Register monitor, Register object) { - if (LockingMode == LM_MONITOR) { - call_VM_preemptable(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), monitor); - } else { - // template code (for LM_LEGACY): - // - // markWord displaced_header = obj->mark().set_unlocked(); - // monitor->lock()->set_displaced_header(displaced_header); - // if (Atomic::cmpxchg(/*addr*/obj->mark_addr(), /*cmp*/displaced_header, /*ex=*/monitor) == displaced_header) { - // // We stored the monitor address into the object's mark word. - // } else if (THREAD->is_lock_owned((address)displaced_header)) - // // Simple recursive case. - // monitor->lock()->set_displaced_header(nullptr); - // } else { - // // Slow path. - // InterpreterRuntime::monitorenter(THREAD, monitor); - // } + const Register header = R7_ARG5; + const Register tmp = R8_ARG6; - const Register header = R7_ARG5; - const Register object_mark_addr = R8_ARG6; - const Register current_header = R9_ARG7; - const Register tmp = R10_ARG8; + Label done, slow_case; - Label count_locking, done, slow_case, cas_failed; + assert_different_registers(header, tmp); - assert_different_registers(header, object_mark_addr, current_header, tmp); + lightweight_lock(monitor, object, header, tmp, slow_case); + b(done); - // markWord displaced_header = obj->mark().set_unlocked(); + bind(slow_case); + call_VM_preemptable(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), monitor); - if (LockingMode == LM_LIGHTWEIGHT) { - lightweight_lock(monitor, object, header, tmp, slow_case); - b(done); - } else if (LockingMode == LM_LEGACY) { - - if (DiagnoseSyncOnValueBasedClasses != 0) { - load_klass(tmp, object); - lbz(tmp, in_bytes(Klass::misc_flags_offset()), tmp); - testbitdi(CR0, R0, tmp, exact_log2(KlassFlags::_misc_is_value_based_class)); - bne(CR0, slow_case); - } - - // Load markWord from object into header. - ld(header, oopDesc::mark_offset_in_bytes(), object); - - // Set displaced_header to be (markWord of object | UNLOCK_VALUE). - ori(header, header, markWord::unlocked_value); - - // monitor->lock()->set_displaced_header(displaced_header); - const int lock_offset = in_bytes(BasicObjectLock::lock_offset()); - const int mark_offset = lock_offset + - BasicLock::displaced_header_offset_in_bytes(); - - // Initialize the box (Must happen before we update the object mark!). - std(header, mark_offset, monitor); - - // if (Atomic::cmpxchg(/*addr*/obj->mark_addr(), /*cmp*/displaced_header, /*ex=*/monitor) == displaced_header) { - - // Store stack address of the BasicObjectLock (this is monitor) into object. - addi(object_mark_addr, object, oopDesc::mark_offset_in_bytes()); - - // Must fence, otherwise, preceding store(s) may float below cmpxchg. - // CmpxchgX sets CR0 to cmpX(current, displaced). - cmpxchgd(/*flag=*/CR0, - /*current_value=*/current_header, - /*compare_value=*/header, /*exchange_value=*/monitor, - /*where=*/object_mark_addr, - MacroAssembler::MemBarRel | MacroAssembler::MemBarAcq, - MacroAssembler::cmpxchgx_hint_acquire_lock(), - noreg, - &cas_failed, - /*check without membar and ldarx first*/true); - - // If the compare-and-exchange succeeded, then we found an unlocked - // object and we have now locked it. - b(count_locking); - bind(cas_failed); - - // } else if (THREAD->is_lock_owned((address)displaced_header)) - // // Simple recursive case. - // monitor->lock()->set_displaced_header(nullptr); - - // We did not see an unlocked object so try the fast recursive case. - - // Check if owner is self by comparing the value in the markWord of object - // (current_header) with the stack pointer. - sub(current_header, current_header, R1_SP); - - assert(os::vm_page_size() > 0xfff, "page size too small - change the constant"); - load_const_optimized(tmp, ~(os::vm_page_size()-1) | markWord::lock_mask_in_place); - - and_(R0/*==0?*/, current_header, tmp); - // If condition is true we are done and hence we can store 0 in the displaced - // header indicating it is a recursive lock. - bne(CR0, slow_case); - std(R0/*==0!*/, mark_offset, monitor); - b(count_locking); - } - - // } else { - // // Slow path. - // InterpreterRuntime::monitorenter(THREAD, monitor); - - // None of the above fast optimizations worked so we have to get into the - // slow case of monitor enter. - bind(slow_case); - call_VM_preemptable(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), monitor); - // } - - if (LockingMode == LM_LEGACY) { - b(done); - align(32, 12); - bind(count_locking); - inc_held_monitor_count(current_header /*tmp*/); - } - bind(done); - } + bind(done); } // Unlocks an object. Used in monitorexit bytecode and remove_activation. @@ -1071,95 +970,34 @@ void InterpreterMacroAssembler::lock_object(Register monitor, Register object) { // // Throw IllegalMonitorException if object is not locked by current thread. void InterpreterMacroAssembler::unlock_object(Register monitor) { - if (LockingMode == LM_MONITOR) { - call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), monitor); - } else { + const Register object = R7_ARG5; + const Register header = R8_ARG6; + const Register current_header = R10_ARG8; - // template code (for LM_LEGACY): - // - // if ((displaced_header = monitor->displaced_header()) == nullptr) { - // // Recursive unlock. Mark the monitor unlocked by setting the object field to null. - // monitor->set_obj(nullptr); - // } else if (Atomic::cmpxchg(obj->mark_addr(), monitor, displaced_header) == monitor) { - // // We swapped the unlocked mark in displaced_header into the object's mark word. - // monitor->set_obj(nullptr); - // } else { - // // Slow path. - // InterpreterRuntime::monitorexit(monitor); - // } + Label free_slot; + Label slow_case; - const Register object = R7_ARG5; - const Register header = R8_ARG6; - const Register object_mark_addr = R9_ARG7; - const Register current_header = R10_ARG8; + assert_different_registers(object, header, current_header); - Label free_slot; - Label slow_case; + // The object address from the monitor is in object. + ld(object, in_bytes(BasicObjectLock::obj_offset()), monitor); - assert_different_registers(object, header, object_mark_addr, current_header); + lightweight_unlock(object, header, slow_case); - if (LockingMode != LM_LIGHTWEIGHT) { - // Test first if we are in the fast recursive case. - ld(header, in_bytes(BasicObjectLock::lock_offset()) + - BasicLock::displaced_header_offset_in_bytes(), monitor); + b(free_slot); - // If the displaced header is zero, we have a recursive unlock. - cmpdi(CR0, header, 0); - beq(CR0, free_slot); // recursive unlock - } + bind(slow_case); + call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), monitor); - // } else if (Atomic::cmpxchg(obj->mark_addr(), monitor, displaced_header) == monitor) { - // // We swapped the unlocked mark in displaced_header into the object's mark word. - // monitor->set_obj(nullptr); + Label done; + b(done); // Monitor register may be overwritten! Runtime has already freed the slot. - // If we still have a lightweight lock, unlock the object and be done. - - // The object address from the monitor is in object. - ld(object, in_bytes(BasicObjectLock::obj_offset()), monitor); - - if (LockingMode == LM_LIGHTWEIGHT) { - lightweight_unlock(object, header, slow_case); - } else { - addi(object_mark_addr, object, oopDesc::mark_offset_in_bytes()); - - // We have the displaced header in displaced_header. If the lock is still - // lightweight, it will contain the monitor address and we'll store the - // displaced header back into the object's mark word. - // CmpxchgX sets CR0 to cmpX(current, monitor). - cmpxchgd(/*flag=*/CR0, - /*current_value=*/current_header, - /*compare_value=*/monitor, /*exchange_value=*/header, - /*where=*/object_mark_addr, - MacroAssembler::MemBarRel, - MacroAssembler::cmpxchgx_hint_release_lock(), - noreg, - &slow_case); - } - b(free_slot); - - // } else { - // // Slow path. - // InterpreterRuntime::monitorexit(monitor); - - // The lock has been converted into a heavy lock and hence - // we need to get into the slow case. - bind(slow_case); - call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), monitor); - // } - - Label done; - b(done); // Monitor register may be overwritten! Runtime has already freed the slot. - - // Exchange worked, do monitor->set_obj(nullptr); - align(32, 12); - bind(free_slot); - li(R0, 0); - std(R0, in_bytes(BasicObjectLock::obj_offset()), monitor); - if (LockingMode == LM_LEGACY) { - dec_held_monitor_count(current_header /*tmp*/); - } - bind(done); - } + // Do monitor->set_obj(nullptr); + align(32, 12); + bind(free_slot); + li(R0, 0); + std(R0, in_bytes(BasicObjectLock::obj_offset()), monitor); + bind(done); } // Load compiled (i2c) or interpreter entry when calling from interpreted and diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp index 396a50427f8..00a46504e14 100644 --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp @@ -2671,238 +2671,6 @@ address MacroAssembler::emit_trampoline_stub(int destination_toc_offset, } // "The box" is the space on the stack where we copy the object mark. -void MacroAssembler::compiler_fast_lock_object(ConditionRegister flag, Register oop, Register box, - Register temp, Register displaced_header, Register current_header) { - assert(LockingMode != LM_LIGHTWEIGHT, "uses fast_lock_lightweight"); - assert_different_registers(oop, box, temp, displaced_header, current_header); - Label object_has_monitor; - Label cas_failed; - Label success, failure; - - // Load markWord from object into displaced_header. - ld(displaced_header, oopDesc::mark_offset_in_bytes(), oop); - - if (DiagnoseSyncOnValueBasedClasses != 0) { - load_klass(temp, oop); - lbz(temp, in_bytes(Klass::misc_flags_offset()), temp); - testbitdi(flag, R0, temp, exact_log2(KlassFlags::_misc_is_value_based_class)); - bne(flag, failure); - } - - // Handle existing monitor. - // The object has an existing monitor iff (mark & monitor_value) != 0. - andi_(temp, displaced_header, markWord::monitor_value); - bne(CR0, object_has_monitor); - - if (LockingMode == LM_MONITOR) { - // Set NE to indicate 'failure' -> take slow-path. - crandc(flag, Assembler::equal, flag, Assembler::equal); - b(failure); - } else { - assert(LockingMode == LM_LEGACY, "must be"); - // Set displaced_header to be (markWord of object | UNLOCK_VALUE). - ori(displaced_header, displaced_header, markWord::unlocked_value); - - // Load Compare Value application register. - - // Initialize the box. (Must happen before we update the object mark!) - std(displaced_header, BasicLock::displaced_header_offset_in_bytes(), box); - - // Must fence, otherwise, preceding store(s) may float below cmpxchg. - // Compare object markWord with mark and if equal exchange scratch1 with object markWord. - cmpxchgd(/*flag=*/flag, - /*current_value=*/current_header, - /*compare_value=*/displaced_header, - /*exchange_value=*/box, - /*where=*/oop, - MacroAssembler::MemBarRel | MacroAssembler::MemBarAcq, - MacroAssembler::cmpxchgx_hint_acquire_lock(), - noreg, - &cas_failed, - /*check without membar and ldarx first*/true); - assert(oopDesc::mark_offset_in_bytes() == 0, "offset of _mark is not 0"); - // If the compare-and-exchange succeeded, then we found an unlocked - // object and we have now locked it. - b(success); - - bind(cas_failed); - // We did not see an unlocked object so try the fast recursive case. - - // Check if the owner is self by comparing the value in the markWord of object - // (current_header) with the stack pointer. - sub(current_header, current_header, R1_SP); - load_const_optimized(temp, ~(os::vm_page_size()-1) | markWord::lock_mask_in_place); - - and_(R0/*==0?*/, current_header, temp); - // If condition is true we are cont and hence we can store 0 as the - // displaced header in the box, which indicates that it is a recursive lock. - std(R0/*==0, perhaps*/, BasicLock::displaced_header_offset_in_bytes(), box); - - if (flag != CR0) { - mcrf(flag, CR0); - } - beq(CR0, success); - b(failure); - } - - // Handle existing monitor. - bind(object_has_monitor); - - // Try to CAS owner (no owner => current thread's _monitor_owner_id). - addi(temp, displaced_header, in_bytes(ObjectMonitor::owner_offset()) - markWord::monitor_value); - Register thread_id = displaced_header; - ld(thread_id, in_bytes(JavaThread::monitor_owner_id_offset()), R16_thread); - cmpxchgd(/*flag=*/flag, - /*current_value=*/current_header, - /*compare_value=*/(intptr_t)0, - /*exchange_value=*/thread_id, - /*where=*/temp, - MacroAssembler::MemBarRel | MacroAssembler::MemBarAcq, - MacroAssembler::cmpxchgx_hint_acquire_lock()); - - // Store a non-null value into the box. - std(box, BasicLock::displaced_header_offset_in_bytes(), box); - beq(flag, success); - - // Check for recursive locking. - cmpd(flag, current_header, thread_id); - bne(flag, failure); - - // Current thread already owns the lock. Just increment recursions. - Register recursions = displaced_header; - ld(recursions, in_bytes(ObjectMonitor::recursions_offset() - ObjectMonitor::owner_offset()), temp); - addi(recursions, recursions, 1); - std(recursions, in_bytes(ObjectMonitor::recursions_offset() - ObjectMonitor::owner_offset()), temp); - - // flag == EQ indicates success, increment held monitor count if LM_LEGACY is enabled - // flag == NE indicates failure - bind(success); - if (LockingMode == LM_LEGACY) { - inc_held_monitor_count(temp); - } -#ifdef ASSERT - // Check that unlocked label is reached with flag == EQ. - Label flag_correct; - beq(flag, flag_correct); - stop("compiler_fast_lock_object: Flag != EQ"); -#endif - bind(failure); -#ifdef ASSERT - // Check that slow_path label is reached with flag == NE. - bne(flag, flag_correct); - stop("compiler_fast_lock_object: Flag != NE"); - bind(flag_correct); -#endif -} - -void MacroAssembler::compiler_fast_unlock_object(ConditionRegister flag, Register oop, Register box, - Register temp, Register displaced_header, Register current_header) { - assert(LockingMode != LM_LIGHTWEIGHT, "uses fast_unlock_lightweight"); - assert_different_registers(oop, box, temp, displaced_header, current_header); - Label success, failure, object_has_monitor, not_recursive; - - if (LockingMode == LM_LEGACY) { - // Find the lock address and load the displaced header from the stack. - ld(displaced_header, BasicLock::displaced_header_offset_in_bytes(), box); - - // If the displaced header is 0, we have a recursive unlock. - cmpdi(flag, displaced_header, 0); - beq(flag, success); - } - - // Handle existing monitor. - // The object has an existing monitor iff (mark & monitor_value) != 0. - ld(current_header, oopDesc::mark_offset_in_bytes(), oop); - andi_(R0, current_header, markWord::monitor_value); - bne(CR0, object_has_monitor); - - if (LockingMode == LM_MONITOR) { - // Set NE to indicate 'failure' -> take slow-path. - crandc(flag, Assembler::equal, flag, Assembler::equal); - b(failure); - } else { - assert(LockingMode == LM_LEGACY, "must be"); - // Check if it is still a light weight lock, this is is true if we see - // the stack address of the basicLock in the markWord of the object. - // Cmpxchg sets flag to cmpd(current_header, box). - cmpxchgd(/*flag=*/flag, - /*current_value=*/current_header, - /*compare_value=*/box, - /*exchange_value=*/displaced_header, - /*where=*/oop, - MacroAssembler::MemBarRel, - MacroAssembler::cmpxchgx_hint_release_lock(), - noreg, - &failure); - assert(oopDesc::mark_offset_in_bytes() == 0, "offset of _mark is not 0"); - b(success); - } - - // Handle existing monitor. - bind(object_has_monitor); - STATIC_ASSERT(markWord::monitor_value <= INT_MAX); - addi(current_header, current_header, -(int)markWord::monitor_value); // monitor - - ld(displaced_header, in_bytes(ObjectMonitor::recursions_offset()), current_header); - addic_(displaced_header, displaced_header, -1); - blt(CR0, not_recursive); // Not recursive if negative after decrement. - - // Recursive unlock - std(displaced_header, in_bytes(ObjectMonitor::recursions_offset()), current_header); - if (flag == CR0) { // Otherwise, flag is already EQ, here. - crorc(CR0, Assembler::equal, CR0, Assembler::equal); // Set CR0 EQ - } - b(success); - - bind(not_recursive); - - // Set owner to null. - // Release to satisfy the JMM - release(); - li(temp, 0); - std(temp, in_bytes(ObjectMonitor::owner_offset()), current_header); - // We need a full fence after clearing owner to avoid stranding. - // StoreLoad achieves this. - membar(StoreLoad); - - // Check if the entry_list is empty. - ld(temp, in_bytes(ObjectMonitor::entry_list_offset()), current_header); - cmpdi(flag, temp, 0); - beq(flag, success); // If so we are done. - - // Check if there is a successor. - ld(temp, in_bytes(ObjectMonitor::succ_offset()), current_header); - cmpdi(flag, temp, 0); - // Invert equal bit - crnand(flag, Assembler::equal, flag, Assembler::equal); - beq(flag, success); // If there is a successor we are done. - - // Save the monitor pointer in the current thread, so we can try - // to reacquire the lock in SharedRuntime::monitor_exit_helper(). - std(current_header, in_bytes(JavaThread::unlocked_inflated_monitor_offset()), R16_thread); - b(failure); // flag == NE - - // flag == EQ indicates success, decrement held monitor count if LM_LEGACY is enabled - // flag == NE indicates failure - bind(success); - if (LockingMode == LM_LEGACY) { - dec_held_monitor_count(temp); - } -#ifdef ASSERT - // Check that unlocked label is reached with flag == EQ. - Label flag_correct; - beq(flag, flag_correct); - stop("compiler_fast_unlock_object: Flag != EQ"); -#endif - bind(failure); -#ifdef ASSERT - // Check that slow_path label is reached with flag == NE. - bne(flag, flag_correct); - stop("compiler_fast_unlock_object: Flag != NE"); - bind(flag_correct); -#endif -} - void MacroAssembler::compiler_fast_lock_lightweight_object(ConditionRegister flag, Register obj, Register box, Register tmp1, Register tmp2, Register tmp3) { assert_different_registers(obj, box, tmp1, tmp2, tmp3); @@ -4769,38 +4537,6 @@ void MacroAssembler::pop_cont_fastpath() { bind(done); } -// Note: Must preserve CR0 EQ (invariant). -void MacroAssembler::inc_held_monitor_count(Register tmp) { - assert(LockingMode == LM_LEGACY, ""); - ld(tmp, in_bytes(JavaThread::held_monitor_count_offset()), R16_thread); -#ifdef ASSERT - Label ok; - cmpdi(CR0, tmp, 0); - bge_predict_taken(CR0, ok); - stop("held monitor count is negativ at increment"); - bind(ok); - crorc(CR0, Assembler::equal, CR0, Assembler::equal); // Restore CR0 EQ -#endif - addi(tmp, tmp, 1); - std(tmp, in_bytes(JavaThread::held_monitor_count_offset()), R16_thread); -} - -// Note: Must preserve CR0 EQ (invariant). -void MacroAssembler::dec_held_monitor_count(Register tmp) { - assert(LockingMode == LM_LEGACY, ""); - ld(tmp, in_bytes(JavaThread::held_monitor_count_offset()), R16_thread); -#ifdef ASSERT - Label ok; - cmpdi(CR0, tmp, 0); - bgt_predict_taken(CR0, ok); - stop("held monitor count is <= 0 at decrement"); - bind(ok); - crorc(CR0, Assembler::equal, CR0, Assembler::equal); // Restore CR0 EQ -#endif - addi(tmp, tmp, -1); - std(tmp, in_bytes(JavaThread::held_monitor_count_offset()), R16_thread); -} - // Function to flip between unlocked and locked state (fast locking). // Branches to failed if the state is not as expected with CR0 NE. // Falls through upon success with CR0 EQ. @@ -4842,7 +4578,6 @@ void MacroAssembler::atomically_flip_locked_state(bool is_unlock, Register obj, // - obj: the object to be locked // - t1, t2: temporary register void MacroAssembler::lightweight_lock(Register box, Register obj, Register t1, Register t2, Label& slow) { - assert(LockingMode == LM_LIGHTWEIGHT, "only used with new lightweight locking"); assert_different_registers(box, obj, t1, t2, R0); Label push; @@ -4899,7 +4634,6 @@ void MacroAssembler::lightweight_lock(Register box, Register obj, Register t1, R // - obj: the object to be unlocked // - t1: temporary register void MacroAssembler::lightweight_unlock(Register obj, Register t1, Label& slow) { - assert(LockingMode == LM_LIGHTWEIGHT, "only used with new lightweight locking"); assert_different_registers(obj, t1); #ifdef ASSERT diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp index 471ebb7459a..63be608094f 100644 --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp @@ -697,8 +697,6 @@ class MacroAssembler: public Assembler { void push_cont_fastpath(); void pop_cont_fastpath(); - void inc_held_monitor_count(Register tmp); - void dec_held_monitor_count(Register tmp); void atomically_flip_locked_state(bool is_unlock, Register obj, Register tmp, Label& failed, int semantics); void lightweight_lock(Register box, Register obj, Register t1, Register t2, Label& slow); void lightweight_unlock(Register obj, Register t1, Label& slow); @@ -715,12 +713,6 @@ class MacroAssembler: public Assembler { enum { trampoline_stub_size = 6 * 4 }; address emit_trampoline_stub(int destination_toc_offset, int insts_call_instruction_offset, Register Rtoc = noreg); - void compiler_fast_lock_object(ConditionRegister flag, Register oop, Register box, - Register tmp1, Register tmp2, Register tmp3); - - void compiler_fast_unlock_object(ConditionRegister flag, Register oop, Register box, - Register tmp1, Register tmp2, Register tmp3); - void compiler_fast_lock_lightweight_object(ConditionRegister flag, Register oop, Register box, Register tmp1, Register tmp2, Register tmp3); diff --git a/src/hotspot/cpu/ppc/ppc.ad b/src/hotspot/cpu/ppc/ppc.ad index bf43ecaba79..cd71e298b7d 100644 --- a/src/hotspot/cpu/ppc/ppc.ad +++ b/src/hotspot/cpu/ppc/ppc.ad @@ -11573,40 +11573,8 @@ instruct partialSubtypeCheckConstSuper(rarg3RegP sub, rarg2RegP super_reg, immP // inlined locking and unlocking -instruct cmpFastLock(flagsRegCR0 crx, iRegPdst oop, iRegPdst box, iRegPdst tmp1, iRegPdst tmp2) %{ - predicate(LockingMode != LM_LIGHTWEIGHT); - match(Set crx (FastLock oop box)); - effect(TEMP tmp1, TEMP tmp2); - - format %{ "FASTLOCK $oop, $box, $tmp1, $tmp2" %} - ins_encode %{ - __ compiler_fast_lock_object($crx$$CondRegister, $oop$$Register, $box$$Register, - $tmp1$$Register, $tmp2$$Register, /*tmp3*/ R0); - // If locking was successful, crx should indicate 'EQ'. - // The compiler generates a branch to the runtime call to - // _complete_monitor_locking_Java for the case where crx is 'NE'. - %} - ins_pipe(pipe_class_compare); -%} - -instruct cmpFastUnlock(flagsRegCR0 crx, iRegPdst oop, iRegPdst box, iRegPdst tmp1, iRegPdst tmp2, iRegPdst tmp3) %{ - predicate(LockingMode != LM_LIGHTWEIGHT); - match(Set crx (FastUnlock oop box)); - effect(TEMP tmp1, TEMP tmp2, TEMP tmp3); - - format %{ "FASTUNLOCK $oop, $box, $tmp1, $tmp2" %} - ins_encode %{ - __ compiler_fast_unlock_object($crx$$CondRegister, $oop$$Register, $box$$Register, - $tmp1$$Register, $tmp2$$Register, $tmp3$$Register); - // If unlocking was successful, crx should indicate 'EQ'. - // The compiler generates a branch to the runtime call to - // _complete_monitor_unlocking_Java for the case where crx is 'NE'. - %} - ins_pipe(pipe_class_compare); -%} - instruct cmpFastLockLightweight(flagsRegCR0 crx, iRegPdst oop, iRegPdst box, iRegPdst tmp1, iRegPdst tmp2) %{ - predicate(LockingMode == LM_LIGHTWEIGHT && !UseObjectMonitorTable); + predicate(!UseObjectMonitorTable); match(Set crx (FastLock oop box)); effect(TEMP tmp1, TEMP tmp2); @@ -11622,7 +11590,7 @@ instruct cmpFastLockLightweight(flagsRegCR0 crx, iRegPdst oop, iRegPdst box, iRe %} instruct cmpFastLockMonitorTable(flagsRegCR0 crx, iRegPdst oop, iRegPdst box, iRegPdst tmp1, iRegPdst tmp2, iRegPdst tmp3, flagsRegCR1 cr1) %{ - predicate(LockingMode == LM_LIGHTWEIGHT && UseObjectMonitorTable); + predicate(UseObjectMonitorTable); match(Set crx (FastLock oop box)); effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr1); @@ -11638,7 +11606,6 @@ instruct cmpFastLockMonitorTable(flagsRegCR0 crx, iRegPdst oop, iRegPdst box, iR %} instruct cmpFastUnlockLightweight(flagsRegCR0 crx, iRegPdst oop, iRegPdst box, iRegPdst tmp1, iRegPdst tmp2, iRegPdst tmp3) %{ - predicate(LockingMode == LM_LIGHTWEIGHT); match(Set crx (FastUnlock oop box)); effect(TEMP tmp1, TEMP tmp2, TEMP tmp3); diff --git a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp index 64bd8dc7812..2a9bad059ba 100644 --- a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp +++ b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp @@ -2446,14 +2446,9 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, __ addi(r_box, R1_SP, lock_offset); // Try fastpath for locking. - if (LockingMode == LM_LIGHTWEIGHT) { - // fast_lock kills r_temp_1, r_temp_2, r_temp_3. - Register r_temp_3_or_noreg = UseObjectMonitorTable ? r_temp_3 : noreg; - __ compiler_fast_lock_lightweight_object(CR0, r_oop, r_box, r_temp_1, r_temp_2, r_temp_3_or_noreg); - } else { - // fast_lock kills r_temp_1, r_temp_2, r_temp_3. - __ compiler_fast_lock_object(CR0, r_oop, r_box, r_temp_1, r_temp_2, r_temp_3); - } + // fast_lock kills r_temp_1, r_temp_2, r_temp_3. + Register r_temp_3_or_noreg = UseObjectMonitorTable ? r_temp_3 : noreg; + __ compiler_fast_lock_lightweight_object(CR0, r_oop, r_box, r_temp_1, r_temp_2, r_temp_3_or_noreg); __ beq(CR0, locked); // None of the above fast optimizations worked so we have to get into the @@ -2620,7 +2615,7 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, __ stw(R0, thread_(thread_state)); // Check preemption for Object.wait() - if (LockingMode != LM_LEGACY && method->is_object_wait0()) { + if (method->is_object_wait0()) { Label not_preempted; __ ld(R0, in_bytes(JavaThread::preempt_alternate_return_offset()), R16_thread); __ cmpdi(CR0, R0, 0); @@ -2672,11 +2667,7 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, __ addi(r_box, R1_SP, lock_offset); // Try fastpath for unlocking. - if (LockingMode == LM_LIGHTWEIGHT) { - __ compiler_fast_unlock_lightweight_object(CR0, r_oop, r_box, r_temp_1, r_temp_2, r_temp_3); - } else { - __ compiler_fast_unlock_object(CR0, r_oop, r_box, r_temp_1, r_temp_2, r_temp_3); - } + __ compiler_fast_unlock_lightweight_object(CR0, r_oop, r_box, r_temp_1, r_temp_2, r_temp_3); __ beq(CR0, done); // Save and restore any potential method result value around the unlocking operation. @@ -2717,7 +2708,7 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, // -------------------------------------------------------------------------- // Last java frame won't be set if we're resuming after preemption - bool maybe_preempted = LockingMode != LM_LEGACY && method->is_object_wait0(); + bool maybe_preempted = method->is_object_wait0(); __ reset_last_Java_frame(!maybe_preempted /* check_last_java_sp */); // Unbox oop result, e.g. JNIHandles::resolve value. diff --git a/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp b/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp index b5f1c76c5da..199b578a36f 100644 --- a/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp +++ b/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp @@ -1362,7 +1362,7 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { // convenient and the slow signature handler can use this same frame // anchor. - bool support_vthread_preemption = Continuations::enabled() && LockingMode != LM_LEGACY; + bool support_vthread_preemption = Continuations::enabled(); // We have a TOP_IJAVA_FRAME here, which belongs to us. Label last_java_pc; From 5febc4e3bb1f47f69fc28c266a775e19cbac9e5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20H=C3=A4ssig?= Date: Thu, 21 Aug 2025 08:23:32 +0000 Subject: [PATCH 14/54] 8365910: [BACKOUT] Add a compilation timeout flag to catch long running compilations Reviewed-by: chagedorn, dholmes --- .../os/linux/compilerThreadTimeout_linux.cpp | 128 ------------------ .../os/linux/compilerThreadTimeout_linux.hpp | 51 ------- src/hotspot/os/linux/globals_linux.hpp | 5 - src/hotspot/share/compiler/compileBroker.cpp | 6 - src/hotspot/share/compiler/compilerThread.cpp | 2 - src/hotspot/share/compiler/compilerThread.hpp | 33 +---- .../arguments/TestCompileTaskTimeout.java | 56 -------- .../jtreg/runtime/signal/TestSigalrm.java | 4 +- 8 files changed, 3 insertions(+), 282 deletions(-) delete mode 100644 src/hotspot/os/linux/compilerThreadTimeout_linux.cpp delete mode 100644 src/hotspot/os/linux/compilerThreadTimeout_linux.hpp delete mode 100644 test/hotspot/jtreg/compiler/arguments/TestCompileTaskTimeout.java diff --git a/src/hotspot/os/linux/compilerThreadTimeout_linux.cpp b/src/hotspot/os/linux/compilerThreadTimeout_linux.cpp deleted file mode 100644 index 609c78616f3..00000000000 --- a/src/hotspot/os/linux/compilerThreadTimeout_linux.cpp +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please 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 "compiler/compilerThread.hpp" -#include "compiler/compileTask.hpp" -#include "compilerThreadTimeout_linux.hpp" -#include "oops/method.hpp" -#include "runtime/osThread.hpp" -#include "signals_posix.hpp" -#include "utilities/globalDefinitions.hpp" - -#include - -#ifdef ASSERT -void compiler_signal_handler(int signo, siginfo_t* info, void* context) { - CompilerThread::current()->timeout()->compiler_signal_handler(signo, info, context); -} - -void CompilerThreadTimeoutLinux::compiler_signal_handler(int signo, siginfo_t* info, void* context) { - switch (signo) { - case TIMEOUT_SIGNAL: { - CompileTask* task = CompilerThread::current()->task(); - const int SIZE = 512; - char method_name_buf[SIZE]; - task->method()->name_and_sig_as_C_string(method_name_buf, SIZE); - assert(false, "compile task %d (%s) timed out after %zd ms", - task->compile_id(), method_name_buf, CompileTaskTimeout); - } - default: { - assert(false, "unexpected signal %d", signo); - } - } -} -#endif // ASSERT - -void CompilerThreadTimeoutLinux::arm() { -#ifdef ASSERT - if (CompileTaskTimeout == 0) { - return; - } - - const intx sec = (CompileTaskTimeout * NANOSECS_PER_MILLISEC) / NANOSECS_PER_SEC; - const intx nsec = (CompileTaskTimeout * NANOSECS_PER_MILLISEC) % NANOSECS_PER_SEC; - const struct timespec ts = {.tv_sec = sec, .tv_nsec = nsec}; - const struct itimerspec its {.it_interval = ts, .it_value = ts}; - - // Start the timer. - timer_settime(_timer, 0, &its, nullptr); -#endif // ASSERT -} - -void CompilerThreadTimeoutLinux::disarm() { -#ifdef ASSERT - if (CompileTaskTimeout == 0) { - return; - } - - // Reset the timer by setting it to zero. - const struct itimerspec its { - .it_interval = {.tv_sec = 0, .tv_nsec=0}, - .it_value = {.tv_sec = 0, .tv_nsec=0} - }; - timer_settime(_timer, 0, &its, nullptr); -#endif // ASSERT -} - -bool CompilerThreadTimeoutLinux::init_timeout() { -#ifdef ASSERT - if (CompileTaskTimeout == 0) { - return true; - } - - JavaThread* thread = JavaThread::current(); - - // Create a POSIX timer sending SIGALRM to this thread only. - sigevent_t sev; - sev.sigev_value.sival_ptr = nullptr; - sev.sigev_signo = TIMEOUT_SIGNAL; - sev.sigev_notify = SIGEV_THREAD_ID; - #ifdef MUSL_LIBC - sev.sigev_notify_thread_id = thread->osthread()->thread_id(); - #else - sev._sigev_un._tid = thread->osthread()->thread_id(); - #endif // MUSL_LIBC - clockid_t clock; - int err = pthread_getcpuclockid(thread->osthread()->pthread_id(), &clock); - if (err != 0) { - return false; - } - err = timer_create(clock, &sev, &_timer); - if (err != 0) { - return false; - } - - // Install the signal handler and check that we do not have a conflicting handler. - struct sigaction sigact, sigact_old; - err = PosixSignals::install_sigaction_signal_handler(&sigact, - &sigact_old, - TIMEOUT_SIGNAL, - (sa_sigaction_t)::compiler_signal_handler); - if (err != 0 || (sigact_old.sa_sigaction != sigact.sa_sigaction && - sigact_old.sa_handler != SIG_DFL && sigact_old.sa_handler != SIG_IGN)) { - return false; - } -#endif // ASSERT - return true; -} diff --git a/src/hotspot/os/linux/compilerThreadTimeout_linux.hpp b/src/hotspot/os/linux/compilerThreadTimeout_linux.hpp deleted file mode 100644 index 2dc6fa7b9c9..00000000000 --- a/src/hotspot/os/linux/compilerThreadTimeout_linux.hpp +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please 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 LINUX_COMPILER_THREAD_TIMEOUT_LINUX_HPP -#define LINUX_COMPILER_THREAD_TIMEOUT_LINUX_HPP - -#include "memory/allocation.hpp" -#include "nmt/memTag.hpp" -#include "utilities/macros.hpp" - -#include -#include - -class CompilerThreadTimeoutLinux : public CHeapObj { -#ifdef ASSERT - public: - static const int TIMEOUT_SIGNAL = SIGALRM; - void compiler_signal_handler(int signo, siginfo_t* info, void* context); - private: - timer_t _timer; -#endif // ASSERT - public: - CompilerThreadTimeoutLinux() DEBUG_ONLY(: _timer(nullptr)) {}; - - bool init_timeout(); - void arm(); - void disarm(); -}; - -#endif //LINUX_COMPILER_THREAD_TIMEOUT_LINUX_HPP diff --git a/src/hotspot/os/linux/globals_linux.hpp b/src/hotspot/os/linux/globals_linux.hpp index 90e1e5e5f3f..542e034f59f 100644 --- a/src/hotspot/os/linux/globals_linux.hpp +++ b/src/hotspot/os/linux/globals_linux.hpp @@ -89,11 +89,6 @@ product(bool, PrintMemoryMapAtExit, false, DIAGNOSTIC, \ "Print an annotated memory map at exit") \ \ - develop(intx, CompileTaskTimeout, 0, \ - "Set the timeout for compile tasks' CPU time in milliseconds."\ - " 0 = no timeout (default)") \ - range(0,1000000) \ - \ // end of RUNTIME_OS_FLAGS // diff --git a/src/hotspot/share/compiler/compileBroker.cpp b/src/hotspot/share/compiler/compileBroker.cpp index 432b0e6a346..36663ab1088 100644 --- a/src/hotspot/share/compiler/compileBroker.cpp +++ b/src/hotspot/share/compiler/compileBroker.cpp @@ -218,7 +218,6 @@ CompileTaskWrapper::CompileTaskWrapper(CompileTask* task) { CompilerThread* thread = CompilerThread::current(); thread->set_task(task); CompileLog* log = thread->log(); - thread->timeout()->arm(); if (log != nullptr && !task->is_unloaded()) task->log_task_start(log); } @@ -229,7 +228,6 @@ CompileTaskWrapper::~CompileTaskWrapper() { if (log != nullptr && !task->is_unloaded()) task->log_task_done(log); thread->set_task(nullptr); thread->set_env(nullptr); - thread->timeout()->disarm(); if (task->is_blocking()) { bool free_task = false; { @@ -1927,10 +1925,6 @@ void CompileBroker::compiler_thread_loop() { log->end_elem(); } - if (!thread->init_compilation_timeout()) { - return; - } - // If compiler thread/runtime initialization fails, exit the compiler thread if (!init_compiler_runtime()) { return; diff --git a/src/hotspot/share/compiler/compilerThread.cpp b/src/hotspot/share/compiler/compilerThread.cpp index 7cf494aad56..4034e63bc10 100644 --- a/src/hotspot/share/compiler/compilerThread.cpp +++ b/src/hotspot/share/compiler/compilerThread.cpp @@ -40,7 +40,6 @@ CompilerThread::CompilerThread(CompileQueue* queue, _can_call_java = false; _compiler = nullptr; _arena_stat = nullptr; - _timeout = nullptr; #ifndef PRODUCT _ideal_graph_printer = nullptr; @@ -50,7 +49,6 @@ CompilerThread::CompilerThread(CompileQueue* queue, CompilerThread::~CompilerThread() { // Delete objects which were allocated on heap. delete _counters; - delete _timeout; // arenastat should have been deleted at the end of the compilation assert(_arena_stat == nullptr, "Should be null"); } diff --git a/src/hotspot/share/compiler/compilerThread.hpp b/src/hotspot/share/compiler/compilerThread.hpp index e4641780a12..e20e3017d1f 100644 --- a/src/hotspot/share/compiler/compilerThread.hpp +++ b/src/hotspot/share/compiler/compilerThread.hpp @@ -25,14 +25,7 @@ #ifndef SHARE_COMPILER_COMPILERTHREAD_HPP #define SHARE_COMPILER_COMPILERTHREAD_HPP -#include "memory/allocation.hpp" -#include "nmt/memTag.hpp" #include "runtime/javaThread.hpp" -#include "utilities/macros.hpp" - -#ifdef LINUX -#include "compilerThreadTimeout_linux.hpp" -#endif //LINUX class AbstractCompiler; class ArenaStatCounter; @@ -45,27 +38,10 @@ class CompileQueue; class CompilerCounters; class IdealGraphPrinter; -#ifndef LINUX -class CompilerThreadTimeoutGeneric : public CHeapObj { - public: - CompilerThreadTimeoutGeneric() {}; - void arm() {}; - void disarm() {}; - bool init_timeout() { return true; }; -}; -#endif // !LINUX - // A thread used for Compilation. class CompilerThread : public JavaThread { friend class VMStructs; JVMCI_ONLY(friend class CompilerThreadCanCallJava;) - -#ifdef LINUX - typedef CompilerThreadTimeoutLinux Timeout; -#else // LINUX - typedef CompilerThreadTimeoutGeneric Timeout; -#endif // LINUX - private: CompilerCounters* _counters; @@ -81,7 +57,6 @@ class CompilerThread : public JavaThread { ArenaStatCounter* _arena_stat; - Timeout* _timeout; public: static CompilerThread* current() { @@ -138,13 +113,7 @@ class CompilerThread : public JavaThread { public: IdealGraphPrinter *ideal_graph_printer() { return _ideal_graph_printer; } void set_ideal_graph_printer(IdealGraphPrinter *n) { _ideal_graph_printer = n; } -#endif // !PRODUCT - - Timeout* timeout() const { return _timeout; }; - bool init_compilation_timeout() { - _timeout = new Timeout(); - return _timeout->init_timeout(); - }; +#endif // Get/set the thread's current task CompileTask* task() { return _task; } diff --git a/test/hotspot/jtreg/compiler/arguments/TestCompileTaskTimeout.java b/test/hotspot/jtreg/compiler/arguments/TestCompileTaskTimeout.java deleted file mode 100644 index 42f13744cae..00000000000 --- a/test/hotspot/jtreg/compiler/arguments/TestCompileTaskTimeout.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2025, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please 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.arguments; - -/* - * @test TestCompileTaskTimeout - * @bug 8308094 - * @requires vm.debug & vm.flagless & os.name == "Linux" - * @summary Check functionality of CompileTaskTimeout - * @library /test/lib - * @run driver compiler.arguments.TestCompileTaskTimeout - */ - -import jdk.test.lib.process.ProcessTools; - -public class TestCompileTaskTimeout { - - public static void main(String[] args) throws Throwable { - ProcessTools.executeTestJava("-Xcomp", "-XX:CompileTaskTimeout=1", "--version") - .shouldHaveExitValue(134) - .shouldContain("timed out after"); - - ProcessTools.executeTestJava("-Xcomp", "-XX:CompileTaskTimeout=1", "-XX:TieredStopAtLevel=3", "--version") - .shouldHaveExitValue(134) - .shouldContain("timed out after"); - - ProcessTools.executeTestJava("-Xcomp", "-XX:CompileTaskTimeout=1", "-XX:-TieredCompilation", "--version") - .shouldHaveExitValue(134) - .shouldContain("timed out after"); - - ProcessTools.executeTestJava("-Xcomp", "-XX:CompileTaskTimeout=200", "--version") - .shouldHaveExitValue(0) - .shouldContain("java version"); - } -} \ No newline at end of file diff --git a/test/hotspot/jtreg/runtime/signal/TestSigalrm.java b/test/hotspot/jtreg/runtime/signal/TestSigalrm.java index 2e485a46cf9..b9a3c3e5060 100644 --- a/test/hotspot/jtreg/runtime/signal/TestSigalrm.java +++ b/test/hotspot/jtreg/runtime/signal/TestSigalrm.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,7 @@ /* * @test - * @requires os.family != "windows" & os.family != "aix" & vm.flagless + * @requires os.family != "windows" & os.family != "aix" * * @summary converted from VM testbase runtime/signal/sigalrm01. * VM testbase keywords: [signal, runtime, linux, macosx] From 5ede5b47d4291a18acc16833978ded038332cf9c Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Thu, 21 Aug 2025 09:18:58 +0000 Subject: [PATCH 15/54] 8364650: G1: Use InvalidCSetIndex instead of UINT_MAX for "invalid" sentinel value of young_index_in_cset Reviewed-by: ayang, iwalulya --- src/hotspot/share/gc/g1/g1HeapRegion.cpp | 2 +- src/hotspot/share/gc/g1/g1HeapRegion.hpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1HeapRegion.cpp b/src/hotspot/share/gc/g1/g1HeapRegion.cpp index 03610ab520b..86b22486517 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegion.cpp +++ b/src/hotspot/share/gc/g1/g1HeapRegion.cpp @@ -245,7 +245,7 @@ G1HeapRegion::G1HeapRegion(uint hrm_index, _parsable_bottom(nullptr), _garbage_bytes(0), _incoming_refs(0), - _young_index_in_cset(-1), + _young_index_in_cset(InvalidCSetIndex), _surv_rate_group(nullptr), _age_index(G1SurvRateGroup::InvalidAgeIndex), _node_index(G1NUMA::UnknownNodeIndex), diff --git a/src/hotspot/share/gc/g1/g1HeapRegion.hpp b/src/hotspot/share/gc/g1/g1HeapRegion.hpp index 1962d3173b7..7d49633d0bc 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegion.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegion.hpp @@ -496,10 +496,10 @@ public: void set_index_in_opt_cset(uint index) { _index_in_opt_cset = index; } void clear_index_in_opt_cset() { _index_in_opt_cset = InvalidCSetIndex; } - uint young_index_in_cset() const { return _young_index_in_cset; } + uint young_index_in_cset() const { return _young_index_in_cset; } void clear_young_index_in_cset() { _young_index_in_cset = 0; } void set_young_index_in_cset(uint index) { - assert(index != UINT_MAX, "just checking"); + assert(index != InvalidCSetIndex, "just checking"); assert(index != 0, "just checking"); assert(is_young(), "pre-condition"); _young_index_in_cset = index; From b735ef99b2285ec55a68896de25d29a02fdfcaf7 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Thu, 21 Aug 2025 09:19:14 +0000 Subject: [PATCH 16/54] 8364925: G1: Improve program flow around incremental collection set building Reviewed-by: ayang, iwalulya --- src/hotspot/share/gc/g1/g1CollectionSet.cpp | 43 +++++++++++++++------ src/hotspot/share/gc/g1/g1CollectionSet.hpp | 16 +++----- 2 files changed, 36 insertions(+), 23 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1CollectionSet.cpp b/src/hotspot/share/gc/g1/g1CollectionSet.cpp index 075951ab07c..747f5664b55 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSet.cpp +++ b/src/hotspot/share/gc/g1/g1CollectionSet.cpp @@ -38,6 +38,15 @@ #include "utilities/globalDefinitions.hpp" #include "utilities/quickSort.hpp" +uint G1CollectionSet::selected_groups_cur_length() const { + assert(_inc_build_state == CSetBuildType::Inactive, "must be"); + return _collection_set_groups.length(); +} + +uint G1CollectionSet::collection_groups_increment_length() const { + return selected_groups_cur_length() - _selected_groups_inc_part_start; +} + G1CollectorState* G1CollectionSet::collector_state() const { return _g1h->collector_state(); } @@ -54,7 +63,6 @@ G1CollectionSet::G1CollectionSet(G1CollectedHeap* g1h, G1Policy* policy) : _collection_set_cur_length(0), _collection_set_max_length(0), _collection_set_groups(), - _selected_groups_cur_length(0), _selected_groups_inc_part_start(0), _eden_region_length(0), _survivor_region_length(0), @@ -122,9 +130,23 @@ void G1CollectionSet::add_old_region(G1HeapRegion* hr) { void G1CollectionSet::start_incremental_building() { assert(_collection_set_cur_length == 0, "Collection set must be empty before starting a new collection set."); + assert(selected_groups_cur_length() == 0, "Collection set groups must be empty before starting a new collection set."); + assert(_optional_groups.length() == 0, "Collection set optional gorups must be empty before starting a new collection set."); + + continue_incremental_building(); +} + +void G1CollectionSet::continue_incremental_building() { assert(_inc_build_state == Inactive, "Precondition"); - update_incremental_marker(); + _inc_part_start = _collection_set_cur_length; + _selected_groups_inc_part_start = selected_groups_cur_length(); + + _inc_build_state = CSetBuildType::Active; +} + +void G1CollectionSet::stop_incremental_building() { + _inc_build_state = Inactive; } void G1CollectionSet::finalize_incremental_building() { @@ -343,9 +365,6 @@ static int compare_region_idx(const uint a, const uint b) { void G1CollectionSet::finalize_old_part(double time_remaining_ms) { double non_young_start_time_sec = os::elapsedTime(); - _selected_groups_cur_length = 0; - _selected_groups_inc_part_start = 0; - if (!candidates()->is_empty()) { candidates()->verify(); @@ -363,13 +382,8 @@ void G1CollectionSet::finalize_old_part(double time_remaining_ms) { log_debug(gc, ergo, cset)("No candidates to reclaim."); } - _selected_groups_cur_length = collection_set_groups()->length(); - stop_incremental_building(); - double non_young_end_time_sec = os::elapsedTime(); phase_times()->record_non_young_cset_choice_time_ms((non_young_end_time_sec - non_young_start_time_sec) * 1000.0); - - QuickSort::sort(_collection_set_regions, _collection_set_cur_length, compare_region_idx); } static void print_finish_message(const char* reason, bool from_marking) { @@ -670,16 +684,21 @@ void G1CollectionSet::add_region_to_collection_set(G1HeapRegion* r) { } void G1CollectionSet::finalize_initial_collection_set(double target_pause_time_ms, G1SurvivorRegions* survivor) { + assert(_inc_part_start == 0, "must be"); + assert(_selected_groups_inc_part_start == 0, "must be"); + double time_remaining_ms = finalize_young_part(target_pause_time_ms, survivor); finalize_old_part(time_remaining_ms); + + stop_incremental_building(); + QuickSort::sort(_collection_set_regions, _collection_set_cur_length, compare_region_idx); } bool G1CollectionSet::finalize_optional_for_evacuation(double remaining_pause_time) { - update_incremental_marker(); + continue_incremental_building(); uint num_regions_selected = select_optional_collection_set_regions(remaining_pause_time); - _selected_groups_cur_length = collection_set_groups()->length(); stop_incremental_building(); _g1h->verify_region_attr_remset_is_tracked(); diff --git a/src/hotspot/share/gc/g1/g1CollectionSet.hpp b/src/hotspot/share/gc/g1/g1CollectionSet.hpp index c703e13a056..963b43d2432 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSet.hpp +++ b/src/hotspot/share/gc/g1/g1CollectionSet.hpp @@ -149,9 +149,7 @@ class G1CollectionSet { // Old gen groups selected for evacuation. G1CSetCandidateGroupList _collection_set_groups; - // Groups are added to the collection set in increments when performing optional evacuations. - // We use the value below to track these increments. - uint _selected_groups_cur_length; + uint selected_groups_cur_length() const; uint _selected_groups_inc_part_start; uint _eden_region_length; @@ -258,14 +256,10 @@ public: // Initialize incremental collection set info. void start_incremental_building(); - // Start a new collection set increment. - void update_incremental_marker() { - _inc_build_state = Active; - _inc_part_start = _collection_set_cur_length; - _selected_groups_inc_part_start = _selected_groups_cur_length; - } + // Start a new collection set increment, continuing the incremental building. + void continue_incremental_building(); // Stop adding regions to the current collection set increment. - void stop_incremental_building() { _inc_build_state = Inactive; } + void stop_incremental_building(); // Iterate over the current collection set increment applying the given G1HeapRegionClosure // from a starting position determined by the given worker id. @@ -276,7 +270,7 @@ public: // Returns the length of the whole current collection set in number of regions size_t cur_length() const { return _collection_set_cur_length; } - uint collection_groups_increment_length() const { return _selected_groups_cur_length - _selected_groups_inc_part_start; } + uint collection_groups_increment_length() const; // Iterate over the entire collection set (all increments calculated so far), applying // the given G1HeapRegionClosure on all of them. From 9439d7630901d3e29141adf46bbe9284b86683f4 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Thu, 21 Aug 2025 09:35:57 +0000 Subject: [PATCH 17/54] 8364532: G1: In liveness tracing, print more significant digits for the liveness value Reviewed-by: ayang, iwalulya --- src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp | 5 ++--- src/hotspot/share/gc/g1/g1CollectionSetCandidates.hpp | 2 +- src/hotspot/share/gc/g1/g1ConcurrentMark.cpp | 5 +++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp b/src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp index 6c13c015eff..63b1d29f535 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp +++ b/src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp @@ -63,10 +63,9 @@ void G1CSetCandidateGroup::calculate_efficiency() { _gc_efficiency = _reclaimable_bytes / predict_group_total_time_ms(); } -size_t G1CSetCandidateGroup::liveness() const { +double G1CSetCandidateGroup::liveness_percent() const { size_t capacity = length() * G1HeapRegion::GrainBytes; - - return (size_t) ceil(((capacity - _reclaimable_bytes) * 100.0) / capacity); + return ((capacity - _reclaimable_bytes) * 100.0) / capacity; } void G1CSetCandidateGroup::clear(bool uninstall_group_cardset) { diff --git a/src/hotspot/share/gc/g1/g1CollectionSetCandidates.hpp b/src/hotspot/share/gc/g1/g1CollectionSetCandidates.hpp index 73421d40ee9..d45fe07cd6e 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSetCandidates.hpp +++ b/src/hotspot/share/gc/g1/g1CollectionSetCandidates.hpp @@ -102,7 +102,7 @@ public: void calculate_efficiency(); - size_t liveness() const; + double liveness_percent() const; // Comparison function to order regions in decreasing GC efficiency order. This // will cause regions with a lot of live objects and large remembered sets to end // up at the end of the list. diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp index c5b8c89e2f0..210d78098b3 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp @@ -2981,6 +2981,7 @@ G1CMTask::G1CMTask(uint worker_id, #define G1PPRL_LEN_FORMAT " " UINT32_FORMAT_W(14) #define G1PPRL_LEN_H_FORMAT " %14s" #define G1PPRL_GID_GCEFF_FORMAT " %14.1f" +#define G1PPRL_GID_LIVENESS_FORMAT " %9.2f" // For summary info #define G1PPRL_SUM_ADDR_FORMAT(tag) " " tag ":" G1PPRL_ADDR_BASE_FORMAT @@ -3114,13 +3115,13 @@ void G1PrintRegionLivenessInfoClosure::log_cset_candidate_group_add_total(G1CSet G1PPRL_GID_FORMAT G1PPRL_LEN_FORMAT G1PPRL_GID_GCEFF_FORMAT - G1PPRL_BYTE_FORMAT + G1PPRL_GID_LIVENESS_FORMAT G1PPRL_BYTE_FORMAT G1PPRL_TYPE_H_FORMAT, group->group_id(), group->length(), group->gc_efficiency(), - group->liveness(), + group->liveness_percent(), group->card_set()->mem_size(), type); _total_remset_bytes += group->card_set()->mem_size(); From f0e706698df5ac199198b252d77d27a05abad1da Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Thu, 21 Aug 2025 09:36:16 +0000 Subject: [PATCH 18/54] 8364414: G1: Use simpler data structure for holding collection set candidates during calculation Reviewed-by: ayang, iwalulya --- .../share/gc/g1/g1CollectionSetCandidates.cpp | 52 ++++------------ .../share/gc/g1/g1CollectionSetCandidates.hpp | 9 +-- .../share/gc/g1/g1CollectionSetChooser.cpp | 60 +++++++++++++------ .../share/gc/g1/g1CollectionSetChooser.hpp | 2 +- 4 files changed, 57 insertions(+), 66 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp b/src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp index 63b1d29f535..2118bf997a7 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp +++ b/src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp @@ -44,12 +44,7 @@ G1CSetCandidateGroup::G1CSetCandidateGroup() : void G1CSetCandidateGroup::add(G1HeapRegion* hr) { G1CollectionSetCandidateInfo c(hr); - add(c); -} - -void G1CSetCandidateGroup::add(G1CollectionSetCandidateInfo& hr_info) { - G1HeapRegion* hr = hr_info._r; - _candidates.append(hr_info); + _candidates.append(c); hr->install_cset_group(this); } @@ -133,31 +128,6 @@ int G1CSetCandidateGroup::compare_gc_efficiency(G1CSetCandidateGroup** gr1, G1CS } } -int G1CollectionSetCandidateInfo::compare_region_gc_efficiency(G1CollectionSetCandidateInfo* ci1, G1CollectionSetCandidateInfo* ci2) { - // Make sure that null entries are moved to the end. - if (ci1->_r == nullptr) { - if (ci2->_r == nullptr) { - return 0; - } else { - return 1; - } - } else if (ci2->_r == nullptr) { - return -1; - } - - G1Policy* p = G1CollectedHeap::heap()->policy(); - double gc_efficiency1 = p->predict_gc_efficiency(ci1->_r); - double gc_efficiency2 = p->predict_gc_efficiency(ci2->_r); - - if (gc_efficiency1 > gc_efficiency2) { - return -1; - } else if (gc_efficiency1 < gc_efficiency2) { - return 1; - } else { - return 0; - } -} - G1CSetCandidateGroupList::G1CSetCandidateGroupList() : _groups(8, mtGC), _num_regions(0) { } void G1CSetCandidateGroupList::append(G1CSetCandidateGroup* group) { @@ -279,9 +249,9 @@ void G1CollectionSetCandidates::sort_marking_by_efficiency() { _from_marking_groups.verify(); } -void G1CollectionSetCandidates::set_candidates_from_marking(G1CollectionSetCandidateInfo* candidate_infos, - uint num_infos) { - if (num_infos == 0) { +void G1CollectionSetCandidates::set_candidates_from_marking(G1HeapRegion** candidates, + uint num_candidates) { + if (num_candidates == 0) { log_debug(gc, ergo, cset) ("No regions selected from marking."); return; } @@ -294,7 +264,7 @@ void G1CollectionSetCandidates::set_candidates_from_marking(G1CollectionSetCandi // the G1MixedGCCountTarget. For the first collection in a Mixed GC cycle, we can add all regions // required to meet this threshold to the same remset group. We are certain these will be collected in // the same MixedGC. - uint group_limit = p->calc_min_old_cset_length(num_infos); + uint group_limit = p->calc_min_old_cset_length(num_candidates); uint num_added_to_group = 0; @@ -303,8 +273,8 @@ void G1CollectionSetCandidates::set_candidates_from_marking(G1CollectionSetCandi current = new G1CSetCandidateGroup(); - for (uint i = 0; i < num_infos; i++) { - G1HeapRegion* r = candidate_infos[i]._r; + for (uint i = 0; i < num_candidates; i++) { + G1HeapRegion* r = candidates[i]; assert(!contains(r), "must not contain region %u", r->hrm_index()); _contains_map[r->hrm_index()] = CandidateOrigin::Marking; @@ -318,16 +288,16 @@ void G1CollectionSetCandidates::set_candidates_from_marking(G1CollectionSetCandi current = new G1CSetCandidateGroup(); num_added_to_group = 0; } - current->add(candidate_infos[i]); + current->add(r); num_added_to_group++; } _from_marking_groups.append(current); - assert(_from_marking_groups.num_regions() == num_infos, "Must be!"); + assert(_from_marking_groups.num_regions() == num_candidates, "Must be!"); - log_debug(gc, ergo, cset) ("Finished creating %u collection groups from %u regions", _from_marking_groups.length(), num_infos); - _last_marking_candidates_length = num_infos; + log_debug(gc, ergo, cset) ("Finished creating %u collection groups from %u regions", _from_marking_groups.length(), num_candidates); + _last_marking_candidates_length = num_candidates; verify(); } diff --git a/src/hotspot/share/gc/g1/g1CollectionSetCandidates.hpp b/src/hotspot/share/gc/g1/g1CollectionSetCandidates.hpp index d45fe07cd6e..02a4d5f6d76 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSetCandidates.hpp +++ b/src/hotspot/share/gc/g1/g1CollectionSetCandidates.hpp @@ -48,8 +48,6 @@ struct G1CollectionSetCandidateInfo { ++_num_unreclaimed; return _num_unreclaimed < G1NumCollectionsKeepPinned; } - - static int compare_region_gc_efficiency(G1CollectionSetCandidateInfo* ci1, G1CollectionSetCandidateInfo* ci2); }; using G1CSetCandidateGroupIterator = GrowableArrayIterator; @@ -91,7 +89,6 @@ public: } void add(G1HeapRegion* hr); - void add(G1CollectionSetCandidateInfo& hr_info); uint length() const { return (uint)_candidates.length(); } @@ -235,10 +232,10 @@ public: void clear(); - // Merge collection set candidates from marking into the current marking list + // Merge collection set candidates from marking into the current marking candidates // (which needs to be empty). - void set_candidates_from_marking(G1CollectionSetCandidateInfo* candidate_infos, - uint num_infos); + void set_candidates_from_marking(G1HeapRegion** candidates, + uint num_candidates); // The most recent length of the list that had been merged last via // set_candidates_from_marking(). Used for calculating minimum collection set // regions. diff --git a/src/hotspot/share/gc/g1/g1CollectionSetChooser.cpp b/src/hotspot/share/gc/g1/g1CollectionSetChooser.cpp index 20d6b125b4d..aa4bd3f1e5b 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSetChooser.cpp +++ b/src/hotspot/share/gc/g1/g1CollectionSetChooser.cpp @@ -31,15 +31,13 @@ #include "utilities/quickSort.hpp" // Determine collection set candidates (from marking): For all regions determine -// whether they should be a collection set candidate, calculate their efficiency, -// sort and put them into the candidates. +// whether they should be a collection set candidate. Calculate their efficiency, +// sort, and put them into the collection set candidates. +// // Threads calculate the GC efficiency of the regions they get to process, and // put them into some work area without sorting. At the end that array is sorted and // moved to the destination. class G1BuildCandidateRegionsTask : public WorkerTask { - - using CandidateInfo = G1CollectionSetCandidateInfo; - // Work area for building the set of collection set candidates. Contains references // to heap regions with their GC efficiencies calculated. To reduce contention // on claiming array elements, worker threads claim parts of this array in chunks; @@ -47,14 +45,40 @@ class G1BuildCandidateRegionsTask : public WorkerTask { // up their chunks completely. // Final sorting will remove them. class G1BuildCandidateArray : public StackObj { - uint const _max_size; uint const _chunk_size; - CandidateInfo* _data; + G1HeapRegion** _data; uint volatile _cur_claim_idx; + static int compare_region_gc_efficiency(G1HeapRegion** rr1, G1HeapRegion** rr2) { + G1HeapRegion* r1 = *rr1; + G1HeapRegion* r2 = *rr2; + // Make sure that null entries are moved to the end. + if (r1 == nullptr) { + if (r2 == nullptr) { + return 0; + } else { + return 1; + } + } else if (r2 == nullptr) { + return -1; + } + + G1Policy* p = G1CollectedHeap::heap()->policy(); + double gc_efficiency1 = p->predict_gc_efficiency(r1); + double gc_efficiency2 = p->predict_gc_efficiency(r2); + + if (gc_efficiency1 > gc_efficiency2) { + return -1; + } else if (gc_efficiency1 < gc_efficiency2) { + return 1; + } else { + return 0; + } + } + // Calculates the maximum array size that will be used. static uint required_array_size(uint num_regions, uint chunk_size, uint num_workers) { uint const max_waste = num_workers * chunk_size; @@ -68,15 +92,15 @@ class G1BuildCandidateRegionsTask : public WorkerTask { G1BuildCandidateArray(uint max_num_regions, uint chunk_size, uint num_workers) : _max_size(required_array_size(max_num_regions, chunk_size, num_workers)), _chunk_size(chunk_size), - _data(NEW_C_HEAP_ARRAY(CandidateInfo, _max_size, mtGC)), + _data(NEW_C_HEAP_ARRAY(G1HeapRegion*, _max_size, mtGC)), _cur_claim_idx(0) { for (uint i = 0; i < _max_size; i++) { - _data[i] = CandidateInfo(); + _data[i] = nullptr; } } ~G1BuildCandidateArray() { - FREE_C_HEAP_ARRAY(CandidateInfo, _data); + FREE_C_HEAP_ARRAY(G1HeapRegion*, _data); } // Claim a new chunk, returning its bounds [from, to[. @@ -92,8 +116,8 @@ class G1BuildCandidateRegionsTask : public WorkerTask { // Set element in array. void set(uint idx, G1HeapRegion* hr) { assert(idx < _max_size, "Index %u out of bounds %u", idx, _max_size); - assert(_data[idx]._r == nullptr, "Value must not have been set."); - _data[idx] = CandidateInfo(hr); + assert(_data[idx] == nullptr, "Value must not have been set."); + _data[idx] = hr; } void sort_by_gc_efficiency() { @@ -101,15 +125,15 @@ class G1BuildCandidateRegionsTask : public WorkerTask { return; } for (uint i = _cur_claim_idx; i < _max_size; i++) { - assert(_data[i]._r == nullptr, "must be"); + assert(_data[i] == nullptr, "must be"); } - qsort(_data, _cur_claim_idx, sizeof(_data[0]), (_sort_Fn)G1CollectionSetCandidateInfo::compare_region_gc_efficiency); + qsort(_data, _cur_claim_idx, sizeof(_data[0]), (_sort_Fn)compare_region_gc_efficiency); for (uint i = _cur_claim_idx; i < _max_size; i++) { - assert(_data[i]._r == nullptr, "must be"); + assert(_data[i] == nullptr, "must be"); } } - CandidateInfo* array() const { return _data; } + G1HeapRegion** array() const { return _data; } }; // Per-region closure. In addition to determining whether a region should be @@ -193,7 +217,7 @@ class G1BuildCandidateRegionsTask : public WorkerTask { // available (for forward progress in evacuation) or the waste accumulated by the // removed regions is above the maximum allowed waste. // Updates number of candidates and reclaimable bytes given. - void prune(CandidateInfo* data) { + void prune(G1HeapRegion** data) { G1Policy* p = G1CollectedHeap::heap()->policy(); uint num_candidates = Atomic::load(&_num_regions_added); @@ -211,7 +235,7 @@ class G1BuildCandidateRegionsTask : public WorkerTask { uint max_to_prune = num_candidates - min_old_cset_length; while (true) { - G1HeapRegion* r = data[num_candidates - num_pruned - 1]._r; + G1HeapRegion* r = data[num_candidates - num_pruned - 1]; size_t const reclaimable = r->reclaimable_bytes(); if (num_pruned >= max_to_prune || wasted_bytes + reclaimable > allowed_waste) { diff --git a/src/hotspot/share/gc/g1/g1CollectionSetChooser.hpp b/src/hotspot/share/gc/g1/g1CollectionSetChooser.hpp index 691017b9d87..cb9727b3413 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSetChooser.hpp +++ b/src/hotspot/share/gc/g1/g1CollectionSetChooser.hpp @@ -38,11 +38,11 @@ class WorkerThreads; class G1CollectionSetChooser : public AllStatic { static uint calculate_work_chunk_size(uint num_workers, uint num_regions); -public: static size_t mixed_gc_live_threshold_bytes() { return G1HeapRegion::GrainBytes * (size_t)G1MixedGCLiveThresholdPercent / 100; } +public: static bool region_occupancy_low_enough_for_evac(size_t live_bytes) { return live_bytes < mixed_gc_live_threshold_bytes(); } From ed260e8cae329a0c077e91ff76d104ee197fb7fd Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Thu, 21 Aug 2025 09:37:34 +0000 Subject: [PATCH 19/54] 8365026: G1: Initialization should start a "full" new collection set Reviewed-by: ayang, kbarrett --- src/hotspot/share/gc/g1/g1CollectedHeap.cpp | 2 ++ src/hotspot/share/gc/g1/g1ConcurrentMark.cpp | 3 ++- src/hotspot/share/gc/g1/g1Policy.cpp | 4 ---- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index e964ecefb18..ed08d43bbbe 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp @@ -1487,6 +1487,8 @@ jint G1CollectedHeap::initialize() { _collection_set.initialize(max_num_regions()); + start_new_collection_set(); + allocation_failure_injector()->reset(); CPUTimeCounters::create_counter(CPUTimeGroups::CPUTimeType::gc_parallel_workers); diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp index 210d78098b3..237704c12a8 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp @@ -1962,7 +1962,8 @@ public: }; void G1ConcurrentMark::verify_no_collection_set_oops() { - assert(SafepointSynchronize::is_at_safepoint(), "should be at a safepoint"); + assert(SafepointSynchronize::is_at_safepoint() || !is_init_completed(), + "should be at a safepoint or initializing"); if (!_g1h->collector_state()->mark_or_rebuild_in_progress()) { return; } diff --git a/src/hotspot/share/gc/g1/g1Policy.cpp b/src/hotspot/share/gc/g1/g1Policy.cpp index bb54d344ca0..53f0a7bf7a6 100644 --- a/src/hotspot/share/gc/g1/g1Policy.cpp +++ b/src/hotspot/share/gc/g1/g1Policy.cpp @@ -97,10 +97,6 @@ void G1Policy::init(G1CollectedHeap* g1h, G1CollectionSet* collection_set) { _free_regions_at_end_of_collection = _g1h->num_free_regions(); update_young_length_bounds(); - - // We immediately start allocating regions placing them in the collection set. - // Initialize the collection set info. - _collection_set->start_incremental_building(); } void G1Policy::record_young_gc_pause_start() { From f61b247fe3a818fc60a61c6f42a676ad94e8e976 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Thu, 21 Aug 2025 09:44:41 +0000 Subject: [PATCH 20/54] 8364962: G1: Inline G1CollectionSet::finalize_incremental_building Reviewed-by: ayang, kbarrett --- src/hotspot/share/gc/g1/g1CollectionSet.cpp | 10 +++------- src/hotspot/share/gc/g1/g1CollectionSet.hpp | 3 --- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1CollectionSet.cpp b/src/hotspot/share/gc/g1/g1CollectionSet.cpp index 747f5664b55..90189cfdf8a 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSet.cpp +++ b/src/hotspot/share/gc/g1/g1CollectionSet.cpp @@ -149,11 +149,6 @@ void G1CollectionSet::stop_incremental_building() { _inc_build_state = Inactive; } -void G1CollectionSet::finalize_incremental_building() { - assert(_inc_build_state == Active, "Precondition"); - assert(SafepointSynchronize::is_at_safepoint(), "should be at a safepoint"); -} - void G1CollectionSet::clear() { assert_at_safepoint_on_vm_thread(); _collection_set_cur_length = 0; @@ -306,9 +301,10 @@ void G1CollectionSet::print(outputStream* st) { // pinned by JNI) to allow faster future evacuation. We already "paid" for this work // when sizing the young generation. double G1CollectionSet::finalize_young_part(double target_pause_time_ms, G1SurvivorRegions* survivors) { - Ticks start_time = Ticks::now(); + assert(_inc_build_state == Active, "Precondition"); + assert(SafepointSynchronize::is_at_safepoint(), "should be at a safepoint"); - finalize_incremental_building(); + Ticks start_time = Ticks::now(); guarantee(target_pause_time_ms > 0.0, "target_pause_time_ms = %1.6lf should be positive", target_pause_time_ms); diff --git a/src/hotspot/share/gc/g1/g1CollectionSet.hpp b/src/hotspot/share/gc/g1/g1CollectionSet.hpp index 963b43d2432..e12f3a82d12 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSet.hpp +++ b/src/hotspot/share/gc/g1/g1CollectionSet.hpp @@ -198,9 +198,6 @@ class G1CollectionSet { // as Eden and calculate a prediction on how long the evacuation of all young regions // will take. double finalize_young_part(double target_pause_time_ms, G1SurvivorRegions* survivors); - // Perform any final calculations on the incremental collection set fields before we - // can use them. - void finalize_incremental_building(); // Select the regions comprising the initial and optional collection set from marking // and retained collection set candidates. From a3fd4248b74ed800ff124cc3e7c259dca36ea446 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Thu, 21 Aug 2025 09:46:02 +0000 Subject: [PATCH 21/54] 8365115: G1: Refactor rem set statistics gather code for group Reviewed-by: kbarrett, ayang --- src/hotspot/share/gc/g1/g1RemSetSummary.cpp | 55 ++++++++++----------- 1 file changed, 25 insertions(+), 30 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1RemSetSummary.cpp b/src/hotspot/share/gc/g1/g1RemSetSummary.cpp index ec876d020ec..cf032bc5d17 100644 --- a/src/hotspot/share/gc/g1/g1RemSetSummary.cpp +++ b/src/hotspot/share/gc/g1/g1RemSetSummary.cpp @@ -268,44 +268,39 @@ public: return false; } - void do_cset_groups() { - G1CollectedHeap* g1h = G1CollectedHeap::heap(); - G1CSetCandidateGroup* young_only_cset_group = g1h->young_regions_cset_group(); - + void accumulate_stats_for_group(G1CSetCandidateGroup* group, G1PerRegionTypeRemSetCounters* gen_counter) { // If the group has only a single region, then stats were accumulated - // during region iteration. - if (young_only_cset_group->length() > 1) { - G1CardSet* young_only_card_set = young_only_cset_group->card_set(); - size_t rs_mem_sz = young_only_card_set->mem_size(); - size_t rs_unused_mem_sz = young_only_card_set->unused_mem_size(); - size_t occupied_cards = young_only_card_set->occupied(); + // during region iteration. Skip these. + if (group->length() > 1) { + G1CardSet* card_set = group->card_set(); - _max_group_cardset_mem_sz = rs_mem_sz; - _max_cardset_mem_sz_group = young_only_cset_group; + size_t rs_mem_sz = card_set->mem_size(); + size_t rs_unused_mem_sz = card_set->unused_mem_size(); + size_t occupied_cards = card_set->occupied(); - // Only update cardset details - _young.add(rs_unused_mem_sz, rs_mem_sz, occupied_cards, 0, 0, false); + if (rs_mem_sz > _max_group_cardset_mem_sz) { + _max_group_cardset_mem_sz = rs_mem_sz; + _max_cardset_mem_sz_group = group; + } + + gen_counter->add(rs_unused_mem_sz, rs_mem_sz, occupied_cards, 0, 0, false); _all.add(rs_unused_mem_sz, rs_mem_sz, occupied_cards, 0, 0, false); } + } + void do_cset_groups() { + G1CollectedHeap* g1h = G1CollectedHeap::heap(); - G1PerRegionTypeRemSetCounters* current = &_old; - for (G1CSetCandidateGroup* group : g1h->policy()->candidates()->from_marking_groups()) { - if (group->length() > 1) { - G1CardSet* group_card_set = group->card_set(); - size_t rs_mem_sz = group_card_set->mem_size(); - size_t rs_unused_mem_sz = group_card_set->unused_mem_size(); - size_t occupied_cards = group_card_set->occupied(); + accumulate_stats_for_group(g1h->young_regions_cset_group(), &_young); - if (rs_mem_sz > _max_group_cardset_mem_sz) { - _max_group_cardset_mem_sz = rs_mem_sz; - _max_cardset_mem_sz_group = group; - } - - // Only update cardset details - _old.add(rs_unused_mem_sz, rs_mem_sz, occupied_cards, 0, 0, false); - _all.add(rs_unused_mem_sz, rs_mem_sz, occupied_cards, 0, 0, false); - } + G1CollectionSetCandidates* candidates = g1h->policy()->candidates(); + for (G1CSetCandidateGroup* group : candidates->from_marking_groups()) { + accumulate_stats_for_group(group, &_old); + } + // Skip gathering statistics for retained regions. Just verify that they have + // the expected amount of regions. + for (G1CSetCandidateGroup* group : candidates->retained_groups()) { + assert(group->length() == 1, "must be"); } } From 02fe095d29994bec28c85beb6bf2a69b0f49b206 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Thu, 21 Aug 2025 11:53:57 +0000 Subject: [PATCH 22/54] 8364934: G1: Rename members of G1CollectionSet Reviewed-by: ayang, kbarrett --- src/hotspot/share/gc/g1/g1CollectedHeap.cpp | 2 +- src/hotspot/share/gc/g1/g1CollectionSet.cpp | 101 +++++++++--------- src/hotspot/share/gc/g1/g1CollectionSet.hpp | 88 ++++++++------- .../share/gc/g1/g1CollectionSet.inline.hpp | 6 +- src/hotspot/share/gc/g1/g1RemSet.cpp | 2 +- src/hotspot/share/gc/g1/g1YoungCollector.cpp | 2 +- .../gc/g1/g1YoungGCPostEvacuateTasks.cpp | 2 +- 7 files changed, 107 insertions(+), 96 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index ed08d43bbbe..e50821e96c1 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp @@ -3159,5 +3159,5 @@ void G1CollectedHeap::finish_codecache_marking_cycle() { void G1CollectedHeap::prepare_group_cardsets_for_scan() { young_regions_cardset()->reset_table_scanner_for_groups(); - collection_set()->prepare_groups_for_scan(); + collection_set()->prepare_for_scan(); } diff --git a/src/hotspot/share/gc/g1/g1CollectionSet.cpp b/src/hotspot/share/gc/g1/g1CollectionSet.cpp index 90189cfdf8a..804ded144bd 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSet.cpp +++ b/src/hotspot/share/gc/g1/g1CollectionSet.cpp @@ -38,13 +38,13 @@ #include "utilities/globalDefinitions.hpp" #include "utilities/quickSort.hpp" -uint G1CollectionSet::selected_groups_cur_length() const { +uint G1CollectionSet::groups_cur_length() const { assert(_inc_build_state == CSetBuildType::Inactive, "must be"); - return _collection_set_groups.length(); + return _groups.length(); } -uint G1CollectionSet::collection_groups_increment_length() const { - return selected_groups_cur_length() - _selected_groups_inc_part_start; +uint G1CollectionSet::groups_increment_length() const { + return groups_cur_length() - _groups_inc_part_start; } G1CollectorState* G1CollectionSet::collector_state() const { @@ -59,21 +59,21 @@ G1CollectionSet::G1CollectionSet(G1CollectedHeap* g1h, G1Policy* policy) : _g1h(g1h), _policy(policy), _candidates(), - _collection_set_regions(nullptr), - _collection_set_cur_length(0), - _collection_set_max_length(0), - _collection_set_groups(), - _selected_groups_inc_part_start(0), + _regions(nullptr), + _regions_max_length(0), + _regions_cur_length(0), + _groups(), _eden_region_length(0), _survivor_region_length(0), _initial_old_region_length(0), _optional_groups(), - _inc_build_state(Inactive), - _inc_part_start(0) { + _inc_build_state(CSetBuildType::Inactive), + _regions_inc_part_start(0), + _groups_inc_part_start(0) { } G1CollectionSet::~G1CollectionSet() { - FREE_C_HEAP_ARRAY(uint, _collection_set_regions); + FREE_C_HEAP_ARRAY(uint, _regions); abandon_all_candidates(); } @@ -84,8 +84,8 @@ void G1CollectionSet::init_region_lengths(uint eden_cset_region_length, _eden_region_length = eden_cset_region_length; _survivor_region_length = survivor_cset_region_length; - assert((size_t)young_region_length() == _collection_set_cur_length, - "Young region length %u should match collection set length %u", young_region_length(), _collection_set_cur_length); + assert((size_t)young_region_length() == _regions_cur_length, + "Young region length %u should match collection set length %u", young_region_length(), _regions_cur_length); _initial_old_region_length = 0; assert(_optional_groups.length() == 0, "Should not have any optional groups yet"); @@ -93,9 +93,9 @@ void G1CollectionSet::init_region_lengths(uint eden_cset_region_length, } void G1CollectionSet::initialize(uint max_region_length) { - guarantee(_collection_set_regions == nullptr, "Must only initialize once."); - _collection_set_max_length = max_region_length; - _collection_set_regions = NEW_C_HEAP_ARRAY(uint, max_region_length, mtGC); + guarantee(_regions == nullptr, "Must only initialize once."); + _regions_max_length = max_region_length; + _regions = NEW_C_HEAP_ARRAY(uint, max_region_length, mtGC); _candidates.initialize(max_region_length); } @@ -105,14 +105,14 @@ void G1CollectionSet::abandon_all_candidates() { _initial_old_region_length = 0; } -void G1CollectionSet::prepare_groups_for_scan () { - collection_set_groups()->prepare_for_scan(); +void G1CollectionSet::prepare_for_scan () { + groups()->prepare_for_scan(); } void G1CollectionSet::add_old_region(G1HeapRegion* hr) { assert_at_safepoint_on_vm_thread(); - assert(_inc_build_state == Active, + assert(_inc_build_state == CSetBuildType::Active, "Precondition, actively building cset or adding optional later on"); assert(hr->is_old(), "the region should be old"); @@ -121,46 +121,46 @@ void G1CollectionSet::add_old_region(G1HeapRegion* hr) { assert(!hr->in_collection_set(), "should not already be in the collection set"); _g1h->register_old_region_with_region_attr(hr); - assert(_collection_set_cur_length < _collection_set_max_length, "Collection set now larger than maximum size."); - _collection_set_regions[_collection_set_cur_length++] = hr->hrm_index(); + assert(_regions_cur_length < _regions_max_length, "Collection set now larger than maximum size."); + _regions[_regions_cur_length++] = hr->hrm_index(); _initial_old_region_length++; _g1h->old_set_remove(hr); } void G1CollectionSet::start_incremental_building() { - assert(_collection_set_cur_length == 0, "Collection set must be empty before starting a new collection set."); - assert(selected_groups_cur_length() == 0, "Collection set groups must be empty before starting a new collection set."); + assert(_regions_cur_length == 0, "Collection set must be empty before starting a new collection set."); + assert(groups_cur_length() == 0, "Collection set groups must be empty before starting a new collection set."); assert(_optional_groups.length() == 0, "Collection set optional gorups must be empty before starting a new collection set."); continue_incremental_building(); } void G1CollectionSet::continue_incremental_building() { - assert(_inc_build_state == Inactive, "Precondition"); + assert(_inc_build_state == CSetBuildType::Inactive, "Precondition"); - _inc_part_start = _collection_set_cur_length; - _selected_groups_inc_part_start = selected_groups_cur_length(); + _regions_inc_part_start = _regions_cur_length; + _groups_inc_part_start = groups_cur_length(); _inc_build_state = CSetBuildType::Active; } void G1CollectionSet::stop_incremental_building() { - _inc_build_state = Inactive; + _inc_build_state = CSetBuildType::Inactive; } void G1CollectionSet::clear() { assert_at_safepoint_on_vm_thread(); - _collection_set_cur_length = 0; - _collection_set_groups.clear(); + _regions_cur_length = 0; + _groups.clear(); } void G1CollectionSet::iterate(G1HeapRegionClosure* cl) const { - size_t len = _collection_set_cur_length; + size_t len = _regions_cur_length; OrderAccess::loadload(); for (uint i = 0; i < len; i++) { - G1HeapRegion* r = _g1h->region_at(_collection_set_regions[i]); + G1HeapRegion* r = _g1h->region_at(_regions[i]); bool result = cl->do_heap_region(r); if (result) { cl->set_incomplete(); @@ -187,7 +187,7 @@ void G1CollectionSet::iterate_optional(G1HeapRegionClosure* cl) const { void G1CollectionSet::iterate_incremental_part_from(G1HeapRegionClosure* cl, G1HeapRegionClaimer* hr_claimer, uint worker_id) const { - iterate_part_from(cl, hr_claimer, _inc_part_start, increment_length(), worker_id); + iterate_part_from(cl, hr_claimer, _regions_inc_part_start, regions_cur_length(), worker_id); } void G1CollectionSet::iterate_part_from(G1HeapRegionClosure* cl, @@ -197,29 +197,29 @@ void G1CollectionSet::iterate_part_from(G1HeapRegionClosure* cl, uint worker_id) const { _g1h->par_iterate_regions_array(cl, hr_claimer, - &_collection_set_regions[offset], + &_regions[offset], length, worker_id); } void G1CollectionSet::add_young_region_common(G1HeapRegion* hr) { assert(hr->is_young(), "invariant"); - assert(_inc_build_state == Active, "Precondition"); + assert(_inc_build_state == CSetBuildType::Active, "Precondition"); assert(!hr->in_collection_set(), "invariant"); _g1h->register_young_region_with_region_attr(hr); // We use UINT_MAX as "invalid" marker in verification. - assert(_collection_set_cur_length < (UINT_MAX - 1), - "Collection set is too large with %u entries", _collection_set_cur_length); - hr->set_young_index_in_cset(_collection_set_cur_length + 1); + assert(_regions_cur_length < (UINT_MAX - 1), + "Collection set is too large with %u entries", _regions_cur_length); + hr->set_young_index_in_cset(_regions_cur_length + 1); - assert(_collection_set_cur_length < _collection_set_max_length, "Collection set larger than maximum allowed."); - _collection_set_regions[_collection_set_cur_length] = hr->hrm_index(); + assert(_regions_cur_length < _regions_max_length, "Collection set larger than maximum allowed."); + _regions[_regions_cur_length] = hr->hrm_index(); // Concurrent readers must observe the store of the value in the array before an // update to the length field. OrderAccess::storestore(); - _collection_set_cur_length++; + _regions_cur_length++; } void G1CollectionSet::add_survivor_regions(G1HeapRegion* hr) { @@ -301,7 +301,7 @@ void G1CollectionSet::print(outputStream* st) { // pinned by JNI) to allow faster future evacuation. We already "paid" for this work // when sizing the young generation. double G1CollectionSet::finalize_young_part(double target_pause_time_ms, G1SurvivorRegions* survivors) { - assert(_inc_build_state == Active, "Precondition"); + assert(_inc_build_state == CSetBuildType::Active, "Precondition"); assert(SafepointSynchronize::is_at_safepoint(), "should be at a safepoint"); Ticks start_time = Ticks::now(); @@ -626,7 +626,8 @@ double G1CollectionSet::select_candidates_from_optional_groups(double time_remai selected.append(group); } - log_debug(gc, ergo, cset) ("Completed with groups, selected %u", num_regions_selected); + log_debug(gc, ergo, cset)("Completed with groups, selected %u region in %u groups", + num_regions_selected, num_groups_selected); // Remove selected groups from candidate list. if (num_groups_selected > 0) { _optional_groups.remove(&selected); @@ -635,7 +636,7 @@ double G1CollectionSet::select_candidates_from_optional_groups(double time_remai return total_prediction_ms; } -uint G1CollectionSet::select_optional_collection_set_regions(double time_remaining_ms) { +uint G1CollectionSet::select_optional_groups(double time_remaining_ms) { uint optional_regions_count = num_optional_regions(); assert(optional_regions_count > 0, "Should only be called when there are optional regions"); @@ -670,7 +671,7 @@ void G1CollectionSet::add_group_to_collection_set(G1CSetCandidateGroup* gr) { assert(r->rem_set()->is_complete(), "must be"); add_region_to_collection_set(r); } - _collection_set_groups.append(gr); + _groups.append(gr); } void G1CollectionSet::add_region_to_collection_set(G1HeapRegion* r) { @@ -680,20 +681,20 @@ void G1CollectionSet::add_region_to_collection_set(G1HeapRegion* r) { } void G1CollectionSet::finalize_initial_collection_set(double target_pause_time_ms, G1SurvivorRegions* survivor) { - assert(_inc_part_start == 0, "must be"); - assert(_selected_groups_inc_part_start == 0, "must be"); + assert(_regions_inc_part_start == 0, "must be"); + assert(_groups_inc_part_start == 0, "must be"); double time_remaining_ms = finalize_young_part(target_pause_time_ms, survivor); finalize_old_part(time_remaining_ms); stop_incremental_building(); - QuickSort::sort(_collection_set_regions, _collection_set_cur_length, compare_region_idx); + QuickSort::sort(_regions, _regions_cur_length, compare_region_idx); } bool G1CollectionSet::finalize_optional_for_evacuation(double remaining_pause_time) { continue_incremental_building(); - uint num_regions_selected = select_optional_collection_set_regions(remaining_pause_time); + uint num_regions_selected = select_optional_groups(remaining_pause_time); stop_incremental_building(); @@ -756,7 +757,7 @@ public: void G1CollectionSet::verify_young_cset_indices() const { assert_at_safepoint_on_vm_thread(); - G1VerifyYoungCSetIndicesClosure cl(_collection_set_cur_length); + G1VerifyYoungCSetIndicesClosure cl(_regions_cur_length); iterate(&cl); } #endif diff --git a/src/hotspot/share/gc/g1/g1CollectionSet.hpp b/src/hotspot/share/gc/g1/g1CollectionSet.hpp index e12f3a82d12..2bde960fbc4 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSet.hpp +++ b/src/hotspot/share/gc/g1/g1CollectionSet.hpp @@ -41,19 +41,19 @@ class G1HeapRegionClosure; // The collection set. // -// The set of regions that are evacuated during an evacuation pause. +// The set of regions and candidate groups that were evacuated during an +// evacuation pause. // -// At the end of a collection, before freeing the collection set, this set -// contains all regions that were evacuated during this collection: +// At the end of a collection, before freeing it, this set contains all regions +// and collection set groups that were evacuated during this collection: // // - survivor regions from the last collection (if any) // - eden regions allocated by the mutator // - old gen regions evacuated during mixed gc // -// This set is built incrementally at mutator time as regions are retired, and -// if this had been a mixed gc, some additional (during gc) incrementally added -// old regions from the collection set candidates built during the concurrent -// cycle. +// This set is initially built at mutator time as regions are retired. If the +// collection is a mixed gc, it contains some additional (during the pause) +// incrementally added old regions from the collection set candidates. // // A more detailed overview of how the collection set changes over time follows: // @@ -129,6 +129,7 @@ class G1HeapRegionClosure; // || ... after step b6) // |SSS| ... after step 7), with three survivor regions // +// Candidate groups are kept in sync with the contents of the collection set regions. class G1CollectionSet { G1CollectedHeap* _g1h; G1Policy* _policy; @@ -137,46 +138,52 @@ class G1CollectionSet { G1CollectionSetCandidates _candidates; // The actual collection set as a set of region indices. - // All entries in _collection_set_regions below _collection_set_cur_length are - // assumed to be part of the collection set. + // + // All regions in _regions below _regions_cur_length are assumed to be part of the + // collection set. // We assume that at any time there is at most only one writer and (one or more) - // concurrent readers. This means we are good with using storestore and loadload - // barriers on the writer and reader respectively only. - uint* _collection_set_regions; - volatile uint _collection_set_cur_length; - uint _collection_set_max_length; + // concurrent readers. This means synchronization using storestore and loadload + // barriers on the writer and reader respectively only are sufficient. + // + // This corresponds to the regions referenced by the candidate groups further below. + uint* _regions; + uint _regions_max_length; + + volatile uint _regions_cur_length; // Old gen groups selected for evacuation. - G1CSetCandidateGroupList _collection_set_groups; + G1CSetCandidateGroupList _groups; - uint selected_groups_cur_length() const; - uint _selected_groups_inc_part_start; + uint groups_cur_length() const; uint _eden_region_length; uint _survivor_region_length; uint _initial_old_region_length; // When doing mixed collections we can add old regions to the collection set, which - // will be collected only if there is enough time. We call these optional (old) regions. + // will be collected only if there is enough time. We call these optional (old) + // groups. Regions are reachable via this list as well. G1CSetCandidateGroupList _optional_groups; - enum CSetBuildType { + enum class CSetBuildType { Active, // We are actively building the collection set Inactive // We are not actively building the collection set }; CSetBuildType _inc_build_state; - size_t _inc_part_start; + // Index into the _regions indicating the start of the current collection set increment. + size_t _regions_inc_part_start; + // Index into the _groups indicating the start of the current collection set increment. + uint _groups_inc_part_start; G1CollectorState* collector_state() const; G1GCPhaseTimes* phase_times(); void verify_young_cset_indices() const NOT_DEBUG_RETURN; - // Update the incremental collection set information when adding a region. void add_young_region_common(G1HeapRegion* hr); - // Add the given old region to the head of the current collection set. + // Add the given old region to the current collection set. void add_old_region(G1HeapRegion* hr); void prepare_optional_group(G1CSetCandidateGroup* gr, uint cur_index); @@ -189,14 +196,14 @@ class G1CollectionSet { void select_candidates_from_retained(double time_remaining_ms); - // Select regions for evacuation from the optional candidates given the remaining time - // and return the number of actually selected regions. - uint select_optional_collection_set_regions(double time_remaining_ms); - double select_candidates_from_optional_groups(double time_remaining_ms, uint& num_regions_selected); + // Select groups for evacuation from the optional candidates given the remaining time + // and return the number of actually selected regions. + uint select_optional_groups(double time_remaining_ms); + double select_candidates_from_optional_groups(double time_remaining_ms, uint& num_groups_selected); // Finalize the young part of the initial collection set. Relabel survivor regions // as Eden and calculate a prediction on how long the evacuation of all young regions - // will take. + // will take. Returns the time remaining from the given target pause time. double finalize_young_part(double target_pause_time_ms, G1SurvivorRegions* survivors); // Select the regions comprising the initial and optional collection set from marking @@ -218,27 +225,29 @@ public: // Initializes the collection set giving the maximum possible length of the collection set. void initialize(uint max_region_length); + // Drop all collection set candidates (only the candidates). void abandon_all_candidates(); G1CollectionSetCandidates* candidates() { return &_candidates; } const G1CollectionSetCandidates* candidates() const { return &_candidates; } - G1CSetCandidateGroupList* collection_set_groups() { return &_collection_set_groups; } - const G1CSetCandidateGroupList* collection_set_groups() const { return &_collection_set_groups; } + G1CSetCandidateGroupList* groups() { return &_groups; } + const G1CSetCandidateGroupList* groups() const { return &_groups; } - void prepare_groups_for_scan(); + void prepare_for_scan(); void init_region_lengths(uint eden_cset_region_length, uint survivor_cset_region_length); - uint region_length() const { return young_region_length() + - initial_old_region_length(); } + // Total length of the initial collection set in regions. + uint initial_region_length() const { return young_region_length() + + initial_old_region_length(); } uint young_region_length() const { return eden_region_length() + survivor_region_length(); } - uint eden_region_length() const { return _eden_region_length; } + uint eden_region_length() const { return _eden_region_length; } uint survivor_region_length() const { return _survivor_region_length; } - uint initial_old_region_length() const { return _initial_old_region_length; } + uint initial_old_region_length() const { return _initial_old_region_length; } uint num_optional_regions() const { return _optional_groups.num_regions(); } bool only_contains_young_regions() const { return (initial_old_region_length() + num_optional_regions()) == 0; } @@ -263,14 +272,14 @@ public: void iterate_incremental_part_from(G1HeapRegionClosure* cl, G1HeapRegionClaimer* hr_claimer, uint worker_id) const; // Returns the length of the current increment in number of regions. - size_t increment_length() const { return _collection_set_cur_length - _inc_part_start; } + size_t regions_cur_length() const { return _regions_cur_length - _regions_inc_part_start; } // Returns the length of the whole current collection set in number of regions - size_t cur_length() const { return _collection_set_cur_length; } + size_t cur_length() const { return _regions_cur_length; } - uint collection_groups_increment_length() const; + uint groups_increment_length() const; // Iterate over the entire collection set (all increments calculated so far), applying - // the given G1HeapRegionClosure on all of them. + // the given G1HeapRegionClosure on all of the regions. void iterate(G1HeapRegionClosure* cl) const; void par_iterate(G1HeapRegionClosure* cl, G1HeapRegionClaimer* hr_claimer, @@ -278,10 +287,11 @@ public: void iterate_optional(G1HeapRegionClosure* cl) const; - // Finalize the initial collection set consisting of all young regions potentially a + // Finalize the initial collection set consisting of all young regions and potentially a // few old gen regions. void finalize_initial_collection_set(double target_pause_time_ms, G1SurvivorRegions* survivor); // Finalize the next collection set from the set of available optional old gen regions. + // Returns whether there still were some optional regions. bool finalize_optional_for_evacuation(double remaining_pause_time); // Abandon (clean up) optional collection set regions that were not evacuated in this // pause. diff --git a/src/hotspot/share/gc/g1/g1CollectionSet.inline.hpp b/src/hotspot/share/gc/g1/g1CollectionSet.inline.hpp index 717f6860eb6..0f166cdf9ff 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSet.inline.hpp +++ b/src/hotspot/share/gc/g1/g1CollectionSet.inline.hpp @@ -31,8 +31,8 @@ template inline void G1CollectionSet::merge_cardsets_for_collection_groups(CardOrRangeVisitor& cl, uint worker_id, uint num_workers) { - uint length = collection_groups_increment_length(); - uint offset = _selected_groups_inc_part_start; + uint length = groups_increment_length(); + uint offset = _groups_inc_part_start; if (length == 0) { return; } @@ -41,7 +41,7 @@ inline void G1CollectionSet::merge_cardsets_for_collection_groups(CardOrRangeVis uint cur_pos = start_pos; uint count = 0; do { - G1HeapRegionRemSet::iterate_for_merge(collection_set_groups()->at(offset + cur_pos)->card_set(), cl); + G1HeapRegionRemSet::iterate_for_merge(groups()->at(offset + cur_pos)->card_set(), cl); cur_pos++; count++; if (cur_pos == length) { diff --git a/src/hotspot/share/gc/g1/g1RemSet.cpp b/src/hotspot/share/gc/g1/g1RemSet.cpp index 44b3234d26b..6b7532a99aa 100644 --- a/src/hotspot/share/gc/g1/g1RemSet.cpp +++ b/src/hotspot/share/gc/g1/g1RemSet.cpp @@ -1426,7 +1426,7 @@ void G1RemSet::merge_heap_roots(bool initial_evacuation) { } WorkerThreads* workers = g1h->workers(); - size_t const increment_length = g1h->collection_set()->increment_length(); + size_t const increment_length = g1h->collection_set()->regions_cur_length(); uint const num_workers = initial_evacuation ? workers->active_workers() : MIN2(workers->active_workers(), (uint)increment_length); diff --git a/src/hotspot/share/gc/g1/g1YoungCollector.cpp b/src/hotspot/share/gc/g1/g1YoungCollector.cpp index c61c766bbdc..29eab44d4a8 100644 --- a/src/hotspot/share/gc/g1/g1YoungCollector.cpp +++ b/src/hotspot/share/gc/g1/g1YoungCollector.cpp @@ -271,7 +271,7 @@ void G1YoungCollector::calculate_collection_set(G1EvacInfo* evacuation_info, dou allocator()->release_mutator_alloc_regions(); collection_set()->finalize_initial_collection_set(target_pause_time_ms, survivor_regions()); - evacuation_info->set_collection_set_regions(collection_set()->region_length() + + evacuation_info->set_collection_set_regions(collection_set()->initial_region_length() + collection_set()->num_optional_regions()); concurrent_mark()->verify_no_collection_set_oops(); diff --git a/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp b/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp index bb567e2af5c..b13e7b8a62f 100644 --- a/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp +++ b/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp @@ -887,7 +887,7 @@ public: p->record_serial_free_cset_time_ms((Ticks::now() - serial_time).seconds() * 1000.0); } - double worker_cost() const override { return G1CollectedHeap::heap()->collection_set()->region_length(); } + double worker_cost() const override { return G1CollectedHeap::heap()->collection_set()->initial_region_length(); } void set_max_workers(uint max_workers) override { _active_workers = max_workers; From 1548ac4f54edbd370aa071fa1db4474574d2987f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20H=C3=BCbner?= Date: Thu, 21 Aug 2025 14:00:18 +0000 Subject: [PATCH 23/54] 8365378: Redundant code in Deoptimization::print_statistics Reviewed-by: jsjolen, coleenp --- src/hotspot/share/runtime/deoptimization.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/hotspot/share/runtime/deoptimization.cpp b/src/hotspot/share/runtime/deoptimization.cpp index 243903ed233..dd8ee7c93fa 100644 --- a/src/hotspot/share/runtime/deoptimization.cpp +++ b/src/hotspot/share/runtime/deoptimization.cpp @@ -2926,8 +2926,6 @@ void Deoptimization::print_statistics() { if (counter != 0) { char name[1*K]; Bytecodes::Code bc = (Bytecodes::Code)(counter & LSB_MASK); - if (bc_case == BC_CASE_LIMIT && (int)bc == 0) - bc = Bytecodes::_illegal; os::snprintf_checked(name, sizeof(name), "%s/%s/%s", trap_reason_name(reason), trap_action_name(action), From fb651fd6d246e69b42363e050eb8d96afb633eed Mon Sep 17 00:00:00 2001 From: Jonas Norlinder Date: Thu, 21 Aug 2025 14:05:36 +0000 Subject: [PATCH 24/54] 8364638: Refactor and make accumulated GC CPU time code generic Reviewed-by: ayang, sjohanss --- src/hotspot/share/gc/shared/collectedHeap.cpp | 55 ------------ src/hotspot/share/gc/shared/collectedHeap.hpp | 6 +- .../gc/shared/stringdedup/stringDedup.hpp | 4 +- .../stringdedup/stringDedupProcessor.hpp | 4 +- src/hotspot/share/memory/universe.cpp | 59 +++++++++++++ src/hotspot/share/memory/universe.hpp | 2 + src/hotspot/share/runtime/java.cpp | 14 +--- src/hotspot/share/runtime/vmThread.cpp | 4 +- src/hotspot/share/runtime/vmThread.hpp | 2 +- src/hotspot/share/services/cpuTimeUsage.cpp | 84 +++++++++++++++++++ src/hotspot/share/services/cpuTimeUsage.hpp | 50 +++++++++++ 11 files changed, 205 insertions(+), 79 deletions(-) create mode 100644 src/hotspot/share/services/cpuTimeUsage.cpp create mode 100644 src/hotspot/share/services/cpuTimeUsage.hpp diff --git a/src/hotspot/share/gc/shared/collectedHeap.cpp b/src/hotspot/share/gc/shared/collectedHeap.cpp index b636e3890d3..e82ec1439ea 100644 --- a/src/hotspot/share/gc/shared/collectedHeap.cpp +++ b/src/hotspot/share/gc/shared/collectedHeap.cpp @@ -201,34 +201,6 @@ void CollectedHeap::print_relative_to_gc(GCWhen::Type when) const { } } -class CPUTimeThreadClosure : public ThreadClosure { -private: - jlong _cpu_time = 0; - -public: - virtual void do_thread(Thread* thread) { - jlong cpu_time = os::thread_cpu_time(thread); - if (cpu_time != -1) { - _cpu_time += cpu_time; - } - } - jlong cpu_time() { return _cpu_time; }; -}; - -double CollectedHeap::elapsed_gc_cpu_time() const { - double string_dedup_cpu_time = UseStringDeduplication ? - os::thread_cpu_time((Thread*)StringDedup::_processor->_thread) : 0; - - if (string_dedup_cpu_time == -1) { - string_dedup_cpu_time = 0; - } - - CPUTimeThreadClosure cl; - gc_threads_do(&cl); - - return (double)(cl.cpu_time() + _vmthread_cpu_time + string_dedup_cpu_time) / NANOSECS_PER_SEC; -} - void CollectedHeap::print_before_gc() const { print_relative_to_gc(GCWhen::BeforeGC); } @@ -633,36 +605,9 @@ void CollectedHeap::post_initialize() { initialize_serviceability(); } -void CollectedHeap::log_gc_cpu_time() const { - LogTarget(Info, gc, cpu) out; - if (os::is_thread_cpu_time_supported() && out.is_enabled()) { - double process_cpu_time = os::elapsed_process_cpu_time(); - double gc_cpu_time = elapsed_gc_cpu_time(); - - if (process_cpu_time == -1 || gc_cpu_time == -1) { - log_warning(gc, cpu)("Could not sample CPU time"); - return; - } - - double usage; - if (gc_cpu_time > process_cpu_time || - process_cpu_time == 0 || gc_cpu_time == 0) { - // This can happen e.g. for short running processes with - // low CPU utilization - usage = 0; - } else { - usage = 100 * gc_cpu_time / process_cpu_time; - } - out.print("GC CPU usage: %.2f%% (Process: %.4fs GC: %.4fs)", usage, process_cpu_time, gc_cpu_time); - } -} - void CollectedHeap::before_exit() { print_tracing_info(); - // Log GC CPU usage. - log_gc_cpu_time(); - // Stop any on-going concurrent work and prepare for exit. stop(); } diff --git a/src/hotspot/share/gc/shared/collectedHeap.hpp b/src/hotspot/share/gc/shared/collectedHeap.hpp index 621f3a0bbc7..33d2fad8bba 100644 --- a/src/hotspot/share/gc/shared/collectedHeap.hpp +++ b/src/hotspot/share/gc/shared/collectedHeap.hpp @@ -36,6 +36,7 @@ #include "runtime/handles.hpp" #include "runtime/perfDataTypes.hpp" #include "runtime/safepoint.hpp" +#include "services/cpuTimeUsage.hpp" #include "services/memoryUsage.hpp" #include "utilities/debug.hpp" #include "utilities/formatBuffer.hpp" @@ -89,6 +90,7 @@ public: // ZCollectedHeap // class CollectedHeap : public CHeapObj { + friend class CPUTimeUsage::GC; friend class VMStructs; friend class JVMCIVMStructs; friend class IsSTWGCActiveMark; // Block structured external access to _is_stw_gc_active @@ -429,8 +431,6 @@ protected: void print_relative_to_gc(GCWhen::Type when) const; - void log_gc_cpu_time() const; - public: void pre_full_gc_dump(GCTimer* timer); void post_full_gc_dump(GCTimer* timer); @@ -463,8 +463,6 @@ protected: // Iterator for all GC threads (other than VM thread) virtual void gc_threads_do(ThreadClosure* tc) const = 0; - double elapsed_gc_cpu_time() const; - void print_before_gc() const; void print_after_gc() const; diff --git a/src/hotspot/share/gc/shared/stringdedup/stringDedup.hpp b/src/hotspot/share/gc/shared/stringdedup/stringDedup.hpp index 43cb513df33..24d17d7d45b 100644 --- a/src/hotspot/share/gc/shared/stringdedup/stringDedup.hpp +++ b/src/hotspot/share/gc/shared/stringdedup/stringDedup.hpp @@ -103,9 +103,9 @@ #include "memory/allocation.hpp" #include "memory/allStatic.hpp" #include "oops/oopsHierarchy.hpp" +#include "services/cpuTimeUsage.hpp" #include "utilities/globalDefinitions.hpp" -class CollectedHeap; class Klass; class StringDedupThread; class ThreadClosure; @@ -116,7 +116,7 @@ class ThreadClosure; // feature. Other functions in the StringDedup class are called where // needed, without requiring GC-specific code. class StringDedup : public AllStatic { - friend class CollectedHeap; + friend class CPUTimeUsage::GC; friend class StringDedupThread; class Config; diff --git a/src/hotspot/share/gc/shared/stringdedup/stringDedupProcessor.hpp b/src/hotspot/share/gc/shared/stringdedup/stringDedupProcessor.hpp index 5d3929c5817..7e5e64df9b4 100644 --- a/src/hotspot/share/gc/shared/stringdedup/stringDedupProcessor.hpp +++ b/src/hotspot/share/gc/shared/stringdedup/stringDedupProcessor.hpp @@ -27,9 +27,9 @@ #include "gc/shared/stringdedup/stringDedup.hpp" #include "memory/allocation.hpp" +#include "services/cpuTimeUsage.hpp" #include "utilities/macros.hpp" -class CollectedHeap; class JavaThread; class OopStorage; @@ -43,7 +43,7 @@ class OopStorage; // incremental operations for resizing and for removing dead entries, so // safepoint checks can be performed between steps in those operations. class StringDedup::Processor : public CHeapObj { - friend class CollectedHeap; + friend class CPUTimeUsage::GC; Processor(); ~Processor() = default; diff --git a/src/hotspot/share/memory/universe.cpp b/src/hotspot/share/memory/universe.cpp index bd47a054bc0..8afa17b0b3d 100644 --- a/src/hotspot/share/memory/universe.cpp +++ b/src/hotspot/share/memory/universe.cpp @@ -81,11 +81,13 @@ #include "runtime/threads.hpp" #include "runtime/timerTrace.hpp" #include "sanitizers/leak.hpp" +#include "services/cpuTimeUsage.hpp" #include "services/memoryService.hpp" #include "utilities/align.hpp" #include "utilities/autoRestore.hpp" #include "utilities/debug.hpp" #include "utilities/formatBuffer.hpp" +#include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" #include "utilities/ostream.hpp" #include "utilities/preserveException.hpp" @@ -1300,6 +1302,63 @@ void Universe::verify(VerifyOption option, const char* prefix) { } } +static void log_cpu_time() { + LogTarget(Info, cpu) cpuLog; + if (!cpuLog.is_enabled()) { + return; + } + + const double process_cpu_time = os::elapsed_process_cpu_time(); + if (process_cpu_time == 0 || process_cpu_time == -1) { + // 0 can happen e.g. for short running processes with + // low CPU utilization + return; + } + + const double gc_threads_cpu_time = (double) CPUTimeUsage::GC::gc_threads() / NANOSECS_PER_SEC; + const double gc_vm_thread_cpu_time = (double) CPUTimeUsage::GC::vm_thread() / NANOSECS_PER_SEC; + const double gc_string_dedup_cpu_time = (double) CPUTimeUsage::GC::stringdedup() / NANOSECS_PER_SEC; + const double gc_cpu_time = (double) gc_threads_cpu_time + gc_vm_thread_cpu_time + gc_string_dedup_cpu_time; + + const double elasped_time = os::elapsedTime(); + const bool has_error = CPUTimeUsage::Error::has_error(); + + if (gc_cpu_time < process_cpu_time) { + cpuLog.print("=== CPU time Statistics ============================================================="); + if (has_error) { + cpuLog.print("WARNING: CPU time sampling reported errors, numbers may be unreliable"); + } + cpuLog.print(" CPUs"); + cpuLog.print(" s %% utilized"); + cpuLog.print(" Process"); + cpuLog.print(" Total %30.4f %6.2f %8.1f", process_cpu_time, 100.0, process_cpu_time / elasped_time); + cpuLog.print(" Garbage Collection %30.4f %6.2f %8.1f", gc_cpu_time, percent_of(gc_cpu_time, process_cpu_time), gc_cpu_time / elasped_time); + cpuLog.print(" GC Threads %30.4f %6.2f %8.1f", gc_threads_cpu_time, percent_of(gc_threads_cpu_time, process_cpu_time), gc_threads_cpu_time / elasped_time); + cpuLog.print(" VM Thread %30.4f %6.2f %8.1f", gc_vm_thread_cpu_time, percent_of(gc_vm_thread_cpu_time, process_cpu_time), gc_vm_thread_cpu_time / elasped_time); + + if (UseStringDeduplication) { + cpuLog.print(" String Deduplication %30.4f %6.2f %8.1f", gc_string_dedup_cpu_time, percent_of(gc_string_dedup_cpu_time, process_cpu_time), gc_string_dedup_cpu_time / elasped_time); + } + cpuLog.print("====================================================================================="); + } +} + +void Universe::before_exit() { + log_cpu_time(); + heap()->before_exit(); + + // Print GC/heap related information. + Log(gc, exit) log; + if (log.is_info()) { + LogStream ls_info(log.info()); + Universe::print_on(&ls_info); + if (log.is_trace()) { + LogStream ls_trace(log.trace()); + MutexLocker mcld(ClassLoaderDataGraph_lock); + ClassLoaderDataGraph::print_on(&ls_trace); + } + } +} #ifndef PRODUCT void Universe::calculate_verify_data(HeapWord* low_boundary, HeapWord* high_boundary) { diff --git a/src/hotspot/share/memory/universe.hpp b/src/hotspot/share/memory/universe.hpp index 5d481e889c4..ee4c05e1e06 100644 --- a/src/hotspot/share/memory/universe.hpp +++ b/src/hotspot/share/memory/universe.hpp @@ -305,6 +305,8 @@ class Universe: AllStatic { // The particular choice of collected heap. static CollectedHeap* heap() { return _collectedHeap; } + static void before_exit(); + DEBUG_ONLY(static bool is_stw_gc_active();) DEBUG_ONLY(static bool is_in_heap(const void* p);) DEBUG_ONLY(static bool is_in_heap_or_null(const void* p) { return p == nullptr || is_in_heap(p); }) diff --git a/src/hotspot/share/runtime/java.cpp b/src/hotspot/share/runtime/java.cpp index 3361ecf1558..2aaf020d6d6 100644 --- a/src/hotspot/share/runtime/java.cpp +++ b/src/hotspot/share/runtime/java.cpp @@ -475,19 +475,7 @@ void before_exit(JavaThread* thread, bool halt) { NativeHeapTrimmer::cleanup(); // Run before exit and then stop concurrent GC threads - Universe::heap()->before_exit(); - - // Print GC/heap related information. - Log(gc, exit) log; - if (log.is_info()) { - LogStream ls_info(log.info()); - Universe::print_on(&ls_info); - if (log.is_trace()) { - LogStream ls_trace(log.trace()); - MutexLocker mcld(ClassLoaderDataGraph_lock); - ClassLoaderDataGraph::print_on(&ls_trace); - } - } + Universe::before_exit(); if (PrintBytecodeHistogram) { BytecodeHistogram::print(); diff --git a/src/hotspot/share/runtime/vmThread.cpp b/src/hotspot/share/runtime/vmThread.cpp index 1f8265484f1..c93469c1362 100644 --- a/src/hotspot/share/runtime/vmThread.cpp +++ b/src/hotspot/share/runtime/vmThread.cpp @@ -28,8 +28,8 @@ #include "jfr/jfrEvents.hpp" #include "jfr/support/jfrThreadId.hpp" #include "logging/log.hpp" -#include "logging/logStream.hpp" #include "logging/logConfiguration.hpp" +#include "logging/logStream.hpp" #include "memory/resourceArea.hpp" #include "memory/universe.hpp" #include "oops/oop.inline.hpp" @@ -46,8 +46,8 @@ #include "runtime/safepoint.hpp" #include "runtime/synchronizer.hpp" #include "runtime/timerTrace.hpp" -#include "runtime/vmThread.hpp" #include "runtime/vmOperations.hpp" +#include "runtime/vmThread.hpp" #include "utilities/dtrace.hpp" #include "utilities/events.hpp" #include "utilities/vmError.hpp" diff --git a/src/hotspot/share/runtime/vmThread.hpp b/src/hotspot/share/runtime/vmThread.hpp index 668ea4ce4e2..d2033f66ea5 100644 --- a/src/hotspot/share/runtime/vmThread.hpp +++ b/src/hotspot/share/runtime/vmThread.hpp @@ -27,8 +27,8 @@ #include "runtime/atomic.hpp" #include "runtime/javaThread.hpp" -#include "runtime/perfDataTypes.hpp" #include "runtime/nonJavaThread.hpp" +#include "runtime/perfDataTypes.hpp" #include "runtime/task.hpp" #include "runtime/vmOperation.hpp" diff --git a/src/hotspot/share/services/cpuTimeUsage.cpp b/src/hotspot/share/services/cpuTimeUsage.cpp new file mode 100644 index 00000000000..aa658a67bad --- /dev/null +++ b/src/hotspot/share/services/cpuTimeUsage.cpp @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 "gc/shared/collectedHeap.hpp" +#include "gc/shared/stringdedup/stringDedup.hpp" +#include "gc/shared/stringdedup/stringDedupProcessor.hpp" +#include "memory/universe.hpp" +#include "runtime/globals.hpp" +#include "runtime/os.hpp" +#include "runtime/perfData.hpp" +#include "runtime/vmThread.hpp" +#include "services/cpuTimeUsage.hpp" + +volatile bool CPUTimeUsage::Error::_has_error = false; + +static inline jlong thread_cpu_time_or_zero(Thread* thread) { + jlong cpu_time = os::thread_cpu_time(thread); + if (cpu_time == -1) { + CPUTimeUsage::Error::mark_error(); + return 0; + } + return cpu_time; +} + +class CPUTimeThreadClosure : public ThreadClosure { +private: + jlong _cpu_time = 0; + +public: + virtual void do_thread(Thread* thread) { + _cpu_time += thread_cpu_time_or_zero(thread); + } + jlong cpu_time() { return _cpu_time; }; +}; + +jlong CPUTimeUsage::GC::vm_thread() { + return Universe::heap()->_vmthread_cpu_time; +} + +jlong CPUTimeUsage::GC::gc_threads() { + CPUTimeThreadClosure cl; + Universe::heap()->gc_threads_do(&cl); + return cl.cpu_time(); +} + +jlong CPUTimeUsage::GC::total() { + return gc_threads() + vm_thread() + stringdedup(); +} + +jlong CPUTimeUsage::GC::stringdedup() { + if (UseStringDeduplication) { + return thread_cpu_time_or_zero((Thread*)StringDedup::_processor->_thread); + } + return 0; +} + +bool CPUTimeUsage::Error::has_error() { + return Atomic::load(&_has_error); +} + +void CPUTimeUsage::Error::mark_error() { + Atomic::store(&_has_error, true); +} diff --git a/src/hotspot/share/services/cpuTimeUsage.hpp b/src/hotspot/share/services/cpuTimeUsage.hpp new file mode 100644 index 00000000000..ae4d04947a7 --- /dev/null +++ b/src/hotspot/share/services/cpuTimeUsage.hpp @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_SERVICES_CPUTIMEUSAGE_HPP +#define SHARE_SERVICES_CPUTIMEUSAGE_HPP + +#include "memory/allStatic.hpp" +#include "utilities/globalDefinitions.hpp" + +namespace CPUTimeUsage { + class GC : public AllStatic { + public: + static jlong total(); + static jlong gc_threads(); + static jlong vm_thread(); + static jlong stringdedup(); + }; + + class Error : public AllStatic { + private: + static volatile bool _has_error; + + public: + static bool has_error(); + static void mark_error(); + }; +} + +#endif // SHARE_SERVICES_CPUTIMEUSAGE_HPP From cf70cb70bcd5292ed10d8fb08019f0da82db25dd Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Thu, 21 Aug 2025 15:32:25 +0000 Subject: [PATCH 25/54] 8365024: G1: Make G1CollectionSet::_inc_build_state assert-only Reviewed-by: ayang, kbarrett --- src/hotspot/share/gc/g1/g1CollectionSet.cpp | 6 +++--- src/hotspot/share/gc/g1/g1CollectionSet.hpp | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1CollectionSet.cpp b/src/hotspot/share/gc/g1/g1CollectionSet.cpp index 804ded144bd..6fbbeb41a82 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSet.cpp +++ b/src/hotspot/share/gc/g1/g1CollectionSet.cpp @@ -67,7 +67,7 @@ G1CollectionSet::G1CollectionSet(G1CollectedHeap* g1h, G1Policy* policy) : _survivor_region_length(0), _initial_old_region_length(0), _optional_groups(), - _inc_build_state(CSetBuildType::Inactive), + DEBUG_ONLY(_inc_build_state(CSetBuildType::Inactive) COMMA) _regions_inc_part_start(0), _groups_inc_part_start(0) { } @@ -142,11 +142,11 @@ void G1CollectionSet::continue_incremental_building() { _regions_inc_part_start = _regions_cur_length; _groups_inc_part_start = groups_cur_length(); - _inc_build_state = CSetBuildType::Active; + DEBUG_ONLY(_inc_build_state = CSetBuildType::Active;) } void G1CollectionSet::stop_incremental_building() { - _inc_build_state = CSetBuildType::Inactive; + DEBUG_ONLY(_inc_build_state = CSetBuildType::Inactive;) } void G1CollectionSet::clear() { diff --git a/src/hotspot/share/gc/g1/g1CollectionSet.hpp b/src/hotspot/share/gc/g1/g1CollectionSet.hpp index 2bde960fbc4..7038cd4e677 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSet.hpp +++ b/src/hotspot/share/gc/g1/g1CollectionSet.hpp @@ -165,12 +165,14 @@ class G1CollectionSet { // groups. Regions are reachable via this list as well. G1CSetCandidateGroupList _optional_groups; +#ifdef ASSERT enum class CSetBuildType { Active, // We are actively building the collection set Inactive // We are not actively building the collection set }; CSetBuildType _inc_build_state; +#endif // Index into the _regions indicating the start of the current collection set increment. size_t _regions_inc_part_start; // Index into the _groups indicating the start of the current collection set increment. From d75724682390efa7cb63ae973fd9c504f7f64852 Mon Sep 17 00:00:00 2001 From: Vladimir Kozlov Date: Thu, 21 Aug 2025 16:37:07 +0000 Subject: [PATCH 26/54] 8365891: failed: Completed task should not be in the queue Reviewed-by: dlong --- src/hotspot/share/compiler/compileBroker.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hotspot/share/compiler/compileBroker.cpp b/src/hotspot/share/compiler/compileBroker.cpp index 36663ab1088..804345d95c5 100644 --- a/src/hotspot/share/compiler/compileBroker.cpp +++ b/src/hotspot/share/compiler/compileBroker.cpp @@ -480,6 +480,7 @@ void CompileQueue::purge_stale_tasks() { MutexUnlocker ul(MethodCompileQueue_lock); for (CompileTask* task = head; task != nullptr; ) { CompileTask* next_task = task->next(); + task->set_next(nullptr); CompileTaskWrapper ctw(task); // Frees the task task->set_failure_reason("stale task"); task = next_task; From bdf9834b81f0565e3572de42ebd42981d1d05a5c Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Thu, 21 Aug 2025 16:46:19 +0000 Subject: [PATCH 27/54] 8365425: [macos26] javax/swing/JInternalFrame/8160248/JInternalFrameDraggingTest.java fails on macOS 26 Reviewed-by: dnguyen, kizune --- .../8160248/JInternalFrameDraggingTest.java | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/test/jdk/javax/swing/JInternalFrame/8160248/JInternalFrameDraggingTest.java b/test/jdk/javax/swing/JInternalFrame/8160248/JInternalFrameDraggingTest.java index 81f5e0d0802..7c3732925be 100644 --- a/test/jdk/javax/swing/JInternalFrame/8160248/JInternalFrameDraggingTest.java +++ b/test/jdk/javax/swing/JInternalFrame/8160248/JInternalFrameDraggingTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,6 +21,7 @@ * questions. */ +import java.io.File; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Point; @@ -28,6 +29,7 @@ import java.awt.Rectangle; import java.awt.Robot; import java.awt.event.InputEvent; import java.awt.image.BufferedImage; +import javax.imageio.ImageIO; import javax.swing.JDesktopPane; import javax.swing.JFrame; import javax.swing.JInternalFrame; @@ -51,6 +53,7 @@ public class JInternalFrameDraggingTest { private static JInternalFrame internalFrame; private static int FRAME_SIZE = 500; private static Color BACKGROUND_COLOR = Color.ORANGE; + private static final int tolerance = 10; public static void main(String[] args) throws Exception { try { @@ -69,14 +72,24 @@ public class JInternalFrameDraggingTest { BufferedImage img = robot.createScreenCapture(rect); int testRGB = BACKGROUND_COLOR.getRGB(); + Color testColor = new Color(testRGB); for (int i = 1; i < size; i++) { int rgbCW = img.getRGB(i, size / 2); int rgbCH = img.getRGB(size / 2, i); - if (rgbCW != testRGB || rgbCH != testRGB) { + Color rgbCWColor = new Color(rgbCW); + Color rgbCHColor = new Color(rgbCH); + + if (Math.abs(rgbCWColor.getRed() - testColor.getRed()) > tolerance + || Math.abs(rgbCWColor.getGreen() - testColor.getGreen()) > tolerance + || Math.abs(rgbCWColor.getBlue() - testColor.getBlue()) > tolerance + || Math.abs(rgbCHColor.getRed() - testColor.getRed()) > tolerance + || Math.abs(rgbCHColor.getGreen() - testColor.getGreen()) > tolerance + || Math.abs(rgbCHColor.getBlue() - testColor.getBlue()) > tolerance) { System.out.println("i " + i + " rgbCW " + Integer.toHexString(rgbCW) + " testRGB " + Integer.toHexString(testRGB) + " rgbCH " + Integer.toHexString(rgbCH)); + ImageIO.write(img, "png", new File("JInternalFrameDraggingTest.png")); throw new RuntimeException("Background color is wrong!"); } } From 11eccfc85f8495b0cbc3965fd69911a6c7ed0140 Mon Sep 17 00:00:00 2001 From: Francesco Andreuzzi Date: Thu, 21 Aug 2025 18:58:27 +0000 Subject: [PATCH 28/54] 8365917: Sort share/logging includes Reviewed-by: ayang, phh --- src/hotspot/share/logging/log.hpp | 2 +- src/hotspot/share/logging/logDecorators.hpp | 2 +- src/hotspot/share/logging/logFileStreamOutput.cpp | 1 + src/hotspot/share/logging/logTag.cpp | 2 +- test/hotspot/jtreg/sources/TestIncludesAreSorted.java | 1 + 5 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/logging/log.hpp b/src/hotspot/share/logging/log.hpp index 87c7cd926fb..7820e2c21d1 100644 --- a/src/hotspot/share/logging/log.hpp +++ b/src/hotspot/share/logging/log.hpp @@ -26,8 +26,8 @@ #include "logging/logLevel.hpp" #include "logging/logPrefix.hpp" -#include "logging/logTagSet.hpp" #include "logging/logTag.hpp" +#include "logging/logTagSet.hpp" #include "utilities/debug.hpp" class LogMessageBuffer; diff --git a/src/hotspot/share/logging/logDecorators.hpp b/src/hotspot/share/logging/logDecorators.hpp index 9e38f429974..5b245626ade 100644 --- a/src/hotspot/share/logging/logDecorators.hpp +++ b/src/hotspot/share/logging/logDecorators.hpp @@ -24,8 +24,8 @@ #ifndef SHARE_LOGGING_LOGDECORATORS_HPP #define SHARE_LOGGING_LOGDECORATORS_HPP -#include "utilities/globalDefinitions.hpp" #include "logging/logSelection.hpp" +#include "utilities/globalDefinitions.hpp" class outputStream; diff --git a/src/hotspot/share/logging/logFileStreamOutput.cpp b/src/hotspot/share/logging/logFileStreamOutput.cpp index bc753676706..394c310b940 100644 --- a/src/hotspot/share/logging/logFileStreamOutput.cpp +++ b/src/hotspot/share/logging/logFileStreamOutput.cpp @@ -29,6 +29,7 @@ #include "logging/logMessageBuffer.hpp" #include "memory/allocation.inline.hpp" #include "utilities/defaultStream.hpp" + #include const char* const LogFileStreamOutput::FoldMultilinesOptionKey = "foldmultilines"; diff --git a/src/hotspot/share/logging/logTag.cpp b/src/hotspot/share/logging/logTag.cpp index d2aeeebfc79..41554c3acb8 100644 --- a/src/hotspot/share/logging/logTag.cpp +++ b/src/hotspot/share/logging/logTag.cpp @@ -22,9 +22,9 @@ * */ #include "logging/logTag.hpp" -#include "utilities/stringUtils.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/ostream.hpp" +#include "utilities/stringUtils.hpp" const char* const LogTag::_name[] = { "", // __NO_TAG diff --git a/test/hotspot/jtreg/sources/TestIncludesAreSorted.java b/test/hotspot/jtreg/sources/TestIncludesAreSorted.java index 5d8c60e23e0..1a304a44944 100644 --- a/test/hotspot/jtreg/sources/TestIncludesAreSorted.java +++ b/test/hotspot/jtreg/sources/TestIncludesAreSorted.java @@ -54,6 +54,7 @@ public class TestIncludesAreSorted { "share/jfr", "share/jvmci", "share/libadt", + "share/logging", "share/metaprogramming", "share/oops", "share/opto", From 52747256bbd5490dba9ef9832025a0f7057e338f Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Thu, 21 Aug 2025 19:56:46 +0000 Subject: [PATCH 29/54] 8154364: (fs) Files.isSameFile() throws NoSuchFileException with broken symbolic links Reviewed-by: alanb --- .../sun/nio/fs/UnixFileAttributes.java | 27 +- .../sun/nio/fs/UnixFileSystemProvider.java | 56 ++- .../sun/nio/fs/WindowsFileSystemProvider.java | 20 +- test/jdk/java/nio/file/Files/IsSameFile.java | 456 ++++++++++++++++++ test/jdk/java/nio/file/Files/Misc.java | 30 +- 5 files changed, 549 insertions(+), 40 deletions(-) create mode 100644 test/jdk/java/nio/file/Files/IsSameFile.java diff --git a/src/java.base/unix/classes/sun/nio/fs/UnixFileAttributes.java b/src/java.base/unix/classes/sun/nio/fs/UnixFileAttributes.java index 6fc86b66735..48dc4c07d0d 100644 --- a/src/java.base/unix/classes/sun/nio/fs/UnixFileAttributes.java +++ b/src/java.base/unix/classes/sun/nio/fs/UnixFileAttributes.java @@ -81,8 +81,11 @@ class UnixFileAttributes return attrs; } - // get the UnixFileAttributes for a given file. Returns null if the file does not exist. - static UnixFileAttributes getIfExists(UnixPath path) throws UnixException { + // get the UnixFileAttributes for a given file. + // Returns null if the file does not exist. + static UnixFileAttributes getIfExists(UnixPath path) + throws UnixException + { UnixFileAttributes attrs = new UnixFileAttributes(); int errno = UnixNativeDispatcher.stat2(path, attrs); if (errno == 0) { @@ -94,6 +97,26 @@ class UnixFileAttributes } } + // get the UnixFileAttributes for a given file, optionally following links. + // Returns null if the file does not exist. + static UnixFileAttributes getIfExists(UnixPath path, boolean followLinks) + throws UnixException + { + UnixFileAttributes attrs = new UnixFileAttributes(); + int flag = (followLinks) ? 0 : UnixConstants.AT_SYMLINK_NOFOLLOW; + try { + UnixNativeDispatcher.fstatat(UnixConstants.AT_FDCWD, + path.asByteArray(), flag, attrs); + } catch (UnixException x) { + if (x.errno() == UnixConstants.ENOENT) + return null; + + throw x; + } + + return attrs; + } + // get the UnixFileAttributes for an open file static UnixFileAttributes get(int fd) throws UnixException { UnixFileAttributes attrs = new UnixFileAttributes(); diff --git a/src/java.base/unix/classes/sun/nio/fs/UnixFileSystemProvider.java b/src/java.base/unix/classes/sun/nio/fs/UnixFileSystemProvider.java index beb9a1af41b..a1c68934604 100644 --- a/src/java.base/unix/classes/sun/nio/fs/UnixFileSystemProvider.java +++ b/src/java.base/unix/classes/sun/nio/fs/UnixFileSystemProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ import java.nio.file.attribute.PosixFileAttributes; import java.nio.file.attribute.PosixFileAttributeView; import java.nio.file.spi.FileTypeDetector; import java.util.Map; +import java.util.HashSet; import java.util.Set; import java.util.concurrent.ExecutorService; @@ -348,8 +349,32 @@ public abstract class UnixFileSystemProvider return access(file, X_OK) == 0; } + // find the key of the last accessible link in the chain + private UnixFileKey lastFileKey(UnixPath path) throws UnixException { + var fileKeys = new HashSet(); + UnixFileKey lastFileKey = null; + while (path != null) { + UnixFileAttributes attrs = UnixFileAttributes.getIfExists(path, false); + if (attrs == null) { + break; + } + UnixFileKey fileKey = attrs.fileKey(); + if (!attrs.isSymbolicLink()) { + break; + } + if (!fileKeys.add(fileKey)) { + throw new UnixException(ELOOP); + } + lastFileKey = fileKey; + byte[] target = readlink(path); + path = new UnixPath(theFileSystem, target); + } + return lastFileKey; + } + @Override public boolean isSameFile(Path obj1, Path obj2) throws IOException { + // toUnixPath verifies its argument is a non-null UnixPath UnixPath file1 = UnixPath.toUnixPath(obj1); if (file1.equals(obj2)) return true; @@ -358,21 +383,28 @@ public abstract class UnixFileSystemProvider if (!(obj2 instanceof UnixPath file2)) return false; - UnixFileAttributes attrs1; - UnixFileAttributes attrs2; + UnixFileKey key1; try { - attrs1 = UnixFileAttributes.get(file1, true); - } catch (UnixException x) { - x.rethrowAsIOException(file1); - return false; // keep compiler happy + UnixFileAttributes attrs = UnixFileAttributes.getIfExists(file1); + key1 = (attrs != null) ? attrs.fileKey() : lastFileKey(file1); + } catch (UnixException e) { + e.rethrowAsIOException(file1); + return false; } + + if (key1 == null) + return false; + + UnixFileKey key2; try { - attrs2 = UnixFileAttributes.get(file2, true); - } catch (UnixException x) { - x.rethrowAsIOException(file2); - return false; // keep compiler happy + UnixFileAttributes attrs = UnixFileAttributes.getIfExists(file2); + key2 = (attrs != null) ? attrs.fileKey() : lastFileKey(file2); + } catch (UnixException e) { + e.rethrowAsIOException(file2); + return false; } - return attrs1.isSameFile(attrs2); + + return key1.equals(key2); } @Override diff --git a/src/java.base/windows/classes/sun/nio/fs/WindowsFileSystemProvider.java b/src/java.base/windows/classes/sun/nio/fs/WindowsFileSystemProvider.java index 3a1bb416fe7..5e740ec1f4d 100644 --- a/src/java.base/windows/classes/sun/nio/fs/WindowsFileSystemProvider.java +++ b/src/java.base/windows/classes/sun/nio/fs/WindowsFileSystemProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -434,8 +434,15 @@ class WindowsFileSystemProvider try { h1 = file1.openForReadAttributeAccess(true); } catch (WindowsException x) { - x.rethrowAsIOException(file1); + if (x.lastError() != ERROR_FILE_NOT_FOUND && + x.lastError() != ERROR_PATH_NOT_FOUND) + x.rethrowAsIOException(file1); } + + // if file1 does not exist, it cannot equal file2 + if (h1 == 0L) + return false; + try { WindowsFileAttributes attrs1 = null; try { @@ -447,8 +454,15 @@ class WindowsFileSystemProvider try { h2 = file2.openForReadAttributeAccess(true); } catch (WindowsException x) { - x.rethrowAsIOException(file2); + if (x.lastError() != ERROR_FILE_NOT_FOUND && + x.lastError() != ERROR_PATH_NOT_FOUND) + x.rethrowAsIOException(file2); } + + // if file2 does not exist, it cannot equal file1, which does + if (h2 == 0L) + return false; + try { WindowsFileAttributes attrs2 = null; try { diff --git a/test/jdk/java/nio/file/Files/IsSameFile.java b/test/jdk/java/nio/file/Files/IsSameFile.java new file mode 100644 index 00000000000..00bac0fb5a7 --- /dev/null +++ b/test/jdk/java/nio/file/Files/IsSameFile.java @@ -0,0 +1,456 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8154364 + * @summary Test of Files.isSameFile + * @requires (os.family != "windows") + * @library .. /test/lib + * @build IsSameFile jdk.test.lib.util.FileUtils + * @run junit IsSameFile + */ +import java.io.IOException; +import java.io.FileOutputStream; +import java.nio.file.Files; +import java.nio.file.FileSystem; +import java.nio.file.FileSystemException; +import java.nio.file.FileSystems; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Stream; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +import jdk.test.lib.util.FileUtils; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.TestInstance.Lifecycle; +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.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@TestInstance(Lifecycle.PER_CLASS) +public class IsSameFile { + private Path home; + private Path a; + private Path aa; + private Path b; + private Path c; + private List allFiles; + + @BeforeAll + public void init() throws IOException { + home = Files.createTempDirectory("TestIsSameFile"); + + allFiles = new ArrayList(); + allFiles.add(a = home.resolve("a")); + allFiles.add(aa = home.resolve("a")); + allFiles.add(b = home.resolve("b")); + allFiles.add(c = home.resolve("c")); + } + + public void deleteFiles() throws IOException { + for (Path p : allFiles) + Files.deleteIfExists(p); + } + + @AfterAll + public void deleteHome() throws IOException { + TestUtil.removeAll(home); + } + + public void test(boolean expect, Path x, Path y) throws IOException { + assertTrue(Files.isSameFile(x, y) == expect); + } + + private Stream stringCompareSource() throws IOException { + deleteFiles(); + List list = new ArrayList(); + Path x = Path.of("x/y/z"); + list.add(Arguments.of(true, x, x)); + list.add(Arguments.of(false, Path.of("w/x/y/z"), x)); + Path y = Path.of("v/w/x/../y/z"); + list.add(Arguments.of(false, y, Path.of("v/w/y/z"))); + list.add(Arguments.of(false, y, Path.of("v/w/x/y/../z"))); + return list.stream(); + } + + @ParameterizedTest + @MethodSource("stringCompareSource") + public void stringCompare(boolean expect, Path x, Path y) + throws IOException { + test(expect, x, y); + } + + private Stream noneExistSource() throws IOException { + deleteFiles(); + List list = new ArrayList(); + list.add(Arguments.of(true, a, a)); + list.add(Arguments.of(true, a, aa)); + list.add(Arguments.of(false, a, b)); + list.add(Arguments.of(true, b, b)); + return list.stream(); + } + + @Test + public void obj2Null() { + Path x = Path.of("x/y"); + assertThrows(NullPointerException.class, () -> Files.isSameFile(x, null)); + } + + private static void zipStringToFile(String entry, String content, + Path path) + throws IOException + { + FileOutputStream fos = new FileOutputStream(path.toString()); + ZipOutputStream zos = new ZipOutputStream(fos); + + ZipEntry zipEntry = new ZipEntry(entry); + zos.putNextEntry(zipEntry); + zos.write(content.getBytes()); + + zos.close(); + fos.close(); + } + + private Stream obj2ZipSource() throws IOException { + deleteFiles(); + Files.createFile(a); + zipStringToFile("quote.txt", "To be determined", b); + FileSystem zipfs = FileSystems.newFileSystem(b); + List list = new ArrayList(); + list.add(Arguments.of(false, a, zipfs.getPath(b.toString()))); + return list.stream(); + } + + @ParameterizedTest + @MethodSource("obj2ZipSource") + public void obj2Zip(boolean expect, Path x, Path y) + throws IOException { + test(expect, x, y); + } + + @ParameterizedTest + @MethodSource("noneExistSource") + public void noneExist(boolean expect, Path x, Path y) + throws IOException { + test(expect, x, y); + } + + private Stream aExistsSource() throws IOException { + deleteFiles(); + Files.createFile(a); + List list = new ArrayList(); + list.add(Arguments.of(true, a, a)); + list.add(Arguments.of(true, a, aa)); + list.add(Arguments.of(false, a, b)); + return list.stream(); + } + + @ParameterizedTest + @MethodSource("aExistsSource") + public void aExists(boolean expect, Path x, Path y) throws IOException { + test(expect, x, y); + } + + private Stream abExistSource() throws IOException { + deleteFiles(); + Files.createFile(a); + Files.createFile(b); + List list = new ArrayList(); + list.add(Arguments.of(false, a, b)); + list.add(Arguments.of(true, b, b)); + list.add(Arguments.of(false, a, c)); + return list.stream(); + } + + @ParameterizedTest + @MethodSource("abExistSource") + public void abExist(boolean expect, Path x, Path y) + throws IOException { + test(expect, x, y); + } + + private Stream abcExistSource() throws IOException { + deleteFiles(); + Files.createFile(a); + Files.createFile(b); + Files.createSymbolicLink(c, a); + List list = new ArrayList(); + list.add(Arguments.of(true, a, c)); + list.add(Arguments.of(false, a, b)); + return list.stream(); + } + + @ParameterizedTest + @MethodSource("abcExistSource") + public void abcExist(boolean expect, Path x, Path y) + throws IOException { + test(expect, x, y); + } + + private Stream bcExistSource() throws IOException { + deleteFiles(); + Files.createFile(b); + Files.createSymbolicLink(c, a); + List list = new ArrayList(); + list.add(Arguments.of(true, a, a)); + list.add(Arguments.of(true, a, aa)); + list.add(Arguments.of(false, a, b)); + list.add(Arguments.of(true, b, b)); + list.add(Arguments.of(false, a, c)); + return list.stream(); + } + + @ParameterizedTest + @MethodSource("bcExistSource") + public void bcExist(boolean expect, Path x, Path y) + throws IOException { + test(expect, x, y); + } + + // + // L1 => L2 => target + // L3 => L4 => target + // + private Stream equalFollowingSource() throws IOException { + deleteFiles(); + Path target = home.resolve("target"); + Files.createFile(target); + allFiles.add(target); + + Path L2 = Path.of("link2"); + Files.createSymbolicLink(L2, target); + allFiles.add(L2); + + Path L1 = Path.of("link1"); + Files.createSymbolicLink(L1, L2); + allFiles.add(L1); + + Path L4 = Path.of("link4"); + Files.createSymbolicLink(L4, target); + allFiles.add(L4); + + Path L3 = Path.of("link3"); + Files.createSymbolicLink(L3, L4); + allFiles.add(L3); + + List list = new ArrayList(); + list.add(Arguments.of(true, L1, L3)); + return list.stream(); + } + + @ParameterizedTest + @MethodSource("equalFollowingSource") + public void equalFollowing(boolean expect, Path x, Path y) + throws IOException { + test(expect, x, y); + } + + // + // L1 => L2 => target + // L3 => L4 => cible + // + private Stream unequalFollowingSource() throws IOException { + deleteFiles(); + Path target = home.resolve("target"); + Files.createFile(target); + allFiles.add(target); + + Path L2 = Path.of("link2"); + Files.createSymbolicLink(L2, target); + allFiles.add(L2); + + Path L1 = Path.of("link1"); + Files.createSymbolicLink(L1, L2); + allFiles.add(L1); + + Path cible = home.resolve("cible"); + Files.createFile(cible); + allFiles.add(cible); + + Path L4 = Path.of("link4"); + Files.createSymbolicLink(L4, cible); + allFiles.add(L4); + + Path L3 = Path.of("link3"); + Files.createSymbolicLink(L3, L4); + allFiles.add(L3); + + List list = new ArrayList(); + list.add(Arguments.of(false, L1, L3)); + return list.stream(); + } + + @ParameterizedTest + @MethodSource("unequalFollowingSource") + public void unequalFollowing(boolean expect, Path x, Path y) + throws IOException { + test(expect, x, y); + } + + // + // L1 => L2 => + // L3 => L4 => + // + private Stream unequalNotFollowingSource() throws IOException { + deleteFiles(); + + Path doesNotExist = Path.of("doesNotExist"); + + Path L2 = Path.of("link2"); + Files.createSymbolicLink(L2, doesNotExist); + allFiles.add(L2); + + Path L1 = Path.of("link1"); + Files.createSymbolicLink(L1, L2); + allFiles.add(L1); + + Path L4 = Path.of("link4"); + Files.createSymbolicLink(L4, doesNotExist); + allFiles.add(L4); + + Path L3 = Path.of("link3"); + Files.createSymbolicLink(L3, L4); + allFiles.add(L3); + + List list = new ArrayList(); + list.add(Arguments.of(false, L1, L3)); + return list.stream(); + } + + @ParameterizedTest + @MethodSource("unequalNotFollowingSource") + public void unequalNotFollowing(boolean expect, Path x, Path y) + throws IOException { + test(expect, x, y); + } + + // + // L1 => L2 => L3 => L4 => target + // + // isSameFile(LX,LY) should be true for all X, Y + // + private Stream multiLinkSource() throws IOException { + deleteFiles(); + Path target = home.resolve("target"); + Files.createFile(target); + allFiles.add(target); + Path[] links = new Path[4]; + links[3] = Files.createSymbolicLink(Path.of("link4"), target); + allFiles.add(links[3]); + for (int i = 3; i > 0; i--) { + links[i-1] = Files.createSymbolicLink(Path.of("link"+i), links[i]); + allFiles.add(links[i-1]); + } + + List list = new ArrayList(); + for (int i = 0; i < 4; i++) { + list.add(Arguments.of(true, links[i], target)); + for (int j = i+1; j < 4; j++) + list.add(Arguments.of(true, links[i], links[j])); + } + + return list.stream(); + } + + @ParameterizedTest + @MethodSource("multiLinkSource") + public void multiLink(boolean expect, Path x, Path y) + throws IOException { + test(expect, x, y); + } + + // + // L1 => L2 => L3 => L4 => + // + // isSameFile(LX,LY) should be true for all X, Y + // + private Stream multiLinkNoTargetSource() throws IOException { + deleteFiles(); + Path target = home.resolve("target"); + Files.createFile(target); + allFiles.add(target); + Path[] links = new Path[4]; + links[3] = Files.createSymbolicLink(Path.of("link4"), target); + allFiles.add(links[3]); + Files.delete(target); + allFiles.remove(target); + for (int i = 3; i > 0; i--) { + links[i-1] = Files.createSymbolicLink(Path.of("link"+i), links[i]); + allFiles.add(links[i-1]); + } + + List list = new ArrayList(); + for (int i = 0; i < 4; i++) { + list.add(Arguments.of(false, links[i], target)); + for (int j = i+1; j < 4; j++) + list.add(Arguments.of(true, links[i], links[j])); + } + + return list.stream(); + } + + @ParameterizedTest + @MethodSource("multiLinkNoTargetSource") + public void multiLinkNoTarget(boolean expect, Path x, Path y) + throws IOException { + test(expect, x, y); + } + + // + // L1 -> L2 -> L3 -> L1... + // + // This is a loop and should throw FileSystemException. + // + private Stream linkLoopSource() throws IOException { + deleteFiles(); + + Path link1 = home.resolve("L1"); + Path link2 = home.resolve("L2"); + Path link3 = home.resolve("L3"); + allFiles.add(Files.createSymbolicLink(link1, link2)); + allFiles.add(Files.createSymbolicLink(link2, link3)); + allFiles.add(Files.createSymbolicLink(link3, link1)); + + List list = new ArrayList(); + list.add(Arguments.of(true, link1, link2)); + list.add(Arguments.of(true, link2, link3)); + list.add(Arguments.of(true, link3, link1)); + + return list.stream(); + } + + @ParameterizedTest + @MethodSource("linkLoopSource") + public void linkLoop(boolean expect, Path x, Path y) throws IOException { + assertThrows(FileSystemException.class, () -> Files.isSameFile(x, y)); + } +} diff --git a/test/jdk/java/nio/file/Files/Misc.java b/test/jdk/java/nio/file/Files/Misc.java index 024b518141b..9ec8d7c252e 100644 --- a/test/jdk/java/nio/file/Files/Misc.java +++ b/test/jdk/java/nio/file/Files/Misc.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,7 +22,7 @@ */ /* @test - * @bug 4313887 6838333 8005566 8215467 8255576 8286160 + * @bug 4313887 6838333 8005566 8154364 8215467 8255576 8286160 * @summary Unit test for miscellaneous methods in java.nio.file.Files * @library .. /test/lib * @build jdk.test.lib.Platform @@ -113,34 +113,18 @@ public class Misc { assertTrue(isSameFile(thisFile, thisFile)); /** - * Test: Neither files exist + * Test: Neither file exists */ - try { - isSameFile(thisFile, thatFile); - throw new RuntimeException("IOException not thrown"); - } catch (IOException x) { - } - try { - isSameFile(thatFile, thisFile); - throw new RuntimeException("IOException not thrown"); - } catch (IOException x) { - } + assertTrue(!isSameFile(thisFile, thatFile)); + assertTrue(!isSameFile(thatFile, thisFile)); createFile(thisFile); try { /** * Test: One file exists */ - try { - isSameFile(thisFile, thatFile); - throw new RuntimeException("IOException not thrown"); - } catch (IOException x) { - } - try { - isSameFile(thatFile, thisFile); - throw new RuntimeException("IOException not thrown"); - } catch (IOException x) { - } + assertTrue(!isSameFile(thisFile, thatFile)); + assertTrue(!isSameFile(thatFile, thisFile)); /** * Test: Both file exists From 3468c6e5ef7e7592cf9484736ce333fbe0eaf34d Mon Sep 17 00:00:00 2001 From: Phil Race Date: Thu, 21 Aug 2025 20:49:04 +0000 Subject: [PATCH 30/54] 8365389: Remove static color fields from SwingUtilities3 and WindowsMenuItemUI Reviewed-by: psadhukhan, aivanov, dnguyen --- .../com/sun/java/swing/SwingUtilities3.java | 21 ++------ .../swing/plaf/basic/BasicMenuItemUI.java | 9 ++-- .../windows/WindowsCheckBoxMenuItemUI.java | 4 +- .../swing/plaf/windows/WindowsMenuItemUI.java | 51 +++++-------------- .../swing/plaf/windows/WindowsMenuUI.java | 3 +- .../windows/WindowsRadioButtonMenuItemUI.java | 4 +- 6 files changed, 28 insertions(+), 64 deletions(-) diff --git a/src/java.desktop/share/classes/com/sun/java/swing/SwingUtilities3.java b/src/java.desktop/share/classes/com/sun/java/swing/SwingUtilities3.java index 5e1e149eb9e..91e0f8dc54d 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/SwingUtilities3.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/SwingUtilities3.java @@ -69,10 +69,6 @@ public class SwingUtilities3 { private static final Object DELEGATE_REPAINT_MANAGER_KEY = new StringBuilder("DelegateRepaintManagerKey"); - private static Color disabledForeground; - private static Color acceleratorSelectionForeground; - private static Color acceleratorForeground; - /** * Registers delegate RepaintManager for {@code JComponent}. */ @@ -204,7 +200,10 @@ public class SwingUtilities3 { public static void paintAccText(Graphics g, MenuItemLayoutHelper lh, - MenuItemLayoutHelper.LayoutResult lr) { + MenuItemLayoutHelper.LayoutResult lr, + Color disabledForeground, + Color acceleratorSelectionForeground, + Color acceleratorForeground) { if (!lh.getAccText().isEmpty()) { ButtonModel model = lh.getMenuItem().getModel(); g.setFont(lh.getAccFontMetrics().getFont()); @@ -243,18 +242,6 @@ public class SwingUtilities3 { } } - public static void setDisabledForeground(Color disabledFg) { - disabledForeground = disabledFg; - } - - public static void setAcceleratorSelectionForeground(Color acceleratorSelectionFg) { - acceleratorSelectionForeground = acceleratorSelectionFg; - } - - public static void setAcceleratorForeground(Color acceleratorFg) { - acceleratorForeground = acceleratorFg; - } - public static void paintArrowIcon(Graphics g, MenuItemLayoutHelper lh, MenuItemLayoutHelper.LayoutResult lr, Color foreground) { diff --git a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicMenuItemUI.java b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicMenuItemUI.java index 524f0337a8f..d361906b291 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicMenuItemUI.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicMenuItemUI.java @@ -716,11 +716,10 @@ public class BasicMenuItemUI extends MenuItemUI private void paintAccText(Graphics g, MenuItemLayoutHelper lh, MenuItemLayoutHelper.LayoutResult lr) { - SwingUtilities3.setDisabledForeground(disabledForeground); - SwingUtilities3.setAcceleratorSelectionForeground( - acceleratorSelectionForeground); - SwingUtilities3.setAcceleratorForeground(acceleratorForeground); - SwingUtilities3.paintAccText(g, lh, lr); + SwingUtilities3.paintAccText(g, lh, lr, + disabledForeground, + acceleratorSelectionForeground, + acceleratorForeground); } private void paintText(Graphics g, MenuItemLayoutHelper lh, diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsCheckBoxMenuItemUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsCheckBoxMenuItemUI.java index f59a59a5125..02054575d77 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsCheckBoxMenuItemUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsCheckBoxMenuItemUI.java @@ -84,7 +84,9 @@ public final class WindowsCheckBoxMenuItemUI extends BasicCheckBoxMenuItemUI { int defaultTextIconGap) { if (WindowsMenuItemUI.isVistaPainting()) { WindowsMenuItemUI.paintMenuItem(accessor, g, c, checkIcon, - arrowIcon, background, foreground, defaultTextIconGap, + arrowIcon, background, foreground, + disabledForeground, acceleratorSelectionForeground, + acceleratorForeground, defaultTextIconGap, menuItem, getPropertyPrefix()); return; } diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuItemUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuItemUI.java index a8bafc54c33..aa90b2f35b3 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuItemUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuItemUI.java @@ -67,9 +67,6 @@ public final class WindowsMenuItemUI extends BasicMenuItemUI { * The instance of {@code PropertyChangeListener}. */ private PropertyChangeListener changeListener; - private static Color disabledForeground; - private static Color acceleratorSelectionForeground; - private static Color acceleratorForeground; final WindowsMenuItemUIAccessor accessor = new WindowsMenuItemUIAccessor() { @@ -167,36 +164,6 @@ public final class WindowsMenuItemUI extends BasicMenuItemUI { changeListener = null; } - private static void applyInsets(Rectangle rect, Insets insets) { - SwingUtilities3.applyInsets(rect, insets); - } - - private static void paintCheckIcon(Graphics g, MenuItemLayoutHelper lh, - MenuItemLayoutHelper.LayoutResult lr, - Color holdc, Color foreground) { - SwingUtilities3.paintCheckIcon(g, lh, lr, holdc, foreground); - } - - private static void paintIcon(Graphics g, MenuItemLayoutHelper lh, - MenuItemLayoutHelper.LayoutResult lr, Color holdc) { - SwingUtilities3.paintIcon(g, lh, lr, holdc); - } - - private static void paintAccText(Graphics g, MenuItemLayoutHelper lh, - MenuItemLayoutHelper.LayoutResult lr) { - SwingUtilities3.setDisabledForeground(disabledForeground); - SwingUtilities3.setAcceleratorSelectionForeground( - acceleratorSelectionForeground); - SwingUtilities3.setAcceleratorForeground(acceleratorForeground); - SwingUtilities3.paintAccText(g, lh, lr); - } - - private static void paintArrowIcon(Graphics g, MenuItemLayoutHelper lh, - MenuItemLayoutHelper.LayoutResult lr, - Color foreground) { - SwingUtilities3.paintArrowIcon(g, lh, lr, foreground); - } - protected void paintMenuItem(Graphics g, JComponent c, Icon checkIcon, Icon arrowIcon, Color background, Color foreground, @@ -204,7 +171,8 @@ public final class WindowsMenuItemUI extends BasicMenuItemUI { if (WindowsMenuItemUI.isVistaPainting()) { WindowsMenuItemUI.paintMenuItem(accessor, g, c, checkIcon, arrowIcon, background, foreground, - defaultTextIconGap, menuItem, + disabledForeground, acceleratorSelectionForeground, + acceleratorForeground, defaultTextIconGap, menuItem, getPropertyPrefix()); return; } @@ -215,6 +183,9 @@ public final class WindowsMenuItemUI extends BasicMenuItemUI { static void paintMenuItem(WindowsMenuItemUIAccessor accessor, Graphics g, JComponent c, Icon checkIcon, Icon arrowIcon, Color background, Color foreground, + Color disabledForeground, + Color acceleratorSelectionForeground, + Color acceleratorForeground, int defaultTextIconGap, JMenuItem menuItem, String prefix) { // Save original graphics font and color Font holdf = g.getFont(); @@ -224,7 +195,7 @@ public final class WindowsMenuItemUI extends BasicMenuItemUI { g.setFont(mi.getFont()); Rectangle viewRect = new Rectangle(0, 0, mi.getWidth(), mi.getHeight()); - applyInsets(viewRect, mi.getInsets()); + SwingUtilities3.applyInsets(viewRect, mi.getInsets()); String acceleratorDelimiter = UIManager.getString("MenuItem.acceleratorDelimiter"); @@ -242,8 +213,8 @@ public final class WindowsMenuItemUI extends BasicMenuItemUI { MenuItemLayoutHelper.LayoutResult lr = lh.layoutMenuItem(); paintBackground(accessor, g, mi, background); - paintCheckIcon(g, lh, lr, holdc, foreground); - paintIcon(g, lh, lr, holdc); + SwingUtilities3.paintCheckIcon(g, lh, lr, holdc, foreground); + SwingUtilities3.paintIcon(g, lh, lr, holdc); if (lh.getCheckIcon() != null && lh.useCheckAndArrow()) { Rectangle rect = lr.getTextRect(); @@ -267,8 +238,10 @@ public final class WindowsMenuItemUI extends BasicMenuItemUI { rect.x += lh.getAfterCheckIconGap(); lr.setAccRect(rect); } - paintAccText(g, lh, lr); - paintArrowIcon(g, lh, lr, foreground); + SwingUtilities3.paintAccText(g, lh, lr, disabledForeground, + acceleratorSelectionForeground, + acceleratorForeground); + SwingUtilities3.paintArrowIcon(g, lh, lr, foreground); // Restore original graphics font and color g.setColor(holdc); diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuUI.java index 81c01c11036..1476c6fc152 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuUI.java @@ -140,7 +140,8 @@ public final class WindowsMenuUI extends BasicMenuUI { if (WindowsMenuItemUI.isVistaPainting()) { WindowsMenuItemUI.paintMenuItem(accessor, g, c, checkIcon, arrowIcon, background, foreground, - defaultTextIconGap, menuItem, + disabledForeground, acceleratorSelectionForeground, + acceleratorForeground, defaultTextIconGap, menuItem, getPropertyPrefix()); return; } diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsRadioButtonMenuItemUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsRadioButtonMenuItemUI.java index 385ab6b3634..628a4be1637 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsRadioButtonMenuItemUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsRadioButtonMenuItemUI.java @@ -84,7 +84,9 @@ public final class WindowsRadioButtonMenuItemUI extends BasicRadioButtonMenuItem int defaultTextIconGap) { if (WindowsMenuItemUI.isVistaPainting()) { WindowsMenuItemUI.paintMenuItem(accessor, g, c, checkIcon, - arrowIcon, background, foreground, defaultTextIconGap, + arrowIcon, background, foreground, + disabledForeground, acceleratorSelectionForeground, + acceleratorForeground, defaultTextIconGap, menuItem, getPropertyPrefix()); return; } From 584137cf968bdfd4fdb88b5bb210bbbfa5f2d537 Mon Sep 17 00:00:00 2001 From: Dingli Zhang Date: Fri, 22 Aug 2025 01:42:57 +0000 Subject: [PATCH 31/54] 8365844: RISC-V: TestBadFormat.java fails when running without RVV Reviewed-by: fjiang, chagedorn, epeter, fyang --- .../testlibrary_tests/ir_framework/tests/TestBadFormat.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestBadFormat.java b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestBadFormat.java index ac8867f3985..a33aacd924e 100644 --- a/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestBadFormat.java +++ b/test/hotspot/jtreg/testlibrary_tests/ir_framework/tests/TestBadFormat.java @@ -1124,8 +1124,8 @@ class BadIRAnnotationsAfterTestVM { @Test @FailCount(8) - @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0"}) - @IR(counts = {IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE_MAX, "> 0"}) // valid + @IR(counts = {IRNode.LOAD_VECTOR_I, "> 0"}, applyIf = {"MaxVectorSize", "> 0"}) // valid, but only if MaxVectorSize > 0, otherwise, a violation is reported + @IR(counts = {IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE_MAX, "> 0"}, applyIf = {"MaxVectorSize", "> 0"}) // valid, but only if MaxVectorSize > 0, otherwise, a violation is reported @IR(counts = {IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE_ANY, "> 0"}) // valid @IR(counts = {IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE + "", "> 0"}) @IR(counts = {IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE + "xxx", "> 0"}) From 558d06399c7a13b247ee3d0f36f4fe6118004c55 Mon Sep 17 00:00:00 2001 From: Amit Kumar Date: Fri, 22 Aug 2025 03:43:01 +0000 Subject: [PATCH 32/54] 8361536: [s390x] Saving return_pc at wrong offset Reviewed-by: lucy, mdoerr --- src/hotspot/cpu/s390/stubGenerator_s390.cpp | 38 +++++++++++---------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/src/hotspot/cpu/s390/stubGenerator_s390.cpp b/src/hotspot/cpu/s390/stubGenerator_s390.cpp index 34696f18848..2aa365be999 100644 --- a/src/hotspot/cpu/s390/stubGenerator_s390.cpp +++ b/src/hotspot/cpu/s390/stubGenerator_s390.cpp @@ -164,15 +164,16 @@ class StubGenerator: public StubCodeGenerator { // Save non-volatile registers to ABI of caller frame. BLOCK_COMMENT("save registers, push frame {"); - __ z_stmg(Z_R6, Z_R14, 16, Z_SP); - __ z_std(Z_F8, 96, Z_SP); - __ z_std(Z_F9, 104, Z_SP); - __ z_std(Z_F10, 112, Z_SP); - __ z_std(Z_F11, 120, Z_SP); - __ z_std(Z_F12, 128, Z_SP); - __ z_std(Z_F13, 136, Z_SP); - __ z_std(Z_F14, 144, Z_SP); - __ z_std(Z_F15, 152, Z_SP); + __ save_return_pc(); + __ z_stmg(Z_R6, Z_R13, 16, Z_SP); + __ z_std(Z_F8, 80, Z_SP); + __ z_std(Z_F9, 88, Z_SP); + __ z_std(Z_F10, 96, Z_SP); + __ z_std(Z_F11, 104, Z_SP); + __ z_std(Z_F12, 112, Z_SP); + __ z_std(Z_F13, 120, Z_SP); + __ z_std(Z_F14, 128, Z_SP); + __ z_std(Z_F15, 136, Z_SP); // // Push ENTRY_FRAME including arguments: @@ -337,15 +338,16 @@ class StubGenerator: public StubCodeGenerator { __ z_lg(r_arg_result_type, result_type_offset, r_entryframe_fp); // Restore non-volatiles. - __ z_lmg(Z_R6, Z_R14, 16, Z_SP); - __ z_ld(Z_F8, 96, Z_SP); - __ z_ld(Z_F9, 104, Z_SP); - __ z_ld(Z_F10, 112, Z_SP); - __ z_ld(Z_F11, 120, Z_SP); - __ z_ld(Z_F12, 128, Z_SP); - __ z_ld(Z_F13, 136, Z_SP); - __ z_ld(Z_F14, 144, Z_SP); - __ z_ld(Z_F15, 152, Z_SP); + __ restore_return_pc(); + __ z_lmg(Z_R6, Z_R13, 16, Z_SP); + __ z_ld(Z_F8, 80, Z_SP); + __ z_ld(Z_F9, 88, Z_SP); + __ z_ld(Z_F10, 96, Z_SP); + __ z_ld(Z_F11, 104, Z_SP); + __ z_ld(Z_F12, 112, Z_SP); + __ z_ld(Z_F13, 120, Z_SP); + __ z_ld(Z_F14, 128, Z_SP); + __ z_ld(Z_F15, 136, Z_SP); BLOCK_COMMENT("} restore"); // From 8e4485699235caff0074c4d25ee78539e57da63a Mon Sep 17 00:00:00 2001 From: Phil Race Date: Fri, 22 Aug 2025 04:28:56 +0000 Subject: [PATCH 33/54] 8365180: Remove sun.awt.windows.WInputMethod.finalize() Reviewed-by: serb, azvegint --- .../classes/sun/awt/windows/WInputMethod.java | 38 ++++++++++++------- .../native/libawt/windows/awt_InputMethod.cpp | 4 +- 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/src/java.desktop/windows/classes/sun/awt/windows/WInputMethod.java b/src/java.desktop/windows/classes/sun/awt/windows/WInputMethod.java index e893a58f9ed..0e4e5bd585e 100644 --- a/src/java.desktop/windows/classes/sun/awt/windows/WInputMethod.java +++ b/src/java.desktop/windows/classes/sun/awt/windows/WInputMethod.java @@ -44,6 +44,8 @@ import java.util.Map; import sun.awt.AWTAccessor; import sun.awt.AWTAccessor.ComponentAccessor; import sun.awt.im.InputMethodAdapter; +import sun.java2d.Disposer; +import sun.java2d.DisposerRecord; final class WInputMethod extends InputMethodAdapter { @@ -124,6 +126,8 @@ final class WInputMethod extends InputMethodAdapter public WInputMethod() { context = createNativeContext(); + disposerRecord = new ContextDisposerRecord(context); + Disposer.addRecord(this, disposerRecord); cmode = getConversionStatus(context); open = getOpenStatus(context); currentLocale = getNativeLocale(); @@ -132,16 +136,23 @@ final class WInputMethod extends InputMethodAdapter } } - @Override - @SuppressWarnings("removal") - protected void finalize() throws Throwable - { - // Release the resources used by the native input context. - if (context!=0) { - destroyNativeContext(context); - context=0; + private final ContextDisposerRecord disposerRecord; + + private static final class ContextDisposerRecord implements DisposerRecord { + + private final int context; + private volatile boolean disposed; + + ContextDisposerRecord(int c) { + context = c; + } + + public synchronized void dispose() { + if (!disposed) { + destroyNativeContext(context); + } + disposed = true; } - super.finalize(); } @Override @@ -151,9 +162,7 @@ final class WInputMethod extends InputMethodAdapter @Override public void dispose() { - // Due to a memory management problem in Windows 98, we should retain - // the native input context until this object is finalized. So do - // nothing here. + disposerRecord.dispose(); } /** @@ -448,6 +457,7 @@ final class WInputMethod extends InputMethodAdapter @Override public void removeNotify() { endCompositionNative(context, DISCARD_INPUT); + disableNativeIME(awtFocussedComponentPeer); awtFocussedComponent = null; awtFocussedComponentPeer = null; } @@ -658,8 +668,8 @@ final class WInputMethod extends InputMethodAdapter } - private native int createNativeContext(); - private native void destroyNativeContext(int context); + private static native int createNativeContext(); + private static native void destroyNativeContext(int context); private native void enableNativeIME(WComponentPeer peer, int context, boolean useNativeCompWindow); private native void disableNativeIME(WComponentPeer peer); private native void handleNativeIMEEvent(WComponentPeer peer, AWTEvent e); diff --git a/src/java.desktop/windows/native/libawt/windows/awt_InputMethod.cpp b/src/java.desktop/windows/native/libawt/windows/awt_InputMethod.cpp index fcc6e4c2cb8..87087870b5d 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_InputMethod.cpp +++ b/src/java.desktop/windows/native/libawt/windows/awt_InputMethod.cpp @@ -52,7 +52,7 @@ extern BOOL g_bUserHasChangedInputLang; * Signature: ()I */ JNIEXPORT jint JNICALL -Java_sun_awt_windows_WInputMethod_createNativeContext(JNIEnv *env, jobject self) +Java_sun_awt_windows_WInputMethod_createNativeContext(JNIEnv *env, jclass cls) { TRY; @@ -69,7 +69,7 @@ Java_sun_awt_windows_WInputMethod_createNativeContext(JNIEnv *env, jobject self) * Signature: (I)V */ JNIEXPORT void JNICALL -Java_sun_awt_windows_WInputMethod_destroyNativeContext(JNIEnv *env, jobject self, jint context) +Java_sun_awt_windows_WInputMethod_destroyNativeContext(JNIEnv *env, jclass cls, jint context) { TRY_NO_VERIFY; From f0498c2aed761d4023917bc9cd1f852a02ce977a Mon Sep 17 00:00:00 2001 From: Alan Bateman Date: Fri, 22 Aug 2025 08:16:55 +0000 Subject: [PATCH 34/54] 8364764: java/nio/channels/vthread/BlockingChannelOps.java subtests timed out Reviewed-by: jpai --- .../channels/vthread/BlockingChannelOps.java | 140 ++++++++++++++---- 1 file changed, 109 insertions(+), 31 deletions(-) diff --git a/test/jdk/java/nio/channels/vthread/BlockingChannelOps.java b/test/jdk/java/nio/channels/vthread/BlockingChannelOps.java index 7ff02cdfea4..1cdd090d1be 100644 --- a/test/jdk/java/nio/channels/vthread/BlockingChannelOps.java +++ b/test/jdk/java/nio/channels/vthread/BlockingChannelOps.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * 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,7 +21,7 @@ * questions. */ -/** +/* * @test id=default * @bug 8284161 * @summary Test virtual threads doing blocking I/O on NIO channels @@ -29,7 +29,7 @@ * @run junit BlockingChannelOps */ -/** +/* * @test id=poller-modes * @requires (os.family == "linux") | (os.family == "mac") * @library /test/lib @@ -37,7 +37,7 @@ * @run junit/othervm -Djdk.pollerMode=2 BlockingChannelOps */ -/** +/* * @test id=no-vmcontinuations * @requires vm.continuations * @library /test/lib @@ -62,6 +62,7 @@ import java.nio.channels.ReadableByteChannel; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.nio.channels.WritableByteChannel; +import java.util.concurrent.locks.LockSupport; import jdk.test.lib.thread.VThreadRunner; import org.junit.jupiter.api.Test; @@ -161,6 +162,22 @@ class BlockingChannelOps { }); } + /** + * SocketChannel shutdownInput while virtual thread blocked in read. + */ + @Test + void testSocketChannelReadAsyncShutdownInput() throws Exception { + VThreadRunner.run(() -> { + try (var connection = new Connection()) { + SocketChannel sc = connection.channel1(); + runAfterParkedAsync(sc::shutdownInput); + int n = sc.read(ByteBuffer.allocate(100)); + assertEquals(-1, n); + assertTrue(sc.isOpen()); + } + }); + } + /** * Virtual thread interrupted while blocked in SocketChannel read. */ @@ -190,13 +207,15 @@ class BlockingChannelOps { @Test void testSocketChannelWriteAsyncClose() throws Exception { VThreadRunner.run(() -> { - boolean retry = true; - while (retry) { + boolean done = false; + while (!done) { try (var connection = new Connection()) { SocketChannel sc = connection.channel1(); // close sc when current thread blocks in write - runAfterParkedAsync(sc::close); + runAfterParkedAsync(sc::close, true); + + // write until channel is closed try { ByteBuffer bb = ByteBuffer.allocate(100*1024); for (;;) { @@ -206,30 +225,59 @@ class BlockingChannelOps { } } catch (AsynchronousCloseException expected) { // closed when blocked in write - retry = false; + done = true; } catch (ClosedChannelException e) { - // closed when not blocked in write, need to retry test + // closed but not blocked in write, need to retry test + System.err.format("%s, need to retry!%n", e); } } } }); } + + /** + * SocketChannel shutdownOutput while virtual thread blocked in write. + */ + @Test + void testSocketChannelWriteAsyncShutdownOutput() throws Exception { + VThreadRunner.run(() -> { + try (var connection = new Connection()) { + SocketChannel sc = connection.channel1(); + + // shutdown output when current thread blocks in write + runAfterParkedAsync(sc::shutdownOutput); + try { + ByteBuffer bb = ByteBuffer.allocate(100*1024); + for (;;) { + int n = sc.write(bb); + assertTrue(n > 0); + bb.clear(); + } + } catch (ClosedChannelException e) { + // expected + } + assertTrue(sc.isOpen()); + } + }); + } + /** * Virtual thread interrupted while blocked in SocketChannel write. */ @Test void testSocketChannelWriteInterrupt() throws Exception { VThreadRunner.run(() -> { - boolean retry = true; - while (retry) { + boolean done = false; + while (!done) { try (var connection = new Connection()) { SocketChannel sc = connection.channel1(); // interrupt current thread when it blocks in write Thread thisThread = Thread.currentThread(); - runAfterParkedAsync(thisThread::interrupt); + runAfterParkedAsync(thisThread::interrupt, true); + // write until channel is closed try { ByteBuffer bb = ByteBuffer.allocate(100*1024); for (;;) { @@ -240,9 +288,10 @@ class BlockingChannelOps { } catch (ClosedByInterruptException e) { // closed when blocked in write assertTrue(Thread.interrupted()); - retry = false; + done = true; } catch (ClosedChannelException e) { - // closed when not blocked in write, need to retry test + // closed but not blocked in write, need to retry test + System.err.format("%s, need to retry!%n", e); } } } @@ -734,14 +783,16 @@ class BlockingChannelOps { @Test void testPipeWriteAsyncClose() throws Exception { VThreadRunner.run(() -> { - boolean retry = true; - while (retry) { + boolean done = false; + while (!done) { Pipe p = Pipe.open(); try (Pipe.SinkChannel sink = p.sink(); Pipe.SourceChannel source = p.source()) { // close sink when current thread blocks in write - runAfterParkedAsync(sink::close); + runAfterParkedAsync(sink::close, true); + + // write until channel is closed try { ByteBuffer bb = ByteBuffer.allocate(100*1024); for (;;) { @@ -751,9 +802,10 @@ class BlockingChannelOps { } } catch (AsynchronousCloseException e) { // closed when blocked in write - retry = false; + done = true; } catch (ClosedChannelException e) { - // closed when not blocked in write, need to retry test + // closed but not blocked in write, need to retry test + System.err.format("%s, need to retry!%n", e); } } } @@ -766,16 +818,17 @@ class BlockingChannelOps { @Test void testPipeWriteInterrupt() throws Exception { VThreadRunner.run(() -> { - boolean retry = true; - while (retry) { + boolean done = false; + while (!done) { Pipe p = Pipe.open(); try (Pipe.SinkChannel sink = p.sink(); Pipe.SourceChannel source = p.source()) { // interrupt current thread when it blocks in write Thread thisThread = Thread.currentThread(); - runAfterParkedAsync(thisThread::interrupt); + runAfterParkedAsync(thisThread::interrupt, true); + // write until channel is closed try { ByteBuffer bb = ByteBuffer.allocate(100*1024); for (;;) { @@ -786,9 +839,10 @@ class BlockingChannelOps { } catch (ClosedByInterruptException expected) { // closed when blocked in write assertTrue(Thread.interrupted()); - retry = false; + done = true; } catch (ClosedChannelException e) { - // closed when not blocked in write, need to retry test + // closed but not blocked in write, need to retry test + System.err.format("%s, need to retry!%n", e); } } } @@ -848,26 +902,50 @@ class BlockingChannelOps { } /** - * Runs the given task asynchronously after the current virtual thread has parked. + * Runs the given task asynchronously after the current virtual thread parks. + * @param writing if the thread will block in write * @return the thread started to run the task */ - static Thread runAfterParkedAsync(ThrowingRunnable task) { + private static Thread runAfterParkedAsync(ThrowingRunnable task, boolean writing) { Thread target = Thread.currentThread(); if (!target.isVirtual()) throw new WrongThreadException(); return Thread.ofPlatform().daemon().start(() -> { try { - Thread.State state = target.getState(); - while (state != Thread.State.WAITING - && state != Thread.State.TIMED_WAITING) { + // wait for target thread to park + while (!isWaiting(target)) { Thread.sleep(20); - state = target.getState(); } - Thread.sleep(20); // give a bit more time to release carrier + + // if the target thread is parked in write then we nudge it a few times + // to avoid wakeup with some bytes written + if (writing) { + for (int i = 0; i < 3; i++) { + LockSupport.unpark(target); + while (!isWaiting(target)) { + Thread.sleep(20); + } + } + } + task.run(); + } catch (Exception e) { e.printStackTrace(); } }); } + + private static Thread runAfterParkedAsync(ThrowingRunnable task) { + return runAfterParkedAsync(task, false); + } + + /** + * Return true if the given Thread is parked. + */ + private static boolean isWaiting(Thread target) { + Thread.State state = target.getState(); + assertNotEquals(Thread.State.TERMINATED, state); + return (state == Thread.State.WAITING || state == Thread.State.TIMED_WAITING); + } } From e1c58f858a64853c2d454fd00a84455ca6700055 Mon Sep 17 00:00:00 2001 From: Martin Doerr Date: Fri, 22 Aug 2025 09:01:21 +0000 Subject: [PATCH 35/54] 8360540: nmethod entry barriers of new nmethods should be disarmed Reviewed-by: eosterlund, tschatzl --- src/hotspot/share/gc/g1/g1CollectedHeap.cpp | 3 +++ src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp | 3 +++ src/hotspot/share/gc/serial/serialHeap.cpp | 3 +++ 3 files changed, 9 insertions(+) diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index e50821e96c1..bf512cfa19d 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp @@ -74,6 +74,7 @@ #include "gc/g1/g1VMOperations.hpp" #include "gc/g1/g1YoungCollector.hpp" #include "gc/g1/g1YoungGCAllocationFailureInjector.hpp" +#include "gc/shared/barrierSetNMethod.hpp" #include "gc/shared/classUnloadingContext.hpp" #include "gc/shared/concurrentGCBreakpoints.hpp" #include "gc/shared/fullGCForwarding.hpp" @@ -3079,6 +3080,8 @@ void G1CollectedHeap::register_nmethod(nmethod* nm) { guarantee(nm != nullptr, "sanity"); RegisterNMethodOopClosure reg_cl(this, nm); nm->oops_do(®_cl); + BarrierSetNMethod* bs_nm = BarrierSet::barrier_set()->barrier_set_nmethod(); + bs_nm->disarm(nm); } void G1CollectedHeap::unregister_nmethod(nmethod* nm) { diff --git a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp index c6a9a312e5c..07ae097c5b8 100644 --- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp +++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp @@ -32,6 +32,7 @@ #include "gc/parallel/psPromotionManager.hpp" #include "gc/parallel/psScavenge.hpp" #include "gc/parallel/psVMOperations.hpp" +#include "gc/shared/barrierSetNMethod.hpp" #include "gc/shared/fullGCForwarding.inline.hpp" #include "gc/shared/gcHeapSummary.hpp" #include "gc/shared/gcLocker.inline.hpp" @@ -861,6 +862,8 @@ void ParallelScavengeHeap::complete_loaded_archive_space(MemRegion archive_space void ParallelScavengeHeap::register_nmethod(nmethod* nm) { ScavengableNMethods::register_nmethod(nm); + BarrierSetNMethod* bs_nm = BarrierSet::barrier_set()->barrier_set_nmethod(); + bs_nm->disarm(nm); } void ParallelScavengeHeap::unregister_nmethod(nmethod* nm) { diff --git a/src/hotspot/share/gc/serial/serialHeap.cpp b/src/hotspot/share/gc/serial/serialHeap.cpp index 6b9328b8697..72f8ad85a4e 100644 --- a/src/hotspot/share/gc/serial/serialHeap.cpp +++ b/src/hotspot/share/gc/serial/serialHeap.cpp @@ -34,6 +34,7 @@ #include "gc/serial/serialMemoryPools.hpp" #include "gc/serial/serialVMOperations.hpp" #include "gc/serial/tenuredGeneration.inline.hpp" +#include "gc/shared/barrierSetNMethod.hpp" #include "gc/shared/cardTableBarrierSet.hpp" #include "gc/shared/classUnloadingContext.hpp" #include "gc/shared/collectedHeap.inline.hpp" @@ -432,6 +433,8 @@ bool SerialHeap::do_young_collection(bool clear_soft_refs) { void SerialHeap::register_nmethod(nmethod* nm) { ScavengableNMethods::register_nmethod(nm); + BarrierSetNMethod* bs_nm = BarrierSet::barrier_set()->barrier_set_nmethod(); + bs_nm->disarm(nm); } void SerialHeap::unregister_nmethod(nmethod* nm) { From f5f414f9fc67e55acb83e04ea270d39041cb6198 Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Fri, 22 Aug 2025 15:57:11 +0000 Subject: [PATCH 36/54] 8365186: Reduce size of j.t.f.DateTimePrintContext::adjust Reviewed-by: rriggs --- .../time/format/DateTimePrintContext.java | 88 ++++++++++++++++++- 1 file changed, 87 insertions(+), 1 deletion(-) diff --git a/src/java.base/share/classes/java/time/format/DateTimePrintContext.java b/src/java.base/share/classes/java/time/format/DateTimePrintContext.java index c7eed23b7bc..d755ba3ee78 100644 --- a/src/java.base/share/classes/java/time/format/DateTimePrintContext.java +++ b/src/java.base/share/classes/java/time/format/DateTimePrintContext.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -120,6 +120,19 @@ final class DateTimePrintContext { this.formatter = formatter; } + /** + * Adjusts the given {@link TemporalAccessor} using chronology and time-zone from a formatter if present. + *

    + * This method serves as an optimization front-end that checks for non-null overrides in the formatter. + * If neither chronology nor time-zone is specified in the formatter, returns the original temporal unchanged. + * Otherwise, delegates to the core adjustment method {@link #adjustWithOverride(TemporalAccessor, Chronology, ZoneId)}. + * + * @implNote Optimizes for the common case where formatters don't specify chronology/time-zone + * by avoiding unnecessary processing. Most formatters have null for these properties. + * @param temporal the temporal object to adjust, not null + * @param formatter the formatter providing potential chronology and time-zone overrides + * @return the adjusted temporal, or the original if no overrides are present in the formatter + */ private static TemporalAccessor adjust(final TemporalAccessor temporal, DateTimeFormatter formatter) { // normal case first (early return is an optimization) Chronology overrideChrono = formatter.getChronology(); @@ -128,6 +141,32 @@ final class DateTimePrintContext { return temporal; } + // Placing the non-null cases in a separate method allows more flexible code optimizations + return adjustWithOverride(temporal, overrideChrono, overrideZone); + } + + /** + * Adjusts the given {@link TemporalAccessor} with optional overriding chronology and time-zone. + *

    + * This method minimizes changes by returning the original temporal if the override parameters + * are either {@code null} or equivalent to those already present in the temporal. When overrides + * are applied: + *

      + *
    • If a time-zone override is provided and the temporal supports {@link ChronoField#INSTANT_SECONDS}, + * the result is a zoned date-time using the override time-zone and chronology (defaulting to ISO if not overridden).
    • + *
    • Other cases (including partial date-times or mixed chronology/time-zone changes) are delegated + * to a secondary adjustment method.
    • + *
    + * + * @param temporal the temporal object to adjust, not null + * @param overrideChrono the chronology to override (null retains the original chronology) + * @param overrideZone the time-zone to override (null retains the original time-zone) + * @return the adjusted temporal, which may be the original object if no effective changes were made, + * or a new object with the applied overrides + * @implNote Optimizes for common cases where overrides are identical to existing values + * or where instant-based temporals can be directly converted with a time-zone. + */ + private static TemporalAccessor adjustWithOverride(TemporalAccessor temporal, Chronology overrideChrono, ZoneId overrideZone) { // ensure minimal change (early return is an optimization) Chronology temporalChrono = temporal.query(TemporalQueries.chronology()); ZoneId temporalZone = temporal.query(TemporalQueries.zoneId()); @@ -149,6 +188,53 @@ final class DateTimePrintContext { Chronology chrono = Objects.requireNonNullElse(effectiveChrono, IsoChronology.INSTANCE); return chrono.zonedDateTime(Instant.from(temporal), overrideZone); } + } + + // Split uncommon code branches into a separate method + return adjustSlow(temporal, overrideZone, temporalZone, overrideChrono, effectiveChrono, temporalChrono); + } + + /** + * Internal helper method to adjust temporal fields using override chronology and time-zone in complex cases. + *

    + * Handles non-instant temporal objects by creating a delegate {@link TemporalAccessor} that combines: + *

      + *
    • The original temporal's time-related fields
    • + *
    • Date fields converted to the effective chronology (if available)
    • + *
    • Override zone/chronology information for temporal queries
    • + *
    + * + * Performs critical validation before processing: + *
      + *
    • Rejects offset changes for non-instant temporal objects with existing offsets
    • + *
    • Verifies date field integrity when applying chronology overrides to partial dates
    • + *
    + * + * @param temporal the original temporal object to adjust, not null + * @param overrideZone override time-zone (nullable) + * @param temporalZone original time-zone from temporal (nullable) + * @param overrideChrono override chronology (nullable) + * @param effectiveChrono precomputed effective chronology (override if present, otherwise temporal's chronology) + * @param temporalChrono original chronology from temporal (nullable) + * @return adjusted temporal accessor combining original fields with overrides + * @throws DateTimeException if: + *
      + *
    • Applying a {@link ZoneOffset} override to a temporal with conflicting existing offset that doesn't represent an instant
    • + *
    • Applying chronology override to temporal with partial date fields
    • + *
    + * @implNote Creates an anonymous temporal accessor that: + *
      + *
    • Delegates time-based fields to original temporal
    • + *
    • Uses converted date fields when chronology override is applied
    • + *
    • Responds to chronology/zone queries with effective values
    • + *
    • Preserves precision queries from original temporal
    • + *
    + */ + private static TemporalAccessor adjustSlow( + TemporalAccessor temporal, + ZoneId overrideZone, ZoneId temporalZone, + Chronology overrideChrono, Chronology effectiveChrono, Chronology temporalChrono) { + if (overrideZone != null) { // block changing zone on OffsetTime, and similar problem cases if (overrideZone.normalized() instanceof ZoneOffset && temporal.isSupported(OFFSET_SECONDS) && temporal.get(OFFSET_SECONDS) != overrideZone.getRules().getOffset(Instant.EPOCH).getTotalSeconds()) { From dba0d545053fb73e57ea6fda829a5bf3d0135ac5 Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Fri, 22 Aug 2025 16:44:47 +0000 Subject: [PATCH 37/54] 8365832: Optimize FloatingDecimal and DigitList with byte[] and cleanup Reviewed-by: rgiulietti, liach --- .../share/classes/java/text/DigitList.java | 69 +++--- .../jdk/internal/math/FloatingDecimal.java | 218 ++++-------------- 2 files changed, 87 insertions(+), 200 deletions(-) diff --git a/src/java.base/share/classes/java/text/DigitList.java b/src/java.base/share/classes/java/text/DigitList.java index 41c143178da..2895126f93b 100644 --- a/src/java.base/share/classes/java/text/DigitList.java +++ b/src/java.base/share/classes/java/text/DigitList.java @@ -41,6 +41,9 @@ package java.text; import java.math.BigDecimal; import java.math.BigInteger; import java.math.RoundingMode; +import java.nio.charset.StandardCharsets; + +import jdk.internal.access.SharedSecrets; import jdk.internal.math.FloatingDecimal; import jdk.internal.util.ArraysSupport; @@ -103,9 +106,9 @@ final class DigitList implements Cloneable { */ public int decimalAt = 0; public int count = 0; - public char[] digits = new char[MAX_COUNT]; + public byte[] digits = new byte[MAX_COUNT]; - private char[] data; + private byte[] data; private RoundingMode roundingMode = RoundingMode.HALF_EVEN; private boolean isNegative = false; @@ -154,11 +157,11 @@ final class DigitList implements Cloneable { */ public void append(char digit) { if (count == digits.length) { - char[] data = new char[ArraysSupport.newLength(count, 1, count)]; + byte[] data = new byte[ArraysSupport.newLength(count, 1, count)]; System.arraycopy(digits, 0, data, 0, count); digits = data; } - digits[count++] = digit; + digits[count++] = (byte) digit; } /** @@ -188,7 +191,7 @@ final class DigitList implements Cloneable { // Parse as unsigned to handle Long.MIN_VALUE, which is the one NEGATIVE value // we represent. If we tried to just pass the digits off to parseLong, // we'd get a parse failure. - long v = Long.parseUnsignedLong(new String(digits, 0, count)); + long v = Long.parseUnsignedLong(new String(digits, 0, count, StandardCharsets.ISO_8859_1)); if (v < 0) { if (v == Long.MIN_VALUE) { return Long.MIN_VALUE; @@ -209,15 +212,20 @@ final class DigitList implements Cloneable { * unlike BigDecimal(""). */ public BigDecimal getBigDecimal() { + int count = this.count; if (count == 0) { return BigDecimal.valueOf(0, -decimalAt); } - if (decimalAt == count) { - return new BigDecimal(digits, 0, count); - } else { - return new BigDecimal(digits, 0, count).scaleByPowerOfTen(decimalAt - count); - } + char[] chars = new char[count]; + SharedSecrets.getJavaLangAccess() + .inflateBytesToChars(digits, 0, chars, 0, count); + BigDecimal value = new BigDecimal(chars, 0, count); + if (decimalAt == count) { + return value; + } else { + return value.scaleByPowerOfTen(decimalAt - count); + } } /** @@ -256,7 +264,7 @@ final class DigitList implements Cloneable { // The number will overflow if it is larger than 9223372036854775807 // or smaller than -9223372036854775808. for (int i=0; i max) return false; if (dig < max) return true; } @@ -317,9 +325,10 @@ final class DigitList implements Cloneable { boolean hasBeenRoundedUp = fdConverter.digitsRoundedUp(); boolean valueExactAsDecimal = fdConverter.decimalDigitsExact(); assert !fdConverter.isExceptional(); - String digitsString = fdConverter.toJavaFormatString(); - set(isNegative, digitsString, + byte[] chars = getDataChars(26); + int len = fdConverter.getChars(chars); + set(isNegative, chars, len, hasBeenRoundedUp, valueExactAsDecimal, maximumDigits, fixedPoint); } @@ -331,14 +340,11 @@ final class DigitList implements Cloneable { * @param valueExactAsDecimal whether or not collected digits provide * an exact decimal representation of the value. */ - private void set(boolean isNegative, String s, + private void set(boolean isNegative, byte[] source, int len, boolean roundedUp, boolean valueExactAsDecimal, int maximumDigits, boolean fixedPoint) { this.isNegative = isNegative; - int len = s.length(); - char[] source = getDataChars(len); - s.getChars(0, len, source, 0); decimalAt = -1; count = 0; @@ -349,7 +355,7 @@ final class DigitList implements Cloneable { boolean nonZeroDigitSeen = false; for (int i = 0; i < len; ) { - char c = source[i++]; + byte c = source[i++]; if (c == '.') { decimalAt = count; } else if (c == 'e' || c == 'E') { @@ -633,7 +639,7 @@ final class DigitList implements Cloneable { int left = MAX_COUNT; int right; while (source > 0) { - digits[--left] = (char)('0' + (source % 10)); + digits[--left] = (byte)('0' + (source % 10)); source /= 10; } decimalAt = MAX_COUNT - left; @@ -661,11 +667,15 @@ final class DigitList implements Cloneable { * @param fixedPoint If true, then maximumDigits is the maximum * fractional digits to be converted. If false, total digits. */ + @SuppressWarnings("deprecation") void set(boolean isNegative, BigDecimal source, int maximumDigits, boolean fixedPoint) { String s = source.toString(); extendDigits(s.length()); - set(isNegative, s, + int len = s.length(); + byte[] chars = getDataChars(len); + s.getBytes(0, len, chars, 0); + set(isNegative, chars, len, false, true, maximumDigits, fixedPoint); } @@ -678,12 +688,13 @@ final class DigitList implements Cloneable { * If maximumDigits is lower than the number of significant digits * in source, the representation will be rounded. Ignored if <= 0. */ + @SuppressWarnings("deprecation") void set(boolean isNegative, BigInteger source, int maximumDigits) { this.isNegative = isNegative; String s = source.toString(); int len = s.length(); extendDigits(len); - s.getChars(0, len, digits, 0); + s.getBytes(0, len, digits, 0); decimalAt = len; int right = len - 1; @@ -734,7 +745,7 @@ final class DigitList implements Cloneable { public Object clone() { try { DigitList other = (DigitList) super.clone(); - char[] newDigits = new char[digits.length]; + byte[] newDigits = new byte[digits.length]; System.arraycopy(digits, 0, newDigits, 0, digits.length); other.digits = newDigits; @@ -749,8 +760,8 @@ final class DigitList implements Cloneable { } } - private static int parseInt(char[] str, int offset, int strLen) { - char c; + private static int parseInt(byte[] str, int offset, int strLen) { + byte c; boolean positive = true; if ((c = str[offset]) == '-') { positive = false; @@ -772,25 +783,25 @@ final class DigitList implements Cloneable { } // The digit part of -9223372036854775808L - private static final char[] LONG_MIN_REP = "9223372036854775808".toCharArray(); + private static final byte[] LONG_MIN_REP = "9223372036854775808".getBytes(StandardCharsets.ISO_8859_1); public String toString() { if (isZero()) { return "0"; } - return "0." + new String(digits, 0, count) + "x10^" + decimalAt; + return "0." + new String(digits, 0, count, StandardCharsets.ISO_8859_1) + "x10^" + decimalAt; } private void extendDigits(int len) { if (len > digits.length) { - digits = new char[len]; + digits = new byte[len]; } } - private char[] getDataChars(int length) { + private byte[] getDataChars(int length) { if (data == null || data.length < length) { - data = new char[length]; + data = new byte[length]; } return data; } diff --git a/src/java.base/share/classes/jdk/internal/math/FloatingDecimal.java b/src/java.base/share/classes/jdk/internal/math/FloatingDecimal.java index 168f76fad8f..32399310bd3 100644 --- a/src/java.base/share/classes/jdk/internal/math/FloatingDecimal.java +++ b/src/java.base/share/classes/jdk/internal/math/FloatingDecimal.java @@ -60,44 +60,6 @@ public class FloatingDecimal{ static final int INT_DECIMAL_DIGITS = 9; - /** - * Converts a double precision floating point value to a String. - * - * @param d The double precision value. - * @return The value converted to a String. - */ - public static String toJavaFormatString(double d) { - return getBinaryToASCIIConverter(d).toJavaFormatString(); - } - - /** - * Converts a single precision floating point value to a String. - * - * @param f The single precision value. - * @return The value converted to a String. - */ - public static String toJavaFormatString(float f) { - return getBinaryToASCIIConverter(f).toJavaFormatString(); - } - - /** - * Appends a double precision floating point value to an Appendable. - * @param d The double precision value. - * @param buf The Appendable with the value appended. - */ - public static void appendTo(double d, Appendable buf) { - getBinaryToASCIIConverter(d).appendTo(buf); - } - - /** - * Appends a single precision floating point value to an Appendable. - * @param f The single precision value. - * @param buf The Appendable with the value appended. - */ - public static void appendTo(float f, Appendable buf) { - getBinaryToASCIIConverter(f).appendTo(buf); - } - /** * Converts a String to a double precision floating point value. * @@ -131,7 +93,7 @@ public class FloatingDecimal{ * @param length Number of digits to use * @return The double-precision value of the conversion */ - public static double parseDoubleSignlessDigits(int decExp, char[] digits, int length) { + public static double parseDoubleSignlessDigits(int decExp, byte[] digits, int length) { return readDoubleSignlessDigits(decExp, digits, length).doubleValue(); } @@ -140,17 +102,7 @@ public class FloatingDecimal{ * values into an ASCII String representation. */ public interface BinaryToASCIIConverter { - /** - * Converts a floating point value into an ASCII String. - * @return The value converted to a String. - */ - String toJavaFormatString(); - - /** - * Appends a floating point value to an Appendable. - * @param buf The Appendable to receive the value. - */ - void appendTo(Appendable buf); + int getChars(byte[] result); /** * Retrieves the decimal exponent most closely corresponding to this value. @@ -209,19 +161,10 @@ public class FloatingDecimal{ } @Override - public String toJavaFormatString() { - return image; - } - - @Override - public void appendTo(Appendable buf) { - if (buf instanceof StringBuilder) { - ((StringBuilder) buf).append(image); - } else if (buf instanceof StringBuffer) { - ((StringBuffer) buf).append(image); - } else { - assert false; - } + @SuppressWarnings("deprecation") + public int getChars(byte[] chars) { + image.getBytes(0, image.length(), chars, 0); + return image.length(); } @Override @@ -261,8 +204,8 @@ public class FloatingDecimal{ private static final BinaryToASCIIConverter B2AC_POSITIVE_INFINITY = new ExceptionalBinaryToASCIIBuffer(INFINITY_REP, false); private static final BinaryToASCIIConverter B2AC_NEGATIVE_INFINITY = new ExceptionalBinaryToASCIIBuffer("-" + INFINITY_REP, true); private static final BinaryToASCIIConverter B2AC_NOT_A_NUMBER = new ExceptionalBinaryToASCIIBuffer(NAN_REP, false); - private static final BinaryToASCIIConverter B2AC_POSITIVE_ZERO = new BinaryToASCIIBuffer(false, new char[]{'0'}); - private static final BinaryToASCIIConverter B2AC_NEGATIVE_ZERO = new BinaryToASCIIBuffer(true, new char[]{'0'}); + private static final BinaryToASCIIConverter B2AC_POSITIVE_ZERO = new BinaryToASCIIBuffer(false, new byte[]{'0'}); + private static final BinaryToASCIIConverter B2AC_NEGATIVE_ZERO = new BinaryToASCIIBuffer(true, new byte[]{'0'}); /** * A buffered implementation of BinaryToASCIIConverter. @@ -272,8 +215,7 @@ public class FloatingDecimal{ private int decExponent; private int firstDigitIndex; private int nDigits; - private final char[] digits; - private final char[] buffer = new char[26]; + private final byte[] digits; // // The fields below provide additional information about the result of @@ -293,13 +235,13 @@ public class FloatingDecimal{ * BinaryToASCIIBuffer may be thread-local and reused */ BinaryToASCIIBuffer(){ - this.digits = new char[20]; + this.digits = new byte[20]; } /** * Creates a specialized value (positive and negative zeros). */ - BinaryToASCIIBuffer(boolean isNegative, char[] digits){ + BinaryToASCIIBuffer(boolean isNegative, byte[] digits){ this.isNegative = isNegative; this.decExponent = 0; this.digits = digits; @@ -307,24 +249,6 @@ public class FloatingDecimal{ this.nDigits = digits.length; } - @Override - public String toJavaFormatString() { - int len = getChars(buffer); - return new String(buffer, 0, len); - } - - @Override - public void appendTo(Appendable buf) { - int len = getChars(buffer); - if (buf instanceof StringBuilder) { - ((StringBuilder) buf).append(buffer, 0, len); - } else if (buf instanceof StringBuffer) { - ((StringBuffer) buf).append(buffer, 0, len); - } else { - assert false; - } - } - @Override public int getDecimalExponent() { return decExponent; @@ -403,12 +327,12 @@ public class FloatingDecimal{ ivalue /= 10; } while ( ivalue != 0){ - digits[digitno--] = (char)(c+'0'); + digits[digitno--] = (byte)(c+'0'); decExponent++; c = ivalue%10; ivalue /= 10; } - digits[digitno] = (char)(c+'0'); + digits[digitno] = (byte)(c+'0'); } else { // same algorithm as above (same bugs, too ) // but using long arithmetic. @@ -420,12 +344,12 @@ public class FloatingDecimal{ lvalue /= 10L; } while ( lvalue != 0L ){ - digits[digitno--] = (char)(c+'0'); + digits[digitno--] = (byte) (c+'0'); decExponent++; c = (int)(lvalue%10L); lvalue /= 10; } - digits[digitno] = (char)(c+'0'); + digits[digitno] = (byte)(c+'0'); } this.decExponent = decExponent+1; this.firstDigitIndex = digitno; @@ -626,7 +550,7 @@ public class FloatingDecimal{ // oops. Usually ignore leading zero. decExp--; } else { - digits[ndigit++] = (char)('0' + q); + digits[ndigit++] = (byte)('0' + q); } // // HACK! Java spec sez that we always have at least @@ -654,7 +578,7 @@ public class FloatingDecimal{ low = true; high = true; } - digits[ndigit++] = (char)('0' + q); + digits[ndigit++] = (byte)('0' + q); } lowDigitDifference = (b<<1) - tens; exactDecimalConversion = (b == 0); @@ -680,7 +604,7 @@ public class FloatingDecimal{ // oops. Usually ignore leading zero. decExp--; } else { - digits[ndigit++] = (char)('0' + q); + digits[ndigit++] = (byte)('0' + q); } // // HACK! Java spec sez that we always have at least @@ -708,7 +632,7 @@ public class FloatingDecimal{ low = true; high = true; } - digits[ndigit++] = (char)('0' + q); + digits[ndigit++] = (byte)('0' + q); } lowDigitDifference = (b<<1) - tens; exactDecimalConversion = (b == 0); @@ -741,7 +665,7 @@ public class FloatingDecimal{ // oops. Usually ignore leading zero. decExp--; } else { - digits[ndigit++] = (char)('0' + q); + digits[ndigit++] = (byte)('0' + q); } // // HACK! Java spec sez that we always have at least @@ -758,7 +682,7 @@ public class FloatingDecimal{ Mval = Mval.multBy10(); //Mval = Mval.mult( 10 ); low = (Bval.cmp( Mval ) < 0); high = tenSval.addAndCmp(Bval,Mval)<=0; - digits[ndigit++] = (char)('0' + q); + digits[ndigit++] = (byte)('0' + q); } if ( high && low ){ Bval = Bval.leftShift(1); @@ -812,7 +736,7 @@ public class FloatingDecimal{ } // else fall through. } - digits[i] = (char) (q + 1); + digits[i] = (byte) (q + 1); decimalDigitsRoundedUp = true; } @@ -845,19 +769,8 @@ public class FloatingDecimal{ } } - private static int insignificantDigits(long insignificant) { - int i; - for ( i = 0; insignificant >= 10L; i++ ) { - insignificant /= 10L; - } - return i; - } - /** * Calculates - *
    -         * insignificantDigitsForPow2(v) == insignificantDigits(1L<
              */
             private static int insignificantDigitsForPow2(int p2) {
                 if (p2 > 1 && p2 < insignificantDigitsNumber.length) {
    @@ -913,7 +826,14 @@ public class FloatingDecimal{
                     61,
             };
     
    -        private int getChars(char[] result) {
    +        /**
    +         * Converts the decimal representation of a floating-point number into its
    +         * ASCII character representation and stores it in the provided byte array.
    +         *
    +         * @param result the byte array to store the ASCII representation, must have length at least 26
    +         * @return the number of characters written to the result array
    +         */
    +        public int getChars(byte[] result) {
                 assert nDigits <= 19 : nDigits; // generous bound on size of nDigits
                 int i = 0;
                 if (isNegative) {
    @@ -927,7 +847,7 @@ public class FloatingDecimal{
                     i += charLength;
                     if (charLength < decExponent) {
                         charLength = decExponent - charLength;
    -                    Arrays.fill(result,i,i+charLength,'0');
    +                    Arrays.fill(result, i, i + charLength, (byte) '0');
                         i += charLength;
                         result[i++] = '.';
                         result[i++] = '0';
    @@ -935,7 +855,7 @@ public class FloatingDecimal{
                         result[i++] = '.';
                         if (charLength < nDigits) {
                             int t = nDigits - charLength;
    -                        System.arraycopy(digits, firstDigitIndex+charLength, result, i, t);
    +                        System.arraycopy(digits, firstDigitIndex + charLength, result, i, t);
                             i += t;
                         } else {
                             result[i++] = '0';
    @@ -945,7 +865,7 @@ public class FloatingDecimal{
                     result[i++] = '0';
                     result[i++] = '.';
                     if (decExponent != 0) {
    -                    Arrays.fill(result, i, i-decExponent, '0');
    +                    Arrays.fill(result, i, i-decExponent, (byte) '0');
                         i -= decExponent;
                     }
                     System.arraycopy(digits, firstDigitIndex, result, i, nDigits);
    @@ -969,15 +889,15 @@ public class FloatingDecimal{
                     }
                     // decExponent has 1, 2, or 3, digits
                     if (e <= 9) {
    -                    result[i++] = (char) (e + '0');
    +                    result[i++] = (byte) (e + '0');
                     } else if (e <= 99) {
    -                    result[i++] = (char) (e / 10 + '0');
    -                    result[i++] = (char) (e % 10 + '0');
    +                    result[i++] = (byte) (e / 10 + '0');
    +                    result[i++] = (byte) (e % 10 + '0');
                     } else {
    -                    result[i++] = (char) (e / 100 + '0');
    +                    result[i++] = (byte) (e / 100 + '0');
                         e %= 100;
    -                    result[i++] = (char) (e / 10 + '0');
    -                    result[i++] = (char) (e % 10 + '0');
    +                    result[i++] = (byte) (e / 10 + '0');
    +                    result[i++] = (byte) (e % 10 + '0');
                     }
                 }
                 return i;
    @@ -1043,10 +963,10 @@ public class FloatingDecimal{
          * A buffered implementation of ASCIIToBinaryConverter.
          */
         static class ASCIIToBinaryBuffer implements ASCIIToBinaryConverter {
    -        boolean     isNegative;
    -        int         decExponent;
    -        byte[]      digits;
    -        int         nDigits;
    +        final boolean isNegative;
    +        final int     decExponent;
    +        final byte[]  digits;
    +        int           nDigits;
     
             ASCIIToBinaryBuffer( boolean negSign, int decExponent, byte[] digits, int n)
             {
    @@ -1765,10 +1685,10 @@ public class FloatingDecimal{
             buf.decimalDigitsRoundedUp = dec.getAway();
     
             long f = dec.getSignificand();
    -        char[] digits = buf.digits;
    +        byte[] digits = buf.digits;
             for (int i = buf.nDigits - 1; i >= 0; --i) {
                 long q = f / 10;
    -            digits[i] = (char) ((f - 10 * q) + '0');
    +            digits[i] = (byte) ((f - 10 * q) + '0');
                 f = q;
             }
             return buf;
    @@ -1819,58 +1739,14 @@ public class FloatingDecimal{
             return buf;
         }
     
    -    private static BinaryToASCIIConverter getBinaryToASCIIConverter(float f) {
    -        int fBits = Float.floatToRawIntBits( f );
    -        boolean isNegative = (fBits&FloatConsts.SIGN_BIT_MASK) != 0;
    -        int fractBits = fBits&FloatConsts.SIGNIF_BIT_MASK;
    -        int binExp = (fBits&FloatConsts.EXP_BIT_MASK) >> SINGLE_EXP_SHIFT;
    -        // Discover obvious special cases of NaN and Infinity.
    -        if ( binExp == (FloatConsts.EXP_BIT_MASK>>SINGLE_EXP_SHIFT) ) {
    -            if ( fractBits == 0L ){
    -                return isNegative ? B2AC_NEGATIVE_INFINITY : B2AC_POSITIVE_INFINITY;
    -            } else {
    -                return B2AC_NOT_A_NUMBER;
    -            }
    -        }
    -        // Finish unpacking
    -        // Normalize denormalized numbers.
    -        // Insert assumed high-order bit for normalized numbers.
    -        // Subtract exponent bias.
    -        int  nSignificantBits;
    -        if ( binExp == 0 ){
    -            if ( fractBits == 0 ){
    -                // not a denorm, just a 0!
    -                return isNegative ? B2AC_NEGATIVE_ZERO : B2AC_POSITIVE_ZERO;
    -            }
    -            int leadingZeros = Integer.numberOfLeadingZeros(fractBits);
    -            int shift = leadingZeros-(31-SINGLE_EXP_SHIFT);
    -            fractBits <<= shift;
    -            binExp = 1 - shift;
    -            nSignificantBits =  32 - leadingZeros; // recall binExp is  - shift count.
    -        } else {
    -            fractBits |= SINGLE_FRACT_HOB;
    -            nSignificantBits = SINGLE_EXP_SHIFT+1;
    -        }
    -        binExp -= FloatConsts.EXP_BIAS;
    -        BinaryToASCIIBuffer buf = getBinaryToASCIIBuffer();
    -        buf.setSign(isNegative);
    -        // call the routine that actually does all the hard work.
    -        buf.dtoa(binExp, ((long)fractBits)<<(EXP_SHIFT-SINGLE_EXP_SHIFT), nSignificantBits, true);
    -        return buf;
    -    }
    -
    -    static ASCIIToBinaryConverter readDoubleSignlessDigits(int decExp, char[] digits, int length) {
    +    static ASCIIToBinaryConverter readDoubleSignlessDigits(int decExp, byte[] digits, int length) {
     
             // Prevent an extreme negative exponent from causing overflow issues in doubleValue().
             // Large positive values are handled within doubleValue();
             if (decExp < MIN_DECIMAL_EXPONENT) {
                 return A2BC_POSITIVE_ZERO;
             }
    -        byte[] buf = new byte[length];
    -        for (int i = 0; i < length; i++) {
    -            buf[i] = (byte) digits[i];
    -        }
    -        return new ASCIIToBinaryBuffer(false, decExp, buf, length);
    +        return new ASCIIToBinaryBuffer(false, decExp, digits, length);
         }
     
         /**
    
    From e916ce8ce9af906cf86f1801fcb43e08f8188665 Mon Sep 17 00:00:00 2001
    From: altrisi 
    Date: Fri, 22 Aug 2025 17:10:40 +0000
    Subject: [PATCH 38/54] 8365878: jshell TOOLING's javap should use binary names
    
    Reviewed-by: liach, cstein
    ---
     .../jdk/jshell/tool/resources/TOOLING.jsh     |  4 +--
     test/langtools/jdk/jshell/ToolingTest.java    | 31 +++++++++++++++++--
     2 files changed, 31 insertions(+), 4 deletions(-)
    
    diff --git a/src/jdk.jshell/share/classes/jdk/jshell/tool/resources/TOOLING.jsh b/src/jdk.jshell/share/classes/jdk/jshell/tool/resources/TOOLING.jsh
    index b97b6341cfa..16436514383 100644
    --- a/src/jdk.jshell/share/classes/jdk/jshell/tool/resources/TOOLING.jsh
    +++ b/src/jdk.jshell/share/classes/jdk/jshell/tool/resources/TOOLING.jsh
    @@ -8,9 +8,9 @@ void jmod(String... args) { run("jmod", args); }
     void jpackage(String... args) { run("jpackage", args); }
     
     void javap(Class type) throws Exception {
    +    if (type.isPrimitive() || type.isHidden() || type.isArray()) throw new IllegalArgumentException("Type has no class file: " + type);
         try {
    -        var name = type.getCanonicalName();
    -        if (name == null) throw new IllegalArgumentException("Type not supported: " + type);
    +        var name = type.getName();
             if (type == Class.forName(name, false, ClassLoader.getSystemClassLoader())) {
                 run("javap", "-c", "-v", "-s", name);
                 return;
    diff --git a/test/langtools/jdk/jshell/ToolingTest.java b/test/langtools/jdk/jshell/ToolingTest.java
    index b36fdc03c19..f0d0e3f68eb 100644
    --- a/test/langtools/jdk/jshell/ToolingTest.java
    +++ b/test/langtools/jdk/jshell/ToolingTest.java
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved.
      * 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 8306560
    + * @bug 8306560 8365878
      * @summary Tests for snippets and methods defined in TOOLING.jsh
      * @modules jdk.compiler/com.sun.tools.javac.api
      *          jdk.compiler/com.sun.tools.javac.main
    @@ -79,4 +79,31 @@ public class ToolingTest extends ReplToolTesting {
                     )
             );
         }
    +
    +    @Test
    +    public void testDisassembleBuiltinInnerClass() {
    +        test(
    +            a -> assertCommand(a, "/open TOOLING",
    +                        ""),
    +            a -> assertCommandUserOutputContains(a, "javap(Base64.Decoder.class)",
    +                        "Classfile jrt:/java.base/java/util/Base64$Decoder.class",
    +                        "class java.util.Base64$Decoder",
    +                        "SourceFile: \"Base64.java\"")
    +        );
    +    }
    +
    +    @Test
    +    public void testDisassembleAnonymousClass() {
    +        test(
    +            a -> assertCommand(a, "Object o() {return new ArrayList<>(){ };}", // must be in a method or it won't be anonymous
    +                        "|  created method o()"),
    +            a -> assertCommand(a, "/open TOOLING",
    +                        ""),
    +            a -> assertCommandUserOutputContains(a, "javap(o().getClass())",
    +                        "Classfile ", // Classfile /.../TOOLING-16063368030094702464.class
    +                        " extends java.util.ArrayList", // class REPL.$JShell$22$1 extends java.util.ArrayList
    +                        "SourceFile: \"$JShell$" // SourceFile: "$JShell$22.java"
    +            )
    +        );
    +    }
     }
    
    From 19882220ecb3eeaef763ccbb0aa4d7760c906222 Mon Sep 17 00:00:00 2001
    From: Francesco Andreuzzi 
    Date: Fri, 22 Aug 2025 17:36:52 +0000
    Subject: [PATCH 39/54] 8365829: Multiple definitions of static 'phase_names'
    
    Reviewed-by: kbarrett
    ---
     src/hotspot/share/opto/phasetype.cpp | 46 ++++++++++++++++++++++++++++
     src/hotspot/share/opto/phasetype.hpp | 35 ++++++---------------
     2 files changed, 56 insertions(+), 25 deletions(-)
     create mode 100644 src/hotspot/share/opto/phasetype.cpp
    
    diff --git a/src/hotspot/share/opto/phasetype.cpp b/src/hotspot/share/opto/phasetype.cpp
    new file mode 100644
    index 00000000000..3e18bd089ba
    --- /dev/null
    +++ b/src/hotspot/share/opto/phasetype.cpp
    @@ -0,0 +1,46 @@
    +/*
    + * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved.
    + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    + *
    + * This code is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License version 2 only, as
    + * published by the Free Software Foundation.
    + *
    + * This code is distributed in the hope that it will be useful, but WITHOUT
    + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    + * version 2 for more details (a copy is included in the LICENSE file that
    + * accompanied this code).
    + *
    + * You should have received a copy of the GNU General Public License version
    + * 2 along with this work; if not, write to the Free Software Foundation,
    + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    + *
    + * Please 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 "phasetype.hpp"
    +
    +const char* const CompilerPhaseTypeHelper::_phase_descriptions[] = {
    +#define array_of_labels(name, description) description,
    +       COMPILER_PHASES(array_of_labels)
    +#undef array_of_labels
    +};
    +
    +const char* const CompilerPhaseTypeHelper::_phase_names[] = {
    +#define array_of_labels(name, description) #name,
    +       COMPILER_PHASES(array_of_labels)
    +#undef array_of_labels
    +};
    +
    +CompilerPhaseType CompilerPhaseTypeHelper::find_phase(const char* str) {
    +  for (int i = 0; i < PHASE_NUM_TYPES; i++) {
    +    if (strcmp(CompilerPhaseTypeHelper::_phase_names[i], str) == 0) {
    +      return (CompilerPhaseType)i;
    +    }
    +  }
    +  return PHASE_NONE;
    +}
    diff --git a/src/hotspot/share/opto/phasetype.hpp b/src/hotspot/share/opto/phasetype.hpp
    index 942850cf892..5c733c7dc0a 100644
    --- a/src/hotspot/share/opto/phasetype.hpp
    +++ b/src/hotspot/share/opto/phasetype.hpp
    @@ -138,36 +138,21 @@ enum CompilerPhaseType {
     };
     #undef table_entry
     
    -static const char* phase_descriptions[] = {
    -#define array_of_labels(name, description) description,
    -       COMPILER_PHASES(array_of_labels)
    -#undef array_of_labels
    -};
    -
    -static const char* phase_names[] = {
    -#define array_of_labels(name, description) #name,
    -       COMPILER_PHASES(array_of_labels)
    -#undef array_of_labels
    -};
    -
     class CompilerPhaseTypeHelper {
    -  public:
    + private:
    +  static const char* const _phase_descriptions[];
    +  static const char* const _phase_names[];
    +
    + public:
       static const char* to_name(CompilerPhaseType cpt) {
    -    return phase_names[cpt];
    +    return _phase_names[cpt];
       }
       static const char* to_description(CompilerPhaseType cpt) {
    -    return phase_descriptions[cpt];
    +    return _phase_descriptions[cpt];
       }
    -};
     
    -static CompilerPhaseType find_phase(const char* str) {
    -  for (int i = 0; i < PHASE_NUM_TYPES; i++) {
    -    if (strcmp(phase_names[i], str) == 0) {
    -      return (CompilerPhaseType)i;
    -    }
    -  }
    -  return PHASE_NONE;
    -}
    +  static CompilerPhaseType find_phase(const char* str);
    +};
     
     class PhaseNameValidator {
      private:
    @@ -183,7 +168,7 @@ class PhaseNameValidator {
       {
         for (StringUtils::CommaSeparatedStringIterator iter(option); *iter != nullptr && _valid; ++iter) {
     
    -      CompilerPhaseType cpt = find_phase(*iter);
    +      CompilerPhaseType cpt = CompilerPhaseTypeHelper::find_phase(*iter);
           if (PHASE_NONE == cpt) {
             const size_t len = MIN2(strlen(*iter), 63) + 1;  // cap len to a value we know is enough for all phase descriptions
             _bad = NEW_C_HEAP_ARRAY(char, len, mtCompiler);
    
    From ae0dac43c09377c87e9b0452618a5b32c8568150 Mon Sep 17 00:00:00 2001
    From: Naoto Sato 
    Date: Fri, 22 Aug 2025 17:50:22 +0000
    Subject: [PATCH 40/54] 8361613: System.console() should only be available for
     interactive terminal
    
    Reviewed-by: jlahoda, smarks, alanb
    ---
     .../share/classes/java/lang/System.java       |   3 +-
     .../org/jline/JdkConsoleProviderImpl.java     |   2 +-
     .../java/io/Console/DefaultCharsetTest.java   |  69 +++++--
     test/jdk/java/io/Console/LocaleTest.java      | 127 ++++++------
     .../java/io/Console/ModuleSelectionTest.java  |  69 +++++--
     test/jdk/java/io/Console/defaultCharset.exp   |  32 ++++
     test/jdk/java/io/Console/locale.exp           |  37 ++++
     test/jdk/java/io/Console/moduleSelection.exp  |  30 +++
     test/jdk/java/lang/IO/IO.java                 |  54 +-----
     .../jline/JLineConsoleProviderTest.java       |  30 ++-
     .../jline/LazyJdkConsoleProvider.java         |  40 ++--
     .../jdk/internal/jline/RedirectedStdOut.java  | 181 ------------------
     12 files changed, 330 insertions(+), 344 deletions(-)
     create mode 100644 test/jdk/java/io/Console/defaultCharset.exp
     create mode 100644 test/jdk/java/io/Console/locale.exp
     create mode 100644 test/jdk/java/io/Console/moduleSelection.exp
     delete mode 100644 test/jdk/jdk/internal/jline/RedirectedStdOut.java
    
    diff --git a/src/java.base/share/classes/java/lang/System.java b/src/java.base/share/classes/java/lang/System.java
    index f046ed4111a..a40c27bbf47 100644
    --- a/src/java.base/share/classes/java/lang/System.java
    +++ b/src/java.base/share/classes/java/lang/System.java
    @@ -237,10 +237,11 @@ public final class System {
         private static volatile Console cons;
     
         /**
    -     * Returns the unique {@link java.io.Console Console} object associated
    +     * Returns the unique {@link Console Console} object associated
          * with the current Java virtual machine, if any.
          *
          * @return  The system console, if any, otherwise {@code null}.
    +     * @see Console
          *
          * @since   1.6
          */
    diff --git a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/JdkConsoleProviderImpl.java b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/JdkConsoleProviderImpl.java
    index 365f6d1e68a..4e4751b264e 100644
    --- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/JdkConsoleProviderImpl.java
    +++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/JdkConsoleProviderImpl.java
    @@ -50,7 +50,7 @@ public class JdkConsoleProviderImpl implements JdkConsoleProvider {
          */
         @Override
         public JdkConsole console(boolean isTTY, Charset inCharset, Charset outCharset) {
    -        return new LazyDelegatingJdkConsoleImpl(inCharset, outCharset);
    +        return isTTY ? new LazyDelegatingJdkConsoleImpl(inCharset, outCharset) : null;
         }
     
         private static class LazyDelegatingJdkConsoleImpl implements JdkConsole {
    diff --git a/test/jdk/java/io/Console/DefaultCharsetTest.java b/test/jdk/java/io/Console/DefaultCharsetTest.java
    index 0fca8a3cc3f..981d92ce282 100644
    --- a/test/jdk/java/io/Console/DefaultCharsetTest.java
    +++ b/test/jdk/java/io/Console/DefaultCharsetTest.java
    @@ -21,33 +21,66 @@
      * questions.
      */
     
    -import org.junit.jupiter.api.Test;
    -import static org.junit.jupiter.api.Assertions.*;
    +import java.nio.file.Files;
    +import java.nio.file.Paths;
    +
    +import jdk.test.lib.process.OutputAnalyzer;
    +import jdk.test.lib.process.ProcessTools;
    +import org.junit.jupiter.api.Assumptions;
    +import org.junit.jupiter.api.BeforeAll;
    +import org.junit.jupiter.params.ParameterizedTest;
    +import org.junit.jupiter.params.provider.ValueSource;
    +
    +import static jdk.test.lib.Utils.*;
     
     /**
      * @test
    - * @bug 8341975 8351435
    + * @bug 8341975 8351435 8361613
      * @summary Tests the default charset. It should honor `stdout.encoding`
      *          which should be the same as System.out.charset()
    - * @modules jdk.internal.le
    - * @run junit/othervm -Djdk.console=jdk.internal.le -Dstdout.encoding=UTF-8 DefaultCharsetTest
    - * @run junit/othervm -Djdk.console=jdk.internal.le -Dstdout.encoding=ISO-8859-1 DefaultCharsetTest
    - * @run junit/othervm -Djdk.console=jdk.internal.le -Dstdout.encoding=US-ASCII DefaultCharsetTest
    - * @run junit/othervm -Djdk.console=jdk.internal.le -Dstdout.encoding=foo DefaultCharsetTest
    - * @run junit/othervm -Djdk.console=jdk.internal.le DefaultCharsetTest
    + * @requires (os.family == "linux") | (os.family == "mac")
    + * @library /test/lib
    + * @build jdk.test.lib.Utils
    + *        jdk.test.lib.JDKToolFinder
    + *        jdk.test.lib.process.ProcessTools
    + * @run junit DefaultCharsetTest
      */
     public class DefaultCharsetTest {
    -    @Test
    -    public void testDefaultCharset() {
    +    @BeforeAll
    +    static void checkExpectAvailability() {
    +        // check "expect" command availability
    +        var expect = Paths.get("/usr/bin/expect");
    +        Assumptions.assumeTrue(Files.exists(expect) && Files.isExecutable(expect),
    +            "'" + expect + "' not found. Test ignored.");
    +    }
    +    @ParameterizedTest
    +    @ValueSource(strings = {"UTF-8", "ISO-8859-1", "US-ASCII", "foo", ""})
    +    void testDefaultCharset(String stdoutEncoding) throws Exception {
    +        // invoking "expect" command
    +        OutputAnalyzer oa = ProcessTools.executeProcess(
    +            "expect",
    +            "-n",
    +            TEST_SRC + "/defaultCharset.exp",
    +            TEST_CLASSES,
    +            TEST_JDK + "/bin/java",
    +            "-Dstdout.encoding=" + stdoutEncoding,
    +            getClass().getName());
    +        oa.reportDiagnosticSummary();
    +        oa.shouldHaveExitValue(0);
    +    }
    +
    +    public static void main(String... args) {
             var stdoutEncoding = System.getProperty("stdout.encoding");
             var sysoutCharset = System.out.charset();
             var consoleCharset = System.console().charset();
    -        System.out.println("""
    -                    stdout.encoding = %s
    -                    System.out.charset() = %s
    -                    System.console().charset() = %s
    -                """.formatted(stdoutEncoding, sysoutCharset.name(), consoleCharset.name()));
    -        assertEquals(consoleCharset, sysoutCharset,
    -            "Charsets for System.out and Console differ for stdout.encoding: %s".formatted(stdoutEncoding));
    +        System.out.printf("""
    +                stdout.encoding = %s
    +                System.out.charset() = %s
    +                System.console().charset() = %s
    +            """, stdoutEncoding, sysoutCharset.name(), consoleCharset.name());
    +        if (!consoleCharset.equals(sysoutCharset)) {
    +            System.err.printf("Charsets for System.out and Console differ for stdout.encoding: %s%n", stdoutEncoding);
    +            System.exit(-1);
    +        }
         }
     }
    diff --git a/test/jdk/java/io/Console/LocaleTest.java b/test/jdk/java/io/Console/LocaleTest.java
    index 1cab84a9af7..e9a281749b1 100644
    --- a/test/jdk/java/io/Console/LocaleTest.java
    +++ b/test/jdk/java/io/Console/LocaleTest.java
    @@ -21,28 +21,40 @@
      * questions.
      */
     
    -import java.io.File;
     import java.util.Calendar;
     import java.util.GregorianCalendar;
     import java.util.List;
     import java.util.Locale;
    +import java.nio.file.Files;
    +import java.nio.file.Paths;
    +import java.util.function.Predicate;
     
    +import jdk.test.lib.process.OutputAnalyzer;
     import jdk.test.lib.process.ProcessTools;
    +import org.junit.jupiter.api.Assumptions;
    +import org.junit.jupiter.api.Test;
    +
    +import static jdk.test.lib.Utils.*;
     
     /**
      * @test
    - * @bug 8330276 8351435
    + * @bug 8330276 8351435 8361613
      * @summary Tests Console methods that have Locale as an argument
    + * @requires (os.family == "linux") | (os.family == "mac")
      * @library /test/lib
    - * @modules jdk.internal.le jdk.localedata
    + * @build jdk.test.lib.Utils
    + *        jdk.test.lib.JDKToolFinder
    + *        jdk.test.lib.process.ProcessTools
    + * @modules jdk.localedata
    + * @run junit LocaleTest
      */
     public class LocaleTest {
    -    private static Calendar TODAY  = new GregorianCalendar(2024, Calendar.APRIL, 22);
    -    private static String FORMAT = "%1$tY-%1$tB-%1$te %1$tA";
    +    private static final Calendar TODAY = new GregorianCalendar(2024, Calendar.APRIL, 22);
    +    private static final String FORMAT = "%1$tY-%1$tB-%1$te %1$tA";
         // We want to limit the expected strings within US-ASCII charset, as
         // the native encoding is determined as such, which is used by
         // the `Process` class under jtreg environment.
    -    private static List EXPECTED = List.of(
    +    private static final List EXPECTED = List.of(
             String.format(Locale.UK, FORMAT, TODAY),
             String.format(Locale.FRANCE, FORMAT, TODAY),
             String.format(Locale.GERMANY, FORMAT, TODAY),
    @@ -53,56 +65,61 @@ public class LocaleTest {
             String.format((Locale)null, FORMAT, TODAY)
         );
     
    -    public static void main(String... args) throws Throwable {
    -        if (args.length == 0) {
    -            // no arg will launch the child process that actually perform tests
    -            var pb = ProcessTools.createTestJavaProcessBuilder(
    -                    "-Djdk.console=jdk.internal.le",
    -                    "LocaleTest", "dummy");
    -            var input = new File(System.getProperty("test.src", "."), "input.txt");
    -            pb.redirectInput(input);
    -            var oa = ProcessTools.executeProcess(pb);
    -            if (oa.getExitValue() == -1) {
    -                System.out.println("System.console() returns null. Ignoring the test.");
    -            } else {
    -                var output = oa.asLines();
    -                var resultText =
    -                    """
    -                    Actual output: %s
    -                    Expected output: %s
    -                    """.formatted(output, EXPECTED);
    -                if (!output.equals(EXPECTED)) {
    -                    throw new RuntimeException("Standard out had unexpected strings:\n" + resultText);
    -                } else {
    -                    oa.shouldHaveExitValue(0);
    -                    System.out.println("Formatting with explicit Locale succeeded.\n" + resultText);
    -                }
    -            }
    -        } else {
    -            var con = System.console();
    -            if (con != null) {
    -                // tests these additional methods that take a Locale
    -                con.format(Locale.UK, FORMAT, TODAY);
    -                con.printf("\n");
    -                con.printf(Locale.FRANCE, FORMAT, TODAY);
    -                con.printf("\n");
    -                con.readLine(Locale.GERMANY, FORMAT, TODAY);
    -                con.printf("\n");
    -                con.readPassword(Locale.of("es"), FORMAT, TODAY);
    -                con.printf("\n");
    +    @Test
    +    void testLocale() throws Exception {
    +        // check "expect" command availability
    +        var expect = Paths.get("/usr/bin/expect");
    +        Assumptions.assumeTrue(Files.exists(expect) && Files.isExecutable(expect),
    +            "'" + expect + "' not found. Test ignored.");
     
    -                // tests null locale
    -                con.format((Locale)null, FORMAT, TODAY);
    -                con.printf("\n");
    -                con.printf((Locale)null, FORMAT, TODAY);
    -                con.printf("\n");
    -                con.readLine((Locale)null, FORMAT, TODAY);
    -                con.printf("\n");
    -                con.readPassword((Locale)null, FORMAT, TODAY);
    -            } else {
    -                // Exit with -1
    -                System.exit(-1);
    -            }
    +        // invoking "expect" command
    +        OutputAnalyzer oa = ProcessTools.executeProcess(
    +            "expect",
    +            "-n",
    +            TEST_SRC + "/locale.exp",
    +            TEST_CLASSES,
    +            TEST_JDK + "/bin/java",
    +            getClass().getName());
    +
    +        var stdout =
    +            oa.stdoutAsLines().stream().filter(Predicate.not(String::isEmpty)).toList();
    +        var resultText =
    +            """
    +            Actual output: %s
    +            Expected output: %s
    +            """.formatted(stdout, EXPECTED);
    +        if (!stdout.equals(EXPECTED)) {
    +            throw new RuntimeException("Standard out had unexpected strings:\n" + resultText);
    +        } else {
    +            oa.shouldHaveExitValue(0);
    +            System.out.println("Formatting with explicit Locale succeeded.\n" + resultText);
    +        }
    +    }
    +
    +    public static void main(String... args) throws Throwable {
    +        var con = System.console();
    +        if (con != null) {
    +            // tests these additional methods that take a Locale
    +            con.format(Locale.UK, FORMAT, TODAY);
    +            con.printf("\n");
    +            con.printf(Locale.FRANCE, FORMAT, TODAY);
    +            con.printf("\n");
    +            con.readLine(Locale.GERMANY, FORMAT, TODAY);
    +            con.printf("\n");
    +            con.readPassword(Locale.of("es"), FORMAT, TODAY);
    +            con.printf("\n");
    +
    +            // tests null locale
    +            con.format((Locale)null, FORMAT, TODAY);
    +            con.printf("\n");
    +            con.printf((Locale)null, FORMAT, TODAY);
    +            con.printf("\n");
    +            con.readLine((Locale)null, FORMAT, TODAY);
    +            con.printf("\n");
    +            con.readPassword((Locale)null, FORMAT, TODAY);
    +        } else {
    +            // Exit with -1
    +            System.exit(-1);
             }
         }
     }
    diff --git a/test/jdk/java/io/Console/ModuleSelectionTest.java b/test/jdk/java/io/Console/ModuleSelectionTest.java
    index d9885699ebf..332acf83fbd 100644
    --- a/test/jdk/java/io/Console/ModuleSelectionTest.java
    +++ b/test/jdk/java/io/Console/ModuleSelectionTest.java
    @@ -23,21 +23,71 @@
     
     /**
      * @test
    - * @bug 8295803 8299689 8351435
    + * @bug 8295803 8299689 8351435 8361613
      * @summary Tests System.console() returns correct Console (or null) from the expected
      *          module.
    - * @modules java.base/java.io:+open
    - * @run main/othervm ModuleSelectionTest java.base
    - * @run main/othervm -Djdk.console=jdk.internal.le ModuleSelectionTest jdk.internal.le
    - * @run main/othervm -Djdk.console=java.base ModuleSelectionTest java.base
    - * @run main/othervm --limit-modules java.base ModuleSelectionTest java.base
    + * @library /test/lib
    + * @build jdk.test.lib.Utils
    + *        jdk.test.lib.process.ProcessTools
    + * @run junit ModuleSelectionTest
      */
     
     import java.io.Console;
     import java.lang.invoke.MethodHandles;
     import java.lang.invoke.MethodType;
    +import java.nio.file.Files;
    +import java.nio.file.Paths;
    +import java.util.stream.Stream;
    +
    +import jdk.test.lib.process.OutputAnalyzer;
    +import jdk.test.lib.process.ProcessTools;
    +import org.junit.jupiter.api.Assumptions;
    +import org.junit.jupiter.params.ParameterizedTest;
    +import org.junit.jupiter.params.provider.Arguments;
    +import org.junit.jupiter.params.provider.MethodSource;
    +
    +import static jdk.test.lib.Utils.*;
     
     public class ModuleSelectionTest {
    +    private static Stream options() {
    +        return Stream.of(
    +            Arguments.of("-Djdk.console=foo", "java.base"),
    +            Arguments.of("-Djdk.console=java.base", "java.base"),
    +            Arguments.of("-Djdk.console=jdk.internal.le", "jdk.internal.le"),
    +            Arguments.of("--limit-modules java.base", "java.base")
    +        );
    +    }
    +
    +    @ParameterizedTest
    +    @MethodSource("options")
    +    void testNonTTY(String opts) throws Exception {
    +        opts = opts +
    +            " --add-opens java.base/java.io=ALL-UNNAMED ModuleSelectionTest null";
    +        OutputAnalyzer output = ProcessTools.executeTestJava(opts.split(" "));
    +        output.reportDiagnosticSummary();
    +        output.shouldHaveExitValue(0);
    +    }
    +
    +    @ParameterizedTest
    +    @MethodSource("options")
    +    void testTTY(String opts, String expected) throws Exception {
    +        // check "expect" command availability
    +        var expect = Paths.get("/usr/bin/expect");
    +        Assumptions.assumeTrue(Files.exists(expect) && Files.isExecutable(expect),
    +            "'" + expect + "' not found. Test ignored.");
    +
    +        opts = "expect -n " + TEST_SRC + "/moduleSelection.exp " +
    +            TEST_CLASSES + " " +
    +            expected + " " +
    +            TEST_JDK + "/bin/java" +
    +            " --add-opens java.base/java.io=ALL-UNNAMED "
    +            + opts;
    +        // invoking "expect" command
    +        OutputAnalyzer output = ProcessTools.executeProcess(opts.split(" "));
    +        output.reportDiagnosticSummary();
    +        output.shouldHaveExitValue(0);
    +    }
    +
         public static void main(String... args) throws Throwable {
             var con = System.console();
             var pc = Class.forName("java.io.ProxyingConsole");
    @@ -49,10 +99,7 @@ public class ModuleSelectionTest {
                     .findGetter(pc, "delegate", jdkc)
                     .invoke(con) : null;
     
    -        var expected = switch (args[0]) {
    -            case "java.base" -> istty ? "java.base" : "null";
    -            default -> args[0];
    -        };
    +        var expected = args[0];
             var actual = con == null ? "null" : impl.getClass().getModule().getName();
     
             if (!actual.equals(expected)) {
    @@ -62,7 +109,7 @@ public class ModuleSelectionTest {
                     Actual: %s
                     """.formatted(expected, actual));
             } else {
    -            System.out.printf("%s is the expected implementation. (tty: %s)\n", impl, istty);
    +            System.out.printf("%s is the expected implementation. (tty: %s)\n", actual, istty);
             }
         }
     }
    diff --git a/test/jdk/java/io/Console/defaultCharset.exp b/test/jdk/java/io/Console/defaultCharset.exp
    new file mode 100644
    index 00000000000..5b1418db28c
    --- /dev/null
    +++ b/test/jdk/java/io/Console/defaultCharset.exp
    @@ -0,0 +1,32 @@
    +#
    +# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
    +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    +#
    +# This code is free software; you can redistribute it and/or modify it
    +# under the terms of the GNU General Public License version 2 only, as
    +# published by the Free Software Foundation.
    +#
    +# This code is distributed in the hope that it will be useful, but WITHOUT
    +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    +# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    +# version 2 for more details (a copy is included in the LICENSE file that
    +# accompanied this code).
    +#
    +# You should have received a copy of the GNU General Public License version
    +# 2 along with this work; if not, write to the Free Software Foundation,
    +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    +#
    +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    +# or visit www.oracle.com if you need additional information or have any
    +# questions.
    +#
    +
    +# simply invoking java under expect command
    +set classpath [lrange $argv 0 0]
    +set java [lrange $argv 1 1]
    +set stdoutProp [lrange $argv 2 2]
    +set clsname [lrange $argv 3 3]
    +eval spawn $java -classpath $classpath $stdoutProp $clsname
    +expect eof
    +set result [wait]
    +exit [lindex $result 3]
    diff --git a/test/jdk/java/io/Console/locale.exp b/test/jdk/java/io/Console/locale.exp
    new file mode 100644
    index 00000000000..a88ea43feac
    --- /dev/null
    +++ b/test/jdk/java/io/Console/locale.exp
    @@ -0,0 +1,37 @@
    +#
    +# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
    +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    +#
    +# This code is free software; you can redistribute it and/or modify it
    +# under the terms of the GNU General Public License version 2 only, as
    +# published by the Free Software Foundation.
    +#
    +# This code is distributed in the hope that it will be useful, but WITHOUT
    +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    +# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    +# version 2 for more details (a copy is included in the LICENSE file that
    +# accompanied this code).
    +#
    +# You should have received a copy of the GNU General Public License version
    +# 2 along with this work; if not, write to the Free Software Foundation,
    +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    +#
    +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    +# or visit www.oracle.com if you need additional information or have any
    +# questions.
    +#
    +
    +# simply invoking java under expect command
    +set classpath [lrange $argv 0 0]
    +set java [lrange $argv 1 1]
    +set clsname [lrange $argv 2 2]
    +eval spawn -noecho $java -classpath $classpath $clsname
    +
    +# sends CR 4 times (readLine x 2, readPassword x 2)
    +send "\r"
    +send "\r"
    +send "\r"
    +send "\r"
    +expect eof
    +set result [wait]
    +exit [lindex $result 3]
    diff --git a/test/jdk/java/io/Console/moduleSelection.exp b/test/jdk/java/io/Console/moduleSelection.exp
    new file mode 100644
    index 00000000000..2b44afe72e4
    --- /dev/null
    +++ b/test/jdk/java/io/Console/moduleSelection.exp
    @@ -0,0 +1,30 @@
    +#
    +# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
    +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    +#
    +# This code is free software; you can redistribute it and/or modify it
    +# under the terms of the GNU General Public License version 2 only, as
    +# published by the Free Software Foundation.
    +#
    +# This code is distributed in the hope that it will be useful, but WITHOUT
    +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    +# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    +# version 2 for more details (a copy is included in the LICENSE file that
    +# accompanied this code).
    +#
    +# You should have received a copy of the GNU General Public License version
    +# 2 along with this work; if not, write to the Free Software Foundation,
    +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    +#
    +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    +# or visit www.oracle.com if you need additional information or have any
    +# questions.
    +#
    +
    +# simply invoking java under expect command
    +set classpath [lrange $argv 0 0]
    +set expected [lrange $argv 1 1]
    +set java [lrange $argv 2 2]
    +set opts [lrange $argv 3 end]
    +eval spawn $java $opts -classpath $classpath ModuleSelectionTest $expected
    +expect eof
    diff --git a/test/jdk/java/lang/IO/IO.java b/test/jdk/java/lang/IO/IO.java
    index dbb83db5f80..2b13657b58e 100644
    --- a/test/jdk/java/lang/IO/IO.java
    +++ b/test/jdk/java/lang/IO/IO.java
    @@ -50,10 +50,9 @@ import static org.junit.jupiter.api.Assertions.*;
     
     /*
      * @test
    - * @bug 8305457 8342936 8351435 8344706
    + * @bug 8305457 8342936 8351435 8344706 8361613
      * @summary java.lang.IO tests
      * @library /test/lib
    - * @modules jdk.internal.le
      * @run junit IO
      */
     @ExtendWith(IO.TimingExtension.class)
    @@ -78,22 +77,6 @@ public class IO {
                 } catch (Exception _) { }
             }
     
    -        /*
    -         * Unlike printTest, which tests a _default_ console that is normally
    -         * jdk.internal.org.jline.JdkConsoleProviderImpl, this test tests
    -         * jdk.internal.io.JdkConsoleImpl. Those console implementations operate
    -         * in different conditions and, thus, are tested separately.
    -         *
    -         * To test jdk.internal.io.JdkConsoleImpl one needs to ensure that both
    -         * conditions are met:
    -         *
    -         *   - a non-existent console provider is requested
    -         *   - isatty is true
    -         *
    -         * To achieve isatty, the test currently uses the EXPECT(1) Unix command,
    -         * which does not work for Windows. Later, a library like pty4j or JPty
    -         * might be used instead of EXPECT, to cover both Unix and Windows.
    -         */
             @ParameterizedTest
             @ValueSource(strings = {"println", "print"})
             public void outputTestInteractive(String mode) throws Exception {
    @@ -102,8 +85,6 @@ public class IO {
                         expect.toString(),
                         Path.of(testSrc, "output.exp").toAbsolutePath().toString(),
                         System.getProperty("test.jdk") + "/bin/java",
    -                    "--enable-preview",
    -                    "-Djdk.console=gibberish",
                         Path.of(testSrc, "Output.java").toAbsolutePath().toString(),
                         mode);
                 assertEquals(0, output.getExitValue());
    @@ -130,7 +111,7 @@ public class IO {
              */
             @ParameterizedTest
             @MethodSource("args")
    -        public void inputTestInteractive(String console, String prompt) throws Exception {
    +        public void inputTestInteractive(String prompt) throws Exception {
                 var testSrc = System.getProperty("test.src", ".");
                 var command = new ArrayList();
                 command.add(expect.toString());
    @@ -138,9 +119,6 @@ public class IO {
                                                                     : "input";
                 command.add(Path.of(testSrc, expectInputName + ".exp").toAbsolutePath().toString());
                 command.add(System.getProperty("test.jdk") + "/bin/java");
    -            command.add("--enable-preview");
    -            if (console != null)
    -                command.add("-Djdk.console=" + console);
                 command.add(Path.of(testSrc, "Input.java").toAbsolutePath().toString());
                 command.add(prompt == null ? "0" : PROMPT_NONE.equals(prompt) ? "2" : "1");
                 command.add(String.valueOf(prompt));
    @@ -152,33 +130,11 @@ public class IO {
             private static final String PROMPT_NONE = "prompt-none";
     
             public static Stream args() {
    -            // cross product: consoles x prompts
    -            return Stream.of("jdk.internal.le", "gibberish").flatMap(console -> Stream.of(null, "?", "%s", PROMPT_NONE)
    -                    .map(prompt -> new String[]{console, prompt}).map(Arguments::of));
    +            // prompts
    +            return Stream.of(null, "?", "%s", PROMPT_NONE).map(Arguments::of);
             }
         }
     
    -    @ParameterizedTest
    -    @ValueSource(strings = {"println", "print"})
    -    public void printTest(String mode) throws Exception {
    -        var file = Path.of(System.getProperty("test.src", "."), "Output.java")
    -                .toAbsolutePath().toString();
    -        var pb = ProcessTools.createTestJavaProcessBuilder("-Djdk.console=jdk.internal.le", "--enable-preview", file, mode);
    -        OutputAnalyzer output = ProcessTools.executeProcess(pb);
    -        assertEquals(0, output.getExitValue());
    -        assertTrue(output.getStderr().isEmpty());
    -        output.reportDiagnosticSummary();
    -        String out = output.getStdout();
    -        // The first half of the output is produced by Console, the second
    -        // half is produced by IO: those halves must match.
    -        // Executing Console and IO in the same VM (as opposed to
    -        // consecutive VM runs, which are cleaner) to be able to compare string
    -        // representation of objects.
    -        assertFalse(out.isBlank());
    -        assertEquals(out.substring(0, out.length() / 2),
    -                out.substring(out.length() / 2));
    -    }
    -
         @Test //JDK-8342936
         public void printlnNoParamsTest() throws Exception {
             var file = Path.of("PrintlnNoParams.java");
    @@ -193,7 +149,7 @@ public class IO {
                         }
                         """);
             }
    -        var pb = ProcessTools.createTestJavaProcessBuilder("-Djdk.console=jdk.internal.le", "--enable-preview", file.toString());
    +        var pb = ProcessTools.createTestJavaProcessBuilder(file.toString());
             OutputAnalyzer output = ProcessTools.executeProcess(pb);
             assertEquals(0, output.getExitValue());
             assertTrue(output.getStderr().isEmpty());
    diff --git a/test/jdk/jdk/internal/jline/JLineConsoleProviderTest.java b/test/jdk/jdk/internal/jline/JLineConsoleProviderTest.java
    index 71590040685..445da167c5f 100644
    --- a/test/jdk/jdk/internal/jline/JLineConsoleProviderTest.java
    +++ b/test/jdk/jdk/internal/jline/JLineConsoleProviderTest.java
    @@ -23,16 +23,19 @@
     
     /**
      * @test
    - * @bug 8331535 8351435 8347050
    + * @bug 8331535 8351435 8347050 8361613
      * @summary Verify the jdk.internal.le's console provider works properly.
    - * @modules jdk.internal.le
    + * @modules java.base/jdk.internal.io
    + *          jdk.internal.le/jdk.internal.org.jline
      * @library /test/lib
    - * @run main/othervm -Djdk.console=jdk.internal.le JLineConsoleProviderTest
    + * @run main JLineConsoleProviderTest
      */
     
     import java.lang.reflect.Method;
    +import java.nio.charset.StandardCharsets;
     import java.util.Objects;
     
    +import jdk.internal.org.jline.JdkConsoleProviderImpl;
     import jdk.test.lib.process.OutputAnalyzer;
     import jdk.test.lib.process.ProcessTools;
     
    @@ -66,8 +69,13 @@ public class JLineConsoleProviderTest {
                               String input,
                               String expectedOut) throws Exception {
             ProcessBuilder builder =
    -                ProcessTools.createTestJavaProcessBuilder("-Djdk.console=jdk.internal.le", ConsoleTest.class.getName(),
    -                                                          testName);
    +                ProcessTools.createTestJavaProcessBuilder(
    +                    "--add-exports",
    +                    "java.base/jdk.internal.io=ALL-UNNAMED",
    +                    "--add-exports",
    +                    "jdk.internal.le/jdk.internal.org.jline=ALL-UNNAMED",
    +                    ConsoleTest.class.getName(),
    +                    testName);
             OutputAnalyzer output = ProcessTools.executeProcess(builder, input);
     
             output.waitFor();
    @@ -98,16 +106,18 @@ public class JLineConsoleProviderTest {
     
         public static class ConsoleTest {
             public static void main(String... args) {
    +            // directly instantiate JLine JdkConsole, simulating isTTY=true
    +            var impl = new JdkConsoleProviderImpl().console(true, StandardCharsets.UTF_8, StandardCharsets.UTF_8);
                 switch (args[0]) {
                     case "testCorrectOutputReadLine" ->
    -                    System.console().readLine("%%s");
    +                    impl.readLine(null, "%%s");
                     case "testCorrectOutputReadPassword" ->
    -                    System.console().readPassword("%%s");
    +                    impl.readPassword(null, "%%s");
                     case "readAndPrint" ->
    -                    System.out.println("'" + System.console().readLine() + "'");
    +                    System.out.println("'" + impl.readLine() + "'");
                     case "readAndPrint2" -> {
    -                    System.out.println("1: '" +System.console().readLine() + "'");
    -                    System.out.println("2: '" + System.console().readLine() + "'");
    +                    System.out.println("1: '" + impl.readLine() + "'");
    +                    System.out.println("2: '" + impl.readLine() + "'");
                     }
                     default -> throw new UnsupportedOperationException(args[0]);
                 }
    diff --git a/test/jdk/jdk/internal/jline/LazyJdkConsoleProvider.java b/test/jdk/jdk/internal/jline/LazyJdkConsoleProvider.java
    index acf0c848b43..a7533796b7c 100644
    --- a/test/jdk/jdk/internal/jline/LazyJdkConsoleProvider.java
    +++ b/test/jdk/jdk/internal/jline/LazyJdkConsoleProvider.java
    @@ -23,15 +23,19 @@
     
     /**
      * @test
    - * @bug 8333086 8344706
    + * @bug 8333086 8344706 8361613
      * @summary Verify the JLine backend is not initialized for simple printing.
    - * @enablePreview
    - * @modules jdk.internal.le/jdk.internal.org.jline.reader
    + * @modules java.base/jdk.internal.io
    + *          jdk.internal.le/jdk.internal.org.jline
    + *          jdk.internal.le/jdk.internal.org.jline.reader
      *          jdk.internal.le/jdk.internal.org.jline.terminal
      * @library /test/lib
      * @run main LazyJdkConsoleProvider
      */
     
    +import java.nio.charset.StandardCharsets;
    +
    +import jdk.internal.org.jline.JdkConsoleProviderImpl;
     import jdk.internal.org.jline.reader.LineReader;
     import jdk.internal.org.jline.terminal.Terminal;
     
    @@ -41,19 +45,18 @@ import jdk.test.lib.process.ProcessTools;
     public class LazyJdkConsoleProvider {
     
         public static void main(String... args) throws Throwable {
    +        // directly instantiate JLine JdkConsole, simulating isTTY=true
             switch (args.length > 0 ? args[0] : "default") {
                 case "write" -> {
    -                System.console().printf("Hello!\n");
    -                System.console().printf("Hello!");
    -                System.console().format("\nHello!\n");
    -                System.console().flush();
    -                IO.println("Hello!");
    -                IO.print("Hello!");
    -            }
    -            case "read" -> System.console().readLine("Hello!");
    -            case "IO-read" -> {
    -                IO.readln("Hello!");
    +                var impl = new JdkConsoleProviderImpl().console(true, StandardCharsets.UTF_8, StandardCharsets.UTF_8);
    +                impl.println("Hello!\n");
    +                impl.println("Hello!");
    +                impl.format(null, "\nHello!\n");
    +                impl.flush();
                 }
    +            case "read" -> new JdkConsoleProviderImpl()
    +                .console(true, StandardCharsets.UTF_8, StandardCharsets.UTF_8)
    +                .readLine(null, "Hello!");
                 case "default" -> {
                     new LazyJdkConsoleProvider().runTest();
                 }
    @@ -64,14 +67,15 @@ public class LazyJdkConsoleProvider {
             record TestCase(String testKey, String expected, String notExpected) {}
             TestCase[] testCases = new TestCase[] {
                 new TestCase("write", null, Terminal.class.getName()),
    -            new TestCase("read", LineReader.class.getName(), null),
    -            new TestCase("IO-read", null, Terminal.class.getName())
    +            new TestCase("read", LineReader.class.getName(), null)
             };
             for (TestCase tc : testCases) {
                 ProcessBuilder builder =
    -                    ProcessTools.createTestJavaProcessBuilder("--enable-preview",
    -                                                              "-verbose:class",
    -                                                              "-Djdk.console=jdk.internal.le",
    +                    ProcessTools.createTestJavaProcessBuilder("-verbose:class",
    +                                                              "--add-exports",
    +                                                              "java.base/jdk.internal.io=ALL-UNNAMED",
    +                                                              "--add-exports",
    +                                                              "jdk.internal.le/jdk.internal.org.jline=ALL-UNNAMED",
                                                                   LazyJdkConsoleProvider.class.getName(),
                                                                   tc.testKey());
                 OutputAnalyzer output = ProcessTools.executeProcess(builder, "");
    diff --git a/test/jdk/jdk/internal/jline/RedirectedStdOut.java b/test/jdk/jdk/internal/jline/RedirectedStdOut.java
    deleted file mode 100644
    index 71419f96c73..00000000000
    --- a/test/jdk/jdk/internal/jline/RedirectedStdOut.java
    +++ /dev/null
    @@ -1,181 +0,0 @@
    -/*
    - * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved.
    - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    - *
    - * This code is free software; you can redistribute it and/or modify it
    - * under the terms of the GNU General Public License version 2 only, as
    - * published by the Free Software Foundation.
    - *
    - * This code is distributed in the hope that it will be useful, but WITHOUT
    - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    - * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    - * version 2 for more details (a copy is included in the LICENSE file that
    - * accompanied this code).
    - *
    - * You should have received a copy of the GNU General Public License version
    - * 2 along with this work; if not, write to the Free Software Foundation,
    - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    - *
    - * Please 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 8330998 8351435
    - * @summary Verify that even if the stdout is redirected java.io.Console will
    - *          use it for writing.
    - * @modules jdk.internal.le
    - * @library /test/lib
    - * @run main RedirectedStdOut runRedirectAllTest
    - * @run main/othervm --enable-native-access=ALL-UNNAMED RedirectedStdOut runRedirectOutOnly
    - */
    -
    -import java.io.ByteArrayOutputStream;
    -import java.io.PrintStream;
    -import java.lang.foreign.Arena;
    -import java.lang.foreign.FunctionDescriptor;
    -import java.lang.foreign.Linker;
    -import java.lang.foreign.MemorySegment;
    -import java.lang.foreign.SymbolLookup;
    -import java.lang.foreign.ValueLayout;
    -import java.lang.invoke.MethodHandle;
    -import java.nio.file.Files;
    -import java.nio.file.Path;
    -import java.util.Objects;
    -import java.util.Optional;
    -
    -import jdk.test.lib.process.OutputAnalyzer;
    -import jdk.test.lib.process.ProcessTools;
    -
    -public class RedirectedStdOut {
    -    private static final String OUTPUT = "Hello!";
    -
    -    public static void main(String... args) throws Throwable {
    -        RedirectedStdOut.class.getDeclaredMethod(args[0])
    -                              .invoke(new RedirectedStdOut());
    -    }
    -
    -    //verify the case where neither stdin/out/err is attached to a terminal,
    -    //this test is weaker, but more reliable:
    -    void runRedirectAllTest() throws Exception {
    -        ProcessBuilder builder =
    -                ProcessTools.createTestJavaProcessBuilder("-Djdk.console=jdk.internal.le", ConsoleTest.class.getName());
    -        OutputAnalyzer output = ProcessTools.executeProcess(builder);
    -
    -        output.waitFor();
    -
    -        if (output.getExitValue() != 0) {
    -            throw new AssertionError("Unexpected return value: " + output.getExitValue() +
    -                                     ", actualOut: " + output.getStdout() +
    -                                     ", actualErr: " + output.getStderr());
    -        }
    -
    -        String expectedOut = OUTPUT;
    -        String actualOut = output.getStdout();
    -
    -        if (!Objects.equals(expectedOut, actualOut)) {
    -            throw new AssertionError("Unexpected stdout content. " +
    -                                     "Expected: '" + expectedOut + "'" +
    -                                     ", got: '" + actualOut + "'");
    -        }
    -
    -        String expectedErr = "";
    -        String actualErr = output.getStderr();
    -
    -        if (!Objects.equals(expectedErr, actualErr)) {
    -            throw new AssertionError("Unexpected stderr content. " +
    -                                     "Expected: '" + expectedErr + "'" +
    -                                     ", got: '" + actualErr + "'");
    -        }
    -    }
    -
    -    //verify the case where stdin is attached to a terminal,
    -    //this test allocates pty, and it might be skipped, if the appropriate
    -    //native functions cannot be found
    -    //it also leaves the VM in a broken state (with a pty attached), and so
    -    //should run in a separate VM instance
    -    void runRedirectOutOnly() throws Throwable {
    -        Path stdout = Path.of(".", "stdout.txt").toAbsolutePath();
    -
    -        Files.deleteIfExists(stdout);
    -
    -        Linker linker = Linker.nativeLinker();
    -        SymbolLookup stdlib = linker.defaultLookup();
    -        MemorySegment parent = Arena.global().allocate(ValueLayout.ADDRESS);
    -        MemorySegment child = Arena.global().allocate(ValueLayout.ADDRESS);
    -        Optional openptyAddress = stdlib.find("openpty");
    -
    -        if (openptyAddress.isEmpty()) {
    -            System.out.println("Cannot lookup openpty.");
    -            //does not have forkpty, ignore
    -            return ;
    -        }
    -
    -        Optional loginttyAddress = stdlib.find("login_tty");
    -
    -        if (loginttyAddress.isEmpty()) {
    -            System.out.println("Cannot lookup login_tty.");
    -            //does not have forkpty, ignore
    -            return ;
    -        }
    -
    -        FunctionDescriptor openttyDescriptor =
    -                FunctionDescriptor.of(ValueLayout.JAVA_INT,
    -                                      ValueLayout.ADDRESS,
    -                                      ValueLayout.ADDRESS,
    -                                      ValueLayout.ADDRESS,
    -                                      ValueLayout.ADDRESS,
    -                                      ValueLayout.ADDRESS);
    -        MethodHandle forkpty = linker.downcallHandle(openptyAddress.get(),
    -                                                     openttyDescriptor);
    -        int res = (int) forkpty.invoke(parent,
    -                                       child,
    -                                       MemorySegment.NULL,
    -                                       MemorySegment.NULL,
    -                                       MemorySegment.NULL);
    -
    -        if (res != 0) {
    -            throw new AssertionError();
    -        }
    -
    -        //set the current VM's in/out to the terminal:
    -        FunctionDescriptor loginttyDescriptor =
    -                FunctionDescriptor.of(ValueLayout.JAVA_INT,
    -                                      ValueLayout.JAVA_INT);
    -        MethodHandle logintty = linker.downcallHandle(loginttyAddress.get(),
    -                                                      loginttyDescriptor);
    -        logintty.invoke(child.get(ValueLayout.JAVA_INT, 0));
    -
    -        //createTestJavaProcessBuilder logs to (current process') System.out, but
    -        //that may not work since the redirect. Setting System.out to a scratch value:
    -        System.setOut(new PrintStream(new ByteArrayOutputStream()));
    -
    -        ProcessBuilder builder =
    -            ProcessTools.createTestJavaProcessBuilder("-Djdk.console=jdk.internal.le", ConsoleTest.class.getName());
    -
    -        builder.inheritIO();
    -        builder.redirectOutput(stdout.toFile());
    -
    -        OutputAnalyzer output = ProcessTools.executeProcess(builder);
    -
    -        output.waitFor();
    -
    -        String expectedOut = OUTPUT;
    -        String actualOut = Files.readString(stdout);
    -
    -        if (!Objects.equals(expectedOut, actualOut)) {
    -            throw new AssertionError("Unexpected stdout content. " +
    -                                     "Expected: '" + expectedOut + "'" +
    -                                     ", got: '" + actualOut + "'");
    -        }
    -    }
    -
    -    public static class ConsoleTest {
    -        public static void main(String... args) {
    -            System.console().printf(OUTPUT);
    -            System.exit(0);
    -        }
    -    }
    -}
    
    From c01b4fc348fff37c502d38ab3bb3385a5a8cff9a Mon Sep 17 00:00:00 2001
    From: Ioi Lam 
    Date: Fri, 22 Aug 2025 20:41:21 +0000
    Subject: [PATCH 41/54] 8365814: Consolidate has_been_archived() and
     has_been_buffered() in ArchiveBuilder
    
    Reviewed-by: kvn, coleenp
    ---
     src/hotspot/share/cds/archiveBuilder.cpp    | 30 ++++++++++++++-------
     src/hotspot/share/cds/archiveBuilder.hpp    |  7 +++--
     src/hotspot/share/cds/archiveHeapWriter.cpp |  2 +-
     src/hotspot/share/cds/archiveUtils.cpp      |  3 +--
     4 files changed, 26 insertions(+), 16 deletions(-)
    
    diff --git a/src/hotspot/share/cds/archiveBuilder.cpp b/src/hotspot/share/cds/archiveBuilder.cpp
    index 7f8c7787152..1d054561c76 100644
    --- a/src/hotspot/share/cds/archiveBuilder.cpp
    +++ b/src/hotspot/share/cds/archiveBuilder.cpp
    @@ -748,17 +748,29 @@ void ArchiveBuilder::mark_and_relocate_to_buffered_addr(address* ptr_location) {
     
     bool ArchiveBuilder::has_been_archived(address src_addr) const {
       SourceObjInfo* p = _src_obj_table.get(src_addr);
    -  return (p != nullptr);
    -}
    -
    -bool ArchiveBuilder::has_been_buffered(address src_addr) const {
    -  if (RegeneratedClasses::has_been_regenerated(src_addr) ||
    -      _src_obj_table.get(src_addr) == nullptr ||
    -      get_buffered_addr(src_addr) == nullptr) {
    +  if (p == nullptr) {
    +    // This object has never been seen by ArchiveBuilder
         return false;
    -  } else {
    -    return true;
       }
    +  if (p->buffered_addr() == nullptr) {
    +    // ArchiveBuilder has seen this object, but decided not to archive it. So
    +    // Any reference to this object will be modified to nullptr inside the buffer.
    +    assert(p->follow_mode() == set_to_null, "must be");
    +    return false;
    +  }
    +
    +  DEBUG_ONLY({
    +    // This is a class/method that belongs to one of the "original" classes that
    +    // have been regenerated by lambdaFormInvokers.cpp. We must have archived
    +    // the "regenerated" version of it.
    +    if (RegeneratedClasses::has_been_regenerated(src_addr)) {
    +      address regen_obj = RegeneratedClasses::get_regenerated_object(src_addr);
    +      precond(regen_obj != nullptr && regen_obj != src_addr);
    +      assert(has_been_archived(regen_obj), "must be");
    +      assert(get_buffered_addr(src_addr) == get_buffered_addr(regen_obj), "must be");
    +    }});
    +
    +  return true;
     }
     
     address ArchiveBuilder::get_buffered_addr(address src_addr) const {
    diff --git a/src/hotspot/share/cds/archiveBuilder.hpp b/src/hotspot/share/cds/archiveBuilder.hpp
    index 1efd4045a99..39cc1c1eb8c 100644
    --- a/src/hotspot/share/cds/archiveBuilder.hpp
    +++ b/src/hotspot/share/cds/archiveBuilder.hpp
    @@ -180,6 +180,7 @@ private:
           return _buffered_addr;
         }
         MetaspaceObj::Type msotype() const { return _msotype; }
    +    FollowMode follow_mode() const { return _follow_mode; }
       };
     
       class SourceObjList {
    @@ -443,10 +444,8 @@ public:
       }
     
       bool has_been_archived(address src_addr) const;
    -
    -  bool has_been_buffered(address src_addr) const;
    -  template  bool has_been_buffered(T src_addr) const {
    -    return has_been_buffered((address)src_addr);
    +  template  bool has_been_archived(T src_addr) const {
    +    return has_been_archived((address)src_addr);
       }
     
       address get_buffered_addr(address src_addr) const;
    diff --git a/src/hotspot/share/cds/archiveHeapWriter.cpp b/src/hotspot/share/cds/archiveHeapWriter.cpp
    index b651da8418b..9c55b71a1b2 100644
    --- a/src/hotspot/share/cds/archiveHeapWriter.cpp
    +++ b/src/hotspot/share/cds/archiveHeapWriter.cpp
    @@ -764,7 +764,7 @@ void ArchiveHeapWriter::compute_ptrmap(ArchiveHeapInfo* heap_info) {
           native_ptr = RegeneratedClasses::get_regenerated_object(native_ptr);
         }
     
    -    guarantee(ArchiveBuilder::current()->has_been_buffered((address)native_ptr),
    +    guarantee(ArchiveBuilder::current()->has_been_archived((address)native_ptr),
                   "Metadata %p should have been archived", native_ptr);
     
         address buffered_native_ptr = ArchiveBuilder::current()->get_buffered_addr((address)native_ptr);
    diff --git a/src/hotspot/share/cds/archiveUtils.cpp b/src/hotspot/share/cds/archiveUtils.cpp
    index 9a92c6a8648..3c900cad035 100644
    --- a/src/hotspot/share/cds/archiveUtils.cpp
    +++ b/src/hotspot/share/cds/archiveUtils.cpp
    @@ -383,8 +383,7 @@ void ArchiveUtils::log_to_classlist(BootstrapInfo* bootstrap_specifier, TRAPS) {
     }
     
     bool ArchiveUtils::has_aot_initialized_mirror(InstanceKlass* src_ik) {
    -  if (SystemDictionaryShared::is_excluded_class(src_ik)) {
    -    assert(!ArchiveBuilder::current()->has_been_buffered(src_ik), "sanity");
    +  if (!ArchiveBuilder::current()->has_been_archived(src_ik)) {
         return false;
       }
       return ArchiveBuilder::current()->get_buffered_addr(src_ik)->has_aot_initialized_mirror();
    
    From 603526b55b5e9b6dfc9323d2cdc4a0b4d0f88a49 Mon Sep 17 00:00:00 2001
    From: Phil Race 
    Date: Fri, 22 Aug 2025 20:50:34 +0000
    Subject: [PATCH 42/54] 8364768: JDK javax.imageio ImageWriters do not all
     flush the output stream
    
    Reviewed-by: psadhukhan, azvegint
    ---
     .../imageio/plugins/gif/GIFImageWriter.java   |  1 +
     .../imageio/plugins/tiff/TIFFImageWriter.java |  1 +
     test/jdk/javax/imageio/FlushTest.java         | 76 +++++++++++++++++++
     3 files changed, 78 insertions(+)
     create mode 100644 test/jdk/javax/imageio/FlushTest.java
    
    diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageWriter.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageWriter.java
    index 9558991b767..e009e33d8a0 100644
    --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageWriter.java
    +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/gif/GIFImageWriter.java
    @@ -734,6 +734,7 @@ public class GIFImageWriter extends ImageWriter {
             if (writeTrailer) {
                 writeTrailer();
             }
    +        stream.flush();
         }
     
         /**
    diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageWriter.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageWriter.java
    index e2227ee6b48..d56bc89035b 100644
    --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageWriter.java
    +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageWriter.java
    @@ -2327,6 +2327,7 @@ public class TIFFImageWriter extends ImageWriter {
             if (abortRequested()) {
                 resetPositions();
             }
    +        stream.flush();
         }
     
         private void writeHeader() throws IOException {
    diff --git a/test/jdk/javax/imageio/FlushTest.java b/test/jdk/javax/imageio/FlushTest.java
    new file mode 100644
    index 00000000000..e342880e65f
    --- /dev/null
    +++ b/test/jdk/javax/imageio/FlushTest.java
    @@ -0,0 +1,76 @@
    +/*
    + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
    + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    + *
    + * This code is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License version 2 only, as
    + * published by the Free Software Foundation.
    + *
    + * This code is distributed in the hope that it will be useful, but WITHOUT
    + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    + * version 2 for more details (a copy is included in the LICENSE file that
    + * accompanied this code).
    + *
    + * You should have received a copy of the GNU General Public License version
    + * 2 along with this work; if not, write to the Free Software Foundation,
    + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    + *
    + * Please 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 8364768
    + * @summary Tests that the standard plugins flush the stream after writing a complete image.
    + */
    +
    +import static java.awt.Color.WHITE;
    +import java.awt.Graphics2D;
    +import java.awt.image.BufferedImage;
    +import java.io.IOException;
    +import java.io.ByteArrayOutputStream;
    +import javax.imageio.ImageIO;
    +import javax.imageio.ImageWriter;
    +import javax.imageio.stream.FileCacheImageOutputStream;
    +
    +public class FlushTest {
    +
    +    static final int SZ = 1000;
    +    static BufferedImage bi;
    +    static final String[] FORMATS = { "jpg", "png", "gif", "tiff", "bmp", "wbmp" } ;
    +    static boolean failed = false;
    +
    +    public static void main(String[] args) throws IOException {
    +
    +        bi = new BufferedImage(SZ, SZ, BufferedImage.TYPE_BYTE_BINARY);
    +        Graphics2D g2d = bi.createGraphics();
    +        g2d.setPaint(WHITE);
    +        g2d.fillRect(0, 0, SZ, SZ);
    +
    +        for (String f : FORMATS) {
    +            testWrite(f);
    +        }
    +        if (failed) {
    +           throw new RuntimeException("Stream sizes differ.");
    +        }
    +    }
    +
    +    static void testWrite(String fmt) throws IOException {
    +        ImageWriter iw = ImageIO.getImageWritersBySuffix(fmt).next();
    +        System.out.println(iw);
    +        ByteArrayOutputStream baos = new ByteArrayOutputStream();
    +        FileCacheImageOutputStream fcs = new FileCacheImageOutputStream(baos, null);
    +        iw.setOutput(fcs);
    +        iw.write(bi);
    +        int sz0 = baos.size();
    +        fcs.close();
    +        int sz1 = baos.size();
    +        System.out.println("fmt=" + fmt + " sizes=" + sz0 + ", " + sz1);
    +        if (sz0 != sz1) {
    +           failed = true;
    +        }
    +    }
    +}
    
    From f28f6189721a86b1a6ad0a19cc38192af55eb45a Mon Sep 17 00:00:00 2001
    From: Cesar Soares Lucas 
    Date: Fri, 22 Aug 2025 21:51:21 +0000
    Subject: [PATCH 43/54] 8356289: Shenandoah: Clean up SATB barrier runtime
     entry points
    
    Reviewed-by: kdnilsen, ysr, wkemper
    ---
     .../shenandoahBarrierSetAssembler_aarch64.cpp  |  6 +++---
     .../shenandoahBarrierSetAssembler_ppc.cpp      |  4 ++--
     .../shenandoahBarrierSetAssembler_riscv.cpp    |  6 +++---
     .../shenandoahBarrierSetAssembler_x86.cpp      |  6 +++---
     src/hotspot/share/code/aotCodeCache.cpp        |  2 +-
     .../shenandoah/c2/shenandoahBarrierSetC2.cpp   | 18 ++++++++----------
     .../shenandoah/c2/shenandoahBarrierSetC2.hpp   |  2 +-
     .../share/gc/shenandoah/shenandoahRuntime.cpp  |  8 ++------
     .../share/gc/shenandoah/shenandoahRuntime.hpp  |  1 -
     9 files changed, 23 insertions(+), 30 deletions(-)
    
    diff --git a/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp
    index ed321ca4759..200c4217134 100644
    --- a/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp
    +++ b/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp
    @@ -172,9 +172,9 @@ void ShenandoahBarrierSetAssembler::satb_write_barrier_pre(MacroAssembler* masm,
     
       if (expand_call) {
         assert(pre_val != c_rarg1, "smashed arg");
    -    __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre), pre_val, thread);
    +    __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_barrier_pre), pre_val);
       } else {
    -    __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre), pre_val, thread);
    +    __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_barrier_pre), pre_val);
       }
     
       __ pop(saved, sp);
    @@ -753,7 +753,7 @@ void ShenandoahBarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAss
       __ bind(runtime);
       __ push_call_clobbered_registers();
       __ load_parameter(0, pre_val);
    -  __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre), pre_val, thread);
    +  __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_barrier_pre), pre_val);
       __ pop_call_clobbered_registers();
       __ bind(done);
     
    diff --git a/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.cpp b/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.cpp
    index b7156144d8b..1f1bc7622ed 100644
    --- a/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.cpp
    +++ b/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.cpp
    @@ -311,7 +311,7 @@ void ShenandoahBarrierSetAssembler::satb_write_barrier_impl(MacroAssembler *masm
       }
     
       // Invoke runtime.
    -  __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre), pre_val, R16_thread);
    +  __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_barrier_pre), pre_val);
     
       // Restore to-be-preserved registers.
       if (!preserve_gp_registers && preloaded_mode && pre_val->is_volatile()) {
    @@ -966,7 +966,7 @@ void ShenandoahBarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAss
       __ push_frame_reg_args(nbytes_save, R11_tmp1);
     
       // Invoke runtime.
    -  __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre), R0_pre_val, R16_thread);
    +  __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_barrier_pre), R0_pre_val);
     
       // Restore to-be-preserved registers.
       __ pop_frame();
    diff --git a/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.cpp b/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.cpp
    index 4c1056e75a5..f1236bc183a 100644
    --- a/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.cpp
    +++ b/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.cpp
    @@ -172,9 +172,9 @@ void ShenandoahBarrierSetAssembler::satb_write_barrier_pre(MacroAssembler* masm,
       // expand_call should be passed true.
       if (expand_call) {
         assert(pre_val != c_rarg1, "smashed arg");
    -    __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre), pre_val, thread);
    +    __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_barrier_pre), pre_val);
       } else {
    -    __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre), pre_val, thread);
    +    __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_barrier_pre), pre_val);
       }
     
       __ pop_reg(saved, sp);
    @@ -702,7 +702,7 @@ void ShenandoahBarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAss
       __ bind(runtime);
       __ push_call_clobbered_registers();
       __ load_parameter(0, pre_val);
    -  __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre), pre_val, thread);
    +  __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_barrier_pre), pre_val);
       __ pop_call_clobbered_registers();
       __ bind(done);
     
    diff --git a/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp
    index d043c8af68a..9e321391f6c 100644
    --- a/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp
    +++ b/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp
    @@ -276,9 +276,9 @@ void ShenandoahBarrierSetAssembler::satb_write_barrier_pre(MacroAssembler* masm,
           __ mov(c_rarg1, thread);
         }
         // Already moved pre_val into c_rarg0 above
    -    __ MacroAssembler::call_VM_leaf_base(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre), 2);
    +    __ MacroAssembler::call_VM_leaf_base(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_barrier_pre), 1);
       } else {
    -    __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre), c_rarg0, thread);
    +    __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_barrier_pre), c_rarg0);
       }
     
       // save the live input values
    @@ -946,7 +946,7 @@ void ShenandoahBarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAss
     
       // load the pre-value
       __ load_parameter(0, rcx);
    -  __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre), rcx, thread);
    +  __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_barrier_pre), rcx);
     
       __ restore_live_registers(true);
     
    diff --git a/src/hotspot/share/code/aotCodeCache.cpp b/src/hotspot/share/code/aotCodeCache.cpp
    index df2e9648b84..7e53f493c47 100644
    --- a/src/hotspot/share/code/aotCodeCache.cpp
    +++ b/src/hotspot/share/code/aotCodeCache.cpp
    @@ -1369,7 +1369,7 @@ void AOTCodeAddressTable::init_extrs() {
       SET_ADDRESS(_extrs, G1BarrierSetRuntime::write_ref_field_pre_entry);
     #endif
     #if INCLUDE_SHENANDOAHGC
    -  SET_ADDRESS(_extrs, ShenandoahRuntime::write_ref_field_pre);
    +  SET_ADDRESS(_extrs, ShenandoahRuntime::write_barrier_pre);
       SET_ADDRESS(_extrs, ShenandoahRuntime::load_reference_barrier_phantom);
       SET_ADDRESS(_extrs, ShenandoahRuntime::load_reference_barrier_phantom_narrow);
     #endif
    diff --git a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp
    index f12b3dc5fa8..fdfde866cd7 100644
    --- a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp
    +++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp
    @@ -250,9 +250,8 @@ void ShenandoahBarrierSetC2::satb_write_barrier_pre(GraphKit* kit,
           } __ else_(); {
     
             // logging buffer is full, call the runtime
    -        const TypeFunc *tf = ShenandoahBarrierSetC2::write_ref_field_pre_Type();
    -        __ make_leaf_call(tf, CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre), "shenandoah_wb_pre",
    -                          pre_val, tls);
    +        const TypeFunc *tf = ShenandoahBarrierSetC2::write_barrier_pre_Type();
    +        __ make_leaf_call(tf, CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_barrier_pre), "shenandoah_wb_pre", pre_val);
           } __ end_if();  // (!index)
         } __ end_if();  // (pre_val != nullptr)
       } __ end_if();  // (!marking)
    @@ -270,7 +269,7 @@ void ShenandoahBarrierSetC2::satb_write_barrier_pre(GraphKit* kit,
     
     bool ShenandoahBarrierSetC2::is_shenandoah_wb_pre_call(Node* call) {
       return call->is_CallLeaf() &&
    -         call->as_CallLeaf()->entry_point() == CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre);
    +         call->as_CallLeaf()->entry_point() == CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_barrier_pre);
     }
     
     bool ShenandoahBarrierSetC2::is_shenandoah_clone_call(Node* call) {
    @@ -520,11 +519,10 @@ void ShenandoahBarrierSetC2::post_barrier(GraphKit* kit,
     
     #undef __
     
    -const TypeFunc* ShenandoahBarrierSetC2::write_ref_field_pre_Type() {
    -  const Type **fields = TypeTuple::fields(2);
    +const TypeFunc* ShenandoahBarrierSetC2::write_barrier_pre_Type() {
    +  const Type **fields = TypeTuple::fields(1);
       fields[TypeFunc::Parms+0] = TypeInstPtr::NOTNULL; // original field value
    -  fields[TypeFunc::Parms+1] = TypeRawPtr::NOTNULL; // thread
    -  const TypeTuple *domain = TypeTuple::make(TypeFunc::Parms+2, fields);
    +  const TypeTuple *domain = TypeTuple::make(TypeFunc::Parms+1, fields);
     
       // create result type (range)
       fields = TypeTuple::fields(0);
    @@ -1108,7 +1106,7 @@ void ShenandoahBarrierSetC2::verify_gc_barriers(Compile* compile, CompilePhase p
     
     Node* ShenandoahBarrierSetC2::ideal_node(PhaseGVN* phase, Node* n, bool can_reshape) const {
       if (is_shenandoah_wb_pre_call(n)) {
    -    uint cnt = ShenandoahBarrierSetC2::write_ref_field_pre_Type()->domain()->cnt();
    +    uint cnt = ShenandoahBarrierSetC2::write_barrier_pre_Type()->domain()->cnt();
         if (n->req() > cnt) {
           Node* addp = n->in(cnt);
           if (has_only_shenandoah_wb_pre_uses(addp)) {
    @@ -1194,7 +1192,7 @@ bool ShenandoahBarrierSetC2::final_graph_reshaping(Compile* compile, Node* n, ui
           assert (n->is_Call(), "");
           CallNode *call = n->as_Call();
           if (ShenandoahBarrierSetC2::is_shenandoah_wb_pre_call(call)) {
    -        uint cnt = ShenandoahBarrierSetC2::write_ref_field_pre_Type()->domain()->cnt();
    +        uint cnt = ShenandoahBarrierSetC2::write_barrier_pre_Type()->domain()->cnt();
             if (call->req() > cnt) {
               assert(call->req() == cnt + 1, "only one extra input");
               Node *addp = call->in(cnt);
    diff --git a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.hpp b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.hpp
    index 5bf549203ea..dd9e9bcc1a5 100644
    --- a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.hpp
    +++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.hpp
    @@ -103,7 +103,7 @@ public:
     
       ShenandoahBarrierSetC2State* state() const;
     
    -  static const TypeFunc* write_ref_field_pre_Type();
    +  static const TypeFunc* write_barrier_pre_Type();
       static const TypeFunc* clone_barrier_Type();
       static const TypeFunc* load_reference_barrier_Type();
       virtual bool has_load_barrier_nodes() const { return true; }
    diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRuntime.cpp b/src/hotspot/share/gc/shenandoah/shenandoahRuntime.cpp
    index 97ba5012efa..0bee8b4cf42 100644
    --- a/src/hotspot/share/gc/shenandoah/shenandoahRuntime.cpp
    +++ b/src/hotspot/share/gc/shenandoah/shenandoahRuntime.cpp
    @@ -38,20 +38,16 @@ JRT_LEAF(void, ShenandoahRuntime::arraycopy_barrier_narrow_oop(narrowOop* src, n
       ShenandoahBarrierSet::barrier_set()->arraycopy_barrier(src, dst, length);
     JRT_END
     
    -JRT_LEAF(void, ShenandoahRuntime::write_ref_field_pre(oopDesc * orig, JavaThread * thread))
    -  assert(thread == JavaThread::current(), "pre-condition");
    +JRT_LEAF(void, ShenandoahRuntime::write_barrier_pre(oopDesc* orig))
       assert(orig != nullptr, "should be optimized out");
       shenandoah_assert_correct(nullptr, orig);
       // Capture the original value that was in the field reference.
    +  JavaThread* thread = JavaThread::current();
       assert(ShenandoahThreadLocalData::satb_mark_queue(thread).is_active(), "Shouldn't be here otherwise");
       SATBMarkQueue& queue = ShenandoahThreadLocalData::satb_mark_queue(thread);
       ShenandoahBarrierSet::satb_mark_queue_set().enqueue_known_active(queue, orig);
     JRT_END
     
    -void ShenandoahRuntime::write_barrier_pre(oopDesc* orig) {
    -  write_ref_field_pre(orig, JavaThread::current());
    -}
    -
     JRT_LEAF(oopDesc*, ShenandoahRuntime::load_reference_barrier_strong(oopDesc* src, oop* load_addr))
       return ShenandoahBarrierSet::barrier_set()->load_reference_barrier_mutator(src, load_addr);
     JRT_END
    diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRuntime.hpp b/src/hotspot/share/gc/shenandoah/shenandoahRuntime.hpp
    index 0ed8959d95e..f1919095d58 100644
    --- a/src/hotspot/share/gc/shenandoah/shenandoahRuntime.hpp
    +++ b/src/hotspot/share/gc/shenandoah/shenandoahRuntime.hpp
    @@ -36,7 +36,6 @@ public:
       static void arraycopy_barrier_oop(oop* src, oop* dst, size_t length);
       static void arraycopy_barrier_narrow_oop(narrowOop* src, narrowOop* dst, size_t length);
     
    -  static void write_ref_field_pre(oopDesc* orig, JavaThread* thread);
       static void write_barrier_pre(oopDesc* orig);
     
       static oopDesc* load_reference_barrier_strong(oopDesc* src, oop* load_addr);
    
    From 7b9969dc8f20989497ff617abb45543d182b684d Mon Sep 17 00:00:00 2001
    From: Alexander Matveev 
    Date: Fri, 22 Aug 2025 22:24:39 +0000
    Subject: [PATCH 44/54] 8356218: [macos] Document --app-content
    
    Reviewed-by: asemenyuk
    ---
     .../internal/MacApplicationBuilder.java       | 20 ++++++++++++++++
     .../resources/MacResources.properties         |  2 ++
     .../jdk/jpackage/internal/CLIHelp.java        | 10 ++++++--
     .../resources/HelpResources.properties        | 11 +++++++--
     src/jdk.jpackage/share/man/jpackage.md        |  6 +++++
     .../jdk/jpackage/test/JPackageCommand.java    | 24 +++++++++++++++----
     .../tools/jpackage/share/AppContentTest.java  | 16 ++++++++++++-
     7 files changed, 80 insertions(+), 9 deletions(-)
    
    diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationBuilder.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationBuilder.java
    index fc1dd97d9ab..226bb9e8134 100644
    --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationBuilder.java
    +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacApplicationBuilder.java
    @@ -26,7 +26,10 @@ package jdk.jpackage.internal;
     
     import java.io.IOException;
     import java.io.UncheckedIOException;
    +import java.nio.file.Files;
     import java.nio.file.Path;
    +import java.util.List;
    +import java.util.Set;
     import java.util.Objects;
     import java.util.Optional;
     import jdk.jpackage.internal.model.Application;
    @@ -95,6 +98,7 @@ final class MacApplicationBuilder {
             }
     
             validateAppVersion(app);
    +        validateAppContentDirs(app);
     
             final var mixin = new MacApplicationMixin.Stub(
                     validatedIcon(),
    @@ -140,6 +144,18 @@ final class MacApplicationBuilder {
             }
         }
     
    +    private static void validateAppContentDirs(Application app) {
    +        for (var contentDir : app.contentDirs()) {
    +            if (!Files.isDirectory(contentDir)) {
    +                Log.info(I18N.format("warning.app.content.is.not.dir",
    +                        contentDir));
    +            } else if (!CONTENTS_SUB_DIRS.contains(contentDir.getFileName().toString())) {
    +                Log.info(I18N.format("warning.non.standard.contents.sub.dir",
    +                        contentDir));
    +            }
    +        }
    +    }
    +
         private MacApplicationBuilder createCopyForExternalInfoPlistFile() throws ConfigException {
             try {
                 final var plistFile = AppImageInfoPListFile.loadFromInfoPList(externalInfoPlistFile);
    @@ -250,4 +266,8 @@ final class MacApplicationBuilder {
         private static final Defaults DEFAULTS = new Defaults("utilities");
     
         private static final int MAX_BUNDLE_NAME_LENGTH = 16;
    +
    +    // List of standard subdirectories of the "Contents" directory
    +    private static final Set CONTENTS_SUB_DIRS = Set.of("MacOS",
    +            "Resources", "Frameworks", "PlugIns", "SharedSupport");
     }
    diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources.properties b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources.properties
    index 7fada9e4305..c48513c7a51 100644
    --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources.properties
    +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources.properties
    @@ -85,3 +85,5 @@ message.codesign.failed.reason.app.content="codesign" failed and additional appl
     message.codesign.failed.reason.xcode.tools=Possible reason for "codesign" failure is missing Xcode with command line developer tools. Install Xcode with command line developer tools to see if it resolves the problem.
     warning.unsigned.app.image=Warning: Using unsigned app-image to build signed {0}.
     warning.per.user.app.image.signed=Warning: Support for per-user configuration of the installed application will not be supported due to missing "{0}" in predefined signed application image.
    +warning.non.standard.contents.sub.dir=Warning: The file name of the directory "{0}" specified for the --app-content option is not a standard subdirectory name in the "Contents" directory of the application bundle. The result application bundle may fail code signing and/or notarization.
    +warning.app.content.is.not.dir=Warning: The value "{0}" of the --app-content option is not a directory. The result application bundle may fail code signing and/or notarization.
    \ No newline at end of file
    diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/CLIHelp.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/CLIHelp.java
    index 1dd2d823f27..7790ebb3ebb 100644
    --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/CLIHelp.java
    +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/CLIHelp.java
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      *
      * This code is free software; you can redistribute it and/or modify it
    @@ -55,6 +55,7 @@ public class CLIHelp {
                 String pInstallDir;
                 String pAppImageDescription;
                 String pSignSampleUsage;
    +            String pAppContentNote;
                 switch (platform) {
                     case MACOS:
                         types = "{\"app-image\", \"dmg\", \"pkg\"}";
    @@ -66,6 +67,8 @@ public class CLIHelp {
                                 = I18N.getString("MSG_Help_mac_app_image");
                         pSignSampleUsage
                                 = I18N.getString("MSG_Help_mac_sign_sample_usage");
    +                    pAppContentNote
    +                            = I18N.getString("MSG_Help_mac_app_content_note");
                         break;
                     case LINUX:
                         types = "{\"app-image\", \"rpm\", \"deb\"}";
    @@ -76,6 +79,7 @@ public class CLIHelp {
                         pAppImageDescription
                                 = I18N.getString("MSG_Help_default_app_image");
                         pSignSampleUsage = "";
    +                    pAppContentNote = "";
                         break;
                     case WINDOWS:
                         types = "{\"app-image\", \"exe\", \"msi\"}";
    @@ -86,6 +90,7 @@ public class CLIHelp {
                         pAppImageDescription
                                 = I18N.getString("MSG_Help_default_app_image");
                         pSignSampleUsage = "";
    +                    pAppContentNote = "";
                         break;
                     default:
                         types = "{\"app-image\", \"exe\", \"msi\", \"rpm\", \"deb\", \"pkg\", \"dmg\"}";
    @@ -99,12 +104,13 @@ public class CLIHelp {
                         pAppImageDescription
                                 = I18N.getString("MSG_Help_default_app_image");
                         pSignSampleUsage = "";
    +                    pAppContentNote = "";
                         break;
                 }
                 Log.info(MessageFormat.format(I18N.getString("MSG_Help"),
                         File.pathSeparator, types, pLaunchOptions,
                         pInstallOptions, pInstallDir, pAppImageDescription,
    -                    pSignSampleUsage));
    +                    pSignSampleUsage, pAppContentNote));
             }
         }
     }
    diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources.properties b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources.properties
    index 0f0d9fd5a17..df87a63cb8e 100644
    --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources.properties
    +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources.properties
    @@ -1,5 +1,5 @@
     #
    -# Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
    +# Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
     # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     #
     # This code is free software; you can redistribute it and/or modify it
    @@ -133,7 +133,7 @@ Generic Options:\n\
     \          A comma separated list of paths to files and/or directories\n\
     \          to add to the application payload.\n\
     \          This option can be used more than once.\n\
    -\n\
    +{7}\n\
     \Options for creating the application launcher(s):\n\
     \  --add-launcher =\n\
     \          Name of launcher, and a path to a Properties file that contains\n\
    @@ -334,3 +334,10 @@ MSG_Help_mac_sign_sample_usage=\
     \            --mac-sign [...]\n\
     \        Note: the only additional options that are permitted in this mode are:\n\
     \              the set of additional mac signing options and --verbose\n\
    +
    +MSG_Help_mac_app_content_note=\
    +\          Note: The value should be a directory with the "Resources"\n\
    +\          subdirectory (or any other directory that is valid in the "Contents"\n\
    +\          directory of the application bundle). Otherwise, jpackage may produce\n\
    +\          invalid application bundle which may fail code signing and/or\n\
    +\          notarization.\n\
    diff --git a/src/jdk.jpackage/share/man/jpackage.md b/src/jdk.jpackage/share/man/jpackage.md
    index e49b04e204e..f78bec9808c 100644
    --- a/src/jdk.jpackage/share/man/jpackage.md
    +++ b/src/jdk.jpackage/share/man/jpackage.md
    @@ -190,6 +190,12 @@ The `jpackage` tool will take as input a Java application and a Java run-time im
     
         This option can be used more than once.
     
    +    macOS note: The value should be a directory with the "Resources"
    +                subdirectory (or any other directory that is valid in the
    +                "Contents" directory of the application bundle). Otherwise,
    +                jpackage may produce invalid application bundle which may fail
    +                code signing and/or notarization.
    +
     ### Options for creating the application launcher(s):
     
     
    diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java
    index 3a423fd71ca..49f565e27e9 100644
    --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java
    +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java
    @@ -46,6 +46,7 @@ import java.util.ListIterator;
     import java.util.Map;
     import java.util.Objects;
     import java.util.Optional;
    +import java.util.OptionalInt;
     import java.util.Set;
     import java.util.function.Consumer;
     import java.util.function.Function;
    @@ -811,11 +812,19 @@ public class JPackageCommand extends CommandArguments {
             return exec;
         }
     
    +    public Executor.Result executeIgnoreExitCode() {
    +        return execute(OptionalInt.empty());
    +    }
    +
         public Executor.Result execute() {
             return execute(0);
         }
     
         public Executor.Result execute(int expectedExitCode) {
    +        return execute(OptionalInt.of(expectedExitCode));
    +    }
    +
    +    private Executor.Result execute(OptionalInt expectedExitCode) {
             verifyMutable();
             executePrerequisiteActions();
     
    @@ -852,7 +861,8 @@ public class JPackageCommand extends CommandArguments {
                 }
             }
     
    -        if (expectedExitCode == 0 && !isImagePackageType()) {
    +        if (expectedExitCode.isPresent() && expectedExitCode.orElseThrow() == 0
    +                && !isImagePackageType()) {
                 ConfigFilesStasher.INSTANCE.accept(this);
             }
     
    @@ -860,11 +870,17 @@ public class JPackageCommand extends CommandArguments {
     
             final var directoriesAssert = new ReadOnlyPathsAssert(copy);
     
    -        Executor.Result result = copy.createExecutor().execute(expectedExitCode);
    +        Executor.Result result;
    +        if (expectedExitCode.isEmpty()) {
    +            result = copy.createExecutor().executeWithoutExitCodeCheck();
    +        } else {
    +            result = copy.createExecutor().execute(expectedExitCode.orElseThrow());
    +        }
     
             directoriesAssert.updateAndAssert();
     
    -        if (expectedExitCode == 0 && isImagePackageType()) {
    +        if (expectedExitCode.isPresent() && expectedExitCode.orElseThrow() == 0
    +                && isImagePackageType()) {
                 ConfigFilesStasher.INSTANCE.accept(this);
             }
     
    @@ -872,7 +888,7 @@ public class JPackageCommand extends CommandArguments {
                 outputValidator.accept(result.getOutput().iterator());
             }
     
    -        if (result.exitCode() == 0) {
    +        if (result.exitCode() == 0 && expectedExitCode.isPresent()) {
                 verifyActions.run();
             }
     
    diff --git a/test/jdk/tools/jpackage/share/AppContentTest.java b/test/jdk/tools/jpackage/share/AppContentTest.java
    index 15b61763562..edb7e2918da 100644
    --- a/test/jdk/tools/jpackage/share/AppContentTest.java
    +++ b/test/jdk/tools/jpackage/share/AppContentTest.java
    @@ -33,12 +33,12 @@ import jdk.jpackage.test.TKit;
     import jdk.jpackage.test.Annotations.Test;
     import jdk.jpackage.test.Annotations.Parameter;
     import java.util.Arrays;
    -import java.util.Collection;
     import java.util.List;
     import java.util.stream.Stream;
     import jdk.jpackage.internal.util.FileUtils;
     import jdk.jpackage.internal.util.function.ThrowingFunction;
     import jdk.jpackage.test.JPackageCommand;
    +import jdk.jpackage.test.JPackageStringBundle;
     
     
     /**
    @@ -116,6 +116,20 @@ public class AppContentTest {
                 .run();
         }
     
    +    @Test(ifOS = MACOS)
    +    @Parameter({TEST_DIR, "warning.non.standard.contents.sub.dir"})
    +    @Parameter({TEST_DUKE, "warning.app.content.is.not.dir"})
    +    public void testWarnings(String testPath, String warningId) throws Exception {
    +        final var appContentValue = TKit.TEST_SRC_ROOT.resolve(testPath);
    +        final var expectedWarning = JPackageStringBundle.MAIN.cannedFormattedString(
    +                warningId, appContentValue);
    +
    +        JPackageCommand.helloAppImage()
    +            .addArguments("--app-content", appContentValue)
    +            .validateOutput(expectedWarning)
    +            .executeIgnoreExitCode();
    +    }
    +
         private static Path getAppContentRoot(JPackageCommand cmd) {
             Path contentDir = cmd.appLayout().contentDirectory();
             if (copyInResources) {
    
    From 09aad0aea8b9f9fda14c5b18ae67b30ffce817d9 Mon Sep 17 00:00:00 2001
    From: SendaoYan 
    Date: Sat, 23 Aug 2025 02:43:23 +0000
    Subject: [PATCH 45/54] 8365834: Mark java/net/httpclient/ManyRequests.java  as
     intermittent
    
    Reviewed-by: jpai
    ---
     test/jdk/java/net/httpclient/ManyRequests.java | 1 +
     1 file changed, 1 insertion(+)
    
    diff --git a/test/jdk/java/net/httpclient/ManyRequests.java b/test/jdk/java/net/httpclient/ManyRequests.java
    index 5d698d60ee5..493c2c3a504 100644
    --- a/test/jdk/java/net/httpclient/ManyRequests.java
    +++ b/test/jdk/java/net/httpclient/ManyRequests.java
    @@ -24,6 +24,7 @@
     /*
      * @test
      * @bug 8087112 8180044 8256459
    + * @key intermittent
      * @modules java.net.http
      *          java.logging
      *          jdk.httpserver
    
    From 58e7581527208dfd6dd694793e4790dcad8fc3ef Mon Sep 17 00:00:00 2001
    From: Alan Bateman 
    Date: Sun, 24 Aug 2025 16:22:21 +0000
    Subject: [PATCH 46/54] 8365893:
     test/jdk/java/lang/Thread/virtual/JfrEvents.java failing intermittently
    
    Reviewed-by: jpai
    ---
     test/jdk/java/lang/Thread/virtual/JfrEvents.java | 12 +++++++-----
     1 file changed, 7 insertions(+), 5 deletions(-)
    
    diff --git a/test/jdk/java/lang/Thread/virtual/JfrEvents.java b/test/jdk/java/lang/Thread/virtual/JfrEvents.java
    index 0b0c2ccc7a0..0c967811481 100644
    --- a/test/jdk/java/lang/Thread/virtual/JfrEvents.java
    +++ b/test/jdk/java/lang/Thread/virtual/JfrEvents.java
    @@ -42,6 +42,7 @@ import java.util.concurrent.ThreadFactory;
     import java.util.concurrent.atomic.AtomicBoolean;
     import java.util.concurrent.locks.LockSupport;
     import java.util.stream.Collectors;
    +import java.util.stream.IntStream;
     import java.util.stream.Stream;
     
     import jdk.jfr.EventType;
    @@ -77,12 +78,13 @@ class JfrEvents {
     
                 // execute 100 tasks, each in their own virtual thread
                 recording.start();
    -            ThreadFactory factory = Thread.ofVirtual().factory();
    -            try (var executor = Executors.newThreadPerTaskExecutor(factory)) {
    -                for (int i = 0; i < 100; i++) {
    -                    executor.submit(() -> { });
    +            try {
    +                List threads = IntStream.range(0, 100)
    +                        .mapToObj(_ -> Thread.startVirtualThread(() -> { }))
    +                        .toList();
    +                for (Thread t : threads) {
    +                    t.join();
                     }
    -                Thread.sleep(1000); // give time for thread end events to be recorded
                 } finally {
                     recording.stop();
                 }
    
    From 15601b4718ed26de6f57e633c4f41f6b0cd90cb0 Mon Sep 17 00:00:00 2001
    From: Ioi Lam 
    Date: Mon, 25 Aug 2025 04:01:00 +0000
    Subject: [PATCH 47/54] 8366029: Do not add -XX:VerifyArchivedFields by default
     to CDS tests
    
    Reviewed-by: kvn
    ---
     .../jtreg/runtime/cds/appcds/LotsOfSyntheticClasses.java      | 3 ++-
     test/hotspot/jtreg/runtime/cds/appcds/TestCommon.java         | 4 +---
     test/lib/jdk/test/lib/cds/CDSAppTester.java                   | 2 --
     test/lib/jdk/test/lib/cds/CDSTestUtils.java                   | 1 -
     4 files changed, 3 insertions(+), 7 deletions(-)
    
    diff --git a/test/hotspot/jtreg/runtime/cds/appcds/LotsOfSyntheticClasses.java b/test/hotspot/jtreg/runtime/cds/appcds/LotsOfSyntheticClasses.java
    index 6267c6bdf33..3c3db7d0397 100644
    --- a/test/hotspot/jtreg/runtime/cds/appcds/LotsOfSyntheticClasses.java
    +++ b/test/hotspot/jtreg/runtime/cds/appcds/LotsOfSyntheticClasses.java
    @@ -120,9 +120,9 @@ public class LotsOfSyntheticClasses {
                 OutputAnalyzer output = TestCommon.createArchive(
                     APP_JAR.toString(),
                     listAppClasses(),
    -                MAIN_CLASS_NAME,
                     // Verification for lots of classes slows down the test.
                     "-XX:+IgnoreUnrecognizedVMOptions",
    +                "-XX:+UnlockDiagnosticVMOptions",
                     "-XX:-VerifyDependencies",
                     "-XX:-VerifyBeforeExit"
                 );
    @@ -134,6 +134,7 @@ public class LotsOfSyntheticClasses {
                 TestCommon.run(
                     // Verification for lots of classes slows down the test.
                     "-XX:+IgnoreUnrecognizedVMOptions",
    +                "-XX:+UnlockDiagnosticVMOptions",
                     "-XX:-VerifyDependencies",
                     "-XX:-VerifyBeforeExit",
                     "-cp", APP_JAR.toString(),
    diff --git a/test/hotspot/jtreg/runtime/cds/appcds/TestCommon.java b/test/hotspot/jtreg/runtime/cds/appcds/TestCommon.java
    index 4f2822a5970..5d1e3831d86 100644
    --- a/test/hotspot/jtreg/runtime/cds/appcds/TestCommon.java
    +++ b/test/hotspot/jtreg/runtime/cds/appcds/TestCommon.java
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved.
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      *
      * This code is free software; you can redistribute it and/or modify it
    @@ -427,8 +427,6 @@ public class TestCommon extends CDSTestUtils {
                 cmd.add(opts.appJar);
             }
     
    -        CDSTestUtils.addVerifyArchivedFields(cmd);
    -
             for (String s : opts.suffix) cmd.add(s);
     
             if (RUN_WITH_JFR) {
    diff --git a/test/lib/jdk/test/lib/cds/CDSAppTester.java b/test/lib/jdk/test/lib/cds/CDSAppTester.java
    index cfe17a0be14..fd244c6acc6 100644
    --- a/test/lib/jdk/test/lib/cds/CDSAppTester.java
    +++ b/test/lib/jdk/test/lib/cds/CDSAppTester.java
    @@ -402,8 +402,6 @@ abstract public class CDSAppTester {
         public OutputAnalyzer productionRun(String[] extraVmArgs, String[] extraAppArgs) throws Exception {
             RunMode runMode = RunMode.PRODUCTION;
             String[] cmdLine = StringArrayUtils.concat(vmArgs(runMode),
    -                                                   "-XX:+UnlockDiagnosticVMOptions",
    -                                                   "-XX:VerifyArchivedFields=2", // make sure archived heap objects are good.
                                                        logToFile(productionRunLog(), "aot", "cds"));
             cmdLine = addCommonVMArgs(runMode, cmdLine);
     
    diff --git a/test/lib/jdk/test/lib/cds/CDSTestUtils.java b/test/lib/jdk/test/lib/cds/CDSTestUtils.java
    index be6fddc17aa..56e3baa2e25 100644
    --- a/test/lib/jdk/test/lib/cds/CDSTestUtils.java
    +++ b/test/lib/jdk/test/lib/cds/CDSTestUtils.java
    @@ -440,7 +440,6 @@ public class CDSTestUtils {
                     opts.archiveName = getDefaultArchiveName();
                 cmd.add("-XX:SharedArchiveFile=" + opts.archiveName);
             }
    -        addVerifyArchivedFields(cmd);
     
             if (opts.useVersion)
                 cmd.add("-version");
    
    From 0b8ae260282dbb1fa1e8ce9d14f06f353327e03c Mon Sep 17 00:00:00 2001
    From: Fredrik Bredberg 
    Date: Mon, 25 Aug 2025 06:47:57 +0000
    Subject: [PATCH 48/54] 8365189: Remove LockingMode related code from arm32
    
    Reviewed-by: aboldtch, coleenp
    ---
     src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp   |   8 +-
     src/hotspot/cpu/arm/c1_MacroAssembler_arm.cpp |  94 ++-------
     src/hotspot/cpu/arm/c2_MacroAssembler_arm.cpp |  66 +-----
     src/hotspot/cpu/arm/interp_masm_arm.cpp       | 191 +++++-------------
     src/hotspot/cpu/arm/macroAssembler_arm.cpp    |   2 -
     src/hotspot/cpu/arm/sharedRuntime_arm.cpp     |  55 +----
     6 files changed, 74 insertions(+), 342 deletions(-)
    
    diff --git a/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp b/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp
    index 6a859a5875b..c3b91e8c76f 100644
    --- a/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp
    +++ b/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp
    @@ -2426,13 +2426,7 @@ void LIR_Assembler::emit_lock(LIR_OpLock* op) {
       Register hdr = op->hdr_opr()->as_pointer_register();
       Register lock = op->lock_opr()->as_pointer_register();
     
    -  if (LockingMode == LM_MONITOR) {
    -    if (op->info() != nullptr) {
    -      add_debug_info_for_null_check_here(op->info());
    -      __ null_check(obj);
    -    }
    -    __ b(*op->stub()->entry());
    -  } else if (op->code() == lir_lock) {
    +  if (op->code() == lir_lock) {
         assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header");
         int null_check_offset = __ lock_object(hdr, obj, lock, *op->stub()->entry());
         if (op->info() != nullptr) {
    diff --git a/src/hotspot/cpu/arm/c1_MacroAssembler_arm.cpp b/src/hotspot/cpu/arm/c1_MacroAssembler_arm.cpp
    index 195607d5c91..f2b08269750 100644
    --- a/src/hotspot/cpu/arm/c1_MacroAssembler_arm.cpp
    +++ b/src/hotspot/cpu/arm/c1_MacroAssembler_arm.cpp
    @@ -177,18 +177,16 @@ void C1_MacroAssembler::allocate_array(Register obj, Register len,
     }
     
     int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr, Label& slow_case) {
    -  Label done, fast_lock, fast_lock_done;
       int null_check_offset = 0;
     
       const Register tmp2 = Rtemp; // Rtemp should be free at c1 LIR level
       assert_different_registers(hdr, obj, disp_hdr, tmp2);
     
       assert(BasicObjectLock::lock_offset() == 0, "adjust this code");
    -  const ByteSize obj_offset = BasicObjectLock::obj_offset();
    -  const int mark_offset = BasicLock::displaced_header_offset_in_bytes();
    +  assert(oopDesc::mark_offset_in_bytes() == 0, "Required by atomic instructions");
     
       // save object being locked into the BasicObjectLock
    -  str(obj, Address(disp_hdr, obj_offset));
    +  str(obj, Address(disp_hdr, BasicObjectLock::obj_offset()));
     
       null_check_offset = offset();
     
    @@ -199,95 +197,29 @@ int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr
         b(slow_case, ne);
       }
     
    -  assert(oopDesc::mark_offset_in_bytes() == 0, "Required by atomic instructions");
    -
    -  if (LockingMode == LM_LIGHTWEIGHT) {
    -
    -    Register t1 = disp_hdr; // Needs saving, probably
    -    Register t2 = hdr;      // blow
    -    Register t3 = Rtemp;    // blow
    -
    -    lightweight_lock(obj /* obj */, t1, t2, t3, 1 /* savemask - save t1 */, slow_case);
    -    // Success: fall through
    -
    -  } else if (LockingMode == LM_LEGACY) {
    -
    -    // On MP platforms the next load could return a 'stale' value if the memory location has been modified by another thread.
    -    // That would be acceptable as ether CAS or slow case path is taken in that case.
    -
    -    // Must be the first instruction here, because implicit null check relies on it
    -    ldr(hdr, Address(obj, oopDesc::mark_offset_in_bytes()));
    -
    -    tst(hdr, markWord::unlocked_value);
    -    b(fast_lock, ne);
    -
    -    // Check for recursive locking
    -    // See comments in InterpreterMacroAssembler::lock_object for
    -    // explanations on the fast recursive locking check.
    -    // -1- test low 2 bits
    -    movs(tmp2, AsmOperand(hdr, lsl, 30));
    -    // -2- test (hdr - SP) if the low two bits are 0
    -    sub(tmp2, hdr, SP, eq);
    -    movs(tmp2, AsmOperand(tmp2, lsr, exact_log2(os::vm_page_size())), eq);
    -    // If still 'eq' then recursive locking OK
    -    // set to zero if recursive lock, set to non zero otherwise (see discussion in JDK-8267042)
    -    str(tmp2, Address(disp_hdr, mark_offset));
    -    b(fast_lock_done, eq);
    -    // else need slow case
    -    b(slow_case);
    -
    -
    -    bind(fast_lock);
    -    // Save previous object header in BasicLock structure and update the header
    -    str(hdr, Address(disp_hdr, mark_offset));
    -
    -    cas_for_lock_acquire(hdr, disp_hdr, obj, tmp2, slow_case);
    -
    -    bind(fast_lock_done);
    -  }
    -  bind(done);
    +  Register t1 = disp_hdr; // Needs saving, probably
    +  Register t2 = hdr;      // blow
    +  Register t3 = Rtemp;    // blow
     
    +  lightweight_lock(obj, t1, t2, t3, 1 /* savemask - save t1 */, slow_case);
    +  // Success: fall through
       return null_check_offset;
     }
     
     void C1_MacroAssembler::unlock_object(Register hdr, Register obj, Register disp_hdr, Label& slow_case) {
       assert_different_registers(hdr, obj, disp_hdr, Rtemp);
    -  Register tmp2 = Rtemp;
     
       assert(BasicObjectLock::lock_offset() == 0, "adjust this code");
    -  const ByteSize obj_offset = BasicObjectLock::obj_offset();
    -  const int mark_offset = BasicLock::displaced_header_offset_in_bytes();
    -
    -  Label done;
    -
       assert(oopDesc::mark_offset_in_bytes() == 0, "Required by atomic instructions");
     
    -  if (LockingMode == LM_LIGHTWEIGHT) {
    +  ldr(obj, Address(disp_hdr, BasicObjectLock::obj_offset()));
     
    -    ldr(obj, Address(disp_hdr, obj_offset));
    +  Register t1 = disp_hdr; // Needs saving, probably
    +  Register t2 = hdr;      // blow
    +  Register t3 = Rtemp;    // blow
     
    -    Register t1 = disp_hdr; // Needs saving, probably
    -    Register t2 = hdr;      // blow
    -    Register t3 = Rtemp;    // blow
    -
    -    lightweight_unlock(obj /* object */, t1, t2, t3, 1 /* savemask (save t1) */,
    -                       slow_case);
    -    // Success: Fall through
    -
    -  } else if (LockingMode == LM_LEGACY) {
    -
    -    // Load displaced header and object from the lock
    -    ldr(hdr, Address(disp_hdr, mark_offset));
    -    // If hdr is null, we've got recursive locking and there's nothing more to do
    -    cbz(hdr, done);
    -
    -    // load object
    -    ldr(obj, Address(disp_hdr, obj_offset));
    -
    -    // Restore the object header
    -    cas_for_lock_release(disp_hdr, hdr, obj, tmp2, slow_case);
    -  }
    -  bind(done);
    +  lightweight_unlock(obj, t1, t2, t3, 1 /* savemask - save t1 */, slow_case);
    +  // Success: fall through
     }
     
     #ifndef PRODUCT
    diff --git a/src/hotspot/cpu/arm/c2_MacroAssembler_arm.cpp b/src/hotspot/cpu/arm/c2_MacroAssembler_arm.cpp
    index 89be6d288ff..2d26b4f9a50 100644
    --- a/src/hotspot/cpu/arm/c2_MacroAssembler_arm.cpp
    +++ b/src/hotspot/cpu/arm/c2_MacroAssembler_arm.cpp
    @@ -81,7 +81,7 @@ void C2_MacroAssembler::fast_lock(Register Roop, Register Rbox, Register Rscratc
       assert(VM_Version::supports_ldrex(), "unsupported, yet?");
       assert_different_registers(Roop, Rbox, Rscratch, Rscratch2);
     
    -  Label fast_lock, done;
    +  Label done;
     
       if (DiagnoseSyncOnValueBasedClasses != 0) {
         load_klass(Rscratch, Roop);
    @@ -90,43 +90,10 @@ void C2_MacroAssembler::fast_lock(Register Roop, Register Rbox, Register Rscratc
         b(done, ne);
       }
     
    -  if (LockingMode == LM_LIGHTWEIGHT) {
    -
    -    lightweight_lock(Roop /* obj */, Rbox /* t1 */, Rscratch /* t2 */, Rscratch2 /* t3 */,
    -                     1 /* savemask (save t1) */, done);
    -
    -    // Success: set Z
    -    cmp(Roop, Roop);
    -
    -  } else if (LockingMode == LM_LEGACY) {
    -
    -    Register Rmark      = Rscratch2;
    -
    -    ldr(Rmark, Address(Roop, oopDesc::mark_offset_in_bytes()));
    -    tst(Rmark, markWord::unlocked_value);
    -    b(fast_lock, ne);
    -
    -    // Check for recursive lock
    -    // See comments in InterpreterMacroAssembler::lock_object for
    -    // explanations on the fast recursive locking check.
    -    // -1- test low 2 bits
    -    movs(Rscratch, AsmOperand(Rmark, lsl, 30));
    -    // -2- test (hdr - SP) if the low two bits are 0
    -    sub(Rscratch, Rmark, SP, eq);
    -    movs(Rscratch, AsmOperand(Rscratch, lsr, exact_log2(os::vm_page_size())), eq);
    -    // If still 'eq' then recursive locking OK
    -    // set to zero if recursive lock, set to non zero otherwise (see discussion in JDK-8153107)
    -    str(Rscratch, Address(Rbox, BasicLock::displaced_header_offset_in_bytes()));
    -    b(done);
    -
    -    bind(fast_lock);
    -    str(Rmark, Address(Rbox, BasicLock::displaced_header_offset_in_bytes()));
    -
    -    bool allow_fallthrough_on_failure = true;
    -    bool one_shot = true;
    -    cas_for_lock_acquire(Rmark, Rbox, Roop, Rscratch, done, allow_fallthrough_on_failure, one_shot);
    -  }
    +  lightweight_lock(Roop /* obj */, Rbox /* t1 */, Rscratch /* t2 */, Rscratch2 /* t3 */,
    +                   1 /* savemask (save t1) */, done);
     
    +  cmp(Roop, Roop); // Success: set Z
       bind(done);
     
       // At this point flags are set as follows:
    @@ -140,29 +107,12 @@ void C2_MacroAssembler::fast_unlock(Register Roop, Register Rbox, Register Rscra
     
       Label done;
     
    -  if (LockingMode == LM_LIGHTWEIGHT) {
    +  lightweight_unlock(Roop /* obj */, Rbox /* t1 */, Rscratch /* t2 */, Rscratch2 /* t3 */,
    +                     1 /* savemask (save t1) */, done);
     
    -    lightweight_unlock(Roop /* obj */, Rbox /* t1 */, Rscratch /* t2 */, Rscratch2 /* t3 */,
    -                       1 /* savemask (save t1) */, done);
    +  cmp(Roop, Roop); // Success: Set Z
    +  // Fall through
     
    -    cmp(Roop, Roop); // Success: Set Z
    -    // Fall through
    -
    -  } else if (LockingMode == LM_LEGACY) {
    -
    -    Register Rmark      = Rscratch2;
    -
    -    // Find the lock address and load the displaced header from the stack.
    -    ldr(Rmark, Address(Rbox, BasicLock::displaced_header_offset_in_bytes()));
    -    // If hdr is null, we've got recursive locking and there's nothing more to do
    -    cmp(Rmark, 0);
    -    b(done, eq);
    -
    -    // Restore the object header
    -    bool allow_fallthrough_on_failure = true;
    -    bool one_shot = true;
    -    cas_for_lock_release(Rbox, Rmark, Roop, Rscratch, done, allow_fallthrough_on_failure, one_shot);
    -  }
       bind(done);
     
       // At this point flags are set as follows:
    diff --git a/src/hotspot/cpu/arm/interp_masm_arm.cpp b/src/hotspot/cpu/arm/interp_masm_arm.cpp
    index e9e6187a6d1..3f9130309e9 100644
    --- a/src/hotspot/cpu/arm/interp_masm_arm.cpp
    +++ b/src/hotspot/cpu/arm/interp_masm_arm.cpp
    @@ -888,105 +888,30 @@ void InterpreterMacroAssembler::set_do_not_unlock_if_synchronized(bool flag, Reg
     void InterpreterMacroAssembler::lock_object(Register Rlock) {
       assert(Rlock == R1, "the second argument");
     
    -  if (LockingMode == LM_MONITOR) {
    -    call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), Rlock);
    -  } else {
    -    Label done;
    +  const Register Robj = R2;
    +  const Register Rmark = R3;
    +  assert_different_registers(Robj, Rmark, Rlock, R0, Rtemp);
     
    -    const Register Robj = R2;
    -    const Register Rmark = R3;
    -    assert_different_registers(Robj, Rmark, Rlock, R0, Rtemp);
    +  Label done, slow_case;
     
    -    const int obj_offset = in_bytes(BasicObjectLock::obj_offset());
    -    const int lock_offset = in_bytes(BasicObjectLock::lock_offset());
    -    const int mark_offset = lock_offset + BasicLock::displaced_header_offset_in_bytes();
    +  // Load object pointer
    +  ldr(Robj, Address(Rlock, BasicObjectLock::obj_offset()));
     
    -    Label already_locked, slow_case;
    -
    -    // Load object pointer
    -    ldr(Robj, Address(Rlock, obj_offset));
    -
    -    if (DiagnoseSyncOnValueBasedClasses != 0) {
    -      load_klass(R0, Robj);
    -      ldrb(R0, Address(R0, Klass::misc_flags_offset()));
    -      tst(R0, KlassFlags::_misc_is_value_based_class);
    -      b(slow_case, ne);
    -    }
    -
    -    if (LockingMode == LM_LIGHTWEIGHT) {
    -      lightweight_lock(Robj, R0 /* t1 */, Rmark /* t2 */, Rtemp /* t3 */, 0 /* savemask */, slow_case);
    -      b(done);
    -    } else if (LockingMode == LM_LEGACY) {
    -      // On MP platforms the next load could return a 'stale' value if the memory location has been modified by another thread.
    -      // That would be acceptable as ether CAS or slow case path is taken in that case.
    -      // Exception to that is if the object is locked by the calling thread, then the recursive test will pass (guaranteed as
    -      // loads are satisfied from a store queue if performed on the same processor).
    -
    -      assert(oopDesc::mark_offset_in_bytes() == 0, "must be");
    -      ldr(Rmark, Address(Robj, oopDesc::mark_offset_in_bytes()));
    -
    -      // Test if object is already locked
    -      tst(Rmark, markWord::unlocked_value);
    -      b(already_locked, eq);
    -
    -      // Save old object->mark() into BasicLock's displaced header
    -      str(Rmark, Address(Rlock, mark_offset));
    -
    -      cas_for_lock_acquire(Rmark, Rlock, Robj, Rtemp, slow_case);
    -
    -      b(done);
    -
    -      // If we got here that means the object is locked by ether calling thread or another thread.
    -      bind(already_locked);
    -      // Handling of locked objects: recursive locks and slow case.
    -
    -      // Fast check for recursive lock.
    -      //
    -      // Can apply the optimization only if this is a stack lock
    -      // allocated in this thread. For efficiency, we can focus on
    -      // recently allocated stack locks (instead of reading the stack
    -      // base and checking whether 'mark' points inside the current
    -      // thread stack):
    -      //  1) (mark & 3) == 0
    -      //  2) SP <= mark < SP + os::pagesize()
    -      //
    -      // Warning: SP + os::pagesize can overflow the stack base. We must
    -      // neither apply the optimization for an inflated lock allocated
    -      // just above the thread stack (this is why condition 1 matters)
    -      // nor apply the optimization if the stack lock is inside the stack
    -      // of another thread. The latter is avoided even in case of overflow
    -      // because we have guard pages at the end of all stacks. Hence, if
    -      // we go over the stack base and hit the stack of another thread,
    -      // this should not be in a writeable area that could contain a
    -      // stack lock allocated by that thread. As a consequence, a stack
    -      // lock less than page size away from SP is guaranteed to be
    -      // owned by the current thread.
    -      //
    -      // Note: assuming SP is aligned, we can check the low bits of
    -      // (mark-SP) instead of the low bits of mark. In that case,
    -      // assuming page size is a power of 2, we can merge the two
    -      // conditions into a single test:
    -      // => ((mark - SP) & (3 - os::pagesize())) == 0
    -
    -      // (3 - os::pagesize()) cannot be encoded as an ARM immediate operand.
    -      // Check independently the low bits and the distance to SP.
    -      // -1- test low 2 bits
    -      movs(R0, AsmOperand(Rmark, lsl, 30));
    -      // -2- test (mark - SP) if the low two bits are 0
    -      sub(R0, Rmark, SP, eq);
    -      movs(R0, AsmOperand(R0, lsr, exact_log2(os::vm_page_size())), eq);
    -      // If still 'eq' then recursive locking OK: store 0 into lock record
    -      str(R0, Address(Rlock, mark_offset), eq);
    -
    -      b(done, eq);
    -    }
    -
    -    bind(slow_case);
    -
    -    // Call the runtime routine for slow case
    -    call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), Rlock);
    -    bind(done);
    +  if (DiagnoseSyncOnValueBasedClasses != 0) {
    +    load_klass(R0, Robj);
    +    ldrb(R0, Address(R0, Klass::misc_flags_offset()));
    +    tst(R0, KlassFlags::_misc_is_value_based_class);
    +    b(slow_case, ne);
       }
    +
    +  lightweight_lock(Robj, R0 /* t1 */, Rmark /* t2 */, Rtemp /* t3 */, 0 /* savemask */, slow_case);
    +  b(done);
    +
    +  bind(slow_case);
    +
    +  // Call the runtime routine for slow case
    +  call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), Rlock);
    +  bind(done);
     }
     
     // Unlocks an object. Used in monitorexit bytecode and remove_activation.
    @@ -997,65 +922,39 @@ void InterpreterMacroAssembler::lock_object(Register Rlock) {
     void InterpreterMacroAssembler::unlock_object(Register Rlock) {
       assert(Rlock == R0, "the first argument");
     
    -  if (LockingMode == LM_MONITOR) {
    -    call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), Rlock);
    -  } else {
    -    Label done, slow_case;
    +  Label done, slow_case;
     
    -    const Register Robj = R2;
    -    const Register Rmark = R3;
    -    assert_different_registers(Robj, Rmark, Rlock, Rtemp);
    +  const Register Robj = R2;
    +  const Register Rmark = R3;
    +  assert_different_registers(Robj, Rmark, Rlock, Rtemp);
     
    -    const int obj_offset = in_bytes(BasicObjectLock::obj_offset());
    -    const int lock_offset = in_bytes(BasicObjectLock::lock_offset());
    -    const int mark_offset = lock_offset + BasicLock::displaced_header_offset_in_bytes();
    +  const int obj_offset = in_bytes(BasicObjectLock::obj_offset());
    +  const Register Rzero = zero_register(Rtemp);
     
    -    const Register Rzero = zero_register(Rtemp);
    +  // Load oop into Robj
    +  ldr(Robj, Address(Rlock, obj_offset));
     
    -    // Load oop into Robj
    -    ldr(Robj, Address(Rlock, obj_offset));
    +  // Free entry
    +  str(Rzero, Address(Rlock, obj_offset));
     
    -    // Free entry
    -    str(Rzero, Address(Rlock, obj_offset));
    +  // Check for non-symmetric locking. This is allowed by the spec and the interpreter
    +  // must handle it.
    +  ldr(Rtemp, Address(Rthread, JavaThread::lock_stack_top_offset()));
    +  sub(Rtemp, Rtemp, oopSize);
    +  ldr(Rtemp, Address(Rthread, Rtemp));
    +  cmpoop(Rtemp, Robj);
    +  b(slow_case, ne);
     
    -    if (LockingMode == LM_LIGHTWEIGHT) {
    +  lightweight_unlock(Robj /* obj */, Rlock /* t1 */, Rmark /* t2 */, Rtemp /* t3 */,
    +                     1 /* savemask (save t1) */, slow_case);
    +  b(done);
     
    -      // Check for non-symmetric locking. This is allowed by the spec and the interpreter
    -      // must handle it.
    -      ldr(Rtemp, Address(Rthread, JavaThread::lock_stack_top_offset()));
    -      sub(Rtemp, Rtemp, oopSize);
    -      ldr(Rtemp, Address(Rthread, Rtemp));
    -      cmpoop(Rtemp, Robj);
    -      b(slow_case, ne);
    +  bind(slow_case);
    +  // Call the runtime routine for slow case.
    +  str(Robj, Address(Rlock, obj_offset)); // restore obj
    +  call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), Rlock);
     
    -      lightweight_unlock(Robj /* obj */, Rlock /* t1 */, Rmark /* t2 */, Rtemp /* t3 */,
    -                         1 /* savemask (save t1) */, slow_case);
    -
    -      b(done);
    -
    -    } else if (LockingMode == LM_LEGACY) {
    -
    -      // Load the old header from BasicLock structure
    -      ldr(Rmark, Address(Rlock, mark_offset));
    -
    -      // Test for recursion (zero mark in BasicLock)
    -      cbz(Rmark, done);
    -
    -      bool allow_fallthrough_on_failure = true;
    -
    -      cas_for_lock_release(Rlock, Rmark, Robj, Rtemp, slow_case, allow_fallthrough_on_failure);
    -
    -      b(done, eq);
    -
    -    }
    -    bind(slow_case);
    -
    -    // Call the runtime routine for slow case.
    -    str(Robj, Address(Rlock, obj_offset)); // restore obj
    -    call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), Rlock);
    -
    -    bind(done);
    -  }
    +  bind(done);
     }
     
     // Test ImethodDataPtr.  If it is null, continue at the specified label
    diff --git a/src/hotspot/cpu/arm/macroAssembler_arm.cpp b/src/hotspot/cpu/arm/macroAssembler_arm.cpp
    index 3dcde7d898d..e101e5631d9 100644
    --- a/src/hotspot/cpu/arm/macroAssembler_arm.cpp
    +++ b/src/hotspot/cpu/arm/macroAssembler_arm.cpp
    @@ -1758,7 +1758,6 @@ void MacroAssembler::read_polling_page(Register dest, relocInfo::relocType rtype
     //  - Success: fallthrough
     //  - Error:   break to slow, Z cleared.
     void MacroAssembler::lightweight_lock(Register obj, Register t1, Register t2, Register t3, unsigned savemask, Label& slow) {
    -  assert(LockingMode == LM_LIGHTWEIGHT, "only used with new lightweight locking");
       assert_different_registers(obj, t1, t2, t3);
     
     #ifdef ASSERT
    @@ -1816,7 +1815,6 @@ void MacroAssembler::lightweight_lock(Register obj, Register t1, Register t2, Re
     //  - Success: fallthrough
     //  - Error:   break to slow, Z cleared.
     void MacroAssembler::lightweight_unlock(Register obj, Register t1, Register t2, Register t3, unsigned savemask, Label& slow) {
    -  assert(LockingMode == LM_LIGHTWEIGHT, "only used with new lightweight locking");
       assert_different_registers(obj, t1, t2, t3);
     
     #ifdef ASSERT
    diff --git a/src/hotspot/cpu/arm/sharedRuntime_arm.cpp b/src/hotspot/cpu/arm/sharedRuntime_arm.cpp
    index 9519c923e22..dcf631525ab 100644
    --- a/src/hotspot/cpu/arm/sharedRuntime_arm.cpp
    +++ b/src/hotspot/cpu/arm/sharedRuntime_arm.cpp
    @@ -1139,41 +1139,10 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
         // Remember the handle for the unlocking code
         __ mov(sync_handle, R1);
     
    -    if (LockingMode == LM_LIGHTWEIGHT) {
    -      log_trace(fastlock)("SharedRuntime lock fast");
    -      __ lightweight_lock(sync_obj /* object */, disp_hdr /* t1 */, tmp /* t2 */, Rtemp /* t3 */,
    -                          0x7 /* savemask */, slow_lock);
    +    log_trace(fastlock)("SharedRuntime lock fast");
    +    __ lightweight_lock(sync_obj /* object */, disp_hdr /* t1 */, tmp /* t2 */, Rtemp /* t3 */,
    +                        0x7 /* savemask */, slow_lock);
           // Fall through to lock_done
    -    } else if (LockingMode == LM_LEGACY) {
    -      const Register mark = tmp;
    -      // On MP platforms the next load could return a 'stale' value if the memory location has been modified by another thread.
    -      // That would be acceptable as either CAS or slow case path is taken in that case
    -
    -      __ ldr(mark, Address(sync_obj, oopDesc::mark_offset_in_bytes()));
    -      __ sub(disp_hdr, FP, lock_slot_fp_offset);
    -      __ tst(mark, markWord::unlocked_value);
    -      __ b(fast_lock, ne);
    -
    -      // Check for recursive lock
    -      // See comments in InterpreterMacroAssembler::lock_object for
    -      // explanations on the fast recursive locking check.
    -      // Check independently the low bits and the distance to SP
    -      // -1- test low 2 bits
    -      __ movs(Rtemp, AsmOperand(mark, lsl, 30));
    -      // -2- test (hdr - SP) if the low two bits are 0
    -      __ sub(Rtemp, mark, SP, eq);
    -      __ movs(Rtemp, AsmOperand(Rtemp, lsr, exact_log2(os::vm_page_size())), eq);
    -      // If still 'eq' then recursive locking OK
    -      // set to zero if recursive lock, set to non zero otherwise (see discussion in JDK-8267042)
    -      __ str(Rtemp, Address(disp_hdr, BasicLock::displaced_header_offset_in_bytes()));
    -      __ b(lock_done, eq);
    -      __ b(slow_lock);
    -
    -      __ bind(fast_lock);
    -      __ str(mark, Address(disp_hdr, BasicLock::displaced_header_offset_in_bytes()));
    -
    -      __ cas_for_lock_acquire(mark, disp_hdr, sync_obj, Rtemp, slow_lock);
    -    }
         __ bind(lock_done);
       }
     
    @@ -1226,21 +1195,11 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
     
       Label slow_unlock, unlock_done;
       if (method->is_synchronized()) {
    -    if (LockingMode == LM_LIGHTWEIGHT) {
    -      log_trace(fastlock)("SharedRuntime unlock fast");
    -      __ lightweight_unlock(sync_obj, R2 /* t1 */, tmp /* t2 */, Rtemp /* t3 */,
    -                            7 /* savemask */, slow_unlock);
    -      // Fall through
    -    } else if (LockingMode == LM_LEGACY) {
    -      // See C1_MacroAssembler::unlock_object() for more comments
    -      __ ldr(sync_obj, Address(sync_handle));
    +    log_trace(fastlock)("SharedRuntime unlock fast");
    +    __ lightweight_unlock(sync_obj, R2 /* t1 */, tmp /* t2 */, Rtemp /* t3 */,
    +                          7 /* savemask */, slow_unlock);
    +    // Fall through
     
    -      // See C1_MacroAssembler::unlock_object() for more comments
    -      __ ldr(R2, Address(disp_hdr, BasicLock::displaced_header_offset_in_bytes()));
    -      __ cbz(R2, unlock_done);
    -
    -      __ cas_for_lock_release(disp_hdr, R2, sync_obj, Rtemp, slow_unlock);
    -    }
         __ bind(unlock_done);
       }
     
    
    From 1f0dfdbccac4d23c00cab5663324c965141e1b23 Mon Sep 17 00:00:00 2001
    From: Marc Chevalier 
    Date: Mon, 25 Aug 2025 06:51:28 +0000
    Subject: [PATCH 49/54] 8360561: PhaseIdealLoop::create_new_if_for_predicate
     hits "must be a uct if pattern" assert
    
    Reviewed-by: mhaessig, thartmann, qamai
    ---
     src/hotspot/share/opto/subnode.cpp            | 26 +++++++
     .../igvn/CmpDisjointButNonOrderedRanges.java  | 73 +++++++++++++++++++
     .../igvn/CmpDisjointButNonOrderedRanges2.java | 68 +++++++++++++++++
     .../CmpDisjointButNonOrderedRangesLong.java   | 61 ++++++++++++++++
     4 files changed, 228 insertions(+)
     create mode 100644 test/hotspot/jtreg/compiler/igvn/CmpDisjointButNonOrderedRanges.java
     create mode 100644 test/hotspot/jtreg/compiler/igvn/CmpDisjointButNonOrderedRanges2.java
     create mode 100644 test/hotspot/jtreg/compiler/igvn/CmpDisjointButNonOrderedRangesLong.java
    
    diff --git a/src/hotspot/share/opto/subnode.cpp b/src/hotspot/share/opto/subnode.cpp
    index 5f1af09463f..9c6c7498dd0 100644
    --- a/src/hotspot/share/opto/subnode.cpp
    +++ b/src/hotspot/share/opto/subnode.cpp
    @@ -694,6 +694,11 @@ const Type *CmpINode::sub( const Type *t1, const Type *t2 ) const {
         return TypeInt::CC_LE;
       else if( r0->_lo == r1->_hi ) // Range is never low?
         return TypeInt::CC_GE;
    +
    +  const Type* joined = r0->join(r1);
    +  if (joined == Type::TOP) {
    +    return TypeInt::CC_NE;
    +  }
       return TypeInt::CC;           // else use worst case results
     }
     
    @@ -798,6 +803,12 @@ const Type *CmpUNode::sub( const Type *t1, const Type *t2 ) const {
       // looks at the structure of the node in any other case.)
       if ((jint)lo0 >= 0 && (jint)lo1 >= 0 && is_index_range_check())
         return TypeInt::CC_LT;
    +
    +  const Type* joined = r0->join(r1);
    +  if (joined == Type::TOP) {
    +    return TypeInt::CC_NE;
    +  }
    +
       return TypeInt::CC;                   // else use worst case results
     }
     
    @@ -939,6 +950,12 @@ const Type *CmpLNode::sub( const Type *t1, const Type *t2 ) const {
         return TypeInt::CC_LE;
       else if( r0->_lo == r1->_hi ) // Range is never low?
         return TypeInt::CC_GE;
    +
    +  const Type* joined = r0->join(r1);
    +  if (joined == Type::TOP) {
    +    return TypeInt::CC_NE;
    +  }
    +
       return TypeInt::CC;           // else use worst case results
     }
     
    @@ -993,6 +1010,11 @@ const Type* CmpULNode::sub(const Type* t1, const Type* t2) const {
         }
       }
     
    +  const Type* joined = r0->join(r1);
    +  if (joined == Type::TOP) {
    +    return TypeInt::CC_NE;
    +  }
    +
       return TypeInt::CC;                   // else use worst case results
     }
     
    @@ -1368,6 +1390,10 @@ const Type *BoolTest::cc2logical( const Type *CC ) const {
         if( _test == le ) return TypeInt::ONE;
         if( _test == gt ) return TypeInt::ZERO;
       }
    +  if( CC == TypeInt::CC_NE ) {
    +    if( _test == ne ) return TypeInt::ONE;
    +    if( _test == eq ) return TypeInt::ZERO;
    +  }
     
       return TypeInt::BOOL;
     }
    diff --git a/test/hotspot/jtreg/compiler/igvn/CmpDisjointButNonOrderedRanges.java b/test/hotspot/jtreg/compiler/igvn/CmpDisjointButNonOrderedRanges.java
    new file mode 100644
    index 00000000000..a8f75b9c8f4
    --- /dev/null
    +++ b/test/hotspot/jtreg/compiler/igvn/CmpDisjointButNonOrderedRanges.java
    @@ -0,0 +1,73 @@
    +/*
    + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
    + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    + *
    + * This code is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License version 2 only, as
    + * published by the Free Software Foundation.
    + *
    + * This code is distributed in the hope that it will be useful, but WITHOUT
    + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    + * version 2 for more details (a copy is included in the LICENSE file that
    + * accompanied this code).
    + *
    + * You should have received a copy of the GNU General Public License version
    + * 2 along with this work; if not, write to the Free Software Foundation,
    + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    + *
    + * Please 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 8360561
    + * @summary Ranges can be proven to be disjoint but not orderable (thanks to unsigned range)
    + *          Comparing such values in such range with != should always be true.
    + * @run main/othervm -Xcomp
    + *                   -XX:CompileCommand=compileonly,compiler.igvn.CmpDisjointButNonOrderedRanges::*
    + *                   compiler.igvn.CmpDisjointButNonOrderedRanges
    + * @run main compiler.igvn.CmpDisjointButNonOrderedRanges
    + */
    +package compiler.igvn;
    +
    +public class CmpDisjointButNonOrderedRanges {
    +    static boolean bFld;
    +
    +    public static void main(String[] strArr) {
    +        test();
    +    }
    +
    +    static void test() {
    +        int x = 7;
    +        int y = 4;
    +        for (int i = 3; i < 12; i++) {
    +            // x = 7 \/ x = -195 => x \in [-195, 7] as a signed value
    +            // but [7, bitwise_cast_uint(-195)] as unsigned
    +            // So 0 is not possible.
    +            if (x != 0) {
    +                A.foo();
    +                // Because A is not loaded, A.foo() traps and this point is not reachable.
    +            }
    +            // x is tighten to be in the meet (so Hotspot's join) of [0, 0] and [7, bitwise_cast_uint(-195)]
    +            // that is bottom (Hotspot's top). Data is dead, control needs to be dead as well.
    +            for (int j = 1; j < 8; j++) {
    +                x = -195;
    +                if (bFld) {
    +                    y += 2;
    +                }
    +            }
    +        }
    +    }
    +
    +    static void foo() {
    +    }
    +}
    +
    +
    +class A {
    +    static void foo() {
    +    }
    +}
    diff --git a/test/hotspot/jtreg/compiler/igvn/CmpDisjointButNonOrderedRanges2.java b/test/hotspot/jtreg/compiler/igvn/CmpDisjointButNonOrderedRanges2.java
    new file mode 100644
    index 00000000000..205a7f7d380
    --- /dev/null
    +++ b/test/hotspot/jtreg/compiler/igvn/CmpDisjointButNonOrderedRanges2.java
    @@ -0,0 +1,68 @@
    +/*
    + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
    + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    + *
    + * This code is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License version 2 only, as
    + * published by the Free Software Foundation.
    + *
    + * This code is distributed in the hope that it will be useful, but WITHOUT
    + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    + * version 2 for more details (a copy is included in the LICENSE file that
    + * accompanied this code).
    + *
    + * You should have received a copy of the GNU General Public License version
    + * 2 along with this work; if not, write to the Free Software Foundation,
    + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    + *
    + * Please 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 8360561
    + * @summary Ranges can be proven to be disjoint but not orderable (thanks to unsigned range)
    + *          Comparing such values in such range with != should always be true.
    + * @run main/othervm -Xbatch
    + *                   -XX:CompileCommand=compileonly,compiler.igvn.CmpDisjointButNonOrderedRanges2::*
    + *                   -XX:-TieredCompilation
    + *                   -XX:+UnlockExperimentalVMOptions
    + *                   -XX:PerMethodTrapLimit=0
    + *                   compiler.igvn.CmpDisjointButNonOrderedRanges2
    + * @run main compiler.igvn.CmpDisjointButNonOrderedRanges2
    + */
    +package compiler.igvn;
    +
    +public class CmpDisjointButNonOrderedRanges2 {
    +    int array[];
    +
    +    void test() {
    +        int val = 2;
    +        for (int i = 0; i < 10; i++) {
    +            // val = 2 \/ val = -12 => val \in [-12, 2] as a signed value
    +            // but [2, bitwise_cast_uint(-12)] as unsigned
    +            // So 0 is not possible.
    +            if (val != 0) {
    +                return;
    +            }
    +            // val is tighten to be in the meet (so Hotspot's join) of [0, 0] and [2, bitwise_cast_uint(-12)]
    +            // that is bottom (Hotspot's top). Data is dead, control needs to be dead as well.
    +            for (int j = 0; j < 10; j++) {
    +                array[1] = val;
    +                val = -12;
    +            }
    +        }
    +    }
    +
    +    static public void main(String[] args) {
    +        var c = new CmpDisjointButNonOrderedRanges2();
    +        for (int i = 0; i < 1000; ++i) {
    +            c.test();
    +            for (int j = 0; j < 100; ++j) {
    +            }
    +        }
    +    }
    +}
    diff --git a/test/hotspot/jtreg/compiler/igvn/CmpDisjointButNonOrderedRangesLong.java b/test/hotspot/jtreg/compiler/igvn/CmpDisjointButNonOrderedRangesLong.java
    new file mode 100644
    index 00000000000..c5ef1640721
    --- /dev/null
    +++ b/test/hotspot/jtreg/compiler/igvn/CmpDisjointButNonOrderedRangesLong.java
    @@ -0,0 +1,61 @@
    +/*
    + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
    + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    + *
    + * This code is free software; you can redistribute it and/or modify it
    + * under the terms of the GNU General Public License version 2 only, as
    + * published by the Free Software Foundation.
    + *
    + * This code is distributed in the hope that it will be useful, but WITHOUT
    + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    + * version 2 for more details (a copy is included in the LICENSE file that
    + * accompanied this code).
    + *
    + * You should have received a copy of the GNU General Public License version
    + * 2 along with this work; if not, write to the Free Software Foundation,
    + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    + *
    + * Please 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 8360561
    + * @summary Ranges can be proven to be disjoint but not orderable (thanks to unsigned range)
    + *          Comparing such values in such range with != should always be true.
    + * @library /test/lib /
    + * @run main compiler.igvn.CmpDisjointButNonOrderedRangesLong
    + */
    +package compiler.igvn;
    +
    +import compiler.lib.ir_framework.*;
    +
    +public class CmpDisjointButNonOrderedRangesLong {
    +    static boolean bFld;
    +    static double dFld1;
    +    static double dFld2;
    +
    +    public static void main(String[] strArr) {
    +        TestFramework.run();
    +    }
    +
    +    @Test
    +    @IR(failOn = {IRNode.PHI})
    +    @Warmup(0)
    +    static int test() {
    +        long x = 7;
    +        if (bFld) {
    +            x = -195;
    +        }
    +
    +        dFld1 = dFld2 % 2.5;
    +
    +        if (x == 0) {
    +            return 0;
    +        }
    +        return 1;
    +    }
    +}
    
    From d99fb09a20df2639af23d1083afd14247abb991e Mon Sep 17 00:00:00 2001
    From: Jan Lahoda 
    Date: Mon, 25 Aug 2025 07:15:44 +0000
    Subject: [PATCH 50/54] 8359497: IllegalArgumentException thrown by
     SourceCodeAnalysisImpl.highlights()
    
    Reviewed-by: vromero
    ---
     .../share/classes/jdk/jshell/SourceCodeAnalysisImpl.java  | 7 ++++++-
     test/langtools/jdk/jshell/SnippetHighlightTest.java       | 8 +++++++-
     2 files changed, 13 insertions(+), 2 deletions(-)
    
    diff --git a/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java b/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java
    index 4ee629476db..cb4861651e3 100644
    --- a/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java
    +++ b/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java
    @@ -66,6 +66,7 @@ import com.sun.tools.javac.parser.Tokens.Token;
     import com.sun.tools.javac.parser.Tokens.TokenKind;
     import com.sun.tools.javac.tree.JCTree;
     import com.sun.tools.javac.util.Context;
    +import com.sun.tools.javac.util.Log;
     import jdk.internal.shellsupport.doc.JavadocHelper;
     import com.sun.tools.javac.util.Name;
     import com.sun.tools.javac.util.Names;
    @@ -139,6 +140,7 @@ import javax.lang.model.type.ExecutableType;
     import javax.lang.model.type.TypeKind;
     import javax.lang.model.util.ElementFilter;
     import javax.lang.model.util.Types;
    +import javax.tools.DiagnosticListener;
     import javax.tools.JavaFileManager.Location;
     import javax.tools.StandardLocation;
     
    @@ -654,7 +656,10 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis {
                 Trees trees = task.trees();
                 SourcePositions sp = trees.getSourcePositions();
                 List tokens = new ArrayList<>();
    -            Scanner scanner = ScannerFactory.instance(new Context()).newScanner(wrappedCode, false);
    +            Context ctx = new Context();
    +            ctx.put(DiagnosticListener.class, (DiagnosticListener) d -> {});
    +            Scanner scanner = ScannerFactory.instance(ctx).newScanner(wrappedCode, false);
    +            Log.instance(ctx).useSource(cut.getSourceFile());
                 scanner.nextToken();
                 BiConsumer addKeywordForSpan = (spanStart, spanEnd) -> {
                     int start = codeWrap.wrapIndexToSnippetIndex(spanStart);
    diff --git a/test/langtools/jdk/jshell/SnippetHighlightTest.java b/test/langtools/jdk/jshell/SnippetHighlightTest.java
    index 9c59a3d8016..902d4347f74 100644
    --- a/test/langtools/jdk/jshell/SnippetHighlightTest.java
    +++ b/test/langtools/jdk/jshell/SnippetHighlightTest.java
    @@ -23,7 +23,7 @@
     
     /*
      * @test
    - * @bug 8274148 8301580
    + * @bug 8274148 8301580 8359497
      * @summary Check snippet highlighting
      * @library /tools/lib
      * @modules jdk.compiler/com.sun.tools.javac.api
    @@ -114,6 +114,12 @@ public class SnippetHighlightTest extends KullaTesting {
                              "Highlight[start=32, end=38, attributes=[KEYWORD]]");
         }
     
    +    public void testNoCrashOnLexicalErrors() { //JDK-8359497
    +        assertHighlights("""
    +                         "
    +                         """);
    +    }
    +
         private void assertHighlights(String code, String... expected) {
             List completions = computeHighlights(code);
             assertEquals(completions, Arrays.asList(expected), "Input: " + code + ", " + completions.toString());
    
    From 7fa501e39874214c9bc7503c0bdb68d090245208 Mon Sep 17 00:00:00 2001
    From: Thomas Schatzl 
    Date: Mon, 25 Aug 2025 07:42:55 +0000
    Subject: [PATCH 51/54] 8365040: G1: Remove sorting at end of collection set
     selection
    
    Reviewed-by: iwalulya, ayang
    ---
     src/hotspot/share/gc/g1/g1CollectionSet.cpp | 6 ------
     1 file changed, 6 deletions(-)
    
    diff --git a/src/hotspot/share/gc/g1/g1CollectionSet.cpp b/src/hotspot/share/gc/g1/g1CollectionSet.cpp
    index 6fbbeb41a82..950ffcbc426 100644
    --- a/src/hotspot/share/gc/g1/g1CollectionSet.cpp
    +++ b/src/hotspot/share/gc/g1/g1CollectionSet.cpp
    @@ -36,7 +36,6 @@
     #include "runtime/orderAccess.hpp"
     #include "utilities/debug.hpp"
     #include "utilities/globalDefinitions.hpp"
    -#include "utilities/quickSort.hpp"
     
     uint G1CollectionSet::groups_cur_length() const {
       assert(_inc_build_state == CSetBuildType::Inactive, "must be");
    @@ -344,10 +343,6 @@ double G1CollectionSet::finalize_young_part(double target_pause_time_ms, G1Survi
       return remaining_time_ms;
     }
     
    -static int compare_region_idx(const uint a, const uint b) {
    -  return static_cast(a-b);
    -}
    -
     // The current mechanism for evacuating pinned old regions is as below:
     // * pinned regions in the marking collection set candidate list (available during mixed gc) are evacuated like
     //   pinned young regions to avoid the complexity of dealing with pinned regions that are part of a
    @@ -688,7 +683,6 @@ void G1CollectionSet::finalize_initial_collection_set(double target_pause_time_m
       finalize_old_part(time_remaining_ms);
     
       stop_incremental_building();
    -  QuickSort::sort(_regions, _regions_cur_length, compare_region_idx);
     }
     
     bool G1CollectionSet::finalize_optional_for_evacuation(double remaining_pause_time) {
    
    From 28bd29f3963938f3846e68f33ac3648b2ba101f4 Mon Sep 17 00:00:00 2001
    From: Thomas Schatzl 
    Date: Mon, 25 Aug 2025 07:43:12 +0000
    Subject: [PATCH 52/54] 8365034: G1: Remove num_groups_selected in
     G1CollectionSet::select_candidates_from_optional_groups as it is unnecessary
    
    Reviewed-by: ayang, iwalulya
    ---
     src/hotspot/share/gc/g1/g1CollectionSet.cpp | 6 ++----
     1 file changed, 2 insertions(+), 4 deletions(-)
    
    diff --git a/src/hotspot/share/gc/g1/g1CollectionSet.cpp b/src/hotspot/share/gc/g1/g1CollectionSet.cpp
    index 950ffcbc426..e6177af7f68 100644
    --- a/src/hotspot/share/gc/g1/g1CollectionSet.cpp
    +++ b/src/hotspot/share/gc/g1/g1CollectionSet.cpp
    @@ -599,7 +599,6 @@ double G1CollectionSet::select_candidates_from_optional_groups(double time_remai
       assert(_optional_groups.num_regions() > 0,
              "Should only be called when there are optional regions");
     
    -  uint num_groups_selected = 0;
       double total_prediction_ms = 0.0;
       G1CSetCandidateGroupList selected;
       for (G1CSetCandidateGroup* group : _optional_groups) {
    @@ -615,16 +614,15 @@ double G1CollectionSet::select_candidates_from_optional_groups(double time_remai
         time_remaining_ms -= predicted_time_ms;
     
         num_regions_selected += group->length();
    -    num_groups_selected++;
     
         add_group_to_collection_set(group);
         selected.append(group);
       }
     
       log_debug(gc, ergo, cset)("Completed with groups, selected %u region in %u groups",
    -                            num_regions_selected, num_groups_selected);
    +                            num_regions_selected, selected.length());
       // Remove selected groups from candidate list.
    -  if (num_groups_selected > 0) {
    +  if (selected.length() > 0) {
         _optional_groups.remove(&selected);
         candidates()->remove(&selected);
       }
    
    From 57434c73eac9bd6557b09d4a057e3a2a18f382b4 Mon Sep 17 00:00:00 2001
    From: Thomas Schatzl 
    Date: Mon, 25 Aug 2025 07:44:20 +0000
    Subject: [PATCH 53/54] 8365976: G1: Full gc should mark nmethods on stack
    
    Reviewed-by: ayang, iwalulya
    ---
     src/hotspot/share/gc/g1/g1CollectedHeap.cpp | 1 +
     src/hotspot/share/gc/g1/g1FullCollector.cpp | 2 --
     2 files changed, 1 insertion(+), 2 deletions(-)
    
    diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp
    index bf512cfa19d..65d863f43ee 100644
    --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp
    +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp
    @@ -800,6 +800,7 @@ void G1CollectedHeap::prepare_for_mutator_after_full_collection(size_t allocatio
     
       // Rebuild the code root lists for each region
       rebuild_code_roots();
    +  finish_codecache_marking_cycle();
     
       start_new_collection_set();
       _allocator->init_mutator_alloc_regions();
    diff --git a/src/hotspot/share/gc/g1/g1FullCollector.cpp b/src/hotspot/share/gc/g1/g1FullCollector.cpp
    index 579413768d1..70cded3220a 100644
    --- a/src/hotspot/share/gc/g1/g1FullCollector.cpp
    +++ b/src/hotspot/share/gc/g1/g1FullCollector.cpp
    @@ -224,8 +224,6 @@ void G1FullCollector::collect() {
       }
     
       phase5_reset_metadata();
    -
    -  G1CollectedHeap::finish_codecache_marking_cycle();
     }
     
     void G1FullCollector::complete_collection(size_t allocation_word_size) {
    
    From 5cc86738411c36378b89d8f4932a54b3089cf22e Mon Sep 17 00:00:00 2001
    From: =?UTF-8?q?Paul=20H=C3=BCbner?= 
    Date: Mon, 25 Aug 2025 09:13:35 +0000
    Subject: [PATCH 54/54] 8365765: thread.inline.hpp includes the wrong primary
     header file
    
    Reviewed-by: stefank, ayang, jwaters
    ---
     src/hotspot/share/runtime/thread.inline.hpp | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/src/hotspot/share/runtime/thread.inline.hpp b/src/hotspot/share/runtime/thread.inline.hpp
    index 756a4702159..98148d485d8 100644
    --- a/src/hotspot/share/runtime/thread.inline.hpp
    +++ b/src/hotspot/share/runtime/thread.inline.hpp
    @@ -26,7 +26,7 @@
     #ifndef SHARE_RUNTIME_THREAD_INLINE_HPP
     #define SHARE_RUNTIME_THREAD_INLINE_HPP
     
    -#include "runtime/javaThread.hpp"
    +#include "runtime/thread.hpp"
     
     #include "gc/shared/tlab_globals.hpp"
     #include "runtime/atomic.hpp"