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 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/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/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/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/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); } 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/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/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/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; 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/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/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: 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/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"); // 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/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/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/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(); 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/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; diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index e964ecefb18..65d863f43ee 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" @@ -799,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(); @@ -1487,6 +1489,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); @@ -3077,6 +3081,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) { @@ -3157,5 +3163,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 075951ab07c..e6177af7f68 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSet.cpp +++ b/src/hotspot/share/gc/g1/g1CollectionSet.cpp @@ -36,7 +36,15 @@ #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"); + return _groups.length(); +} + +uint G1CollectionSet::groups_increment_length() const { + return groups_cur_length() - _groups_inc_part_start; +} G1CollectorState* G1CollectionSet::collector_state() const { return _g1h->collector_state(); @@ -50,22 +58,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_cur_length(0), - _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) { + DEBUG_ONLY(_inc_build_state(CSetBuildType::Inactive) COMMA) + _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(); } @@ -76,8 +83,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"); @@ -85,9 +92,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); } @@ -97,14 +104,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"); @@ -113,37 +120,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(_inc_build_state == Inactive, "Precondition"); + 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."); - update_incremental_marker(); + continue_incremental_building(); } -void G1CollectionSet::finalize_incremental_building() { - assert(_inc_build_state == Active, "Precondition"); - assert(SafepointSynchronize::is_at_safepoint(), "should be at a safepoint"); +void G1CollectionSet::continue_incremental_building() { + assert(_inc_build_state == CSetBuildType::Inactive, "Precondition"); + + _regions_inc_part_start = _regions_cur_length; + _groups_inc_part_start = groups_cur_length(); + + DEBUG_ONLY(_inc_build_state = CSetBuildType::Active;) +} + +void G1CollectionSet::stop_incremental_building() { + DEBUG_ONLY(_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(); @@ -170,7 +186,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, @@ -180,29 +196,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) { @@ -284,9 +300,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 == CSetBuildType::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); @@ -326,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 @@ -343,9 +356,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 +373,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) { @@ -594,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) { @@ -610,22 +614,22 @@ 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", num_regions_selected); + log_debug(gc, ergo, cset)("Completed with groups, selected %u region in %u groups", + 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); } 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"); @@ -660,7 +664,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) { @@ -670,16 +674,20 @@ void G1CollectionSet::add_region_to_collection_set(G1HeapRegion* r) { } void G1CollectionSet::finalize_initial_collection_set(double target_pause_time_ms, G1SurvivorRegions* survivor) { + 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(); } 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); + uint num_regions_selected = select_optional_groups(remaining_pause_time); - _selected_groups_cur_length = collection_set_groups()->length(); stop_incremental_building(); _g1h->verify_region_attr_remset_is_tracked(); @@ -741,7 +749,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 c703e13a056..7038cd4e677 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,48 +138,54 @@ 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; - // 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_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 { +#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; - size_t _inc_part_start; +#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. + 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); @@ -191,18 +198,15 @@ 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); - // 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. @@ -223,27 +227,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; } @@ -258,28 +264,24 @@ 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. 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 { return _selected_groups_cur_length - _selected_groups_inc_part_start; } + 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, @@ -287,10 +289,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/g1CollectionSetCandidates.cpp b/src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp index 6c13c015eff..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); } @@ -63,10 +58,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) { @@ -134,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) { @@ -280,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; } @@ -295,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; @@ -304,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; @@ -319,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 73421d40ee9..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(); } @@ -102,7 +99,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. @@ -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(); } diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp index c5b8c89e2f0..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; } @@ -2981,6 +2982,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 +3116,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(); 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) { 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; 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() { 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/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"); } } 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; 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) { 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/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); 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/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/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/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/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); 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/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)); 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 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), 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/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" 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 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/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/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()) { 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))) { 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);
     }
 
     /**
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/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/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;
         }
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;
 
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/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/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; 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( 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/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/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/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(); 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; + } +} 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()); 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/hotspot/jtreg/sources/TestIncludesAreSorted.java b/test/hotspot/jtreg/sources/TestIncludesAreSorted.java index 7460a160ee6..1a304a44944 100644 --- a/test/hotspot/jtreg/sources/TestIncludesAreSorted.java +++ b/test/hotspot/jtreg/sources/TestIncludesAreSorted.java @@ -51,8 +51,10 @@ public class TestIncludesAreSorted { "share/code", "share/compiler", "share/interpreter", + "share/jfr", "share/jvmci", "share/libadt", + "share/logging", "share/metaprogramming", "share/oops", "share/opto", 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"}) 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/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(); } 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 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); + } } 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 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; + } + } +} 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!"); } } 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); - } - } -} 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) { 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()); 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" + ) + ); + } } 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 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");