diff --git a/make/ToolsJdk.gmk b/make/ToolsJdk.gmk index 629cadbf83a..ae0dd069c80 100644 --- a/make/ToolsJdk.gmk +++ b/make/ToolsJdk.gmk @@ -63,7 +63,7 @@ TOOL_GENERATECURRENCYDATA = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_ TOOL_TZDB = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ build.tools.tzdb.TzdbZoneRulesCompiler -TOOL_BLOCKED_CERTS = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ +TOOL_BLOCKED_CERTS = $(JAVA_SMALL) -Xlog:disable -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ --add-exports java.base/sun.security.util=ALL-UNNAMED \ build.tools.blockedcertsconverter.BlockedCertsConverter diff --git a/make/autoconf/flags-ldflags.m4 b/make/autoconf/flags-ldflags.m4 index 651be3a1913..66f8904db89 100644 --- a/make/autoconf/flags-ldflags.m4 +++ b/make/autoconf/flags-ldflags.m4 @@ -79,7 +79,7 @@ AC_DEFUN([FLAGS_SETUP_LDFLAGS_HELPER], fi if test "x$OPENJDK_TARGET_OS" = xaix; then BASIC_LDFLAGS="-Wl,-b64 -Wl,-brtl -Wl,-bnorwexec -Wl,-blibpath:/usr/lib:lib -Wl,-bnoexpall \ - -Wl,-bernotok -Wl,-bdatapsize:64k -Wl,-btextpsize:64k -Wl,-bstackpsize:64k" + -Wl,-bernotok -Wl,-bcdtors:mbr::s -Wl,-bdatapsize:64k -Wl,-btextpsize:64k -Wl,-bstackpsize:64k" BASIC_LDFLAGS_JVM_ONLY="$BASIC_LDFLAGS_JVM_ONLY -Wl,-lC_r -Wl,-bbigtoc" fi diff --git a/make/autoconf/jdk-options.m4 b/make/autoconf/jdk-options.m4 index d4299078abf..bb188778001 100644 --- a/make/autoconf/jdk-options.m4 +++ b/make/autoconf/jdk-options.m4 @@ -565,9 +565,14 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_UNDEFINED_BEHAVIOR_SANITIZER], # with an additional define LLVM_SYMBOLIZER, which we set here. # To calculate the correct llvm_symbolizer path we can use the location of the compiler, because # their relation is fixed. + # In the ubsan case we have to link every binary with the C++-compiler as linker, because inherently + # the C-Compiler and the C++-compiler used as linker provide a different set of ubsan exports. + # Linking an executable with the C-compiler and one of its shared libraries with the C++-compiler + # leeds to unresolved symbols. if test "x$TOOLCHAIN_TYPE" = "xclang" && test "x$OPENJDK_TARGET_OS" = "xaix"; then - UBSAN_CFLAGS="$UBSAN_CFLAGS -fno-sanitize=function,vptr -DLLVM_SYMBOLIZER=$(dirname $(dirname $CC))/tools/ibm-llvm-symbolizer" - UBSAN_LDFLAGS="$UBSAN_LDFLAGS -fno-sanitize=function,vptr -Wl,-bbigtoc" + UBSAN_CFLAGS="$UBSAN_CFLAGS -DLLVM_SYMBOLIZER=$(dirname $(dirname $CC))/tools/ibm-llvm-symbolizer" + UBSAN_LDFLAGS="$UBSAN_LDFLAGS -Wl,-bbigtoc" + LD="$LDCXX" fi UTIL_ARG_ENABLE(NAME: ubsan, DEFAULT: false, RESULT: UBSAN_ENABLED, DESC: [enable UndefinedBehaviorSanitizer], diff --git a/make/autoconf/libraries.m4 b/make/autoconf/libraries.m4 index bf697928f1b..8dc3d55ed0c 100644 --- a/make/autoconf/libraries.m4 +++ b/make/autoconf/libraries.m4 @@ -136,12 +136,8 @@ AC_DEFUN_ONCE([LIB_SETUP_LIBRARIES], BASIC_JVM_LIBS="$BASIC_JVM_LIBS $LIBPTHREAD" fi - # librt for legacy clock_gettime + # librt - for timers (timer_* functions) if test "x$OPENJDK_TARGET_OS" = xlinux; then - # Hotspot needs to link librt to get the clock_* functions. - # But once our supported minimum build and runtime platform - # has glibc 2.17, this can be removed as the functions are - # in libc. BASIC_JVM_LIBS="$BASIC_JVM_LIBS -lrt" fi diff --git a/make/common/Execute.gmk b/make/common/Execute.gmk index 0311c4ecba1..c195510151f 100644 --- a/make/common/Execute.gmk +++ b/make/common/Execute.gmk @@ -149,7 +149,7 @@ define SetupExecuteBody endif $1_VARDEPS := $$($1_COMMAND) $$($1_PRE_COMMAND) $$($1_POST_COMMAND) - $1_VARDEPS_FILE := $$(call DependOnVariable, $1_VARDEPS) + $1_VARDEPS_FILE := $$(call DependOnVariable, $1_VARDEPS, $$($1_BASE)_exec.vardeps) ifneq ($$($1_PRE_COMMAND), ) diff --git a/make/ide/vscode/hotspot/template-workspace.jsonc b/make/ide/vscode/hotspot/template-workspace.jsonc index c582c48047d..8a349b232ce 100644 --- a/make/ide/vscode/hotspot/template-workspace.jsonc +++ b/make/ide/vscode/hotspot/template-workspace.jsonc @@ -22,6 +22,7 @@ // Java extension "jdk.project.jdkhome": "{{OUTPUTDIR}}/jdk", "jdk.java.onSave.organizeImports": false, // prevents unnecessary changes + "jdk.serverVmOptions": ["-Xmx2G"], // prevent out of memory // Additional conventions "files.associations": { diff --git a/src/hotspot/cpu/aarch64/c1_CodeStubs_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_CodeStubs_aarch64.cpp index 954e4abee14..9bf46678535 100644 --- a/src/hotspot/cpu/aarch64/c1_CodeStubs_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_CodeStubs_aarch64.cpp @@ -216,10 +216,10 @@ void MonitorEnterStub::emit_code(LIR_Assembler* ce) { void MonitorExitStub::emit_code(LIR_Assembler* ce) { __ bind(_entry); - if (_compute_lock) { - // lock_reg was destroyed by fast unlocking attempt => recompute it - ce->monitor_address(_monitor_ix, _lock_reg); - } + + // lock_reg was destroyed by fast unlocking attempt => recompute it + ce->monitor_address(_monitor_ix, _lock_reg); + ce->store_parameter(_lock_reg->as_register(), 0); // note: non-blocking leaf routine => no call info needed StubId exit_id; diff --git a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp index d788c0c201a..9ab463125fe 100644 --- a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp @@ -409,7 +409,7 @@ int LIR_Assembler::emit_unwind_handler() { MonitorExitStub* stub = nullptr; if (method()->is_synchronized()) { monitor_address(0, FrameMap::r0_opr); - stub = new MonitorExitStub(FrameMap::r0_opr, true, 0); + stub = new MonitorExitStub(FrameMap::r0_opr, 0); __ unlock_object(r5, r4, r0, r6, *stub->entry()); __ bind(*stub->continuation()); } @@ -2481,7 +2481,6 @@ void LIR_Assembler::emit_lock(LIR_OpLock* op) { Register lock = op->lock_opr()->as_register(); Register temp = op->scratch_opr()->as_register(); if (op->code() == lir_lock) { - 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 int null_check_offset = __ lock_object(hdr, obj, lock, temp, *op->stub()->entry()); if (op->info() != nullptr) { @@ -2489,7 +2488,6 @@ void LIR_Assembler::emit_lock(LIR_OpLock* op) { } // done } else if (op->code() == lir_unlock) { - assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header"); __ unlock_object(hdr, obj, lock, temp, *op->stub()->entry()); } else { Unimplemented(); diff --git a/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp index 8a79274b2ff..31c36e749c5 100644 --- a/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp @@ -59,28 +59,28 @@ void C1_MacroAssembler::float_cmp(bool is_float, int unordered_result, } } -int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr, Register temp, Label& slow_case) { - assert_different_registers(hdr, obj, disp_hdr, temp, rscratch2); +int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register basic_lock, Register temp, Label& slow_case) { + assert_different_registers(hdr, obj, basic_lock, temp, rscratch2); int null_check_offset = -1; verify_oop(obj); // save object being locked into the BasicObjectLock - str(obj, Address(disp_hdr, BasicObjectLock::obj_offset())); + str(obj, Address(basic_lock, BasicObjectLock::obj_offset())); null_check_offset = offset(); - lightweight_lock(disp_hdr, obj, hdr, temp, rscratch2, slow_case); + lightweight_lock(basic_lock, obj, hdr, temp, rscratch2, slow_case); return null_check_offset; } -void C1_MacroAssembler::unlock_object(Register hdr, Register obj, Register disp_hdr, Register temp, Label& slow_case) { - assert_different_registers(hdr, obj, disp_hdr, temp, rscratch2); +void C1_MacroAssembler::unlock_object(Register hdr, Register obj, Register basic_lock, Register temp, Label& slow_case) { + assert_different_registers(hdr, obj, basic_lock, temp, rscratch2); // load object - ldr(obj, Address(disp_hdr, BasicObjectLock::obj_offset())); + ldr(obj, Address(basic_lock, BasicObjectLock::obj_offset())); verify_oop(obj); lightweight_unlock(obj, hdr, temp, rscratch2, slow_case); diff --git a/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.hpp index fc8e83d706b..7b181b104c1 100644 --- a/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.hpp @@ -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. * Copyright (c) 2014, 2021, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -55,19 +55,19 @@ using MacroAssembler::null_check; Register result); // locking - // hdr : must be r0, contents destroyed - // obj : must point to the object to lock, contents preserved - // disp_hdr: must point to the displaced header location, contents preserved - // temp : temporary register, must not be rscratch1 or rscratch2 + // hdr : must be r0, contents destroyed + // obj : must point to the object to lock, contents preserved + // basic_lock: must point to the basic lock, contents preserved + // temp : temporary register, must not be rscratch1 or rscratch2 // returns code offset at which to add null check debug information - int lock_object (Register swap, Register obj, Register disp_hdr, Register temp, Label& slow_case); + int lock_object (Register swap, Register obj, Register basic_lock, Register temp, Label& slow_case); // unlocking - // hdr : contents destroyed - // obj : must point to the object to lock, contents preserved - // disp_hdr: must be r0 & must point to the displaced header location, contents destroyed - // temp : temporary register, must not be rscratch1 or rscratch2 - void unlock_object(Register swap, Register obj, Register lock, Register temp, Label& slow_case); + // hdr : contents destroyed + // obj : must point to the object to lock, contents preserved + // basic_lock: must be r0 & must point to the basic lock, contents destroyed + // temp : temporary register, must not be rscratch1 or rscratch2 + void unlock_object(Register swap, Register obj, Register basic_lock, Register temp, Label& slow_case); void initialize_object( Register obj, // result: pointer to object after successful allocation diff --git a/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.cpp index a2b43d80746..021af3e5698 100644 --- a/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.cpp @@ -398,14 +398,18 @@ void BarrierSetAssembler::check_oop(MacroAssembler* masm, Register obj, Register OptoReg::Name BarrierSetAssembler::encode_float_vector_register_size(const Node* node, OptoReg::Name opto_reg) { switch (node->ideal_reg()) { case Op_RegF: + case Op_RegI: // RA may place scalar values (Op_RegI/N/L/P) in FP registers when UseFPUForSpilling is enabled + case Op_RegN: // No need to refine. The original encoding is already fine to distinguish. - assert(opto_reg % 4 == 0, "Float register should only occupy a single slot"); + assert(opto_reg % 4 == 0, "32-bit register should only occupy a single slot"); break; // Use different encoding values of the same fp/vector register to help distinguish different sizes. // Such as V16. The OptoReg::name and its corresponding slot value are // "V16": 64, "V16_H": 65, "V16_J": 66, "V16_K": 67. case Op_RegD: case Op_VecD: + case Op_RegL: + case Op_RegP: opto_reg &= ~3; opto_reg |= 1; break; diff --git a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp index 4b3b8e58b9a..70af8dd91d8 100644 --- a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp @@ -1761,9 +1761,6 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, Label lock_done; if (method->is_synchronized()) { - Label count; - const int mark_word_offset = BasicLock::displaced_header_offset_in_bytes(); - // Get the handle (the 2nd argument) __ mov(oop_handle_reg, c_rarg1); diff --git a/src/hotspot/cpu/arm/c1_CodeStubs_arm.cpp b/src/hotspot/cpu/arm/c1_CodeStubs_arm.cpp index efdc190f09a..8e49cfcbcaa 100644 --- a/src/hotspot/cpu/arm/c1_CodeStubs_arm.cpp +++ b/src/hotspot/cpu/arm/c1_CodeStubs_arm.cpp @@ -200,9 +200,10 @@ void MonitorEnterStub::emit_code(LIR_Assembler* ce) { void MonitorExitStub::emit_code(LIR_Assembler* ce) { __ bind(_entry); - if (_compute_lock) { - ce->monitor_address(_monitor_ix, _lock_reg); - } + + // lock_reg was destroyed by fast unlocking attempt => recompute it + ce->monitor_address(_monitor_ix, _lock_reg); + const Register lock_reg = _lock_reg->as_pointer_register(); ce->verify_reserved_argument_area_size(1); diff --git a/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp b/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp index d6ed82dcdb2..219c49d1f14 100644 --- a/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp +++ b/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp @@ -245,7 +245,7 @@ int LIR_Assembler::emit_unwind_handler() { MonitorExitStub* stub = nullptr; if (method()->is_synchronized()) { monitor_address(0, FrameMap::R0_opr); - stub = new MonitorExitStub(FrameMap::R0_opr, true, 0); + stub = new MonitorExitStub(FrameMap::R0_opr, 0); __ unlock_object(R2, R1, R0, *stub->entry()); __ bind(*stub->continuation()); } @@ -2427,7 +2427,6 @@ void LIR_Assembler::emit_lock(LIR_OpLock* op) { Register lock = op->lock_opr()->as_pointer_register(); 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) { add_debug_info_for_null_check(null_check_offset, op->info()); diff --git a/src/hotspot/cpu/arm/c1_MacroAssembler_arm.cpp b/src/hotspot/cpu/arm/c1_MacroAssembler_arm.cpp index f2b08269750..ca7711353d2 100644 --- a/src/hotspot/cpu/arm/c1_MacroAssembler_arm.cpp +++ b/src/hotspot/cpu/arm/c1_MacroAssembler_arm.cpp @@ -176,17 +176,17 @@ void C1_MacroAssembler::allocate_array(Register obj, Register len, initialize_object(obj, tmp1, klass, len, tmp2, tmp3, header_size_in_bytes, -1, /* is_tlab_allocated */ UseTLAB); } -int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr, Label& slow_case) { +int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register basic_lock, Label& slow_case) { 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_different_registers(hdr, obj, basic_lock, tmp2); assert(BasicObjectLock::lock_offset() == 0, "adjust this code"); assert(oopDesc::mark_offset_in_bytes() == 0, "Required by atomic instructions"); // save object being locked into the BasicObjectLock - str(obj, Address(disp_hdr, BasicObjectLock::obj_offset())); + str(obj, Address(basic_lock, BasicObjectLock::obj_offset())); null_check_offset = offset(); @@ -197,26 +197,26 @@ int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr b(slow_case, ne); } - Register t1 = disp_hdr; // Needs saving, probably - Register t2 = hdr; // blow - Register t3 = Rtemp; // blow + Register t1 = basic_lock; // 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); +void C1_MacroAssembler::unlock_object(Register hdr, Register obj, Register basic_lock, Label& slow_case) { + assert_different_registers(hdr, obj, basic_lock, Rtemp); assert(BasicObjectLock::lock_offset() == 0, "adjust this code"); assert(oopDesc::mark_offset_in_bytes() == 0, "Required by atomic instructions"); - ldr(obj, Address(disp_hdr, BasicObjectLock::obj_offset())); + ldr(obj, Address(basic_lock, BasicObjectLock::obj_offset())); - Register t1 = disp_hdr; // Needs saving, probably - Register t2 = hdr; // blow - Register t3 = Rtemp; // blow + Register t1 = basic_lock; // Needs saving, probably + Register t2 = hdr; // blow + Register t3 = Rtemp; // blow lightweight_unlock(obj, t1, t2, t3, 1 /* savemask - save t1 */, slow_case); // Success: fall through diff --git a/src/hotspot/cpu/arm/c1_MacroAssembler_arm.hpp b/src/hotspot/cpu/arm/c1_MacroAssembler_arm.hpp index 0a626822a9b..fd88b6c4fe9 100644 --- a/src/hotspot/cpu/arm/c1_MacroAssembler_arm.hpp +++ b/src/hotspot/cpu/arm/c1_MacroAssembler_arm.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2023, 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 @@ -59,9 +59,9 @@ max_array_allocation_length = 0x01000000 }; - int lock_object(Register hdr, Register obj, Register disp_hdr, Label& slow_case); + int lock_object(Register hdr, Register obj, Register basic_lock, Label& slow_case); - void unlock_object(Register hdr, Register obj, Register disp_hdr, Label& slow_case); + void unlock_object(Register hdr, Register obj, Register basic_lock, Label& slow_case); // This platform only uses signal-based null checks. The Label is not needed. void null_check(Register r, Label *Lnull = nullptr) { MacroAssembler::null_check(r); } diff --git a/src/hotspot/cpu/arm/sharedRuntime_arm.cpp b/src/hotspot/cpu/arm/sharedRuntime_arm.cpp index 9e90b56f9f0..99d8773368d 100644 --- a/src/hotspot/cpu/arm/sharedRuntime_arm.cpp +++ b/src/hotspot/cpu/arm/sharedRuntime_arm.cpp @@ -1128,7 +1128,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, const Register sync_handle = R5; const Register sync_obj = R6; - const Register disp_hdr = altFP_7_11; + const Register basic_lock = altFP_7_11; const Register tmp = R8; Label slow_lock, lock_done, fast_lock; @@ -1139,7 +1139,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, __ mov(sync_handle, R1); log_trace(fastlock)("SharedRuntime lock fast"); - __ lightweight_lock(sync_obj /* object */, disp_hdr /* t1 */, tmp /* t2 */, Rtemp /* t3 */, + __ lightweight_lock(sync_obj /* object */, basic_lock /* t1 */, tmp /* t2 */, Rtemp /* t3 */, 0x7 /* savemask */, slow_lock); // Fall through to lock_done __ bind(lock_done); @@ -1254,7 +1254,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, // last_Java_frame is already set, so do call_VM manually; no exception can occur __ mov(R0, sync_obj); - __ mov(R1, disp_hdr); + __ mov(R1, basic_lock); __ mov(R2, Rthread); __ call(CAST_FROM_FN_PTR(address, SharedRuntime::complete_monitor_locking_C)); @@ -1269,12 +1269,12 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, // Clear pending exception before reentering VM. // Can store the oop in register since it is a leaf call. - assert_different_registers(Rtmp_save1, sync_obj, disp_hdr); + assert_different_registers(Rtmp_save1, sync_obj, basic_lock); __ ldr(Rtmp_save1, Address(Rthread, Thread::pending_exception_offset())); Register zero = __ zero_register(Rtemp); __ str(zero, Address(Rthread, Thread::pending_exception_offset())); __ mov(R0, sync_obj); - __ mov(R1, disp_hdr); + __ mov(R1, basic_lock); __ mov(R2, Rthread); __ call(CAST_FROM_FN_PTR(address, SharedRuntime::complete_monitor_unlocking_C)); __ str(Rtmp_save1, Address(Rthread, Thread::pending_exception_offset())); diff --git a/src/hotspot/cpu/ppc/c1_CodeStubs_ppc.cpp b/src/hotspot/cpu/ppc/c1_CodeStubs_ppc.cpp index 438521b0a9b..61780a73969 100644 --- a/src/hotspot/cpu/ppc/c1_CodeStubs_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_CodeStubs_ppc.cpp @@ -268,9 +268,10 @@ void MonitorEnterStub::emit_code(LIR_Assembler* ce) { void MonitorExitStub::emit_code(LIR_Assembler* ce) { __ bind(_entry); - if (_compute_lock) { - ce->monitor_address(_monitor_ix, _lock_reg); - } + + // lock_reg was destroyed by fast unlocking attempt => recompute it + ce->monitor_address(_monitor_ix, _lock_reg); + address stub = Runtime1::entry_for(ce->compilation()->has_fpu_code() ? StubId::c1_monitorexit_id : StubId::c1_monitorexit_nofpu_id); //__ load_const_optimized(R0, stub); __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(stub)); diff --git a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp index 3ca75305eca..108da2039f6 100644 --- a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp @@ -227,7 +227,7 @@ int LIR_Assembler::emit_unwind_handler() { MonitorExitStub* stub = nullptr; if (method()->is_synchronized()) { monitor_address(0, FrameMap::R4_opr); - stub = new MonitorExitStub(FrameMap::R4_opr, true, 0); + stub = new MonitorExitStub(FrameMap::R4_opr, 0); __ unlock_object(R5, R6, R4, *stub->entry()); __ bind(*stub->continuation()); } @@ -2614,7 +2614,6 @@ void LIR_Assembler::emit_lock(LIR_OpLock* op) { // Obj may not be an oop. if (op->code() == lir_lock) { MonitorEnterStub* stub = (MonitorEnterStub*)op->stub(); - 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) { @@ -2626,7 +2625,6 @@ void LIR_Assembler::emit_lock(LIR_OpLock* op) { __ lock_object(hdr, obj, lock, op->scratch_opr()->as_register(), *op->stub()->entry()); } else { assert (op->code() == lir_unlock, "Invalid code, expected lir_unlock"); - 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/riscv/assembler_riscv.hpp b/src/hotspot/cpu/riscv/assembler_riscv.hpp index 0828342ee65..0712b60fb2a 100644 --- a/src/hotspot/cpu/riscv/assembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/assembler_riscv.hpp @@ -914,6 +914,17 @@ class Assembler : public AbstractAssembler { public: + static uint32_t encode_csrrw(Register Rd, const uint32_t csr, Register Rs1) { + guarantee(is_uimm12(csr), "csr is invalid"); + uint32_t insn = 0; + patch((address)&insn, 6, 0, 0b1110011); + patch((address)&insn, 14, 12, 0b001); + patch_reg((address)&insn, 7, Rd); + patch_reg((address)&insn, 15, Rs1); + patch((address)&insn, 31, 20, csr); + return insn; + } + static uint32_t encode_jal(Register Rd, const int32_t offset) { guarantee(is_simm21(offset) && ((offset % 2) == 0), "offset is invalid."); uint32_t insn = 0; @@ -3693,19 +3704,15 @@ enum Nf { // -------------------------- // Upper Immediate Instruction // -------------------------- -#define INSN(NAME) \ - void NAME(Register Rd, int32_t imm) { \ - /* lui -> c.lui */ \ - if (do_compress() && (Rd != x0 && Rd != x2 && imm != 0 && is_simm18(imm))) { \ - c_lui(Rd, imm); \ - return; \ - } \ - _lui(Rd, imm); \ + void lui(Register Rd, int32_t imm) { + /* lui -> c.lui */ + if (do_compress() && (Rd != x0 && Rd != x2 && imm != 0 && is_simm18(imm))) { + c_lui(Rd, imm); + return; + } + _lui(Rd, imm); } - INSN(lui); - -#undef INSN // Cache Management Operations // These instruction may be turned off for user space. diff --git a/src/hotspot/cpu/riscv/c1_CodeStubs_riscv.cpp b/src/hotspot/cpu/riscv/c1_CodeStubs_riscv.cpp index 0c16e632e5a..a8a21342248 100644 --- a/src/hotspot/cpu/riscv/c1_CodeStubs_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_CodeStubs_riscv.cpp @@ -204,10 +204,10 @@ void MonitorEnterStub::emit_code(LIR_Assembler* ce) { void MonitorExitStub::emit_code(LIR_Assembler* ce) { __ bind(_entry); - if (_compute_lock) { - // lock_reg was destroyed by fast unlocking attempt => recompute it - ce->monitor_address(_monitor_ix, _lock_reg); - } + + // lock_reg was destroyed by fast unlocking attempt => recompute it + ce->monitor_address(_monitor_ix, _lock_reg); + ce->store_parameter(_lock_reg->as_register(), 0); // note: non-blocking leaf routine => no call info needed StubId exit_id; diff --git a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp index c3fe72870cf..9d8ae770ccf 100644 --- a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp @@ -338,7 +338,7 @@ int LIR_Assembler::emit_unwind_handler() { MonitorExitStub* stub = nullptr; if (method()->is_synchronized()) { monitor_address(0, FrameMap::r10_opr); - stub = new MonitorExitStub(FrameMap::r10_opr, true, 0); + stub = new MonitorExitStub(FrameMap::r10_opr, 0); __ unlock_object(x15, x14, x10, x16, *stub->entry()); __ bind(*stub->continuation()); } @@ -1350,6 +1350,7 @@ void LIR_Assembler::align_call(LIR_Code code) { } void LIR_Assembler::call(LIR_OpJavaCall* op, relocInfo::relocType rtype) { + Assembler::IncompressibleScope scope(_masm); address call = __ reloc_call(Address(op->addr(), rtype)); if (call == nullptr) { bailout("reloc call address stub overflow"); @@ -1360,6 +1361,7 @@ void LIR_Assembler::call(LIR_OpJavaCall* op, relocInfo::relocType rtype) { } void LIR_Assembler::ic_call(LIR_OpJavaCall* op) { + Assembler::IncompressibleScope scope(_masm); address call = __ ic_call(op->addr()); if (call == nullptr) { bailout("reloc call address stub overflow"); @@ -1494,14 +1496,12 @@ void LIR_Assembler::emit_lock(LIR_OpLock* op) { Register lock = op->lock_opr()->as_register(); Register temp = op->scratch_opr()->as_register(); if (op->code() == lir_lock) { - 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 int null_check_offset = __ lock_object(hdr, obj, lock, temp, *op->stub()->entry()); if (op->info() != nullptr) { add_debug_info_for_null_check(null_check_offset, op->info()); } } else if (op->code() == lir_unlock) { - assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header"); __ unlock_object(hdr, obj, lock, temp, *op->stub()->entry()); } else { Unimplemented(); @@ -1844,6 +1844,10 @@ void LIR_Assembler::leal(LIR_Opr addr, LIR_Opr dest, LIR_PatchCode patch_code, C void LIR_Assembler::rt_call(LIR_Opr result, address dest, const LIR_OprList* args, LIR_Opr tmp, CodeEmitInfo* info) { assert(!tmp->is_valid(), "don't need temporary"); + Assembler::IncompressibleScope scope(_masm); + // Post call nops must be natural aligned due to cmodx rules. + align_call(lir_rtcall); + __ rt_call(dest); if (info != nullptr) { diff --git a/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.cpp index 8198192f506..8e989de2665 100644 --- a/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.cpp @@ -48,27 +48,27 @@ void C1_MacroAssembler::float_cmp(bool is_float, int unordered_result, } } -int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr, Register temp, Label& slow_case) { - assert_different_registers(hdr, obj, disp_hdr, temp, t0, t1); +int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register basic_lock, Register temp, Label& slow_case) { + assert_different_registers(hdr, obj, basic_lock, temp, t0, t1); int null_check_offset = -1; verify_oop(obj); // save object being locked into the BasicObjectLock - sd(obj, Address(disp_hdr, BasicObjectLock::obj_offset())); + sd(obj, Address(basic_lock, BasicObjectLock::obj_offset())); null_check_offset = offset(); - lightweight_lock(disp_hdr, obj, hdr, temp, t1, slow_case); + lightweight_lock(basic_lock, obj, hdr, temp, t1, slow_case); return null_check_offset; } -void C1_MacroAssembler::unlock_object(Register hdr, Register obj, Register disp_hdr, Register temp, Label& slow_case) { - assert_different_registers(hdr, obj, disp_hdr, temp, t0, t1); +void C1_MacroAssembler::unlock_object(Register hdr, Register obj, Register basic_lock, Register temp, Label& slow_case) { + assert_different_registers(hdr, obj, basic_lock, temp, t0, t1); // load object - ld(obj, Address(disp_hdr, BasicObjectLock::obj_offset())); + ld(obj, Address(basic_lock, BasicObjectLock::obj_offset())); verify_oop(obj); lightweight_unlock(obj, hdr, temp, t1, slow_case); diff --git a/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.hpp index 561053045ec..16e76884049 100644 --- a/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.hpp @@ -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. * Copyright (c) 2014, 2015, Red Hat Inc. All rights reserved. * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -56,19 +56,19 @@ using MacroAssembler::null_check; Register result); // locking - // hdr : must be x10, contents destroyed - // obj : must point to the object to lock, contents preserved - // disp_hdr: must point to the displaced header location, contents preserved - // temp : temporary register, must not be scratch register t0 or t1 + // hdr : must be x10, contents destroyed + // obj : must point to the object to lock, contents preserved + // basic_lock: must point to the basic_lock, contents preserved + // temp : temporary register, must not be scratch register t0 or t1 // returns code offset at which to add null check debug information - int lock_object(Register swap, Register obj, Register disp_hdr, Register temp, Label& slow_case); + int lock_object(Register swap, Register obj, Register basic_lock, Register temp, Label& slow_case); // unlocking - // hdr : contents destroyed - // obj : must point to the object to lock, contents preserved - // disp_hdr: must be x10 & must point to the displaced header location, contents destroyed - // temp : temporary register, must not be scratch register t0 or t1 - void unlock_object(Register swap, Register obj, Register lock, Register temp, Label& slow_case); + // hdr : contents destroyed + // obj : must point to the object to lock, contents preserved + // basic_lock: must be x10 & must point to the basic lock, contents destroyed + // temp : temporary register, must not be scratch register t0 or t1 + void unlock_object(Register swap, Register obj, Register basic_lock, Register temp, Label& slow_case); void initialize_object( Register obj, // result: pointer to object after successful allocation diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index c9de1db0308..5c85cc13bed 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -355,14 +355,15 @@ void MacroAssembler::call_VM(Register oop_result, } void MacroAssembler::post_call_nop() { + assert(!in_compressible_scope(), "Must be"); + assert_alignment(pc()); if (!Continuations::enabled()) { return; } - relocate(post_call_nop_Relocation::spec(), [&] { - InlineSkippedInstructionsCounter skipCounter(this); - nop(); - li32(zr, 0); - }); + relocate(post_call_nop_Relocation::spec()); + InlineSkippedInstructionsCounter skipCounter(this); + nop(); + li32(zr, 0); } // these are no-ops overridden by InterpreterMacroAssembler @@ -5013,7 +5014,7 @@ address MacroAssembler::reloc_call(Address entry, Register tmp) { address MacroAssembler::ic_call(address entry, jint method_index) { RelocationHolder rh = virtual_call_Relocation::spec(pc(), method_index); - IncompressibleScope scope(this); // relocations + assert(!in_compressible_scope(), "Must be"); movptr(t0, (address)Universe::non_oop_word(), t1); assert_cond(entry != nullptr); return reloc_call(Address(entry, rh)); diff --git a/src/hotspot/cpu/riscv/nativeInst_riscv.cpp b/src/hotspot/cpu/riscv/nativeInst_riscv.cpp index 72cc95a595d..5d1cac72ade 100644 --- a/src/hotspot/cpu/riscv/nativeInst_riscv.cpp +++ b/src/hotspot/cpu/riscv/nativeInst_riscv.cpp @@ -331,13 +331,10 @@ bool NativeInstruction::is_safepoint_poll() { return MacroAssembler::is_lwu_to_zr(address(this)); } -void NativeIllegalInstruction::insert(address code_pos) { - assert_cond(code_pos != nullptr); - Assembler::sd_instr(code_pos, 0xffffffff); // all bits ones is permanently reserved as an illegal instruction -} - bool NativeInstruction::is_stop() { - return uint_at(0) == 0xc0101073; // an illegal instruction, 'csrrw x0, time, x0' + // an illegal instruction, 'csrrw x0, time, x0' + uint32_t encoded = Assembler::encode_csrrw(x0, Assembler::time, x0); + return uint_at(0) == encoded; } //------------------------------------------------------------------- @@ -347,6 +344,8 @@ void NativeGeneralJump::insert_unconditional(address code_pos, address entry) { MacroAssembler a(&cb); Assembler::IncompressibleScope scope(&a); // Fixed length: see NativeGeneralJump::get_instruction_size() + MacroAssembler::assert_alignment(code_pos); + int32_t offset = 0; a.movptr(t1, entry, offset, t0); // lui, lui, slli, add a.jr(t1, offset); // jalr @@ -378,6 +377,7 @@ bool NativePostCallNop::decode(int32_t& oopmap_slot, int32_t& cb_offset) const { } bool NativePostCallNop::patch(int32_t oopmap_slot, int32_t cb_offset) { + MacroAssembler::assert_alignment(addr_at(4)); if (((oopmap_slot & 0xff) != oopmap_slot) || ((cb_offset & 0xffffff) != cb_offset)) { return false; // cannot encode } @@ -389,14 +389,17 @@ bool NativePostCallNop::patch(int32_t oopmap_slot, int32_t cb_offset) { return true; // successfully encoded } -void NativeDeoptInstruction::verify() { +bool NativeDeoptInstruction::is_deopt_at(address instr) { + assert(instr != nullptr, "Must be"); + uint32_t value = Assembler::ld_instr(instr); + uint32_t encoded = Assembler::encode_csrrw(x0, Assembler::instret, x0); + return value == encoded; } // Inserts an undefined instruction at a given pc void NativeDeoptInstruction::insert(address code_pos) { - // 0xc0201073 encodes CSRRW x0, instret, x0 - uint32_t insn = 0xc0201073; - uint32_t *pos = (uint32_t *) code_pos; - *pos = insn; + MacroAssembler::assert_alignment(code_pos); + uint32_t encoded = Assembler::encode_csrrw(x0, Assembler::instret, x0); + Assembler::sd_instr(code_pos, encoded); ICache::invalidate_range(code_pos, 4); } diff --git a/src/hotspot/cpu/riscv/nativeInst_riscv.hpp b/src/hotspot/cpu/riscv/nativeInst_riscv.hpp index 4235e23d421..d990cfbc50d 100644 --- a/src/hotspot/cpu/riscv/nativeInst_riscv.hpp +++ b/src/hotspot/cpu/riscv/nativeInst_riscv.hpp @@ -294,12 +294,6 @@ inline NativeGeneralJump* nativeGeneralJump_at(address addr) { return jump; } -class NativeIllegalInstruction: public NativeInstruction { - public: - // Insert illegal opcode as specific address - static void insert(address code_pos); -}; - inline bool NativeInstruction::is_nop() const { uint32_t insn = Assembler::ld_instr(addr_at(0)); return insn == 0x13; @@ -353,14 +347,7 @@ class NativeDeoptInstruction: public NativeInstruction { address instruction_address() const { return addr_at(instruction_offset); } address next_instruction_address() const { return addr_at(instruction_size); } - void verify(); - - static bool is_deopt_at(address instr) { - assert(instr != nullptr, ""); - uint32_t value = Assembler::ld_instr(instr); - // 0xc0201073 encodes CSRRW x0, instret, x0 - return value == 0xc0201073; - } + static bool is_deopt_at(address instr); // MT-safe patching static void insert(address code_pos); diff --git a/src/hotspot/cpu/riscv/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad index 739a525c9a4..d816f2405c4 100644 --- a/src/hotspot/cpu/riscv/riscv.ad +++ b/src/hotspot/cpu/riscv/riscv.ad @@ -1269,6 +1269,26 @@ int CallDynamicJavaDirectNode::compute_padding(int current_offset) const return align_up(current_offset, alignment_required()) - current_offset; } +int CallRuntimeDirectNode::compute_padding(int current_offset) const +{ + return align_up(current_offset, alignment_required()) - current_offset; +} + +int CallLeafDirectNode::compute_padding(int current_offset) const +{ + return align_up(current_offset, alignment_required()) - current_offset; +} + +int CallLeafDirectVectorNode::compute_padding(int current_offset) const +{ + return align_up(current_offset, alignment_required()) - current_offset; +} + +int CallLeafNoFPDirectNode::compute_padding(int current_offset) const +{ + return align_up(current_offset, alignment_required()) - current_offset; +} + //============================================================================= #ifndef PRODUCT @@ -8175,7 +8195,7 @@ instruct unnecessary_membar_volatile_rvtso() %{ ins_cost(0); size(0); - + format %{ "#@unnecessary_membar_volatile_rvtso (unnecessary so empty encoding)" %} ins_encode %{ __ block_comment("unnecessary_membar_volatile_rvtso"); @@ -10509,6 +10529,7 @@ instruct CallRuntimeDirect(method meth) ins_encode(riscv_enc_java_to_runtime(meth)); ins_pipe(pipe_class_call); + ins_alignment(4); %} // Call Runtime Instruction @@ -10526,6 +10547,7 @@ instruct CallLeafDirect(method meth) ins_encode(riscv_enc_java_to_runtime(meth)); ins_pipe(pipe_class_call); + ins_alignment(4); %} // Call Runtime Instruction without safepoint and with vector arguments @@ -10543,6 +10565,7 @@ instruct CallLeafDirectVector(method meth) ins_encode(riscv_enc_java_to_runtime(meth)); ins_pipe(pipe_class_call); + ins_alignment(4); %} // Call Runtime Instruction @@ -10560,6 +10583,7 @@ instruct CallLeafNoFPDirect(method meth) ins_encode(riscv_enc_java_to_runtime(meth)); ins_pipe(pipe_class_call); + ins_alignment(4); %} // ============================================================================ diff --git a/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp b/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp index 01970c68090..94506e9f19d 100644 --- a/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp +++ b/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp @@ -1002,20 +1002,23 @@ static void gen_continuation_enter(MacroAssembler* masm, __ bnez(c_rarg2, call_thaw); - // Make sure the call is patchable - __ align(NativeInstruction::instruction_size); - - const address tr_call = __ reloc_call(resolve); - if (tr_call == nullptr) { - fatal("CodeCache is full at gen_continuation_enter"); - } + address call_pc; + { + Assembler::IncompressibleScope scope(masm); + // Make sure the call is patchable + __ align(NativeInstruction::instruction_size); - oop_maps->add_gc_map(__ pc() - start, map); - __ post_call_nop(); + call_pc = __ reloc_call(resolve); + if (call_pc == nullptr) { + fatal("CodeCache is full at gen_continuation_enter"); + } + oop_maps->add_gc_map(__ pc() - start, map); + __ post_call_nop(); + } __ j(exit); - address stub = CompiledDirectCall::emit_to_interp_stub(masm, tr_call); + address stub = CompiledDirectCall::emit_to_interp_stub(masm, call_pc); if (stub == nullptr) { fatal("CodeCache is full at gen_continuation_enter"); } @@ -1034,26 +1037,36 @@ static void gen_continuation_enter(MacroAssembler* masm, __ bnez(c_rarg2, call_thaw); - // Make sure the call is patchable - __ align(NativeInstruction::instruction_size); + address call_pc; + { + Assembler::IncompressibleScope scope(masm); + // Make sure the call is patchable + __ align(NativeInstruction::instruction_size); - const address tr_call = __ reloc_call(resolve); - if (tr_call == nullptr) { - fatal("CodeCache is full at gen_continuation_enter"); - } + call_pc = __ reloc_call(resolve); + if (call_pc == nullptr) { + fatal("CodeCache is full at gen_continuation_enter"); + } - oop_maps->add_gc_map(__ pc() - start, map); - __ post_call_nop(); + oop_maps->add_gc_map(__ pc() - start, map); + __ post_call_nop(); + } __ j(exit); __ bind(call_thaw); - ContinuationEntry::_thaw_call_pc_offset = __ pc() - start; - __ rt_call(CAST_FROM_FN_PTR(address, StubRoutines::cont_thaw())); - oop_maps->add_gc_map(__ pc() - start, map->deep_copy()); - ContinuationEntry::_return_pc_offset = __ pc() - start; - __ post_call_nop(); + // Post call nops must be natural aligned due to cmodx rules. + { + Assembler::IncompressibleScope scope(masm); + __ align(NativeInstruction::instruction_size); + + ContinuationEntry::_thaw_call_pc_offset = __ pc() - start; + __ rt_call(CAST_FROM_FN_PTR(address, StubRoutines::cont_thaw())); + oop_maps->add_gc_map(__ pc() - start, map->deep_copy()); + ContinuationEntry::_return_pc_offset = __ pc() - start; + __ post_call_nop(); + } __ bind(exit); ContinuationEntry::_cleanup_offset = __ pc() - start; @@ -1082,7 +1095,7 @@ static void gen_continuation_enter(MacroAssembler* masm, __ jr(x11); // the exception handler } - address stub = CompiledDirectCall::emit_to_interp_stub(masm, tr_call); + address stub = CompiledDirectCall::emit_to_interp_stub(masm, call_pc); if (stub == nullptr) { fatal("CodeCache is full at gen_continuation_enter"); } @@ -1115,10 +1128,16 @@ static void gen_continuation_yield(MacroAssembler* masm, __ mv(c_rarg1, sp); + // Post call nops must be natural aligned due to cmodx rules. + __ align(NativeInstruction::instruction_size); + frame_complete = __ pc() - start; address the_pc = __ pc(); - __ post_call_nop(); // this must be exactly after the pc value that is pushed into the frame info, we use this nop for fast CodeBlob lookup + { + Assembler::IncompressibleScope scope(masm); + __ post_call_nop(); // this must be exactly after the pc value that is pushed into the frame info, we use this nop for fast CodeBlob lookup + } __ mv(c_rarg0, xthread); __ set_last_Java_frame(sp, fp, the_pc, t0); @@ -1677,8 +1696,6 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, Label lock_done; if (method->is_synchronized()) { - const int mark_word_offset = BasicLock::displaced_header_offset_in_bytes(); - // Get the handle (the 2nd argument) __ mv(oop_handle_reg, c_rarg1); diff --git a/src/hotspot/cpu/riscv/vm_version_riscv.cpp b/src/hotspot/cpu/riscv/vm_version_riscv.cpp index 1bb9509cdde..53f7ff9bc66 100644 --- a/src/hotspot/cpu/riscv/vm_version_riscv.cpp +++ b/src/hotspot/cpu/riscv/vm_version_riscv.cpp @@ -35,15 +35,28 @@ uint32_t VM_Version::_initial_vector_length = 0; -#define DEF_RV_FEATURE(NAME, PRETTY, BIT, FSTRING, FLAGF) \ -VM_Version::NAME##RVFeatureValue VM_Version::NAME(PRETTY, BIT, FSTRING); -RV_FEATURE_FLAGS(DEF_RV_FEATURE) - -#define ADD_RV_FEATURE_IN_LIST(NAME, PRETTY, BIT, FSTRING, FLAGF) \ - &VM_Version::NAME, -VM_Version::RVFeatureValue* VM_Version::_feature_list[] = { -RV_FEATURE_FLAGS(ADD_RV_FEATURE_IN_LIST) +#define DEF_RV_EXT_FEATURE(NAME, PRETTY, LINUX_BIT, FSTRING, FLAGF) \ +VM_Version::NAME##RVExtFeatureValue VM_Version::NAME; +RV_EXT_FEATURE_FLAGS(DEF_RV_EXT_FEATURE) +#undef DEF_RV_EXT_FEATURE + +#define DEF_RV_NON_EXT_FEATURE(NAME, PRETTY, LINUX_BIT, FSTRING, FLAGF) \ +VM_Version::NAME##RVNonExtFeatureValue VM_Version::NAME; +RV_NON_EXT_FEATURE_FLAGS(DEF_RV_NON_EXT_FEATURE) +#undef DEF_RV_NON_EXT_FEATURE + +#define ADD_RV_EXT_FEATURE_IN_LIST(NAME, PRETTY, LINUX_BIT, FSTRING, FLAGF) \ + &VM_Version::NAME, +#define ADD_RV_NON_EXT_FEATURE_IN_LIST(NAME, PRETTY, LINUX_BIT, FSTRING, FLAGF) \ + &VM_Version::NAME, + VM_Version::RVFeatureValue* VM_Version::_feature_list[] = { + RV_EXT_FEATURE_FLAGS(ADD_RV_EXT_FEATURE_IN_LIST) + RV_NON_EXT_FEATURE_FLAGS(ADD_RV_NON_EXT_FEATURE_IN_LIST) nullptr}; +#undef ADD_RV_NON_EXT_FEATURE_IN_LIST +#undef ADD_RV_EXT_FEATURE_IN_LIST + +VM_Version::RVExtFeatures* VM_Version::_rv_ext_features = new VM_Version::RVExtFeatures(); void VM_Version::useRVA20U64Profile() { RV_USE_RVA20U64; @@ -147,7 +160,7 @@ void VM_Version::common_initialize() { if (FLAG_IS_DEFAULT(AvoidUnalignedAccesses)) { FLAG_SET_DEFAULT(AvoidUnalignedAccesses, - unaligned_access.value() != MISALIGNED_FAST); + unaligned_scalar.value() != MISALIGNED_SCALAR_FAST); } if (!AvoidUnalignedAccesses) { @@ -162,7 +175,12 @@ void VM_Version::common_initialize() { // This machine has fast unaligned memory accesses if (FLAG_IS_DEFAULT(UseUnalignedAccesses)) { FLAG_SET_DEFAULT(UseUnalignedAccesses, - unaligned_access.value() == MISALIGNED_FAST); + (unaligned_scalar.value() == MISALIGNED_SCALAR_FAST)); + } + + if (FLAG_IS_DEFAULT(AlignVector)) { + FLAG_SET_DEFAULT(AlignVector, + unaligned_vector.value() != MISALIGNED_VECTOR_FAST); } #ifdef __riscv_ztso @@ -195,13 +213,8 @@ void VM_Version::common_initialize() { } if (UseRVV) { - if (!ext_V.enabled() && FLAG_IS_DEFAULT(UseRVV)) { - warning("RVV is not supported on this CPU"); - FLAG_SET_DEFAULT(UseRVV, false); - } else { - // read vector length from vector CSR vlenb - _initial_vector_length = cpu_vector_length(); - } + // read vector length from vector CSR vlenb + _initial_vector_length = cpu_vector_length(); } // Misc Intrinsics that could depend on RVV. @@ -221,36 +234,6 @@ void VM_Version::common_initialize() { warning("CRC32C intrinsics are not available on this CPU."); FLAG_SET_DEFAULT(UseCRC32CIntrinsics, false); } - - // UseZvbb (depends on RVV). - if (UseZvbb && !UseRVV) { - warning("Cannot enable UseZvbb on cpu without RVV support."); - FLAG_SET_DEFAULT(UseZvbb, false); - } - - // UseZvbc (depends on RVV). - if (UseZvbc && !UseRVV) { - warning("Cannot enable UseZvbc on cpu without RVV support."); - FLAG_SET_DEFAULT(UseZvbc, false); - } - - // UseZvkn (depends on RVV). - if (UseZvkn && !UseRVV) { - warning("Cannot enable UseZvkn on cpu without RVV support."); - FLAG_SET_DEFAULT(UseZvkn, false); - } - - // UseZvfh (depends on RVV) - if (UseZvfh) { - if (!UseRVV) { - warning("Cannot enable UseZvfh on cpu without RVV support."); - FLAG_SET_DEFAULT(UseZvfh, false); - } - if (!UseZfh) { - warning("Cannot enable UseZvfh on cpu without Zfh support."); - FLAG_SET_DEFAULT(UseZvfh, false); - } - } } #ifdef COMPILER2 diff --git a/src/hotspot/cpu/riscv/vm_version_riscv.hpp b/src/hotspot/cpu/riscv/vm_version_riscv.hpp index d94385cd8ac..b3d905dff9d 100644 --- a/src/hotspot/cpu/riscv/vm_version_riscv.hpp +++ b/src/hotspot/cpu/riscv/vm_version_riscv.hpp @@ -46,31 +46,59 @@ class VM_Version : public Abstract_VM_Version { RIVOS = 0x6cf, // JEDEC: 0x4f, Bank: 14 }; + class RVExtFeatures; + class RVFeatureValue { const char* const _pretty; const bool _feature_string; - const uint64_t _feature_bit; - bool _enabled; + const uint64_t _linux_feature_bit; int64_t _value; public: - RVFeatureValue(const char* pretty, int bit_num, bool fstring) : - _pretty(pretty), _feature_string(fstring), _feature_bit(nth_bit(bit_num)), - _enabled(false), _value(-1) { + RVFeatureValue(const char* pretty, int linux_bit_num, bool fstring) : + _pretty(pretty), _feature_string(fstring), _linux_feature_bit(nth_bit(linux_bit_num)), + _value(-1) { } - void enable_feature(int64_t value = 0) { - _enabled = true; + virtual void enable_feature(int64_t value = 0) { _value = value; } - void disable_feature() { - _enabled = false; + virtual void disable_feature() { _value = -1; } const char* pretty() { return _pretty; } - uint64_t feature_bit() { return _feature_bit; } + uint64_t feature_bit() { return _linux_feature_bit; } bool feature_string() { return _feature_string; } - bool enabled() { return _enabled; } int64_t value() { return _value; } + virtual bool enabled() = 0; virtual void update_flag() = 0; + + protected: + bool deps_all_enabled(RVFeatureValue* dep0, ...) { + assert(dep0 != nullptr, "must not"); + + va_list va; + va_start(va, dep0); + RVFeatureValue* next = dep0; + bool enabled = true; + while (next != nullptr && enabled) { + enabled = next->enabled(); + next = va_arg(va, RVFeatureValue*); + } + va_end(va); + return enabled; + } + + void deps_string(stringStream& ss, RVFeatureValue* dep0, ...) { + assert(dep0 != nullptr, "must not"); + ss.print("%s (%s)", dep0->pretty(), dep0->enabled() ? "enabled" : "disabled"); + + va_list va; + va_start(va, dep0); + RVFeatureValue* next = nullptr; + while ((next = va_arg(va, RVFeatureValue*)) != nullptr) { + ss.print(", %s (%s)", next->pretty(), next->enabled() ? "enabled" : "disabled"); + } + va_end(va); + } }; #define UPDATE_DEFAULT(flag) \ @@ -86,31 +114,77 @@ class VM_Version : public Abstract_VM_Version { } \ } \ - #define UPDATE_DEFAULT_DEP(flag, dep) \ - void update_flag() { \ - assert(enabled(), "Must be."); \ - /* dep must be declared before */ \ - assert((uintptr_t)(this) > \ - (uintptr_t)(&dep), "Invalid"); \ - if (FLAG_IS_DEFAULT(flag)) { \ - if (dep.enabled()) { \ - FLAG_SET_DEFAULT(flag, true); \ - } else { \ - FLAG_SET_DEFAULT(flag, false); \ - /* Sync CPU features with flags */ \ - disable_feature(); \ - } \ - } else { \ - /* Sync CPU features with flags */ \ - if (!flag) { \ - disable_feature(); \ - } \ - } \ - } \ + #define UPDATE_DEFAULT_DEP(flag, dep0, ...) \ + void update_flag() { \ + assert(enabled(), "Must be."); \ + if (FLAG_IS_DEFAULT(flag)) { \ + if (this->deps_all_enabled(dep0, ##__VA_ARGS__)) { \ + FLAG_SET_DEFAULT(flag, true); \ + } else { \ + FLAG_SET_DEFAULT(flag, false); \ + stringStream ss; \ + deps_string(ss, dep0, ##__VA_ARGS__); \ + warning("Cannot enable " #flag ", it's missing dependent extension(s) %s", ss.as_string(true)); \ + /* Sync CPU features with flags */ \ + disable_feature(); \ + } \ + } else { \ + /* Sync CPU features with flags */ \ + if (!flag) { \ + disable_feature(); \ + } else if (!deps_all_enabled(dep0, ##__VA_ARGS__)) { \ + FLAG_SET_DEFAULT(flag, false); \ + stringStream ss; \ + deps_string(ss, dep0, ##__VA_ARGS__); \ + warning("Cannot enable " #flag ", it's missing dependent extension(s) %s", ss.as_string(true)); \ + /* Sync CPU features with flags */ \ + disable_feature(); \ + } \ + } \ + } \ #define NO_UPDATE_DEFAULT \ void update_flag() {} \ + + class RVExtFeatureValue : public RVFeatureValue { + const uint32_t _cpu_feature_index; + public: + RVExtFeatureValue(const char* pretty, int linux_bit_num, uint32_t cpu_feature_index, bool fstring) : + RVFeatureValue(pretty, linux_bit_num, fstring), + _cpu_feature_index(cpu_feature_index) { + } + bool enabled() { + return RVExtFeatures::current()->support_feature(_cpu_feature_index); + } + void enable_feature(int64_t value = 0) { + RVFeatureValue::enable_feature(value); + RVExtFeatures::current()->set_feature(_cpu_feature_index); + } + void disable_feature() { + RVFeatureValue::disable_feature(); + RVExtFeatures::current()->clear_feature(_cpu_feature_index); + } + }; + + class RVNonExtFeatureValue : public RVFeatureValue { + bool _enabled; + public: + RVNonExtFeatureValue(const char* pretty, int linux_bit_num, bool fstring) : + RVFeatureValue(pretty, linux_bit_num, fstring), + _enabled(false) { + } + bool enabled() { return _enabled; } + void enable_feature(int64_t value = 0) { + RVFeatureValue::enable_feature(value); + _enabled = true; + } + void disable_feature() { + RVFeatureValue::disable_feature(); + _enabled = false; + } + }; + // Frozen standard extensions // I RV64I // M Integer Multiplication and Division @@ -153,7 +227,8 @@ class VM_Version : public Abstract_VM_Version { // mvendorid Manufactory JEDEC id encoded, ISA vol 2 3.1.2.. // marchid Id for microarch. Mvendorid plus marchid uniquely identify the microarch. // mimpid A unique encoding of the version of the processor implementation. - // unaligned_access Unaligned memory accesses (unknown, unspported, emulated, slow, firmware, fast) + // unaligned_scalar Performance of misaligned scalar accesses (unknown, emulated, slow, fast, unsupported) + // unaligned_vector Performance of misaligned vector accesses (unknown, unspported, slow, fast) // satp mode SATP bits (number of virtual addr bits) mbare, sv39, sv48, sv57, sv64 public: @@ -161,58 +236,141 @@ class VM_Version : public Abstract_VM_Version { #define RV_NO_FLAG_BIT (BitsPerWord+1) // nth_bit will return 0 on values larger than BitsPerWord // Note: the order matters, depender should be after their dependee. E.g. ext_V before ext_Zvbb. - // declaration name , extension name, bit pos ,in str, mapped flag) - #define RV_FEATURE_FLAGS(decl) \ - decl(ext_I , "i" , ('I' - 'A'), true , NO_UPDATE_DEFAULT) \ - decl(ext_M , "m" , ('M' - 'A'), true , NO_UPDATE_DEFAULT) \ - decl(ext_A , "a" , ('A' - 'A'), true , NO_UPDATE_DEFAULT) \ - decl(ext_F , "f" , ('F' - 'A'), true , NO_UPDATE_DEFAULT) \ - decl(ext_D , "d" , ('D' - 'A'), true , NO_UPDATE_DEFAULT) \ - decl(ext_C , "c" , ('C' - 'A'), true , UPDATE_DEFAULT(UseRVC)) \ - decl(ext_Q , "q" , ('Q' - 'A'), true , NO_UPDATE_DEFAULT) \ - decl(ext_H , "h" , ('H' - 'A'), true , NO_UPDATE_DEFAULT) \ - decl(ext_V , "v" , ('V' - 'A'), true , UPDATE_DEFAULT(UseRVV)) \ - decl(ext_Zicbom , "Zicbom" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZicbom)) \ - decl(ext_Zicboz , "Zicboz" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZicboz)) \ - decl(ext_Zicbop , "Zicbop" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZicbop)) \ - decl(ext_Zba , "Zba" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZba)) \ - decl(ext_Zbb , "Zbb" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZbb)) \ - decl(ext_Zbc , "Zbc" , RV_NO_FLAG_BIT, true , NO_UPDATE_DEFAULT) \ - decl(ext_Zbs , "Zbs" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZbs)) \ - decl(ext_Zbkb , "Zbkb" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZbkb)) \ - decl(ext_Zcb , "Zcb" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZcb)) \ - decl(ext_Zfa , "Zfa" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZfa)) \ - decl(ext_Zfh , "Zfh" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZfh)) \ - decl(ext_Zfhmin , "Zfhmin" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZfhmin)) \ - decl(ext_Zicsr , "Zicsr" , RV_NO_FLAG_BIT, true , NO_UPDATE_DEFAULT) \ - decl(ext_Zicntr , "Zicntr" , RV_NO_FLAG_BIT, true , NO_UPDATE_DEFAULT) \ - decl(ext_Zifencei , "Zifencei" , RV_NO_FLAG_BIT, true , NO_UPDATE_DEFAULT) \ - decl(ext_Zic64b , "Zic64b" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZic64b)) \ - decl(ext_Ztso , "Ztso" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZtso)) \ - decl(ext_Zihintpause , "Zihintpause" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZihintpause)) \ - decl(ext_Zacas , "Zacas" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZacas)) \ - decl(ext_Zvbb , "Zvbb" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT_DEP(UseZvbb, ext_V)) \ - decl(ext_Zvbc , "Zvbc" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT_DEP(UseZvbc, ext_V)) \ - decl(ext_Zvfh , "Zvfh" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT_DEP(UseZvfh, ext_V)) \ - decl(ext_Zvkn , "Zvkn" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT_DEP(UseZvkn, ext_V)) \ - decl(ext_Zicond , "Zicond" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZicond)) \ - decl(mvendorid , "VendorId" , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \ - decl(marchid , "ArchId" , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \ - decl(mimpid , "ImpId" , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \ - decl(unaligned_access , "Unaligned" , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \ - decl(satp_mode , "SATP" , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \ - decl(zicboz_block_size, "ZicbozBlockSize", RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \ - - #define DECLARE_RV_FEATURE(NAME, PRETTY, BIT, FSTRING, FLAGF) \ - struct NAME##RVFeatureValue : public RVFeatureValue { \ - NAME##RVFeatureValue(const char* pretty, int bit, bool fstring) : \ - RVFeatureValue(pretty, bit, fstring) {} \ - FLAGF; \ - }; \ - static NAME##RVFeatureValue NAME; \ - - RV_FEATURE_FLAGS(DECLARE_RV_FEATURE) - #undef DECLARE_RV_FEATURE + // + // Fields description in `decl`: + // declaration name, extension name, bit value from linux, feature string?, mapped flag) + #define RV_EXT_FEATURE_FLAGS(decl) \ + decl(ext_I , i , ('I' - 'A'), true , NO_UPDATE_DEFAULT) \ + decl(ext_M , m , ('M' - 'A'), true , NO_UPDATE_DEFAULT) \ + decl(ext_A , a , ('A' - 'A'), true , NO_UPDATE_DEFAULT) \ + decl(ext_F , f , ('F' - 'A'), true , NO_UPDATE_DEFAULT) \ + decl(ext_D , d , ('D' - 'A'), true , NO_UPDATE_DEFAULT) \ + decl(ext_C , c , ('C' - 'A'), true , UPDATE_DEFAULT(UseRVC)) \ + decl(ext_Q , q , ('Q' - 'A'), true , NO_UPDATE_DEFAULT) \ + decl(ext_H , h , ('H' - 'A'), true , NO_UPDATE_DEFAULT) \ + decl(ext_V , v , ('V' - 'A'), true , UPDATE_DEFAULT(UseRVV)) \ + decl(ext_Zicbom , Zicbom , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZicbom)) \ + decl(ext_Zicboz , Zicboz , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZicboz)) \ + decl(ext_Zicbop , Zicbop , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZicbop)) \ + decl(ext_Zba , Zba , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZba)) \ + decl(ext_Zbb , Zbb , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZbb)) \ + decl(ext_Zbc , Zbc , RV_NO_FLAG_BIT, true , NO_UPDATE_DEFAULT) \ + decl(ext_Zbs , Zbs , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZbs)) \ + decl(ext_Zbkb , Zbkb , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZbkb)) \ + decl(ext_Zcb , Zcb , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZcb)) \ + decl(ext_Zfa , Zfa , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZfa)) \ + decl(ext_Zfh , Zfh , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZfh)) \ + decl(ext_Zfhmin , Zfhmin , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZfhmin)) \ + decl(ext_Zicsr , Zicsr , RV_NO_FLAG_BIT, true , NO_UPDATE_DEFAULT) \ + decl(ext_Zicntr , Zicntr , RV_NO_FLAG_BIT, true , NO_UPDATE_DEFAULT) \ + decl(ext_Zifencei , Zifencei , RV_NO_FLAG_BIT, true , NO_UPDATE_DEFAULT) \ + decl(ext_Zic64b , Zic64b , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZic64b)) \ + decl(ext_Ztso , Ztso , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZtso)) \ + decl(ext_Zihintpause , Zihintpause , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZihintpause)) \ + decl(ext_Zacas , Zacas , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZacas)) \ + decl(ext_Zvbb , Zvbb , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT_DEP(UseZvbb, &ext_V, nullptr)) \ + decl(ext_Zvbc , Zvbc , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT_DEP(UseZvbc, &ext_V, nullptr)) \ + decl(ext_Zvfh , Zvfh , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT_DEP(UseZvfh, &ext_V, &ext_Zfh, nullptr)) \ + decl(ext_Zvkn , Zvkn , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT_DEP(UseZvkn, &ext_V, nullptr)) \ + decl(ext_Zicond , Zicond , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZicond)) \ + + #define DECLARE_RV_EXT_FEATURE(NAME, PRETTY, LINUX_BIT, FSTRING, FLAGF) \ + struct NAME##RVExtFeatureValue : public RVExtFeatureValue { \ + NAME##RVExtFeatureValue() : \ + RVExtFeatureValue(#PRETTY, LINUX_BIT, RVExtFeatures::CPU_##NAME, FSTRING) {} \ + FLAGF; \ + }; \ + static NAME##RVExtFeatureValue NAME; \ + + RV_EXT_FEATURE_FLAGS(DECLARE_RV_EXT_FEATURE) + #undef DECLARE_RV_EXT_FEATURE + + // Non-extension features + // + #define RV_NON_EXT_FEATURE_FLAGS(decl) \ + decl(mvendorid , VendorId , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \ + decl(marchid , ArchId , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \ + decl(mimpid , ImpId , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \ + decl(satp_mode , SATP , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \ + decl(unaligned_scalar , UnalignedScalar , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \ + decl(unaligned_vector , UnalignedVector , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \ + decl(zicboz_block_size, ZicbozBlockSize , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \ + + #define DECLARE_RV_NON_EXT_FEATURE(NAME, PRETTY, LINUX_BIT, FSTRING, FLAGF) \ + struct NAME##RVNonExtFeatureValue : public RVNonExtFeatureValue { \ + NAME##RVNonExtFeatureValue() : \ + RVNonExtFeatureValue(#PRETTY, LINUX_BIT, FSTRING) {} \ + FLAGF; \ + }; \ + static NAME##RVNonExtFeatureValue NAME; \ + + RV_NON_EXT_FEATURE_FLAGS(DECLARE_RV_NON_EXT_FEATURE) + #undef DECLARE_RV_NON_EXT_FEATURE + +private: + // Utility for AOT CPU feature store/check. + class RVExtFeatures : public CHeapObj { + public: + enum RVFeatureIndex { + #define DECLARE_RV_FEATURE_ENUM(NAME, PRETTY, LINUX_BIT, FSTRING, FLAGF) CPU_##NAME, + + RV_EXT_FEATURE_FLAGS(DECLARE_RV_FEATURE_ENUM) + MAX_CPU_FEATURE_INDEX + #undef DECLARE_RV_FEATURE_ENUM + }; + private: + uint64_t _features_bitmap[(MAX_CPU_FEATURE_INDEX / BitsPerLong) + 1]; + STATIC_ASSERT(sizeof(_features_bitmap) * BitsPerByte >= MAX_CPU_FEATURE_INDEX); + + // Number of 8-byte elements in _features_bitmap. + constexpr static int element_count() { + return sizeof(_features_bitmap) / sizeof(uint64_t); + } + + static int element_index(RVFeatureIndex feature) { + int idx = feature / BitsPerLong; + assert(idx < element_count(), "Features array index out of bounds"); + return idx; + } + + static uint64_t feature_bit(RVFeatureIndex feature) { + return (1ULL << (feature % BitsPerLong)); + } + + static RVFeatureIndex convert(uint32_t index) { + assert(index < MAX_CPU_FEATURE_INDEX, "must"); + return (RVFeatureIndex)index; + } + + public: + static RVExtFeatures* current() { + return _rv_ext_features; + } + + RVExtFeatures() { + for (int i = 0; i < element_count(); i++) { + _features_bitmap[i] = 0; + } + } + + void set_feature(uint32_t feature) { + RVFeatureIndex f = convert(feature); + int idx = element_index(f); + _features_bitmap[idx] |= feature_bit(f); + } + + void clear_feature(uint32_t feature) { + RVFeatureIndex f = convert(feature); + int idx = element_index(f); + _features_bitmap[idx] &= ~feature_bit(f); + } + + bool support_feature(uint32_t feature) { + RVFeatureIndex f = convert(feature); + int idx = element_index(f); + return (_features_bitmap[idx] & feature_bit(f)) != 0; + } + }; // enable extensions based on profile, current supported profiles: // RVA20U64 @@ -276,16 +434,24 @@ class VM_Version : public Abstract_VM_Version { static VM_MODE parse_satp_mode(const char* vm_mode); // Values from riscv_hwprobe() - enum UNALIGNED_ACCESS : int { - MISALIGNED_UNKNOWN = 0, - MISALIGNED_EMULATED = 1, - MISALIGNED_SLOW = 2, - MISALIGNED_FAST = 3, - MISALIGNED_UNSUPPORTED = 4 + enum UNALIGNED_SCALAR_ACCESS : int { + MISALIGNED_SCALAR_UNKNOWN = 0, + MISALIGNED_SCALAR_EMULATED = 1, + MISALIGNED_SCALAR_SLOW = 2, + MISALIGNED_SCALAR_FAST = 3, + MISALIGNED_SCALAR_UNSUPPORTED = 4 + }; + + enum UNALIGNED_VECTOR_ACCESS : int { + MISALIGNED_VECTOR_UNKNOWN = 0, + MISALIGNED_VECTOR_SLOW = 2, + MISALIGNED_VECTOR_FAST = 3, + MISALIGNED_VECTOR_UNSUPPORTED = 4 }; // Null terminated list static RVFeatureValue* _feature_list[]; + static RVExtFeatures* _rv_ext_features; // Enables features in _feature_list static void setup_cpu_available_features(); diff --git a/src/hotspot/cpu/s390/c1_CodeStubs_s390.cpp b/src/hotspot/cpu/s390/c1_CodeStubs_s390.cpp index 68e7114b3b6..f1272ee1a22 100644 --- a/src/hotspot/cpu/s390/c1_CodeStubs_s390.cpp +++ b/src/hotspot/cpu/s390/c1_CodeStubs_s390.cpp @@ -234,12 +234,10 @@ void MonitorEnterStub::emit_code(LIR_Assembler* ce) { void MonitorExitStub::emit_code(LIR_Assembler* ce) { __ bind(_entry); // Move address of the BasicObjectLock into Z_R1_scratch. - if (_compute_lock) { - // Lock_reg was destroyed by fast unlocking attempt => recompute it. - ce->monitor_address(_monitor_ix, FrameMap::as_opr(Z_R1_scratch)); - } else { - __ lgr_if_needed(Z_R1_scratch, _lock_reg->as_register()); - } + + // Lock_reg was destroyed by fast unlocking attempt => recompute it. + ce->monitor_address(_monitor_ix, FrameMap::as_opr(Z_R1_scratch)); + // Note: non-blocking leaf routine => no call info needed. StubId exit_id; if (ce->compilation()->has_fpu_code()) { diff --git a/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp b/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp index b875eeca9ad..298234156c3 100644 --- a/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp @@ -228,7 +228,7 @@ int LIR_Assembler::emit_unwind_handler() { // StubId::c1_monitorexit_id expects lock address in Z_R1_scratch. LIR_Opr lock = FrameMap::as_opr(Z_R1_scratch); monitor_address(0, lock); - stub = new MonitorExitStub(lock, true, 0); + stub = new MonitorExitStub(lock, 0); __ unlock_object(Rtmp1, Rtmp2, lock->as_register(), *stub->entry()); __ bind(*stub->continuation()); } @@ -2711,7 +2711,6 @@ void LIR_Assembler::emit_lock(LIR_OpLock* op) { Register hdr = op->hdr_opr()->as_register(); Register lock = op->lock_opr()->as_register(); if (op->code() == lir_lock) { - 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) { add_debug_info_for_null_check_here(op->info()); @@ -2719,7 +2718,6 @@ void LIR_Assembler::emit_lock(LIR_OpLock* op) { __ lock_object(hdr, obj, lock, *op->stub()->entry()); // done } else if (op->code() == lir_unlock) { - 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 { ShouldNotReachHere(); diff --git a/src/hotspot/cpu/s390/c2_globals_s390.hpp b/src/hotspot/cpu/s390/c2_globals_s390.hpp index 94190c25f5b..f1e757889b0 100644 --- a/src/hotspot/cpu/s390/c2_globals_s390.hpp +++ b/src/hotspot/cpu/s390/c2_globals_s390.hpp @@ -45,8 +45,7 @@ define_pd_global(intx, CompileThreshold, 10000); define_pd_global(intx, OnStackReplacePercentage, 140); define_pd_global(intx, ConditionalMoveLimit, 4); define_pd_global(intx, FreqInlineSize, 175); -// 10 prevents spill-split-recycle sanity check in JVM2008.xml.transform. -define_pd_global(intx, InteriorEntryAlignment, 2); +define_pd_global(intx, InteriorEntryAlignment, 4); define_pd_global(size_t, NewSizeThreadIncrease, ScaleForWordSize(4*K)); define_pd_global(intx, RegisterCostAreaRatio, 12000); define_pd_global(intx, LoopUnrollLimit, 60); diff --git a/src/hotspot/cpu/s390/s390.ad b/src/hotspot/cpu/s390/s390.ad index 4c6b0d96e6f..e9377733d2d 100644 --- a/src/hotspot/cpu/s390/s390.ad +++ b/src/hotspot/cpu/s390/s390.ad @@ -1947,6 +1947,7 @@ bool Matcher::is_spillable_arg(int reg) { uint Matcher::int_pressure_limit() { // Medium size register set, 6 special purpose regs, 3 SOE regs. + // 10 prevents spill-split-recycle sanity check in JVM2008.xml.transform. return (INTPRESSURE == -1) ? 10 : INTPRESSURE; } diff --git a/src/hotspot/cpu/x86/assembler_x86.cpp b/src/hotspot/cpu/x86/assembler_x86.cpp index 3f1140c937b..fd62e9358bf 100644 --- a/src/hotspot/cpu/x86/assembler_x86.cpp +++ b/src/hotspot/cpu/x86/assembler_x86.cpp @@ -2225,6 +2225,44 @@ void Assembler::cvttss2sil(Register dst, XMMRegister src) { emit_int16(0x2C, (0xC0 | encode)); } +void Assembler::evcvttss2sisl(Register dst, XMMRegister src) { + assert(VM_Version::supports_avx10_2(), ""); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_is_evex_instruction(); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F3, VEX_OPCODE_MAP5, &attributes); + emit_int16(0x6D, (0xC0 | encode)); +} + +void Assembler::evcvttss2sisl(Register dst, Address src) { + assert(VM_Version::supports_avx10_2(), ""); + InstructionMark im(this); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_32bit); + attributes.set_is_evex_instruction(); + vex_prefix(src, 0, dst->encoding(), VEX_SIMD_F3, VEX_OPCODE_MAP5, &attributes); + emit_int8((unsigned char)0x6D); + emit_operand(dst, src, 0); +} + +void Assembler::evcvttss2sisq(Register dst, XMMRegister src) { + assert(VM_Version::supports_avx10_2(), ""); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_is_evex_instruction(); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F3, VEX_OPCODE_MAP5, &attributes); + emit_int16(0x6D, (0xC0 | encode)); +} + +void Assembler::evcvttss2sisq(Register dst, Address src) { + assert(VM_Version::supports_avx10_2(), ""); + InstructionMark im(this); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_32bit); + attributes.set_is_evex_instruction(); + vex_prefix(src, 0, dst->encoding(), VEX_SIMD_F3, VEX_OPCODE_MAP5, &attributes); + emit_int8((unsigned char)0x6D); + emit_operand(dst, src, 0); +} + void Assembler::cvttpd2dq(XMMRegister dst, XMMRegister src) { int vector_len = VM_Version::supports_avx512novl() ? AVX_512bit : AVX_128bit; InstructionAttr attributes(vector_len, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); @@ -2310,6 +2348,25 @@ void Assembler::vcvttps2dq(XMMRegister dst, XMMRegister src, int vector_len) { emit_int16(0x5B, (0xC0 | encode)); } +void Assembler::evcvttps2dqs(XMMRegister dst, XMMRegister src, int vector_len) { + assert(VM_Version::supports_avx10_2(), ""); + InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_MAP5, &attributes); + emit_int16(0x6D, (0xC0 | encode)); +} + +void Assembler::evcvttps2dqs(XMMRegister dst, Address src, int vector_len) { + assert(VM_Version::supports_avx10_2(), ""); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_32bit); + attributes.set_is_evex_instruction(); + vex_prefix(src, 0, dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_MAP5, &attributes); + emit_int8((unsigned char)0x6D); + emit_operand(dst, src, 0); +} + void Assembler::vcvttpd2dq(XMMRegister dst, XMMRegister src, int vector_len) { assert(vector_len <= AVX_256bit ? VM_Version::supports_avx() : VM_Version::supports_evex(), ""); InstructionAttr attributes(vector_len, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); @@ -2317,6 +2374,25 @@ void Assembler::vcvttpd2dq(XMMRegister dst, XMMRegister src, int vector_len) { emit_int16((unsigned char)0xE6, (0xC0 | encode)); } +void Assembler::evcvttpd2dqs(XMMRegister dst, XMMRegister src, int vector_len) { + assert(VM_Version::supports_avx10_2(), ""); + InstructionAttr attributes(vector_len, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_MAP5, &attributes); + emit_int16(0x6D, (0xC0 | encode)); +} + +void Assembler::evcvttpd2dqs(XMMRegister dst, Address src, int vector_len) { + assert(VM_Version::supports_avx10_2(), ""); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_64bit); + attributes.set_is_evex_instruction(); + vex_prefix(src, 0, dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_MAP5, &attributes); + emit_int8((unsigned char)0x6D); + emit_operand(dst, src, 0); +} + void Assembler::vcvtps2dq(XMMRegister dst, XMMRegister src, int vector_len) { assert(vector_len <= AVX_256bit ? VM_Version::supports_avx() : VM_Version::supports_evex(), ""); InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); @@ -2332,6 +2408,25 @@ void Assembler::evcvttps2qq(XMMRegister dst, XMMRegister src, int vector_len) { emit_int16(0x7A, (0xC0 | encode)); } +void Assembler::evcvttps2qqs(XMMRegister dst, XMMRegister src, int vector_len) { + assert(VM_Version::supports_avx10_2(), ""); + InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_MAP5, &attributes); + emit_int16(0x6D, (0xC0 | encode)); +} + +void Assembler::evcvttps2qqs(XMMRegister dst, Address src, int vector_len) { + assert(VM_Version::supports_avx10_2(), ""); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_HV, /* input_size_in_bits */ EVEX_32bit); + attributes.set_is_evex_instruction(); + vex_prefix(src, 0, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_MAP5, &attributes); + emit_int8((unsigned char)0x6D); + emit_operand(dst, src, 0); +} + void Assembler::evcvtpd2qq(XMMRegister dst, XMMRegister src, int vector_len) { assert(VM_Version::supports_avx512dq(), ""); InstructionAttr attributes(vector_len, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); @@ -2356,6 +2451,25 @@ void Assembler::evcvttpd2qq(XMMRegister dst, XMMRegister src, int vector_len) { emit_int16(0x7A, (0xC0 | encode)); } +void Assembler::evcvttpd2qqs(XMMRegister dst, XMMRegister src, int vector_len) { + assert(VM_Version::supports_avx10_2(), ""); + InstructionAttr attributes(vector_len, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_MAP5, &attributes); + emit_int16(0x6D, (0xC0 | encode)); +} + +void Assembler::evcvttpd2qqs(XMMRegister dst, Address src, int vector_len) { + assert(VM_Version::supports_avx10_2(), ""); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_64bit); + attributes.set_is_evex_instruction(); + vex_prefix(src, 0, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_MAP5, &attributes); + emit_int8((unsigned char)0x6D); + emit_operand(dst, src, 0); +} + void Assembler::evcvtqq2pd(XMMRegister dst, XMMRegister src, int vector_len) { assert(VM_Version::supports_avx512dq(), ""); InstructionAttr attributes(vector_len, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); @@ -14988,6 +15102,44 @@ void Assembler::cvttsd2siq(Register dst, Address src) { emit_operand(dst, src, 0); } +void Assembler::evcvttsd2sisl(Register dst, XMMRegister src) { + assert(VM_Version::supports_avx10_2(), ""); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_is_evex_instruction(); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_MAP5, &attributes); + emit_int16(0x6D, (0xC0 | encode)); +} + +void Assembler::evcvttsd2sisl(Register dst, Address src) { + assert(VM_Version::supports_avx10_2(), ""); + InstructionMark im(this); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_64bit); + attributes.set_is_evex_instruction(); + vex_prefix(src, 0, dst->encoding(), VEX_SIMD_F2, VEX_OPCODE_MAP5, &attributes); + emit_int8((unsigned char)0x6D); + emit_operand(dst, src, 0); +} + +void Assembler::evcvttsd2sisq(Register dst, XMMRegister src) { + assert(VM_Version::supports_avx10_2(), ""); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_is_evex_instruction(); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_MAP5, &attributes); + emit_int16(0x6D, (0xC0 | encode)); +} + +void Assembler::evcvttsd2sisq(Register dst, Address src) { + assert(VM_Version::supports_avx10_2(), ""); + InstructionMark im(this); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_64bit); + attributes.set_is_evex_instruction(); + vex_prefix(src, 0, dst->encoding(), VEX_SIMD_F2, VEX_OPCODE_MAP5, &attributes); + emit_int8((unsigned char)0x6D); + emit_operand(dst, src, 0); +} + void Assembler::cvttsd2siq(Register dst, XMMRegister src) { InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); int encode = simd_prefix_and_encode(as_XMMRegister(dst->encoding()), xnoreg, src, VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); diff --git a/src/hotspot/cpu/x86/assembler_x86.hpp b/src/hotspot/cpu/x86/assembler_x86.hpp index 99dade412b2..c863191df4c 100644 --- a/src/hotspot/cpu/x86/assembler_x86.hpp +++ b/src/hotspot/cpu/x86/assembler_x86.hpp @@ -1316,11 +1316,19 @@ class Assembler : public AbstractAssembler { void cvttsd2sil(Register dst, XMMRegister src); void cvttsd2siq(Register dst, Address src); void cvttsd2siq(Register dst, XMMRegister src); + void evcvttsd2sisl(Register dst, XMMRegister src); + void evcvttsd2sisl(Register dst, Address src); + void evcvttsd2sisq(Register dst, XMMRegister src); + void evcvttsd2sisq(Register dst, Address src); // Convert with Truncation Scalar Single-Precision Floating-Point Value to Doubleword Integer void cvttss2sil(Register dst, XMMRegister src); void cvttss2siq(Register dst, XMMRegister src); void cvtss2sil(Register dst, XMMRegister src); + void evcvttss2sisl(Register dst, XMMRegister src); + void evcvttss2sisl(Register dst, Address src); + void evcvttss2sisq(Register dst, XMMRegister src); + void evcvttss2sisq(Register dst, Address src); // Convert vector double to int void cvttpd2dq(XMMRegister dst, XMMRegister src); @@ -1332,7 +1340,11 @@ class Assembler : public AbstractAssembler { // Convert vector float to int/long void vcvtps2dq(XMMRegister dst, XMMRegister src, int vector_len); void vcvttps2dq(XMMRegister dst, XMMRegister src, int vector_len); + void evcvttps2dqs(XMMRegister dst, XMMRegister src, int vector_len); + void evcvttps2dqs(XMMRegister dst, Address src, int vector_len); void evcvttps2qq(XMMRegister dst, XMMRegister src, int vector_len); + void evcvttps2qqs(XMMRegister dst, XMMRegister src, int vector_len); + void evcvttps2qqs(XMMRegister dst, Address src, int vector_len); // Convert vector long to vector FP void evcvtqq2ps(XMMRegister dst, XMMRegister src, int vector_len); @@ -1341,9 +1353,13 @@ class Assembler : public AbstractAssembler { // Convert vector double to long void evcvtpd2qq(XMMRegister dst, XMMRegister src, int vector_len); void evcvttpd2qq(XMMRegister dst, XMMRegister src, int vector_len); + void evcvttpd2qqs(XMMRegister dst, XMMRegister src, int vector_len); + void evcvttpd2qqs(XMMRegister dst, Address src, int vector_len); // Convert vector double to int void vcvttpd2dq(XMMRegister dst, XMMRegister src, int vector_len); + void evcvttpd2dqs(XMMRegister dst, XMMRegister src, int vector_len); + void evcvttpd2dqs(XMMRegister dst, Address src, int vector_len); // Evex casts with truncation void evpmovwb(XMMRegister dst, XMMRegister src, int vector_len); diff --git a/src/hotspot/cpu/x86/c1_CodeStubs_x86.cpp b/src/hotspot/cpu/x86/c1_CodeStubs_x86.cpp index 2fd067a7749..95ce48f34db 100644 --- a/src/hotspot/cpu/x86/c1_CodeStubs_x86.cpp +++ b/src/hotspot/cpu/x86/c1_CodeStubs_x86.cpp @@ -207,10 +207,10 @@ void MonitorEnterStub::emit_code(LIR_Assembler* ce) { void MonitorExitStub::emit_code(LIR_Assembler* ce) { __ bind(_entry); - if (_compute_lock) { - // lock_reg was destroyed by fast unlocking attempt => recompute it - ce->monitor_address(_monitor_ix, _lock_reg); - } + + // lock_reg was destroyed by fast unlocking attempt => recompute it + ce->monitor_address(_monitor_ix, _lock_reg); + ce->store_parameter(_lock_reg->as_register(), 0); // note: non-blocking leaf routine => no call info needed StubId exit_id; diff --git a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp index 98759295bb1..edeb0baea0e 100644 --- a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp @@ -412,7 +412,7 @@ int LIR_Assembler::emit_unwind_handler() { MonitorExitStub* stub = nullptr; if (method()->is_synchronized()) { monitor_address(0, FrameMap::rax_opr); - stub = new MonitorExitStub(FrameMap::rax_opr, true, 0); + stub = new MonitorExitStub(FrameMap::rax_opr, 0); __ unlock_object(rdi, rsi, rax, *stub->entry()); __ bind(*stub->continuation()); } @@ -2730,7 +2730,6 @@ void LIR_Assembler::emit_lock(LIR_OpLock* op) { Register hdr = op->hdr_opr()->as_register(); Register lock = op->lock_opr()->as_register(); if (op->code() == lir_lock) { - assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header"); Register tmp = op->scratch_opr()->as_register(); // add debug info for NullPointerException only if one is possible int null_check_offset = __ lock_object(hdr, obj, lock, tmp, *op->stub()->entry()); @@ -2739,7 +2738,6 @@ void LIR_Assembler::emit_lock(LIR_OpLock* op) { } // done } else if (op->code() == lir_unlock) { - 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 { Unimplemented(); diff --git a/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp b/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp index 36efeafa940..c3d45f9d15d 100644 --- a/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp @@ -41,32 +41,32 @@ #include "utilities/checkedCast.hpp" #include "utilities/globalDefinitions.hpp" -int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr, Register tmp, Label& slow_case) { +int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register basic_lock, Register tmp, Label& slow_case) { assert(hdr == rax, "hdr must be rax, for the cmpxchg instruction"); - assert_different_registers(hdr, obj, disp_hdr, tmp); + assert_different_registers(hdr, obj, basic_lock, tmp); int null_check_offset = -1; verify_oop(obj); // save object being locked into the BasicObjectLock - movptr(Address(disp_hdr, BasicObjectLock::obj_offset()), obj); + movptr(Address(basic_lock, BasicObjectLock::obj_offset()), obj); null_check_offset = offset(); - lightweight_lock(disp_hdr, obj, hdr, tmp, slow_case); + lightweight_lock(basic_lock, obj, hdr, tmp, slow_case); return null_check_offset; } -void C1_MacroAssembler::unlock_object(Register hdr, Register obj, Register disp_hdr, Label& slow_case) { - assert(disp_hdr == rax, "disp_hdr must be rax, for the cmpxchg instruction"); - assert(hdr != obj && hdr != disp_hdr && obj != disp_hdr, "registers must be different"); +void C1_MacroAssembler::unlock_object(Register hdr, Register obj, Register basic_lock, Label& slow_case) { + assert(basic_lock == rax, "basic_lock must be rax, for the cmpxchg instruction"); + assert(hdr != obj && hdr != basic_lock && obj != basic_lock, "registers must be different"); // load object - movptr(obj, Address(disp_hdr, BasicObjectLock::obj_offset())); + movptr(obj, Address(basic_lock, BasicObjectLock::obj_offset())); verify_oop(obj); - lightweight_unlock(obj, disp_hdr, hdr, slow_case); + lightweight_unlock(obj, rax, hdr, slow_case); } diff --git a/src/hotspot/cpu/x86/c1_MacroAssembler_x86.hpp b/src/hotspot/cpu/x86/c1_MacroAssembler_x86.hpp index 6344a7b6ef1..f33e47aadb3 100644 --- a/src/hotspot/cpu/x86/c1_MacroAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/c1_MacroAssembler_x86.hpp @@ -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 @@ -46,17 +46,17 @@ void initialize_body(Register obj, Register len_in_bytes, int hdr_size_in_bytes, Register t1); // locking - // hdr : must be rax, contents destroyed - // obj : must point to the object to lock, contents preserved - // disp_hdr: must point to the displaced header location, contents preserved + // hdr : must be rax, contents destroyed + // obj : must point to the object to lock, contents preserved + // basic_lock: must point to the basic lock, contents preserved // returns code offset at which to add null check debug information - int lock_object (Register swap, Register obj, Register disp_hdr, Register tmp, Label& slow_case); + int lock_object (Register swap, Register obj, Register basic_lock, Register tmp, Label& slow_case); // unlocking - // hdr : contents destroyed - // obj : must point to the object to lock, contents preserved - // disp_hdr: must be eax & must point to the displaced header location, contents destroyed - void unlock_object(Register swap, Register obj, Register lock, Label& slow_case); + // hdr : contents destroyed + // obj : must point to the object to lock, contents preserved + // basic_lock: must be eax & must point to the basic lock, contents destroyed + void unlock_object(Register swap, Register obj, Register basic_lock, Label& slow_case); void initialize_object( Register obj, // result: pointer to object after successful allocation diff --git a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp index 8c3f33e0aca..8386e57c389 100644 --- a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp @@ -5053,12 +5053,12 @@ void C2_MacroAssembler::vector_cast_int_to_subword(BasicType to_elem_bt, XMMRegi } vpackuswb(dst, dst, zero, vec_enc); break; - default: assert(false, "%s", type2name(to_elem_bt)); + default: assert(false, "Unexpected basic type for target of vector cast int to subword: %s", type2name(to_elem_bt)); } } /* - * Algorithm for vector D2L and F2I conversions:- + * Algorithm for vector D2L and F2I conversions (AVX 10.2 unsupported):- * a) Perform vector D2L/F2I cast. * b) Choose fast path if none of the result vector lane contains 0x80000000 value. * It signifies that source value could be any of the special floating point @@ -5096,7 +5096,7 @@ void C2_MacroAssembler::vector_castF2X_evex(BasicType to_elem_bt, XMMRegister ds case T_BYTE: evpmovdb(dst, dst, vec_enc); break; - default: assert(false, "%s", type2name(to_elem_bt)); + default: assert(false, "Unexpected basic type for target of vector castF2X EVEX: %s", type2name(to_elem_bt)); } } @@ -5143,7 +5143,7 @@ void C2_MacroAssembler::vector_castD2X_evex(BasicType to_elem_bt, XMMRegister ds evpmovsqd(dst, dst, vec_enc); evpmovdb(dst, dst, vec_enc); break; - default: assert(false, "%s", type2name(to_elem_bt)); + default: assert(false, "Unexpected basic type for target of vector castD2X AVX512DQ EVEX: %s", type2name(to_elem_bt)); } } else { assert(type2aelembytes(to_elem_bt) <= 4, ""); @@ -5158,11 +5158,91 @@ void C2_MacroAssembler::vector_castD2X_evex(BasicType to_elem_bt, XMMRegister ds case T_BYTE: evpmovdb(dst, dst, vec_enc); break; - default: assert(false, "%s", type2name(to_elem_bt)); + default: assert(false, "Unexpected basic type for target of vector castD2X EVEX: %s", type2name(to_elem_bt)); } } } +void C2_MacroAssembler::vector_castF2X_avx10(BasicType to_elem_bt, XMMRegister dst, XMMRegister src, int vec_enc) { + switch(to_elem_bt) { + case T_LONG: + evcvttps2qqs(dst, src, vec_enc); + break; + case T_INT: + evcvttps2dqs(dst, src, vec_enc); + break; + case T_SHORT: + evcvttps2dqs(dst, src, vec_enc); + evpmovdw(dst, dst, vec_enc); + break; + case T_BYTE: + evcvttps2dqs(dst, src, vec_enc); + evpmovdb(dst, dst, vec_enc); + break; + default: assert(false, "Unexpected basic type for target of vector castF2X AVX10 (reg src): %s", type2name(to_elem_bt)); + } +} + +void C2_MacroAssembler::vector_castF2X_avx10(BasicType to_elem_bt, XMMRegister dst, Address src, int vec_enc) { + switch(to_elem_bt) { + case T_LONG: + evcvttps2qqs(dst, src, vec_enc); + break; + case T_INT: + evcvttps2dqs(dst, src, vec_enc); + break; + case T_SHORT: + evcvttps2dqs(dst, src, vec_enc); + evpmovdw(dst, dst, vec_enc); + break; + case T_BYTE: + evcvttps2dqs(dst, src, vec_enc); + evpmovdb(dst, dst, vec_enc); + break; + default: assert(false, "Unexpected basic type for target of vector castF2X AVX10 (mem src): %s", type2name(to_elem_bt)); + } +} + +void C2_MacroAssembler::vector_castD2X_avx10(BasicType to_elem_bt, XMMRegister dst, XMMRegister src, int vec_enc) { + switch(to_elem_bt) { + case T_LONG: + evcvttpd2qqs(dst, src, vec_enc); + break; + case T_INT: + evcvttpd2dqs(dst, src, vec_enc); + break; + case T_SHORT: + evcvttpd2dqs(dst, src, vec_enc); + evpmovdw(dst, dst, vec_enc); + break; + case T_BYTE: + evcvttpd2dqs(dst, src, vec_enc); + evpmovdb(dst, dst, vec_enc); + break; + default: assert(false, "Unexpected basic type for target of vector castD2X AVX10 (reg src): %s", type2name(to_elem_bt)); + } +} + +void C2_MacroAssembler::vector_castD2X_avx10(BasicType to_elem_bt, XMMRegister dst, Address src, int vec_enc) { + switch(to_elem_bt) { + case T_LONG: + evcvttpd2qqs(dst, src, vec_enc); + break; + case T_INT: + evcvttpd2dqs(dst, src, vec_enc); + break; + case T_SHORT: + evcvttpd2dqs(dst, src, vec_enc); + evpmovdw(dst, dst, vec_enc); + break; + case T_BYTE: + evcvttpd2dqs(dst, src, vec_enc); + evpmovdb(dst, dst, vec_enc); + break; + default: assert(false, "Unexpected basic type for target of vector castD2X AVX10 (mem src): %s", type2name(to_elem_bt)); + } +} + void C2_MacroAssembler::vector_round_double_evex(XMMRegister dst, XMMRegister src, AddressLiteral double_sign_flip, AddressLiteral new_mxcsr, int vec_enc, Register tmp, XMMRegister xtmp1, XMMRegister xtmp2, KRegister ktmp1, KRegister ktmp2) { diff --git a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp index 950fcb75290..aaee25f440a 100644 --- a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp @@ -347,6 +347,13 @@ XMMRegister xtmp2, XMMRegister xtmp3, XMMRegister xtmp4, XMMRegister xtmp5, AddressLiteral float_sign_flip, Register rscratch, int vec_enc); + void vector_castF2X_avx10(BasicType to_elem_bt, XMMRegister dst, XMMRegister src, int vec_enc); + + void vector_castF2X_avx10(BasicType to_elem_bt, XMMRegister dst, Address src, int vec_enc); + + void vector_castD2X_avx10(BasicType to_elem_bt, XMMRegister dst, XMMRegister src, int vec_enc); + + void vector_castD2X_avx10(BasicType to_elem_bt, XMMRegister dst, Address src, int vec_enc); void vector_cast_double_to_int_special_cases_avx(XMMRegister dst, XMMRegister src, XMMRegister xtmp1, XMMRegister xtmp2, XMMRegister xtmp3, XMMRegister xtmp4, XMMRegister xtmp5, Register rscratch, diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_cbrt.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_cbrt.cpp index c35f1b9f65e..73330dedc0f 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_cbrt.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_cbrt.cpp @@ -49,142 +49,142 @@ /* Represents 0x7FFFFFFFFFFFFFFF double precision in lower 64 bits*/ ATTRIBUTE_ALIGNED(16) static const juint _ABS_MASK[] = { - 4294967295, 2147483647, 0, 0 + 0xFFFFFFFFUL, 0x7FFFFFFFUL, 0x00000000UL, 0x00000000UL }; ATTRIBUTE_ALIGNED(4) static const juint _SIG_MASK[] = { - 0, 1032192 + 0x00000000UL, 0x000FC000UL }; ATTRIBUTE_ALIGNED(4) static const juint _EXP_MASK[] = { - 0, 3220176896 + 0x00000000UL, 0xBFF00000UL }; ATTRIBUTE_ALIGNED(4) static const juint _EXP_MSK2[] = { - 0, 3220193280 + 0x00000000UL, 0xBFF04000UL }; ATTRIBUTE_ALIGNED(4) static const juint _EXP_MSK3[] = { - 4294967295, 1048575 + 0xFFFFFFFFUL, 0x000FFFFFUL }; ATTRIBUTE_ALIGNED(4) static const juint _SCALE63[] = { - 0, 1138753536 + 0x00000000UL, 0x43E00000UL }; ATTRIBUTE_ALIGNED(4) static const juint _ZERON[] = { - 0, 2147483648 + 0x00000000UL, 0x80000000UL }; ATTRIBUTE_ALIGNED(4) static const juint _INF[] = { - 0, 2146435072 + 0x00000000UL, 0x7FF00000UL }; ATTRIBUTE_ALIGNED(4) static const juint _NEG_INF[] = { - 0, 4293918720 + 0x00000000UL, 0xFFF00000UL }; ATTRIBUTE_ALIGNED(16) static const juint _coeff_table[] = { - 1553778919, 3213899486, 3534952507, 3215266280, 1646371399, - 3214412045, 477218588, 3216798151, 3582521621, 1066628362, - 1007461464, 1068473053, 889629714, 1067378449, 1431655765, - 1070945621 + 0x5C9CC8E7UL, 0xBF9036DEUL, 0xD2B3183BUL, 0xBFA511E8UL, 0x6221A247UL, + 0xBF98090DUL, 0x1C71C71CUL, 0xBFBC71C7UL, 0xD588F115UL, 0x3F93750AUL, + 0x3C0CA458UL, 0x3FAF9ADDUL, 0x3506AC12UL, 0x3F9EE711UL, 0x55555555UL, + 0x3FD55555UL }; ATTRIBUTE_ALIGNED(4) static const juint _rcp_table[] = { - 528611360, 3220144632, 2884679527, 3220082993, 1991868891, 3220024928, - 2298714891, 3219970134, 58835168, 3219918343, 3035110223, 3219869313, - 1617585086, 3219822831, 2500867033, 3219778702, 4241943008, 3219736752, - 258732970, 3219696825, 404232216, 3219658776, 2172167368, 3219622476, - 1544257904, 3219587808, 377579543, 3219554664, 1616385542, 3219522945, - 813783277, 3219492562, 3940743189, 3219463431, 2689777499, 3219435478, - 1700977147, 3219408632, 3169102082, 3219382828, 327235604, 3219358008, - 1244336319, 3219334115, 1300311200, 3219311099, 3095471925, 3219288912, - 2166487928, 3219267511, 2913108253, 3219246854, 293672978, 3219226904, - 288737297, 3219207624, 1810275472, 3219188981, 174592167, 3219170945, - 3539053052, 3219153485, 2164392968, 3219136576 + 0x1F81F820UL, 0xBFEF81F8UL, 0xABF0B767UL, 0xBFEE9131UL, 0x76B981DBUL, 0xBFEDAE60UL, + 0x89039B0BUL, 0xBFECD856UL, 0x0381C0E0UL, 0xBFEC0E07UL, 0xB4E81B4FUL, 0xBFEB4E81UL, + 0x606A63BEUL, 0xBFEA98EFUL, 0x951033D9UL, 0xBFE9EC8EUL, 0xFCD6E9E0UL, 0xBFE948B0UL, + 0x0F6BF3AAUL, 0xBFE8ACB9UL, 0x18181818UL, 0xBFE81818UL, 0x8178A4C8UL, 0xBFE78A4CUL, + 0x5C0B8170UL, 0xBFE702E0UL, 0x16816817UL, 0xBFE68168UL, 0x60581606UL, 0xBFE60581UL, + 0x308158EDUL, 0xBFE58ED2UL, 0xEAE2F815UL, 0xBFE51D07UL, 0xA052BF5BUL, 0xBFE4AFD6UL, + 0x6562D9FBUL, 0xBFE446F8UL, 0xBCE4A902UL, 0xBFE3E22CUL, 0x13813814UL, 0xBFE38138UL, + 0x4A2B10BFUL, 0xBFE323E3UL, 0x4D812CA0UL, 0xBFE2C9FBUL, 0xB8812735UL, 0xBFE27350UL, + 0x8121FB78UL, 0xBFE21FB7UL, 0xADA2811DUL, 0xBFE1CF06UL, 0x11811812UL, 0xBFE18118UL, + 0x1135C811UL, 0xBFE135C8UL, 0x6BE69C90UL, 0xBFE0ECF5UL, 0x0A6810A7UL, 0xBFE0A681UL, + 0xD2F1A9FCUL, 0xBFE0624DUL, 0x81020408UL, 0xBFE02040UL }; ATTRIBUTE_ALIGNED(4) static const juint _cbrt_table[] = { - 572345495, 1072698681, 1998204467, 1072709382, 3861501553, 1072719872, - 2268192434, 1072730162, 2981979308, 1072740260, 270859143, 1072750176, - 2958651392, 1072759916, 313113243, 1072769490, 919449400, 1072778903, - 2809328903, 1072788162, 2222981587, 1072797274, 2352530781, 1072806244, - 594152517, 1072815078, 1555767199, 1072823780, 4282421314, 1072832355, - 2355578597, 1072840809, 1162590619, 1072849145, 797864051, 1072857367, - 431273680, 1072865479, 2669831148, 1072873484, 733477752, 1072881387, - 4280220604, 1072889189, 801961634, 1072896896, 2915370760, 1072904508, - 1159613482, 1072912030, 2689944798, 1072919463, 1248687822, 1072926811, - 2967951030, 1072934075, 630170432, 1072941259, 3760898254, 1072948363, - 0, 1072955392, 2370273294, 1072962345, 1261754802, 1072972640, - 546334065, 1072986123, 1054893830, 1072999340, 1571187597, 1073012304, - 1107975175, 1073025027, 3606909377, 1073037519, 1113616747, 1073049792, - 4154744632, 1073061853, 3358931423, 1073073713, 4060702372, 1073085379, - 747576176, 1073096860, 3023138255, 1073108161, 1419988548, 1073119291, - 1914185305, 1073130255, 294389948, 1073141060, 3761802570, 1073151710, - 978281566, 1073162213, 823148820, 1073172572, 2420954441, 1073182792, - 3815449908, 1073192878, 2046058587, 1073202835, 1807524753, 1073212666, - 2628681401, 1073222375, 3225667357, 1073231966, 1555307421, 1073241443, - 3454043099, 1073250808, 1208137896, 1073260066, 3659916772, 1073269218, - 1886261264, 1073278269, 3593647839, 1073287220, 3086012205, 1073296075, - 2769796922, 1073304836, 888716057, 1073317807, 2201465623, 1073334794, - 164369365, 1073351447, 3462666733, 1073367780, 2773905457, 1073383810, - 1342879088, 1073399550, 2543933975, 1073415012, 1684477781, 1073430209, - 3532178543, 1073445151, 1147747300, 1073459850, 1928031793, 1073474314, - 2079717015, 1073488553, 4016765315, 1073502575, 3670431139, 1073516389, - 3549227225, 1073530002, 11637607, 1073543422, 588220169, 1073556654, - 2635407503, 1073569705, 2042029317, 1073582582, 1925128962, 1073595290, - 4136375664, 1073607834, 759964600, 1073620221, 4257606771, 1073632453, - 297278907, 1073644538, 3655053093, 1073656477, 2442253172, 1073668277, - 1111876799, 1073679941, 3330973139, 1073691472, 3438879452, 1073702875, - 3671565478, 1073714153, 1317849547, 1073725310, 1642364115, 1073736348 + 0x221D4C97UL, 0x3FF01539UL, 0x771A2E33UL, 0x3FF03F06UL, 0xE629D671UL, 0x3FF06800UL, + 0x8731DEB2UL, 0x3FF09032UL, 0xB1BD64ACUL, 0x3FF0B7A4UL, 0x1024FB87UL, 0x3FF0DE60UL, + 0xB0597000UL, 0x3FF1046CUL, 0x12A9BA9BUL, 0x3FF129D2UL, 0x36CDAF38UL, 0x3FF14E97UL, + 0xA772F507UL, 0x3FF172C2UL, 0x848001D3UL, 0x3FF1965AUL, 0x8C38C55DUL, 0x3FF1B964UL, + 0x236A0C45UL, 0x3FF1DBE6UL, 0x5CBB1F9FUL, 0x3FF1FDE4UL, 0xFF409042UL, 0x3FF21F63UL, + 0x8C6746E5UL, 0x3FF24069UL, 0x454BB99BUL, 0x3FF260F9UL, 0x2F8E7073UL, 0x3FF28117UL, + 0x19B4B6D0UL, 0x3FF2A0C7UL, 0x9F2263ECUL, 0x3FF2C00CUL, 0x2BB7FB78UL, 0x3FF2DEEBUL, + 0xFF1EFBBCUL, 0x3FF2FD65UL, 0x2FCCF6A2UL, 0x3FF31B80UL, 0xADC50708UL, 0x3FF3393CUL, + 0x451E4C2AUL, 0x3FF3569EUL, 0xA0554CDEUL, 0x3FF373A7UL, 0x4A6D76CEUL, 0x3FF3905BUL, + 0xB0E756B6UL, 0x3FF3ACBBUL, 0x258FA340UL, 0x3FF3C8CBUL, 0xE02AC0CEUL, 0x3FF3E48BUL, + 0x00000000UL, 0x3FF40000UL, 0x8D47800EUL, 0x3FF41B29UL, 0x4B34D9B2UL, 0x3FF44360UL, + 0x20906571UL, 0x3FF4780BUL, 0x3EE06706UL, 0x3FF4ABACUL, 0x5DA66B8DUL, 0x3FF4DE50UL, + 0x420A5C07UL, 0x3FF51003UL, 0xD6FD11C1UL, 0x3FF540CFUL, 0x4260716BUL, 0x3FF570C0UL, + 0xF7A45F38UL, 0x3FF59FDDUL, 0xC83539DFUL, 0x3FF5CE31UL, 0xF20966A4UL, 0x3FF5FBC3UL, + 0x2C8F1B70UL, 0x3FF6289CUL, 0xB4316DCFUL, 0x3FF654C1UL, 0x54A34E44UL, 0x3FF6803BUL, + 0x72182659UL, 0x3FF6AB0FUL, 0x118C08BCUL, 0x3FF6D544UL, 0xE0388D4AUL, 0x3FF6FEDEUL, + 0x3A4F645EUL, 0x3FF727E5UL, 0x31104114UL, 0x3FF7505CUL, 0x904CD549UL, 0x3FF77848UL, + 0xE36B2534UL, 0x3FF79FAEUL, 0x79F4605BUL, 0x3FF7C693UL, 0x6BBCA391UL, 0x3FF7ECFAUL, + 0x9CAE7EB9UL, 0x3FF812E7UL, 0xC043C71DUL, 0x3FF8385EUL, 0x5CB41B9DUL, 0x3FF85D63UL, + 0xCDE083DBUL, 0x3FF881F8UL, 0x4802B8A8UL, 0x3FF8A622UL, 0xDA25E5E4UL, 0x3FF8C9E2UL, + 0x706E1010UL, 0x3FF8ED3DUL, 0xD632B6DFUL, 0x3FF91034UL, 0xB7F0CF2DUL, 0x3FF932CBUL, + 0xA517BF3AUL, 0x3FF95504UL, 0x34F8BB19UL, 0x3FF987AFUL, 0x8337B317UL, 0x3FF9CA0AUL, + 0x09CC13D5UL, 0x3FFA0B17UL, 0xCE6419EDUL, 0x3FFA4AE4UL, 0xA5567031UL, 0x3FFA8982UL, + 0x500AB570UL, 0x3FFAC6FEUL, 0x97A15A17UL, 0x3FFB0364UL, 0x64671755UL, 0x3FFB3EC1UL, + 0xD288C46FUL, 0x3FFB791FUL, 0x44693BE4UL, 0x3FFBB28AUL, 0x72EB6E31UL, 0x3FFBEB0AUL, + 0x7BF5F697UL, 0x3FFC22A9UL, 0xEF6AF983UL, 0x3FFC596FUL, 0xDAC655A3UL, 0x3FFC8F65UL, + 0xD38CE8D9UL, 0x3FFCC492UL, 0x00B19367UL, 0x3FFCF8FEUL, 0x230F8709UL, 0x3FFD2CAEUL, + 0x9D15208FUL, 0x3FFD5FA9UL, 0x79B6E505UL, 0x3FFD91F6UL, 0x72BF2302UL, 0x3FFDC39AUL, + 0xF68C1570UL, 0x3FFDF49AUL, 0x2D4C23B8UL, 0x3FFE24FDUL, 0xFDC5EC73UL, 0x3FFE54C5UL, + 0x11B81DBBUL, 0x3FFE83FAUL, 0xD9DBAF25UL, 0x3FFEB29DUL, 0x9191D374UL, 0x3FFEE0B5UL, + 0x4245E4BFUL, 0x3FFF0E45UL, 0xC68A9DD3UL, 0x3FFF3B50UL, 0xCCF922DCUL, 0x3FFF67DBUL, + 0xDAD7A4A6UL, 0x3FFF93E9UL, 0x4E8CC9CBUL, 0x3FFFBF7EUL, 0x61E47CD3UL, 0x3FFFEA9CUL }; ATTRIBUTE_ALIGNED(4) static const juint _D_table[] = { - 4050900474, 1014427190, 1157977860, 1016444461, 1374568199, 1017271387, - 2809163288, 1016882676, 3742377377, 1013168191, 3101606597, 1017541672, - 65224358, 1017217597, 2691591250, 1017266643, 4020758549, 1017689313, - 1316310992, 1018030788, 1031537856, 1014090882, 3261395239, 1016413641, - 886424999, 1016313335, 3114776834, 1014195875, 1681120620, 1017825416, - 1329600273, 1016625740, 465474623, 1017097119, 4251633980, 1017169077, - 1986990133, 1017710645, 752958613, 1017159641, 2216216792, 1018020163, - 4282860129, 1015924861, 1557627859, 1016039538, 3889219754, 1018086237, - 3684996408, 1017353275, 723532103, 1017717141, 2951149676, 1012528470, - 831890937, 1017830553, 1031212645, 1017387331, 2741737450, 1017604974, - 2863311531, 1003776682, 4276736099, 1013153088, 4111778382, 1015673686, - 1728065769, 1016413986, 2708718031, 1018078833, 1069335005, 1015291224, - 700037144, 1016482032, 2904566452, 1017226861, 4074156649, 1017622651, - 25019565, 1015245366, 3601952608, 1015771755, 3267129373, 1017904664, - 503203103, 1014921629, 2122011730, 1018027866, 3927295461, 1014189456, - 2790625147, 1016024251, 1330460186, 1016940346, 4033568463, 1015538390, - 3695818227, 1017509621, 257573361, 1017208868, 3227697852, 1017337964, - 234118548, 1017169577, 4009025803, 1017278524, 1948343394, 1017749310, - 678398162, 1018144239, 3083864863, 1016669086, 2415453452, 1017890370, - 175467344, 1017330033, 3197359580, 1010339928, 2071276951, 1015941358, - 268372543, 1016737773, 938132959, 1017389108, 1816750559, 1017337448, - 4119203749, 1017152174, 2578653878, 1013108497, 2470331096, 1014678606, - 123855735, 1016553320, 1265650889, 1014782687, 3414398172, 1017182638, - 1040773369, 1016158401, 3483628886, 1016886550, 4140499405, 1016191425, - 3893477850, 1016964495, 3935319771, 1009634717, 2978982660, 1015027112, - 2452709923, 1017990229, 3190365712, 1015835149, 4237588139, 1015832925, - 2610678389, 1017962711, 2127316774, 1017405770, 824267502, 1017959463, - 2165924042, 1017912225, 2774007076, 1013257418, 4123916326, 1017582284, - 1976417958, 1016959909, 4092806412, 1017711279, 119251817, 1015363631, - 3475418768, 1017675415, 1972580503, 1015470684, 815541017, 1017517969, - 2429917451, 1017397776, 4062888482, 1016749897, 68284153, 1017925678, - 2207779246, 1016320298, 1183466520, 1017408657, 143326427, 1017060403 + 0xF173D5FAUL, 0x3C76EE36UL, 0x45055704UL, 0x3C95B62DUL, 0x51EE3F07UL, 0x3CA2545BUL, + 0xA7706E18UL, 0x3C9C65F4UL, 0xDF1025A1UL, 0x3C63B83FUL, 0xB8DEC2C5UL, 0x3CA67428UL, + 0x03E33EA6UL, 0x3CA1823DUL, 0xA06E6C52UL, 0x3CA241D3UL, 0xEFA7E815UL, 0x3CA8B4E1UL, + 0x4E754FD0UL, 0x3CADEAC4UL, 0x3D7C04C0UL, 0x3C71CC82UL, 0xC264F127UL, 0x3C953DC9UL, + 0x34D5C5A7UL, 0x3C93B5F7UL, 0xB9A7B902UL, 0x3C7366A3UL, 0x6433DD6CUL, 0x3CAAC888UL, + 0x4F401711UL, 0x3C987A4CUL, 0x1BBE943FUL, 0x3C9FAB9FUL, 0xFD6AC93CUL, 0x3CA0C4B5UL, + 0x766F1035UL, 0x3CA90835UL, 0x2CE13C95UL, 0x3CA09FD9UL, 0x8418C8D8UL, 0x3CADC143UL, + 0xFF474261UL, 0x3C8DC87DUL, 0x5CD783D3UL, 0x3C8F8872UL, 0xE7D0C8AAUL, 0x3CAEC35DUL, + 0xDBA49538UL, 0x3CA3943BUL, 0x2B203947UL, 0x3CA92195UL, 0xAFE6F86CUL, 0x3C59F556UL, + 0x3195A5F9UL, 0x3CAADC99UL, 0x3D770E65UL, 0x3CA41943UL, 0xA36B97EAUL, 0x3CA76B6EUL, + 0xAAAAAAABUL, 0x3BD46AAAUL, 0xFEE9D063UL, 0x3C637D40UL, 0xF514C24EUL, 0x3C89F356UL, + 0x670030E9UL, 0x3C953F22UL, 0xA173C1CFUL, 0x3CAEA671UL, 0x3FBCC1DDUL, 0x3C841D58UL, + 0x29B9B818UL, 0x3C9648F0UL, 0xAD202AB4UL, 0x3CA1A66DUL, 0xF2D6B269UL, 0x3CA7B07BUL, + 0x017DC4ADUL, 0x3C836A36UL, 0xD6B16F60UL, 0x3C8B726BUL, 0xC2BC701DUL, 0x3CABFE18UL, + 0x1DFE451FUL, 0x3C7E799DUL, 0x7E7B5452UL, 0x3CADDF5AUL, 0xEA15C5E5UL, 0x3C734D90UL, + 0xA6558F7BUL, 0x3C8F4CBBUL, 0x4F4D361AUL, 0x3C9D473AUL, 0xF06B5ECFUL, 0x3C87E2D6UL, + 0xDC49B5F3UL, 0x3CA5F6F5UL, 0x0F5A41F1UL, 0x3CA16024UL, 0xC062C2BCUL, 0x3CA3586CUL, + 0x0DF45D94UL, 0x3CA0C6A9UL, 0xEEF4E10BUL, 0x3CA2703CUL, 0x74215C62UL, 0x3CA99F3EUL, + 0x286F88D2UL, 0x3CAFA5EFUL, 0xB7D00B1FUL, 0x3C99239EUL, 0x8FF8E50CUL, 0x3CABC642UL, + 0x0A756B50UL, 0x3CA33971UL, 0xBE93D5DCUL, 0x3C389058UL, 0x7B752D97UL, 0x3C8E08EEUL, + 0x0FFF0A3FUL, 0x3C9A2FEDUL, 0x37EAC5DFUL, 0x3CA42034UL, 0x6C4969DFUL, 0x3CA35668UL, + 0xF5860FA5UL, 0x3CA082AEUL, 0x99B322B6UL, 0x3C62CF11UL, 0x933E42D8UL, 0x3C7AC44EUL, + 0x0761E377UL, 0x3C975F68UL, 0x4B704CC9UL, 0x3C7C5ADFUL, 0xCB8394DCUL, 0x3CA0F9AEUL, + 0x3E08F0F9UL, 0x3C9158C1UL, 0xCFA3F556UL, 0x3C9C7516UL, 0xF6CB01CDUL, 0x3C91D9C1UL, + 0xE811C1DAUL, 0x3C9DA58FUL, 0xEA9036DBUL, 0x3C2DCD9DUL, 0xB18FAB04UL, 0x3C8015A8UL, + 0x92316223UL, 0x3CAD4C55UL, 0xBE291E10UL, 0x3C8C6A0DUL, 0xFC9476ABUL, 0x3C8C615DUL, + 0x9B9BCA75UL, 0x3CACE0D7UL, 0x7ECC4726UL, 0x3CA4614AUL, 0x312152EEUL, 0x3CACD427UL, + 0x811960CAUL, 0x3CAC1BA1UL, 0xA557FD24UL, 0x3C6514CAUL, 0xF5CDF826UL, 0x3CA712CCUL, + 0x75CDBEA6UL, 0x3C9D93A5UL, 0xF3F3450CUL, 0x3CA90AAFUL, 0x071BA369UL, 0x3C85382FUL, + 0xCF26AE90UL, 0x3CA87E97UL, 0x75933097UL, 0x3C86DA5CUL, 0x309C2B19UL, 0x3CA61791UL, + 0x90D5990BUL, 0x3CA44210UL, 0xF22AC222UL, 0x3C9A5F49UL, 0x0411EEF9UL, 0x3CAC502EUL, + 0x839809AEUL, 0x3C93D12AUL, 0x468A4418UL, 0x3CA46C91UL, 0x088AFCDBUL, 0x3C9F1C33UL }; #define __ _masm-> diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_tanh.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_tanh.cpp index 372c4898f37..dce4fbfc455 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_tanh.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_tanh.cpp @@ -77,226 +77,226 @@ ATTRIBUTE_ALIGNED(4) static const juint _HALFMASK[] = { - 4160749568, 2147483647 + 0xF8000000UL, 0x7FFFFFFFUL }; ATTRIBUTE_ALIGNED(4) static const juint _ONEMASK[] = { - 0, 1072693248 + 0x00000000UL, 0x3FF00000UL }; ATTRIBUTE_ALIGNED(4) static const juint _TWOMASK[] = { - 0, 1073741824 + 0x00000000UL, 0x40000000UL }; ATTRIBUTE_ALIGNED(16) static const juint _MASK3[] = { - 0, 4294967280, 0, 4294967280 + 0x00000000UL, 0xFFFFFFF0UL, 0x00000000UL, 0xFFFFFFF0UL }; ATTRIBUTE_ALIGNED(16) static const juint _RMASK[] = { - 4294705152, 4294967295, 4294705152, 4294967295 + 0xFFFC0000UL, 0xFFFFFFFFUL, 0xFFFC0000UL, 0xFFFFFFFFUL }; ATTRIBUTE_ALIGNED(16) static const juint _L2E[] = { - 1610612736, 1082594631, 4166901572, 1055174155 + 0x60000000UL, 0x40871547UL, 0xF85DDF44UL, 0x3EE4AE0BUL }; ATTRIBUTE_ALIGNED(16) static const juint _Shifter[] = { - 0, 1127743488, 0, 3275227136 + 0x00000000UL, 0x43380000UL, 0x00000000UL, 0xC3380000UL }; ATTRIBUTE_ALIGNED(16) static const juint _cv[] = { - 3884607281, 3168131199, 3607404735, 3190582024, 1874480759, - 1032041131, 4286760334, 1053736893, 4277811695, 3211144770, - 0, 0 + 0xE78A6731UL, 0xBCD5D87FUL, 0xD704A0BFUL, 0xBE2C6B08UL, 0x6FBA4E77UL, + 0x3D83B2ABUL, 0xFF82C58EUL, 0x3ECEBFBDUL, 0xFEFA39EFUL, 0xBF662E42UL, + 0x00000000UL, 0x00000000UL }; ATTRIBUTE_ALIGNED(4) static const juint _pv[] = { - 236289503, 1064135997, 463583772, 3215696314, 1441186365, - 3212977891, 286331153, 1069617425, 2284589306, 1066820852, - 1431655765, 3218429269 + 0x0E157DDFUL, 0x3F6D6D3DUL, 0x1BA1BA1CUL, 0xBFABA1BAUL, 0x55E6C23DUL, + 0xBF8226E3UL, 0x11111111UL, 0x3FC11111UL, 0x882C10FAUL, 0x3F9664F4UL, + 0x55555555UL, 0xBFD55555UL }; ATTRIBUTE_ALIGNED(16) static const juint _T2_neg_f[] = { - 0, 1072693248, 0, 0, 1797923801, 1072687577, - 1950547427, 1013229059, 730821105, 1072681922, 2523232743, 1012067188, - 915592468, 1072676282, 352947894, 3161024371, 2174652632, 1072670657, - 4087714590, 1014450259, 35929225, 1072665048, 2809788041, 3159436968, - 2912730644, 1072659453, 3490067722, 3163405074, 2038973688, 1072653874, - 892941374, 1016046459, 1533953344, 1072648310, 769171851, 1015665633, - 1222472308, 1072642761, 1054357470, 3161021018, 929806999, 1072637227, - 3205336643, 1015259557, 481706282, 1072631708, 1696079173, 3162710528, - 3999357479, 1072626203, 2258941616, 1015924724, 2719515920, 1072620714, - 2760332941, 1015137933, 764307441, 1072615240, 3021057420, 3163329523, - 2256325230, 1072609780, 580117746, 1015317295, 2728693978, 1072604335, - 396109971, 3163462691, 2009970496, 1072598905, 2159039665, 3162572948, - 4224142467, 1072593489, 3389820386, 1015207202, 610758006, 1072588089, - 1965209397, 3161866232, 3884662774, 1072582702, 2158611599, 1014210185, - 991358482, 1072577331, 838715019, 3163157668, 351641897, 1072571974, - 2172261526, 3163010599, 1796832535, 1072566631, 3176955716, 3160585513, - 863738719, 1072561303, 1326992220, 3162613197, 1679558232, 1072555989, - 2390342287, 3163333970, 4076975200, 1072550689, 2029000899, 1015208535, - 3594158869, 1072545404, 2456521700, 3163256561, 64696965, 1072540134, - 1768797490, 1015816960, 1912561781, 1072534877, 3147495102, 1015678253, - 382305176, 1072529635, 2347622376, 3162578625, 3898795731, 1072524406, - 1249994144, 1011869818, 3707479175, 1072519192, 3613079303, 1014164738, - 3939148246, 1072513992, 3210352148, 1015274323, 135105010, 1072508807, - 1906148728, 3163375739, 721996136, 1072503635, 563754734, 1015371318, - 1242007932, 1072498477, 1132034716, 3163339831, 1532734324, 1072493333, - 3094216535, 3163162857, 1432208378, 1072488203, 1401068914, 3162363963, - 778901109, 1072483087, 2248183955, 3161268751, 3706687593, 1072477984, - 3521726940, 1013253067, 1464976603, 1072472896, 3507292405, 3161977534, - 2483480501, 1072467821, 1216371780, 1013034172, 2307442995, 1072462760, - 3190117721, 3162404539, 777507147, 1072457713, 4282924205, 1015187533, - 2029714210, 1072452679, 613660079, 1015099143, 1610600570, 1072447659, - 3766732298, 1015760183, 3657065772, 1072442652, 399025623, 3162957078, - 3716502172, 1072437659, 2303740125, 1014042725, 1631695677, 1072432680, - 2717633076, 3162344026, 1540824585, 1072427714, 1064017011, 3163487690, - 3287523847, 1072422761, 1625971539, 3157009955, 2420883922, 1072417822, - 2049810052, 1014119888, 3080351519, 1072412896, 3379126788, 3157218001, - 815859274, 1072407984, 240396590, 3163487443, 4062661092, 1072403084, - 1422616006, 3163255318, 4076559943, 1072398198, 2119478331, 3160758351, - 703710506, 1072393326, 1384660846, 1015195891, 2380618042, 1072388466, - 3149557219, 3163320799, 364333489, 1072383620, 3923737744, 3161421373, - 3092190715, 1072378786, 814012168, 3159523422, 1822067026, 1072373966, - 1241994956, 1015340290, 697153126, 1072369159, 1283515429, 3163283189, - 3861050111, 1072364364, 254893773, 3162813180, 2572866477, 1072359583, - 878562433, 1015521741, 977020788, 1072354815, 3065100517, 1015541563, - 3218338682, 1072350059, 3404164304, 3162477108, 557149882, 1072345317, - 3672720709, 1014537265, 1434058175, 1072340587, 251133233, 1015085769, - 1405169241, 1072335870, 2998539689, 3162830951, 321958744, 1072331166, - 3401933767, 1015794558, 2331271250, 1072326474, 812057446, 1012207446, - 2990417245, 1072321795, 3683467745, 3163369326, 2152073944, 1072317129, - 1486860576, 3163203456, 3964284211, 1072312475, 2111583915, 1015427164, - 3985553595, 1072307834, 4002146062, 1015834136, 2069751141, 1072303206, - 1562170675, 3162724681, 2366108318, 1072298590, 2867985102, 3161762254, - 434316067, 1072293987, 2028358766, 1013458122, 424392917, 1072289396, - 2749202995, 3162838718, 2191782032, 1072284817, 2960257726, 1013742662, - 1297350157, 1072280251, 1308022040, 3163412558, 1892288442, 1072275697, - 2446255666, 3162600381, 3833209506, 1072271155, 2722920684, 1013754842, - 2682146384, 1072266626, 2082178513, 3163363419, 2591453363, 1072262109, - 2132396182, 3159074198, 3418903055, 1072257604, 2527457337, 3160820604, - 727685349, 1072253112, 2038246809, 3162358742, 2966275557, 1072248631, - 2176155324, 3159842759, 1403662306, 1072244163, 2788809599, 3161671007, - 194117574, 1072239707, 777528612, 3163412089, 3492293770, 1072235262, - 2248032210, 1015386826, 2568320822, 1072230830, 2732824428, 1014352915, - 1577608921, 1072226410, 1875489510, 3162968394, 380978316, 1072222002, - 854188970, 3160462686, 3134592888, 1072217605, 4232266862, 1015991134, - 1110089947, 1072213221, 1451641639, 1015474673, 2759350287, 1072208848, - 1148526634, 1015894933, 3649726105, 1072204487, 4085036346, 1015649474, - 3643909174, 1072200138, 3537586109, 1014354647, 2604962541, 1072195801, - 2614425274, 3163539192, 396319521, 1072191476, 4172420816, 3159074632, - 1176749997, 1072187162, 2738998779, 3162035844, 515457527, 1072182860, - 836709333, 1015651226, 2571947539, 1072178569, 3558159064, 3163376669, - 2916157145, 1072174290, 219487565, 1015309367, 1413356050, 1072170023, - 1651349291, 3162668166, 2224145553, 1072165767, 3482522030, 3161489169, - 919555682, 1072161523, 3121969534, 1012948226, 1660913392, 1072157290, - 4218599604, 1015135707, 19972402, 1072153069, 3507899862, 1016009292, - 158781403, 1072148859, 2221464712, 3163286453, 1944781191, 1072144660, - 3993278767, 3161724279, 950803702, 1072140473, 1655364926, 1015237032, - 1339972927, 1072136297, 167908909, 1015572152, 2980802057, 1072132132, - 378619896, 1015773303, 1447192521, 1072127979, 1462857171, 3162514521, - 903334909, 1072123837, 1636462108, 1015039997, 1218806132, 1072119706, - 1818613052, 3162548441, 2263535754, 1072115586, 752233586, 3162639008, - 3907805044, 1072111477, 2257091225, 3161550407, 1727278727, 1072107380, - 3562710623, 1011471940, 4182873220, 1072103293, 629542646, 3161996303, - 2555984613, 1072099218, 2652555442, 3162552692, 1013258799, 1072095154, - 1748797611, 3160129082, 3721688645, 1072091100, 3069276937, 1015839401, - 1963711167, 1072087058, 1744767757, 3160574294, 4201977662, 1072083026, - 748330254, 1013594357, 1719614413, 1072079006, 330458198, 3163282740, - 2979960120, 1072074996, 2599109725, 1014498493, 3561793907, 1072070997, - 1157054053, 1011890350, 3339203574, 1072067009, 1483497780, 3162408754, - 2186617381, 1072063032, 2270764084, 3163272713, 4273770423, 1072059065, - 3383180809, 3163218901, 885834528, 1072055110, 1973258547, 3162261564, - 488188413, 1072051165, 3199821029, 1015564048, 2956612997, 1072047230, - 2118169751, 3162735553, 3872257780, 1072043306, 1253592103, 1015958334, - 3111574537, 1072039393, 2606161479, 3162759746, 551349105, 1072035491, - 3821916050, 3162106589, 363667784, 1072031599, 813753950, 1015785209, - 2425981843, 1072027717, 2830390851, 3163346599, 2321106615, 1072023846, - 2171176610, 1009535771, 4222122499, 1072019985, 1277378074, 3163256737, - 3712504873, 1072016135, 88491949, 1015427660, 671025100, 1072012296, - 3832014351, 3163022030, 3566716925, 1072008466, 1536826856, 1014142433, - 3689071823, 1072004647, 2321004996, 3162552716, 917841882, 1072000839, - 18715565, 1015659308, 3723038930, 1071997040, 378465264, 3162569582, - 3395129871, 1071993252, 4025345435, 3162335388, 4109806887, 1071989474, - 422403966, 1014469229, 1453150082, 1071985707, 498154669, 3161488062, - 3896463087, 1071981949, 1139797873, 3161233805, 2731501122, 1071978202, - 1774031855, 3162470021, 2135241198, 1071974465, 1236747871, 1013589147, - 1990012071, 1071970738, 3529070563, 3162813193, 2178460671, 1071967021, - 777878098, 3162842493, 2583551245, 1071963314, 3161094195, 1015606491, - 3088564500, 1071959617, 1762311517, 1015045673, 3577096743, 1071955930, - 2951496418, 1013793687, 3933059031, 1071952253, 2133366768, 3161531832, - 4040676318, 1071948586, 4090609238, 1015663458, 3784486610, 1071944929, - 1581883040, 3161698953, 3049340112, 1071941282, 3062915824, 1013170595, - 1720398391, 1071937645, 3980678963, 3163300080, 3978100823, 1071934017, - 3513027190, 1015845963, 1118294578, 1071930400, 2197495694, 3159909401, - 1617004845, 1071926792, 82804944, 1010342778, 1065662932, 1071923194, - 2533670915, 1014530238, 3645941911, 1071919605, 3814685081, 3161573341, - 654919306, 1071916027, 3232961757, 3163047469, 569847338, 1071912458, - 472945272, 3159290729, 3278348324, 1071908898, 3069497416, 1014750712, - 78413852, 1071905349, 4183226867, 3163017251, 3743175029, 1071901808, - 2072812490, 3162175075, 1276261410, 1071898278, 300981948, 1014684169, - 1156440435, 1071894757, 2351451249, 1013967056, 3272845541, 1071891245, - 928852419, 3163488248, 3219942644, 1071887743, 3798990616, 1015368806, - 887463927, 1071884251, 3596744163, 3160794166, 460407023, 1071880768, - 4237175092, 3163138469, 1829099622, 1071877294, 1016661181, 3163461005, - 589198666, 1071873830, 2664346172, 3163157962, 926591435, 1071870375, - 3208833762, 3162913514, 2732492859, 1071866929, 2691479646, 3162255684, - 1603444721, 1071863493, 1548633640, 3162201326, 1726216749, 1071860066, - 2466808228, 3161676405, 2992903935, 1071856648, 2218154406, 1015228193, - 1000925746, 1071853240, 1018491672, 3163309544, 4232894513, 1071849840, - 2383938684, 1014668519, 3991843581, 1071846450, 4092853457, 1014585763, - 171030293, 1071843070, 3526460132, 1014428778, 1253935211, 1071839698, - 1395382931, 3159702613, 2839424854, 1071836335, 1171596163, 1013041679, - 526652809, 1071832982, 4223459736, 1015879375, 2799960843, 1071829637, - 1423655381, 1015022151, 964107055, 1071826302, 2800439588, 3162833221, - 3504003472, 1071822975, 3594001060, 3157330652, 1724976915, 1071819658, - 420909223, 3163117379, 4112506593, 1071816349, 2947355221, 1014371048, - 1972484976, 1071813050, 675290301, 3161640050, 3790955393, 1071809759, - 2352942462, 3163180090, 874372905, 1071806478, 100263788, 1015940732, - 1709341917, 1071803205, 2571168217, 1014152499, 1897844341, 1071799941, - 1254300460, 1015275938, 1337108031, 1071796686, 3203724452, 1014677845, - 4219606026, 1071793439, 2434574742, 1014681548, 1853186616, 1071790202, - 3066496371, 1015656574, 2725843665, 1071786973, 1433917087, 1014838523, - 2440944790, 1071783753, 2492769774, 1014147454, 897099801, 1071780542, - 754756297, 1015241005, 2288159958, 1071777339, 2169144469, 1014876021, - 2218315341, 1071774145, 2694295388, 3163288868, 586995997, 1071770960, - 41662348, 3162627992, 1588871207, 1071767783, 143439582, 3162963416, - 828946858, 1071764615, 10642492, 1015939438, 2502433899, 1071761455, - 2148595913, 1015023991, 2214878420, 1071758304, 892270087, 3163116422, - 4162030108, 1071755161, 2763428480, 1015529349, 3949972341, 1071752027, - 2068408548, 1014913868, 1480023343, 1071748902, 2247196168, 1015327453, - 948735466, 1071745785, 3516338028, 3162574883, 2257959872, 1071742676, - 3802946148, 1012964927, 1014845819, 1071739576, 3117910646, 3161559105, - 1416741826, 1071736484, 2196380210, 1011413563, 3366293073, 1071733400, - 3119426314, 1014120554, 2471440686, 1071730325, 968836267, 3162214888, - 2930322912, 1071727258, 2599499422, 3162714047, 351405227, 1071724200, - 3125337328, 3159822479, 3228316108, 1071721149, 3010241991, 3158422804, - 2875075254, 1071718107, 4144233330, 3163333716, 3490863953, 1071715073, - 960797498, 3162948880, 685187902, 1071712048, 378731989, 1014843115, - 2952712987, 1071709030, 3293494651, 3160120301, 1608493509, 1071706021, - 3159622171, 3162807737, 852742562, 1071703020, 667253586, 1009793559, - 590962156, 1071700027, 3829346666, 3163275597, 728909815, 1071697042, - 383930225, 1015029468, 1172597893, 1071694065, 114433263, 1015347593, - 1828292879, 1071691096, 1255956747, 1015588398, 2602514713, 1071688135, - 2268929336, 1014354284, 3402036099, 1071685182, 405889334, 1015105656, - 4133881824, 1071682237, 2148155345, 3162931299, 410360776, 1071679301, - 1269990655, 1011975870, 728934454, 1071676372, 1413842688, 1014178612, - 702412510, 1071673451, 3803266087, 3162280415, 238821257, 1071670538, - 1469694871, 3162884987, 3541402996, 1071667632, 2759177317, 1014854626, - 1928746161, 1071664735, 983617676, 1014285177, 3899555717, 1071661845, - 427280750, 3162546972, 772914124, 1071658964, 4004372762, 1012230161, - 1048019041, 1071656090, 1398474845, 3160510595, 339411585, 1071653224, - 264588982, 3161636657, 2851812149, 1071650365, 2595802551, 1015767337, - 4200250559, 1071647514, 2808127345, 3161781938 + 0x00000000UL, 0x3FF00000UL, 0x00000000UL, 0x00000000UL, 0x6B2A23D9UL, 0x3FEFE9D9UL, + 0x7442FDE3UL, 0x3C64A603UL, 0x2B8F71F1UL, 0x3FEFD3C2UL, 0x966579E7UL, 0x3C52EB74UL, + 0x3692D514UL, 0x3FEFBDBAUL, 0x15098EB6UL, 0xBC696773UL, 0x819E90D8UL, 0x3FEFA7C1UL, + 0xF3A5931EUL, 0x3C774853UL, 0x02243C89UL, 0x3FEF91D8UL, 0xA779F689UL, 0xBC512EA8UL, + 0xAD9CBE14UL, 0x3FEF7BFDUL, 0xD006350AUL, 0xBC8DBB12UL, 0x798844F8UL, 0x3FEF6632UL, + 0x3539343EUL, 0x3C8FA37BUL, 0x5B6E4540UL, 0x3FEF5076UL, 0x2DD8A18BUL, 0x3C89D3E1UL, + 0x48DD7274UL, 0x3FEF3AC9UL, 0x3ED837DEUL, 0xBC695A5AUL, 0x376BBA97UL, 0x3FEF252BUL, + 0xBF0D8E43UL, 0x3C83A1A5UL, 0x1CB6412AUL, 0x3FEF0F9CUL, 0x65181D45UL, 0xBC832200UL, + 0xEE615A27UL, 0x3FEEFA1BUL, 0x86A4B6B0UL, 0x3C8DC7F4UL, 0xA2188510UL, 0x3FEEE4AAUL, + 0xA487568DUL, 0x3C81C68DUL, 0x2D8E67F1UL, 0x3FEECF48UL, 0xB411AD8CUL, 0xBC8C93F3UL, + 0x867CCA6EUL, 0x3FEEB9F4UL, 0x2293E4F2UL, 0x3C84832FUL, 0xA2A490DAUL, 0x3FEEA4AFUL, + 0x179C2893UL, 0xBC8E9C23UL, 0x77CDB740UL, 0x3FEE8F79UL, 0x80B054B1UL, 0xBC810894UL, + 0xFBC74C83UL, 0x3FEE7A51UL, 0xCA0C8DE2UL, 0x3C82D522UL, 0x24676D76UL, 0x3FEE6539UL, + 0x7522B735UL, 0xBC763FF8UL, 0xE78B3FF6UL, 0x3FEE502EUL, 0x80A9CC8FUL, 0x3C739E89UL, + 0x3B16EE12UL, 0x3FEE3B33UL, 0x31FDC68BUL, 0xBC89F4A4UL, 0x14F5A129UL, 0x3FEE2646UL, + 0x817A1496UL, 0xBC87B627UL, 0x6B197D17UL, 0x3FEE1167UL, 0xBD5C7F44UL, 0xBC62B529UL, + 0x337B9B5FUL, 0x3FEDFC97UL, 0x4F184B5CUL, 0xBC81A5CDUL, 0x641C0658UL, 0x3FEDE7D5UL, + 0x8E79BA8FUL, 0xBC8CA552UL, 0xF301B460UL, 0x3FEDD321UL, 0x78F018C3UL, 0x3C82DA57UL, + 0xD63A8315UL, 0x3FEDBE7CUL, 0x926B8BE4UL, 0xBC8B76F1UL, 0x03DB3285UL, 0x3FEDA9E6UL, + 0x696DB532UL, 0x3C8C2300UL, 0x71FF6075UL, 0x3FED955DUL, 0xBB9AF6BEUL, 0x3C8A052DUL, + 0x16C98398UL, 0x3FED80E3UL, 0x8BEDDFE8UL, 0xBC811EC1UL, 0xE862E6D3UL, 0x3FED6C76UL, + 0x4A8165A0UL, 0x3C4FE87AUL, 0xDCFBA487UL, 0x3FED5818UL, 0xD75B3707UL, 0x3C72ED02UL, + 0xEACAA1D6UL, 0x3FED43C8UL, 0xBF5A1614UL, 0x3C83DB53UL, 0x080D89F2UL, 0x3FED2F87UL, + 0x719D8578UL, 0xBC8D487BUL, 0x2B08C968UL, 0x3FED1B53UL, 0x219A36EEUL, 0x3C855636UL, + 0x4A07897CUL, 0x3FED072DUL, 0x43797A9CUL, 0xBC8CBC37UL, 0x5B5BAB74UL, 0x3FECF315UL, + 0xB86DFF57UL, 0xBC8A08E9UL, 0x555DC3FAUL, 0x3FECDF0BUL, 0x53829D72UL, 0xBC7DD83BUL, + 0x2E6D1675UL, 0x3FECCB0FUL, 0x86009093UL, 0xBC6D220FUL, 0xDCEF9069UL, 0x3FECB720UL, + 0xD1E949DCUL, 0x3C6503CBUL, 0x5751C4DBUL, 0x3FECA340UL, 0xD10D08F5UL, 0xBC77F2BEUL, + 0x9406E7B5UL, 0x3FEC8F6DUL, 0x48805C44UL, 0x3C61ACBCUL, 0x8988C933UL, 0x3FEC7BA8UL, + 0xBE255559UL, 0xBC7E76BBUL, 0x2E57D14BUL, 0x3FEC67F1UL, 0xFF483CADUL, 0x3C82884DUL, + 0x78FAFB22UL, 0x3FEC5447UL, 0x2493B5AFUL, 0x3C812F07UL, 0x5FFFD07AUL, 0x3FEC40ABUL, + 0xE083C60AUL, 0x3C8B4537UL, 0xD9FA652CUL, 0x3FEC2D1CUL, 0x17C8A5D7UL, 0xBC86E516UL, + 0xDD85529CUL, 0x3FEC199BUL, 0x895048DDUL, 0x3C711065UL, 0x6141B33DUL, 0x3FEC0628UL, + 0xA1FBCA34UL, 0xBC7D8A5AUL, 0x5BD71E09UL, 0x3FEBF2C2UL, 0x3F6B9C73UL, 0xBC8EFDCAUL, + 0xC3F3A207UL, 0x3FEBDF69UL, 0x60EA5B53UL, 0xBC2C2623UL, 0x904BC1D2UL, 0x3FEBCC1EUL, + 0x7A2D9E84UL, 0x3C723DD0UL, 0xB79A6F1FUL, 0x3FEBB8E0UL, 0xC9696204UL, 0xBC2F52D1UL, + 0x30A1064AUL, 0x3FEBA5B0UL, 0x0E54292EUL, 0xBC8EFCD3UL, 0xF22749E4UL, 0x3FEB928CUL, + 0x54CB65C6UL, 0xBC8B7216UL, 0xF2FB5E47UL, 0x3FEB7F76UL, 0x7E54AC3BUL, 0xBC65584FUL, + 0x29F1C52AUL, 0x3FEB6C6EUL, 0x52883F6EUL, 0x3C82A8F3UL, 0x8DE5593AUL, 0x3FEB5972UL, + 0xBBBA6DE3UL, 0xBC8C71DFUL, 0x15B749B1UL, 0x3FEB4684UL, 0xE9DF7C90UL, 0xBC6F763DUL, + 0xB84F15FBUL, 0x3FEB33A2UL, 0x3084D708UL, 0xBC52805EUL, 0x6C9A8952UL, 0x3FEB20CEUL, + 0x4A0756CCUL, 0x3C84DD02UL, 0x298DB666UL, 0x3FEB0E07UL, 0x4C80E425UL, 0xBC8BDEF5UL, + 0xE622F2FFUL, 0x3FEAFB4CUL, 0x0F315ECDUL, 0xBC84B2FCUL, 0x995AD3ADUL, 0x3FEAE89FUL, + 0x345DCC81UL, 0x3C87A1CDUL, 0x3A3C2774UL, 0x3FEAD5FFUL, 0xB6B1B8E5UL, 0x3C87EF3BUL, + 0xBFD3F37AUL, 0x3FEAC36BUL, 0xCAE76CD0UL, 0xBC7F9234UL, 0x21356EBAUL, 0x3FEAB0E5UL, + 0xDAE94545UL, 0x3C789C31UL, 0x5579FDBFUL, 0x3FEA9E6BUL, 0x0EF7FD31UL, 0x3C80FAC9UL, + 0x53C12E59UL, 0x3FEA8BFEUL, 0xB2BA15A9UL, 0xBC84F867UL, 0x1330B358UL, 0x3FEA799EUL, + 0xCAC563C7UL, 0x3C8BCB7EUL, 0x8AF46052UL, 0x3FEA674AUL, 0x30670366UL, 0x3C550F56UL, + 0xB23E255DUL, 0x3FEA5503UL, 0xDB8D41E1UL, 0xBC8D2F6EUL, 0x80460AD8UL, 0x3FEA42C9UL, + 0x589FB120UL, 0xBC8AA780UL, 0xEC4A2D33UL, 0x3FEA309BUL, 0x7DDC36ABUL, 0x3C86305CUL, + 0xED8EB8BBUL, 0x3FEA1E7AUL, 0xEE8BE70EUL, 0x3C8C6618UL, 0x7B5DE565UL, 0x3FEA0C66UL, + 0x5D1CD533UL, 0xBC835949UL, 0x8D07F29EUL, 0x3FE9FA5EUL, 0xAAF1FACEUL, 0xBC74A9CEUL, + 0x19E32323UL, 0x3FE9E863UL, 0x78E64C6EUL, 0x3C6824CAUL, 0x194BB8D5UL, 0x3FE9D674UL, + 0xA3DD8233UL, 0xBC8516BEUL, 0x82A3F090UL, 0x3FE9C491UL, 0xB071F2BEUL, 0x3C6C7C46UL, + 0x4D53FE0DUL, 0x3FE9B2BBUL, 0x4DF6D518UL, 0xBC8DD84EUL, 0x70CA07BAUL, 0x3FE9A0F1UL, + 0x91CEE632UL, 0xBC8173BDUL, 0xE47A22A2UL, 0x3FE98F33UL, 0xA24C78ECUL, 0x3C6CABDAUL, + 0x9FDE4E50UL, 0x3FE97D82UL, 0x7C1B85D1UL, 0xBC8D185BUL, 0x9A7670B3UL, 0x3FE96BDDUL, + 0x7F19C896UL, 0xBC4BA596UL, 0xCBC8520FUL, 0x3FE95A44UL, 0x96A5F039UL, 0xBC664B7CUL, + 0x2B5F98E5UL, 0x3FE948B8UL, 0x797D2D99UL, 0xBC7DC3D6UL, 0xB0CDC5E5UL, 0x3FE93737UL, + 0x81B57EBCUL, 0xBC575FC7UL, 0x53AA2FE2UL, 0x3FE925C3UL, 0xA639DB7FUL, 0xBC73455FUL, + 0x0B91FFC6UL, 0x3FE9145BUL, 0x2E582524UL, 0xBC8DD679UL, 0xD0282C8AUL, 0x3FE902FEUL, + 0x85FE3FD2UL, 0x3C8592CAUL, 0x99157736UL, 0x3FE8F1AEUL, 0xA2E3976CUL, 0x3C75CC13UL, + 0x5E0866D9UL, 0x3FE8E06AUL, 0x6FC9B2E6UL, 0xBC87114AUL, 0x16B5448CUL, 0x3FE8CF32UL, + 0x32E9E3AAUL, 0xBC60D55EUL, 0xBAD61778UL, 0x3FE8BE05UL, 0xFC43446EUL, 0x3C8ECB5EUL, + 0x422AA0DBUL, 0x3FE8ACE5UL, 0x56864B27UL, 0x3C86E9F1UL, 0xA478580FUL, 0x3FE89BD0UL, + 0x4475202AUL, 0x3C8D5395UL, 0xD98A6699UL, 0x3FE88AC7UL, 0xF37CB53AUL, 0x3C8994C2UL, + 0xD931A436UL, 0x3FE879CAUL, 0xD2DB47BDUL, 0x3C75D2D7UL, 0x9B4492EDUL, 0x3FE868D9UL, + 0x9BD4F6BAUL, 0xBC8FC6F8UL, 0x179F5B21UL, 0x3FE857F4UL, 0xF8B216D0UL, 0xBC4BA748UL, + 0x4623C7ADUL, 0x3FE8471AUL, 0xA341CDFBUL, 0xBC78D684UL, 0x1EB941F7UL, 0x3FE8364CUL, + 0x31DF2BD5UL, 0x3C899B9AUL, 0x994CCE13UL, 0x3FE82589UL, 0xD41532D8UL, 0xBC8D4C1DUL, + 0xADD106D9UL, 0x3FE814D2UL, 0x0D151D4DUL, 0x3C846437UL, 0x543E1A12UL, 0x3FE80427UL, + 0x626D972BUL, 0xBC827C86UL, 0x8491C491UL, 0x3FE7F387UL, 0xCF9311AEUL, 0xBC707F11UL, + 0x36CF4E62UL, 0x3FE7E2F3UL, 0xBA15797EUL, 0x3C605D02UL, 0x62FF86F0UL, 0x3FE7D26AUL, + 0xFB72B8B4UL, 0x3C81BDDBUL, 0x0130C132UL, 0x3FE7C1EDUL, 0xD1164DD6UL, 0x3C8F124CUL, + 0x0976CFDBUL, 0x3FE7B17BUL, 0x8468DC88UL, 0xBC8BEBB5UL, 0x73EB0187UL, 0x3FE7A114UL, + 0xEE04992FUL, 0xBC741577UL, 0x38AC1CF6UL, 0x3FE790B9UL, 0x62AADD3EUL, 0x3C8349A8UL, + 0x4FDE5D3FUL, 0x3FE78069UL, 0x0A02162DUL, 0x3C8866B8UL, 0xB1AB6E09UL, 0x3FE77024UL, + 0x169147F8UL, 0x3C8B7877UL, 0x564267C9UL, 0x3FE75FEBUL, 0x57316DD3UL, 0xBC802459UL, + 0x35D7CBFDUL, 0x3FE74FBDUL, 0x618A6E1CUL, 0x3C8047FDUL, 0x48A58174UL, 0x3FE73F9AUL, + 0x6C65D53CUL, 0xBC80A8D9UL, 0x86EAD08AUL, 0x3FE72F82UL, 0x2CD62C72UL, 0xBC820AA0UL, + 0xE8EC5F74UL, 0x3FE71F75UL, 0x86887A99UL, 0xBC716E47UL, 0x66F42E87UL, 0x3FE70F74UL, + 0xD45AA65FUL, 0x3C49D644UL, 0xF9519484UL, 0x3FE6FF7DUL, 0x25860EF6UL, 0xBC783C0FUL, + 0x98593AE5UL, 0x3FE6EF92UL, 0x9E1AC8B2UL, 0xBC80B974UL, 0x3C651A2FUL, 0x3FE6DFB2UL, + 0x683C88ABUL, 0xBC5BBE3AUL, 0xDDD47645UL, 0x3FE6CFDCUL, 0xB6F17309UL, 0x3C8C7AA9UL, + 0x750BDABFUL, 0x3FE6C012UL, 0x67FF0B0DUL, 0xBC628956UL, 0xFA75173EUL, 0x3FE6B052UL, + 0x2C9A9D0EUL, 0x3C6A38F5UL, 0x667F3BCDUL, 0x3FE6A09EUL, 0x13B26456UL, 0xBC8BDD34UL, + 0xB19E9538UL, 0x3FE690F4UL, 0x9AEB445DUL, 0x3C7804BDUL, 0xD44CA973UL, 0x3FE68155UL, + 0x44F73E65UL, 0x3C5038AEUL, 0xC70833F6UL, 0x3FE671C1UL, 0x586C6134UL, 0xBC7E8732UL, + 0x82552225UL, 0x3FE66238UL, 0x87591C34UL, 0xBC8BB609UL, 0xFEBC8FB7UL, 0x3FE652B9UL, + 0xC9A73E09UL, 0xBC8AE3D5UL, 0x34CCC320UL, 0x3FE64346UL, 0x759D8933UL, 0xBC7C483CUL, + 0x1D1929FDUL, 0x3FE633DDUL, 0xBEB964E5UL, 0x3C884710UL, 0xB03A5585UL, 0x3FE6247EUL, + 0x7E40B497UL, 0xBC8383C1UL, 0xE6CDF6F4UL, 0x3FE6152AUL, 0x4AB84C27UL, 0x3C8E4B3EUL, + 0xB976DC09UL, 0x3FE605E1UL, 0x9B56DE47UL, 0xBC83E242UL, 0x20DCEB71UL, 0x3FE5F6A3UL, + 0xE3CDCF92UL, 0xBC79EADDUL, 0x15AD2148UL, 0x3FE5E76FUL, 0x3080E65EUL, 0x3C8BA6F9UL, + 0x90998B93UL, 0x3FE5D845UL, 0xA8B45643UL, 0xBC8CD6A7UL, 0x8A5946B7UL, 0x3FE5C926UL, + 0x816986A2UL, 0x3C2C4B1BUL, 0xFBA87A03UL, 0x3FE5BA11UL, 0x4C233E1AUL, 0xBC8B77A1UL, + 0xDD485429UL, 0x3FE5AB07UL, 0x054647ADUL, 0x3C86324CUL, 0x27FF07CCUL, 0x3FE59C08UL, + 0xE467E60FUL, 0xBC87E2CEUL, 0xD497C7FDUL, 0x3FE58D12UL, 0x5B9A1DE8UL, 0x3C7295E1UL, + 0xDBE2C4CFUL, 0x3FE57E27UL, 0x8A57B9C4UL, 0xBC80B98CUL, 0x36B527DAUL, 0x3FE56F47UL, + 0x011D93ADUL, 0x3C89BB2CUL, 0xDDE910D2UL, 0x3FE56070UL, 0x168EEBF0UL, 0xBC80FB6EUL, + 0xCA5D920FUL, 0x3FE551A4UL, 0xEFEDE59BUL, 0xBC7D689CUL, 0xF4F6AD27UL, 0x3FE542E2UL, + 0x192D5F7EUL, 0x3C77926DUL, 0x569D4F82UL, 0x3FE5342BUL, 0x1DB13CADUL, 0xBC707ABEUL, + 0xE83F4EEFUL, 0x3FE5257DUL, 0x43EFEF71UL, 0xBC6C998DUL, 0xA2CF6642UL, 0x3FE516DAUL, + 0x69BD93EFUL, 0xBC7F7685UL, 0x7F4531EEUL, 0x3FE50841UL, 0x49B7465FUL, 0x3C6A249BUL, + 0x769D2CA7UL, 0x3FE4F9B2UL, 0xD25957E3UL, 0xBC84B309UL, 0x81D8ABFFUL, 0x3FE4EB2DUL, + 0x2E5D7A52UL, 0xBC85257DUL, 0x99FDDD0DUL, 0x3FE4DCB2UL, 0xBC6A7833UL, 0x3C88ECDBUL, + 0xB817C114UL, 0x3FE4CE41UL, 0x690ABD5DUL, 0x3C805E29UL, 0xD5362A27UL, 0x3FE4BFDAUL, + 0xAFEC42E2UL, 0x3C6D4397UL, 0xEA6DB7D7UL, 0x3FE4B17DUL, 0x7F2897F0UL, 0xBC7125B8UL, + 0xF0D7D3DEUL, 0x3FE4A32AUL, 0xF3D1BE56UL, 0x3C89CB62UL, 0xE192AED2UL, 0x3FE494E1UL, + 0x5E499EA0UL, 0xBC73B289UL, 0xB5C13CD0UL, 0x3FE486A2UL, 0xB69062F0UL, 0x3C63C1A3UL, + 0x668B3237UL, 0x3FE4786DUL, 0xED445733UL, 0xBC8C20F0UL, 0xED1D0057UL, 0x3FE46A41UL, + 0xD1648A76UL, 0x3C8C944BUL, 0x42A7D232UL, 0x3FE45C20UL, 0x82FB1F8EUL, 0xBC586419UL, + 0x6061892DUL, 0x3FE44E08UL, 0x04EF80D0UL, 0x3C389B7AUL, 0x3F84B9D4UL, 0x3FE43FFAUL, + 0x9704C003UL, 0x3C7880BEUL, 0xD950A897UL, 0x3FE431F5UL, 0xE35F7999UL, 0xBC71C7DDUL, + 0x2709468AUL, 0x3FE423FBUL, 0xC0B314DDUL, 0xBC88462DUL, 0x21F72E2AUL, 0x3FE4160AUL, + 0x1C309278UL, 0xBC4EF369UL, 0xC367A024UL, 0x3FE40822UL, 0xB6F4D048UL, 0x3C7BDDF8UL, + 0x04AC801CUL, 0x3FE3FA45UL, 0xF956F9F3UL, 0xBC87D023UL, 0xDF1C5175UL, 0x3FE3EC70UL, + 0x7B8C9BCAUL, 0xBC7AF663UL, 0x4C123422UL, 0x3FE3DEA6UL, 0x11F09EBCUL, 0x3C7ADA09UL, + 0x44EDE173UL, 0x3FE3D0E5UL, 0x8C284C71UL, 0x3C6FE8D0UL, 0xC313A8E5UL, 0x3FE3C32DUL, + 0x375D29C3UL, 0xBC8EFFF8UL, 0xBFEC6CF4UL, 0x3FE3B57FUL, 0xE26FFF18UL, 0x3C854C66UL, + 0x34E59FF7UL, 0x3FE3A7DBUL, 0xD661F5E3UL, 0xBC65E436UL, 0x1B7140EFUL, 0x3FE39A40UL, + 0xFC8E2934UL, 0xBC89A9A5UL, 0x6D05D866UL, 0x3FE38CAEUL, 0x3C9904BDUL, 0xBC8E958DUL, + 0x231E754AUL, 0x3FE37F26UL, 0x9ECEB23CUL, 0xBC89F5CAUL, 0x373AA9CBUL, 0x3FE371A7UL, + 0xBF42EAE2UL, 0xBC863AEAUL, 0xA2DE883BUL, 0x3FE36431UL, 0xA06CB85EUL, 0xBC7C3144UL, + 0x5F929FF1UL, 0x3FE356C5UL, 0x5C4E4628UL, 0xBC7B5CEEUL, 0x66E3FA2DUL, 0x3FE34962UL, + 0x930881A4UL, 0xBC735A75UL, 0xB26416FFUL, 0x3FE33C08UL, 0x843659A6UL, 0x3C832721UL, + 0x3BA8EA32UL, 0x3FE32EB8UL, 0x3CB4F318UL, 0xBC8C45E8UL, 0xFC4CD831UL, 0x3FE32170UL, + 0x8E18047CUL, 0x3C7A9CE7UL, 0xEDEEB2FDUL, 0x3FE31432UL, 0xF3F3FCD1UL, 0x3C7959A3UL, + 0x0A31B715UL, 0x3FE306FEUL, 0xD23182E4UL, 0x3C76F46AUL, 0x4ABD886BUL, 0x3FE2F9D2UL, + 0x532BDA93UL, 0xBC553C55UL, 0xA93E2F56UL, 0x3FE2ECAFUL, 0x45D52383UL, 0x3C61CA0FUL, + 0x1F641589UL, 0x3FE2DF96UL, 0xFBBCE198UL, 0x3C8D16CFUL, 0xA6E4030BUL, 0x3FE2D285UL, + 0x54DB41D5UL, 0x3C800247UL, 0x39771B2FUL, 0x3FE2C57EUL, 0xA6EB5124UL, 0xBC850145UL, + 0xD0DAD990UL, 0x3FE2B87FUL, 0xD6381AA4UL, 0xBC310ADCUL, 0x66D10F13UL, 0x3FE2AB8AUL, + 0x191690A7UL, 0xBC895743UL, 0xF51FDEE1UL, 0x3FE29E9DUL, 0xAFAD1255UL, 0x3C7612E8UL, + 0x7591BB70UL, 0x3FE291BAUL, 0x28401CBDUL, 0xBC72CC72UL, 0xE1F56381UL, 0x3FE284DFUL, + 0x8C3F0D7EUL, 0xBC8A4C3AUL, 0x341DDF29UL, 0x3FE2780EUL, 0x05F9E76CUL, 0x3C8E067CUL, + 0x65E27CDDUL, 0x3FE26B45UL, 0x9940E9D9UL, 0x3C72BD33UL, 0x711ECE75UL, 0x3FE25E85UL, + 0x4AC31B2CUL, 0x3C83E1A2UL, 0x4FB2A63FUL, 0x3FE251CEUL, 0xBEF4F4A4UL, 0x3C7AC155UL, + 0xFB82140AUL, 0x3FE2451FUL, 0x911CA996UL, 0x3C7ACFCCUL, 0x6E756238UL, 0x3FE2387AUL, + 0xB6C70573UL, 0x3C89B07EUL, 0xA27912D1UL, 0x3FE22BDDUL, 0x5577D69FUL, 0x3C7D34FBUL, + 0x917DDC96UL, 0x3FE21F49UL, 0x9494A5EEUL, 0x3C72A97EUL, 0x3578A819UL, 0x3FE212BEUL, + 0x2CFCAAC9UL, 0x3C83592DUL, 0x88628CD6UL, 0x3FE2063BUL, 0x814A8495UL, 0x3C7DC775UL, + 0x8438CE4DUL, 0x3FE1F9C1UL, 0xA097AF5CUL, 0xBC8BF524UL, 0x22FCD91DUL, 0x3FE1ED50UL, + 0x027BB78CUL, 0xBC81DF98UL, 0x5EB44027UL, 0x3FE1E0E7UL, 0x088CB6DEUL, 0xBC86FDD8UL, + 0x3168B9AAUL, 0x3FE1D487UL, 0x00A2643CUL, 0x3C8E016EUL, 0x95281C6BUL, 0x3FE1C82FUL, + 0x8010F8C9UL, 0x3C800977UL, 0x84045CD4UL, 0x3FE1BBE0UL, 0x352EF607UL, 0xBC895386UL, + 0xF8138A1CUL, 0x3FE1AF99UL, 0xA4B69280UL, 0x3C87BF85UL, 0xEB6FCB75UL, 0x3FE1A35BUL, + 0x7B4968E4UL, 0x3C7E5B4CUL, 0x58375D2FUL, 0x3FE19726UL, 0x85F17E08UL, 0x3C84AADDUL, + 0x388C8DEAUL, 0x3FE18AF9UL, 0xD1970F6CUL, 0xBC811023UL, 0x8695BBC0UL, 0x3FE17ED4UL, + 0xE2AC5A64UL, 0x3C609E3FUL, 0x3C7D517BUL, 0x3FE172B8UL, 0xB9D78A76UL, 0xBC719041UL, + 0x5471C3C2UL, 0x3FE166A4UL, 0x82EA1A32UL, 0x3C48F23BUL, 0xC8A58E51UL, 0x3FE15A98UL, + 0xB9EEAB0AUL, 0x3C72406AUL, 0x934F312EUL, 0x3FE14E95UL, 0x39BF44ABUL, 0xBC7B91E8UL, + 0xAEA92DE0UL, 0x3FE1429AUL, 0x9AF1369EUL, 0xBC832FBFUL, 0x14F204ABUL, 0x3FE136A8UL, + 0xBA48DCF0UL, 0xBC57108FUL, 0xC06C31CCUL, 0x3FE12ABDUL, 0xB36CA5C7UL, 0xBC41B514UL, + 0xAB5E2AB6UL, 0x3FE11EDBUL, 0xF703FB72UL, 0xBC8CA454UL, 0xD0125B51UL, 0x3FE11301UL, + 0x39449B3AUL, 0xBC86C510UL, 0x28D7233EUL, 0x3FE10730UL, 0x1692FDD5UL, 0x3C7D46EBUL, + 0xAFFED31BUL, 0x3FE0FB66UL, 0xC44EBD7BUL, 0xBC5B9BEDUL, 0x5FDFA9C5UL, 0x3FE0EFA5UL, + 0xBC54021BUL, 0xBC849DB9UL, 0x32D3D1A2UL, 0x3FE0E3ECUL, 0x27C57B52UL, 0x3C303A17UL, + 0x23395DECUL, 0x3FE0D83BUL, 0xE43F316AUL, 0xBC8BC14DUL, 0x2B7247F7UL, 0x3FE0CC92UL, + 0x16E24F71UL, 0x3C801EDCUL, 0x45E46C85UL, 0x3FE0C0F1UL, 0x06D21CEFUL, 0x3C84F989UL, + 0x6CF9890FUL, 0x3FE0B558UL, 0x4ADC610BUL, 0x3C88A62EUL, 0x9B1F3919UL, 0x3FE0A9C7UL, + 0x873D1D38UL, 0x3C75D16CUL, 0xCAC6F383UL, 0x3FE09E3EUL, 0x18316136UL, 0x3C814878UL, + 0xF66607E0UL, 0x3FE092BDUL, 0x800A3FD1UL, 0xBC868063UL, 0x18759BC8UL, 0x3FE08745UL, + 0x4BB284FFUL, 0x3C5186BEUL, 0x2B72A836UL, 0x3FE07BD4UL, 0x54458700UL, 0x3C732334UL, + 0x29DDF6DEUL, 0x3FE0706BUL, 0xE2B13C27UL, 0xBC7C91DFUL, 0x0E3C1F89UL, 0x3FE0650AUL, + 0x5799C397UL, 0xBC85CB7BUL, 0xD3158574UL, 0x3FE059B0UL, 0xA475B465UL, 0x3C7D73E2UL, + 0x72F654B1UL, 0x3FE04E5FUL, 0x3AA0D08CUL, 0x3C74C379UL, 0xE86E7F85UL, 0x3FE04315UL, + 0x1977C96EUL, 0xBC80A31CUL, 0x2E11BBCCUL, 0x3FE037D4UL, 0xEEADE11AUL, 0x3C556811UL, + 0x3E778061UL, 0x3FE02C9AUL, 0x535B085DUL, 0xBC619083UL, 0x143B0281UL, 0x3FE02168UL, + 0x0FC54EB6UL, 0xBC72BF31UL, 0xA9FB3335UL, 0x3FE0163DUL, 0x9AB8CDB7UL, 0x3C8B6129UL, + 0xFA5ABCBFUL, 0x3FE00B1AUL, 0xA7609F71UL, 0xBC74F6B2UL }; #define __ _masm-> diff --git a/src/hotspot/cpu/x86/x86.ad b/src/hotspot/cpu/x86/x86.ad index 2eb748e350c..efe0482e095 100644 --- a/src/hotspot/cpu/x86/x86.ad +++ b/src/hotspot/cpu/x86/x86.ad @@ -7664,8 +7664,11 @@ instruct vcastFtoD_reg(vec dst, vec src) %{ instruct castFtoX_reg_avx(vec dst, vec src, vec xtmp1, vec xtmp2, vec xtmp3, vec xtmp4, rFlagsReg cr) %{ - predicate(!VM_Version::supports_avx512vl() && Matcher::vector_length_in_bytes(n->in(1)) < 64 && - type2aelembytes(Matcher::vector_element_basic_type(n)) <= 4); + predicate(!VM_Version::supports_avx10_2() && + !VM_Version::supports_avx512vl() && + Matcher::vector_length_in_bytes(n->in(1)) < 64 && + type2aelembytes(Matcher::vector_element_basic_type(n)) <= 4 && + is_integral_type(Matcher::vector_element_basic_type(n))); match(Set dst (VectorCastF2X src)); effect(TEMP dst, TEMP xtmp1, TEMP xtmp2, TEMP xtmp3, TEMP xtmp4, KILL cr); format %{ "vector_cast_f2x $dst,$src\t! using $xtmp1, $xtmp2, $xtmp3 and $xtmp4 as TEMP" %} @@ -7687,7 +7690,8 @@ instruct castFtoX_reg_avx(vec dst, vec src, vec xtmp1, vec xtmp2, vec xtmp3, vec %} instruct castFtoX_reg_evex(vec dst, vec src, vec xtmp1, vec xtmp2, kReg ktmp1, kReg ktmp2, rFlagsReg cr) %{ - predicate((VM_Version::supports_avx512vl() || Matcher::vector_length_in_bytes(n->in(1)) == 64) && + predicate(!VM_Version::supports_avx10_2() && + (VM_Version::supports_avx512vl() || Matcher::vector_length_in_bytes(n->in(1)) == 64) && is_integral_type(Matcher::vector_element_basic_type(n))); match(Set dst (VectorCastF2X src)); effect(TEMP dst, TEMP xtmp1, TEMP xtmp2, TEMP ktmp1, TEMP ktmp2, KILL cr); @@ -7709,6 +7713,33 @@ instruct castFtoX_reg_evex(vec dst, vec src, vec xtmp1, vec xtmp2, kReg ktmp1, k ins_pipe( pipe_slow ); %} +instruct castFtoX_reg_avx10(vec dst, vec src) %{ + predicate(VM_Version::supports_avx10_2() && + is_integral_type(Matcher::vector_element_basic_type(n))); + match(Set dst (VectorCastF2X src)); + format %{ "vector_cast_f2x_avx10 $dst, $src\t!" %} + ins_encode %{ + BasicType to_elem_bt = Matcher::vector_element_basic_type(this); + int vlen_enc = (to_elem_bt == T_LONG) ? vector_length_encoding(this) : vector_length_encoding(this, $src); + __ vector_castF2X_avx10(to_elem_bt, $dst$$XMMRegister, $src$$XMMRegister, vlen_enc); + %} + ins_pipe( pipe_slow ); +%} + +instruct castFtoX_mem_avx10(vec dst, memory src) %{ + predicate(VM_Version::supports_avx10_2() && + is_integral_type(Matcher::vector_element_basic_type(n))); + match(Set dst (VectorCastF2X (LoadVector src))); + format %{ "vector_cast_f2x_avx10 $dst, $src\t!" %} + ins_encode %{ + int vlen = Matcher::vector_length(this); + BasicType to_elem_bt = Matcher::vector_element_basic_type(this); + int vlen_enc = (to_elem_bt == T_LONG) ? vector_length_encoding(this) : vector_length_encoding(vlen * sizeof(jfloat)); + __ vector_castF2X_avx10(to_elem_bt, $dst$$XMMRegister, $src$$Address, vlen_enc); + %} + ins_pipe( pipe_slow ); +%} + instruct vcastDtoF_reg(vec dst, vec src) %{ predicate(Matcher::vector_element_basic_type(n) == T_FLOAT); match(Set dst (VectorCastD2X src)); @@ -7721,7 +7752,9 @@ instruct vcastDtoF_reg(vec dst, vec src) %{ %} instruct castDtoX_reg_avx(vec dst, vec src, vec xtmp1, vec xtmp2, vec xtmp3, vec xtmp4, vec xtmp5, rFlagsReg cr) %{ - predicate(!VM_Version::supports_avx512vl() && Matcher::vector_length_in_bytes(n->in(1)) < 64 && + predicate(!VM_Version::supports_avx10_2() && + !VM_Version::supports_avx512vl() && + Matcher::vector_length_in_bytes(n->in(1)) < 64 && is_integral_type(Matcher::vector_element_basic_type(n))); match(Set dst (VectorCastD2X src)); effect(TEMP dst, TEMP xtmp1, TEMP xtmp2, TEMP xtmp3, TEMP xtmp4, TEMP xtmp5, KILL cr); @@ -7737,7 +7770,8 @@ instruct castDtoX_reg_avx(vec dst, vec src, vec xtmp1, vec xtmp2, vec xtmp3, vec %} instruct castDtoX_reg_evex(vec dst, vec src, vec xtmp1, vec xtmp2, kReg ktmp1, kReg ktmp2, rFlagsReg cr) %{ - predicate((VM_Version::supports_avx512vl() || Matcher::vector_length_in_bytes(n->in(1)) == 64) && + predicate(!VM_Version::supports_avx10_2() && + (VM_Version::supports_avx512vl() || Matcher::vector_length_in_bytes(n->in(1)) == 64) && is_integral_type(Matcher::vector_element_basic_type(n))); match(Set dst (VectorCastD2X src)); effect(TEMP dst, TEMP xtmp1, TEMP xtmp2, TEMP ktmp1, TEMP ktmp2, KILL cr); @@ -7753,6 +7787,33 @@ instruct castDtoX_reg_evex(vec dst, vec src, vec xtmp1, vec xtmp2, kReg ktmp1, k ins_pipe( pipe_slow ); %} +instruct castDtoX_reg_avx10(vec dst, vec src) %{ + predicate(VM_Version::supports_avx10_2() && + is_integral_type(Matcher::vector_element_basic_type(n))); + match(Set dst (VectorCastD2X src)); + format %{ "vector_cast_d2x_avx10 $dst, $src\t!" %} + ins_encode %{ + int vlen_enc = vector_length_encoding(this, $src); + BasicType to_elem_bt = Matcher::vector_element_basic_type(this); + __ vector_castD2X_avx10(to_elem_bt, $dst$$XMMRegister, $src$$XMMRegister, vlen_enc); + %} + ins_pipe( pipe_slow ); +%} + +instruct castDtoX_mem_avx10(vec dst, memory src) %{ + predicate(VM_Version::supports_avx10_2() && + is_integral_type(Matcher::vector_element_basic_type(n))); + match(Set dst (VectorCastD2X (LoadVector src))); + format %{ "vector_cast_d2x_avx10 $dst, $src\t!" %} + ins_encode %{ + int vlen = Matcher::vector_length(this); + int vlen_enc = vector_length_encoding(vlen * sizeof(jdouble)); + BasicType to_elem_bt = Matcher::vector_element_basic_type(this); + __ vector_castD2X_avx10(to_elem_bt, $dst$$XMMRegister, $src$$Address, vlen_enc); + %} + ins_pipe( pipe_slow ); +%} + instruct vucast(vec dst, vec src) %{ match(Set dst (VectorUCastB2X src)); match(Set dst (VectorUCastS2X src)); diff --git a/src/hotspot/cpu/x86/x86_64.ad b/src/hotspot/cpu/x86/x86_64.ad index 0914bea82a1..0b254966db6 100644 --- a/src/hotspot/cpu/x86/x86_64.ad +++ b/src/hotspot/cpu/x86/x86_64.ad @@ -11712,6 +11712,7 @@ instruct convD2F_reg_mem(regF dst, memory src) // XXX do mem variants instruct convF2I_reg_reg(rRegI dst, regF src, rFlagsReg cr) %{ + predicate(!VM_Version::supports_avx10_2()); match(Set dst (ConvF2I src)); effect(KILL cr); format %{ "convert_f2i $dst, $src" %} @@ -11721,8 +11722,31 @@ instruct convF2I_reg_reg(rRegI dst, regF src, rFlagsReg cr) ins_pipe(pipe_slow); %} +instruct convF2I_reg_reg_avx10(rRegI dst, regF src) +%{ + predicate(VM_Version::supports_avx10_2()); + match(Set dst (ConvF2I src)); + format %{ "evcvttss2sisl $dst, $src" %} + ins_encode %{ + __ evcvttss2sisl($dst$$Register, $src$$XMMRegister); + %} + ins_pipe(pipe_slow); +%} + +instruct convF2I_reg_mem_avx10(rRegI dst, memory src) +%{ + predicate(VM_Version::supports_avx10_2()); + match(Set dst (ConvF2I (LoadF src))); + format %{ "evcvttss2sisl $dst, $src" %} + ins_encode %{ + __ evcvttss2sisl($dst$$Register, $src$$Address); + %} + ins_pipe(pipe_slow); +%} + instruct convF2L_reg_reg(rRegL dst, regF src, rFlagsReg cr) %{ + predicate(!VM_Version::supports_avx10_2()); match(Set dst (ConvF2L src)); effect(KILL cr); format %{ "convert_f2l $dst, $src"%} @@ -11732,8 +11756,31 @@ instruct convF2L_reg_reg(rRegL dst, regF src, rFlagsReg cr) ins_pipe(pipe_slow); %} +instruct convF2L_reg_reg_avx10(rRegL dst, regF src) +%{ + predicate(VM_Version::supports_avx10_2()); + match(Set dst (ConvF2L src)); + format %{ "evcvttss2sisq $dst, $src" %} + ins_encode %{ + __ evcvttss2sisq($dst$$Register, $src$$XMMRegister); + %} + ins_pipe(pipe_slow); +%} + +instruct convF2L_reg_mem_avx10(rRegL dst, memory src) +%{ + predicate(VM_Version::supports_avx10_2()); + match(Set dst (ConvF2L (LoadF src))); + format %{ "evcvttss2sisq $dst, $src" %} + ins_encode %{ + __ evcvttss2sisq($dst$$Register, $src$$Address); + %} + ins_pipe(pipe_slow); +%} + instruct convD2I_reg_reg(rRegI dst, regD src, rFlagsReg cr) %{ + predicate(!VM_Version::supports_avx10_2()); match(Set dst (ConvD2I src)); effect(KILL cr); format %{ "convert_d2i $dst, $src"%} @@ -11743,8 +11790,31 @@ instruct convD2I_reg_reg(rRegI dst, regD src, rFlagsReg cr) ins_pipe(pipe_slow); %} +instruct convD2I_reg_reg_avx10(rRegI dst, regD src) +%{ + predicate(VM_Version::supports_avx10_2()); + match(Set dst (ConvD2I src)); + format %{ "evcvttsd2sisl $dst, $src" %} + ins_encode %{ + __ evcvttsd2sisl($dst$$Register, $src$$XMMRegister); + %} + ins_pipe(pipe_slow); +%} + +instruct convD2I_reg_mem_avx10(rRegI dst, memory src) +%{ + predicate(VM_Version::supports_avx10_2()); + match(Set dst (ConvD2I (LoadD src))); + format %{ "evcvttsd2sisl $dst, $src" %} + ins_encode %{ + __ evcvttsd2sisl($dst$$Register, $src$$Address); + %} + ins_pipe(pipe_slow); +%} + instruct convD2L_reg_reg(rRegL dst, regD src, rFlagsReg cr) %{ + predicate(!VM_Version::supports_avx10_2()); match(Set dst (ConvD2L src)); effect(KILL cr); format %{ "convert_d2l $dst, $src"%} @@ -11754,6 +11824,28 @@ instruct convD2L_reg_reg(rRegL dst, regD src, rFlagsReg cr) ins_pipe(pipe_slow); %} +instruct convD2L_reg_reg_avx10(rRegL dst, regD src) +%{ + predicate(VM_Version::supports_avx10_2()); + match(Set dst (ConvD2L src)); + format %{ "evcvttsd2sisq $dst, $src" %} + ins_encode %{ + __ evcvttsd2sisq($dst$$Register, $src$$XMMRegister); + %} + ins_pipe(pipe_slow); +%} + +instruct convD2L_reg_mem_avx10(rRegL dst, memory src) +%{ + predicate(VM_Version::supports_avx10_2()); + match(Set dst (ConvD2L (LoadD src))); + format %{ "evcvttsd2sisq $dst, $src" %} + ins_encode %{ + __ evcvttsd2sisq($dst$$Register, $src$$Address); + %} + ins_pipe(pipe_slow); +%} + instruct round_double_reg(rRegL dst, regD src, rRegL rtmp, rcx_RegL rcx, rFlagsReg cr) %{ match(Set dst (RoundD src)); diff --git a/src/hotspot/os/aix/os_aix.cpp b/src/hotspot/os/aix/os_aix.cpp index dbdc66b0eb6..0c0c2808fa1 100644 --- a/src/hotspot/os/aix/os_aix.cpp +++ b/src/hotspot/os/aix/os_aix.cpp @@ -169,7 +169,7 @@ static void vmembk_print_on(outputStream* os); //////////////////////////////////////////////////////////////////////////////// // global variables (for a description see os_aix.hpp) -size_t os::Aix::_physical_memory = 0; +physical_memory_size_type os::Aix::_physical_memory = 0; pthread_t os::Aix::_main_thread = ((pthread_t)0); @@ -254,43 +254,43 @@ static bool is_close_to_brk(address a) { return false; } -bool os::free_memory(size_t& value) { +bool os::free_memory(physical_memory_size_type& value) { return Aix::available_memory(value); } -bool os::available_memory(size_t& value) { +bool os::available_memory(physical_memory_size_type& value) { return Aix::available_memory(value); } -bool os::Aix::available_memory(size_t& value) { +bool os::Aix::available_memory(physical_memory_size_type& value) { os::Aix::meminfo_t mi; if (os::Aix::get_meminfo(&mi)) { - value = static_cast(mi.real_free); + value = static_cast(mi.real_free); return true; } else { return false; } } -bool os::total_swap_space(size_t& value) { +bool os::total_swap_space(physical_memory_size_type& value) { perfstat_memory_total_t memory_info; if (libperfstat::perfstat_memory_total(nullptr, &memory_info, sizeof(perfstat_memory_total_t), 1) == -1) { return false; } - value = static_cast(memory_info.pgsp_total * 4 * K); + value = static_cast(memory_info.pgsp_total * 4 * K); return true; } -bool os::free_swap_space(size_t& value) { +bool os::free_swap_space(physical_memory_size_type& value) { perfstat_memory_total_t memory_info; if (libperfstat::perfstat_memory_total(nullptr, &memory_info, sizeof(perfstat_memory_total_t), 1) == -1) { return false; } - value = static_cast(memory_info.pgsp_free * 4 * K); + value = static_cast(memory_info.pgsp_free * 4 * K); return true; } -size_t os::physical_memory() { +physical_memory_size_type os::physical_memory() { return Aix::physical_memory(); } @@ -329,7 +329,7 @@ void os::Aix::initialize_system_info() { if (!os::Aix::get_meminfo(&mi)) { assert(false, "os::Aix::get_meminfo failed."); } - _physical_memory = static_cast(mi.real_total); + _physical_memory = static_cast(mi.real_total); } // Helper function for tracing page sizes. @@ -2192,7 +2192,7 @@ jint os::init_2(void) { os::Posix::init_2(); trcVerbose("processor count: %d", os::_processor_count); - trcVerbose("physical memory: %zu", Aix::_physical_memory); + trcVerbose("physical memory: " PHYS_MEM_TYPE_FORMAT, Aix::_physical_memory); // Initially build up the loaded dll map. LoadedLibraries::reload(); diff --git a/src/hotspot/os/aix/os_aix.hpp b/src/hotspot/os/aix/os_aix.hpp index 1530f2adb76..a7bac40e79b 100644 --- a/src/hotspot/os/aix/os_aix.hpp +++ b/src/hotspot/os/aix/os_aix.hpp @@ -35,7 +35,7 @@ class os::Aix { private: - static size_t _physical_memory; + static physical_memory_size_type _physical_memory; static pthread_t _main_thread; // 0 = uninitialized, otherwise 16 bit number: @@ -54,9 +54,9 @@ class os::Aix { // 1 - EXTSHM=ON static int _extshm; - static bool available_memory(size_t& value); - static bool free_memory(size_t& value); - static size_t physical_memory() { return _physical_memory; } + static bool available_memory(physical_memory_size_type& value); + static bool free_memory(physical_memory_size_type& value); + static physical_memory_size_type physical_memory() { return _physical_memory; } static void initialize_system_info(); // OS recognitions (AIX OS level) call this before calling Aix::os_version(). diff --git a/src/hotspot/os/bsd/os_bsd.cpp b/src/hotspot/os/bsd/os_bsd.cpp index b03dbd48cf8..8c5bbd58a84 100644 --- a/src/hotspot/os/bsd/os_bsd.cpp +++ b/src/hotspot/os/bsd/os_bsd.cpp @@ -114,7 +114,7 @@ //////////////////////////////////////////////////////////////////////////////// // global variables -size_t os::Bsd::_physical_memory = 0; +physical_memory_size_type os::Bsd::_physical_memory = 0; #ifdef __APPLE__ mach_timebase_info_data_t os::Bsd::_timebase_info = {0, 0}; @@ -133,19 +133,19 @@ static volatile int processor_id_next = 0; //////////////////////////////////////////////////////////////////////////////// // utility functions -bool os::available_memory(size_t& value) { +bool os::available_memory(physical_memory_size_type& value) { return Bsd::available_memory(value); } -bool os::free_memory(size_t& value) { +bool os::free_memory(physical_memory_size_type& value) { return Bsd::available_memory(value); } // Available here means free. Note that this number is of no much use. As an estimate // for future memory pressure it is far too conservative, since MacOS will use a lot // of unused memory for caches, and return it willingly in case of needs. -bool os::Bsd::available_memory(size_t& value) { - uint64_t available = static_cast(physical_memory() >> 2); +bool os::Bsd::available_memory(physical_memory_size_type& value) { + physical_memory_size_type available = physical_memory() >> 2; #ifdef __APPLE__ mach_msg_type_number_t count = HOST_VM_INFO64_COUNT; vm_statistics64_data_t vmstat; @@ -160,7 +160,7 @@ bool os::Bsd::available_memory(size_t& value) { return false; } #endif - value = static_cast(available); + value = available; return true; } @@ -180,35 +180,35 @@ void os::Bsd::print_uptime_info(outputStream* st) { } } -bool os::total_swap_space(size_t& value) { +bool os::total_swap_space(physical_memory_size_type& value) { #if defined(__APPLE__) struct xsw_usage vmusage; size_t size = sizeof(vmusage); if (sysctlbyname("vm.swapusage", &vmusage, &size, nullptr, 0) != 0) { return false; } - value = static_cast(vmusage.xsu_total); + value = static_cast(vmusage.xsu_total); return true; #else return false; #endif } -bool os::free_swap_space(size_t& value) { +bool os::free_swap_space(physical_memory_size_type& value) { #if defined(__APPLE__) struct xsw_usage vmusage; size_t size = sizeof(vmusage); if (sysctlbyname("vm.swapusage", &vmusage, &size, nullptr, 0) != 0) { return false; } - value = static_cast(vmusage.xsu_avail); + value = static_cast(vmusage.xsu_avail); return true; #else return false; #endif } -size_t os::physical_memory() { +physical_memory_size_type os::physical_memory() { return Bsd::physical_memory(); } @@ -286,7 +286,7 @@ void os::Bsd::initialize_system_info() { len = sizeof(mem_val); if (sysctl(mib, 2, &mem_val, &len, nullptr, 0) != -1) { assert(len == sizeof(mem_val), "unexpected data size"); - _physical_memory = static_cast(mem_val); + _physical_memory = static_cast(mem_val); } else { _physical_memory = 256 * 1024 * 1024; // fallback (XXXBSD?) } @@ -297,7 +297,7 @@ void os::Bsd::initialize_system_info() { // datasize rlimit restricts us anyway. struct rlimit limits; getrlimit(RLIMIT_DATA, &limits); - _physical_memory = MIN2(_physical_memory, static_cast(limits.rlim_cur)); + _physical_memory = MIN2(_physical_memory, static_cast(limits.rlim_cur)); } #endif } @@ -1469,12 +1469,12 @@ void os::print_memory_info(outputStream* st) { st->print("Memory:"); st->print(" %zuk page", os::vm_page_size()>>10); - size_t phys_mem = os::physical_memory(); - st->print(", physical %zuk", + physical_memory_size_type phys_mem = os::physical_memory(); + st->print(", physical " PHYS_MEM_TYPE_FORMAT "k", phys_mem >> 10); - size_t avail_mem = 0; + physical_memory_size_type avail_mem = 0; (void)os::available_memory(avail_mem); - st->print("(%zuk free)", + st->print("(" PHYS_MEM_TYPE_FORMAT "k free)", avail_mem >> 10); if((sysctlbyname("vm.swapusage", &swap_usage, &size, nullptr, 0) == 0) || (errno == ENOMEM)) { diff --git a/src/hotspot/os/bsd/os_bsd.hpp b/src/hotspot/os/bsd/os_bsd.hpp index 173cc5a40ad..82002917f39 100644 --- a/src/hotspot/os/bsd/os_bsd.hpp +++ b/src/hotspot/os/bsd/os_bsd.hpp @@ -42,12 +42,12 @@ class os::Bsd { protected: - static size_t _physical_memory; + static physical_memory_size_type _physical_memory; static pthread_t _main_thread; - static bool available_memory(size_t& value); - static bool free_memory(size_t& value); - static size_t physical_memory() { return _physical_memory; } + static bool available_memory(physical_memory_size_type& value); + static bool free_memory(physical_memory_size_type& value); + static physical_memory_size_type physical_memory() { return _physical_memory; } static void initialize_system_info(); static void rebuild_cpu_to_node_map(); diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index 3d44d839735..7159b2a78c4 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -154,13 +154,12 @@ enum CoredumpFilterBit { //////////////////////////////////////////////////////////////////////////////// // global variables -size_t os::Linux::_physical_memory = 0; +physical_memory_size_type os::Linux::_physical_memory = 0; address os::Linux::_initial_thread_stack_bottom = nullptr; uintptr_t os::Linux::_initial_thread_stack_size = 0; int (*os::Linux::_pthread_getcpuclockid)(pthread_t, clockid_t *) = nullptr; -int (*os::Linux::_pthread_setname_np)(pthread_t, const char*) = nullptr; pthread_t os::Linux::_main_thread; bool os::Linux::_supports_fast_thread_cpu_time = false; const char * os::Linux::_libc_version = nullptr; @@ -229,15 +228,15 @@ julong os::Linux::available_memory_in_container() { return avail_mem; } -bool os::available_memory(size_t& value) { +bool os::available_memory(physical_memory_size_type& value) { return Linux::available_memory(value); } -bool os::Linux::available_memory(size_t& value) { +bool os::Linux::available_memory(physical_memory_size_type& value) { julong avail_mem = available_memory_in_container(); if (avail_mem != static_cast(-1L)) { log_trace(os)("available container memory: " JULONG_FORMAT, avail_mem); - value = static_cast(avail_mem); + value = static_cast(avail_mem); return true; } @@ -253,28 +252,28 @@ bool os::Linux::available_memory(size_t& value) { fclose(fp); } if (avail_mem == static_cast(-1L)) { - size_t free_mem = 0; + physical_memory_size_type free_mem = 0; if (!free_memory(free_mem)) { return false; } avail_mem = static_cast(free_mem); } log_trace(os)("available memory: " JULONG_FORMAT, avail_mem); - value = static_cast(avail_mem); + value = static_cast(avail_mem); return true; } -bool os::free_memory(size_t& value) { +bool os::free_memory(physical_memory_size_type& value) { return Linux::free_memory(value); } -bool os::Linux::free_memory(size_t& value) { +bool os::Linux::free_memory(physical_memory_size_type& value) { // values in struct sysinfo are "unsigned long" struct sysinfo si; julong free_mem = available_memory_in_container(); if (free_mem != static_cast(-1L)) { log_trace(os)("free container memory: " JULONG_FORMAT, free_mem); - value = static_cast(free_mem); + value = static_cast(free_mem); return true; } @@ -284,16 +283,16 @@ bool os::Linux::free_memory(size_t& value) { } free_mem = (julong)si.freeram * si.mem_unit; log_trace(os)("free memory: " JULONG_FORMAT, free_mem); - value = static_cast(free_mem); + value = static_cast(free_mem); return true; } -bool os::total_swap_space(size_t& value) { +bool os::total_swap_space(physical_memory_size_type& value) { if (OSContainer::is_containerized()) { jlong memory_and_swap_limit_in_bytes = OSContainer::memory_and_swap_limit_in_bytes(); jlong memory_limit_in_bytes = OSContainer::memory_limit_in_bytes(); if (memory_limit_in_bytes > 0 && memory_and_swap_limit_in_bytes > 0) { - value = static_cast(memory_and_swap_limit_in_bytes - memory_limit_in_bytes); + value = static_cast(memory_and_swap_limit_in_bytes - memory_limit_in_bytes); return true; } } // fallback to the host swap space if the container did return the unbound value of -1 @@ -303,30 +302,30 @@ bool os::total_swap_space(size_t& value) { assert(false, "sysinfo failed in total_swap_space(): %s", os::strerror(errno)); return false; } - value = static_cast(si.totalswap * si.mem_unit); + value = static_cast(si.totalswap) * si.mem_unit; return true; } -static bool host_free_swap_f(size_t& value) { +static bool host_free_swap_f(physical_memory_size_type& value) { struct sysinfo si; int ret = sysinfo(&si); if (ret != 0) { assert(false, "sysinfo failed in host_free_swap_f(): %s", os::strerror(errno)); return false; } - value = static_cast(si.freeswap * si.mem_unit); + value = static_cast(si.freeswap) * si.mem_unit; return true; } -bool os::free_swap_space(size_t& value) { +bool os::free_swap_space(physical_memory_size_type& value) { // os::total_swap_space() might return the containerized limit which might be // less than host_free_swap(). The upper bound of free swap needs to be the lower of the two. - size_t total_swap_space = 0; - size_t host_free_swap = 0; + physical_memory_size_type total_swap_space = 0; + physical_memory_size_type host_free_swap = 0; if (!os::total_swap_space(total_swap_space) || !host_free_swap_f(host_free_swap)) { return false; } - size_t host_free_swap_val = MIN2(total_swap_space, host_free_swap); + physical_memory_size_type host_free_swap_val = MIN2(total_swap_space, host_free_swap); if (OSContainer::is_containerized()) { jlong mem_swap_limit = OSContainer::memory_and_swap_limit_in_bytes(); jlong mem_limit = OSContainer::memory_limit_in_bytes(); @@ -342,31 +341,31 @@ bool os::free_swap_space(size_t& value) { jlong delta_usage = mem_swap_usage - mem_usage; if (delta_usage >= 0) { jlong free_swap = delta_limit - delta_usage; - value = free_swap >= 0 ? static_cast(free_swap) : 0; + value = free_swap >= 0 ? static_cast(free_swap) : 0; return true; } } } // unlimited or not supported. Fall through to return host value log_trace(os,container)("os::free_swap_space: container_swap_limit=" JLONG_FORMAT - " container_mem_limit=" JLONG_FORMAT " returning host value: %zu", + " container_mem_limit=" JLONG_FORMAT " returning host value: " PHYS_MEM_TYPE_FORMAT, mem_swap_limit, mem_limit, host_free_swap_val); } value = host_free_swap_val; return true; } -size_t os::physical_memory() { +physical_memory_size_type os::physical_memory() { if (OSContainer::is_containerized()) { jlong mem_limit; if ((mem_limit = OSContainer::memory_limit_in_bytes()) > 0) { log_trace(os)("total container memory: " JLONG_FORMAT, mem_limit); - return static_cast(mem_limit); + return static_cast(mem_limit); } } - size_t phys_mem = Linux::physical_memory(); - log_trace(os)("total system memory: %zu", phys_mem); + physical_memory_size_type phys_mem = Linux::physical_memory(); + log_trace(os)("total system memory: " PHYS_MEM_TYPE_FORMAT, phys_mem); return phys_mem; } @@ -550,7 +549,7 @@ void os::Linux::initialize_system_info() { fclose(fp); } } - _physical_memory = static_cast(sysconf(_SC_PHYS_PAGES)) * static_cast(sysconf(_SC_PAGESIZE)); + _physical_memory = static_cast(sysconf(_SC_PHYS_PAGES)) * static_cast(sysconf(_SC_PAGESIZE)); assert(processor_count() > 0, "linux error"); } @@ -860,11 +859,9 @@ static void *thread_native_entry(Thread *thread) { osthread->set_thread_id(checked_cast(os::current_thread_id())); if (UseNUMA) { - int lgrp_id = os::numa_get_group_id(); - if (lgrp_id != -1) { - thread->set_lgrp_id(lgrp_id); - } + thread->update_lgrp_id(); } + // initialize signal mask for this thread PosixSignals::hotspot_sigmask(thread); @@ -1191,10 +1188,7 @@ bool os::create_attached_thread(JavaThread* thread) { thread->set_osthread(osthread); if (UseNUMA) { - int lgrp_id = os::numa_get_group_id(); - if (lgrp_id != -1) { - thread->set_lgrp_id(lgrp_id); - } + thread->update_lgrp_id(); } if (os::is_primordial_thread()) { @@ -2609,12 +2603,12 @@ void os::print_memory_info(outputStream* st) { // values in struct sysinfo are "unsigned long" struct sysinfo si; sysinfo(&si); - size_t phys_mem = physical_memory(); - st->print(", physical %zuk", + physical_memory_size_type phys_mem = physical_memory(); + st->print(", physical " PHYS_MEM_TYPE_FORMAT "k", phys_mem >> 10); - size_t avail_mem = 0; + physical_memory_size_type avail_mem = 0; (void)os::available_memory(avail_mem); - st->print("(%zuk free)", + st->print("(" PHYS_MEM_TYPE_FORMAT "k free)", avail_mem >> 10); st->print(", swap " UINT64_FORMAT "k", ((jlong)si.totalswap * si.mem_unit) >> 10); @@ -4376,10 +4370,6 @@ void os::init(void) { // _main_thread points to the thread that created/loaded the JVM. Linux::_main_thread = pthread_self(); - // retrieve entry point for pthread_setname_np - Linux::_pthread_setname_np = - (int(*)(pthread_t, const char*))dlsym(RTLD_DEFAULT, "pthread_setname_np"); - check_pax(); // Check the availability of MADV_POPULATE_WRITE. @@ -4856,14 +4846,24 @@ uint os::processor_id() { } void os::set_native_thread_name(const char *name) { - if (Linux::_pthread_setname_np) { - char buf [16]; // according to glibc manpage, 16 chars incl. '/0' - (void) os::snprintf(buf, sizeof(buf), "%s", name); - buf[sizeof(buf) - 1] = '\0'; - const int rc = Linux::_pthread_setname_np(pthread_self(), buf); - // ERANGE should not happen; all other errors should just be ignored. - assert(rc != ERANGE, "pthread_setname_np failed"); - } + char buf[16]; // according to glibc manpage, 16 chars incl. '/0' + // We may need to truncate the thread name. Since a common pattern + // for thread names is to be both longer than 15 chars and have a + // trailing number ("DispatcherWorkerThread21", "C2 CompilerThread#54" etc), + // we preserve the end of the thread name by truncating the middle + // (e.g. "Dispatc..read21"). + const size_t len = strlen(name); + if (len < sizeof(buf)) { + strcpy(buf, name); + } else { + (void) os::snprintf(buf, sizeof(buf), "%.7s..%.6s", name, name + len - 6); + } + // Note: we use the system call here instead of calling pthread_setname_np + // since this is the only way to make ASAN aware of our thread names. Even + // though ASAN intercepts both prctl and pthread_setname_np, it only processes + // the thread name given to the former. + int rc = prctl(PR_SET_NAME, buf); + assert(rc == 0, "prctl(PR_SET_NAME) failed"); } //////////////////////////////////////////////////////////////////////////////// diff --git a/src/hotspot/os/linux/os_linux.hpp b/src/hotspot/os/linux/os_linux.hpp index 497d383200d..b77cd9f3c81 100644 --- a/src/hotspot/os/linux/os_linux.hpp +++ b/src/hotspot/os/linux/os_linux.hpp @@ -33,7 +33,6 @@ class os::Linux { friend class os; static int (*_pthread_getcpuclockid)(pthread_t, clockid_t *); - static int (*_pthread_setname_np)(pthread_t, const char*); static address _initial_thread_stack_bottom; static uintptr_t _initial_thread_stack_size; @@ -50,11 +49,11 @@ class os::Linux { protected: - static size_t _physical_memory; + static physical_memory_size_type _physical_memory; static pthread_t _main_thread; - static bool available_memory(size_t& value); - static bool free_memory(size_t& value); + static bool available_memory(physical_memory_size_type& value); + static bool free_memory(physical_memory_size_type& value); static void initialize_system_info(); @@ -117,7 +116,7 @@ class os::Linux { static address initial_thread_stack_bottom(void) { return _initial_thread_stack_bottom; } static uintptr_t initial_thread_stack_size(void) { return _initial_thread_stack_size; } - static size_t physical_memory() { return _physical_memory; } + static physical_memory_size_type physical_memory() { return _physical_memory; } static julong host_swap(); static intptr_t* ucontext_get_sp(const ucontext_t* uc); diff --git a/src/hotspot/os/posix/os_posix.inline.hpp b/src/hotspot/os/posix/os_posix.inline.hpp index 67be82e4d63..f1ec9411f2a 100644 --- a/src/hotspot/os/posix/os_posix.inline.hpp +++ b/src/hotspot/os/posix/os_posix.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2022, 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 @@ -34,9 +34,6 @@ #include #include -// Aix does not have NUMA support but need these for compilation. -inline bool os::numa_has_group_homing() { AIX_ONLY(ShouldNotReachHere();) return false; } - // Platform Mutex/Monitor implementation inline void PlatformMutex::lock() { diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp index 8d4c93f3080..875e97ce038 100644 --- a/src/hotspot/os/windows/os_windows.cpp +++ b/src/hotspot/os/windows/os_windows.cpp @@ -534,13 +534,6 @@ static unsigned thread_native_entry(void* t) { OSThread* osthr = thread->osthread(); assert(osthr->get_state() == RUNNABLE, "invalid os thread state"); - if (UseNUMA) { - int lgrp_id = os::numa_get_group_id(); - if (lgrp_id != -1) { - thread->set_lgrp_id(lgrp_id); - } - } - // Diagnostic code to investigate JDK-6573254 int res = 30115; // non-java thread if (thread->is_Java_thread()) { @@ -598,13 +591,6 @@ static OSThread* create_os_thread(Thread* thread, HANDLE thread_handle, osthread->set_thread_handle(thread_handle); osthread->set_thread_id(thread_id); - if (UseNUMA) { - int lgrp_id = os::numa_get_group_id(); - if (lgrp_id != -1) { - thread->set_lgrp_id(lgrp_id); - } - } - // Initial thread state is INITIALIZED, not SUSPENDED osthread->set_state(INITIALIZED); @@ -848,22 +834,22 @@ jlong os::elapsed_frequency() { } -bool os::available_memory(size_t& value) { +bool os::available_memory(physical_memory_size_type& value) { return win32::available_memory(value); } -bool os::free_memory(size_t& value) { +bool os::free_memory(physical_memory_size_type& value) { return win32::available_memory(value); } -bool os::win32::available_memory(size_t& value) { +bool os::win32::available_memory(physical_memory_size_type& value) { // Use GlobalMemoryStatusEx() because GlobalMemoryStatus() may return incorrect // value if total memory is larger than 4GB MEMORYSTATUSEX ms; ms.dwLength = sizeof(ms); BOOL res = GlobalMemoryStatusEx(&ms); if (res == TRUE) { - value = static_cast(ms.ullAvailPhys); + value = static_cast(ms.ullAvailPhys); return true; } else { assert(false, "GlobalMemoryStatusEx failed in os::win32::available_memory(): %lu", ::GetLastError()); @@ -871,12 +857,12 @@ bool os::win32::available_memory(size_t& value) { } } -bool os::total_swap_space(size_t& value) { +bool os::total_swap_space(physical_memory_size_type& value) { MEMORYSTATUSEX ms; ms.dwLength = sizeof(ms); BOOL res = GlobalMemoryStatusEx(&ms); if (res == TRUE) { - value = static_cast(ms.ullTotalPageFile); + value = static_cast(ms.ullTotalPageFile); return true; } else { assert(false, "GlobalMemoryStatusEx failed in os::total_swap_space(): %lu", ::GetLastError()); @@ -884,12 +870,12 @@ bool os::total_swap_space(size_t& value) { } } -bool os::free_swap_space(size_t& value) { +bool os::free_swap_space(physical_memory_size_type& value) { MEMORYSTATUSEX ms; ms.dwLength = sizeof(ms); BOOL res = GlobalMemoryStatusEx(&ms); if (res == TRUE) { - value = static_cast(ms.ullAvailPageFile); + value = static_cast(ms.ullAvailPageFile); return true; } else { assert(false, "GlobalMemoryStatusEx failed in os::free_swap_space(): %lu", ::GetLastError()); @@ -897,7 +883,7 @@ bool os::free_swap_space(size_t& value) { } } -size_t os::physical_memory() { +physical_memory_size_type os::physical_memory() { return win32::physical_memory(); } @@ -3961,25 +3947,25 @@ int os::current_process_id() { return (_initial_pid ? _initial_pid : _getpid()); } -int os::win32::_processor_type = 0; +int os::win32::_processor_type = 0; // Processor level is not available on non-NT systems, use vm_version instead -int os::win32::_processor_level = 0; -size_t os::win32::_physical_memory = 0; +int os::win32::_processor_level = 0; +physical_memory_size_type os::win32::_physical_memory = 0; -bool os::win32::_is_windows_server = false; +bool os::win32::_is_windows_server = false; // 6573254 // Currently, the bug is observed across all the supported Windows releases, // including the latest one (as of this writing - Windows Server 2012 R2) -bool os::win32::_has_exit_bug = true; +bool os::win32::_has_exit_bug = true; -int os::win32::_major_version = 0; -int os::win32::_minor_version = 0; -int os::win32::_build_number = 0; -int os::win32::_build_minor = 0; +int os::win32::_major_version = 0; +int os::win32::_minor_version = 0; +int os::win32::_build_number = 0; +int os::win32::_build_minor = 0; -bool os::win32::_processor_group_warning_displayed = false; -bool os::win32::_job_object_processor_group_warning_displayed = false; +bool os::win32::_processor_group_warning_displayed = false; +bool os::win32::_job_object_processor_group_warning_displayed = false; void getWindowsInstallationType(char* buffer, int bufferSize) { HKEY hKey; @@ -4198,7 +4184,7 @@ void os::win32::initialize_system_info() { if (res != TRUE) { assert(false, "GlobalMemoryStatusEx failed in os::win32::initialize_system_info(): %lu", ::GetLastError()); } - _physical_memory = static_cast(ms.ullTotalPhys); + _physical_memory = static_cast(ms.ullTotalPhys); if (FLAG_IS_DEFAULT(MaxRAM)) { // Adjust MaxRAM according to the maximum virtual address space available. diff --git a/src/hotspot/os/windows/os_windows.hpp b/src/hotspot/os/windows/os_windows.hpp index 1426dc8be93..efb7b414989 100644 --- a/src/hotspot/os/windows/os_windows.hpp +++ b/src/hotspot/os/windows/os_windows.hpp @@ -38,18 +38,18 @@ class os::win32 { friend class os; protected: - static int _processor_type; - static int _processor_level; - static size_t _physical_memory; - static bool _is_windows_server; - static bool _has_exit_bug; - static bool _processor_group_warning_displayed; - static bool _job_object_processor_group_warning_displayed; - - static int _major_version; - static int _minor_version; - static int _build_number; - static int _build_minor; + static int _processor_type; + static int _processor_level; + static physical_memory_size_type _physical_memory; + static bool _is_windows_server; + static bool _has_exit_bug; + static bool _processor_group_warning_displayed; + static bool _job_object_processor_group_warning_displayed; + + static int _major_version; + static int _minor_version; + static int _build_number; + static int _build_minor; static void print_windows_version(outputStream* st); static void print_uptime_info(outputStream* st); @@ -102,9 +102,9 @@ class os::win32 { static int processor_level() { return _processor_level; } - static bool available_memory(size_t& value); - static bool free_memory(size_t& value); - static size_t physical_memory() { return _physical_memory; } + static bool available_memory(physical_memory_size_type& value); + static bool free_memory(physical_memory_size_type& value); + static physical_memory_size_type physical_memory() { return _physical_memory; } // load dll from Windows system directory or Windows directory static HINSTANCE load_Windows_dll(const char* name, char *ebuf, int ebuflen); diff --git a/src/hotspot/os/windows/os_windows.inline.hpp b/src/hotspot/os/windows/os_windows.inline.hpp index 41471224b6c..9eebbee2d8b 100644 --- a/src/hotspot/os/windows/os_windows.inline.hpp +++ b/src/hotspot/os/windows/os_windows.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -62,8 +62,6 @@ inline void os::map_stack_shadow_pages(address sp) { state->set_shadow_zone_growth_watermark(original_sp); } -inline bool os::numa_has_group_homing() { return false; } - // Platform Mutex/Monitor implementation inline void PlatformMutex::lock() { diff --git a/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp b/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp index 3e5fb4610de..a95bfb4ff96 100644 --- a/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp +++ b/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp @@ -89,7 +89,24 @@ #define RISCV_HWPROBE_MISALIGNED_UNSUPPORTED (4 << 0) #define RISCV_HWPROBE_MISALIGNED_MASK (7 << 0) -#define RISCV_HWPROBE_KEY_ZICBOZ_BLOCK_SIZE 6 +#define RISCV_HWPROBE_KEY_ZICBOZ_BLOCK_SIZE 6 + +#define RISCV_HWPROBE_KEY_HIGHEST_VIRT_ADDRESS 7 + +#define RISCV_HWPROBE_KEY_TIME_CSR_FREQ 8 + +#define RISCV_HWPROBE_KEY_MISALIGNED_SCALAR_PERF 9 +#define RISCV_HWPROBE_MISALIGNED_SCALAR_UNKNOWN 0 +#define RISCV_HWPROBE_MISALIGNED_SCALAR_EMULATED 1 +#define RISCV_HWPROBE_MISALIGNED_SCALAR_SLOW 2 +#define RISCV_HWPROBE_MISALIGNED_SCALAR_FAST 3 +#define RISCV_HWPROBE_MISALIGNED_SCALAR_UNSUPPORTED 4 + +#define RISCV_HWPROBE_KEY_MISALIGNED_VECTOR_PERF 10 +#define RISCV_HWPROBE_MISALIGNED_VECTOR_UNKNOWN 0 +#define RISCV_HWPROBE_MISALIGNED_VECTOR_SLOW 2 +#define RISCV_HWPROBE_MISALIGNED_VECTOR_FAST 3 +#define RISCV_HWPROBE_MISALIGNED_VECTOR_UNSUPPORTED 4 #ifndef NR_riscv_hwprobe #ifndef NR_arch_specific_syscall @@ -117,7 +134,11 @@ static struct riscv_hwprobe query[] = {{RISCV_HWPROBE_KEY_MVENDORID, 0}, {RISCV_HWPROBE_KEY_BASE_BEHAVIOR, 0}, {RISCV_HWPROBE_KEY_IMA_EXT_0, 0}, {RISCV_HWPROBE_KEY_CPUPERF_0, 0}, - {RISCV_HWPROBE_KEY_ZICBOZ_BLOCK_SIZE, 0}}; + {RISCV_HWPROBE_KEY_ZICBOZ_BLOCK_SIZE, 0}, + {RISCV_HWPROBE_KEY_HIGHEST_VIRT_ADDRESS, 0}, + {RISCV_HWPROBE_KEY_TIME_CSR_FREQ, 0}, + {RISCV_HWPROBE_KEY_MISALIGNED_SCALAR_PERF, 0}, + {RISCV_HWPROBE_KEY_MISALIGNED_VECTOR_PERF, 0}}; bool RiscvHwprobe::probe_features() { assert(!rw_hwprobe_completed, "Called twice."); @@ -246,9 +267,20 @@ void RiscvHwprobe::add_features_from_query_result() { VM_Version::ext_Zicond.enable_feature(); } #endif + // RISCV_HWPROBE_KEY_CPUPERF_0 is deprecated and returns similar values + // to RISCV_HWPROBE_KEY_MISALIGNED_SCALAR_PERF. Keep it there for backward + // compatibility with old kernels. if (is_valid(RISCV_HWPROBE_KEY_CPUPERF_0)) { - VM_Version::unaligned_access.enable_feature( + VM_Version::unaligned_scalar.enable_feature( query[RISCV_HWPROBE_KEY_CPUPERF_0].value & RISCV_HWPROBE_MISALIGNED_MASK); + } else if (is_valid(RISCV_HWPROBE_KEY_MISALIGNED_SCALAR_PERF)) { + VM_Version::unaligned_scalar.enable_feature( + query[RISCV_HWPROBE_KEY_MISALIGNED_SCALAR_PERF].value); + } + + if (is_valid(RISCV_HWPROBE_KEY_MISALIGNED_VECTOR_PERF)) { + VM_Version::unaligned_vector.enable_feature( + query[RISCV_HWPROBE_KEY_MISALIGNED_VECTOR_PERF].value); } if (is_valid(RISCV_HWPROBE_KEY_ZICBOZ_BLOCK_SIZE)) { VM_Version::zicboz_block_size.enable_feature(query[RISCV_HWPROBE_KEY_ZICBOZ_BLOCK_SIZE].value); diff --git a/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp b/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp index cf9429b6bea..67d405f0656 100644 --- a/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp +++ b/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp @@ -100,7 +100,6 @@ #endif uint32_t VM_Version::cpu_vector_length() { - assert(ext_V.enabled(), "should not call this"); return (uint32_t)read_csr(CSR_VLENB); } @@ -303,7 +302,7 @@ void VM_Version::rivos_features() { ext_Zvfh.enable_feature(); - unaligned_access.enable_feature(MISALIGNED_FAST); + unaligned_scalar.enable_feature(MISALIGNED_SCALAR_FAST); satp_mode.enable_feature(VM_SV48); // Features dependent on march/mimpid. diff --git a/src/hotspot/share/adlc/output_h.cpp b/src/hotspot/share/adlc/output_h.cpp index 8a5ad72137a..6cb82f4df7f 100644 --- a/src/hotspot/share/adlc/output_h.cpp +++ b/src/hotspot/share/adlc/output_h.cpp @@ -759,20 +759,15 @@ void ArchDesc::declare_pipe_classes(FILE *fp_hpp) { if (_pipeline->_maxcycleused <= 32) { fprintf(fp_hpp, "protected:\n"); - fprintf(fp_hpp, " %s _mask;\n\n", _pipeline->_maxcycleused <= 32 ? "uint" : "uint64_t" ); + fprintf(fp_hpp, " uint32_t _mask;\n\n"); fprintf(fp_hpp, "public:\n"); fprintf(fp_hpp, " Pipeline_Use_Cycle_Mask() : _mask(0) {}\n\n"); - if (_pipeline->_maxcycleused <= 32) - fprintf(fp_hpp, " Pipeline_Use_Cycle_Mask(uint mask) : _mask(mask) {}\n\n"); - else { - fprintf(fp_hpp, " Pipeline_Use_Cycle_Mask(uint mask1, uint mask2) : _mask((((uint64_t)mask1) << 32) | mask2) {}\n\n"); - fprintf(fp_hpp, " Pipeline_Use_Cycle_Mask(uint64_t mask) : _mask(mask) {}\n\n"); - } + fprintf(fp_hpp, " Pipeline_Use_Cycle_Mask(uint32_t mask) : _mask(mask) {}\n\n"); fprintf(fp_hpp, " bool overlaps(const Pipeline_Use_Cycle_Mask &in2) const {\n"); fprintf(fp_hpp, " return ((_mask & in2._mask) != 0);\n"); fprintf(fp_hpp, " }\n\n"); fprintf(fp_hpp, " Pipeline_Use_Cycle_Mask& operator<<=(int n) {\n"); - fprintf(fp_hpp, " _mask <<= n;\n"); + fprintf(fp_hpp, " _mask <<= (n < 32) ? n : 31;\n"); fprintf(fp_hpp, " return *this;\n"); fprintf(fp_hpp, " }\n\n"); fprintf(fp_hpp, " void Or(const Pipeline_Use_Cycle_Mask &in2) {\n"); @@ -785,7 +780,7 @@ void ArchDesc::declare_pipe_classes(FILE *fp_hpp) { fprintf(fp_hpp, "protected:\n"); uint masklen = (_pipeline->_maxcycleused + 31) >> 5; uint l; - fprintf(fp_hpp, " uint "); + fprintf(fp_hpp, " uint32_t "); for (l = 1; l <= masklen; l++) fprintf(fp_hpp, "_mask%d%s", l, l < masklen ? ", " : ";\n\n"); fprintf(fp_hpp, "public:\n"); @@ -794,7 +789,7 @@ void ArchDesc::declare_pipe_classes(FILE *fp_hpp) { fprintf(fp_hpp, "_mask%d(0)%s", l, l < masklen ? ", " : " {}\n\n"); fprintf(fp_hpp, " Pipeline_Use_Cycle_Mask("); for (l = 1; l <= masklen; l++) - fprintf(fp_hpp, "uint mask%d%s", l, l < masklen ? ", " : ") : "); + fprintf(fp_hpp, "uint32_t mask%d%s", l, l < masklen ? ", " : ") : "); for (l = 1; l <= masklen; l++) fprintf(fp_hpp, "_mask%d(mask%d)%s", l, l, l < masklen ? ", " : " {}\n\n"); @@ -805,10 +800,10 @@ void ArchDesc::declare_pipe_classes(FILE *fp_hpp) { fprintf(fp_hpp, " return out;\n"); fprintf(fp_hpp, " }\n\n"); fprintf(fp_hpp, " bool overlaps(const Pipeline_Use_Cycle_Mask &in2) const {\n"); - fprintf(fp_hpp, " return ("); + fprintf(fp_hpp, " return "); for (l = 1; l <= masklen; l++) fprintf(fp_hpp, "((_mask%d & in2._mask%d) != 0)%s", l, l, l < masklen ? " || " : ""); - fprintf(fp_hpp, ") ? true : false;\n"); + fprintf(fp_hpp, ";\n"); fprintf(fp_hpp, " }\n\n"); fprintf(fp_hpp, " Pipeline_Use_Cycle_Mask& operator<<=(int n) {\n"); fprintf(fp_hpp, " if (n >= 32)\n"); @@ -819,10 +814,10 @@ void ArchDesc::declare_pipe_classes(FILE *fp_hpp) { fprintf(fp_hpp, " } while ((n -= 32) >= 32);\n\n"); fprintf(fp_hpp, " if (n > 0) {\n"); fprintf(fp_hpp, " uint m = 32 - n;\n"); - fprintf(fp_hpp, " uint mask = (1 << n) - 1;\n"); - fprintf(fp_hpp, " uint temp%d = mask & (_mask%d >> m); _mask%d <<= n;\n", 2, 1, 1); + fprintf(fp_hpp, " uint32_t mask = (1 << n) - 1;\n"); + fprintf(fp_hpp, " uint32_t temp%d = mask & (_mask%d >> m); _mask%d <<= n;\n", 2, 1, 1); for (l = 2; l < masklen; l++) { - fprintf(fp_hpp, " uint temp%d = mask & (_mask%d >> m); _mask%d <<= n; _mask%d |= temp%d;\n", l+1, l, l, l, l); + fprintf(fp_hpp, " uint32_t temp%d = mask & (_mask%d >> m); _mask%d <<= n; _mask%d |= temp%d;\n", l+1, l, l, l, l); } fprintf(fp_hpp, " _mask%d <<= n; _mask%d |= temp%d;\n", masklen, masklen, masklen); fprintf(fp_hpp, " }\n"); @@ -872,8 +867,7 @@ void ArchDesc::declare_pipe_classes(FILE *fp_hpp) { fprintf(fp_hpp, " }\n\n"); fprintf(fp_hpp, " void step(uint cycles) {\n"); fprintf(fp_hpp, " _used = 0;\n"); - fprintf(fp_hpp, " uint max_shift = 8 * sizeof(_mask) - 1;\n"); - fprintf(fp_hpp, " _mask <<= (cycles < max_shift) ? cycles : max_shift;\n"); + fprintf(fp_hpp, " _mask <<= cycles;\n"); fprintf(fp_hpp, " }\n\n"); fprintf(fp_hpp, " friend class Pipeline_Use;\n"); fprintf(fp_hpp, "};\n\n"); diff --git a/src/hotspot/share/c1/c1_CodeStubs.hpp b/src/hotspot/share/c1/c1_CodeStubs.hpp index 5d1c51bdbbf..a02368487c5 100644 --- a/src/hotspot/share/c1/c1_CodeStubs.hpp +++ b/src/hotspot/share/c1/c1_CodeStubs.hpp @@ -371,21 +371,16 @@ class MonitorEnterStub: public MonitorAccessStub { class MonitorExitStub: public MonitorAccessStub { private: - bool _compute_lock; int _monitor_ix; public: - MonitorExitStub(LIR_Opr lock_reg, bool compute_lock, int monitor_ix) + MonitorExitStub(LIR_Opr lock_reg, int monitor_ix) : MonitorAccessStub(LIR_OprFact::illegalOpr, lock_reg), - _compute_lock(compute_lock), _monitor_ix(monitor_ix) { } + _monitor_ix(monitor_ix) { } virtual void emit_code(LIR_Assembler* e); virtual void visit(LIR_OpVisitState* visitor) { assert(_obj_reg->is_illegal(), "unused"); - if (_compute_lock) { - visitor->do_temp(_lock_reg); - } else { - visitor->do_input(_lock_reg); - } + visitor->do_temp(_lock_reg); } #ifndef PRODUCT virtual void print_name(outputStream* out) const { out->print("MonitorExitStub"); } diff --git a/src/hotspot/share/c1/c1_LIRGenerator.cpp b/src/hotspot/share/c1/c1_LIRGenerator.cpp index b30667dcac3..66adfa5ed66 100644 --- a/src/hotspot/share/c1/c1_LIRGenerator.cpp +++ b/src/hotspot/share/c1/c1_LIRGenerator.cpp @@ -635,7 +635,7 @@ void LIRGenerator::monitor_exit(LIR_Opr object, LIR_Opr lock, LIR_Opr new_hdr, L // setup registers LIR_Opr hdr = lock; lock = new_hdr; - CodeStub* slow_path = new MonitorExitStub(lock, true, monitor_no); + CodeStub* slow_path = new MonitorExitStub(lock, monitor_no); __ load_stack_address_monitor(monitor_no, lock); __ unlock_object(hdr, object, lock, scratch, slow_path); } diff --git a/src/hotspot/share/cds/dumpTimeClassInfo.inline.hpp b/src/hotspot/share/cds/dumpTimeClassInfo.inline.hpp index 90f35c61de1..2d0953288b0 100644 --- a/src/hotspot/share/cds/dumpTimeClassInfo.inline.hpp +++ b/src/hotspot/share/cds/dumpTimeClassInfo.inline.hpp @@ -1,4 +1,3 @@ - /* * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -53,7 +52,7 @@ void DumpTimeSharedClassTable::iterate_all_live_classes(Function function) const assert(k->is_loader_alive(), "must not change"); } else { if (!SystemDictionaryShared::is_excluded_class(k)) { - SystemDictionaryShared::warn_excluded(k, "Class loader not alive"); + SystemDictionaryShared::log_exclusion(k, "Class loader not alive"); SystemDictionaryShared::set_excluded_locked(k); } } diff --git a/src/hotspot/share/classfile/classFileParser.cpp b/src/hotspot/share/classfile/classFileParser.cpp index 52bbab01d61..fddd9df726b 100644 --- a/src/hotspot/share/classfile/classFileParser.cpp +++ b/src/hotspot/share/classfile/classFileParser.cpp @@ -2445,7 +2445,7 @@ Method* ClassFileParser::parse_method(const ClassFileStream* const cfs, cfs->skip_u2_fast(method_parameters_length); cfs->skip_u2_fast(method_parameters_length); // ignore this attribute if it cannot be reflected - if (!vmClasses::Parameter_klass_loaded()) + if (!vmClasses::reflect_Parameter_klass_is_loaded()) method_parameters_length = -1; } else if (method_attribute_name == vmSymbols::tag_synthetic()) { if (method_attribute_length != 0) { @@ -3979,7 +3979,7 @@ void ClassFileParser::set_precomputed_flags(InstanceKlass* ik) { #endif // Check if this klass supports the java.lang.Cloneable interface - if (vmClasses::Cloneable_klass_loaded()) { + if (vmClasses::Cloneable_klass_is_loaded()) { if (ik->is_subtype_of(vmClasses::Cloneable_klass())) { ik->set_is_cloneable(); } diff --git a/src/hotspot/share/classfile/classLoaderData.hpp b/src/hotspot/share/classfile/classLoaderData.hpp index da49a9326e3..64fcfb7519f 100644 --- a/src/hotspot/share/classfile/classLoaderData.hpp +++ b/src/hotspot/share/classfile/classLoaderData.hpp @@ -97,7 +97,7 @@ class ClassLoaderData : public CHeapObj { }; friend class ClassLoaderDataGraph; - friend class ClassLoaderDataGraphKlassIteratorAtomic; + friend class ClassLoaderDataGraphIteratorAtomic; friend class Klass; friend class MetaDataFactory; friend class Method; diff --git a/src/hotspot/share/classfile/classLoaderDataGraph.cpp b/src/hotspot/share/classfile/classLoaderDataGraph.cpp index 4d3d6a951c5..61404fdf9db 100644 --- a/src/hotspot/share/classfile/classLoaderDataGraph.cpp +++ b/src/hotspot/share/classfile/classLoaderDataGraph.cpp @@ -489,62 +489,25 @@ void ClassLoaderDataGraph::purge(bool at_safepoint) { } } -ClassLoaderDataGraphKlassIteratorAtomic::ClassLoaderDataGraphKlassIteratorAtomic() - : _next_klass(nullptr) { +ClassLoaderDataGraphIteratorAtomic::ClassLoaderDataGraphIteratorAtomic() + : _cld(nullptr) { assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint!"); - ClassLoaderData* cld = ClassLoaderDataGraph::_head; - Klass* klass = nullptr; - - // Find the first klass in the CLDG. - while (cld != nullptr) { - assert_locked_or_safepoint(cld->metaspace_lock()); - klass = cld->_klasses; - if (klass != nullptr) { - _next_klass = klass; - return; - } - cld = cld->next(); - } + _cld = AtomicAccess::load_acquire(&ClassLoaderDataGraph::_head); } -Klass* ClassLoaderDataGraphKlassIteratorAtomic::next_klass_in_cldg(Klass* klass) { - Klass* next = klass->next_link(); - if (next != nullptr) { - return next; - } - - // No more klasses in the current CLD. Time to find a new CLD. - ClassLoaderData* cld = klass->class_loader_data(); - assert_locked_or_safepoint(cld->metaspace_lock()); - while (next == nullptr) { - cld = cld->next(); - if (cld == nullptr) { - break; +ClassLoaderData* ClassLoaderDataGraphIteratorAtomic::next() { + ClassLoaderData* cur = AtomicAccess::load(&_cld); + for (;;) { + if (cur == nullptr) { + return nullptr; } - next = cld->_klasses; - } - - return next; -} - -Klass* ClassLoaderDataGraphKlassIteratorAtomic::next_klass() { - Klass* head = _next_klass; - - while (head != nullptr) { - Klass* next = next_klass_in_cldg(head); - - Klass* old_head = AtomicAccess::cmpxchg(&_next_klass, head, next); - - if (old_head == head) { - return head; // Won the CAS. + ClassLoaderData* next = cur->next(); + ClassLoaderData* old; + if ((old = AtomicAccess::cmpxchg(&_cld, cur, next)) == cur) { + return cur; } - - head = old_head; + cur = old; } - - // Nothing more for the iterator to hand out. - assert(head == nullptr, "head is " PTR_FORMAT ", expected not null:", p2i(head)); - return nullptr; } void ClassLoaderDataGraph::verify() { diff --git a/src/hotspot/share/classfile/classLoaderDataGraph.hpp b/src/hotspot/share/classfile/classLoaderDataGraph.hpp index 1dcca4d1069..803f227dcf3 100644 --- a/src/hotspot/share/classfile/classLoaderDataGraph.hpp +++ b/src/hotspot/share/classfile/classLoaderDataGraph.hpp @@ -34,7 +34,7 @@ class ClassLoaderDataGraph : public AllStatic { friend class ClassLoaderData; - friend class ClassLoaderDataGraphKlassIteratorAtomic; + friend class ClassLoaderDataGraphIteratorAtomic; friend class VMStructs; private: class ClassLoaderDataGraphIterator; @@ -140,14 +140,14 @@ class LockedClassesDo : public KlassClosure { } }; -// An iterator that distributes Klasses to parallel worker threads. -class ClassLoaderDataGraphKlassIteratorAtomic : public StackObj { - Klass* volatile _next_klass; - public: - ClassLoaderDataGraphKlassIteratorAtomic(); - Klass* next_klass(); - private: - static Klass* next_klass_in_cldg(Klass* klass); +// An iterator that distributes Klasses to parallel worker threads based on CLDs. +class ClassLoaderDataGraphIteratorAtomic : public StackObj { + ClassLoaderData* volatile _cld; + +public: + ClassLoaderDataGraphIteratorAtomic(); + + ClassLoaderData* next(); }; #endif // SHARE_CLASSFILE_CLASSLOADERDATAGRAPH_HPP diff --git a/src/hotspot/share/classfile/compactHashtable.cpp b/src/hotspot/share/classfile/compactHashtable.cpp index 9f7ec6bd118..6808ae7bb8f 100644 --- a/src/hotspot/share/classfile/compactHashtable.cpp +++ b/src/hotspot/share/classfile/compactHashtable.cpp @@ -72,10 +72,10 @@ CompactHashtableWriter::~CompactHashtableWriter() { FREE_C_HEAP_ARRAY(GrowableArray*, _buckets); } -// Add a symbol entry to the temporary hash table -void CompactHashtableWriter::add(unsigned int hash, u4 value) { +// Add an entry to the temporary hash table +void CompactHashtableWriter::add(unsigned int hash, u4 encoded_value) { int index = hash % _num_buckets; - _buckets[index]->append_if_missing(Entry(hash, value)); + _buckets[index]->append_if_missing(Entry(hash, encoded_value)); _num_entries_written++; } @@ -107,27 +107,28 @@ void CompactHashtableWriter::allocate_table() { SharedSpaceObjectAlignment); } -// Write the compact table's buckets +// Write the compact table's buckets and entries void CompactHashtableWriter::dump_table(NumberSeq* summary) { u4 offset = 0; for (int index = 0; index < _num_buckets; index++) { GrowableArray* bucket = _buckets[index]; int bucket_size = bucket->length(); if (bucket_size == 1) { - // bucket with one entry is compacted and only has the symbol offset _compact_buckets->at_put(index, BUCKET_INFO(offset, VALUE_ONLY_BUCKET_TYPE)); Entry ent = bucket->at(0); - _compact_entries->at_put(offset++, ent.value()); + // bucket with one entry is value_only and only has the encoded_value + _compact_entries->at_put(offset++, ent.encoded_value()); _num_value_only_buckets++; } else { - // regular bucket, each entry is a symbol (hash, offset) pair + // regular bucket, it could contain zero or more than one entry, + // each entry is a pair _compact_buckets->at_put(index, BUCKET_INFO(offset, REGULAR_BUCKET_TYPE)); for (int i=0; iat(i); - _compact_entries->at_put(offset++, u4(ent.hash())); // write entry hash - _compact_entries->at_put(offset++, ent.value()); + _compact_entries->at_put(offset++, u4(ent.hash())); // write entry hash + _compact_entries->at_put(offset++, ent.encoded_value()); // write entry encoded_value } if (bucket_size == 0) { _num_empty_buckets++; @@ -189,15 +190,7 @@ void SimpleCompactHashtable::init(address base_address, u4 entry_count, u4 bucke _entries = entries; } -size_t SimpleCompactHashtable::calculate_header_size() { - // We have 5 fields. Each takes up sizeof(intptr_t). See WriteClosure::do_u4 - size_t bytes = sizeof(intptr_t) * 5; - return bytes; -} - void SimpleCompactHashtable::serialize_header(SerializeClosure* soc) { - // NOTE: if you change this function, you MUST change the number 5 in - // calculate_header_size() accordingly. soc->do_u4(&_entry_count); soc->do_u4(&_bucket_count); soc->do_ptr(&_buckets); diff --git a/src/hotspot/share/classfile/compactHashtable.hpp b/src/hotspot/share/classfile/compactHashtable.hpp index 83299eda8c7..cb241ef5e70 100644 --- a/src/hotspot/share/classfile/compactHashtable.hpp +++ b/src/hotspot/share/classfile/compactHashtable.hpp @@ -35,7 +35,7 @@ template < typename K, typename V, - V (*DECODE)(address base_address, u4 offset), + V (*DECODE)(address base_address, u4 encoded_value), bool (*EQUALS)(V value, K key, int len) > class CompactHashtable; @@ -62,8 +62,9 @@ class CompactHashtableStats { // The compact hash table writer. Used at dump time for writing out // the compact table to the shared archive. // -// At dump time, the CompactHashtableWriter obtains all entries from the -// symbol/string table and adds them to a new temporary hash table. The hash +// At dump time, the CompactHashtableWriter obtains all entries from +// a table (the table could be in any form of a collection of pair) +// and adds them to a new temporary hash table (_buckets). The hash // table size (number of buckets) is calculated using // '(num_entries + bucket_size - 1) / bucket_size'. The default bucket // size is 4 and can be changed by -XX:SharedSymbolTableBucketSize option. @@ -76,10 +77,10 @@ class CompactHashtableStats { // above the CompactHashtable class for the table layout detail. The bucket // offsets are written to the archive as part of the compact table. The // bucket offset is encoded in the low 30-bit (0-29) and the bucket type -// (regular or compact) are encoded in bit[31, 30]. For buckets with more -// than one entry, both hash and entry offset are written to the -// table. For buckets with only one entry, only the entry offset is written -// to the table and the buckets are tagged as compact in their type bits. +// (regular or value_only) are encoded in bit[31, 30]. For buckets with more +// than one entry, both hash and encoded_value are written to the +// table. For buckets with only one entry, only the encoded_value is written +// to the table and the buckets are tagged as value_only in their type bits. // Buckets without entry are skipped from the table. Their offsets are // still written out for faster lookup. // @@ -87,21 +88,21 @@ class CompactHashtableWriter: public StackObj { public: class Entry { unsigned int _hash; - u4 _value; + u4 _encoded_value; public: Entry() {} - Entry(unsigned int hash, u4 val) : _hash(hash), _value(val) {} + Entry(unsigned int hash, u4 encoded_value) : _hash(hash), _encoded_value(encoded_value) {} - u4 value() { - return _value; + u4 encoded_value() { + return _encoded_value; } unsigned int hash() { return _hash; } bool operator==(const CompactHashtableWriter::Entry& other) { - return (_value == other._value && _hash == other._hash); + return (_encoded_value == other._encoded_value && _hash == other._hash); } }; // class CompactHashtableWriter::Entry @@ -121,7 +122,8 @@ class CompactHashtableWriter: public StackObj { CompactHashtableWriter(int num_entries, CompactHashtableStats* stats); ~CompactHashtableWriter(); - void add(unsigned int hash, u4 value); + void add(unsigned int hash, u4 encoded_value); + void dump(SimpleCompactHashtable *cht, const char* table_name); private: void allocate_table(); @@ -131,9 +133,6 @@ class CompactHashtableWriter: public StackObj { // calculation of num_buckets can result in zero buckets, we need at least one return (num_buckets < 1) ? 1 : num_buckets; } - -public: - void dump(SimpleCompactHashtable *cht, const char* table_name); }; #endif // INCLUDE_CDS @@ -148,7 +147,8 @@ class CompactHashtableWriter: public StackObj { ///////////////////////////////////////////////////////////////////////////// // -// CompactHashtable is used to store the CDS archive's symbol/string tables. +// CompactHashtable is used to store the CDS archive's tables. +// A table could be in any form of a collection of pair. // // Because these tables are read-only (no entries can be added/deleted) at run-time // and tend to have large number of entries, we try to minimize the footprint @@ -162,32 +162,47 @@ class CompactHashtableWriter: public StackObj { // The size of buckets[] is 'num_buckets + 1'. Each entry of // buckets[] is a 32-bit encoding of the bucket type and bucket offset, // with the type in the left-most 2-bit and offset in the remaining 30-bit. -// The last entry is a special type. It contains the end of the last -// bucket. // -// There are two types of buckets, regular buckets and value_only buckets. The -// value_only buckets have '01' in their highest 2-bit, and regular buckets have -// '00' in their highest 2-bit. +// There are three types of buckets: regular, value_only, and table_end. +// . The regular buckets have '00' in their highest 2-bit. +// . The value_only buckets have '01' in their highest 2-bit. +// . There is only a single table_end bucket that marks the end of buckets[]. +// It has '11' in its highest 2-bit. // -// For normal buckets, each entry is 8 bytes in the entries[]: -// u4 hash; /* symbol/string hash */ -// union { -// u4 offset; /* Symbol* sym = (Symbol*)(base_address + offset) */ -// narrowOop str; /* String narrowOop encoding */ -// } +// For regular buckets, each entry is 8 bytes in the entries[]: +// u4 hash; // entry hash +// u4 encoded_value; // A 32-bit encoding of the template type V. The template parameter DECODE +// // converts this to type V. Many CompactHashtables encode a pointer as a 32-bit offset, where +// // V entry = (V)(base_address + offset) +// // see StringTable, SymbolTable and AdapterHandlerLibrary for examples // +// For value_only buckets, each entry has only the 4-byte 'encoded_value' in the entries[]. // -// For value_only buckets, each entry has only the 4-byte 'offset' in the entries[]. +// The single table_end bucket has no corresponding entry. // -// Example -- note that the second bucket is a VALUE_ONLY_BUCKET_TYPE so the hash code -// is skipped. -// buckets[0, 4, 5, ....] -// | | | -// | | +---+ -// | | | -// | +----+ | -// v v v -// entries[H,O,H,O,O,H,O,H,O.....] +// The number of entries in bucket can be calculated like this: +// my_offset = _buckets[i] & 0x3fffffff; // mask off top 2-bit +// next_offset = _buckets[i+1] & 0x3fffffff +// For REGULAR_BUCKET_TYPE +// num_entries = (next_offset - my_offset) / 8; +// For VALUE_ONLY_BUCKET_TYPE +// num_entries = (next_offset - my_offset) / 4; +// +// If bucket is empty, we have my_offset == next_offset. Empty buckets are +// always encoded as regular buckets. +// +// In the following example: +// - Bucket #0 is a REGULAR_BUCKET_TYPE with two entries +// - Bucket #1 is a VALUE_ONLY_BUCKET_TYPE with one entry. +// - Bucket #2 is a REGULAR_BUCKET_TYPE with zero entries. +// +// buckets[0, 4, 5(empty), 5, ...., N(table_end)] +// | | | | | +// | | +---+-----+ | +// | | | | +// | +----+ + | +// v v v v +// entries[H,O,H,O,O,H,O,H,O........] // // See CompactHashtable::lookup() for how the table is searched at runtime. // See CompactHashtableWriter::dump() for how the table is written at CDS @@ -230,21 +245,19 @@ class SimpleCompactHashtable { inline size_t entry_count() const { return _entry_count; } - - static size_t calculate_header_size(); }; template < typename K, typename V, - V (*DECODE)(address base_address, u4 offset), + V (*DECODE)(address base_address, u4 encoded_value), bool (*EQUALS)(V value, K key, int len) > class CompactHashtable : public SimpleCompactHashtable { friend class VMStructs; - V decode(u4 offset) const { - return DECODE(_base_address, offset); + V decode(u4 encoded_value) const { + return DECODE(_base_address, encoded_value); } public: @@ -264,7 +277,7 @@ class CompactHashtable : public SimpleCompactHashtable { } } else { // This is a regular bucket, which has more than one - // entries. Each entry is a pair of entry (hash, offset). + // entries. Each entry is a (hash, value) pair. // Seek until the end of the bucket. u4* entry_max = _entries + BUCKET_OFFSET(_buckets[index + 1]); while (entry < entry_max) { diff --git a/src/hotspot/share/classfile/javaClasses.cpp b/src/hotspot/share/classfile/javaClasses.cpp index 75f54bfa549..cfe55bf7f76 100644 --- a/src/hotspot/share/classfile/javaClasses.cpp +++ b/src/hotspot/share/classfile/javaClasses.cpp @@ -1150,7 +1150,7 @@ void java_lang_Class::create_mirror(Klass* k, Handle class_loader, // Class_klass has to be loaded because it is used to allocate // the mirror. - if (vmClasses::Class_klass_loaded()) { + if (vmClasses::Class_klass_is_loaded()) { Handle mirror; Handle comp_mirror; @@ -1223,7 +1223,7 @@ bool java_lang_Class::restore_archived_mirror(Klass *k, Handle protection_domain, TRAPS) { // Postpone restoring archived mirror until java.lang.Class is loaded. Please // see more details in vmClasses::resolve_all(). - if (!vmClasses::Class_klass_loaded() && !CDSConfig::is_using_aot_linked_classes()) { + if (!vmClasses::Class_klass_is_loaded() && !CDSConfig::is_using_aot_linked_classes()) { assert(fixup_mirror_list() != nullptr, "fixup_mirror_list not initialized"); fixup_mirror_list()->push(k); return true; diff --git a/src/hotspot/share/classfile/systemDictionaryShared.cpp b/src/hotspot/share/classfile/systemDictionaryShared.cpp index 04c2d7ffb84..da022436292 100644 --- a/src/hotspot/share/classfile/systemDictionaryShared.cpp +++ b/src/hotspot/share/classfile/systemDictionaryShared.cpp @@ -354,11 +354,13 @@ void SystemDictionaryShared::check_exclusion_for_self_and_dependencies(InstanceK }); } -// Returns true so the caller can do: return warn_excluded("....."); -bool SystemDictionaryShared::warn_excluded(InstanceKlass* k, const char* reason) { +void SystemDictionaryShared::log_exclusion(InstanceKlass* k, const char* reason, bool is_warning) { ResourceMark rm; - aot_log_warning(aot)("Skipping %s: %s", k->name()->as_C_string(), reason); - return true; + if (is_warning) { + aot_log_warning(aot)("Skipping %s: %s", k->name()->as_C_string(), reason); + } else { + aot_log_info(aot)("Skipping %s: %s", k->name()->as_C_string(), reason); + } } bool SystemDictionaryShared::is_jfr_event_class(InstanceKlass *k) { @@ -377,23 +379,35 @@ bool SystemDictionaryShared::is_early_klass(InstanceKlass* ik) { } bool SystemDictionaryShared::check_self_exclusion(InstanceKlass* k) { + bool log_warning = false; + const char* error = check_self_exclusion_helper(k, log_warning); + if (error != nullptr) { + log_exclusion(k, error, log_warning); + return true; // Should be excluded + } else { + return false; // Should not be excluded + } +} + +const char* SystemDictionaryShared::check_self_exclusion_helper(InstanceKlass* k, bool& log_warning) { assert_lock_strong(DumpTimeTable_lock); if (CDSConfig::is_dumping_final_static_archive() && k->defined_by_other_loaders() && k->in_aot_cache()) { - return false; // Do not exclude: unregistered classes are passed from preimage to final image. + return nullptr; // Do not exclude: unregistered classes are passed from preimage to final image. } if (k->is_in_error_state()) { - return warn_excluded(k, "In error state"); + log_warning = true; + return "In error state"; } if (k->is_scratch_class()) { - return warn_excluded(k, "A scratch class"); + return "A scratch class"; } if (!k->is_loaded()) { - return warn_excluded(k, "Not in loaded state"); + return "Not in loaded state"; } if (has_been_redefined(k)) { - return warn_excluded(k, "Has been redefined"); + return "Has been redefined"; } if (!k->is_hidden() && k->shared_classpath_index() < 0 && is_builtin(k)) { if (k->name()->starts_with("java/lang/invoke/BoundMethodHandle$Species_")) { @@ -401,43 +415,42 @@ bool SystemDictionaryShared::check_self_exclusion(InstanceKlass* k) { if (CDSConfig::is_dumping_method_handles()) { k->set_shared_classpath_index(0); } else { - ResourceMark rm; - aot_log_info(aot)("Skipping %s because it is dynamically generated", k->name()->as_C_string()); - return true; // exclude without warning + return "dynamically generated"; } } else { // These are classes loaded from unsupported locations (such as those loaded by JVMTI native // agent during dump time). - return warn_excluded(k, "Unsupported location"); + return "Unsupported location"; } } if (k->signers() != nullptr) { // We cannot include signed classes in the archive because the certificates // used during dump time may be different than those used during // runtime (due to expiration, etc). - return warn_excluded(k, "Signed JAR"); + return "Signed JAR"; } if (is_jfr_event_class(k)) { // We cannot include JFR event classes because they need runtime-specific // instrumentation in order to work with -XX:FlightRecorderOptions:retransform=false. // There are only a small number of these classes, so it's not worthwhile to // support them and make CDS more complicated. - return warn_excluded(k, "JFR event class"); + return "JFR event class"; } if (!k->is_linked()) { if (has_class_failed_verification(k)) { - return warn_excluded(k, "Failed verification"); + log_warning = true; + return "Failed verification"; } else if (CDSConfig::is_dumping_aot_linked_classes()) { // Most loaded classes should have been speculatively linked by AOTMetaspace::link_class_for_cds(). // Old classes may not be linked if CDSConfig::is_preserving_verification_constraints()==false. // An unlinked class may fail to verify in AOTLinkedClassBulkLoader::init_required_classes_for_loader(), // causing the JVM to fail at bootstrap. - return warn_excluded(k, "Unlinked class not supported by AOTClassLinking"); + return "Unlinked class not supported by AOTClassLinking"; } else if (CDSConfig::is_dumping_preimage_static_archive()) { // When dumping the final static archive, we will unconditionally load and link all // classes from the preimage. We don't want to get a VerifyError when linking this class. - return warn_excluded(k, "Unlinked class not supported by AOTConfiguration"); + return "Unlinked class not supported by AOTConfiguration"; } } else { if (!k->can_be_verified_at_dumptime()) { @@ -447,17 +460,15 @@ bool SystemDictionaryShared::check_self_exclusion(InstanceKlass* k) { // won't work at runtime. // As a result, we cannot store this class. It must be loaded and fully verified // at runtime. - return warn_excluded(k, "Old class has been linked"); + return "Old class has been linked"; } } if (UnregisteredClasses::check_for_exclusion(k)) { - ResourceMark rm; - aot_log_info(aot)("Skipping %s: used only when dumping CDS archive", k->name()->as_C_string()); - return true; + return "used only when dumping CDS archive"; } - return false; + return nullptr; } // Returns true if DumpTimeClassInfo::is_excluded() is true for at least one of k's exclusion dependencies. @@ -511,7 +522,7 @@ bool SystemDictionaryShared::is_dependency_excluded(InstanceKlass* k, InstanceKl DumpTimeClassInfo* dependency_info = get_info_locked(dependency); if (dependency_info->is_excluded()) { ResourceMark rm; - aot_log_warning(aot)("Skipping %s: %s %s is excluded", k->name()->as_C_string(), type, dependency->name()->as_C_string()); + aot_log_info(aot)("Skipping %s: %s %s is excluded", k->name()->as_C_string(), type, dependency->name()->as_C_string()); return true; } return false; @@ -838,7 +849,7 @@ class UnregisteredClassesDuplicationChecker : StackObj { InstanceKlass* k = _list.at(i); bool i_am_first = SystemDictionaryShared::add_unregistered_class(_thread, k); if (!i_am_first) { - SystemDictionaryShared::warn_excluded(k, "Duplicated unregistered class"); + SystemDictionaryShared::log_exclusion(k, "Duplicated unregistered class"); SystemDictionaryShared::set_excluded_locked(k); } } @@ -967,7 +978,7 @@ bool SystemDictionaryShared::has_class_failed_verification(InstanceKlass* ik) { } void SystemDictionaryShared::set_from_class_file_load_hook(InstanceKlass* ik) { - warn_excluded(ik, "From ClassFileLoadHook"); + log_exclusion(ik, "From ClassFileLoadHook"); set_excluded(ik); } diff --git a/src/hotspot/share/classfile/systemDictionaryShared.hpp b/src/hotspot/share/classfile/systemDictionaryShared.hpp index baad020cb61..5ff57653dd0 100644 --- a/src/hotspot/share/classfile/systemDictionaryShared.hpp +++ b/src/hotspot/share/classfile/systemDictionaryShared.hpp @@ -180,6 +180,7 @@ class SystemDictionaryShared: public SystemDictionary { // exclusion checks static void check_exclusion_for_self_and_dependencies(InstanceKlass *k); static bool check_self_exclusion(InstanceKlass* k); + static const char* check_self_exclusion_helper(InstanceKlass* k, bool& log_warning); static bool check_dependencies_exclusion(InstanceKlass* k, DumpTimeClassInfo* info); static bool check_verification_constraint_exclusion(InstanceKlass* k, Symbol* constraint_class_name); static bool is_dependency_excluded(InstanceKlass* k, InstanceKlass* dependency, const char* type); @@ -277,7 +278,7 @@ class SystemDictionaryShared: public SystemDictionary { static void set_excluded(InstanceKlass* k); static void set_excluded_locked(InstanceKlass* k); static void set_from_class_file_load_hook(InstanceKlass* k) NOT_CDS_RETURN; - static bool warn_excluded(InstanceKlass* k, const char* reason); + static void log_exclusion(InstanceKlass* k, const char* reason, bool is_warning = false); static void dumptime_classes_do(class MetaspaceClosure* it); static void write_to_archive(bool is_static_archive = true); static void serialize_dictionary_headers(class SerializeClosure* soc, diff --git a/src/hotspot/share/classfile/verifier.cpp b/src/hotspot/share/classfile/verifier.cpp index f6f5aa70fbd..bc278f3d158 100644 --- a/src/hotspot/share/classfile/verifier.cpp +++ b/src/hotspot/share/classfile/verifier.cpp @@ -237,7 +237,7 @@ bool Verifier::verify(InstanceKlass* klass, bool should_verify_class, TRAPS) { // Exclude any classes that are verified with the old verifier, as the old verifier // doesn't call SystemDictionaryShared::add_verification_constraint() if (CDSConfig::is_dumping_archive()) { - SystemDictionaryShared::warn_excluded(klass, "Verified with old verifier"); + SystemDictionaryShared::log_exclusion(klass, "Verified with old verifier"); SystemDictionaryShared::set_excluded(klass); } #endif diff --git a/src/hotspot/share/classfile/vmClasses.cpp b/src/hotspot/share/classfile/vmClasses.cpp index e337d5569bc..478f40ff05b 100644 --- a/src/hotspot/share/classfile/vmClasses.cpp +++ b/src/hotspot/share/classfile/vmClasses.cpp @@ -113,7 +113,7 @@ void vmClasses::resolve_until(vmClassID limit_id, vmClassID &start_id, TRAPS) { } void vmClasses::resolve_all(TRAPS) { - assert(!Object_klass_loaded(), "well-known classes should only be initialized once"); + assert(!Object_klass_is_loaded(), "well-known classes should only be initialized once"); // Create the ModuleEntry for java.base. This call needs to be done here, // after vmSymbols::initialize() is called but before any classes are pre-loaded. diff --git a/src/hotspot/share/classfile/vmClasses.hpp b/src/hotspot/share/classfile/vmClasses.hpp index 4fa078c50cd..caa54590eb2 100644 --- a/src/hotspot/share/classfile/vmClasses.hpp +++ b/src/hotspot/share/classfile/vmClasses.hpp @@ -102,12 +102,6 @@ class vmClasses : AllStatic { assert((uint)t < T_VOID+1, "range check"); return check_klass(_box_klasses[t]); } - - static bool Object_klass_loaded() { return is_loaded(VM_CLASS_AT(Object_klass)); } - static bool Class_klass_loaded() { return is_loaded(VM_CLASS_AT(Class_klass)); } - static bool Cloneable_klass_loaded() { return is_loaded(VM_CLASS_AT(Cloneable_klass)); } - static bool Parameter_klass_loaded() { return is_loaded(VM_CLASS_AT(reflect_Parameter_klass)); } - static bool ClassLoader_klass_loaded() { return is_loaded(VM_CLASS_AT(ClassLoader_klass)); } }; #endif // SHARE_CLASSFILE_VMCLASSES_HPP diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index fbd9f5030c8..c0091cd2f65 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -791,15 +791,9 @@ class CheckClass : public MetadataClosure { }; #endif // ASSERT - -static void clean_ic_if_metadata_is_dead(CompiledIC *ic) { - ic->clean_metadata(); -} - // Clean references to unloaded nmethods at addr from this one, which is not unloaded. template -static void clean_if_nmethod_is_unloaded(CallsiteT* callsite, nmethod* from, - bool clean_all) { +static void clean_if_nmethod_is_unloaded(CallsiteT* callsite, bool clean_all) { CodeBlob* cb = CodeCache::find_blob(callsite->destination()); if (!cb->is_nmethod()) { return; @@ -874,15 +868,15 @@ void nmethod::cleanup_inline_caches_impl(bool unloading_occurred, bool clean_all if (unloading_occurred) { // If class unloading occurred we first clear ICs where the cached metadata // is referring to an unloaded klass or method. - clean_ic_if_metadata_is_dead(CompiledIC_at(&iter)); + CompiledIC_at(&iter)->clean_metadata(); } - clean_if_nmethod_is_unloaded(CompiledIC_at(&iter), this, clean_all); + clean_if_nmethod_is_unloaded(CompiledIC_at(&iter), clean_all); break; case relocInfo::opt_virtual_call_type: case relocInfo::static_call_type: - clean_if_nmethod_is_unloaded(CompiledDirectCall::at(iter.reloc()), this, clean_all); + clean_if_nmethod_is_unloaded(CompiledDirectCall::at(iter.reloc()), clean_all); break; case relocInfo::static_stub_type: { diff --git a/src/hotspot/share/code/nmethod.hpp b/src/hotspot/share/code/nmethod.hpp index 3abda6010b7..020370c504b 100644 --- a/src/hotspot/share/code/nmethod.hpp +++ b/src/hotspot/share/code/nmethod.hpp @@ -1080,4 +1080,13 @@ class nmethod : public CodeBlob { static const Vptr _vpntr; }; +struct NMethodMarkingScope : StackObj { + NMethodMarkingScope() { + nmethod::oops_do_marking_prologue(); + } + ~NMethodMarkingScope() { + nmethod::oops_do_marking_epilogue(); + } +}; + #endif // SHARE_CODE_NMETHOD_HPP diff --git a/src/hotspot/share/compiler/compileBroker.cpp b/src/hotspot/share/compiler/compileBroker.cpp index 226a6d3ad5c..574f4d6543b 100644 --- a/src/hotspot/share/compiler/compileBroker.cpp +++ b/src/hotspot/share/compiler/compileBroker.cpp @@ -1064,7 +1064,7 @@ void CompileBroker::possibly_add_compiler_threads(JavaThread* THREAD) { if (new_c2_count <= old_c2_count && new_c1_count <= old_c1_count) return; // Now, we do the more expensive operations. - size_t free_memory = 0; + physical_memory_size_type free_memory = 0; // Return value ignored - defaulting to 0 on failure. (void)os::free_memory(free_memory); // If SegmentedCodeCache is off, both values refer to the single heap (with type CodeBlobType::All). diff --git a/src/hotspot/share/gc/g1/g1NUMA.cpp b/src/hotspot/share/gc/g1/g1NUMA.cpp index cd7dc55d0fe..778ed31d7b5 100644 --- a/src/hotspot/share/gc/g1/g1NUMA.cpp +++ b/src/hotspot/share/gc/g1/g1NUMA.cpp @@ -203,9 +203,7 @@ uint G1NUMA::index_for_region(G1HeapRegion* hr) const { // * G1HeapRegion #: |-#0-||-#1-||-#2-||-#3-||-#4-||-#5-||-#6-||-#7-||-#8-||-#9-||#10-||#11-||#12-||#13-||#14-||#15-| // * NUMA node #: |----#0----||----#1----||----#2----||----#3----||----#0----||----#1----||----#2----||----#3----| void G1NUMA::request_memory_on_node(void* aligned_address, size_t size_in_bytes, uint region_index) { - if (!is_enabled()) { - return; - } + assert(is_enabled(), "must be, check before"); if (size_in_bytes == 0) { return; diff --git a/src/hotspot/share/gc/g1/g1PeriodicGCTask.cpp b/src/hotspot/share/gc/g1/g1PeriodicGCTask.cpp index afbd0f35ce6..0a7367fcab5 100644 --- a/src/hotspot/share/gc/g1/g1PeriodicGCTask.cpp +++ b/src/hotspot/share/gc/g1/g1PeriodicGCTask.cpp @@ -54,11 +54,17 @@ bool G1PeriodicGCTask::should_start_periodic_gc(G1CollectedHeap* g1h, // Check if load is lower than max. double recent_load; - if ((G1PeriodicGCSystemLoadThreshold > 0.0f) && - (os::loadavg(&recent_load, 1) == -1 || recent_load > G1PeriodicGCSystemLoadThreshold)) { - log_debug(gc, periodic)("Load %1.2f is higher than threshold %1.2f. Skipping.", - recent_load, G1PeriodicGCSystemLoadThreshold); - return false; + if (G1PeriodicGCSystemLoadThreshold > 0.0) { + if (os::loadavg(&recent_load, 1) == -1) { + G1PeriodicGCSystemLoadThreshold = 0.0; + log_warning(gc, periodic)("System loadavg() call failed, " + "disabling G1PeriodicGCSystemLoadThreshold check."); + // Fall through and start the periodic GC. + } else if (recent_load > G1PeriodicGCSystemLoadThreshold) { + log_debug(gc, periodic)("Load %1.2f is higher than threshold %1.2f. Skipping.", + recent_load, G1PeriodicGCSystemLoadThreshold); + return false; + } } // Record counters with GC safepoints blocked, to get a consistent snapshot. diff --git a/src/hotspot/share/gc/g1/g1RegionToSpaceMapper.cpp b/src/hotspot/share/gc/g1/g1RegionToSpaceMapper.cpp index 1710ceaf73a..5e37c7fa5a1 100644 --- a/src/hotspot/share/gc/g1/g1RegionToSpaceMapper.cpp +++ b/src/hotspot/share/gc/g1/g1RegionToSpaceMapper.cpp @@ -96,13 +96,15 @@ class G1RegionsLargerThanCommitSizeMapper : public G1RegionToSpaceMapper { const size_t start_page = (size_t)start_idx * _pages_per_region; const size_t size_in_pages = num_regions * _pages_per_region; bool zero_filled = _storage.commit(start_page, size_in_pages); - if (_memory_tag == mtJavaHeap) { + + if (should_distribute_across_numa_nodes()) { for (uint region_index = start_idx; region_index < start_idx + num_regions; region_index++ ) { void* address = _storage.page_start(region_index * _pages_per_region); size_t size_in_bytes = _storage.page_size() * _pages_per_region; G1NUMA::numa()->request_memory_on_node(address, size_in_bytes, region_index); } } + if (AlwaysPreTouch) { _storage.pretouch(start_page, size_in_pages, pretouch_workers); } @@ -122,7 +124,7 @@ class G1RegionsLargerThanCommitSizeMapper : public G1RegionToSpaceMapper { // G1RegionToSpaceMapper implementation where the region granularity is smaller // than the commit granularity. -// Basically, the contents of one OS page span several regions. +// Basically, the contents of one OS page spans several regions. class G1RegionsSmallerThanCommitSizeMapper : public G1RegionToSpaceMapper { size_t _regions_per_page; // Lock to prevent bitmap updates and the actual underlying @@ -148,13 +150,18 @@ class G1RegionsSmallerThanCommitSizeMapper : public G1RegionToSpaceMapper { return _region_commit_map.find_first_set_bit(region, region_limit) != region_limit; } - void numa_request_on_node(size_t page_idx) { - if (_memory_tag == mtJavaHeap) { - uint region = (uint)(page_idx * _regions_per_page); - void* address = _storage.page_start(page_idx); - size_t size_in_bytes = _storage.page_size(); - G1NUMA::numa()->request_memory_on_node(address, size_in_bytes, region); + bool commit_pages(size_t start_page, size_t size_in_pages) { + bool result = _storage.commit(start_page, size_in_pages); + + if (should_distribute_across_numa_nodes()) { + for (size_t page = start_page; page < start_page + size_in_pages; page++) { + uint region = checked_cast(page * _regions_per_page); + void* address = _storage.page_start(page); + size_t size_in_bytes = _storage.page_size(); + G1NUMA::numa()->request_memory_on_node(address, size_in_bytes, region); + } } + return result; } public: @@ -171,6 +178,21 @@ class G1RegionsSmallerThanCommitSizeMapper : public G1RegionToSpaceMapper { guarantee((page_size * commit_factor) >= alloc_granularity, "allocation granularity smaller than commit granularity"); } + size_t find_first_uncommitted(size_t page, size_t end) { + assert(page < end, "must be"); + while (page < end && is_page_committed(page)) { + page++; + } + return page; + } + + size_t find_first_committed(size_t page, size_t end) { + while (page < end && !is_page_committed(page)) { + page++; + } + return MIN2(page, end); + } + virtual void commit_regions(uint start_idx, size_t num_regions, WorkerThreads* pretouch_workers) { uint region_limit = (uint)(start_idx + num_regions); assert(num_regions > 0, "Must commit at least one region"); @@ -179,11 +201,11 @@ class G1RegionsSmallerThanCommitSizeMapper : public G1RegionToSpaceMapper { size_t const NoPage = SIZE_MAX; - size_t first_committed = NoPage; - size_t num_committed = 0; + size_t first_newly_committed = NoPage; + size_t num_committed_pages = 0; - size_t start_page = region_idx_to_page_idx(start_idx); - size_t end_page = region_idx_to_page_idx(region_limit - 1); + size_t const start_page = region_idx_to_page_idx(start_idx); + size_t const end_page = region_idx_to_page_idx(region_limit - 1) + 1; bool all_zero_filled = true; @@ -191,34 +213,27 @@ class G1RegionsSmallerThanCommitSizeMapper : public G1RegionToSpaceMapper { // underlying OS page. See lock declaration for more details. { MutexLocker ml(&_lock, Mutex::_no_safepoint_check_flag); - for (size_t page = start_page; page <= end_page; page++) { - if (!is_page_committed(page)) { - // Page not committed. - if (num_committed == 0) { - first_committed = page; - } - num_committed++; - - if (!_storage.commit(page, 1)) { - // Found dirty region during commit. - all_zero_filled = false; - } - - // Move memory to correct NUMA node for the heap. - numa_request_on_node(page); - } else { - // Page already committed. - all_zero_filled = false; - } + + size_t uncommitted_l = find_first_uncommitted(start_page, end_page); + size_t uncommitted_r = find_first_committed(uncommitted_l + 1, end_page); + + first_newly_committed = uncommitted_l; + num_committed_pages = uncommitted_r - uncommitted_l; + + if (num_committed_pages > 0 && + !commit_pages(first_newly_committed, num_committed_pages)) { + all_zero_filled = false; } + all_zero_filled &= (uncommitted_l == start_page) && (uncommitted_r == end_page); + // Update the commit map for the given range. Not using the par_set_range // since updates to _region_commit_map for this mapper is protected by _lock. _region_commit_map.set_range(start_idx, region_limit, BitMap::unknown_range); } - if (AlwaysPreTouch && num_committed > 0) { - _storage.pretouch(first_committed, num_committed, pretouch_workers); + if (AlwaysPreTouch && num_committed_pages > 0) { + _storage.pretouch(first_newly_committed, num_committed_pages, pretouch_workers); } fire_on_commit(start_idx, num_regions, all_zero_filled); @@ -230,8 +245,8 @@ class G1RegionsSmallerThanCommitSizeMapper : public G1RegionToSpaceMapper { assert(_region_commit_map.find_first_clear_bit(start_idx, region_limit) == region_limit, "Should only be committed regions in the range [%u, %u)", start_idx, region_limit); - size_t start_page = region_idx_to_page_idx(start_idx); - size_t end_page = region_idx_to_page_idx(region_limit - 1); + size_t const start_page = region_idx_to_page_idx(start_idx); + size_t const end_page = region_idx_to_page_idx(region_limit - 1) + 1; // Concurrent operations might operate on regions sharing the same // underlying OS page. See lock declaration for more details. @@ -240,13 +255,16 @@ class G1RegionsSmallerThanCommitSizeMapper : public G1RegionToSpaceMapper { // updates to _region_commit_map for this mapper is protected by _lock. _region_commit_map.clear_range(start_idx, region_limit, BitMap::unknown_range); - for (size_t page = start_page; page <= end_page; page++) { - // We know all pages were committed before clearing the map. If the - // the page is still marked as committed after the clear we should - // not uncommit it. - if (!is_page_committed(page)) { - _storage.uncommit(page, 1); - } + // We know all pages were committed before clearing the map. If the + // the page is still marked as committed after the clear we should + // not uncommit it. + size_t uncommitted_l = find_first_uncommitted(start_page, end_page); + size_t uncommitted_r = find_first_committed(uncommitted_l + 1, end_page); + + size_t num_uncommitted_pages_found = uncommitted_r - uncommitted_l; + + if (num_uncommitted_pages_found > 0) { + _storage.uncommit(uncommitted_l, num_uncommitted_pages_found); } } }; @@ -257,6 +275,10 @@ void G1RegionToSpaceMapper::fire_on_commit(uint start_idx, size_t num_regions, b } } +bool G1RegionToSpaceMapper::should_distribute_across_numa_nodes() const { + return _memory_tag == mtJavaHeap && G1NUMA::numa()->is_enabled(); +} + G1RegionToSpaceMapper* G1RegionToSpaceMapper::create_mapper(ReservedSpace rs, size_t actual_size, size_t page_size, diff --git a/src/hotspot/share/gc/g1/g1RegionToSpaceMapper.hpp b/src/hotspot/share/gc/g1/g1RegionToSpaceMapper.hpp index 823fa549f36..e2fc3d4fa04 100644 --- a/src/hotspot/share/gc/g1/g1RegionToSpaceMapper.hpp +++ b/src/hotspot/share/gc/g1/g1RegionToSpaceMapper.hpp @@ -58,6 +58,8 @@ class G1RegionToSpaceMapper : public CHeapObj { G1RegionToSpaceMapper(ReservedSpace rs, size_t used_size, size_t page_size, size_t region_granularity, size_t commit_factor, MemTag mem_tag); void fire_on_commit(uint start_idx, size_t num_regions, bool zero_filled); + + bool should_distribute_across_numa_nodes() const; public: MemRegion reserved() { return _storage.reserved(); } diff --git a/src/hotspot/share/gc/g1/g1ThreadLocalData.hpp b/src/hotspot/share/gc/g1/g1ThreadLocalData.hpp index 858081b0581..07c8c569504 100644 --- a/src/hotspot/share/gc/g1/g1ThreadLocalData.hpp +++ b/src/hotspot/share/gc/g1/g1ThreadLocalData.hpp @@ -36,6 +36,15 @@ class G1ThreadLocalData { private: SATBMarkQueue _satb_mark_queue; + // The current base address of the card table. Accessed by the barrier to do + // the card mark. Changed as required by the refinement control thread to + // implement card table switching. + // + // Tests showed that embedding this value in the TLS block is the cheapest + // way for fast access to this value in the barrier. + // E.g. embedding an address to that value directly into the code stream and + // then loading from that was found to be slower on non-x64 architectures. + // Additionally it increases code size a lot. G1CardTable::CardValue* _byte_map_base; // Per-thread cache of pinned object count to reduce atomic operation traffic diff --git a/src/hotspot/share/gc/parallel/mutableNUMASpace.cpp b/src/hotspot/share/gc/parallel/mutableNUMASpace.cpp index 08569fd5bd1..df4312ebd75 100644 --- a/src/hotspot/share/gc/parallel/mutableNUMASpace.cpp +++ b/src/hotspot/share/gc/parallel/mutableNUMASpace.cpp @@ -118,73 +118,30 @@ size_t MutableNUMASpace::free_in_words() const { return s; } -int MutableNUMASpace::lgrp_space_index(int lgrp_id) const { - return lgrp_spaces()->find_if([&](LGRPSpace* space) { - return space->lgrp_id() == checked_cast(lgrp_id); +MutableNUMASpace::LGRPSpace *MutableNUMASpace::lgrp_space_for_thread(Thread* thr) const { + guarantee(thr != nullptr, "No thread"); + + int lgrp_id = thr->lgrp_id(); + assert(lgrp_id != -1, "lgrp_id must be set during thread creation"); + + int lgrp_spaces_index = lgrp_spaces()->find_if([&](LGRPSpace* space) { + return space->lgrp_id() == (uint)lgrp_id; }); + + assert(lgrp_spaces_index != -1, "must have created spaces for all lgrp_ids"); + return lgrp_spaces()->at(lgrp_spaces_index); } size_t MutableNUMASpace::tlab_capacity(Thread *thr) const { - guarantee(thr != nullptr, "No thread"); - int lgrp_id = thr->lgrp_id(); - if (lgrp_id == -1) { - // This case can occur after the topology of the system has - // changed. Thread can change their location, the new home - // group will be determined during the first allocation - // attempt. For now we can safely assume that all spaces - // have equal size because the whole space will be reinitialized. - if (lgrp_spaces()->length() > 0) { - return capacity_in_bytes() / lgrp_spaces()->length(); - } else { - assert(false, "There should be at least one locality group"); - return 0; - } - } - // That's the normal case, where we know the locality group of the thread. - int i = lgrp_space_index(lgrp_id); - if (i == -1) { - return 0; - } - return lgrp_spaces()->at(i)->space()->capacity_in_bytes(); + return lgrp_space_for_thread(thr)->space()->capacity_in_bytes(); } size_t MutableNUMASpace::tlab_used(Thread *thr) const { - // Please see the comments for tlab_capacity(). - guarantee(thr != nullptr, "No thread"); - int lgrp_id = thr->lgrp_id(); - if (lgrp_id == -1) { - if (lgrp_spaces()->length() > 0) { - return (used_in_bytes()) / lgrp_spaces()->length(); - } else { - assert(false, "There should be at least one locality group"); - return 0; - } - } - int i = lgrp_space_index(lgrp_id); - if (i == -1) { - return 0; - } - return lgrp_spaces()->at(i)->space()->used_in_bytes(); + return lgrp_space_for_thread(thr)->space()->used_in_bytes(); } - size_t MutableNUMASpace::unsafe_max_tlab_alloc(Thread *thr) const { - // Please see the comments for tlab_capacity(). - guarantee(thr != nullptr, "No thread"); - int lgrp_id = thr->lgrp_id(); - if (lgrp_id == -1) { - if (lgrp_spaces()->length() > 0) { - return free_in_bytes() / lgrp_spaces()->length(); - } else { - assert(false, "There should be at least one locality group"); - return 0; - } - } - int i = lgrp_space_index(lgrp_id); - if (i == -1) { - return 0; - } - return lgrp_spaces()->at(i)->space()->free_in_bytes(); + return lgrp_space_for_thread(thr)->space()->free_in_bytes(); } // Bias region towards the first-touching lgrp. Set the right page sizes. @@ -528,32 +485,13 @@ void MutableNUMASpace::clear(bool mangle_space) { } } -/* - Linux supports static memory binding, therefore the most part of the - logic dealing with the possible invalid page allocation is effectively - disabled. Besides there is no notion of the home node in Linux. A - thread is allowed to migrate freely. Although the scheduler is rather - reluctant to move threads between the nodes. We check for the current - node every allocation. And with a high probability a thread stays on - the same node for some time allowing local access to recently allocated - objects. - */ - HeapWord* MutableNUMASpace::cas_allocate(size_t size) { - Thread* thr = Thread::current(); - int lgrp_id = thr->lgrp_id(); - if (lgrp_id == -1 || !os::numa_has_group_homing()) { - lgrp_id = os::numa_get_group_id(); - thr->set_lgrp_id(lgrp_id); - } + Thread *thr = Thread::current(); - int i = lgrp_space_index(lgrp_id); - // It is possible that a new CPU has been hotplugged and - // we haven't reshaped the space accordingly. - if (i == -1) { - i = os::random() % lgrp_spaces()->length(); - } - LGRPSpace *ls = lgrp_spaces()->at(i); + // Update the locality group to match where the thread actually is. + thr->update_lgrp_id(); + + LGRPSpace *ls = lgrp_space_for_thread(thr); MutableSpace *s = ls->space(); HeapWord *p = s->cas_allocate(size); if (p != nullptr) { diff --git a/src/hotspot/share/gc/parallel/mutableNUMASpace.hpp b/src/hotspot/share/gc/parallel/mutableNUMASpace.hpp index abb4c77952a..3699dcde964 100644 --- a/src/hotspot/share/gc/parallel/mutableNUMASpace.hpp +++ b/src/hotspot/share/gc/parallel/mutableNUMASpace.hpp @@ -152,7 +152,7 @@ class MutableNUMASpace : public MutableSpace { void select_tails(MemRegion new_region, MemRegion intersection, MemRegion* bottom_region, MemRegion *top_region); - int lgrp_space_index(int lgrp_id) const; + LGRPSpace *lgrp_space_for_thread(Thread *thr) const; public: GrowableArray* lgrp_spaces() const { return _lgrp_spaces; } diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.cpp b/src/hotspot/share/gc/parallel/psParallelCompact.cpp index f4383e573af..af812c652a6 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.cpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.cpp @@ -1053,24 +1053,19 @@ bool PSParallelCompact::invoke(bool clear_all_soft_refs, bool should_do_max_comp } class PCAddThreadRootsMarkingTaskClosure : public ThreadClosure { -private: - uint _worker_id; + ParCompactionManager* _cm; public: - PCAddThreadRootsMarkingTaskClosure(uint worker_id) : _worker_id(worker_id) { } + PCAddThreadRootsMarkingTaskClosure(ParCompactionManager* cm) : _cm(cm) { } void do_thread(Thread* thread) { - assert(ParallelScavengeHeap::heap()->is_stw_gc_active(), "called outside gc"); - ResourceMark rm; - ParCompactionManager* cm = ParCompactionManager::gc_thread_compaction_manager(_worker_id); - - MarkingNMethodClosure mark_and_push_in_blobs(&cm->_mark_and_push_closure); + MarkingNMethodClosure mark_and_push_in_blobs(&_cm->_mark_and_push_closure); - thread->oops_do(&cm->_mark_and_push_closure, &mark_and_push_in_blobs); + thread->oops_do(&_cm->_mark_and_push_closure, &mark_and_push_in_blobs); // Do the real work - cm->follow_marking_stacks(); + _cm->follow_marking_stacks(); } }; @@ -1114,7 +1109,7 @@ class MarkFromRootsTask : public WorkerTask { } { - PCAddThreadRootsMarkingTaskClosure closure(worker_id); + PCAddThreadRootsMarkingTaskClosure closure(cm); Threads::possibly_parallel_threads_do(_active_workers > 1 /* is_par */, &closure); } @@ -1660,21 +1655,19 @@ static void compaction_with_stealing_work(TaskTerminator* terminator, uint worke } class FillDensePrefixAndCompactionTask: public WorkerTask { - uint _num_workers; TaskTerminator _terminator; public: FillDensePrefixAndCompactionTask(uint active_workers) : WorkerTask("FillDensePrefixAndCompactionTask"), - _num_workers(active_workers), _terminator(active_workers, ParCompactionManager::region_task_queues()) { } virtual void work(uint worker_id) { - { + if (worker_id == 0) { auto start = Ticks::now(); - PSParallelCompact::fill_dead_objs_in_dense_prefix(worker_id, _num_workers); - log_trace(gc, phases)("Fill dense prefix by worker %u: %.3f ms", worker_id, (Ticks::now() - start).seconds() * 1000); + PSParallelCompact::fill_dead_objs_in_dense_prefix(); + log_trace(gc, phases)("Fill dense prefix by worker 0: %.3f ms", (Ticks::now() - start).seconds() * 1000); } compaction_with_stealing_work(&_terminator, worker_id); } @@ -1687,9 +1680,10 @@ void PSParallelCompact::fill_range_in_dense_prefix(HeapWord* start, HeapWord* en assert(mark_bitmap()->find_obj_beg(start, end) == end, "precondition"); HeapWord* bottom = _space_info[old_space_id].space()->bottom(); if (start != bottom) { + // The preceding live obj. HeapWord* obj_start = mark_bitmap()->find_obj_beg_reverse(bottom, start); - HeapWord* after_obj = obj_start + cast_to_oop(obj_start)->size(); - assert(after_obj == start, "precondition"); + HeapWord* obj_end = obj_start + cast_to_oop(obj_start)->size(); + assert(obj_end == start, "precondition"); } } #endif @@ -1703,58 +1697,51 @@ void PSParallelCompact::fill_range_in_dense_prefix(HeapWord* start, HeapWord* en } while (addr < end); } -void PSParallelCompact::fill_dead_objs_in_dense_prefix(uint worker_id, uint num_workers) { +void PSParallelCompact::fill_dead_objs_in_dense_prefix() { ParMarkBitMap* bitmap = mark_bitmap(); HeapWord* const bottom = _space_info[old_space_id].space()->bottom(); HeapWord* const prefix_end = dense_prefix(old_space_id); - if (bottom == prefix_end) { - return; - } - - size_t bottom_region = _summary_data.addr_to_region_idx(bottom); - size_t prefix_end_region = _summary_data.addr_to_region_idx(prefix_end); + const size_t region_size = ParallelCompactData::RegionSize; - size_t start_region; - size_t end_region; - split_regions_for_worker(bottom_region, prefix_end_region, - worker_id, num_workers, - &start_region, &end_region); + // Fill dead space in [start_addr, end_addr) + HeapWord* const start_addr = bottom; + HeapWord* const end_addr = prefix_end; - if (start_region == end_region) { - return; - } - - HeapWord* const start_addr = _summary_data.region_to_addr(start_region); - HeapWord* const end_addr = _summary_data.region_to_addr(end_region); + for (HeapWord* cur_addr = start_addr; cur_addr < end_addr; /* empty */) { + RegionData* cur_region_ptr = _summary_data.addr_to_region_ptr(cur_addr); + if (cur_region_ptr->data_size() == region_size) { + // Full; no dead space. Next region. + if (_summary_data.is_region_aligned(cur_addr)) { + cur_addr += region_size; + } else { + cur_addr = _summary_data.region_align_up(cur_addr); + } + continue; + } - // Skip live partial obj (if any) from previous region. - HeapWord* cur_addr; - RegionData* start_region_ptr = _summary_data.region(start_region); - if (start_region_ptr->partial_obj_size() != 0) { - HeapWord* partial_obj_start = start_region_ptr->partial_obj_addr(); - assert(bitmap->is_marked(partial_obj_start), "inv"); - cur_addr = partial_obj_start + cast_to_oop(partial_obj_start)->size(); - } else { - cur_addr = start_addr; - } + // Fill dead space inside cur_region. + if (_summary_data.is_region_aligned(cur_addr)) { + cur_addr += cur_region_ptr->partial_obj_size(); + } - // end_addr is inclusive to handle regions starting with dead space. - while (cur_addr <= end_addr) { - // Use prefix_end to handle trailing obj in each worker region-chunk. - HeapWord* live_start = bitmap->find_obj_beg(cur_addr, prefix_end); - if (cur_addr != live_start) { - // Only worker 0 handles proceeding dead space. - if (cur_addr != start_addr || worker_id == 0) { + HeapWord* region_end_addr = _summary_data.region_align_up(cur_addr + 1); + assert(region_end_addr <= end_addr, "inv"); + while (cur_addr < region_end_addr) { + // Use end_addr to allow filler-obj to cross region boundary. + HeapWord* live_start = bitmap->find_obj_beg(cur_addr, end_addr); + if (cur_addr != live_start) { + // Found dead space [cur_addr, live_start). fill_range_in_dense_prefix(cur_addr, live_start); } + if (live_start >= region_end_addr) { + cur_addr = live_start; + break; + } + assert(bitmap->is_marked(live_start), "inv"); + cur_addr = live_start + cast_to_oop(live_start)->size(); } - if (live_start >= end_addr) { - break; - } - assert(bitmap->is_marked(live_start), "inv"); - cur_addr = live_start + cast_to_oop(live_start)->size(); } } @@ -1787,15 +1774,38 @@ void PSParallelCompact::compact() { void PSParallelCompact::verify_filler_in_dense_prefix() { HeapWord* bottom = _space_info[old_space_id].space()->bottom(); HeapWord* dense_prefix_end = dense_prefix(old_space_id); - HeapWord* cur_addr = bottom; - while (cur_addr < dense_prefix_end) { - oop obj = cast_to_oop(cur_addr); - oopDesc::verify(obj); - if (!mark_bitmap()->is_marked(cur_addr)) { - Klass* k = cast_to_oop(cur_addr)->klass(); - assert(k == Universe::fillerArrayKlass() || k == vmClasses::FillerObject_klass(), "inv"); + + const size_t region_size = ParallelCompactData::RegionSize; + + for (HeapWord* cur_addr = bottom; cur_addr < dense_prefix_end; /* empty */) { + RegionData* cur_region_ptr = _summary_data.addr_to_region_ptr(cur_addr); + if (cur_region_ptr->data_size() == region_size) { + // Full; no dead space. Next region. + if (_summary_data.is_region_aligned(cur_addr)) { + cur_addr += region_size; + } else { + cur_addr = _summary_data.region_align_up(cur_addr); + } + continue; + } + + // This region contains filler objs. + if (_summary_data.is_region_aligned(cur_addr)) { + cur_addr += cur_region_ptr->partial_obj_size(); + } + + HeapWord* region_end_addr = _summary_data.region_align_up(cur_addr + 1); + assert(region_end_addr <= dense_prefix_end, "inv"); + + while (cur_addr < region_end_addr) { + oop obj = cast_to_oop(cur_addr); + oopDesc::verify(obj); + if (!mark_bitmap()->is_marked(cur_addr)) { + Klass* k = cast_to_oop(cur_addr)->klass(); + assert(k == Universe::fillerArrayKlass() || k == vmClasses::FillerObject_klass(), "inv"); + } + cur_addr += obj->size(); } - cur_addr += obj->size(); } } diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.hpp b/src/hotspot/share/gc/parallel/psParallelCompact.hpp index 4d212499b4c..2297d720b35 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.hpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.hpp @@ -755,7 +755,7 @@ class PSParallelCompact : AllStatic { static void fill_range_in_dense_prefix(HeapWord* start, HeapWord* end); public: - static void fill_dead_objs_in_dense_prefix(uint worker_id, uint num_workers); + static void fill_dead_objs_in_dense_prefix(); // This method invokes a full collection. // clear_all_soft_refs controls whether soft-refs should be cleared or not. diff --git a/src/hotspot/share/gc/parallel/psYoungGen.cpp b/src/hotspot/share/gc/parallel/psYoungGen.cpp index 21d023f8207..4fbe314d14c 100644 --- a/src/hotspot/share/gc/parallel/psYoungGen.cpp +++ b/src/hotspot/share/gc/parallel/psYoungGen.cpp @@ -314,7 +314,7 @@ HeapWord* PSYoungGen::expand_and_allocate(size_t word_size) { } HeapWord* result = eden_space()->cas_allocate(word_size); - assert(result, "inv"); + assert(result || UseNUMA, "inv"); return result; } diff --git a/src/hotspot/share/gc/serial/defNewGeneration.cpp b/src/hotspot/share/gc/serial/defNewGeneration.cpp index bcd131a5fa2..42f8b191f5e 100644 --- a/src/hotspot/share/gc/serial/defNewGeneration.cpp +++ b/src/hotspot/share/gc/serial/defNewGeneration.cpp @@ -807,7 +807,7 @@ void DefNewGeneration::reset_scratch() { } } -void DefNewGeneration::gc_epilogue(bool full) { +void DefNewGeneration::gc_epilogue() { assert(!GCLocker::is_active(), "We should not be executing here"); // update the generation and space performance counters update_counters(); diff --git a/src/hotspot/share/gc/serial/defNewGeneration.hpp b/src/hotspot/share/gc/serial/defNewGeneration.hpp index 7f4077873b2..32b6b32f42f 100644 --- a/src/hotspot/share/gc/serial/defNewGeneration.hpp +++ b/src/hotspot/share/gc/serial/defNewGeneration.hpp @@ -187,7 +187,7 @@ class DefNewGeneration: public Generation { HeapWord* allocate(size_t word_size); HeapWord* par_allocate(size_t word_size); - void gc_epilogue(bool full); + void gc_epilogue(); // For Old collection (part of running Full GC), the DefNewGeneration can // contribute the free part of "to-space" as the scratch space. diff --git a/src/hotspot/share/gc/serial/serialFullGC.cpp b/src/hotspot/share/gc/serial/serialFullGC.cpp index d45454a768f..76a335d209f 100644 --- a/src/hotspot/share/gc/serial/serialFullGC.cpp +++ b/src/hotspot/share/gc/serial/serialFullGC.cpp @@ -54,7 +54,6 @@ #include "gc/shared/referencePolicy.hpp" #include "gc/shared/referenceProcessorPhaseTimes.hpp" #include "gc/shared/space.hpp" -#include "gc/shared/strongRootsScope.hpp" #include "gc/shared/weakProcessor.hpp" #include "memory/iterator.inline.hpp" #include "memory/universe.hpp" @@ -483,9 +482,7 @@ void SerialFullGC::phase1_mark(bool clear_all_softrefs) { ref_processor()->start_discovery(clear_all_softrefs); { - StrongRootsScope srs(0); - - MarkingNMethodClosure mark_code_closure(&follow_root_closure); + GCTraceTime(Debug, gc, phases) tm_m("Marking From Roots", gc_timer()); // Start tracing from roots, there are 3 kinds of roots in full-gc. // @@ -494,8 +491,13 @@ void SerialFullGC::phase1_mark(bool clear_all_softrefs) { // strong CLDs. ClassLoaderDataGraph::always_strong_cld_do(&follow_cld_closure); - // 2. Threads stack frames and active nmethods in them. - Threads::oops_do(&follow_root_closure, &mark_code_closure); + { + // 2. Threads stack frames and active nmethods in them. + NMethodMarkingScope nmethod_marking_scope; + MarkingNMethodClosure mark_code_closure(&follow_root_closure); + + Threads::oops_do(&follow_root_closure, &mark_code_closure); + } // 3. VM internal roots. OopStorageSet::strong_oops_do(&follow_root_closure); diff --git a/src/hotspot/share/gc/serial/serialHeap.cpp b/src/hotspot/share/gc/serial/serialHeap.cpp index 89218648fe0..dbd54c302ea 100644 --- a/src/hotspot/share/gc/serial/serialHeap.cpp +++ b/src/hotspot/share/gc/serial/serialHeap.cpp @@ -779,7 +779,7 @@ void SerialHeap::gc_epilogue(bool full) { resize_all_tlabs(); - _young_gen->gc_epilogue(full); + _young_gen->gc_epilogue(); _old_gen->gc_epilogue(); if (_is_heap_almost_full) { diff --git a/src/hotspot/share/gc/shared/cardTable.hpp b/src/hotspot/share/gc/shared/cardTable.hpp index 63dcfe7aecb..ab26055e522 100644 --- a/src/hotspot/share/gc/shared/cardTable.hpp +++ b/src/hotspot/share/gc/shared/cardTable.hpp @@ -61,6 +61,20 @@ class CardTable: public CHeapObj { inline size_t compute_byte_map_size(size_t num_bytes); + // We use 0x00 (zero) to represent Dirty and 0xFF to represent Clean because + // this choice reduces the barrier code by one instruction on architectures with + // a constant-zero register. On such architectures, the Dirty value (0x00) is + // directly accessible through the zero register, eliminating the need to load + // the value explicitly and thereby saving one instruction + // + // E.g. see + // Urs Hölzle. A fast write barrier for generational garbage collectors. + // In Eliot Moss, Paul R. Wilson, and Benjamin Zorn, editors, OOPSLA/ECOOP '93 + // Workshop on Garbage Collection in Object-Oriented Systems, October 1993 + // + // that shows this for SPARC (but aarch32/aarch64/RISC-V are similar in this + // respect). + // enum CardValues { clean_card = (CardValue)-1, diff --git a/src/hotspot/share/gc/shared/gcInitLogger.cpp b/src/hotspot/share/gc/shared/gcInitLogger.cpp index 763c265b65e..ba639945860 100644 --- a/src/hotspot/share/gc/shared/gcInitLogger.cpp +++ b/src/hotspot/share/gc/shared/gcInitLogger.cpp @@ -62,8 +62,9 @@ void GCInitLogger::print_cpu() { } void GCInitLogger::print_memory() { - size_t memory = os::physical_memory(); - log_info_p(gc, init)("Memory: " PROPERFMT, PROPERFMTARGS(memory)); + physical_memory_size_type memory = os::physical_memory(); + log_info_p(gc, init)("Memory: " PHYS_MEM_TYPE_FORMAT "%s", + byte_size_in_proper_unit(memory), proper_unit_for_byte_size(memory)); } void GCInitLogger::print_large_pages() { diff --git a/src/hotspot/share/gc/shared/parallelCleaning.cpp b/src/hotspot/share/gc/shared/parallelCleaning.cpp index 9d496783ca2..d2f69bfa679 100644 --- a/src/hotspot/share/gc/shared/parallelCleaning.cpp +++ b/src/hotspot/share/gc/shared/parallelCleaning.cpp @@ -27,7 +27,7 @@ #include "code/codeCache.hpp" #include "gc/shared/parallelCleaning.hpp" #include "logging/log.hpp" -#include "memory/resourceArea.hpp" +#include "oops/klass.inline.hpp" #include "runtime/atomicAccess.hpp" CodeCacheUnloadingTask::CodeCacheUnloadingTask(uint num_workers, bool unloading_occurred) : @@ -94,38 +94,26 @@ void CodeCacheUnloadingTask::work(uint worker_id) { } } -KlassCleaningTask::KlassCleaningTask() : - _clean_klass_tree_claimed(false), - _klass_iterator() { -} - -bool KlassCleaningTask::claim_clean_klass_tree_task() { - if (_clean_klass_tree_claimed) { - return false; - } +void KlassCleaningTask::work() { + for (ClassLoaderData* cur = _cld_iterator_atomic.next(); cur != nullptr; cur = _cld_iterator_atomic.next()) { + class CleanKlasses : public KlassClosure { + public: - return !AtomicAccess::cmpxchg(&_clean_klass_tree_claimed, false, true); -} + void do_klass(Klass* klass) override { + klass->clean_subklass(true); -InstanceKlass* KlassCleaningTask::claim_next_klass() { - Klass* klass; - do { - klass =_klass_iterator.next_klass(); - } while (klass != nullptr && !klass->is_instance_klass()); + Klass* sibling = klass->next_sibling(true); + klass->set_next_sibling(sibling); - // this can be null so don't call InstanceKlass::cast - return static_cast(klass); -} + if (klass->is_instance_klass()) { + Klass::clean_weak_instanceklass_links(InstanceKlass::cast(klass)); + } -void KlassCleaningTask::work() { - // One worker will clean the subklass/sibling klass tree. - if (claim_clean_klass_tree_task()) { - Klass::clean_weak_klass_links(true /* class_unloading_occurred */, false /* clean_alive_klasses */); - } + assert(klass->subklass() == nullptr || klass->subklass()->is_loader_alive(), "must be"); + assert(klass->next_sibling(false) == nullptr || klass->next_sibling(false)->is_loader_alive(), "must be"); + } + } cl; - // All workers will help cleaning the classes, - InstanceKlass* klass; - while ((klass = claim_next_klass()) != nullptr) { - Klass::clean_weak_instanceklass_links(klass); + cur->classes_do(&cl); } } diff --git a/src/hotspot/share/gc/shared/parallelCleaning.hpp b/src/hotspot/share/gc/shared/parallelCleaning.hpp index 4a7c724fef5..b47bf92e2ac 100644 --- a/src/hotspot/share/gc/shared/parallelCleaning.hpp +++ b/src/hotspot/share/gc/shared/parallelCleaning.hpp @@ -54,14 +54,10 @@ class CodeCacheUnloadingTask { // Cleans out the Klass tree from stale data. class KlassCleaningTask : public StackObj { - volatile bool _clean_klass_tree_claimed; - ClassLoaderDataGraphKlassIteratorAtomic _klass_iterator; - - bool claim_clean_klass_tree_task(); - InstanceKlass* claim_next_klass(); + ClassLoaderDataGraphIteratorAtomic _cld_iterator_atomic; public: - KlassCleaningTask(); + KlassCleaningTask() : _cld_iterator_atomic() { } void work(); }; diff --git a/src/hotspot/share/gc/shared/workerUtils.hpp b/src/hotspot/share/gc/shared/workerUtils.hpp index 223dfb34eb2..5f167ffb6b2 100644 --- a/src/hotspot/share/gc/shared/workerUtils.hpp +++ b/src/hotspot/share/gc/shared/workerUtils.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 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,11 +27,12 @@ #include "memory/allocation.hpp" #include "metaprogramming/enableIf.hpp" -#include "metaprogramming/logical.hpp" #include "runtime/mutex.hpp" #include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" +#include + // A class that acts as a synchronisation barrier. Workers enter // the barrier and must wait until all other workers have entered // before any of them may leave. @@ -103,7 +104,7 @@ class SubTasksDone: public CHeapObj { // explicitly passed as extra arguments. Every thread in the parallel task // must execute this. template...>::value)> + ENABLE_IF(std::conjunction_v...>)> void all_tasks_claimed(T0 first_skipped, Ts... more_skipped) { static_assert(std::is_convertible::value, "not convertible"); uint skipped[] = { static_cast(first_skipped), static_cast(more_skipped)... }; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.cpp b/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.cpp index c3b99af8a80..86ff6f22c72 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.cpp @@ -43,7 +43,7 @@ ShenandoahAgeCensus::ShenandoahAgeCensus(uint max_workers) ShenandoahGenerationalMinTenuringAge, ShenandoahGenerationalMaxTenuringAge)); } - _global_age_table = NEW_C_HEAP_ARRAY(AgeTable*, MAX_SNAPSHOTS, mtGC); + _global_age_tables = NEW_C_HEAP_ARRAY(AgeTable*, MAX_SNAPSHOTS, mtGC); CENSUS_NOISE(_global_noise = NEW_C_HEAP_ARRAY(ShenandoahNoiseStats, MAX_SNAPSHOTS, mtGC);) _tenuring_threshold = NEW_C_HEAP_ARRAY(uint, MAX_SNAPSHOTS, mtGC); CENSUS_NOISE(_skipped = 0); @@ -52,36 +52,40 @@ ShenandoahAgeCensus::ShenandoahAgeCensus(uint max_workers) for (int i = 0; i < MAX_SNAPSHOTS; i++) { // Note that we don't now get perfdata from age_table - _global_age_table[i] = new AgeTable(false); + _global_age_tables[i] = new AgeTable(false); CENSUS_NOISE(_global_noise[i].clear();) // Sentinel value _tenuring_threshold[i] = MAX_COHORTS; } if (ShenandoahGenerationalAdaptiveTenuring) { - _local_age_table = NEW_C_HEAP_ARRAY(AgeTable*, _max_workers, mtGC); + _local_age_tables = NEW_C_HEAP_ARRAY(AgeTable*, _max_workers, mtGC); CENSUS_NOISE(_local_noise = NEW_C_HEAP_ARRAY(ShenandoahNoiseStats, max_workers, mtGC);) for (uint i = 0; i < _max_workers; i++) { - _local_age_table[i] = new AgeTable(false); + _local_age_tables[i] = new AgeTable(false); CENSUS_NOISE(_local_noise[i].clear();) } } else { - _local_age_table = nullptr; + _local_age_tables = nullptr; + } + _epoch = MAX_SNAPSHOTS - 1; // see prepare_for_census_update() + + if (!ShenandoahGenerationalAdaptiveTenuring) { + _tenuring_threshold[_epoch] = InitialTenuringThreshold; } - _epoch = MAX_SNAPSHOTS - 1; // see update_epoch() } ShenandoahAgeCensus::~ShenandoahAgeCensus() { for (uint i = 0; i < MAX_SNAPSHOTS; i++) { - delete _global_age_table[i]; + delete _global_age_tables[i]; } - FREE_C_HEAP_ARRAY(AgeTable*, _global_age_table); + FREE_C_HEAP_ARRAY(AgeTable*, _global_age_tables); FREE_C_HEAP_ARRAY(uint, _tenuring_threshold); CENSUS_NOISE(FREE_C_HEAP_ARRAY(ShenandoahNoiseStats, _global_noise)); - if (_local_age_table) { + if (_local_age_tables) { for (uint i = 0; i < _max_workers; i++) { - delete _local_age_table[i]; + delete _local_age_tables[i]; } - FREE_C_HEAP_ARRAY(AgeTable*, _local_age_table); + FREE_C_HEAP_ARRAY(AgeTable*, _local_age_tables); CENSUS_NOISE(FREE_C_HEAP_ARRAY(ShenandoahNoiseStats, _local_noise)); } } @@ -142,37 +146,31 @@ void ShenandoahAgeCensus::prepare_for_census_update() { if (++_epoch >= MAX_SNAPSHOTS) { _epoch=0; } - _global_age_table[_epoch]->clear(); + _global_age_tables[_epoch]->clear(); CENSUS_NOISE(_global_noise[_epoch].clear();) } // Update the census data from appropriate sources, // and compute the new tenuring threshold. -void ShenandoahAgeCensus::update_census(size_t age0_pop, AgeTable* pv1, AgeTable* pv2) { +void ShenandoahAgeCensus::update_census(size_t age0_pop) { prepare_for_census_update(); - assert(_global_age_table[_epoch]->is_clear(), "Dirty decks"); + assert(ShenandoahGenerationalAdaptiveTenuring, "Only update census when adaptive tenuring is enabled"); + assert(_global_age_tables[_epoch]->is_clear(), "Dirty decks"); CENSUS_NOISE(assert(_global_noise[_epoch].is_clear(), "Dirty decks");) - if (ShenandoahGenerationalAdaptiveTenuring) { - assert(pv1 == nullptr && pv2 == nullptr, "Error, check caller"); - // Seed cohort 0 with population that may have been missed during - // regular census. - _global_age_table[_epoch]->add(0u, age0_pop); - // Merge data from local age tables into the global age table for the epoch, - // clearing the local tables. - for (uint i = 0; i < _max_workers; i++) { - // age stats - _global_age_table[_epoch]->merge(_local_age_table[i]); - _local_age_table[i]->clear(); // clear for next census - // Merge noise stats - CENSUS_NOISE(_global_noise[_epoch].merge(_local_noise[i]);) - CENSUS_NOISE(_local_noise[i].clear();) - } - } else { - // census during evac - assert(pv1 != nullptr && pv2 != nullptr, "Error, check caller"); - _global_age_table[_epoch]->merge(pv1); - _global_age_table[_epoch]->merge(pv2); + // Seed cohort 0 with population that may have been missed during + // regular census. + _global_age_tables[_epoch]->add(0u, age0_pop); + + // Merge data from local age tables into the global age table for the epoch, + // clearing the local tables. + for (uint i = 0; i < _max_workers; i++) { + // age stats + _global_age_tables[_epoch]->merge(_local_age_tables[i]); + _local_age_tables[i]->clear(); // clear for next census + // Merge noise stats + CENSUS_NOISE(_global_noise[_epoch].merge(_local_noise[i]);) + CENSUS_NOISE(_local_noise[i].clear();) } update_tenuring_threshold(); @@ -188,7 +186,7 @@ void ShenandoahAgeCensus::update_census(size_t age0_pop, AgeTable* pv1, AgeTable void ShenandoahAgeCensus::reset_global() { assert(_epoch < MAX_SNAPSHOTS, "Out of bounds"); for (uint i = 0; i < MAX_SNAPSHOTS; i++) { - _global_age_table[i]->clear(); + _global_age_tables[i]->clear(); CENSUS_NOISE(_global_noise[i].clear();) } _epoch = MAX_SNAPSHOTS; @@ -198,11 +196,11 @@ void ShenandoahAgeCensus::reset_global() { // Reset the local age tables, clearing any partial census. void ShenandoahAgeCensus::reset_local() { if (!ShenandoahGenerationalAdaptiveTenuring) { - assert(_local_age_table == nullptr, "Error"); + assert(_local_age_tables == nullptr, "Error"); return; } for (uint i = 0; i < _max_workers; i++) { - _local_age_table[i]->clear(); + _local_age_tables[i]->clear(); CENSUS_NOISE(_local_noise[i].clear();) } } @@ -212,7 +210,7 @@ void ShenandoahAgeCensus::reset_local() { bool ShenandoahAgeCensus::is_clear_global() { assert(_epoch < MAX_SNAPSHOTS, "Out of bounds"); for (uint i = 0; i < MAX_SNAPSHOTS; i++) { - bool clear = _global_age_table[i]->is_clear(); + bool clear = _global_age_tables[i]->is_clear(); CENSUS_NOISE(clear |= _global_noise[i].is_clear();) if (!clear) { return false; @@ -224,11 +222,11 @@ bool ShenandoahAgeCensus::is_clear_global() { // Is local census information clear? bool ShenandoahAgeCensus::is_clear_local() { if (!ShenandoahGenerationalAdaptiveTenuring) { - assert(_local_age_table == nullptr, "Error"); + assert(_local_age_tables == nullptr, "Error"); return true; } for (uint i = 0; i < _max_workers; i++) { - bool clear = _local_age_table[i]->is_clear(); + bool clear = _local_age_tables[i]->is_clear(); CENSUS_NOISE(clear |= _local_noise[i].is_clear();) if (!clear) { return false; @@ -240,7 +238,7 @@ bool ShenandoahAgeCensus::is_clear_local() { size_t ShenandoahAgeCensus::get_all_ages(uint snap) { assert(snap < MAX_SNAPSHOTS, "Out of bounds"); size_t pop = 0; - const AgeTable* pv = _global_age_table[snap]; + const AgeTable* pv = _global_age_tables[snap]; for (uint i = 0; i < MAX_COHORTS; i++) { pop += pv->sizes[i]; } @@ -260,13 +258,11 @@ void ShenandoahAgeCensus::update_total() { #endif // !PRODUCT void ShenandoahAgeCensus::update_tenuring_threshold() { - if (!ShenandoahGenerationalAdaptiveTenuring) { - _tenuring_threshold[_epoch] = InitialTenuringThreshold; - } else { - uint tt = compute_tenuring_threshold(); - assert(tt <= MAX_COHORTS, "Out of bounds"); - _tenuring_threshold[_epoch] = tt; - } + assert(ShenandoahGenerationalAdaptiveTenuring, "Only update when adaptive tenuring is enabled"); + uint tt = compute_tenuring_threshold(); + assert(tt <= MAX_COHORTS, "Out of bounds"); + _tenuring_threshold[_epoch] = tt; + print(); log_info(gc, age)("New tenuring threshold %zu (min %zu, max %zu)", (uintx) _tenuring_threshold[_epoch], ShenandoahGenerationalMinTenuringAge, ShenandoahGenerationalMaxTenuringAge); @@ -296,8 +292,8 @@ uint ShenandoahAgeCensus::compute_tenuring_threshold() { const uint prev_epoch = cur_epoch > 0 ? cur_epoch - 1 : markWord::max_age; // Current and previous population vectors in ring - const AgeTable* cur_pv = _global_age_table[cur_epoch]; - const AgeTable* prev_pv = _global_age_table[prev_epoch]; + const AgeTable* cur_pv = _global_age_tables[cur_epoch]; + const AgeTable* prev_pv = _global_age_tables[prev_epoch]; uint upper_bound = ShenandoahGenerationalMaxTenuringAge; const uint prev_tt = previous_tenuring_threshold(); if (ShenandoahGenerationalCensusIgnoreOlderCohorts && prev_tt > 0) { @@ -372,8 +368,8 @@ void ShenandoahAgeCensus::print() { const uint cur_epoch = _epoch; const uint prev_epoch = cur_epoch > 0 ? cur_epoch - 1: markWord::max_age; - const AgeTable* cur_pv = _global_age_table[cur_epoch]; - const AgeTable* prev_pv = _global_age_table[prev_epoch]; + const AgeTable* cur_pv = _global_age_tables[cur_epoch]; + const AgeTable* prev_pv = _global_age_tables[prev_epoch]; const uint tt = tenuring_threshold(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.hpp b/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.hpp index d862498c69d..39ea4ee9002 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.hpp @@ -97,8 +97,8 @@ struct ShenandoahNoiseStats { // once the per-worker data is consolidated into the appropriate population vector // per minor collection. The _local_age_table is thus C x N, for N GC workers. class ShenandoahAgeCensus: public CHeapObj { - AgeTable** _global_age_table; // Global age table used for adapting tenuring threshold, one per snapshot - AgeTable** _local_age_table; // Local scratch age tables to track object ages, one per worker + AgeTable** _global_age_tables; // Global age tables used for adapting tenuring threshold, one per snapshot + AgeTable** _local_age_tables; // Local scratch age tables to track object ages, one per worker #ifdef SHENANDOAH_CENSUS_NOISE ShenandoahNoiseStats* _global_noise; // Noise stats, one per snapshot @@ -175,7 +175,7 @@ class ShenandoahAgeCensus: public CHeapObj { // Return the local age table (population vector) for worker_id. // Only used in the case of ShenandoahGenerationalAdaptiveTenuring AgeTable* get_local_age_table(uint worker_id) const { - return _local_age_table[worker_id]; + return _local_age_tables[worker_id]; } // Return the most recently computed tenuring threshold. @@ -209,11 +209,7 @@ class ShenandoahAgeCensus: public CHeapObj { // age0_pop is the population of Cohort 0 that may have been missed in // the regular census during the marking cycle, corresponding to objects // allocated when the concurrent marking was in progress. - // Optional parameters, pv1 and pv2 are population vectors that together - // provide object census data (only) for the case when - // ShenandoahGenerationalCensusAtEvac. In this case, the age0_pop - // is 0, because the evacuated objects have all had their ages incremented. - void update_census(size_t age0_pop, AgeTable* pv1 = nullptr, AgeTable* pv2 = nullptr); + void update_census(size_t age0_pop); // Reset the epoch, clearing accumulated census history // Note: this isn't currently used, but reserved for planned diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp index facba2236be..005d6c42f8c 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp @@ -25,7 +25,6 @@ #include "gc/shared/satbMarkQueue.hpp" -#include "gc/shared/strongRootsScope.hpp" #include "gc/shared/taskTerminator.hpp" #include "gc/shenandoah/shenandoahBarrierSet.inline.hpp" #include "gc/shenandoah/shenandoahClosures.inline.hpp" @@ -94,10 +93,12 @@ class ShenandoahFinalMarkingTask : public WorkerTask { ShenandoahConcurrentMark* _cm; TaskTerminator* _terminator; bool _dedup_string; + ThreadsClaimTokenScope _threads_claim_token_scope; // needed for Threads::possibly_parallel_threads_do public: ShenandoahFinalMarkingTask(ShenandoahConcurrentMark* cm, TaskTerminator* terminator, bool dedup_string) : - WorkerTask("Shenandoah Final Mark"), _cm(cm), _terminator(terminator), _dedup_string(dedup_string) { + WorkerTask("Shenandoah Final Mark"), _cm(cm), _terminator(terminator), _dedup_string(dedup_string), + _threads_claim_token_scope() { } void work(uint worker_id) { @@ -297,7 +298,6 @@ void ShenandoahConcurrentMark::finish_mark_work() { uint nworkers = heap->workers()->active_workers(); task_queues()->reserve(nworkers); - StrongRootsScope scope(nworkers); TaskTerminator terminator(nworkers, task_queues()); switch (_generation->type()) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp index f4005e45f39..b960255891f 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp @@ -201,26 +201,8 @@ void ShenandoahControlThread::run_service() { heuristics->clear_metaspace_oom(); } - // Commit worker statistics to cycle data - heap->phase_timings()->flush_par_workers_to_cycle(); - - // Print GC stats for current cycle - { - LogTarget(Info, gc, stats) lt; - if (lt.is_enabled()) { - ResourceMark rm; - LogStream ls(lt); - heap->phase_timings()->print_cycle_on(&ls); - if (ShenandoahEvacTracking) { - ShenandoahEvacuationTracker* evac_tracker = heap->evac_tracker(); - ShenandoahCycleStats evac_stats = evac_tracker->flush_cycle_to_global(); - evac_tracker->print_evacuations_on(&ls, &evac_stats.workers, &evac_stats.mutators); - } - } - } - - // Commit statistics to globals - heap->phase_timings()->flush_cycle_to_global(); + // Manage and print gc stats + heap->process_gc_stats(); // Print Metaspace change following GC (if logging is enabled). MetaspaceUtils::print_metaspace_change(meta_sizes); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahEvacTracker.cpp b/src/hotspot/share/gc/shenandoah/shenandoahEvacTracker.cpp index bc8fad713af..72d0773eccd 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahEvacTracker.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahEvacTracker.cpp @@ -23,7 +23,6 @@ * */ -#include "gc/shenandoah/shenandoahAgeCensus.hpp" #include "gc/shenandoah/shenandoahEvacTracker.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" #include "gc/shenandoah/shenandoahThreadLocalData.hpp" @@ -44,19 +43,6 @@ ShenandoahEvacuationStats::ShenandoahEvacuations* ShenandoahEvacuationStats::get return &_old; } -ShenandoahEvacuationStats::ShenandoahEvacuationStats() - : _use_age_table(!ShenandoahGenerationalAdaptiveTenuring), - _age_table(nullptr) { - if (_use_age_table) { - _age_table = new AgeTable(false); - } -} - -AgeTable* ShenandoahEvacuationStats::age_table() const { - assert(_use_age_table, "Don't call"); - return _age_table; -} - void ShenandoahEvacuationStats::begin_evacuation(size_t bytes, ShenandoahAffiliation from, ShenandoahAffiliation to) { ShenandoahEvacuations* category = get_category(from, to); category->_evacuations_attempted++; @@ -70,31 +56,16 @@ void ShenandoahEvacuationStats::end_evacuation(size_t bytes, ShenandoahAffiliati category->_bytes_completed += bytes; } -void ShenandoahEvacuationStats::record_age(size_t bytes, uint age) { - assert(_use_age_table, "Don't call!"); - if (age <= markWord::max_age) { // Filter age sentinel. - _age_table->add(age, bytes >> LogBytesPerWord); - } -} - void ShenandoahEvacuationStats::accumulate(const ShenandoahEvacuationStats* other) { _young.accumulate(other->_young); _old.accumulate(other->_old); _promotion.accumulate(other->_promotion); - - if (_use_age_table) { - _age_table->merge(other->age_table()); - } } void ShenandoahEvacuationStats::reset() { _young.reset(); _old.reset(); _promotion.reset(); - - if (_use_age_table) { - _age_table->clear(); - } } void ShenandoahEvacuationStats::ShenandoahEvacuations::print_on(outputStream* st) const { @@ -112,10 +83,6 @@ void ShenandoahEvacuationStats::print_on(outputStream* st) const { st->print("Promotion: "); _promotion.print_on(st); st->print("Old: "); _old.print_on(st); } - - if (_use_age_table) { - _age_table->print_on(st); - } } void ShenandoahEvacuationTracker::print_global_on(outputStream* st) { @@ -125,28 +92,13 @@ void ShenandoahEvacuationTracker::print_global_on(outputStream* st) { void ShenandoahEvacuationTracker::print_evacuations_on(outputStream* st, ShenandoahEvacuationStats* workers, ShenandoahEvacuationStats* mutators) { - if (ShenandoahEvacTracking) { - st->print_cr("Workers: "); - workers->print_on(st); - st->cr(); - st->print_cr("Mutators: "); - mutators->print_on(st); - st->cr(); - } - - ShenandoahHeap* heap = ShenandoahHeap::heap(); - if (heap->mode()->is_generational()) { - AgeTable young_region_ages(false); - for (uint i = 0; i < heap->num_regions(); ++i) { - ShenandoahHeapRegion* r = heap->get_region(i); - if (r->is_young()) { - young_region_ages.add(r->age(), r->get_live_data_words()); - } - } - st->print("Young regions: "); - young_region_ages.print_on(st); - st->cr(); - } + assert(ShenandoahEvacTracking, "Only when evac tracking is enabled"); + st->print_cr("Workers: "); + workers->print_on(st); + st->cr(); + st->print_cr("Mutators: "); + mutators->print_on(st); + st->cr(); } class ShenandoahStatAggregator : public ThreadClosure { @@ -173,15 +125,6 @@ ShenandoahCycleStats ShenandoahEvacuationTracker::flush_cycle_to_global() { _mutators_global.accumulate(&mutators); _workers_global.accumulate(&workers); - if (!ShenandoahGenerationalAdaptiveTenuring) { - // Ingest mutator & worker collected population vectors into the heap's - // global census data, and use it to compute an appropriate tenuring threshold - // for use in the next cycle. - // The first argument is used for any age 0 cohort population that we may otherwise have - // missed during the census. This is non-zero only when census happens at marking. - ShenandoahGenerationalHeap::heap()->age_census()->update_census(0, mutators.age_table(), workers.age_table()); - } - return {workers, mutators}; } @@ -192,7 +135,3 @@ void ShenandoahEvacuationTracker::begin_evacuation(Thread* thread, size_t bytes, void ShenandoahEvacuationTracker::end_evacuation(Thread* thread, size_t bytes, ShenandoahAffiliation from, ShenandoahAffiliation to) { ShenandoahThreadLocalData::end_evacuation(thread, bytes, from, to); } - -void ShenandoahEvacuationTracker::record_age(Thread* thread, size_t bytes, uint age) { - ShenandoahThreadLocalData::record_age(thread, bytes, age); -} diff --git a/src/hotspot/share/gc/shenandoah/shenandoahEvacTracker.hpp b/src/hotspot/share/gc/shenandoah/shenandoahEvacTracker.hpp index e5d7a7fec94..6e1182680a5 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahEvacTracker.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahEvacTracker.hpp @@ -66,20 +66,12 @@ class ShenandoahEvacuationStats : public CHeapObj { ShenandoahEvacuations _old; ShenandoahEvacuations _promotion; - bool _use_age_table; - AgeTable* _age_table; - public: - ShenandoahEvacuationStats(); - - AgeTable* age_table() const; - // Record that the current thread is attempting to copy this many bytes. void begin_evacuation(size_t bytes, ShenandoahAffiliation from, ShenandoahAffiliation to); // Record that the current thread has completed copying this many bytes. void end_evacuation(size_t bytes, ShenandoahAffiliation from, ShenandoahAffiliation to); - void record_age(size_t bytes, uint age); void print_on(outputStream* st) const; void accumulate(const ShenandoahEvacuationStats* other); @@ -106,7 +98,6 @@ class ShenandoahEvacuationTracker : public CHeapObj { // Multiple threads may attempt to evacuate the same object, but only the successful thread will end the evacuation. // Evacuations that were begun, but not ended are considered 'abandoned'. void end_evacuation(Thread* thread, size_t bytes, ShenandoahAffiliation from, ShenandoahAffiliation to); - void record_age(Thread* thread, size_t bytes, uint age); void print_global_on(outputStream* st); void print_evacuations_on(outputStream* st, diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp index 761ba02d569..c6d1cf02ee2 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.cpp @@ -201,6 +201,24 @@ ShenandoahGenerationalControlThread::GCMode ShenandoahGenerationalControlThread: return request.generation->is_old() ? servicing_old : concurrent_normal; } +void ShenandoahGenerationalControlThread::maybe_print_young_region_ages() const { + LogTarget(Debug, gc, age) lt; + if (lt.is_enabled()) { + LogStream ls(lt); + AgeTable young_region_ages(false); + for (uint i = 0; i < _heap->num_regions(); ++i) { + const ShenandoahHeapRegion* r = _heap->get_region(i); + if (r->is_young()) { + young_region_ages.add(r->age(), r->get_live_data_words()); + } + } + + ls.print("Young regions: "); + young_region_ages.print_on(&ls); + ls.cr(); + } +} + void ShenandoahGenerationalControlThread::maybe_set_aging_cycle() { if (_age_period-- == 0) { _heap->set_aging_cycle(true); @@ -298,7 +316,11 @@ void ShenandoahGenerationalControlThread::run_gc_cycle(const ShenandoahGCRequest _heap->global_generation()->heuristics()->clear_metaspace_oom(); } - process_phase_timings(); + // Manage and print gc stats + _heap->process_gc_stats(); + + // Print table for young region ages if log is enabled + maybe_print_young_region_ages(); // Print Metaspace change following GC (if logging is enabled). MetaspaceUtils::print_metaspace_change(meta_sizes); @@ -317,29 +339,6 @@ void ShenandoahGenerationalControlThread::run_gc_cycle(const ShenandoahGCRequest gc_mode_name(gc_mode()), GCCause::to_string(request.cause), request.generation->name(), GCCause::to_string(_heap->cancelled_cause())); } -void ShenandoahGenerationalControlThread::process_phase_timings() const { - // Commit worker statistics to cycle data - _heap->phase_timings()->flush_par_workers_to_cycle(); - - ShenandoahEvacuationTracker* evac_tracker = _heap->evac_tracker(); - ShenandoahCycleStats evac_stats = evac_tracker->flush_cycle_to_global(); - - // Print GC stats for current cycle - { - LogTarget(Info, gc, stats) lt; - if (lt.is_enabled()) { - ResourceMark rm; - LogStream ls(lt); - _heap->phase_timings()->print_cycle_on(&ls); - evac_tracker->print_evacuations_on(&ls, &evac_stats.workers, - &evac_stats.mutators); - } - } - - // Commit statistics to globals - _heap->phase_timings()->flush_cycle_to_global(); -} - // Young and old concurrent cycles are initiated by the regulator. Implicit // and explicit GC requests are handled by the controller thread and always // run a global cycle (which is concurrent by default, but may be overridden @@ -417,7 +416,7 @@ void ShenandoahGenerationalControlThread::service_concurrent_old_cycle(const She set_gc_mode(bootstrapping_old); young_generation->set_old_gen_task_queues(old_generation->task_queues()); service_concurrent_cycle(young_generation, request.cause, true); - process_phase_timings(); + _heap->process_gc_stats(); if (_heap->cancelled_gc()) { // Young generation bootstrap cycle has failed. Concurrent mark for old generation // is going to resume after degenerated bootstrap cycle completes. diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.hpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.hpp index 1586205742a..6a4f5bde578 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalControlThread.hpp @@ -129,9 +129,6 @@ class ShenandoahGenerationalControlThread: public ShenandoahController { // Returns true if the old generation marking was interrupted to allow a young cycle. bool preempt_old_marking(ShenandoahGeneration* generation); - // Flushes cycle timings to global timings and prints the phase timings for the last completed cycle. - void process_phase_timings() const; - // Set the gc mode and post a notification if it has changed. The overloaded variant should be used // when the _control_lock is already held. void set_gc_mode(GCMode new_mode); @@ -160,6 +157,9 @@ class ShenandoahGenerationalControlThread: public ShenandoahController { GCMode prepare_for_allocation_failure_gc(ShenandoahGCRequest &request); GCMode prepare_for_explicit_gc(ShenandoahGCRequest &request) const; GCMode prepare_for_concurrent_gc(const ShenandoahGCRequest &request) const; + + // Print table for young region ages if log is enabled + void maybe_print_young_region_ages() const; }; #endif // SHARE_GC_SHENANDOAH_SHENANDOAHGENERATIONALCONTROLTHREAD_HPP diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp index 8a21ae376e1..34f217ada25 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp @@ -360,11 +360,6 @@ oop ShenandoahGenerationalHeap::try_evacuate_object(oop p, Thread* thread, Shena // When copying to the old generation above, we don't care // about recording object age in the census stats. assert(target_gen == YOUNG_GENERATION, "Error"); - // We record this census only when simulating pre-adaptive tenuring behavior, or - // when we have been asked to record the census at evacuation rather than at mark - if (!ShenandoahGenerationalAdaptiveTenuring) { - evac_tracker()->record_age(thread, size * HeapWordSize, ShenandoahHeap::get_object_age(copy_val)); - } } shenandoah_assert_correct(nullptr, copy_val); return copy_val; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index 10d7e8edcad..e6d41237c98 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -1441,6 +1441,27 @@ void ShenandoahHeap::print_heap_regions_on(outputStream* st) const { } } +void ShenandoahHeap::process_gc_stats() const { + // Commit worker statistics to cycle data + phase_timings()->flush_par_workers_to_cycle(); + + // Print GC stats for current cycle + LogTarget(Info, gc, stats) lt; + if (lt.is_enabled()) { + ResourceMark rm; + LogStream ls(lt); + phase_timings()->print_cycle_on(&ls); + if (ShenandoahEvacTracking) { + ShenandoahCycleStats evac_stats = evac_tracker()->flush_cycle_to_global(); + evac_tracker()->print_evacuations_on(&ls, &evac_stats.workers, + &evac_stats.mutators); + } + } + + // Commit statistics to globals + phase_timings()->flush_cycle_to_global(); +} + size_t ShenandoahHeap::trash_humongous_region_at(ShenandoahHeapRegion* start) const { assert(start->is_humongous_start(), "reclaim regions starting with the first one"); assert(!start->has_live(), "liveness must be zero"); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp index 322ac26e254..11a20d4a2f9 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp @@ -206,9 +206,12 @@ class ShenandoahHeap : public CollectedHeap { void initialize_serviceability() override; void print_heap_on(outputStream* st) const override; - void print_gc_on(outputStream *st) const override; + void print_gc_on(outputStream* st) const override; void print_heap_regions_on(outputStream* st) const; + // Flushes cycle timings to global timings and prints the phase timings for the last completed cycle. + void process_gc_stats() const; + void prepare_for_verify() override; void verify(VerifyOption vo) override; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMarkBitMap.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahMarkBitMap.inline.hpp index 637948e2615..3bea8d73959 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMarkBitMap.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMarkBitMap.inline.hpp @@ -135,14 +135,12 @@ inline ShenandoahMarkBitMap::idx_t ShenandoahMarkBitMap::get_next_bit_impl(idx_t // Get the word containing l_index, and shift out low bits. idx_t index = to_words_align_down(l_index); bm_word_t cword = (map(index) ^ flip) >> bit_in_word(l_index); - if ((cword & 1) != 0) { - // The first bit is similarly often interesting. When it matters - // (density or features of the calling algorithm make it likely - // the first bit is set), going straight to the next clause compares - // poorly with doing this check first; count_trailing_zeros can be - // relatively expensive, plus there is the additional range check. - // But when the first bit isn't set, the cost of having tested for - // it is relatively small compared to the rest of the search. + if ((cword & 0x03) != 0) { + // The first bits (representing weak mark or strong mark) are similarly often interesting. When it matters + // (density or features of the calling algorithm make it likely the first bits are set), going straight to + // the next clause compares poorly with doing this check first; count_trailing_zeros can be relatively expensive, + // plus there is the additional range check. But when the first bits are not set, the cost of having tested for + // them is relatively small compared to the rest of the search. return l_index; } else if (cword != 0) { // Flipped and shifted first word is non-zero. diff --git a/src/hotspot/share/gc/shenandoah/shenandoahThreadLocalData.hpp b/src/hotspot/share/gc/shenandoah/shenandoahThreadLocalData.hpp index 37d935d1f78..f54a65b0785 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahThreadLocalData.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahThreadLocalData.hpp @@ -166,10 +166,6 @@ class ShenandoahThreadLocalData { data(thread)->_evacuation_stats->end_evacuation(bytes, from, to); } - static void record_age(Thread* thread, size_t bytes, uint age) { - data(thread)->_evacuation_stats->record_age(bytes, age); - } - static ShenandoahEvacuationStats* evacuation_stats(Thread* thread) { return data(thread)->_evacuation_stats; } diff --git a/src/hotspot/share/gc/z/zLargePages.cpp b/src/hotspot/share/gc/z/zLargePages.cpp index 639c9b0a04f..c259448563b 100644 --- a/src/hotspot/share/gc/z/zLargePages.cpp +++ b/src/hotspot/share/gc/z/zLargePages.cpp @@ -31,7 +31,7 @@ bool ZLargePages::_os_enforced_transparent_mode; void ZLargePages::initialize() { pd_initialize(); - const size_t memory = os::physical_memory(); + const size_t memory = static_cast(os::physical_memory()); log_info_p(gc, init)("Memory: " PROPERFMT, PROPERFMTARGS(memory)); log_info_p(gc, init)("Large Page Support: %s", to_string()); } diff --git a/src/hotspot/share/jfr/jni/jfrJniMethod.cpp b/src/hotspot/share/jfr/jni/jfrJniMethod.cpp index 57bea5c268b..cc5bbe1fc60 100644 --- a/src/hotspot/share/jfr/jni/jfrJniMethod.cpp +++ b/src/hotspot/share/jfr/jni/jfrJniMethod.cpp @@ -423,7 +423,7 @@ JVM_ENTRY_NO_ENV(jlong, jfr_host_total_swap_memory(JNIEnv* env, jclass jvm)) // We want the host swap memory, not the container value. return os::Linux::host_swap(); #else - size_t total_swap_space = 0; + physical_memory_size_type total_swap_space = 0; // Return value ignored - defaulting to 0 on failure. (void)os::total_swap_space(total_swap_space); return static_cast(total_swap_space); diff --git a/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp index a8a9e191ed8..b30ebd8108c 100644 --- a/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp +++ b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp @@ -528,23 +528,23 @@ TRACE_REQUEST_FUNC(ThreadAllocationStatistics) { * the total memory reported is the amount of memory configured for the guest OS by the hypervisor. */ TRACE_REQUEST_FUNC(PhysicalMemory) { - u8 totalPhysicalMemory = static_cast(os::physical_memory()); + physical_memory_size_type totalPhysicalMemory = os::physical_memory(); EventPhysicalMemory event; event.set_totalSize(totalPhysicalMemory); - size_t avail_mem = 0; + physical_memory_size_type avail_mem = 0; // Return value ignored - defaulting to 0 on failure. (void)os::available_memory(avail_mem); - event.set_usedSize(totalPhysicalMemory - static_cast(avail_mem)); + event.set_usedSize(totalPhysicalMemory - avail_mem); event.commit(); } TRACE_REQUEST_FUNC(SwapSpace) { EventSwapSpace event; - size_t total_swap_space = 0; + physical_memory_size_type total_swap_space = 0; // Return value ignored - defaulting to 0 on failure. (void)os::total_swap_space(total_swap_space); event.set_totalSize(static_cast(total_swap_space)); - size_t free_swap_space = 0; + physical_memory_size_type free_swap_space = 0; // Return value ignored - defaulting to 0 on failure. (void)os::free_swap_space(free_swap_space); event.set_freeSize(static_cast(free_swap_space)); diff --git a/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.cpp b/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.cpp index 3fca3ad7631..2ce1a93455b 100644 --- a/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.cpp +++ b/src/hotspot/share/jfr/periodic/sampling/jfrCPUTimeThreadSampler.cpp @@ -275,6 +275,7 @@ class JfrCPUSamplerThread : public NonJavaThread { void handle_timer_signal(siginfo_t* info, void* context); bool init_timers(); void stop_timer(); + virtual void print_on(outputStream* st) const; void trigger_async_processing_of_cpu_time_jfr_requests(); @@ -788,6 +789,12 @@ void JfrCPUSamplerThread::stop_timer() { VMThread::execute(&op); } +void JfrCPUSamplerThread::print_on(outputStream* st) const { + st->print("\"%s\" ", name()); + Thread::print_on(st); + st->cr(); +} + void JfrCPUSamplerThread::recompute_period_if_needed() { int64_t current_period = get_sampling_period(); int64_t period = _throttle.compute_sampling_period(); diff --git a/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp b/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp index ae79c8bb6e3..7e7747ba396 100644 --- a/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp +++ b/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp @@ -85,6 +85,7 @@ class JfrSamplerThread : public NonJavaThread { bool is_JfrSampler_thread() const { return true; } int64_t java_period() const { return AtomicAccess::load(&_java_period_millis); }; int64_t native_period() const { return AtomicAccess::load(&_native_period_millis); }; + virtual void print_on(outputStream* st) const; }; JfrSamplerThread::JfrSamplerThread(int64_t java_period_millis, int64_t native_period_millis, u4 max_frames) : @@ -384,6 +385,12 @@ void JfrSamplerThread::set_native_period(int64_t period_millis) { AtomicAccess::store(&_native_period_millis, period_millis); } +void JfrSamplerThread::print_on(outputStream* st) const { + st->print("\"%s\" ", name()); + Thread::print_on(st); + st->cr(); +} + // JfrThreadSampler; static JfrThreadSampler* _instance = nullptr; diff --git a/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp b/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp index b8ff3ba504a..ff688a297ed 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp @@ -676,18 +676,36 @@ void JfrCheckpointManager::write_simplified_vthread_checkpoint(traceid vtid) { JfrTypeManager::write_simplified_vthread_checkpoint(vtid); } -class JfrNotifyClosure : public ThreadClosure { +// Reset thread local state used for object allocation sampling. +static void clear_last_allocated_bytes(JavaThread* jt) { + assert(jt != nullptr, "invariant"); + assert(!JfrRecorder::is_recording(), "invariant"); + JfrThreadLocal* const tl = jt->jfr_thread_local(); + assert(tl != nullptr, "invariant"); + if (tl->last_allocated_bytes() != 0) { + tl->clear_last_allocated_bytes(); + } + assert(tl->last_allocated_bytes() == 0, "invariant"); +} + +class JfrNotifyClosure : public StackObj { + private: + bool _clear; public: - void do_thread(Thread* thread) { - assert(thread != nullptr, "invariant"); + JfrNotifyClosure(bool clear) : _clear(clear) {} + void do_thread(JavaThread* jt) { + assert(jt != nullptr, "invariant"); assert_locked_or_safepoint(Threads_lock); - JfrJavaEventWriter::notify(JavaThread::cast(thread)); + JfrJavaEventWriter::notify(jt); + if (_clear) { + clear_last_allocated_bytes(jt); + } } }; -void JfrCheckpointManager::notify_threads() { +void JfrCheckpointManager::notify_threads(bool clear /* false */) { assert(SafepointSynchronize::is_at_safepoint(), "invariant"); - JfrNotifyClosure tc; + JfrNotifyClosure tc(clear); JfrJavaThreadIterator iter; while (iter.has_next()) { tc.do_thread(iter.next()); diff --git a/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.hpp b/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.hpp index f9f8f1c26cf..f713a77e66d 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.hpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.hpp @@ -88,7 +88,7 @@ class JfrCheckpointManager : public JfrCHeapObj { size_t clear(); size_t write(); - void notify_threads(); + void notify_threads(bool clear = false); size_t write_static_type_set(Thread* thread); size_t write_threads(JavaThread* thread); diff --git a/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp b/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp index 0087980f430..0e68e8a6032 100644 --- a/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp +++ b/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp @@ -122,30 +122,6 @@ const Thread* JfrRotationLock::_owner_thread = nullptr; const int JfrRotationLock::retry_wait_millis = 10; volatile int JfrRotationLock::_lock = 0; -// Reset thread local state used for object allocation sampling. -class ClearObjectAllocationSampling : public ThreadClosure { - public: - void do_thread(Thread* t) { - assert(t != nullptr, "invariant"); - t->jfr_thread_local()->clear_last_allocated_bytes(); - } -}; - -template -static inline void iterate(Iterator& it, ClearObjectAllocationSampling& coas) { - while (it.has_next()) { - coas.do_thread(it.next()); - } -} - -static void clear_object_allocation_sampling() { - ClearObjectAllocationSampling coas; - JfrJavaThreadIterator jit; - iterate(jit, coas); - JfrNonJavaThreadIterator njit; - iterate(njit, coas); -} - template class Content { private: @@ -472,7 +448,6 @@ void JfrRecorderService::clear() { } void JfrRecorderService::pre_safepoint_clear() { - clear_object_allocation_sampling(); _storage.clear(); JfrStackTraceRepository::clear(); } @@ -486,7 +461,7 @@ void JfrRecorderService::invoke_safepoint_clear() { void JfrRecorderService::safepoint_clear() { assert(SafepointSynchronize::is_at_safepoint(), "invariant"); _storage.clear(); - _checkpoint_manager.notify_threads(); + _checkpoint_manager.notify_threads(true); _chunkwriter.set_time_stamp(); JfrDeprecationManager::on_safepoint_clear(); JfrStackTraceRepository::clear(); diff --git a/src/hotspot/share/jfr/support/jfrAllocationTracer.cpp b/src/hotspot/share/jfr/support/jfrAllocationTracer.cpp index a1245d7bafe..5817ad194c2 100644 --- a/src/hotspot/share/jfr/support/jfrAllocationTracer.cpp +++ b/src/hotspot/share/jfr/support/jfrAllocationTracer.cpp @@ -22,6 +22,7 @@ * */ +#include "jfr/jfrEvents.hpp" #include "jfr/leakprofiler/leakProfiler.hpp" #include "jfr/support/jfrAllocationTracer.hpp" #include "jfr/support/jfrObjectAllocationSample.hpp" @@ -31,5 +32,7 @@ JfrAllocationTracer::JfrAllocationTracer(const Klass* klass, HeapWord* obj, size if (LeakProfiler::is_running()) { LeakProfiler::sample(obj, alloc_size, thread); } - JfrObjectAllocationSample::send_event(klass, alloc_size, outside_tlab, thread); + if (EventObjectAllocationSample::is_enabled()) { + JfrObjectAllocationSample::send_event(klass, alloc_size, outside_tlab, thread); + } } diff --git a/src/hotspot/share/jfr/support/jfrObjectAllocationSample.cpp b/src/hotspot/share/jfr/support/jfrObjectAllocationSample.cpp index 6a99271a80e..c337030bddd 100644 --- a/src/hotspot/share/jfr/support/jfrObjectAllocationSample.cpp +++ b/src/hotspot/share/jfr/support/jfrObjectAllocationSample.cpp @@ -26,7 +26,7 @@ #include "gc/shared/tlab_globals.hpp" #include "jfr/jfrEvents.hpp" #include "jfr/support/jfrObjectAllocationSample.hpp" -#include "jfr/support/jfrThreadLocal.hpp" +#include "runtime/javaThread.hpp" #include "utilities/globalDefinitions.hpp" inline bool send_allocation_sample(const Klass* klass, int64_t allocated_bytes, JfrThreadLocal* tl) { @@ -43,35 +43,42 @@ inline bool send_allocation_sample(const Klass* klass, int64_t allocated_bytes, return false; } -inline int64_t estimate_tlab_size_bytes(Thread* thread) { - const size_t desired_tlab_size_bytes = thread->tlab().desired_size() * HeapWordSize; - const size_t alignment_reserve_bytes = thread->tlab().alignment_reserve_in_bytes(); +inline int64_t estimate_tlab_size_bytes(JavaThread* jt) { + const size_t desired_tlab_size_bytes = jt->tlab().desired_size() * HeapWordSize; + const size_t alignment_reserve_bytes = jt->tlab().alignment_reserve_in_bytes(); assert(desired_tlab_size_bytes >= alignment_reserve_bytes, "invariant"); return static_cast(desired_tlab_size_bytes - alignment_reserve_bytes); } -inline int64_t load_allocated_bytes(JfrThreadLocal* tl, Thread* thread) { - const int64_t allocated_bytes = thread->allocated_bytes(); - return allocated_bytes == tl->last_allocated_bytes() ? 0 : allocated_bytes; +inline int64_t load_allocated_bytes(JfrThreadLocal* tl, JavaThread* jt) { + const int64_t allocated_bytes = jt->allocated_bytes(); + const int64_t last_allocated_bytes = tl->last_allocated_bytes(); + assert(allocated_bytes >= last_allocated_bytes, "invariant"); + if (last_allocated_bytes == 0) { + // Initialization. + tl->set_last_allocated_bytes(allocated_bytes); + return 0; + } + return allocated_bytes == last_allocated_bytes ? 0 : allocated_bytes; } // To avoid large objects from being undersampled compared to the regular TLAB samples, // the data amount is normalized as if it was a TLAB, giving a number of TLAB sampling attempts to the large object. -static void normalize_as_tlab_and_send_allocation_samples(const Klass* klass, int64_t obj_alloc_size_bytes, JfrThreadLocal* tl, Thread* thread) { - const int64_t allocated_bytes = load_allocated_bytes(tl, thread); +static void normalize_as_tlab_and_send_allocation_samples(const Klass* klass, + int64_t obj_alloc_size_bytes, + int64_t allocated_bytes, + JfrThreadLocal* tl, + JavaThread* jt) { assert(allocated_bytes > 0, "invariant"); // obj_alloc_size_bytes is already attributed to allocated_bytes at this point. if (!UseTLAB) { send_allocation_sample(klass, allocated_bytes, tl); return; } - const int64_t tlab_size_bytes = estimate_tlab_size_bytes(thread); - if (tlab_size_bytes <= 0) { + const int64_t tlab_size_bytes = estimate_tlab_size_bytes(jt); + if (tlab_size_bytes <= 0 || allocated_bytes - tl->last_allocated_bytes() < tlab_size_bytes) { // We don't get a TLAB, avoid endless loop below. return; } - if (allocated_bytes - tl->last_allocated_bytes() < tlab_size_bytes) { - return; - } assert(obj_alloc_size_bytes > 0, "invariant"); do { if (send_allocation_sample(klass, allocated_bytes, tl)) { @@ -81,17 +88,17 @@ static void normalize_as_tlab_and_send_allocation_samples(const Klass* klass, in } while (obj_alloc_size_bytes > 0); } -void JfrObjectAllocationSample::send_event(const Klass* klass, size_t alloc_size, bool outside_tlab, Thread* thread) { - assert(thread != nullptr, "invariant"); - JfrThreadLocal* const tl = thread->jfr_thread_local(); +void JfrObjectAllocationSample::send_event(const Klass* klass, size_t alloc_size, bool outside_tlab, JavaThread* jt) { + assert(klass != nullptr, "invariant"); + assert(jt != nullptr, "invariant"); + JfrThreadLocal* const tl = jt->jfr_thread_local(); assert(tl != nullptr, "invariant"); - if (outside_tlab) { - normalize_as_tlab_and_send_allocation_samples(klass, static_cast(alloc_size), tl, thread); - return; - } - const int64_t allocated_bytes = load_allocated_bytes(tl, thread); - if (allocated_bytes == 0) { - return; + const int64_t allocated_bytes = load_allocated_bytes(tl, jt); + if (allocated_bytes > 0) { + if (outside_tlab) { + normalize_as_tlab_and_send_allocation_samples(klass, static_cast(alloc_size), allocated_bytes, tl, jt); + return; + } + send_allocation_sample(klass, allocated_bytes, tl); } - send_allocation_sample(klass, allocated_bytes, tl); } diff --git a/src/hotspot/share/jfr/support/jfrObjectAllocationSample.hpp b/src/hotspot/share/jfr/support/jfrObjectAllocationSample.hpp index f58caf3c2a6..cb63d7e1e29 100644 --- a/src/hotspot/share/jfr/support/jfrObjectAllocationSample.hpp +++ b/src/hotspot/share/jfr/support/jfrObjectAllocationSample.hpp @@ -27,12 +27,12 @@ #include "memory/allStatic.hpp" +class JavaThread; class Klass; -class Thread; class JfrObjectAllocationSample : AllStatic { friend class JfrAllocationTracer; - static void send_event(const Klass* klass, size_t alloc_size, bool outside_tlab, Thread* thread); + static void send_event(const Klass* klass, size_t alloc_size, bool outside_tlab, JavaThread* jt); }; #endif // SHARE_JFR_SUPPORT_JFROBJECTALLOCATIONSAMPLE_HPP diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp index 7ddb9be540a..b91de1c9b35 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -168,7 +168,7 @@ nonstatic_field(Array, _length, int) \ nonstatic_field(Array, _data[0], Klass*) \ \ - volatile_nonstatic_field(BasicLock, _metadata, uintptr_t) \ + volatile_nonstatic_field(BasicLock, _monitor, ObjectMonitor*) \ \ static_field(CodeCache, _low_bound, address) \ static_field(CodeCache, _high_bound, address) \ diff --git a/src/hotspot/share/memory/universe.cpp b/src/hotspot/share/memory/universe.cpp index a3b841a400b..424e43c5e83 100644 --- a/src/hotspot/share/memory/universe.cpp +++ b/src/hotspot/share/memory/universe.cpp @@ -504,7 +504,7 @@ void Universe::genesis(TRAPS) { // Since some of the old system object arrays have been converted to // ordinary object arrays, _objectArrayKlass will be loaded when // SystemDictionary::initialize(CHECK); is run. See the extra check - // for Object_klass_loaded in objArrayKlassKlass::allocate_objArray_klass_impl. + // for Object_klass_is_loaded in ObjArrayKlass::allocate_objArray_klass. { Klass* oak = vmClasses::Object_klass()->array_klass(CHECK); _objectArrayKlass = ObjArrayKlass::cast(oak); @@ -593,7 +593,7 @@ void Universe::fixup_mirrors(TRAPS) { // but we cannot do that for classes created before java.lang.Class is loaded. Here we simply // walk over permanent objects created so far (mostly classes) and fixup their mirrors. Note // that the number of objects allocated at this point is very small. - assert(vmClasses::Class_klass_loaded(), "java.lang.Class should be loaded"); + assert(vmClasses::Class_klass_is_loaded(), "java.lang.Class should be loaded"); HandleMark hm(THREAD); if (!CDSConfig::is_using_archive()) { diff --git a/src/hotspot/share/metaprogramming/logical.hpp b/src/hotspot/share/metaprogramming/logical.hpp deleted file mode 100644 index a488b94f8b9..00000000000 --- a/src/hotspot/share/metaprogramming/logical.hpp +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef SHARE_METAPROGRAMMING_LOGICAL_HPP -#define SHARE_METAPROGRAMMING_LOGICAL_HPP - -// Stand-ins for C++17 logical operations on types. - -#include - -// Stand-in for C++17 std::bool_constant. -template -using BoolConstant = std::integral_constant; - -// Stand-in for C++17 std::conjunction -template -struct Conjunction : public std::true_type {}; - -template -struct Conjunction : public T1 {}; - -template -struct Conjunction : - public std::conditional_t, T1> -{}; - -// Stand-in for C++17 std::disjunction. -template -struct Disjunction : public std::false_type {}; - -template -struct Disjunction : public T1 {}; - -template -struct Disjunction : - public std::conditional_t> -{}; - -// Stand-in for C++17 std::negation. -template -using Negation = BoolConstant; - -#endif // SHARE_METAPROGRAMMING_LOGICAL_HPP diff --git a/src/hotspot/share/nmt/memoryFileTracker.cpp b/src/hotspot/share/nmt/memoryFileTracker.cpp index 2f3f4f1973a..fe723d09364 100644 --- a/src/hotspot/share/nmt/memoryFileTracker.cpp +++ b/src/hotspot/share/nmt/memoryFileTracker.cpp @@ -42,7 +42,8 @@ void MemoryFileTracker::allocate_memory(MemoryFile* file, size_t offset, MemTag mem_tag) { NativeCallStackStorage::StackIndex sidx = _stack_storage.push(stack); VMATree::RegionData regiondata(sidx, mem_tag); - VMATree::SummaryDiff diff = file->_tree.commit_mapping(offset, size, regiondata); + VMATree::SummaryDiff diff; + file->_tree.commit_mapping(offset, size, regiondata, diff); for (int i = 0; i < mt_number_of_tags; i++) { VirtualMemory* summary = file->_summary.by_tag(NMTUtil::index_to_tag(i)); summary->reserve_memory(diff.tag[i].commit); @@ -51,7 +52,8 @@ void MemoryFileTracker::allocate_memory(MemoryFile* file, size_t offset, } void MemoryFileTracker::free_memory(MemoryFile* file, size_t offset, size_t size) { - VMATree::SummaryDiff diff = file->_tree.release_mapping(offset, size); + VMATree::SummaryDiff diff; + file->_tree.release_mapping(offset, size, diff); for (int i = 0; i < mt_number_of_tags; i++) { VirtualMemory* summary = file->_summary.by_tag(NMTUtil::index_to_tag(i)); summary->reserve_memory(diff.tag[i].commit); diff --git a/src/hotspot/share/nmt/regionsTree.cpp b/src/hotspot/share/nmt/regionsTree.cpp index a2f5a5df67a..83306cbc14f 100644 --- a/src/hotspot/share/nmt/regionsTree.cpp +++ b/src/hotspot/share/nmt/regionsTree.cpp @@ -25,12 +25,12 @@ #include "nmt/regionsTree.inline.hpp" #include "nmt/virtualMemoryTracker.hpp" -VMATree::SummaryDiff RegionsTree::commit_region(address addr, size_t size, const NativeCallStack& stack) { - return commit_mapping((VMATree::position)addr, size, make_region_data(stack, mtNone), /*use tag inplace*/ true); +void RegionsTree::commit_region(address addr, size_t size, const NativeCallStack& stack, VMATree::SummaryDiff& diff) { + commit_mapping((VMATree::position)addr, size, make_region_data(stack, mtNone), diff, /*use tag inplace*/ true); } -VMATree::SummaryDiff RegionsTree::uncommit_region(address addr, size_t size) { - return uncommit_mapping((VMATree::position)addr, size, make_region_data(NativeCallStack::empty_stack(), mtNone)); +void RegionsTree::uncommit_region(address addr, size_t size, VMATree::SummaryDiff& diff) { + uncommit_mapping((VMATree::position)addr, size, make_region_data(NativeCallStack::empty_stack(), mtNone), diff); } #ifdef ASSERT diff --git a/src/hotspot/share/nmt/regionsTree.hpp b/src/hotspot/share/nmt/regionsTree.hpp index 35272c27423..2e1b37d0c1a 100644 --- a/src/hotspot/share/nmt/regionsTree.hpp +++ b/src/hotspot/share/nmt/regionsTree.hpp @@ -48,8 +48,8 @@ class RegionsTree : public VMATree { ReservedMemoryRegion find_reserved_region(address addr); - SummaryDiff commit_region(address addr, size_t size, const NativeCallStack& stack); - SummaryDiff uncommit_region(address addr, size_t size); + void commit_region(address addr, size_t size, const NativeCallStack& stack, SummaryDiff& diff); + void uncommit_region(address addr, size_t size, SummaryDiff& diff); using Node = VMATree::TNode; diff --git a/src/hotspot/share/nmt/virtualMemoryTracker.cpp b/src/hotspot/share/nmt/virtualMemoryTracker.cpp index 643a3d1f8d7..d676d93e040 100644 --- a/src/hotspot/share/nmt/virtualMemoryTracker.cpp +++ b/src/hotspot/share/nmt/virtualMemoryTracker.cpp @@ -69,7 +69,8 @@ void VirtualMemoryTracker::Instance::add_reserved_region(address base_addr, size void VirtualMemoryTracker::add_reserved_region(address base_addr, size_t size, const NativeCallStack& stack, MemTag mem_tag) { - VMATree::SummaryDiff diff = tree()->reserve_mapping((size_t)base_addr, size, tree()->make_region_data(stack, mem_tag)); + VMATree::SummaryDiff diff; + tree()->reserve_mapping((size_t)base_addr, size, tree()->make_region_data(stack, mem_tag), diff); apply_summary_diff(diff); } @@ -148,7 +149,8 @@ void VirtualMemoryTracker::Instance::add_committed_region(address addr, size_t s void VirtualMemoryTracker::add_committed_region(address addr, size_t size, const NativeCallStack& stack) { - VMATree::SummaryDiff diff = tree()->commit_region(addr, size, stack); + VMATree::SummaryDiff diff; + tree()->commit_region(addr, size, stack, diff); apply_summary_diff(diff); } @@ -159,7 +161,8 @@ void VirtualMemoryTracker::Instance::remove_uncommitted_region(address addr, siz void VirtualMemoryTracker::remove_uncommitted_region(address addr, size_t size) { MemTracker::assert_locked(); - VMATree::SummaryDiff diff = tree()->uncommit_region(addr, size); + VMATree::SummaryDiff diff; + tree()->uncommit_region(addr, size, diff); apply_summary_diff(diff); } @@ -169,7 +172,8 @@ void VirtualMemoryTracker::Instance::remove_released_region(address addr, size_t } void VirtualMemoryTracker::remove_released_region(address addr, size_t size) { - VMATree::SummaryDiff diff = tree()->release_mapping((VMATree::position)addr, size); + VMATree::SummaryDiff diff; + tree()->release_mapping((VMATree::position)addr, size, diff); apply_summary_diff(diff); } diff --git a/src/hotspot/share/nmt/vmatree.cpp b/src/hotspot/share/nmt/vmatree.cpp index 69887068cb2..df7b1ac867e 100644 --- a/src/hotspot/share/nmt/vmatree.cpp +++ b/src/hotspot/share/nmt/vmatree.cpp @@ -242,14 +242,14 @@ void VMATree::update_region(TNode* n1, TNode* n2, const RequestInfo& req, Summar } -VMATree::SummaryDiff VMATree::register_mapping(position _A, position _B, StateType state, - const RegionData& metadata, bool use_tag_inplace) { +void VMATree::register_mapping(position _A, position _B, StateType state, + const RegionData& metadata, VMATree::SummaryDiff& diff, bool use_tag_inplace) { + diff.clear(); if (_A == _B) { - return SummaryDiff(); + return; } assert(_A < _B, "should be"); - SummaryDiff diff; RequestInfo req{_A, _B, state, metadata.mem_tag, metadata.stack_idx, use_tag_inplace}; IntervalChange stA{ IntervalState{StateType::Released, empty_regiondata}, @@ -644,8 +644,6 @@ VMATree::SummaryDiff VMATree::register_mapping(position _A, position _B, StateTy while(to_be_removed.length() != 0) { _tree.remove(to_be_removed.pop()); } - - return diff; } #ifdef ASSERT @@ -702,7 +700,8 @@ VMATree::SummaryDiff VMATree::set_tag(const position start, const size size, con // Ignore any released ranges, these must be mtNone and have no stack if (type != StateType::Released) { RegionData new_data = RegionData(out.reserved_stack(), tag); - SummaryDiff result = register_mapping(from, end, type, new_data); + SummaryDiff result; + register_mapping(from, end, type, new_data, result); diff.add(result); } @@ -723,7 +722,8 @@ VMATree::SummaryDiff VMATree::set_tag(const position start, const size size, con if (type != StateType::Released) { RegionData new_data = RegionData(out.reserved_stack(), tag); - SummaryDiff result = register_mapping(from, end, type, new_data); + SummaryDiff result; + register_mapping(from, end, type, new_data, result); diff.add(result); } remsize = remsize - (end - from); diff --git a/src/hotspot/share/nmt/vmatree.hpp b/src/hotspot/share/nmt/vmatree.hpp index dff2491c69c..f7ca8f4c7e0 100644 --- a/src/hotspot/share/nmt/vmatree.hpp +++ b/src/hotspot/share/nmt/vmatree.hpp @@ -241,6 +241,9 @@ class VMATree : public CHeapObjBase { struct SummaryDiff { SingleDiff tag[mt_number_of_tags]; SummaryDiff() { + clear(); + } + void clear() { for (int i = 0; i < mt_number_of_tags; i++) { tag[i] = SingleDiff{0, 0}; } @@ -283,7 +286,7 @@ class VMATree : public CHeapObjBase { }; private: - SummaryDiff register_mapping(position A, position B, StateType state, const RegionData& metadata, bool use_tag_inplace = false); + void register_mapping(position A, position B, StateType state, const RegionData& metadata, SummaryDiff& diff, bool use_tag_inplace = false); StateType get_new_state(const StateType existinting_state, const RequestInfo& req) const; MemTag get_new_tag(const MemTag existinting_tag, const RequestInfo& req) const; SIndex get_new_reserve_callstack(const SIndex existinting_stack, const StateType ex, const RequestInfo& req) const; @@ -298,12 +301,12 @@ class VMATree : public CHeapObjBase { } public: - SummaryDiff reserve_mapping(position from, size size, const RegionData& metadata) { - return register_mapping(from, from + size, StateType::Reserved, metadata, false); + void reserve_mapping(position from, size size, const RegionData& metadata, SummaryDiff& diff ) { + register_mapping(from, from + size, StateType::Reserved, metadata, diff, false); } - SummaryDiff commit_mapping(position from, size size, const RegionData& metadata, bool use_tag_inplace = false) { - return register_mapping(from, from + size, StateType::Committed, metadata, use_tag_inplace); + void commit_mapping(position from, size size, const RegionData& metadata, SummaryDiff& diff, bool use_tag_inplace = false) { + register_mapping(from, from + size, StateType::Committed, metadata, diff, use_tag_inplace); } // Given an interval and a tag, find all reserved and committed ranges at least @@ -312,12 +315,12 @@ class VMATree : public CHeapObjBase { // Released regions are ignored. SummaryDiff set_tag(position from, size size, MemTag tag); - SummaryDiff uncommit_mapping(position from, size size, const RegionData& metadata) { - return register_mapping(from, from + size, StateType::Reserved, metadata, true); + void uncommit_mapping(position from, size size, const RegionData& metadata, SummaryDiff& diff) { + register_mapping(from, from + size, StateType::Reserved, metadata, diff, true); } - SummaryDiff release_mapping(position from, position sz) { - return register_mapping(from, from + sz, StateType::Released, VMATree::empty_regiondata); + void release_mapping(position from, position sz, SummaryDiff& diff) { + register_mapping(from, from + sz, StateType::Released, VMATree::empty_regiondata, diff); } public: diff --git a/src/hotspot/share/oops/compressedKlass.cpp b/src/hotspot/share/oops/compressedKlass.cpp index d7c97d3c8d5..b32d10c74d2 100644 --- a/src/hotspot/share/oops/compressedKlass.cpp +++ b/src/hotspot/share/oops/compressedKlass.cpp @@ -110,7 +110,7 @@ void CompressedKlassPointers::sanity_check_after_initialization() { // Check that Klass range is fully engulfed in the encoding range const address encoding_start = _base; const address encoding_end = (address) - LP64_ONLY(p2u(_base) + (uintptr_t)nth_bit(narrow_klass_pointer_bits() + _shift)) + LP64_ONLY((p2u(_base) + (uintptr_t)nth_bit(narrow_klass_pointer_bits() + _shift))) NOT_LP64(max_klass_range_size()); ASSERT_HERE_2(_klass_range_start >= _base && _klass_range_end <= encoding_end, "Resulting encoding range does not fully cover the class range"); diff --git a/src/hotspot/share/oops/constantPool.cpp b/src/hotspot/share/oops/constantPool.cpp index ddb24302d69..5d5c0548215 100644 --- a/src/hotspot/share/oops/constantPool.cpp +++ b/src/hotspot/share/oops/constantPool.cpp @@ -395,7 +395,7 @@ void ConstantPool::restore_unshareable_info(TRAPS) { // Only create the new resolved references array if it hasn't been attempted before if (resolved_references() != nullptr) return; - if (vmClasses::Object_klass_loaded()) { + if (vmClasses::Object_klass_is_loaded()) { ClassLoaderData* loader_data = pool_holder()->class_loader_data(); #if INCLUDE_CDS_JAVA_HEAP if (ArchiveHeapLoader::is_in_use() && diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp index 9d6cb951aeb..e13f4849454 100644 --- a/src/hotspot/share/oops/instanceKlass.cpp +++ b/src/hotspot/share/oops/instanceKlass.cpp @@ -159,7 +159,7 @@ static inline bool is_class_loader(const Symbol* class_name, return true; } - if (vmClasses::ClassLoader_klass_loaded()) { + if (vmClasses::ClassLoader_klass_is_loaded()) { const Klass* const super_klass = parser.super_klass(); if (super_klass != nullptr) { if (super_klass->is_subtype_of(vmClasses::ClassLoader_klass())) { diff --git a/src/hotspot/share/oops/klass.cpp b/src/hotspot/share/oops/klass.cpp index a93875b86a5..b3386694b79 100644 --- a/src/hotspot/share/oops/klass.cpp +++ b/src/hotspot/share/oops/klass.cpp @@ -614,8 +614,7 @@ GrowableArray* Klass::compute_secondary_supers(int num_extra_slots, // subklass links. Used by the compiler (and vtable initialization) // May be cleaned concurrently, so must use the Compile_lock. -// The log parameter is for clean_weak_klass_links to report unlinked classes. -Klass* Klass::subklass(bool log) const { +Klass* Klass::subklass() const { // Need load_acquire on the _subklass, because it races with inserts that // publishes freshly initialized data. for (Klass* chain = AtomicAccess::load_acquire(&_subklass); @@ -626,11 +625,6 @@ Klass* Klass::subklass(bool log) const { { if (chain->is_loader_alive()) { return chain; - } else if (log) { - if (log_is_enabled(Trace, class, unload)) { - ResourceMark rm; - log_trace(class, unload)("unlinking class (subclass): %s", chain->external_name()); - } } } return nullptr; @@ -701,15 +695,20 @@ void Klass::append_to_sibling_list() { DEBUG_ONLY(verify();) } -void Klass::clean_subklass() { +// The log parameter is for clean_weak_klass_links to report unlinked classes. +Klass* Klass::clean_subklass(bool log) { for (;;) { // Need load_acquire, due to contending with concurrent inserts Klass* subklass = AtomicAccess::load_acquire(&_subklass); if (subklass == nullptr || subklass->is_loader_alive()) { - return; + return subklass; + } + if (log && log_is_enabled(Trace, class, unload)) { + ResourceMark rm; + log_trace(class, unload)("unlinking class (subclass): %s", subklass->external_name()); } // Try to fix _subklass until it points at something not dead. - AtomicAccess::cmpxchg(&_subklass, subklass, subklass->next_sibling()); + AtomicAccess::cmpxchg(&_subklass, subklass, subklass->next_sibling(log)); } } @@ -728,8 +727,7 @@ void Klass::clean_weak_klass_links(bool unloading_occurred, bool clean_alive_kla assert(current->is_loader_alive(), "just checking, this should be live"); // Find and set the first alive subklass - Klass* sub = current->subklass(true); - current->clean_subklass(); + Klass* sub = current->clean_subklass(true); if (sub != nullptr) { stack.push(sub); } diff --git a/src/hotspot/share/oops/klass.hpp b/src/hotspot/share/oops/klass.hpp index 70d9ce3a881..db3360b080e 100644 --- a/src/hotspot/share/oops/klass.hpp +++ b/src/hotspot/share/oops/klass.hpp @@ -300,7 +300,7 @@ class Klass : public Metadata { // Use InstanceKlass::contains_field_offset to classify field offsets. // sub/superklass links - Klass* subklass(bool log = false) const; + Klass* subklass() const; Klass* next_sibling(bool log = false) const; void append_to_sibling_list(); // add newly created receiver to superklass' subklass list @@ -413,9 +413,9 @@ class Klass : public Metadata { virtual ModuleEntry* module() const = 0; virtual PackageEntry* package() const = 0; + void set_next_sibling(Klass* s); protected: // internal accessors void set_subklass(Klass* s); - void set_next_sibling(Klass* s); private: static uint8_t compute_hash_slot(Symbol* s); @@ -743,7 +743,7 @@ class Klass : public Metadata { inline bool is_loader_alive() const; inline bool is_loader_present_and_alive() const; - void clean_subklass(); + Klass* clean_subklass(bool log = false); // Clean out unnecessary weak klass links from the whole klass hierarchy. static void clean_weak_klass_links(bool unloading_occurred, bool clean_alive_klasses = true); diff --git a/src/hotspot/share/oops/objArrayKlass.cpp b/src/hotspot/share/oops/objArrayKlass.cpp index 48d56ddc540..ba2bc7f889f 100644 --- a/src/hotspot/share/oops/objArrayKlass.cpp +++ b/src/hotspot/share/oops/objArrayKlass.cpp @@ -78,7 +78,7 @@ ObjArrayKlass* ObjArrayKlass::allocate_objArray_klass(ClassLoaderData* loader_da // Eagerly allocate the direct array supertype. Klass* super_klass = nullptr; - if (!Universe::is_bootstrapping() || vmClasses::Object_klass_loaded()) { + if (!Universe::is_bootstrapping() || vmClasses::Object_klass_is_loaded()) { assert(MultiArray_lock->holds_lock(THREAD), "must hold lock after bootstrapping"); Klass* element_super = element_klass->super(); if (element_super != nullptr) { diff --git a/src/hotspot/share/oops/trainingData.cpp b/src/hotspot/share/oops/trainingData.cpp index c768d13fe59..ca5883a19ca 100644 --- a/src/hotspot/share/oops/trainingData.cpp +++ b/src/hotspot/share/oops/trainingData.cpp @@ -328,7 +328,9 @@ void CompileTrainingData::notice_jit_observation(ciEnv* env, ciBaseObject* what) // This JIT task is (probably) requesting that ik be initialized, // so add him to my _init_deps list. TrainingDataLocker l; - add_init_dep(ktd); + if (l.can_add()) { + add_init_dep(ktd); + } } } } @@ -618,7 +620,7 @@ void CompileTrainingData::verify(bool verify_dep_counter) { for (int i = 0; i < init_dep_count(); i++) { KlassTrainingData* ktd = init_dep(i); if (ktd->has_holder() && ktd->holder()->defined_by_other_loaders()) { - LogStreamHandle(Warning, training) log; + LogStreamHandle(Info, training) log; if (log.is_enabled()) { ResourceMark rm; log.print("CTD "); print_value_on(&log); diff --git a/src/hotspot/share/opto/divnode.cpp b/src/hotspot/share/opto/divnode.cpp index 213f2e1e9a8..823745ea8e7 100644 --- a/src/hotspot/share/opto/divnode.cpp +++ b/src/hotspot/share/opto/divnode.cpp @@ -1206,6 +1206,11 @@ static const Type* mod_value(const PhaseGVN* phase, const Node* in1, const Node* if (t1 == Type::TOP) { return Type::TOP; } if (t2 == Type::TOP) { return Type::TOP; } + // Mod by zero? Throw exception at runtime! + if (t2 == TypeInteger::zero(bt)) { + return Type::TOP; + } + // We always generate the dynamic check for 0. // 0 MOD X is 0 if (t1 == TypeInteger::zero(bt)) { return t1; } @@ -1215,11 +1220,6 @@ static const Type* mod_value(const PhaseGVN* phase, const Node* in1, const Node* return TypeInteger::zero(bt); } - // Mod by zero? Throw exception at runtime! - if (t2 == TypeInteger::zero(bt)) { - return Type::TOP; - } - const TypeInteger* i1 = t1->is_integer(bt); const TypeInteger* i2 = t2->is_integer(bt); if (i1->is_con() && i2->is_con()) { diff --git a/src/hotspot/share/prims/jvmtiExport.cpp b/src/hotspot/share/prims/jvmtiExport.cpp index 2da9a074fb6..077b3fec505 100644 --- a/src/hotspot/share/prims/jvmtiExport.cpp +++ b/src/hotspot/share/prims/jvmtiExport.cpp @@ -1690,6 +1690,23 @@ void JvmtiExport::post_vthread_unmount(jobject vthread) { } } +bool JvmtiExport::has_frame_pops(JavaThread* thread) { + if (!can_post_frame_pop()) { + return false; + } + JvmtiThreadState *state = get_jvmti_thread_state(thread); + if (state == nullptr) { + return false; + } + JvmtiEnvThreadStateIterator it(state); + for (JvmtiEnvThreadState* ets = it.first(); ets != nullptr; ets = it.next(ets)) { + if (ets->has_frame_pops()) { + return true; + } + } + return false; +} + void JvmtiExport::continuation_yield_cleanup(JavaThread* thread, jint continuation_frame_count) { if (JvmtiEnv::get_phase() < JVMTI_PHASE_PRIMORDIAL) { return; diff --git a/src/hotspot/share/prims/jvmtiExport.hpp b/src/hotspot/share/prims/jvmtiExport.hpp index 4f8c3016908..062057c70ab 100644 --- a/src/hotspot/share/prims/jvmtiExport.hpp +++ b/src/hotspot/share/prims/jvmtiExport.hpp @@ -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 @@ -373,6 +373,7 @@ class JvmtiExport : public AllStatic { JVMTI_ONLY(return _should_post_class_file_load_hook); NOT_JVMTI(return false;) } + static bool has_frame_pops(JavaThread* thread) NOT_JVMTI_RETURN_(false); static bool is_early_phase() NOT_JVMTI_RETURN_(false); static bool has_early_class_hook_env() NOT_JVMTI_RETURN_(false); static bool has_early_vmstart_env() NOT_JVMTI_RETURN_(false); diff --git a/src/hotspot/share/prims/jvmtiRedefineClasses.cpp b/src/hotspot/share/prims/jvmtiRedefineClasses.cpp index 74192d724f6..ef8875d582e 100644 --- a/src/hotspot/share/prims/jvmtiRedefineClasses.cpp +++ b/src/hotspot/share/prims/jvmtiRedefineClasses.cpp @@ -1358,11 +1358,11 @@ jvmtiError VM_RedefineClasses::load_new_class_versions() { // constant pools HandleMark hm(current); InstanceKlass* the_class = get_ik(_class_defs[i].klass); - size_t avail_mem = 0; + physical_memory_size_type avail_mem = 0; // Return value ignored - defaulting to 0 on failure. (void)os::available_memory(avail_mem); log_debug(redefine, class, load) - ("loading name=%s kind=%d (avail_mem=%zuK)", + ("loading name=%s kind=%d (avail_mem=" PHYS_MEM_TYPE_FORMAT "K)", the_class->external_name(), _class_load_kind, avail_mem >> 10); ClassFileStream st((u1*)_class_defs[i].class_bytes, @@ -1530,7 +1530,7 @@ jvmtiError VM_RedefineClasses::load_new_class_versions() { // Return value ignored - defaulting to 0 on failure. (void)os::available_memory(avail_mem); log_debug(redefine, class, load) - ("loaded name=%s (avail_mem=%zuK)", the_class->external_name(), avail_mem >> 10); + ("loaded name=%s (avail_mem=" PHYS_MEM_TYPE_FORMAT "K)", the_class->external_name(), avail_mem >> 10); } return JVMTI_ERROR_NONE; @@ -4438,11 +4438,11 @@ void VM_RedefineClasses::redefine_single_class(Thread* current, jclass the_jclas ResourceMark rm(current); // increment the classRedefinedCount field in the_class and in any // direct and indirect subclasses of the_class - size_t avail_mem = 0; + physical_memory_size_type avail_mem = 0; // Return value ignored - defaulting to 0 on failure. (void)os::available_memory(avail_mem); log_info(redefine, class, load) - ("redefined name=%s, count=%d (avail_mem=%zuK)", + ("redefined name=%s, count=%d (avail_mem=" PHYS_MEM_TYPE_FORMAT "K)", the_class->external_name(), java_lang_Class::classRedefinedCount(the_class->java_mirror()), avail_mem >> 10); Events::log_redefinition(current, "redefined class name=%s, count=%d", the_class->external_name(), diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index 6d9ab57bb9a..f77b648ba95 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -2510,7 +2510,7 @@ WB_END // Available memory of the host machine (container-aware) WB_ENTRY(jlong, WB_HostAvailableMemory(JNIEnv* env, jobject o)) - size_t avail_mem = 0; + physical_memory_size_type avail_mem = 0; // Return value ignored - defaulting to 0 on failure. (void)os::available_memory(avail_mem); return static_cast(avail_mem); diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index b7ab68e143c..e43b18209bf 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -1649,7 +1649,7 @@ jint Arguments::set_aggressive_heap_flags() { // Thus, we need to make sure we're using a julong for intermediate // calculations. julong initHeapSize; - size_t phys_mem = os::physical_memory(); + physical_memory_size_type phys_mem = os::physical_memory(); julong total_memory = static_cast(phys_mem); if (total_memory < (julong) 256 * M) { diff --git a/src/hotspot/share/runtime/basicLock.cpp b/src/hotspot/share/runtime/basicLock.cpp index 71082e24bb9..4a6e7402dfa 100644 --- a/src/hotspot/share/runtime/basicLock.cpp +++ b/src/hotspot/share/runtime/basicLock.cpp @@ -74,7 +74,7 @@ void BasicLock::move_to(oop obj, BasicLock* dest) { } #ifdef ASSERT else { - dest->set_bad_metadata_deopt(); + dest->set_bad_monitor_deopt(); } #endif } diff --git a/src/hotspot/share/runtime/basicLock.hpp b/src/hotspot/share/runtime/basicLock.hpp index c22416a1c06..479748f51a4 100644 --- a/src/hotspot/share/runtime/basicLock.hpp +++ b/src/hotspot/share/runtime/basicLock.hpp @@ -37,23 +37,21 @@ class BasicLock { private: // Used as a cache of the ObjectMonitor* used when locking. Must either // be nullptr or the ObjectMonitor* used when locking. - volatile uintptr_t _metadata; + ObjectMonitor* volatile _monitor; - uintptr_t get_metadata() const { return AtomicAccess::load(&_metadata); } - void set_metadata(uintptr_t value) { AtomicAccess::store(&_metadata, value); } - static int metadata_offset_in_bytes() { return (int)offset_of(BasicLock, _metadata); } + ObjectMonitor* get_monitor() const { return AtomicAccess::load(&_monitor); } + void set_monitor(ObjectMonitor* mon) { AtomicAccess::store(&_monitor, mon); } + static int monitor_offset_in_bytes() { return (int)offset_of(BasicLock, _monitor); } public: - BasicLock() : _metadata(0) {} + BasicLock() : _monitor(nullptr) {} - void set_bad_metadata_deopt() { set_metadata(badDispHeaderDeopt); } - - static int displaced_header_offset_in_bytes() { return metadata_offset_in_bytes(); } + void set_bad_monitor_deopt() { set_monitor(reinterpret_cast(badDispHeaderDeopt)); } inline ObjectMonitor* object_monitor_cache() const; inline void clear_object_monitor_cache(); inline void set_object_monitor_cache(ObjectMonitor* mon); - static int object_monitor_cache_offset_in_bytes() { return metadata_offset_in_bytes(); } + static int object_monitor_cache_offset_in_bytes() { return monitor_offset_in_bytes(); } void print_on(outputStream* st, oop owner) const; diff --git a/src/hotspot/share/runtime/basicLock.inline.hpp b/src/hotspot/share/runtime/basicLock.inline.hpp index 2ea1fe2371c..9f0f26ee957 100644 --- a/src/hotspot/share/runtime/basicLock.inline.hpp +++ b/src/hotspot/share/runtime/basicLock.inline.hpp @@ -32,23 +32,23 @@ inline ObjectMonitor* BasicLock::object_monitor_cache() const { assert(UseObjectMonitorTable, "must be"); #if !defined(ZERO) && (defined(X86) || defined(AARCH64) || defined(RISCV64) || defined(PPC64) || defined(S390)) - return reinterpret_cast(get_metadata()); + return reinterpret_cast(get_monitor()); #else // Other platforms do not make use of the cache yet, // and are not as careful with maintaining the invariant - // that the metadata either is nullptr or ObjectMonitor*. + // that the monitor either is nullptr or a valid ObjectMonitor*. return nullptr; #endif } inline void BasicLock::clear_object_monitor_cache() { assert(UseObjectMonitorTable, "must be"); - set_metadata(0); + set_monitor(nullptr); } inline void BasicLock::set_object_monitor_cache(ObjectMonitor* mon) { assert(UseObjectMonitorTable, "must be"); - set_metadata(reinterpret_cast(mon)); + set_monitor(mon); } #endif // SHARE_RUNTIME_BASICLOCK_INLINE_HPP diff --git a/src/hotspot/share/runtime/continuationFreezeThaw.cpp b/src/hotspot/share/runtime/continuationFreezeThaw.cpp index 64f9d2b9994..024b69c765f 100644 --- a/src/hotspot/share/runtime/continuationFreezeThaw.cpp +++ b/src/hotspot/share/runtime/continuationFreezeThaw.cpp @@ -1619,15 +1619,14 @@ static int num_java_frames(ContinuationWrapper& cont) { } static void invalidate_jvmti_stack(JavaThread* thread) { - if (thread->is_interp_only_mode()) { - JvmtiThreadState *state = thread->jvmti_thread_state(); - if (state != nullptr) - state->invalidate_cur_stack_depth(); + JvmtiThreadState *state = thread->jvmti_thread_state(); + if (state != nullptr) { + state->invalidate_cur_stack_depth(); } } static void jvmti_yield_cleanup(JavaThread* thread, ContinuationWrapper& cont) { - if (JvmtiExport::can_post_frame_pop()) { + if (JvmtiExport::has_frame_pops(thread)) { int num_frames = num_java_frames(cont); ContinuationWrapper::SafepointOp so(Thread::current(), cont); diff --git a/src/hotspot/share/runtime/deoptimization.cpp b/src/hotspot/share/runtime/deoptimization.cpp index d14db6ad0ed..a96c18a18aa 100644 --- a/src/hotspot/share/runtime/deoptimization.cpp +++ b/src/hotspot/share/runtime/deoptimization.cpp @@ -1656,7 +1656,7 @@ bool Deoptimization::relock_objects(JavaThread* thread, GrowableArraylock()->set_bad_metadata_deopt(); + mon_info->lock()->set_bad_monitor_deopt(); } #endif JvmtiDeferredUpdates::inc_relock_count_after_wait(deoptee_thread); diff --git a/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.cpp b/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.cpp index 4e28135dccf..d0141c2e6cc 100644 --- a/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.cpp +++ b/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.cpp @@ -355,10 +355,8 @@ JVMFlag::Error InteriorEntryAlignmentConstraintFunc(intx value, bool verbose) { } int minimum_alignment = 16; -#if defined(X86) && !defined(AMD64) +#if (defined(X86) && !defined(AMD64)) || defined(S390) minimum_alignment = 4; -#elif defined(S390) - minimum_alignment = 2; #endif if (InteriorEntryAlignment < minimum_alignment) { diff --git a/src/hotspot/share/runtime/java.cpp b/src/hotspot/share/runtime/java.cpp index 9363f9055ba..6fda21ac86c 100644 --- a/src/hotspot/share/runtime/java.cpp +++ b/src/hotspot/share/runtime/java.cpp @@ -747,29 +747,19 @@ int JDK_Version::compare(const JDK_Version& other) const { /* See JEP 223 */ void JDK_Version::to_string(char* buffer, size_t buflen) const { - assert(buffer && buflen > 0, "call with useful buffer"); - size_t index = 0; - + assert((buffer != nullptr) && (buflen > 0), "call with useful buffer"); + stringStream ss{buffer, buflen}; if (!is_valid()) { - jio_snprintf(buffer, buflen, "%s", "(uninitialized)"); + ss.print_raw("(uninitialized)"); } else { - int rc = jio_snprintf( - &buffer[index], buflen - index, "%d.%d", _major, _minor); - if (rc == -1) return; - index += rc; + ss.print("%d.%d", _major, _minor); if (_patch > 0) { - rc = jio_snprintf(&buffer[index], buflen - index, ".%d.%d", _security, _patch); - if (rc == -1) return; - index += rc; + ss.print(".%d.%d", _security, _patch); } else if (_security > 0) { - rc = jio_snprintf(&buffer[index], buflen - index, ".%d", _security); - if (rc == -1) return; - index += rc; + ss.print(".%d", _security); } if (_build > 0) { - rc = jio_snprintf(&buffer[index], buflen - index, "+%d", _build); - if (rc == -1) return; - index += rc; + ss.print("+%d", _build); } } } diff --git a/src/hotspot/share/runtime/objectMonitor.hpp b/src/hotspot/share/runtime/objectMonitor.hpp index 3c925928be2..50aec549045 100644 --- a/src/hotspot/share/runtime/objectMonitor.hpp +++ b/src/hotspot/share/runtime/objectMonitor.hpp @@ -32,6 +32,7 @@ #include "oops/weakHandle.hpp" #include "runtime/javaThread.hpp" #include "utilities/checkedCast.hpp" +#include "utilities/globalDefinitions.hpp" class ObjectMonitor; class ObjectMonitorContentionMark; @@ -72,20 +73,19 @@ class ObjectWaiter : public CHeapObj { void wait_reenter_begin(ObjectMonitor *mon); void wait_reenter_end(ObjectMonitor *mon); - ObjectWaiter* const badObjectWaiterPtr = (ObjectWaiter*) 0xBAD; void set_bad_pointers() { #ifdef ASSERT - this->_prev = badObjectWaiterPtr; - this->_next = badObjectWaiterPtr; + this->_prev = (ObjectWaiter*) badAddressVal; + this->_next = (ObjectWaiter*) badAddressVal; this->TState = ObjectWaiter::TS_RUN; #endif } ObjectWaiter* next() { - assert (_next != badObjectWaiterPtr, "corrupted list!"); + assert (_next != (ObjectWaiter*) badAddressVal, "corrupted list!"); return _next; } ObjectWaiter* prev() { - assert (_prev != badObjectWaiterPtr, "corrupted list!"); + assert (_prev != (ObjectWaiter*) badAddressVal, "corrupted list!"); return _prev; } }; diff --git a/src/hotspot/share/runtime/os.cpp b/src/hotspot/share/runtime/os.cpp index 4f00ff17269..674b0a55841 100644 --- a/src/hotspot/share/runtime/os.cpp +++ b/src/hotspot/share/runtime/os.cpp @@ -1184,13 +1184,13 @@ void os::print_summary_info(outputStream* st, char* buf, size_t buflen) { #endif // PRODUCT get_summary_cpu_info(buf, buflen); st->print("%s, ", buf); - size_t phys_mem = physical_memory(); - size_t mem = phys_mem/G; + physical_memory_size_type phys_mem = physical_memory(); + physical_memory_size_type mem = phys_mem/G; if (mem == 0) { // for low memory systems mem = phys_mem/M; - st->print("%d cores, %zuM, ", processor_count(), mem); + st->print("%d cores, " PHYS_MEM_TYPE_FORMAT "M, ", processor_count(), mem); } else { - st->print("%d cores, %zuG, ", processor_count(), mem); + st->print("%d cores, " PHYS_MEM_TYPE_FORMAT "G, ", processor_count(), mem); } get_summary_os_info(buf, buflen); st->print_raw(buf); @@ -1935,17 +1935,17 @@ bool os::is_server_class_machine() { return true; } // Then actually look at the machine - bool result = false; - const unsigned int server_processors = 2; - const julong server_memory = 2UL * G; + bool result = false; + const unsigned int server_processors = 2; + const physical_memory_size_type server_memory = 2UL * G; // We seem not to get our full complement of memory. // We allow some part (1/8?) of the memory to be "missing", // based on the sizes of DIMMs, and maybe graphics cards. - const julong missing_memory = 256UL * M; - size_t phys_mem = os::physical_memory(); + const physical_memory_size_type missing_memory = 256UL * M; + physical_memory_size_type phys_mem = os::physical_memory(); /* Is this a server class machine? */ if ((os::active_processor_count() >= (int)server_processors) && - (phys_mem >= (server_memory - missing_memory))) { + (phys_mem >= server_memory - missing_memory)) { const unsigned int logical_processors = VM_Version::logical_processors_per_package(); if (logical_processors > 1) { @@ -2204,22 +2204,22 @@ static void assert_nonempty_range(const char* addr, size_t bytes) { p2i(addr), p2i(addr) + bytes); } -bool os::used_memory(size_t& value) { +bool os::used_memory(physical_memory_size_type& value) { #ifdef LINUX if (OSContainer::is_containerized()) { jlong mem_usage = OSContainer::memory_usage_in_bytes(); if (mem_usage > 0) { - value = static_cast(mem_usage); + value = static_cast(mem_usage); return true; } else { return false; } } #endif - size_t avail_mem = 0; + physical_memory_size_type avail_mem = 0; // Return value ignored - defaulting to 0 on failure. (void)os::available_memory(avail_mem); - size_t phys_mem = os::physical_memory(); + physical_memory_size_type phys_mem = os::physical_memory(); value = phys_mem - avail_mem; return true; } diff --git a/src/hotspot/share/runtime/os.hpp b/src/hotspot/share/runtime/os.hpp index 626970fa4fb..76695de2c1b 100644 --- a/src/hotspot/share/runtime/os.hpp +++ b/src/hotspot/share/runtime/os.hpp @@ -332,14 +332,14 @@ class os: AllStatic { // For example, on Linux, "available" memory (`MemAvailable` in `/proc/meminfo`) is greater // than "free" memory (`MemFree` in `/proc/meminfo`) because Linux can free memory // aggressively (e.g. clear caches) so that it becomes available. - [[nodiscard]] static bool available_memory(size_t& value); - [[nodiscard]] static bool used_memory(size_t& value); - [[nodiscard]] static bool free_memory(size_t& value); + [[nodiscard]] static bool available_memory(physical_memory_size_type& value); + [[nodiscard]] static bool used_memory(physical_memory_size_type& value); + [[nodiscard]] static bool free_memory(physical_memory_size_type& value); - [[nodiscard]] static bool total_swap_space(size_t& value); - [[nodiscard]] static bool free_swap_space(size_t& value); + [[nodiscard]] static bool total_swap_space(physical_memory_size_type& value); + [[nodiscard]] static bool free_swap_space(physical_memory_size_type& value); - static size_t physical_memory(); + static physical_memory_size_type physical_memory(); static bool is_server_class_machine(); static size_t rss(); @@ -535,7 +535,6 @@ class os: AllStatic { static void realign_memory(char *addr, size_t bytes, size_t alignment_hint); // NUMA-specific interface - static bool numa_has_group_homing(); static void numa_make_local(char *addr, size_t bytes, int lgrp_hint); static void numa_make_global(char *addr, size_t bytes); static size_t numa_get_groups_num(); diff --git a/src/hotspot/share/runtime/synchronizer.inline.hpp b/src/hotspot/share/runtime/synchronizer.inline.hpp index a44fe817276..6a850e5c8ca 100644 --- a/src/hotspot/share/runtime/synchronizer.inline.hpp +++ b/src/hotspot/share/runtime/synchronizer.inline.hpp @@ -45,7 +45,7 @@ inline ObjectMonitor* ObjectSynchronizer::read_monitor(Thread* current, oop obj, inline void ObjectSynchronizer::enter(Handle obj, BasicLock* lock, JavaThread* current) { assert(current == Thread::current(), "must be"); - LightweightSynchronizer::enter(obj, lock, current); + LightweightSynchronizer::enter(obj, lock, current); } inline bool ObjectSynchronizer::quick_enter(oop obj, BasicLock* lock, JavaThread* current) { diff --git a/src/hotspot/share/runtime/thread.cpp b/src/hotspot/share/runtime/thread.cpp index 361743f83e8..32c99320bdf 100644 --- a/src/hotspot/share/runtime/thread.cpp +++ b/src/hotspot/share/runtime/thread.cpp @@ -65,7 +65,7 @@ Thread::Thread(MemTag mem_tag) { // stack and get_thread set_stack_base(nullptr); set_stack_size(0); - set_lgrp_id(-1); + _lgrp_id = -1; DEBUG_ONLY(clear_suspendible_thread();) DEBUG_ONLY(clear_indirectly_suspendible_thread();) DEBUG_ONLY(clear_indirectly_safepoint_thread();) diff --git a/src/hotspot/share/runtime/thread.hpp b/src/hotspot/share/runtime/thread.hpp index fe2b997f94c..f752ce87644 100644 --- a/src/hotspot/share/runtime/thread.hpp +++ b/src/hotspot/share/runtime/thread.hpp @@ -537,8 +537,8 @@ class Thread: public ThreadShadow { void register_thread_stack_with_NMT(); void unregister_thread_stack_with_NMT(); - int lgrp_id() const { return _lgrp_id; } - void set_lgrp_id(int value) { _lgrp_id = value; } + int lgrp_id() const { return _lgrp_id; } + void update_lgrp_id() { _lgrp_id = os::numa_get_group_id(); } // Printing void print_on(outputStream* st, bool print_extended_info) const; diff --git a/src/hotspot/share/runtime/threads.cpp b/src/hotspot/share/runtime/threads.cpp index 0172fe4d69b..d098343c354 100644 --- a/src/hotspot/share/runtime/threads.cpp +++ b/src/hotspot/share/runtime/threads.cpp @@ -1,4 +1,3 @@ - /* * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2021, Azul Systems, Inc. All rights reserved. diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index 86874a967e3..10069e849bc 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -1,4 +1,3 @@ - /* * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -682,7 +681,6 @@ unchecked_nonstatic_field(ObjectMonitor, _object, sizeof(void *)) /* NOTE: no type */ \ volatile_nonstatic_field(ObjectMonitor, _owner, int64_t) \ volatile_nonstatic_field(ObjectMonitor, _next_om, ObjectMonitor*) \ - volatile_nonstatic_field(BasicLock, _metadata, uintptr_t) \ nonstatic_field(ObjectMonitor, _contentions, int) \ volatile_nonstatic_field(ObjectMonitor, _waiters, int) \ volatile_nonstatic_field(ObjectMonitor, _recursions, intx) \ diff --git a/src/hotspot/share/services/heapDumper.cpp b/src/hotspot/share/services/heapDumper.cpp index 626434b08a7..bfb4546a8a1 100644 --- a/src/hotspot/share/services/heapDumper.cpp +++ b/src/hotspot/share/services/heapDumper.cpp @@ -2610,7 +2610,7 @@ int HeapDumper::dump(const char* path, outputStream* out, int compression, bool // (DumpWriter buffer, DumperClassCacheTable, GZipCompressor buffers). // For the OOM handling we may already be limited in memory. // Lets ensure we have at least 20MB per thread. - size_t free_memory = 0; + physical_memory_size_type free_memory = 0; // Return value ignored - defaulting to 0 on failure. (void)os::free_memory(free_memory); julong max_threads = free_memory / (20 * M); diff --git a/src/hotspot/share/services/threadIdTable.cpp b/src/hotspot/share/services/threadIdTable.cpp index 24ea28abaf6..1604927a0ac 100644 --- a/src/hotspot/share/services/threadIdTable.cpp +++ b/src/hotspot/share/services/threadIdTable.cpp @@ -1,4 +1,3 @@ - /* * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. diff --git a/src/hotspot/share/services/threadIdTable.hpp b/src/hotspot/share/services/threadIdTable.hpp index 12772aed88c..b295cec2514 100644 --- a/src/hotspot/share/services/threadIdTable.hpp +++ b/src/hotspot/share/services/threadIdTable.hpp @@ -1,4 +1,3 @@ - /* * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. diff --git a/src/hotspot/share/services/threadService.cpp b/src/hotspot/share/services/threadService.cpp index 04d39bf9cf2..547ca4e51d5 100644 --- a/src/hotspot/share/services/threadService.cpp +++ b/src/hotspot/share/services/threadService.cpp @@ -1161,9 +1161,11 @@ class GetThreadSnapshotHandshakeClosure: public HandshakeClosure { Type _type; // park blocker or an object the thread waiting on/trying to lock OopHandle _obj; + // thread that owns park blocker object when park blocker is AbstractOwnableSynchronizer + OopHandle _owner; - Blocker(Type type, OopHandle obj): _type(type), _obj(obj) {} - Blocker(): _type(NOTHING), _obj(nullptr) {} + Blocker(Type type, OopHandle obj): _type(type), _obj(obj), _owner() {} + Blocker(): _type(NOTHING), _obj(), _owner() {} bool is_empty() const { return _type == NOTHING; @@ -1198,6 +1200,7 @@ class GetThreadSnapshotHandshakeClosure: public HandshakeClosure { delete _locks; } _blocker._obj.release(oop_storage()); + _blocker._owner.release(oop_storage()); } private: @@ -1300,6 +1303,13 @@ class GetThreadSnapshotHandshakeClosure: public HandshakeClosure { oop park_blocker = java_lang_Thread::park_blocker(_thread_h()); if (park_blocker != nullptr) { _blocker = Blocker(Blocker::PARK_BLOCKER, OopHandle(oop_storage(), park_blocker)); + if (park_blocker->is_a(vmClasses::java_util_concurrent_locks_AbstractOwnableSynchronizer_klass())) { + // could be stale (unlikely in practice), but it's good enough to see deadlocks + oop ownerObj = java_util_concurrent_locks_AbstractOwnableSynchronizer::get_owner_threadObj(park_blocker); + if (ownerObj != nullptr) { + _blocker._owner = OopHandle(oop_storage(), ownerObj); + } + } } ResourceMark rm(current); @@ -1381,6 +1391,7 @@ class jdk_internal_vm_ThreadSnapshot: AllStatic { static int _locks_offset; static int _blockerTypeOrdinal_offset; static int _blockerObject_offset; + static int _parkBlockerOwner_offset; static void compute_offsets(InstanceKlass* klass, TRAPS) { JavaClasses::compute_offset(_name_offset, klass, "name", vmSymbols::string_signature(), false); @@ -1390,6 +1401,7 @@ class jdk_internal_vm_ThreadSnapshot: AllStatic { JavaClasses::compute_offset(_locks_offset, klass, "locks", vmSymbols::jdk_internal_vm_ThreadLock_array(), false); JavaClasses::compute_offset(_blockerTypeOrdinal_offset, klass, "blockerTypeOrdinal", vmSymbols::int_signature(), false); JavaClasses::compute_offset(_blockerObject_offset, klass, "blockerObject", vmSymbols::object_signature(), false); + JavaClasses::compute_offset(_parkBlockerOwner_offset, klass, "parkBlockerOwner", vmSymbols::thread_signature(), false); } public: static void init(InstanceKlass* klass, TRAPS) { @@ -1420,9 +1432,10 @@ class jdk_internal_vm_ThreadSnapshot: AllStatic { static void set_locks(oop snapshot, oop locks) { snapshot->obj_field_put(_locks_offset, locks); } - static void set_blocker(oop snapshot, int type_ordinal, oop lock) { + static void set_blocker(oop snapshot, int type_ordinal, oop lock, oop owner) { snapshot->int_field_put(_blockerTypeOrdinal_offset, type_ordinal); snapshot->obj_field_put(_blockerObject_offset, lock); + snapshot->obj_field_put(_parkBlockerOwner_offset, owner); } }; @@ -1434,6 +1447,7 @@ int jdk_internal_vm_ThreadSnapshot::_stackTrace_offset; int jdk_internal_vm_ThreadSnapshot::_locks_offset; int jdk_internal_vm_ThreadSnapshot::_blockerTypeOrdinal_offset; int jdk_internal_vm_ThreadSnapshot::_blockerObject_offset; +int jdk_internal_vm_ThreadSnapshot::_parkBlockerOwner_offset; oop ThreadSnapshotFactory::get_thread_snapshot(jobject jthread, TRAPS) { ThreadsListHandle tlh(THREAD); @@ -1559,7 +1573,8 @@ oop ThreadSnapshotFactory::get_thread_snapshot(jobject jthread, TRAPS) { jdk_internal_vm_ThreadSnapshot::set_stack_trace(snapshot(), trace()); jdk_internal_vm_ThreadSnapshot::set_locks(snapshot(), locks()); if (!cl._blocker.is_empty()) { - jdk_internal_vm_ThreadSnapshot::set_blocker(snapshot(), cl._blocker._type, cl._blocker._obj.resolve()); + jdk_internal_vm_ThreadSnapshot::set_blocker(snapshot(), + cl._blocker._type, cl._blocker._obj.resolve(), cl._blocker._owner.resolve()); } return snapshot(); } diff --git a/src/hotspot/share/utilities/globalDefinitions.hpp b/src/hotspot/share/utilities/globalDefinitions.hpp index ea684368888..0d6e3bb2d76 100644 --- a/src/hotspot/share/utilities/globalDefinitions.hpp +++ b/src/hotspot/share/utilities/globalDefinitions.hpp @@ -135,6 +135,7 @@ class oopDesc; #define UINT64_FORMAT_X_0 "0x%016" PRIx64 #define UINT64_FORMAT_W(width) "%" #width PRIu64 #define UINT64_FORMAT_0 "%016" PRIx64 +#define PHYS_MEM_TYPE_FORMAT "%" PRIu64 // Format jlong, if necessary #ifndef JLONG_FORMAT @@ -417,6 +418,11 @@ const uintx max_uintx = (uintx)-1; typedef unsigned int uint; NEEDS_CLEANUP +// This typedef is to address the issue of running a 32-bit VM. In this case the amount +// of physical memory may not fit in size_t, so we have to have a larger type. Once 32-bit +// is deprecated, one can use size_t. +typedef uint64_t physical_memory_size_type; + //---------------------------------------------------------------------------------------------------- // Java type definitions diff --git a/src/hotspot/share/utilities/stringUtils.cpp b/src/hotspot/share/utilities/stringUtils.cpp index cd4c2d6c33b..0872ce43d4b 100644 --- a/src/hotspot/share/utilities/stringUtils.cpp +++ b/src/hotspot/share/utilities/stringUtils.cpp @@ -24,6 +24,7 @@ #include "jvm_io.h" #include "memory/allocation.hpp" +#include "runtime/os.hpp" #include "utilities/debug.hpp" #include "utilities/stringUtils.hpp" diff --git a/src/hotspot/share/utilities/stringUtils.hpp b/src/hotspot/share/utilities/stringUtils.hpp index f30c9c3ea78..c3d21233808 100644 --- a/src/hotspot/share/utilities/stringUtils.hpp +++ b/src/hotspot/share/utilities/stringUtils.hpp @@ -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 diff --git a/src/java.base/share/classes/java/lang/Class.java b/src/java.base/share/classes/java/lang/Class.java index 5341249e085..fd3fe3ac2c0 100644 --- a/src/java.base/share/classes/java/lang/Class.java +++ b/src/java.base/share/classes/java/lang/Class.java @@ -84,12 +84,11 @@ import jdk.internal.vm.annotation.IntrinsicCandidate; import jdk.internal.vm.annotation.Stable; +import sun.invoke.util.BytecodeDescriptor; import sun.invoke.util.Wrapper; import sun.reflect.generics.factory.CoreReflectionFactory; import sun.reflect.generics.factory.GenericsFactory; import sun.reflect.generics.repository.ClassRepository; -import sun.reflect.generics.repository.MethodRepository; -import sun.reflect.generics.repository.ConstructorRepository; import sun.reflect.generics.scope.ClassScope; import sun.reflect.annotation.*; @@ -1447,17 +1446,10 @@ public Method getEnclosingMethod() { if (!enclosingInfo.isMethod()) return null; - MethodRepository typeInfo = MethodRepository.make(enclosingInfo.getDescriptor(), - getFactory()); - Class returnType = toClass(typeInfo.getReturnType()); - Type [] parameterTypes = typeInfo.getParameterTypes(); - Class[] parameterClasses = new Class[parameterTypes.length]; - - // Convert Types to Classes; returned types *should* - // be class objects since the methodDescriptor's used - // don't have generics information - for(int i = 0; i < parameterClasses.length; i++) - parameterClasses[i] = toClass(parameterTypes[i]); + // Descriptor already validated by VM + List> types = BytecodeDescriptor.parseMethod(enclosingInfo.getDescriptor(), getClassLoader()); + Class returnType = types.removeLast(); + Class[] parameterClasses = types.toArray(EMPTY_CLASS_ARRAY); final Class enclosingCandidate = enclosingInfo.getEnclosingClass(); Method[] candidates = enclosingCandidate.privateGetDeclaredMethods(false); @@ -1576,17 +1568,10 @@ public Constructor getEnclosingConstructor() { if (!enclosingInfo.isConstructor()) return null; - ConstructorRepository typeInfo = ConstructorRepository.make(enclosingInfo.getDescriptor(), - getFactory()); - Type [] parameterTypes = typeInfo.getParameterTypes(); - Class[] parameterClasses = new Class[parameterTypes.length]; - - // Convert Types to Classes; returned types *should* - // be class objects since the methodDescriptor's used - // don't have generics information - for (int i = 0; i < parameterClasses.length; i++) - parameterClasses[i] = toClass(parameterTypes[i]); - + // Descriptor already validated by VM + List> types = BytecodeDescriptor.parseMethod(enclosingInfo.getDescriptor(), getClassLoader()); + types.removeLast(); + Class[] parameterClasses = types.toArray(EMPTY_CLASS_ARRAY); final Class enclosingCandidate = enclosingInfo.getEnclosingClass(); Constructor[] candidates = enclosingCandidate @@ -1892,7 +1877,7 @@ public Class[] getClasses() { } currentClass = currentClass.getSuperclass(); } - return list.toArray(new Class[0]); + return list.toArray(EMPTY_CLASS_ARRAY); } diff --git a/src/java.base/share/classes/java/math/BigInteger.java b/src/java.base/share/classes/java/math/BigInteger.java index 21f8598266f..6253adffb2b 100644 --- a/src/java.base/share/classes/java/math/BigInteger.java +++ b/src/java.base/share/classes/java/math/BigInteger.java @@ -4180,6 +4180,10 @@ public String toString(int radix) { if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX) radix = 10; + if (fitsIntoLong()) { + return Long.toString(longValue(), radix); + } + BigInteger abs = this.abs(); // Ensure buffer capacity sufficient to contain string representation @@ -5121,12 +5125,16 @@ private byte[] magSerializedForm() { * @since 1.8 */ public long longValueExact() { - if (mag.length <= 2 && bitLength() < Long.SIZE) + if (fitsIntoLong()) return longValue(); throw new ArithmeticException("BigInteger out of long range"); } + private boolean fitsIntoLong() { + return mag.length <= 2 && bitLength() < Long.SIZE; + } + /** * Converts this {@code BigInteger} to an {@code int}, checking * for lost information. If the value of this {@code BigInteger} diff --git a/src/java.base/share/classes/java/text/CompactNumberFormat.java b/src/java.base/share/classes/java/text/CompactNumberFormat.java index 7163b2dd63b..74c1eabe970 100644 --- a/src/java.base/share/classes/java/text/CompactNumberFormat.java +++ b/src/java.base/share/classes/java/text/CompactNumberFormat.java @@ -250,38 +250,43 @@ public final class CompactNumberFormat extends NumberFormat { /** * List of positive prefix patterns of this formatter's - * compact number patterns. + * compact number patterns. This field is a read-only + * constant once initialized. */ private transient List positivePrefixPatterns; /** * List of negative prefix patterns of this formatter's - * compact number patterns. + * compact number patterns. This field is a read-only + * constant once initialized. */ private transient List negativePrefixPatterns; /** * List of positive suffix patterns of this formatter's - * compact number patterns. + * compact number patterns. This field is a read-only + * constant once initialized. */ private transient List positiveSuffixPatterns; /** * List of negative suffix patterns of this formatter's - * compact number patterns. + * compact number patterns. This field is a read-only + * constant once initialized. */ private transient List negativeSuffixPatterns; /** * List of divisors of this formatter's compact number patterns. * Divisor can be either Long or BigInteger (if the divisor value goes - * beyond long boundary) + * beyond long boundary). This field is a read-only constant + * once initialized. */ private transient List divisors; /** * List of place holders that represent minimum integer digits at each index - * for each count. + * for each count. This field is a read-only constant once initialized. */ private transient List placeHolderPatterns; @@ -374,7 +379,7 @@ public final class CompactNumberFormat extends NumberFormat { /** * The map for plural rules that maps LDML defined tags (e.g. "one") to - * its rule. + * its rule. This field is a read-only constant once initialized. */ private transient Map rulesMap; @@ -1515,7 +1520,7 @@ private void applyPattern(String count, String pattern, int index) { } } - private final transient DigitList digitList = new DigitList(); + private transient DigitList digitList = new DigitList(); private static final int STATUS_INFINITE = 0; private static final int STATUS_POSITIVE = 1; private static final int STATUS_LENGTH = 2; @@ -2506,8 +2511,14 @@ public String toString() { @Override public CompactNumberFormat clone() { CompactNumberFormat other = (CompactNumberFormat) super.clone(); + + // Cloning reference fields. Other fields (e.g., "positivePrefixPatterns") + // are not cloned since they are read-only constants after initialization. other.compactPatterns = compactPatterns.clone(); other.symbols = (DecimalFormatSymbols) symbols.clone(); + other.decimalFormat = (DecimalFormat) decimalFormat.clone(); + other.defaultDecimalFormat = (DecimalFormat) defaultDecimalFormat.clone(); + other.digitList = (DigitList) digitList.clone(); return other; } diff --git a/src/java.base/share/classes/java/text/DecimalFormat.java b/src/java.base/share/classes/java/text/DecimalFormat.java index 7ace5e136fe..c803a97ad86 100644 --- a/src/java.base/share/classes/java/text/DecimalFormat.java +++ b/src/java.base/share/classes/java/text/DecimalFormat.java @@ -2335,9 +2335,10 @@ public Number parse(String text, ParsePosition pos) { // (bug 4162852). if (multiplier != 1 && gotDouble) { longResult = (long)doubleResult; - gotDouble = ((doubleResult != (double)longResult) || - (doubleResult == 0.0 && 1/doubleResult < 0.0)) && - !isParseIntegerOnly(); + gotDouble = ((doubleResult >= Long.MAX_VALUE || doubleResult <= Long.MIN_VALUE) || + (doubleResult != (double)longResult) || + (doubleResult == 0.0 && 1/doubleResult < 0.0)) && + !isParseIntegerOnly(); } // cast inside of ?: because of binary numeric promotion, JLS 15.25 diff --git a/src/java.base/share/classes/java/text/DigitList.java b/src/java.base/share/classes/java/text/DigitList.java index 2895126f93b..ce098bd8800 100644 --- a/src/java.base/share/classes/java/text/DigitList.java +++ b/src/java.base/share/classes/java/text/DigitList.java @@ -46,6 +46,7 @@ import jdk.internal.access.SharedSecrets; import jdk.internal.math.FloatingDecimal; import jdk.internal.util.ArraysSupport; +import jdk.internal.vm.annotation.Stable; /** * Digit List. Private to DecimalFormat. @@ -108,7 +109,6 @@ final class DigitList implements Cloneable { public int count = 0; public byte[] digits = new byte[MAX_COUNT]; - private byte[] data; private RoundingMode roundingMode = RoundingMode.HALF_EVEN; private boolean isNegative = false; @@ -320,15 +320,18 @@ void set(boolean isNegative, double source, int maximumFractionDigits) { * fractional digits to be converted. If false, total digits. */ void set(boolean isNegative, double source, int maximumDigits, boolean fixedPoint) { + assert Double.isFinite(source); + FloatingDecimal.BinaryToASCIIConverter fdConverter = FloatingDecimal.getBinaryToASCIIConverter(source, COMPAT); boolean hasBeenRoundedUp = fdConverter.digitsRoundedUp(); boolean valueExactAsDecimal = fdConverter.decimalDigitsExact(); - assert !fdConverter.isExceptional(); - byte[] chars = getDataChars(26); - int len = fdConverter.getChars(chars); - set(isNegative, chars, len, + count = fdConverter.getDigits(digits); + + int exp = fdConverter.getDecimalExponent() - count; + + set(isNegative, exp, hasBeenRoundedUp, valueExactAsDecimal, maximumDigits, fixedPoint); } @@ -340,44 +343,18 @@ void set(boolean isNegative, double source, int maximumDigits, boolean fixedPoin * @param valueExactAsDecimal whether or not collected digits provide * an exact decimal representation of the value. */ - private void set(boolean isNegative, byte[] source, int len, + private void set(boolean isNegative, int exp, boolean roundedUp, boolean valueExactAsDecimal, int maximumDigits, boolean fixedPoint) { this.isNegative = isNegative; - decimalAt = -1; - count = 0; - int exponent = 0; - // Number of zeros between decimal point and first non-zero digit after - // decimal point, for numbers < 1. - int leadingZerosAfterDecimal = 0; - boolean nonZeroDigitSeen = false; - - for (int i = 0; i < len; ) { - byte c = source[i++]; - if (c == '.') { - decimalAt = count; - } else if (c == 'e' || c == 'E') { - exponent = parseInt(source, i, len); - break; - } else { - if (!nonZeroDigitSeen) { - nonZeroDigitSeen = (c != '0'); - if (!nonZeroDigitSeen && decimalAt != -1) - ++leadingZerosAfterDecimal; - } - if (nonZeroDigitSeen) { - digits[count++] = c; - } - } - } - if (decimalAt == -1) { - decimalAt = count; - } - if (nonZeroDigitSeen) { - decimalAt += exponent - leadingZerosAfterDecimal; + if (!nonZeroAfterIndex(0)) { + count = 0; + decimalAt = 0; + return; } + decimalAt = count + exp; if (fixedPoint) { // The negative of the exponent represents the number of leading @@ -669,13 +646,13 @@ void set(boolean isNegative, long source, int maximumDigits) { */ @SuppressWarnings("deprecation") void set(boolean isNegative, BigDecimal source, int maximumDigits, boolean fixedPoint) { - String s = source.toString(); - extendDigits(s.length()); - + String s = source.unscaledValue().toString(); int len = s.length(); - byte[] chars = getDataChars(len); - s.getBytes(0, len, chars, 0); - set(isNegative, chars, len, + + extendDigits(len); + s.getBytes(0, len, digits, 0); + count = len; + set(isNegative, -source.scale(), false, true, maximumDigits, fixedPoint); } @@ -745,14 +722,7 @@ public int hashCode() { public Object clone() { try { DigitList other = (DigitList) super.clone(); - byte[] newDigits = new byte[digits.length]; - System.arraycopy(digits, 0, newDigits, 0, digits.length); - other.digits = newDigits; - - // Data does not need to be copied because it does - // not carry significant information. It will be recreated on demand. - // Setting it to null is needed to avoid sharing across clones. - other.data = null; + other.digits = digits.clone(); return other; } catch (CloneNotSupportedException e) { @@ -760,29 +730,8 @@ public Object clone() { } } - private static int parseInt(byte[] str, int offset, int strLen) { - byte c; - boolean positive = true; - if ((c = str[offset]) == '-') { - positive = false; - offset++; - } else if (c == '+') { - offset++; - } - - int value = 0; - while (offset < strLen) { - c = str[offset++]; - if (c >= '0' && c <= '9') { - value = value * 10 + (c - '0'); - } else { - break; - } - } - return positive ? value : -value; - } - // The digit part of -9223372036854775808L + @Stable private static final byte[] LONG_MIN_REP = "9223372036854775808".getBytes(StandardCharsets.ISO_8859_1); public String toString() { @@ -798,11 +747,4 @@ private void extendDigits(int len) { digits = new byte[len]; } } - - private byte[] getDataChars(int length) { - if (data == null || data.length < length) { - data = new byte[length]; - } - return data; - } } diff --git a/src/java.base/share/classes/java/time/Duration.java b/src/java.base/share/classes/java/time/Duration.java index 88d49fa9e45..23577a8a634 100644 --- a/src/java.base/share/classes/java/time/Duration.java +++ b/src/java.base/share/classes/java/time/Duration.java @@ -172,7 +172,7 @@ private static class Lazy { * Obtains a {@code Duration} representing a number of standard 24 hour days. *

* The seconds are calculated based on the standard definition of a day, - * where each day is 86400 seconds which implies a 24 hour day. + * where each day is 86,400 seconds which implies a 24 hour day. * The nanosecond in second field is set to zero. * * @param days the number of days, positive or negative @@ -187,7 +187,7 @@ public static Duration ofDays(long days) { * Obtains a {@code Duration} representing a number of standard hours. *

* The seconds are calculated based on the standard definition of an hour, - * where each hour is 3600 seconds. + * where each hour is 3,600 seconds. * The nanosecond in second field is set to zero. * * @param hours the number of hours, positive or negative @@ -375,8 +375,8 @@ public static Duration from(TemporalAmount amount) { *

      *    "PT20.345S" -- parses as "20.345 seconds"
      *    "PT15M"     -- parses as "15 minutes" (where a minute is 60 seconds)
-     *    "PT10H"     -- parses as "10 hours" (where an hour is 3600 seconds)
-     *    "P2D"       -- parses as "2 days" (where a day is 24 hours or 86400 seconds)
+     *    "PT10H"     -- parses as "10 hours" (where an hour is 3,600 seconds)
+     *    "P2D"       -- parses as "2 days" (where a day is 24 hours or 86,400 seconds)
      *    "P2DT3H4M"  -- parses as "2 days, 3 hours and 4 minutes"
      *    "PT-6H3M"    -- parses as "-6 hours and +3 minutes"
      *    "-PT6H3M"    -- parses as "-6 hours and -3 minutes"
@@ -477,7 +477,7 @@ private static Duration create(boolean negate, long daysAsSecs, long hoursAsSecs
      * {@link ChronoField#NANO_OF_SECOND NANO_OF_SECOND} field should be supported.
      * 

* The result of this method can be a negative duration if the end is before the start. - * To guarantee to obtain a positive duration call {@link #abs()} on the result. + * To guarantee a positive duration, call {@link #abs()} on the result. * * @param startInclusive the start instant, inclusive, not null * @param endExclusive the end instant, exclusive, not null @@ -752,7 +752,7 @@ public Duration plus(long amountToAdd, TemporalUnit unit) { /** * Returns a copy of this duration with the specified duration in standard 24 hour days added. *

- * The number of days is multiplied by 86400 to obtain the number of seconds to add. + * The number of days is multiplied by 86,400 to obtain the number of seconds to add. * This is based on the standard definition of a day as 24 hours. *

* This instance is immutable and unaffected by this method call. @@ -893,7 +893,7 @@ public Duration minus(long amountToSubtract, TemporalUnit unit) { /** * Returns a copy of this duration with the specified duration in standard 24 hour days subtracted. *

- * The number of days is multiplied by 86400 to obtain the number of seconds to subtract. + * The number of days is multiplied by 86,400 to obtain the number of seconds to subtract. * This is based on the standard definition of a day as 24 hours. *

* This instance is immutable and unaffected by this method call. @@ -909,7 +909,7 @@ public Duration minusDays(long daysToSubtract) { /** * Returns a copy of this duration with the specified duration in hours subtracted. *

- * The number of hours is multiplied by 3600 to obtain the number of seconds to subtract. + * The number of hours is multiplied by 3,600 to obtain the number of seconds to subtract. *

* This instance is immutable and unaffected by this method call. * @@ -924,7 +924,7 @@ public Duration minusHours(long hoursToSubtract) { /** * Returns a copy of this duration with the specified duration in minutes subtracted. *

- * The number of hours is multiplied by 60 to obtain the number of seconds to subtract. + * The number of minutes is multiplied by 60 to obtain the number of seconds to subtract. *

* This instance is immutable and unaffected by this method call. * @@ -1165,7 +1165,7 @@ public Temporal subtractFrom(Temporal temporal) { * Gets the number of days in this duration. *

* This returns the total number of days in the duration by dividing the - * number of seconds by 86400. + * number of seconds by 86,400. * This is based on the standard definition of a day as 24 hours. *

* This instance is immutable and unaffected by this method call. @@ -1180,7 +1180,7 @@ public long toDays() { * Gets the number of hours in this duration. *

* This returns the total number of hours in the duration by dividing the - * number of seconds by 3600. + * number of seconds by 3,600. *

* This instance is immutable and unaffected by this method call. * @@ -1272,7 +1272,7 @@ public long toNanos() { * Extracts the number of days in the duration. *

* This returns the total number of days in the duration by dividing the - * number of seconds by 86400. + * number of seconds by 86,400. * This is based on the standard definition of a day as 24 hours. *

* This instance is immutable and unaffected by this method call. @@ -1476,10 +1476,10 @@ public int hashCode() { *

* Examples: *

-     *    "20.345 seconds"                 -- "PT20.345S
+     *    "20.345 seconds"                 -- "PT20.345S"
      *    "15 minutes" (15 * 60 seconds)   -- "PT15M"
-     *    "10 hours" (10 * 3600 seconds)   -- "PT10H"
-     *    "2 days" (2 * 86400 seconds)     -- "PT48H"
+     *    "10 hours" (10 * 3,600 seconds)  -- "PT10H"
+     *    "2 days" (2 * 86,400 seconds)    -- "PT48H"
      * 
* Note that multiples of 24 hours are not output as days to avoid confusion * with {@code Period}. diff --git a/src/java.base/share/classes/java/time/Instant.java b/src/java.base/share/classes/java/time/Instant.java index 1c7a41d7f0e..db8db4aaa38 100644 --- a/src/java.base/share/classes/java/time/Instant.java +++ b/src/java.base/share/classes/java/time/Instant.java @@ -114,15 +114,15 @@ *

* The length of the solar day is the standard way that humans measure time. * This has traditionally been subdivided into 24 hours of 60 minutes of 60 seconds, - * forming a 86400 second day. + * forming an 86,400 second day. *

* Modern timekeeping is based on atomic clocks which precisely define an SI second * relative to the transitions of a Caesium atom. The length of an SI second was defined - * to be very close to the 86400th fraction of a day. + * to be very close to the 86,400th fraction of a day. *

* Unfortunately, as the Earth rotates the length of the day varies. * In addition, over time the average length of the day is getting longer as the Earth slows. - * As a result, the length of a solar day in 2012 is slightly longer than 86400 SI seconds. + * As a result, the length of a solar day in 2012 is slightly longer than 86,400 SI seconds. * The actual length of any given day and the amount by which the Earth is slowing * are not predictable and can only be determined by measurement. * The UT1 time-scale captures the accurate length of day, but is only available some @@ -131,7 +131,7 @@ * The UTC time-scale is a standard approach to bundle up all the additional fractions * of a second from UT1 into whole seconds, known as leap-seconds. * A leap-second may be added or removed depending on the Earth's rotational changes. - * As such, UTC permits a day to have 86399 SI seconds or 86401 SI seconds where + * As such, UTC permits a day to have 86,399 SI seconds or 86,401 SI seconds where * necessary in order to keep the day aligned with the Sun. *

* The modern UTC time-scale was introduced in 1972, introducing the concept of whole leap-seconds. @@ -143,7 +143,7 @@ * Given the complexity of accurate timekeeping described above, this Java API defines * its own time-scale, the Java Time-Scale. *

- * The Java Time-Scale divides each calendar day into exactly 86400 + * The Java Time-Scale divides each calendar day into exactly 86,400 * subdivisions, known as seconds. These seconds may differ from the * SI second. It closely matches the de facto international civil time * scale, the definition of which changes from time to time. @@ -171,7 +171,7 @@ * This is identical to UTC on days that do not have a leap second. * On days that do have a leap second, the leap second is spread equally * over the last 1000 seconds of the day, maintaining the appearance of - * exactly 86400 seconds per day. + * exactly 86,400 seconds per day. *

* For the segment prior to 1972-11-03, extending back arbitrarily far, * the consensus international time scale is defined to be UT1, applied diff --git a/src/java.base/share/classes/java/time/Period.java b/src/java.base/share/classes/java/time/Period.java index 5ee80710edb..745714788c3 100644 --- a/src/java.base/share/classes/java/time/Period.java +++ b/src/java.base/share/classes/java/time/Period.java @@ -765,7 +765,7 @@ public Period minusMonths(long monthsToSubtract) { *

* This instance is immutable and unaffected by this method call. * - * @param daysToSubtract the months to subtract, positive or negative + * @param daysToSubtract the days to subtract, positive or negative * @return a {@code Period} based on this period with the specified days subtracted, not null * @throws ArithmeticException if numeric overflow occurs */ diff --git a/src/java.base/share/classes/java/time/ZoneOffset.java b/src/java.base/share/classes/java/time/ZoneOffset.java index d93c6e2d46d..4199d17735c 100644 --- a/src/java.base/share/classes/java/time/ZoneOffset.java +++ b/src/java.base/share/classes/java/time/ZoneOffset.java @@ -417,9 +417,9 @@ private static int totalSeconds(int hours, int minutes, int seconds) { /** * Obtains an instance of {@code ZoneOffset} specifying the total offset in seconds *

- * The offset must be in the range {@code -18:00} to {@code +18:00}, which corresponds to -64800 to +64800. + * The offset must be in the range {@code -18:00} to {@code +18:00}, which corresponds to -64,800 to +64,800. * - * @param totalSeconds the total time-zone offset in seconds, from -64800 to +64800 + * @param totalSeconds the total time-zone offset in seconds, from -64,800 to +64,800 * @return the ZoneOffset, not null * @throws DateTimeException if the offset is not in the required range */ @@ -450,7 +450,7 @@ public static ZoneOffset ofTotalSeconds(int totalSeconds) { /** * Constructor. * - * @param totalSeconds the total time-zone offset in seconds, from -64800 to +64800 + * @param totalSeconds the total time-zone offset in seconds, from -64,800 to +64,800 */ private ZoneOffset(int totalSeconds) { this.totalSeconds = totalSeconds; diff --git a/src/java.base/share/classes/java/time/ZonedDateTime.java b/src/java.base/share/classes/java/time/ZonedDateTime.java index 962469b3225..57dc98d5c68 100644 --- a/src/java.base/share/classes/java/time/ZonedDateTime.java +++ b/src/java.base/share/classes/java/time/ZonedDateTime.java @@ -136,7 +136,7 @@ * For Overlaps, the general strategy is that if the local date-time falls in the * middle of an Overlap, then the previous offset will be retained. If there is no * previous offset, or the previous offset is invalid, then the earlier offset is - * used, typically "summer" time.. Two additional methods, + * used, typically "summer" time. Two additional methods, * {@link #withEarlierOffsetAtOverlap()} and {@link #withLaterOffsetAtOverlap()}, * help manage the case of an overlap. *

@@ -246,7 +246,7 @@ public static ZonedDateTime now(Clock clock) { * Time-zone rules, such as daylight savings, mean that not every local date-time * is valid for the specified zone, thus the local date-time may be adjusted. *

- * The local date time and first combined to form a local date-time. + * The local date and time are first combined to form a local date-time. * The local date-time is then resolved to a single instant on the time-line. * This is achieved by finding a valid offset from UTC/Greenwich for the local * date-time as defined by the {@link ZoneRules rules} of the zone ID. @@ -263,7 +263,7 @@ public static ZonedDateTime now(Clock clock) { * @param date the local date, not null * @param time the local time, not null * @param zone the time-zone, not null - * @return the offset date-time, not null + * @return the zoned date-time, not null */ public static ZonedDateTime of(LocalDate date, LocalTime time, ZoneId zone) { return of(LocalDateTime.of(date, time), zone); @@ -333,7 +333,7 @@ public static ZonedDateTime of(LocalDateTime localDateTime, ZoneId zone) { * @param second the second-of-minute to represent, from 0 to 59 * @param nanoOfSecond the nano-of-second to represent, from 0 to 999,999,999 * @param zone the time-zone, not null - * @return the offset date-time, not null + * @return the zoned date-time, not null * @throws DateTimeException if the value of any field is out of range, or * if the day-of-month is invalid for the month-year */ diff --git a/src/java.base/share/classes/java/time/package-info.java b/src/java.base/share/classes/java/time/package-info.java index 8a4fbe44d8b..d0fb7a6c2bc 100644 --- a/src/java.base/share/classes/java/time/package-info.java +++ b/src/java.base/share/classes/java/time/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2022, 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 @@ -65,7 +65,7 @@ * The main API for dates, times, instants, and durations. *

*

- * The classes defined here represent the principle date-time concepts, + * The classes defined here represent the principal date-time concepts, * including instants, durations, dates, times, time-zones and periods. * They are based on the ISO calendar system, which is the de facto world * calendar following the proleptic Gregorian rules. @@ -150,7 +150,7 @@ *

*

* {@link java.time.OffsetTime} stores a time and offset from UTC without a date. - * This stores a date like '11:30+01:00'. + * This stores a time like '11:30+01:00'. * The {@link java.time.ZoneOffset ZoneOffset} is of the form '+01:00'. *

*

@@ -249,7 +249,7 @@ *

* Multiple calendar systems is an awkward addition to the design challenges. * The first principle is that most users want the standard ISO calendar system. - * As such, the main classes are ISO-only. The second principle is that most of those that want a + * As such, the main classes are ISO-only. The second principle is that most of those who want a * non-ISO calendar system want it for user interaction, thus it is a UI localization issue. * As such, date and time objects should be held as ISO objects in the data model and persistent * storage, only being converted to and from a local calendar for display. diff --git a/src/java.base/share/classes/java/time/temporal/ChronoField.java b/src/java.base/share/classes/java/time/temporal/ChronoField.java index 9e5de367b0e..506737ff268 100644 --- a/src/java.base/share/classes/java/time/temporal/ChronoField.java +++ b/src/java.base/share/classes/java/time/temporal/ChronoField.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2024, 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 @@ -599,7 +599,7 @@ public enum ChronoField implements TemporalField { * A {@link ZoneOffset} represents the period of time that local time differs from UTC/Greenwich. * This is usually a fixed number of hours and minutes. * It is equivalent to the {@link ZoneOffset#getTotalSeconds() total amount} of the offset in seconds. - * For example, during the winter Paris has an offset of {@code +01:00}, which is 3600 seconds. + * For example, during the winter, Paris has an offset of {@code +01:00}, which is 3,600 seconds. *

* This field is strictly defined to have the same meaning in all calendar systems. * This is necessary to ensure interoperation between calendars. diff --git a/src/java.base/share/classes/java/time/temporal/ValueRange.java b/src/java.base/share/classes/java/time/temporal/ValueRange.java index 442cf0a2509..27e71e77d66 100644 --- a/src/java.base/share/classes/java/time/temporal/ValueRange.java +++ b/src/java.base/share/classes/java/time/temporal/ValueRange.java @@ -78,7 +78,7 @@ * Only the minimum and maximum values are provided. * It is possible for there to be invalid values within the outer range. * For example, a weird field may have valid values of 1, 2, 4, 6, 7, thus - * have a range of '1 - 7', despite that fact that values 3 and 5 are invalid. + * have a range of '1 - 7', despite the fact that values 3 and 5 are invalid. *

* Instances of this class are not tied to a specific field. * diff --git a/src/java.base/share/classes/javax/crypto/Cipher.java b/src/java.base/share/classes/javax/crypto/Cipher.java index 902c3998fbe..b22b8cf5483 100644 --- a/src/java.base/share/classes/javax/crypto/Cipher.java +++ b/src/java.base/share/classes/javax/crypto/Cipher.java @@ -515,12 +515,12 @@ private static Transform getTransform(Service s, * transformation * * @throws NoSuchAlgorithmException if {@code transformation} - * is {@code null}, empty, in an invalid format, - * or if no provider supports a {@code CipherSpi} - * implementation for the specified algorithm + * is {@code null}, empty or in an invalid format; + * or if a {@code CipherSpi} implementation is not found or + * is found but does not support the mode * - * @throws NoSuchPaddingException if {@code transformation} - * contains a padding scheme that is not available + * @throws NoSuchPaddingException if a {@code CipherSpi} implementation + * is found but does not support the padding scheme * * @see java.security.Provider */ @@ -573,8 +573,12 @@ public static final Cipher getInstance(String transformation) failure = e; } } + if (failure instanceof NoSuchPaddingException nspe) { + throw nspe; + } throw new NoSuchAlgorithmException - ("Cannot find any provider supporting " + transformation, failure); + ("Cannot find any provider supporting " + transformation, + failure); } /** @@ -582,8 +586,8 @@ public static final Cipher getInstance(String transformation) * transformation. * *

A new {@code Cipher} object encapsulating the - * {@code CipherSpi} implementation from the specified provider - * is returned. The specified provider must be registered + * {@code CipherSpi} implementation from the specified {@code provider} + * is returned. The specified {@code provider} must be registered * in the security provider list. * *

Note that the list of registered providers may be retrieved via @@ -625,15 +629,16 @@ public static final Cipher getInstance(String transformation) * is {@code null} or empty * * @throws NoSuchAlgorithmException if {@code transformation} - * is {@code null}, empty, in an invalid format, - * or if a {@code CipherSpi} implementation for the - * specified algorithm is not available from the specified - * provider + * is {@code null}, empty or in an invalid format; + * or if a {@code CipherSpi} implementation from the specified + * {@code provider} is not found or is found but does not support + * the mode * - * @throws NoSuchPaddingException if {@code transformation} - * contains a padding scheme that is not available + * @throws NoSuchPaddingException if a {@code CipherSpi} implementation + * from the specified {@code provider} is found but does not + * support the padding scheme * - * @throws NoSuchProviderException if the specified provider is not + * @throws NoSuchProviderException if the specified {@code provider} is not * registered in the security provider list * * @see java.security.Provider @@ -706,13 +711,14 @@ private String getProviderName() { * is {@code null} * * @throws NoSuchAlgorithmException if {@code transformation} - * is {@code null}, empty, in an invalid format, - * or if a {@code CipherSpi} implementation for the - * specified algorithm is not available from the specified - * {@code provider} object - * - * @throws NoSuchPaddingException if {@code transformation} - * contains a padding scheme that is not available + * is {@code null}, empty or in an invalid format; + * or if a {@code CipherSpi} implementation from the specified + * {@code provider} is not found or is found but does not support + * the mode + * + * @throws NoSuchPaddingException if a {@code CipherSpi} implementation + * from the specified {@code provider} is found but does not + * support the padding scheme * * @see java.security.Provider */ 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 32399310bd3..e90ca4d75f1 100644 --- a/src/java.base/share/classes/jdk/internal/math/FloatingDecimal.java +++ b/src/java.base/share/classes/jdk/internal/math/FloatingDecimal.java @@ -27,8 +27,6 @@ import jdk.internal.vm.annotation.Stable; -import java.util.Arrays; - /** * A class for converting between ASCII and decimal representations of a single * or double precision floating point number. Most conversions are provided via @@ -102,7 +100,6 @@ public static double parseDoubleSignlessDigits(int decExp, byte[] digits, int le * values into an ASCII String representation. */ public interface BinaryToASCIIConverter { - int getChars(byte[] result); /** * Retrieves the decimal exponent most closely corresponding to this value. @@ -115,21 +112,7 @@ public interface BinaryToASCIIConverter { * @param digits The digit array. * @return The number of valid digits copied into the array. */ - int getDigits(char[] digits); - - /** - * Indicates the sign of the value. - * @return {@code value < 0.0}. - */ - boolean isNegative(); - - /** - * Indicates whether the value is either infinite or not a number. - * - * @return true if and only if the value is NaN - * or infinite. - */ - boolean isExceptional(); + int getDigits(byte[] digits); /** * Indicates whether the value was rounded up during the binary to ASCII @@ -147,63 +130,9 @@ public interface BinaryToASCIIConverter { boolean decimalDigitsExact(); } - /** - * A BinaryToASCIIConverter which represents NaN - * and infinite values. - */ - private static class ExceptionalBinaryToASCIIBuffer implements BinaryToASCIIConverter { - private final String image; - private final boolean isNegative; - - public ExceptionalBinaryToASCIIBuffer(String image, boolean isNegative) { - this.image = image; - this.isNegative = isNegative; - } - - @Override - @SuppressWarnings("deprecation") - public int getChars(byte[] chars) { - image.getBytes(0, image.length(), chars, 0); - return image.length(); - } - - @Override - public int getDecimalExponent() { - throw new IllegalArgumentException("Exceptional value does not have an exponent"); - } - - @Override - public int getDigits(char[] digits) { - throw new IllegalArgumentException("Exceptional value does not have digits"); - } - - @Override - public boolean isNegative() { - return isNegative; - } - - @Override - public boolean isExceptional() { - return true; - } - - @Override - public boolean digitsRoundedUp() { - throw new IllegalArgumentException("Exceptional value is not rounded"); - } - - @Override - public boolean decimalDigitsExact() { - throw new IllegalArgumentException("Exceptional value is not exact"); - } - } - private static final String INFINITY_REP = "Infinity"; private static final String NAN_REP = "NaN"; - 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 byte[]{'0'}); private static final BinaryToASCIIConverter B2AC_NEGATIVE_ZERO = new BinaryToASCIIBuffer(true, new byte[]{'0'}); @@ -255,21 +184,11 @@ public int getDecimalExponent() { } @Override - public int getDigits(char[] digits) { + public int getDigits(byte[] digits) { System.arraycopy(this.digits, firstDigitIndex, digits, 0, this.nDigits); return this.nDigits; } - @Override - public boolean isNegative() { - return isNegative; - } - - @Override - public boolean isExceptional() { - return false; - } - @Override public boolean digitsRoundedUp() { return decimalDigitsRoundedUp; @@ -826,83 +745,6 @@ private static int insignificantDigitsForPow2(int p2) { 61, }; - /** - * 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) { - result[0] = '-'; - i = 1; - } - if (decExponent > 0 && decExponent < 8) { - // print digits.digits. - int charLength = Math.min(nDigits, decExponent); - System.arraycopy(digits, firstDigitIndex, result, i, charLength); - i += charLength; - if (charLength < decExponent) { - charLength = decExponent - charLength; - Arrays.fill(result, i, i + charLength, (byte) '0'); - i += charLength; - result[i++] = '.'; - result[i++] = '0'; - } else { - result[i++] = '.'; - if (charLength < nDigits) { - int t = nDigits - charLength; - System.arraycopy(digits, firstDigitIndex + charLength, result, i, t); - i += t; - } else { - result[i++] = '0'; - } - } - } else if (decExponent <= 0 && decExponent > -3) { - result[i++] = '0'; - result[i++] = '.'; - if (decExponent != 0) { - Arrays.fill(result, i, i-decExponent, (byte) '0'); - i -= decExponent; - } - System.arraycopy(digits, firstDigitIndex, result, i, nDigits); - i += nDigits; - } else { - result[i++] = digits[firstDigitIndex]; - result[i++] = '.'; - if (nDigits > 1) { - System.arraycopy(digits, firstDigitIndex+1, result, i, nDigits - 1); - i += nDigits - 1; - } else { - result[i++] = '0'; - } - result[i++] = 'E'; - int e; - if (decExponent <= 0) { - result[i++] = '-'; - e = -decExponent + 1; - } else { - e = decExponent - 1; - } - // decExponent has 1, 2, or 3, digits - if (e <= 9) { - result[i++] = (byte) (e + '0'); - } else if (e <= 99) { - result[i++] = (byte) (e / 10 + '0'); - result[i++] = (byte) (e % 10 + '0'); - } else { - result[i++] = (byte) (e / 100 + '0'); - e %= 100; - result[i++] = (byte) (e / 10 + '0'); - result[i++] = (byte) (e % 10 + '0'); - } - } - return i; - } - } private static final ThreadLocal threadLocalBinaryToASCIIBuffer = @@ -1707,9 +1549,9 @@ private static BinaryToASCIIConverter getCompatBinaryToASCIIConverter(double d, // Discover obvious special cases of NaN and Infinity. if ( binExp == (int)(DoubleConsts.EXP_BIT_MASK>>EXP_SHIFT) ) { if ( fractBits == 0L ){ - return isNegative ? B2AC_NEGATIVE_INFINITY : B2AC_POSITIVE_INFINITY; + throw new IllegalArgumentException((isNegative ? "-" : "") + INFINITY_REP); } else { - return B2AC_NOT_A_NUMBER; + throw new IllegalArgumentException(NAN_REP); } } // Finish unpacking diff --git a/src/java.base/share/classes/jdk/internal/vm/ThreadDumper.java b/src/java.base/share/classes/jdk/internal/vm/ThreadDumper.java index a26003a3afb..276c379a564 100644 --- a/src/java.base/share/classes/jdk/internal/vm/ThreadDumper.java +++ b/src/java.base/share/classes/jdk/internal/vm/ThreadDumper.java @@ -205,7 +205,10 @@ private static boolean dumpThread(Thread thread, TextWriter writer) { // park blocker Object parkBlocker = snapshot.parkBlocker(); if (parkBlocker != null) { - writer.println(" - parking to wait for " + decorateObject(parkBlocker)); + String suffix = (snapshot.parkBlockerOwner() instanceof Thread owner) + ? ", owner #" + owner.threadId() + : ""; + writer.println(" - parking to wait for " + decorateObject(parkBlocker) + suffix); } // blocked on monitor enter or Object.wait @@ -335,6 +338,9 @@ private static boolean dumpThread(Thread thread, JsonWriter jsonWriter) { // parkBlocker is an object to allow for exclusiveOwnerThread in the future jsonWriter.startObject("parkBlocker"); jsonWriter.writeProperty("object", Objects.toIdentityString(parkBlocker)); + if (snapshot.parkBlockerOwner() instanceof Thread owner) { + jsonWriter.writeProperty("owner", owner.threadId()); + } jsonWriter.endObject(); } diff --git a/src/java.base/share/classes/jdk/internal/vm/ThreadSnapshot.java b/src/java.base/share/classes/jdk/internal/vm/ThreadSnapshot.java index 4fcbaf24d2e..357d38008d1 100644 --- a/src/java.base/share/classes/jdk/internal/vm/ThreadSnapshot.java +++ b/src/java.base/share/classes/jdk/internal/vm/ThreadSnapshot.java @@ -44,6 +44,8 @@ class ThreadSnapshot { // an object the thread is blocked/waiting on, converted to ThreadBlocker by ThreadSnapshot.of() private int blockerTypeOrdinal; private Object blockerObject; + // the owner of the blockerObject when the object is park blocker and is AbstractOwnableSynchronizer + private Thread parkBlockerOwner; // set by ThreadSnapshot.of() private ThreadBlocker blocker; @@ -70,8 +72,11 @@ static ThreadSnapshot of(Thread thread) { snapshot.locks = EMPTY_LOCKS; } if (snapshot.blockerObject != null) { - snapshot.blocker = new ThreadBlocker(snapshot.blockerTypeOrdinal, snapshot.blockerObject); + snapshot.blocker = new ThreadBlocker(snapshot.blockerTypeOrdinal, + snapshot.blockerObject, + snapshot.parkBlockerOwner); snapshot.blockerObject = null; // release + snapshot.parkBlockerOwner = null; } return snapshot; } @@ -104,6 +109,13 @@ Object parkBlocker() { return getBlocker(BlockerLockType.PARK_BLOCKER); } + /** + * Returns the owner of the parkBlocker if the parkBlocker is an AbstractOwnableSynchronizer. + */ + Thread parkBlockerOwner() { + return (blocker != null && blocker.type == BlockerLockType.PARK_BLOCKER) ? blocker.owner : null; + } + /** * Returns the object that the thread is blocked on. * @throws IllegalStateException if not in the blocked state @@ -211,11 +223,11 @@ Object lockObject() { } } - private record ThreadBlocker(BlockerLockType type, Object obj) { + private record ThreadBlocker(BlockerLockType type, Object obj, Thread owner) { private static final BlockerLockType[] lockTypeValues = BlockerLockType.values(); // cache - ThreadBlocker(int typeOrdinal, Object obj) { - this(lockTypeValues[typeOrdinal], obj); + ThreadBlocker(int typeOrdinal, Object obj, Thread owner) { + this(lockTypeValues[typeOrdinal], obj, owner); } } diff --git a/src/java.base/share/classes/sun/invoke/util/BytecodeDescriptor.java b/src/java.base/share/classes/sun/invoke/util/BytecodeDescriptor.java index 76bbff2a610..bd5ea6d7635 100644 --- a/src/java.base/share/classes/sun/invoke/util/BytecodeDescriptor.java +++ b/src/java.base/share/classes/sun/invoke/util/BytecodeDescriptor.java @@ -37,12 +37,33 @@ public class BytecodeDescriptor { private BytecodeDescriptor() { } // cannot instantiate - /** - * @param loader the class loader in which to look up the types (null means - * bootstrap class loader) - */ - public static List> parseMethod(String bytecodeSignature, ClassLoader loader) { - return parseMethod(bytecodeSignature, 0, bytecodeSignature.length(), loader); + /// Parses and validates a field descriptor string in the {@code loader} context. + /// + /// @param descriptor a field descriptor string + /// @param loader the class loader in which to look up the types (null means + /// bootstrap class loader) + /// @throws IllegalArgumentException if the descriptor is invalid + /// @throws TypeNotPresentException if the descriptor is valid, but + /// the class cannot be found by the loader + public static Class parseClass(String descriptor, ClassLoader loader) { + int[] i = {0}; + var ret = parseSig(descriptor, i, descriptor.length(), loader); + if (i[0] != descriptor.length() || ret == null) { + parseError("not a class descriptor", descriptor); + } + return ret; + } + + /// Parses and validates a method descriptor string in the {@code loader} context. + /// + /// @param descriptor a method descriptor string + /// @param loader the class loader in which to look up the types (null means + /// bootstrap class loader) + /// @throws IllegalArgumentException if the descriptor is invalid + /// @throws TypeNotPresentException if a reference type cannot be found by + /// the loader (before the descriptor is found invalid) + public static List> parseMethod(String descriptor, ClassLoader loader) { + return parseMethod(descriptor, 0, descriptor.length(), loader); } /** @@ -77,10 +98,19 @@ private static void parseError(String str, String msg) { throw new IllegalArgumentException("bad signature: "+str+": "+msg); } - /** - * @param loader the class loader in which to look up the types (null means - * bootstrap class loader) - */ + /// Parse a single type in a descriptor. Results can be: + /// + /// - A `Class` for successful parsing + /// - `null` for malformed descriptor format + /// - Throwing a [TypeNotPresentException] for valid class name, + /// but class cannot be found + /// + /// @param str contains the string to parse + /// @param i cursor for the next token in the string, modified in-place + /// @param end the limit for parsing + /// @param loader the class loader in which to look up the types (null means + /// bootstrap class loader) + /// private static Class parseSig(String str, int[] i, int end, ClassLoader loader) { if (i[0] == end) return null; char c = str.charAt(i[0]++); @@ -107,7 +137,14 @@ private static Class parseSig(String str, int[] i, int end, ClassLoader loade } return t; } else { - return Wrapper.forBasicType(c).primitiveType(); + Wrapper w; + try { + w = Wrapper.forBasicType(c); + } catch (IllegalArgumentException ex) { + // Our reporting has better error message + return null; + } + return w.primitiveType(); } } diff --git a/src/java.base/share/classes/sun/reflect/annotation/AnnotationParser.java b/src/java.base/share/classes/sun/reflect/annotation/AnnotationParser.java index 82751e3fcd2..74ed1e01553 100644 --- a/src/java.base/share/classes/sun/reflect/annotation/AnnotationParser.java +++ b/src/java.base/share/classes/sun/reflect/annotation/AnnotationParser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -34,12 +34,7 @@ import jdk.internal.reflect.ConstantPool; -import sun.reflect.generics.parser.SignatureParser; -import sun.reflect.generics.tree.TypeSignature; -import sun.reflect.generics.factory.GenericsFactory; -import sun.reflect.generics.factory.CoreReflectionFactory; -import sun.reflect.generics.visitor.Reifier; -import sun.reflect.generics.scope.ClassScope; +import sun.invoke.util.BytecodeDescriptor; /** * Parser for Java programming language annotations. Translates @@ -429,19 +424,11 @@ private static Object parseClassValue(ByteBuffer buf, } private static Class parseSig(String sig, Class container) { - if (sig.equals("V")) return void.class; - SignatureParser parser = SignatureParser.make(); - TypeSignature typeSig = parser.parseTypeSig(sig); - GenericsFactory factory = CoreReflectionFactory.make(container, ClassScope.make(container)); - Reifier reify = Reifier.make(factory); - typeSig.accept(reify); - Type result = reify.getResult(); - return toClass(result); - } - static Class toClass(Type o) { - if (o instanceof GenericArrayType gat) - return toClass(gat.getGenericComponentType()).arrayType(); - return (Class) o; + try { + return BytecodeDescriptor.parseClass(sig, container.getClassLoader()); + } catch (IllegalArgumentException ex) { + throw new GenericSignatureFormatError(ex.getMessage()); + } } /** diff --git a/src/java.base/share/classes/sun/security/ssl/Alert.java b/src/java.base/share/classes/sun/security/ssl/Alert.java index 960b3f3b37d..ed5e079bf44 100644 --- a/src/java.base/share/classes/sun/security/ssl/Alert.java +++ b/src/java.base/share/classes/sun/security/ssl/Alert.java @@ -181,6 +181,16 @@ private static final class AlertMessage { AlertMessage(TransportContext context, ByteBuffer m) throws IOException { + // From RFC 8446 "Implementations + // MUST NOT send Handshake and Alert records that have a zero-length + // TLSInnerPlaintext.content; if such a message is received, the + // receiving implementation MUST terminate the connection with an + // "unexpected_message" alert." + if (m.remaining() == 0) { + throw context.fatal(Alert.UNEXPECTED_MESSAGE, + "Alert fragments must not be zero length."); + } + // struct { // AlertLevel level; // AlertDescription description; diff --git a/src/java.base/share/classes/sun/security/ssl/CertSignAlgsExtension.java b/src/java.base/share/classes/sun/security/ssl/CertSignAlgsExtension.java index b975290d09d..2125a148162 100644 --- a/src/java.base/share/classes/sun/security/ssl/CertSignAlgsExtension.java +++ b/src/java.base/share/classes/sun/security/ssl/CertSignAlgsExtension.java @@ -36,6 +36,11 @@ /** * Pack of the "signature_algorithms_cert" extensions. + *

+ * Note: Per RFC 8446, if no "signature_algorithms_cert" extension is + * present, then the "signature_algorithms" extension also applies to + * signatures appearing in certificates. + * See {@code SignatureAlgorithmsExtension} for details. */ final class CertSignAlgsExtension { static final HandshakeProducer chNetworkProducer = diff --git a/src/java.base/share/classes/sun/security/ssl/DTLSInputRecord.java b/src/java.base/share/classes/sun/security/ssl/DTLSInputRecord.java index e0196f3009c..101a42a5407 100644 --- a/src/java.base/share/classes/sun/security/ssl/DTLSInputRecord.java +++ b/src/java.base/share/classes/sun/security/ssl/DTLSInputRecord.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 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 @@ -801,8 +801,11 @@ void queueUpHandshake(HandshakeFragment hsf) throws SSLProtocolException { // buffer this fragment if (hsf.handshakeType == SSLHandshake.FINISHED.id) { - // Need no status update. - bufferedFragments.add(hsf); + // Make sure it's not a retransmitted message + if (hsf.recordEpoch > handshakeEpoch) { + bufferedFragments.add(hsf); + flightIsReady = holes.isEmpty(); + } } else { bufferFragment(hsf); } diff --git a/src/java.base/share/classes/sun/security/ssl/SSLCipher.java b/src/java.base/share/classes/sun/security/ssl/SSLCipher.java index d11ffc96b47..4a52a2ea583 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLCipher.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLCipher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, 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 @@ -1923,9 +1923,9 @@ public Plaintext decrypt(byte contentType, ByteBuffer bb, // remove inner plaintext padding int i = pt.limit() - 1; - for (; i > 0 && pt.get(i) == 0; i--); + for (; i >= pos && pt.get(i) == 0; i--); - if (i < (pos + 1)) { + if (i < pos) { throw new BadPaddingException( "Incorrect inner plaintext: no content type"); } @@ -2441,10 +2441,9 @@ public Plaintext decrypt(byte contentType, ByteBuffer bb, // remove inner plaintext padding int i = pt.limit() - 1; - for (; i > 0 && pt.get(i) == 0; i--) { - // blank - } - if (i < (pos + 1)) { + for (; i >= pos && pt.get(i) == 0; i--); + + if (i < pos) { throw new BadPaddingException( "Incorrect inner plaintext: no content type"); } diff --git a/src/java.base/share/classes/sun/security/ssl/SessionTicketExtension.java b/src/java.base/share/classes/sun/security/ssl/SessionTicketExtension.java index c0d2bea77ca..444af5d6dae 100644 --- a/src/java.base/share/classes/sun/security/ssl/SessionTicketExtension.java +++ b/src/java.base/share/classes/sun/security/ssl/SessionTicketExtension.java @@ -278,8 +278,10 @@ ByteBuffer decrypt(HandshakeContext hc) { aad.putInt(keyID).put(compressed); c.updateAAD(aad); + // use getOutputSize to avoid a ShortBufferException + // from providers that require oversized buffers. See JDK-8368514. ByteBuffer out = ByteBuffer.allocate( - data.remaining() - GCM_TAG_LEN / 8); + c.getOutputSize(data.remaining())); c.doFinal(data, out); out.flip(); @@ -291,7 +293,7 @@ ByteBuffer decrypt(HandshakeContext hc) { return out; } catch (Exception e) { if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { - SSLLogger.fine("Decryption failed." + e.getMessage()); + SSLLogger.fine("Decryption failed." + e); } } diff --git a/src/java.base/share/classes/sun/security/ssl/SignatureAlgorithmsExtension.java b/src/java.base/share/classes/sun/security/ssl/SignatureAlgorithmsExtension.java index a95b31583bb..b298da05e9a 100644 --- a/src/java.base/share/classes/sun/security/ssl/SignatureAlgorithmsExtension.java +++ b/src/java.base/share/classes/sun/security/ssl/SignatureAlgorithmsExtension.java @@ -31,6 +31,7 @@ import java.io.IOException; import java.nio.ByteBuffer; import java.text.MessageFormat; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Locale; @@ -191,21 +192,9 @@ public byte[] produce(ConnectionContext context, // Produce the extension. SignatureScheme.updateHandshakeLocalSupportedAlgs(chc); - int vectorLen = SignatureScheme.sizeInRecord() * - chc.localSupportedSignAlgs.size(); - byte[] extData = new byte[vectorLen + 2]; - ByteBuffer m = ByteBuffer.wrap(extData); - Record.putInt16(m, vectorLen); - for (SignatureScheme ss : chc.localSupportedSignAlgs) { - Record.putInt16(m, ss.id); - } - - // Update the context. - chc.handshakeExtensions.put( + return produceNetworkLoad(chc, SSLExtension.CH_SIGNATURE_ALGORITHMS, - new SignatureSchemesSpec(chc.localSupportedSignAlgs)); - - return extData; + SSLExtension.CH_SIGNATURE_ALGORITHMS_CERT); } } @@ -391,23 +380,11 @@ public byte[] produce(ConnectionContext context, } // Produce the extension. - // localSupportedSignAlgs has been already updated when we - // set the negotiated protocol. - int vectorLen = SignatureScheme.sizeInRecord() - * shc.localSupportedSignAlgs.size(); - byte[] extData = new byte[vectorLen + 2]; - ByteBuffer m = ByteBuffer.wrap(extData); - Record.putInt16(m, vectorLen); - for (SignatureScheme ss : shc.localSupportedSignAlgs) { - Record.putInt16(m, ss.id); - } - - // Update the context. - shc.handshakeExtensions.put( + // localSupportedSignAlgs and localSupportedCertSignAlgs have been + // already updated when we set the negotiated protocol. + return produceNetworkLoad(shc, SSLExtension.CR_SIGNATURE_ALGORITHMS, - new SignatureSchemesSpec(shc.localSupportedSignAlgs)); - - return extData; + SSLExtension.CR_SIGNATURE_ALGORITHMS_CERT); } } @@ -546,4 +523,45 @@ private static void updateHandshakeContext(HandshakeContext hc, hc.handshakeSession.setPeerSupportedSignatureAlgorithms(certSS); } } + + /** + * Produce network load and update context. + * + * @param hc HandshakeContext + * @param signatureAlgorithmsExt "signature_algorithms" extension + * @param signatureAlgorithmsCertExt "signature_algorithms_cert" + * extension + * @return network load as byte array + */ + private static byte[] produceNetworkLoad( + HandshakeContext hc, SSLExtension signatureAlgorithmsExt, + SSLExtension signatureAlgorithmsCertExt) throws IOException { + + List sigAlgs; + + // If we don't produce "signature_algorithms_cert" extension, then + // the "signature_algorithms" extension should contain signatures + // supported for both: handshake signatures and certificate signatures. + if (hc.sslConfig.isAvailable(signatureAlgorithmsCertExt)) { + sigAlgs = hc.localSupportedSignAlgs; + } else { + sigAlgs = new ArrayList<>(hc.localSupportedSignAlgs); + sigAlgs.retainAll(hc.localSupportedCertSignAlgs); + } + + int vectorLen = SignatureScheme.sizeInRecord() * sigAlgs.size(); + byte[] extData = new byte[vectorLen + 2]; + ByteBuffer m = ByteBuffer.wrap(extData); + Record.putInt16(m, vectorLen); + + for (SignatureScheme ss : sigAlgs) { + Record.putInt16(m, ss.id); + } + + // Update the context. + hc.handshakeExtensions.put( + signatureAlgorithmsExt, new SignatureSchemesSpec(sigAlgs)); + + return extData; + } } diff --git a/src/java.base/share/classes/sun/util/locale/UnicodeLocaleExtension.java b/src/java.base/share/classes/sun/util/locale/UnicodeLocaleExtension.java index 634932e9e19..7f66febf65f 100644 --- a/src/java.base/share/classes/sun/util/locale/UnicodeLocaleExtension.java +++ b/src/java.base/share/classes/sun/util/locale/UnicodeLocaleExtension.java @@ -1,4 +1,3 @@ - /* * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. diff --git a/src/java.base/windows/native/libjava/canonicalize_md.c b/src/java.base/windows/native/libjava/canonicalize_md.c index ecfdf63d091..7e567c7fbb4 100644 --- a/src/java.base/windows/native/libjava/canonicalize_md.c +++ b/src/java.base/windows/native/libjava/canonicalize_md.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2020, 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 @@ -41,7 +41,7 @@ /* We should also include jdk_util.h here, for the prototype of JDK_Canonicalize. This isn't possible though because canonicalize_md.c is as well used in different contexts within Oracle. - */ +*/ #include "io_util_md.h" /* Copy bytes to dst, not going past dend; return dst + number of bytes copied, @@ -139,7 +139,8 @@ lastErrorReportable() || (errval == ERROR_ACCESS_DENIED) || (errval == ERROR_NETWORK_UNREACHABLE) || (errval == ERROR_NETWORK_ACCESS_DENIED) - || (errval == ERROR_NO_MORE_FILES)) { + || (errval == ERROR_NO_MORE_FILES) + || (errval == ERROR_NETNAME_DELETED)) { return 0; } return 1; @@ -183,7 +184,7 @@ wcanonicalize(WCHAR *orig_path, WCHAR *result, int size) /* Copy prefix, assuming path is absolute */ c = src[0]; if (((c <= L'z' && c >= L'a') || (c <= L'Z' && c >= L'A')) - && (src[1] == L':') && (src[2] == L'\\')) { + && (src[1] == L':') && (src[2] == L'\\')) { /* Drive specifier */ *src = towupper(*src); /* Canonicalize drive letter */ if (!(dst = wcp(dst, dend, L'\0', src, src + 2))) { @@ -244,9 +245,9 @@ wcanonicalize(WCHAR *orig_path, WCHAR *result, int size) continue; } else { if (!lastErrorReportable()) { - if (!(dst = wcp(dst, dend, L'\0', src, src + wcslen(src)))){ - goto err; - } + if (!(dst = wcp(dst, dend, L'\0', src, src + wcslen(src)))){ + goto err; + } break; } else { goto err; @@ -255,7 +256,7 @@ wcanonicalize(WCHAR *orig_path, WCHAR *result, int size) } if (dst >= dend) { - errno = ENAMETOOLONG; + errno = ENAMETOOLONG; goto err; } *dst = L'\0'; @@ -366,7 +367,7 @@ JDK_Canonicalize(const char *orig, char *out, int len) { // Change return value to success. ret = 0; -finish: + finish: free(wresult); free(wpath); diff --git a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterGraphics.java b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterGraphics.java index c3ed089472b..45fcdfd2c0c 100644 --- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterGraphics.java +++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterGraphics.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -75,4 +75,16 @@ public boolean drawImage(Image img, // needToCopyBgColorImage, is private instead of protected!) return getDelegate().drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, bgcolor, observer); } + + @Override + public void drawString(String str, int x, int y) { + str = RasterPrinterJob.removeControlChars(str); + super.drawString(str, x, y); + } + + @Override + public void drawString(String str, float x, float y) { + str = RasterPrinterJob.removeControlChars(str); + super.drawString(str, x, y); + } } diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/CTextPipe.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/CTextPipe.m index 9da3b6648fb..f1c12585728 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/CTextPipe.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/CTextPipe.m @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -457,15 +457,17 @@ render using the right font (see bug 7183516) when attribString is not } } if (positions != NULL) { + + CGAffineTransform invTx = CGAffineTransformInvert(strike->fFontTx); + CGPoint prev; prev.x = positions[0]; prev.y = positions[1]; + prev = CGPointApplyAffineTransform(prev, invTx); // take the first point, and move the context to that location CGContextTranslateCTM(qsdo->cgRef, prev.x, prev.y); - CGAffineTransform invTx = CGAffineTransformInvert(strike->fFontTx); - // for each position, figure out the advance (since CG won't take positions directly) size_t i; for (i = 0; i < length - 1; i++) @@ -476,7 +478,7 @@ render using the right font (see bug 7183516) when attribString is not pt.y = positions[i2+1]; pt = CGPointApplyAffineTransform(pt, invTx); advances[i].width = pt.x - prev.x; - advances[i].height = -(pt.y - prev.y); // negative to translate to device space + advances[i].height = pt.y - prev.y; prev.x = pt.x; prev.y = pt.y; } diff --git a/src/java.desktop/share/classes/java/awt/image/LookupOp.java b/src/java.desktop/share/classes/java/awt/image/LookupOp.java index 5d11f78e76d..c8d8a703a3f 100644 --- a/src/java.desktop/share/classes/java/awt/image/LookupOp.java +++ b/src/java.desktop/share/classes/java/awt/image/LookupOp.java @@ -1,4 +1,3 @@ - /* * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. diff --git a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicPopupMenuUI.java b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicPopupMenuUI.java index e518f509c5a..6fab795e36c 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicPopupMenuUI.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicPopupMenuUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -377,6 +377,7 @@ public void menuKeyPressed(MenuKeyEvent e) { } else if (item.isEnabled()) { // we have a menu item manager.clearSelectedPath(); + sun.awt.SunToolkit.consumeNextKeyTyped(e); item.doClick(); } e.consume(); diff --git a/src/java.desktop/share/classes/sun/java2d/pipe/OutlineTextRenderer.java b/src/java.desktop/share/classes/sun/java2d/pipe/OutlineTextRenderer.java index b657e434d2f..949a914990b 100644 --- a/src/java.desktop/share/classes/sun/java2d/pipe/OutlineTextRenderer.java +++ b/src/java.desktop/share/classes/sun/java2d/pipe/OutlineTextRenderer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -73,8 +73,8 @@ public void drawChars(SunGraphics2D g2d, public void drawString(SunGraphics2D g2d, String str, double x, double y) { - if ("".equals(str)) { - return; // TextLayout constructor throws IAE on "". + if (str.length() == 0) { + return; } TextLayout tl = new TextLayout(str, g2d.getFont(), g2d.getFontRenderContext()); diff --git a/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java b/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java index 2a6d45e2ba8..754af87b94e 100644 --- a/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java +++ b/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java @@ -2470,13 +2470,16 @@ protected void initPrinterGraphics(Graphics2D g, Rectangle2D clip) { g.setPaint(Color.black); } - /* On-screen drawString renders most control chars as the missing glyph - * and have the non-zero advance of that glyph. - * Exceptions are \t, \n and \r which are considered zero-width. - * This is a utility method used by subclasses to remove them so we - * don't have to worry about platform or font specific handling of them. + /** + * Removes ignorable whitespace from the specified text, so that there + * is no need for platform-specific or font-specific custom whitespace + * handling, and so that these characters are not treated like control + * characters which are printed as the missing glyph. + * + * @param s the text to process + * @return the input text, with ignorable whitespace (if any) removed */ - protected String removeControlChars(String s) { + public static String removeControlChars(String s) { char[] in_chars = s.toCharArray(); int len = in_chars.length; char[] out_chars = new char[len]; diff --git a/src/java.desktop/windows/classes/sun/awt/windows/WPathGraphics.java b/src/java.desktop/windows/classes/sun/awt/windows/WPathGraphics.java index 75e8fa42da0..87b1591c0eb 100644 --- a/src/java.desktop/windows/classes/sun/awt/windows/WPathGraphics.java +++ b/src/java.desktop/windows/classes/sun/awt/windows/WPathGraphics.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 @@ -73,6 +73,7 @@ import sun.print.PathGraphics; import sun.print.ProxyGraphics2D; +import sun.print.RasterPrinterJob; final class WPathGraphics extends PathGraphics { @@ -847,7 +848,7 @@ private void textOut(String str, * removed now so the string and positions are the same length. * For other cases we need to pass glyph codes to GDI. */ - str = wPrinterJob.removeControlChars(str); + str = RasterPrinterJob.removeControlChars(str); char[] chars = str.toCharArray(); int len = chars.length; GlyphVector gv = null; diff --git a/src/java.desktop/windows/classes/sun/awt/windows/WPrinterJob.java b/src/java.desktop/windows/classes/sun/awt/windows/WPrinterJob.java index e50cfcff33b..17d41036bcc 100644 --- a/src/java.desktop/windows/classes/sun/awt/windows/WPrinterJob.java +++ b/src/java.desktop/windows/classes/sun/awt/windows/WPrinterJob.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -1202,14 +1202,6 @@ protected void setTextColor(Color color) { } } - /** - * Remove control characters. - */ - @Override - protected String removeControlChars(String str) { - return super.removeControlChars(str); - } - /** * Draw the string {@code text} to the printer's * device context at the specified position. diff --git a/src/jdk.compiler/share/classes/com/sun/source/tree/UsesTree.java b/src/jdk.compiler/share/classes/com/sun/source/tree/UsesTree.java index 9b52eb29e1b..d14257de626 100644 --- a/src/jdk.compiler/share/classes/com/sun/source/tree/UsesTree.java +++ b/src/jdk.compiler/share/classes/com/sun/source/tree/UsesTree.java @@ -1,4 +1,3 @@ - /* * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 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 8eab238f82a..88c9da5d9e8 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 @@ -161,24 +161,7 @@ private void initializeRootIfNeeded() { values = LintCategory.newEmptySet(); } else { // otherwise, enable on-by-default categories - values = LintCategory.newEmptySet(); - - Source source = Source.instance(context); - if (source.compareTo(Source.JDK9) >= 0) { - values.add(LintCategory.DEP_ANN); - } - if (Source.Feature.REDUNDANT_STRICTFP.allowedInSource(source)) { - values.add(LintCategory.STRICTFP); - } - values.add(LintCategory.REQUIRES_TRANSITIVE_AUTOMATIC); - values.add(LintCategory.OPENS); - values.add(LintCategory.MODULE); - values.add(LintCategory.REMOVAL); - if (!options.isSet(Option.PREVIEW)) { - values.add(LintCategory.PREVIEW); - } - values.add(LintCategory.IDENTITY); - values.add(LintCategory.INCUBATING); + values = getDefaults(); } // Look for specific overrides @@ -193,6 +176,23 @@ private void initializeRootIfNeeded() { suppressedValues = LintCategory.newEmptySet(); } + // Obtain the set of on-by-default categories. Note that for a few categories, + // whether the category is on-by-default depends on other compiler options. + private EnumSet getDefaults() { + EnumSet defaults = LintCategory.newEmptySet(); + Source source = Source.instance(context); + Stream.of(LintCategory.values()) + .filter(lc -> + switch (lc) { + case DEP_ANN -> source.compareTo(Source.JDK9) >= 0; + case STRICTFP -> Source.Feature.REDUNDANT_STRICTFP.allowedInSource(source); + case PREVIEW -> !options.isSet(Option.PREVIEW); + default -> lc.enabledByDefault; + }) + .forEach(defaults::add); + return defaults; + } + @Override public String toString() { initializeRootIfNeeded(); @@ -221,7 +221,7 @@ public enum LintCategory { *

* This category is not supported by {@code @SuppressWarnings}. */ - CLASSFILE("classfile", false), + CLASSFILE("classfile", false, false), /** * Warn about "dangling" documentation comments, @@ -238,7 +238,7 @@ public enum LintCategory { * Warn about items which are documented with an {@code @deprecated} JavaDoc * comment, but which do not have {@code @Deprecated} annotation. */ - DEP_ANN("dep-ann"), + DEP_ANN("dep-ann", true, true), /** * Warn about division by constant integer 0. @@ -268,7 +268,7 @@ public enum LintCategory { /** * Warn about uses of @ValueBased classes where an identity class is expected. */ - IDENTITY("identity", true, "synchronization"), + IDENTITY("identity", true, true, "synchronization"), /** * Warn about use of incubating modules. @@ -276,7 +276,7 @@ public enum LintCategory { *

* This category is not supported by {@code @SuppressWarnings}. */ - INCUBATING("incubating", false), + INCUBATING("incubating", false, true), /** * Warn about compiler possible lossy conversions. @@ -291,12 +291,12 @@ public enum LintCategory { /** * Warn about module system related issues. */ - MODULE("module"), + MODULE("module", true, true), /** * Warn about issues regarding module opens. */ - OPENS("opens"), + OPENS("opens", true, true), /** * Warn about issues relating to use of command line options. @@ -304,7 +304,7 @@ public enum LintCategory { *

* This category is not supported by {@code @SuppressWarnings}. */ - OPTIONS("options", false), + OPTIONS("options", false, false), /** * Warn when any output file is written to more than once. @@ -312,7 +312,7 @@ public enum LintCategory { *

* This category is not supported by {@code @SuppressWarnings}. */ - OUTPUT_FILE_CLASH("output-file-clash", false), + OUTPUT_FILE_CLASH("output-file-clash", false, false), /** * Warn about issues regarding method overloads. @@ -330,12 +330,15 @@ public enum LintCategory { *

* This category is not supported by {@code @SuppressWarnings}. */ - PATH("path", false), + PATH("path", false, false), /** * Warn about issues regarding annotation processing. + * + *

+ * This category is not supported by {@code @SuppressWarnings}. */ - PROCESSING("processing"), + PROCESSING("processing", false, false), /** * Warn about unchecked operations on raw types. @@ -345,7 +348,7 @@ public enum LintCategory { /** * Warn about use of deprecated-for-removal items. */ - REMOVAL("removal"), + REMOVAL("removal", true, true), /** * Warn about use of automatic modules in the requires clauses. @@ -355,7 +358,7 @@ public enum LintCategory { /** * Warn about automatic modules in requires transitive. */ - REQUIRES_TRANSITIVE_AUTOMATIC("requires-transitive-automatic"), + REQUIRES_TRANSITIVE_AUTOMATIC("requires-transitive-automatic", true, true), /** * Warn about Serializable classes that do not provide a serial version ID. @@ -370,7 +373,7 @@ public enum LintCategory { /** * Warn about unnecessary uses of the strictfp modifier */ - STRICTFP("strictfp"), + STRICTFP("strictfp", true, true), /** * Warn about issues relating to use of text blocks @@ -400,7 +403,7 @@ public enum LintCategory { /** * Warn about use of preview features. */ - PREVIEW("preview"), + PREVIEW("preview", true, true), /** * Warn about use of restricted methods. @@ -408,12 +411,13 @@ public enum LintCategory { RESTRICTED("restricted"); LintCategory(String option) { - this(option, true); + this(option, true, false); } - LintCategory(String option, boolean annotationSuppression, String... aliases) { + LintCategory(String option, boolean annotationSuppression, boolean enabledByDefault, String... aliases) { this.option = option; this.annotationSuppression = annotationSuppression; + this.enabledByDefault = enabledByDefault; ArrayList optionList = new ArrayList<>(1 + aliases.length); optionList.add(option); Collections.addAll(optionList, aliases); @@ -450,6 +454,12 @@ public static EnumSet newEmptySet() { /** Does this category support being suppressed by the {@code @SuppressWarnings} annotation? */ public final boolean annotationSuppression; + + /** + * Is this category included in the default set of enabled lint categories? + * Note that for some categories, command line options can alter this at runtime. + */ + public final boolean enabledByDefault; } /** diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Option.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Option.java index f4122cebb64..8d5ad4c4d78 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Option.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Option.java @@ -39,10 +39,12 @@ import java.util.EnumSet; import java.util.Iterator; import java.util.LinkedHashSet; +import java.util.List; import java.util.Locale; import java.util.ServiceLoader; import java.util.Set; import java.util.StringJoiner; +import java.util.TreeMap; import java.util.TreeSet; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -484,24 +486,54 @@ public void process(OptionHelper helper, String option) throws InvalidValueExcep }, HELP_LINT("--help-lint", "opt.help.lint", EXTENDED, INFO) { - private final String LINT_KEY_FORMAT = SMALL_INDENT + SMALL_INDENT + "%-" + + private final String HELP_INDENT = SMALL_INDENT + SMALL_INDENT; + private final String LINT_KEY_FORMAT = HELP_INDENT + "%-" + (DEFAULT_SYNOPSIS_WIDTH - LARGE_INDENT.length()) + "s %s"; @Override public void process(OptionHelper helper, String option) throws InvalidValueException { Log log = helper.getLog(); + + // Print header log.printRawLines(WriterKind.STDOUT, log.localize(PrefixKind.JAVAC, "opt.help.lint.header")); + + // Print "all" option log.printRawLines(WriterKind.STDOUT, String.format(LINT_KEY_FORMAT, LINT_CUSTOM_ALL, log.localize(PrefixKind.JAVAC, "opt.Xlint.all"))); - LintCategory.options().forEach(ident -> log.printRawLines(WriterKind.STDOUT, - String.format(LINT_KEY_FORMAT, - ident, - log.localize(PrefixKind.JAVAC, "opt.Xlint.desc." + ident)))); + + // Alphabetize all the category names and their aliases together, and then list them with their descriptions + TreeMap keyMap = new TreeMap<>(); + Stream.of(LintCategory.values()).forEach(lc -> + lc.optionList.stream() + .forEach(key -> keyMap.put(key, + String.format(LINT_KEY_FORMAT, + key, + key.equals(lc.option) ? + log.localize(PrefixKind.JAVAC, "opt.Xlint.desc." + key) : + log.localize(PrefixKind.JAVAC, "opt.Xlint.alias.of", lc.option, key))))); + keyMap.values().forEach(desc -> log.printRawLines(WriterKind.STDOUT, desc)); + + // Print "none" option log.printRawLines(WriterKind.STDOUT, String.format(LINT_KEY_FORMAT, LINT_CUSTOM_NONE, log.localize(PrefixKind.JAVAC, "opt.Xlint.none"))); + + // Show which lint categories are enabled by default + log.printRawLines(WriterKind.STDOUT, log.localize(PrefixKind.JAVAC, "opt.help.lint.enabled.by.default")); + String defaults = Stream.of(LintCategory.values()) + .filter(lc -> lc.enabledByDefault) + .map(lc -> lc.option) + .sorted() + .collect(Collectors.joining(", ")); + log.printRawLines(WriterKind.STDOUT, + String.format("%s%s.", HELP_INDENT, defaults)); + + // Add trailing blurb about aliases + List aliasExample = LintCategory.IDENTITY.optionList; + log.printRawLines(WriterKind.STDOUT, + log.localize(PrefixKind.JAVAC, "opt.help.lint.footer", aliasExample.get(0), aliasExample.get(1))); super.process(helper, option); } }, diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac.properties b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac.properties index 6c3238cfdfe..15a63da06eb 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac.properties +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac.properties @@ -168,18 +168,20 @@ javac.opt.Xbootclasspath.p=\ javac.opt.Xbootclasspath.a=\ Append to the bootstrap class path javac.opt.Xlint=\ - Enable recommended warning categories + Enable recommended lint warning categories. In this release, all\n\ + available lint warning categories are recommended. javac.opt.Xlint.all=\ - Enable all warning categories + Enable all lint warning categories javac.opt.Xlint.none=\ - Disable all warning categories + Disable all lint warning categories #L10N: do not localize: -Xlint javac.opt.arg.Xlint=\ (,)* javac.opt.Xlint.custom=\ - Warning categories to enable or disable, separated by comma.\n\ - Precede a key by ''-'' to disable the specified warning.\n\ - Use --help-lint to see the supported keys. + Lint warning categories to enable or disable, separated by comma.\n\ + Precede a key by ''-'' to disable the specified category. Use\n\ + ''--help-lint'' to show supported keys and which categories are\n\ + enabled by default. javac.opt.Xlint.desc.auxiliaryclass=\ Warn about an auxiliary class that is hidden in a source file, and is used from other files. @@ -291,16 +293,13 @@ javac.opt.Xlint.desc.preview=\ javac.opt.Xlint.desc.restricted=\ Warn about use of restricted methods. -# L10N: do not localize: identity synchronization -javac.opt.Xlint.desc.synchronization=\ - Warn about synchronization attempts on instances of value-based classes.\n\ -\ This key is a deprecated alias for ''identity'', which has the same uses and\n\ -\ effects. Users are encouraged to use the ''identity'' category for all future\n\ -\ and existing uses of ''synchronization''. - javac.opt.Xlint.desc.identity=\ Warn about uses of value-based classes where an identity class is expected. +javac.opt.Xlint.alias.of=\ + Deprecated alias for ''{0}'' with an identical effect. Users are encouraged to use\n\ +\ ''{0}'' instead of ''{1}'' for all current and future uses. + javac.opt.Xdoclint=\ Enable recommended checks for problems in javadoc comments # L10N: do not localize: all none @@ -334,6 +333,11 @@ javac.opt.help.lint=\ Print the supported keys for -Xlint javac.opt.help.lint.header=\ The supported keys for -Xlint are: +javac.opt.help.lint.enabled.by.default=\ + The following lint warning categories are enabled by default: +javac.opt.help.lint.footer=\ + Categories and their aliases can be used interchangeably; for example, the flag\n\ + ''-Xlint:{0},{1}'' would be redundant. javac.opt.print=\ Print out a textual representation of specified types javac.opt.printRounds=\ @@ -346,8 +350,9 @@ javac.opt.userpathsfirst=\ javac.opt.prefer=\ Specify which file to read when both a source file and class file\n\ are found for an implicitly compiled class +# L10N: do not localize: ''preview'' javac.opt.preview=\ - Enable preview language features.\n\ + Enable preview language features. Also disables the ''preview'' lint category.\n\ To be used in conjunction with either -source or --release. javac.opt.AT=\ Read options and filenames from file diff --git a/src/jdk.compiler/share/classes/module-info.java b/src/jdk.compiler/share/classes/module-info.java index 33cff9379f2..46ada3a12e7 100644 --- a/src/jdk.compiler/share/classes/module-info.java +++ b/src/jdk.compiler/share/classes/module-info.java @@ -141,7 +141,8 @@ * * In addition, javac also supports other strings that can be used * to suppress other kinds of warnings. The following table lists all the - * strings that can be used with {@code @SuppressWarnings}. + * strings that are recognized by javac in {@code @SuppressWarnings} + * annotations. Unrecognized strings are ignored. * * * @@ -152,7 +153,6 @@ * *
Strings supported by {@code SuppressWarnings}
{@code auxiliaryclass} an auxiliary class that is hidden in a source file, and is used * from other files *
{@code cast} use of unnecessary casts - *
{@code classfile} issues related to classfile contents *
{@code dangling-doc-comments} issues related to "dangling" documentation comments, * not attached to a declaration *
{@code deprecation} use of deprecated items @@ -165,7 +165,6 @@ * the next *
{@code finally} {@code finally} clauses that do not terminate normally *
{@code identity} use of a value-based class where an identity class is expected - *
{@code incubating} use of incubating modules *
{@code lossy-conversions} possible lossy conversions in compound assignment *
{@code missing-explicit-ctor} missing explicit constructors in public and protected classes * in exported packages @@ -173,13 +172,12 @@ *
{@code opens} issues regarding module opens *
{@code overloads} issues regarding method overloads *
{@code overrides} issues regarding method overrides - *
{@code path} invalid path elements on the command line *
{@code preview} use of preview language features *
{@code rawtypes} use of raw types *
{@code removal} use of API that has been marked for removal - *
{@code restricted} use of restricted methods *
{@code requires-automatic} use of automatic modules in the {@code requires} clauses *
{@code requires-transitive-automatic} automatic modules in {@code requires transitive} + *
{@code restricted} use of restricted methods *
{@code serial} {@link java.base/java.io.Serializable Serializable} classes * that do not have a {@code serialVersionUID} field, or other * suspect declarations in {@code Serializable} and @@ -187,11 +185,9 @@ * and interfaces *
{@code static} accessing a static member using an instance *
{@code strictfp} unnecessary use of the {@code strictfp} modifier - *
{@code synchronization} synchronization attempts on instances of value-based classes; - * this key is a deprecated alias for {@code identity}, which has - * the same uses and effects. Users are encouraged to use the - * {@code identity} category for all future and existing uses of - * {@code synchronization} + *
{@code synchronization} deprecated alias for {@code identity} with an identical effect. + * Users are encouraged to use {@code identity} instead of + * {@code synchronization} for all current and future uses. *
{@code text-blocks} inconsistent white space characters in text block indentation *
{@code this-escape} superclass constructor leaking {@code this} before subclass initialized *
{@code try} issues relating to use of {@code try} blocks @@ -207,6 +203,25 @@ *
* + * All of the non-{@code docllint:} strings listed above may also be used with the {@code -Xlint} command line flag. + * The {@code -Xlint} flag also supports these strings not supported by {@code @SuppressWarnings}: + * + * + * + * + * + * + * + *
Strings supported by {@code -Xlint} but not {@code SuppressWarnings}
StringWarnings Related To ... + *
{@code classfile} issues related to classfile contents + *
{@code incubating} use of incubating modules + *
{@code options} issues relating to use of command line options + *
{@code output-file-clash} output files being overwritten due to filename clashes + *
{@code path} invalid path elements on the command line + *
{@code processing} issues regarding annotation processing + *
{@code restricted} use of restricted methods + *
+ * * @toolGuide javac * * @provides java.util.spi.ToolProvider diff --git a/src/jdk.compiler/share/data/symbols/include.list b/src/jdk.compiler/share/data/symbols/include.list index b99422a60e3..b2502f18fa4 100644 --- a/src/jdk.compiler/share/data/symbols/include.list +++ b/src/jdk.compiler/share/data/symbols/include.list @@ -267,6 +267,7 @@ +com/sun/management/ +com/sun/nio/sctp/ +jdk/ ++jdk/net/ # #Exported(true) in 8u40: # diff --git a/src/jdk.compiler/share/data/symbols/java.base-8.sym.txt b/src/jdk.compiler/share/data/symbols/java.base-8.sym.txt index 051003c2799..3f0b74098ef 100644 --- a/src/jdk.compiler/share/data/symbols/java.base-8.sym.txt +++ b/src/jdk.compiler/share/data/symbols/java.base-8.sym.txt @@ -1,5 +1,5 @@ # -# Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2015, 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 @@ -1711,6 +1711,7 @@ field name SHARADA descriptor Ljava/lang/Character$UnicodeBlock; flags 19 field name TAKRI descriptor Ljava/lang/Character$UnicodeBlock; flags 19 field name MIAO descriptor Ljava/lang/Character$UnicodeBlock; flags 19 field name ARABIC_MATHEMATICAL_ALPHABETIC_SYMBOLS descriptor Ljava/lang/Character$UnicodeBlock; flags 19 +field name CJK_UNIFIED_IDEOGRAPHS_EXTENSION_E descriptor Ljava/lang/Character$UnicodeBlock; flags 19 method name of descriptor (C)Ljava/lang/Character$UnicodeBlock; flags 9 method name of descriptor (I)Ljava/lang/Character$UnicodeBlock; flags 9 method name forName descriptor (Ljava/lang/String;)Ljava/lang/Character$UnicodeBlock; flags 19 @@ -2078,7 +2079,7 @@ field name POSITIVE_INFINITY descriptor F constantValue Infinity flags 19 field name NEGATIVE_INFINITY descriptor F constantValue -Infinity flags 19 field name NaN descriptor F constantValue NaN flags 19 field name MAX_VALUE descriptor F constantValue 3.4028235E38 flags 19 -field name MIN_NORMAL descriptor F constantValue 1.17549435E-38 flags 19 +field name MIN_NORMAL descriptor F constantValue 1.1754944E-38 flags 19 field name MIN_VALUE descriptor F constantValue 1.4E-45 flags 19 field name MAX_EXPONENT descriptor I constantValue 127 flags 19 field name MIN_EXPONENT descriptor I constantValue -126 flags 19 @@ -3574,6 +3575,7 @@ method name get descriptor ()Ljava/lang/Object; flags 1 signature ()TT; method name clear descriptor ()V flags 1 method name isEnqueued descriptor ()Z flags 1 method name enqueue descriptor ()Z flags 1 +method name clone descriptor ()Ljava/lang/Object; thrownTypes java/lang/CloneNotSupportedException flags 4 class name java/lang/ref/ReferenceQueue header extends java/lang/Object flags 21 signature Ljava/lang/Object; classAnnotations @Ljdk/Profile+Annotation;(value=I1) diff --git a/src/jdk.compiler/share/data/symbols/java.base-9.sym.txt b/src/jdk.compiler/share/data/symbols/java.base-9.sym.txt index 99a4f8e9f0e..7ea597bda46 100644 --- a/src/jdk.compiler/share/data/symbols/java.base-9.sym.txt +++ b/src/jdk.compiler/share/data/symbols/java.base-9.sym.txt @@ -1,5 +1,5 @@ # -# Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2015, 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 @@ -165,10 +165,6 @@ header extends java/lang/Object implements java/io/Serializable,java/lang/Compar innerclass innerClass java/lang/Character$UnicodeScript outerClass java/lang/Character innerClassName UnicodeScript flags 4019 innerclass innerClass java/lang/Character$UnicodeBlock outerClass java/lang/Character innerClassName UnicodeBlock flags 19 innerclass innerClass java/lang/Character$Subset outerClass java/lang/Character innerClassName Subset flags 9 -field name DIRECTIONALITY_LEFT_TO_RIGHT_ISOLATE descriptor B constantValue 19 flags 19 -field name DIRECTIONALITY_RIGHT_TO_LEFT_ISOLATE descriptor B constantValue 20 flags 19 -field name DIRECTIONALITY_FIRST_STRONG_ISOLATE descriptor B constantValue 21 flags 19 -field name DIRECTIONALITY_POP_DIRECTIONAL_ISOLATE descriptor B constantValue 22 flags 19 -method name descriptor (C)V -method name valueOf descriptor (C)Ljava/lang/Character; -method name charValue descriptor ()C @@ -176,6 +172,10 @@ field name DIRECTIONALITY_POP_DIRECTIONAL_ISOLATE descriptor B constantValue 22 -method name isJavaLetterOrDigit descriptor (C)Z -method name isSpace descriptor (C)Z -method name reverseBytes descriptor (C)C +field name DIRECTIONALITY_LEFT_TO_RIGHT_ISOLATE descriptor B constantValue 19 flags 19 +field name DIRECTIONALITY_RIGHT_TO_LEFT_ISOLATE descriptor B constantValue 20 flags 19 +field name DIRECTIONALITY_FIRST_STRONG_ISOLATE descriptor B constantValue 21 flags 19 +field name DIRECTIONALITY_POP_DIRECTIONAL_ISOLATE descriptor B constantValue 22 flags 19 method name descriptor (C)V flags 1 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(since="9") method name valueOf descriptor (C)Ljava/lang/Character; flags 9 runtimeAnnotations @Ljdk/internal/HotSpotIntrinsicCandidate; method name charValue descriptor ()C flags 1 runtimeAnnotations @Ljdk/internal/HotSpotIntrinsicCandidate; @@ -229,7 +229,6 @@ field name EARLY_DYNASTIC_CUNEIFORM descriptor Ljava/lang/Character$UnicodeBlock field name ANATOLIAN_HIEROGLYPHS descriptor Ljava/lang/Character$UnicodeBlock; flags 19 field name SUTTON_SIGNWRITING descriptor Ljava/lang/Character$UnicodeBlock; flags 19 field name SUPPLEMENTAL_SYMBOLS_AND_PICTOGRAPHS descriptor Ljava/lang/Character$UnicodeBlock; flags 19 -field name CJK_UNIFIED_IDEOGRAPHS_EXTENSION_E descriptor Ljava/lang/Character$UnicodeBlock; flags 19 class name java/lang/Character$UnicodeScript field name CAUCASIAN_ALBANIAN descriptor Ljava/lang/Character$UnicodeScript; flags 4019 @@ -711,7 +710,6 @@ innerclass innerClass java/lang/module/ModuleDescriptor$Opens outerClass java/la innerclass innerClass java/lang/module/ModuleDescriptor$Exports outerClass java/lang/module/ModuleDescriptor innerClassName Exports flags 19 innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 -field name inCheck descriptor Z -field name inCheck descriptor Z flags 4 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(forRemoval=Ztrue,since="1.2") -method name getInCheck descriptor ()Z -method name getClassContext descriptor ()[Ljava/lang/Class; -method name currentClassLoader descriptor ()Ljava/lang/ClassLoader; @@ -725,6 +723,7 @@ field name inCheck descriptor Z flags 4 deprecated true runtimeAnnotations @Ljav -method name checkSystemClipboardAccess descriptor ()V -method name checkAwtEventQueueAccess descriptor ()V -method name checkMemberAccess descriptor (Ljava/lang/Class;I)V +field name inCheck descriptor Z flags 4 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(forRemoval=Ztrue,since="1.2") method name getInCheck descriptor ()Z flags 1 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(forRemoval=Ztrue,since="1.2") method name getClassContext descriptor ()[Ljava/lang/Class; flags 104 signature ()[Ljava/lang/Class<*>; method name currentClassLoader descriptor ()Ljava/lang/ClassLoader; flags 4 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(forRemoval=Ztrue,since="1.2") @@ -1404,6 +1403,7 @@ method name clean descriptor ()V flags 401 class name java/lang/ref/Reference -method name get descriptor ()Ljava/lang/Object; +-method name clone descriptor ()Ljava/lang/Object; method name get descriptor ()Ljava/lang/Object; flags 1 signature ()TT; runtimeAnnotations @Ljdk/internal/HotSpotIntrinsicCandidate; method name reachabilityFence descriptor (Ljava/lang/Object;)V flags 9 runtimeAnnotations @Ljdk/internal/vm/annotation/DontInline; @@ -1515,6 +1515,9 @@ class name java/math/BigDecimal -field name ROUND_HALF_DOWN descriptor I -field name ROUND_HALF_EVEN descriptor I -field name ROUND_UNNECESSARY descriptor I +-method name divide descriptor (Ljava/math/BigDecimal;II)Ljava/math/BigDecimal; +-method name divide descriptor (Ljava/math/BigDecimal;I)Ljava/math/BigDecimal; +-method name setScale descriptor (II)Ljava/math/BigDecimal; field name ROUND_UP descriptor I constantValue 0 flags 19 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(since="9") field name ROUND_DOWN descriptor I constantValue 1 flags 19 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(since="9") field name ROUND_CEILING descriptor I constantValue 2 flags 19 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(since="9") @@ -1523,9 +1526,6 @@ field name ROUND_HALF_UP descriptor I constantValue 4 flags 19 deprecated true r field name ROUND_HALF_DOWN descriptor I constantValue 5 flags 19 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(since="9") field name ROUND_HALF_EVEN descriptor I constantValue 6 flags 19 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(since="9") field name ROUND_UNNECESSARY descriptor I constantValue 7 flags 19 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(since="9") --method name divide descriptor (Ljava/math/BigDecimal;II)Ljava/math/BigDecimal; --method name divide descriptor (Ljava/math/BigDecimal;I)Ljava/math/BigDecimal; --method name setScale descriptor (II)Ljava/math/BigDecimal; method name divide descriptor (Ljava/math/BigDecimal;II)Ljava/math/BigDecimal; flags 1 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(since="9") method name divide descriptor (Ljava/math/BigDecimal;I)Ljava/math/BigDecimal; flags 1 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(since="9") method name sqrt descriptor (Ljava/math/MathContext;)Ljava/math/BigDecimal; flags 1 @@ -2189,8 +2189,8 @@ innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang class name java/time/LocalDate header extends java/lang/Object implements java/time/temporal/Temporal,java/time/temporal/TemporalAdjuster,java/time/chrono/ChronoLocalDate,java/io/Serializable flags 31 innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 -field name EPOCH descriptor Ljava/time/LocalDate; flags 19 -method name getEra descriptor ()Ljava/time/chrono/Era; +field name EPOCH descriptor Ljava/time/LocalDate; flags 19 method name ofInstant descriptor (Ljava/time/Instant;Ljava/time/ZoneId;)Ljava/time/LocalDate; flags 9 method name getEra descriptor ()Ljava/time/chrono/IsoEra; flags 1 method name datesUntil descriptor (Ljava/time/LocalDate;)Ljava/util/stream/Stream; flags 1 signature (Ljava/time/LocalDate;)Ljava/util/stream/Stream; diff --git a/src/jdk.compiler/share/data/symbols/java.desktop-8.sym.txt b/src/jdk.compiler/share/data/symbols/java.desktop-8.sym.txt index 3daa15e5081..782c96da30c 100644 --- a/src/jdk.compiler/share/data/symbols/java.desktop-8.sym.txt +++ b/src/jdk.compiler/share/data/symbols/java.desktop-8.sym.txt @@ -1,5 +1,5 @@ # -# Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2015, 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 @@ -666,7 +666,6 @@ innerclass innerClass java/awt/Component$BaselineResizeBehavior outerClass java/ innerclass innerClass java/awt/Component$FlipBufferStrategy outerClass java/awt/Component innerClassName FlipBufferStrategy flags 4 innerclass innerClass java/awt/Component$BltBufferStrategy outerClass java/awt/Component innerClassName BltBufferStrategy flags 4 innerclass innerClass java/awt/Component$AccessibleAWTComponent outerClass java/awt/Component innerClassName AccessibleAWTComponent flags 404 -innerclass innerClass sun/awt/CausedFocusEvent$Cause outerClass sun/awt/CausedFocusEvent innerClassName Cause flags 4019 field name TOP_ALIGNMENT descriptor F constantValue 0.0 flags 19 field name CENTER_ALIGNMENT descriptor F constantValue 0.5 flags 19 field name BOTTOM_ALIGNMENT descriptor F constantValue 1.0 flags 19 @@ -2116,7 +2115,6 @@ method name postProcessKeyEvent descriptor (Ljava/awt/event/KeyEvent;)Z flags 40 class name java/awt/KeyboardFocusManager header extends java/lang/Object implements java/awt/KeyEventDispatcher,java/awt/KeyEventPostProcessor flags 421 classAnnotations @Ljdk/Profile+Annotation;(value=I4) -innerclass innerClass sun/awt/CausedFocusEvent$Cause outerClass sun/awt/CausedFocusEvent innerClassName Cause flags 4019 field name FORWARD_TRAVERSAL_KEYS descriptor I constantValue 0 flags 19 field name BACKWARD_TRAVERSAL_KEYS descriptor I constantValue 1 flags 19 field name UP_CYCLE_TRAVERSAL_KEYS descriptor I constantValue 2 flags 19 @@ -7473,7 +7471,6 @@ method name select descriptor (I)V flags 401 class name java/awt/peer/ComponentPeer header extends java/lang/Object flags 601 classAnnotations @Ljdk/Profile+Annotation;(value=I4)@Lsun/Proprietary+Annotation; -innerclass innerClass sun/awt/CausedFocusEvent$Cause outerClass sun/awt/CausedFocusEvent innerClassName Cause flags 4019 innerclass innerClass java/awt/BufferCapabilities$FlipContents outerClass java/awt/BufferCapabilities innerClassName FlipContents flags 19 field name SET_LOCATION descriptor I constantValue 1 flags 19 field name SET_SIZE descriptor I constantValue 2 flags 19 @@ -15617,6 +15614,7 @@ method name descriptor (Ljavax/swing/JSpinner;)V flags 1 method name descriptor (Ljavax/swing/JSpinner;Ljava/lang/String;)V flags 1 method name getFormat descriptor ()Ljava/text/DecimalFormat; flags 1 method name getModel descriptor ()Ljavax/swing/SpinnerNumberModel; flags 1 +method name setComponentOrientation descriptor (Ljava/awt/ComponentOrientation;)V flags 1 class name javax/swing/JSplitPane header extends javax/swing/JComponent implements javax/accessibility/Accessible flags 21 classAnnotations @Ljdk/Profile+Annotation;(value=I4) diff --git a/src/jdk.compiler/share/data/symbols/java.desktop-9.sym.txt b/src/jdk.compiler/share/data/symbols/java.desktop-9.sym.txt index cf0ab3466a8..039610548bb 100644 --- a/src/jdk.compiler/share/data/symbols/java.desktop-9.sym.txt +++ b/src/jdk.compiler/share/data/symbols/java.desktop-9.sym.txt @@ -1,5 +1,5 @@ # -# Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2015, 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 @@ -789,6 +789,7 @@ innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang -field name BUTTON1_MASK descriptor I -field name BUTTON2_MASK descriptor I -field name BUTTON3_MASK descriptor I +-method name getModifiers descriptor ()I field name SHIFT_MASK descriptor I constantValue 1 flags 19 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(since="9") field name CTRL_MASK descriptor I constantValue 2 flags 19 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(since="9") field name META_MASK descriptor I constantValue 4 flags 19 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(since="9") @@ -797,7 +798,6 @@ field name ALT_GRAPH_MASK descriptor I constantValue 32 flags 19 deprecated true field name BUTTON1_MASK descriptor I constantValue 16 flags 19 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(since="9") field name BUTTON2_MASK descriptor I constantValue 8 flags 19 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(since="9") field name BUTTON3_MASK descriptor I constantValue 4 flags 19 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(since="9") --method name getModifiers descriptor ()I method name getModifiers descriptor ()I flags 1 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(since="9") class name java/awt/event/InputMethodEvent @@ -1354,10 +1354,10 @@ innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang class name java/beans/beancontext/BeanContextServiceAvailableEvent -field name serviceClass descriptor Ljava/lang/Class; -field name serviceClass descriptor Ljava/lang/Class; flags 4 signature Ljava/lang/Class<*>; -method name descriptor (Ljava/beans/beancontext/BeanContextServices;Ljava/lang/Class;)V -method name getServiceClass descriptor ()Ljava/lang/Class; -method name getCurrentServiceSelectors descriptor ()Ljava/util/Iterator; +field name serviceClass descriptor Ljava/lang/Class; flags 4 signature Ljava/lang/Class<*>; method name descriptor (Ljava/beans/beancontext/BeanContextServices;Ljava/lang/Class;)V flags 1 signature (Ljava/beans/beancontext/BeanContextServices;Ljava/lang/Class<*>;)V method name getServiceClass descriptor ()Ljava/lang/Class; flags 1 signature ()Ljava/lang/Class<*>; method name getCurrentServiceSelectors descriptor ()Ljava/util/Iterator; flags 1 signature ()Ljava/util/Iterator<*>; @@ -1370,10 +1370,10 @@ method name getCurrentServiceSelectors descriptor (Ljava/beans/beancontext/BeanC class name java/beans/beancontext/BeanContextServiceRevokedEvent -field name serviceClass descriptor Ljava/lang/Class; -field name serviceClass descriptor Ljava/lang/Class; flags 4 signature Ljava/lang/Class<*>; -method name descriptor (Ljava/beans/beancontext/BeanContextServices;Ljava/lang/Class;Z)V -method name getServiceClass descriptor ()Ljava/lang/Class; -method name isServiceClass descriptor (Ljava/lang/Class;)Z +field name serviceClass descriptor Ljava/lang/Class; flags 4 signature Ljava/lang/Class<*>; method name descriptor (Ljava/beans/beancontext/BeanContextServices;Ljava/lang/Class;Z)V flags 1 signature (Ljava/beans/beancontext/BeanContextServices;Ljava/lang/Class<*>;Z)V method name getServiceClass descriptor ()Ljava/lang/Class; flags 1 signature ()Ljava/lang/Class<*>; method name isServiceClass descriptor (Ljava/lang/Class;)Z flags 1 signature (Ljava/lang/Class<*>;)Z @@ -1402,8 +1402,6 @@ innerclass innerClass java/util/Map$Entry outerClass java/util/Map innerClassNam innerclass innerClass java/beans/beancontext/BeanContextSupport$BCSIterator outerClass java/beans/beancontext/BeanContextSupport innerClassName BCSIterator flags 1c -field name services descriptor Ljava/util/HashMap; -field name bcsListeners descriptor Ljava/util/ArrayList; -field name services descriptor Ljava/util/HashMap; flags 84 signature Ljava/util/HashMap; -field name bcsListeners descriptor Ljava/util/ArrayList; flags 84 signature Ljava/util/ArrayList; -method name createBCSSServiceProvider descriptor (Ljava/lang/Class;Ljava/beans/beancontext/BeanContextServiceProvider;)Ljava/beans/beancontext/BeanContextServicesSupport$BCSSServiceProvider; -method name addService descriptor (Ljava/lang/Class;Ljava/beans/beancontext/BeanContextServiceProvider;)Z -method name addService descriptor (Ljava/lang/Class;Ljava/beans/beancontext/BeanContextServiceProvider;Z)Z @@ -1414,6 +1412,8 @@ field name bcsListeners descriptor Ljava/util/ArrayList; flags 84 signature Ljav -method name getCurrentServiceSelectors descriptor (Ljava/lang/Class;)Ljava/util/Iterator; -method name fireServiceAdded descriptor (Ljava/lang/Class;)V -method name fireServiceRevoked descriptor (Ljava/lang/Class;Z)V +field name services descriptor Ljava/util/HashMap; flags 84 signature Ljava/util/HashMap; +field name bcsListeners descriptor Ljava/util/ArrayList; flags 84 signature Ljava/util/ArrayList; method name createBCSSServiceProvider descriptor (Ljava/lang/Class;Ljava/beans/beancontext/BeanContextServiceProvider;)Ljava/beans/beancontext/BeanContextServicesSupport$BCSSServiceProvider; flags 4 signature (Ljava/lang/Class<*>;Ljava/beans/beancontext/BeanContextServiceProvider;)Ljava/beans/beancontext/BeanContextServicesSupport$BCSSServiceProvider; method name addService descriptor (Ljava/lang/Class;Ljava/beans/beancontext/BeanContextServiceProvider;)Z flags 1 signature (Ljava/lang/Class<*>;Ljava/beans/beancontext/BeanContextServiceProvider;)Z method name addService descriptor (Ljava/lang/Class;Ljava/beans/beancontext/BeanContextServiceProvider;Z)Z flags 4 signature (Ljava/lang/Class<*>;Ljava/beans/beancontext/BeanContextServiceProvider;Z)Z @@ -1448,12 +1448,12 @@ innerclass innerClass java/beans/beancontext/BeanContextSupport$BCSIterator oute innerclass innerClass java/util/Map$Entry outerClass java/util/Map innerClassName Entry flags 609 -field name children descriptor Ljava/util/HashMap; -field name bcmListeners descriptor Ljava/util/ArrayList; -field name children descriptor Ljava/util/HashMap; flags 84 signature Ljava/util/HashMap; -field name bcmListeners descriptor Ljava/util/ArrayList; flags 84 signature Ljava/util/ArrayList; -method name iterator descriptor ()Ljava/util/Iterator; -method name bcsChildren descriptor ()Ljava/util/Iterator; -method name serialize descriptor (Ljava/io/ObjectOutputStream;Ljava/util/Collection;)V -method name classEquals descriptor (Ljava/lang/Class;Ljava/lang/Class;)Z +field name children descriptor Ljava/util/HashMap; flags 84 signature Ljava/util/HashMap; +field name bcmListeners descriptor Ljava/util/ArrayList; flags 84 signature Ljava/util/ArrayList; method name iterator descriptor ()Ljava/util/Iterator; flags 1 signature ()Ljava/util/Iterator; method name bcsChildren descriptor ()Ljava/util/Iterator; flags 4 signature ()Ljava/util/Iterator; method name serialize descriptor (Ljava/io/ObjectOutputStream;Ljava/util/Collection;)V thrownTypes java/io/IOException flags 14 signature (Ljava/io/ObjectOutputStream;Ljava/util/Collection<*>;)V @@ -2028,10 +2028,10 @@ method name getTagNames descriptor ()Ljava/util/SortedSet; flags 1 signature ()L class name javax/imageio/spi/ImageReaderSpi -field name STANDARD_INPUT_TYPE descriptor [Ljava/lang/Class; -field name inputTypes descriptor [Ljava/lang/Class; -field name STANDARD_INPUT_TYPE descriptor [Ljava/lang/Class; flags 19 deprecated true signature [Ljava/lang/Class<*>; runtimeAnnotations @Ljava/lang/Deprecated; -field name inputTypes descriptor [Ljava/lang/Class; flags 4 signature [Ljava/lang/Class<*>; -method name descriptor (Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/Class;[Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;)V -method name getInputTypes descriptor ()[Ljava/lang/Class; +field name STANDARD_INPUT_TYPE descriptor [Ljava/lang/Class; flags 19 deprecated true signature [Ljava/lang/Class<*>; runtimeAnnotations @Ljava/lang/Deprecated; +field name inputTypes descriptor [Ljava/lang/Class; flags 4 signature [Ljava/lang/Class<*>; method name descriptor (Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/Class;[Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;)V flags 1 signature (Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/Class<*>;[Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;)V method name getInputTypes descriptor ()[Ljava/lang/Class; flags 1 signature ()[Ljava/lang/Class<*>; @@ -2042,10 +2042,10 @@ innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang class name javax/imageio/spi/ImageWriterSpi -field name STANDARD_OUTPUT_TYPE descriptor [Ljava/lang/Class; -field name outputTypes descriptor [Ljava/lang/Class; -field name STANDARD_OUTPUT_TYPE descriptor [Ljava/lang/Class; flags 19 deprecated true signature [Ljava/lang/Class<*>; runtimeAnnotations @Ljava/lang/Deprecated; -field name outputTypes descriptor [Ljava/lang/Class; flags 4 signature [Ljava/lang/Class<*>; -method name descriptor (Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/Class;[Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;)V -method name getOutputTypes descriptor ()[Ljava/lang/Class; +field name STANDARD_OUTPUT_TYPE descriptor [Ljava/lang/Class; flags 19 deprecated true signature [Ljava/lang/Class<*>; runtimeAnnotations @Ljava/lang/Deprecated; +field name outputTypes descriptor [Ljava/lang/Class; flags 4 signature [Ljava/lang/Class<*>; method name descriptor (Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/Class;[Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;)V flags 1 signature (Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/Class<*>;[Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;)V method name getOutputTypes descriptor ()[Ljava/lang/Class; flags 1 signature ()[Ljava/lang/Class<*>; @@ -3485,7 +3485,6 @@ innerclass innerClass javax/swing/JSpinner$NumberEditor outerClass javax/swing/J innerclass innerClass javax/swing/JSpinner$DefaultEditor outerClass javax/swing/JSpinner innerClassName DefaultEditor flags 9 innerclass innerClass javax/swing/JFormattedTextField$AbstractFormatter outerClass javax/swing/JFormattedTextField innerClassName AbstractFormatter flags 409 innerclass innerClass javax/swing/JFormattedTextField$AbstractFormatterFactory outerClass javax/swing/JFormattedTextField innerClassName AbstractFormatterFactory flags 409 -method name setComponentOrientation descriptor (Ljava/awt/ComponentOrientation;)V flags 1 class name javax/swing/JSplitPane header extends javax/swing/JComponent implements javax/accessibility/Accessible flags 21 runtimeAnnotations @Ljava/beans/JavaBean;(defaultProperty="UI") @@ -3592,8 +3591,6 @@ innerclass innerClass javax/swing/UIDefaults$LazyValue outerClass javax/swing/UI innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 -field name defaultRenderersByColumnClass descriptor Ljava/util/Hashtable; -field name defaultEditorsByColumnClass descriptor Ljava/util/Hashtable; -field name defaultRenderersByColumnClass descriptor Ljava/util/Hashtable; flags 84 signature Ljava/util/Hashtable; -field name defaultEditorsByColumnClass descriptor Ljava/util/Hashtable; flags 84 signature Ljava/util/Hashtable; -method name descriptor (Ljava/util/Vector;Ljava/util/Vector;)V -method name setTableHeader descriptor (Ljavax/swing/table/JTableHeader;)V -method name setRowHeight descriptor (I)V @@ -3638,6 +3635,8 @@ field name defaultEditorsByColumnClass descriptor Ljava/util/Hashtable; flags 84 -method name setFillsViewportHeight descriptor (Z)V -method name setCellEditor descriptor (Ljavax/swing/table/TableCellEditor;)V -method name getAccessibleContext descriptor ()Ljavax/accessibility/AccessibleContext; +field name defaultRenderersByColumnClass descriptor Ljava/util/Hashtable; flags 84 signature Ljava/util/Hashtable; +field name defaultEditorsByColumnClass descriptor Ljava/util/Hashtable; flags 84 signature Ljava/util/Hashtable; method name descriptor (Ljava/util/Vector;Ljava/util/Vector;)V flags 1 signature (Ljava/util/Vector<+Ljava/util/Vector;>;Ljava/util/Vector<*>;)V method name setTableHeader descriptor (Ljavax/swing/table/JTableHeader;)V flags 1 runtimeAnnotations @Ljava/beans/BeanProperty;(description="The\u005C;u0020;JTableHeader\u005C;u0020;instance\u005C;u0020;which\u005C;u0020;renders\u005C;u0020;the\u005C;u0020;column\u005C;u0020;headers.") method name setRowHeight descriptor (I)V flags 1 runtimeAnnotations @Ljava/beans/BeanProperty;(description="The\u005C;u0020;height\u005C;u0020;of\u005C;u0020;the\u005C;u0020;specified\u005C;u0020;row.") @@ -4230,12 +4229,12 @@ innerclass innerClass javax/swing/plaf/basic/BasicComboBoxRenderer$UIResource ou innerclass innerClass javax/swing/plaf/basic/BasicComboBoxEditor$UIResource outerClass javax/swing/plaf/basic/BasicComboBoxEditor innerClassName UIResource flags 9 -field name comboBox descriptor Ljavax/swing/JComboBox; -field name listBox descriptor Ljavax/swing/JList; -field name comboBox descriptor Ljavax/swing/JComboBox; flags 4 signature Ljavax/swing/JComboBox; -field name listBox descriptor Ljavax/swing/JList; flags 4 signature Ljavax/swing/JList; -method name createRenderer descriptor ()Ljavax/swing/ListCellRenderer; -method name isPopupVisible descriptor (Ljavax/swing/JComboBox;)Z -method name setPopupVisible descriptor (Ljavax/swing/JComboBox;Z)V -method name isFocusTraversable descriptor (Ljavax/swing/JComboBox;)Z +field name comboBox descriptor Ljavax/swing/JComboBox; flags 4 signature Ljavax/swing/JComboBox; +field name listBox descriptor Ljavax/swing/JList; flags 4 signature Ljavax/swing/JList; method name createRenderer descriptor ()Ljavax/swing/ListCellRenderer; flags 4 signature ()Ljavax/swing/ListCellRenderer; method name isPopupVisible descriptor (Ljavax/swing/JComboBox;)Z flags 1 signature (Ljavax/swing/JComboBox<*>;)Z method name setPopupVisible descriptor (Ljavax/swing/JComboBox;Z)V flags 1 signature (Ljavax/swing/JComboBox<*>;Z)V @@ -4254,13 +4253,13 @@ innerclass innerClass javax/swing/plaf/basic/BasicComboPopup$InvocationMouseMoti innerclass innerClass javax/swing/plaf/basic/BasicComboPopup$InvocationMouseHandler outerClass javax/swing/plaf/basic/BasicComboPopup innerClassName InvocationMouseHandler flags 4 -field name comboBox descriptor Ljavax/swing/JComboBox; -field name list descriptor Ljavax/swing/JList; -field name comboBox descriptor Ljavax/swing/JComboBox; flags 4 signature Ljavax/swing/JComboBox; -field name list descriptor Ljavax/swing/JList; flags 4 signature Ljavax/swing/JList; -method name getList descriptor ()Ljavax/swing/JList; -method name uninstallComboBoxModelListeners descriptor (Ljavax/swing/ComboBoxModel;)V -method name descriptor (Ljavax/swing/JComboBox;)V -method name createList descriptor ()Ljavax/swing/JList; -method name installComboBoxModelListeners descriptor (Ljavax/swing/ComboBoxModel;)V +field name comboBox descriptor Ljavax/swing/JComboBox; flags 4 signature Ljavax/swing/JComboBox; +field name list descriptor Ljavax/swing/JList; flags 4 signature Ljavax/swing/JList; method name getList descriptor ()Ljavax/swing/JList; flags 1 signature ()Ljavax/swing/JList; method name uninstallComboBoxModelListeners descriptor (Ljavax/swing/ComboBoxModel;)V flags 4 signature (Ljavax/swing/ComboBoxModel<*>;)V method name descriptor (Ljavax/swing/JComboBox;)V flags 1 signature (Ljavax/swing/JComboBox;)V @@ -4357,11 +4356,11 @@ innerclass innerClass javax/swing/plaf/basic/BasicListUI$MouseInputHandler outer innerclass innerClass javax/swing/JList$DropLocation outerClass javax/swing/JList innerClassName DropLocation flags 19 innerclass innerClass java/awt/Component$BaselineResizeBehavior outerClass java/awt/Component innerClassName BaselineResizeBehavior flags 4019 -field name list descriptor Ljavax/swing/JList; -field name list descriptor Ljavax/swing/JList; flags 4 signature Ljavax/swing/JList; -method name paintCell descriptor (Ljava/awt/Graphics;ILjava/awt/Rectangle;Ljavax/swing/ListCellRenderer;Ljavax/swing/ListModel;Ljavax/swing/ListSelectionModel;I)V -method name locationToIndex descriptor (Ljavax/swing/JList;Ljava/awt/Point;)I -method name indexToLocation descriptor (Ljavax/swing/JList;I)Ljava/awt/Point; -method name getCellBounds descriptor (Ljavax/swing/JList;II)Ljava/awt/Rectangle; +field name list descriptor Ljavax/swing/JList; flags 4 signature Ljavax/swing/JList; method name paintCell descriptor (Ljava/awt/Graphics;ILjava/awt/Rectangle;Ljavax/swing/ListCellRenderer;Ljavax/swing/ListModel;Ljavax/swing/ListSelectionModel;I)V flags 4 signature (Ljava/awt/Graphics;ILjava/awt/Rectangle;Ljavax/swing/ListCellRenderer;Ljavax/swing/ListModel;Ljavax/swing/ListSelectionModel;I)V method name locationToIndex descriptor (Ljavax/swing/JList;Ljava/awt/Point;)I flags 1 signature (Ljavax/swing/JList<*>;Ljava/awt/Point;)I method name indexToLocation descriptor (Ljavax/swing/JList;I)Ljava/awt/Point; flags 1 signature (Ljavax/swing/JList<*>;I)Ljava/awt/Point; @@ -4615,12 +4614,12 @@ innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang class name javax/swing/plaf/metal/MetalComboBoxButton -field name comboBox descriptor Ljavax/swing/JComboBox; -field name listBox descriptor Ljavax/swing/JList; -field name comboBox descriptor Ljavax/swing/JComboBox; flags 4 signature Ljavax/swing/JComboBox; -field name listBox descriptor Ljavax/swing/JList; flags 4 signature Ljavax/swing/JList; -method name getComboBox descriptor ()Ljavax/swing/JComboBox; -method name setComboBox descriptor (Ljavax/swing/JComboBox;)V -method name descriptor (Ljavax/swing/JComboBox;Ljavax/swing/Icon;Ljavax/swing/CellRendererPane;Ljavax/swing/JList;)V -method name descriptor (Ljavax/swing/JComboBox;Ljavax/swing/Icon;ZLjavax/swing/CellRendererPane;Ljavax/swing/JList;)V +field name comboBox descriptor Ljavax/swing/JComboBox; flags 4 signature Ljavax/swing/JComboBox; +field name listBox descriptor Ljavax/swing/JList; flags 4 signature Ljavax/swing/JList; method name getComboBox descriptor ()Ljavax/swing/JComboBox; flags 11 signature ()Ljavax/swing/JComboBox; method name setComboBox descriptor (Ljavax/swing/JComboBox;)V flags 11 signature (Ljavax/swing/JComboBox;)V method name descriptor (Ljavax/swing/JComboBox;Ljavax/swing/Icon;Ljavax/swing/CellRendererPane;Ljavax/swing/JList;)V flags 1 signature (Ljavax/swing/JComboBox;Ljavax/swing/Icon;Ljavax/swing/CellRendererPane;Ljavax/swing/JList;)V @@ -4740,10 +4739,10 @@ field name uis descriptor Ljava/util/Vector; flags 4 signature Ljava/util/Vector class name javax/swing/plaf/multi/MultiComboBoxUI -field name uis descriptor Ljava/util/Vector; -field name uis descriptor Ljava/util/Vector; flags 4 signature Ljava/util/Vector; -method name isFocusTraversable descriptor (Ljavax/swing/JComboBox;)Z -method name setPopupVisible descriptor (Ljavax/swing/JComboBox;Z)V -method name isPopupVisible descriptor (Ljavax/swing/JComboBox;)Z +field name uis descriptor Ljava/util/Vector; flags 4 signature Ljava/util/Vector; method name isFocusTraversable descriptor (Ljavax/swing/JComboBox;)Z flags 1 signature (Ljavax/swing/JComboBox<*>;)Z method name setPopupVisible descriptor (Ljavax/swing/JComboBox;Z)V flags 1 signature (Ljavax/swing/JComboBox<*>;Z)V method name isPopupVisible descriptor (Ljavax/swing/JComboBox;)Z flags 1 signature (Ljavax/swing/JComboBox<*>;)Z @@ -4770,10 +4769,10 @@ field name uis descriptor Ljava/util/Vector; flags 4 signature Ljava/util/Vector class name javax/swing/plaf/multi/MultiListUI -field name uis descriptor Ljava/util/Vector; -field name uis descriptor Ljava/util/Vector; flags 4 signature Ljava/util/Vector; -method name locationToIndex descriptor (Ljavax/swing/JList;Ljava/awt/Point;)I -method name indexToLocation descriptor (Ljavax/swing/JList;I)Ljava/awt/Point; -method name getCellBounds descriptor (Ljavax/swing/JList;II)Ljava/awt/Rectangle; +field name uis descriptor Ljava/util/Vector; flags 4 signature Ljava/util/Vector; method name locationToIndex descriptor (Ljavax/swing/JList;Ljava/awt/Point;)I flags 1 signature (Ljavax/swing/JList<*>;Ljava/awt/Point;)I method name indexToLocation descriptor (Ljavax/swing/JList;I)Ljava/awt/Point; flags 1 signature (Ljavax/swing/JList<*>;I)Ljava/awt/Point; method name getCellBounds descriptor (Ljavax/swing/JList;II)Ljava/awt/Rectangle; flags 1 signature (Ljavax/swing/JList<*>;II)Ljava/awt/Rectangle; @@ -4852,11 +4851,11 @@ field name uis descriptor Ljava/util/Vector; flags 4 signature Ljava/util/Vector class name javax/swing/plaf/multi/MultiTextUI -field name uis descriptor Ljava/util/Vector; -field name uis descriptor Ljava/util/Vector; flags 4 signature Ljava/util/Vector; -method name modelToView descriptor (Ljavax/swing/text/JTextComponent;I)Ljava/awt/Rectangle; -method name modelToView descriptor (Ljavax/swing/text/JTextComponent;ILjavax/swing/text/Position$Bias;)Ljava/awt/Rectangle; -method name viewToModel descriptor (Ljavax/swing/text/JTextComponent;Ljava/awt/Point;)I -method name viewToModel descriptor (Ljavax/swing/text/JTextComponent;Ljava/awt/Point;[Ljavax/swing/text/Position$Bias;)I +field name uis descriptor Ljava/util/Vector; flags 4 signature Ljava/util/Vector; method name modelToView descriptor (Ljavax/swing/text/JTextComponent;I)Ljava/awt/Rectangle; thrownTypes javax/swing/text/BadLocationException flags 1 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(since="9") method name modelToView descriptor (Ljavax/swing/text/JTextComponent;ILjavax/swing/text/Position$Bias;)Ljava/awt/Rectangle; thrownTypes javax/swing/text/BadLocationException flags 1 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(since="9") method name modelToView2D descriptor (Ljavax/swing/text/JTextComponent;ILjavax/swing/text/Position$Bias;)Ljava/awt/geom/Rectangle2D; thrownTypes javax/swing/text/BadLocationException flags 1 @@ -4982,7 +4981,6 @@ innerclass innerClass javax/swing/JTable$DropLocation outerClass javax/swing/JTa class name javax/swing/table/DefaultTableModel -field name dataVector descriptor Ljava/util/Vector; -field name dataVector descriptor Ljava/util/Vector; flags 4 signature Ljava/util/Vector; -method name descriptor (Ljava/util/Vector;I)V -method name descriptor (Ljava/util/Vector;Ljava/util/Vector;)V -method name getDataVector descriptor ()Ljava/util/Vector; @@ -4993,6 +4991,7 @@ field name dataVector descriptor Ljava/util/Vector; flags 4 signature Ljava/util -method name addColumn descriptor (Ljava/lang/Object;Ljava/util/Vector;)V -method name convertToVector descriptor ([Ljava/lang/Object;)Ljava/util/Vector; -method name convertToVector descriptor ([[Ljava/lang/Object;)Ljava/util/Vector; +field name dataVector descriptor Ljava/util/Vector; flags 4 signature Ljava/util/Vector; method name descriptor (Ljava/util/Vector;I)V flags 1 signature (Ljava/util/Vector<*>;I)V method name descriptor (Ljava/util/Vector;Ljava/util/Vector;)V flags 1 signature (Ljava/util/Vector<+Ljava/util/Vector;>;Ljava/util/Vector<*>;)V method name getDataVector descriptor ()Ljava/util/Vector; flags 1 signature ()Ljava/util/Vector; @@ -5832,13 +5831,13 @@ class name javax/swing/tree/DefaultMutableTreeNode header extends java/lang/Object implements java/lang/Cloneable,javax/swing/tree/MutableTreeNode,java/io/Serializable flags 21 innerclass innerClass java/io/ObjectInputStream$GetField outerClass java/io/ObjectInputStream innerClassName GetField flags 409 -field name children descriptor Ljava/util/Vector; -field name children descriptor Ljava/util/Vector; flags 4 signature Ljava/util/Vector; -method name children descriptor ()Ljava/util/Enumeration; -method name preorderEnumeration descriptor ()Ljava/util/Enumeration; -method name postorderEnumeration descriptor ()Ljava/util/Enumeration; -method name breadthFirstEnumeration descriptor ()Ljava/util/Enumeration; -method name depthFirstEnumeration descriptor ()Ljava/util/Enumeration; -method name pathFromAncestorEnumeration descriptor (Ljavax/swing/tree/TreeNode;)Ljava/util/Enumeration; +field name children descriptor Ljava/util/Vector; flags 4 signature Ljava/util/Vector; method name children descriptor ()Ljava/util/Enumeration; flags 1 signature ()Ljava/util/Enumeration; method name preorderEnumeration descriptor ()Ljava/util/Enumeration; flags 1 signature ()Ljava/util/Enumeration; method name postorderEnumeration descriptor ()Ljava/util/Enumeration; flags 1 signature ()Ljava/util/Enumeration; diff --git a/src/jdk.compiler/share/data/symbols/java.xml.bind-9.sym.txt b/src/jdk.compiler/share/data/symbols/java.xml.bind-9.sym.txt index f6c007544d9..f6a8ebd2f2c 100644 --- a/src/jdk.compiler/share/data/symbols/java.xml.bind-9.sym.txt +++ b/src/jdk.compiler/share/data/symbols/java.xml.bind-9.sym.txt @@ -1,5 +1,5 @@ # -# Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2015, 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 @@ -35,10 +35,10 @@ innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang class name javax/xml/bind/JAXBContext -field name JAXB_CONTEXT_FACTORY descriptor Ljava/lang/String; -field name JAXB_CONTEXT_FACTORY descriptor Ljava/lang/String; constantValue javax.xml.bind.JAXBContextFactory flags 19 -method name newInstance descriptor ([Ljava/lang/Class;)Ljavax/xml/bind/JAXBContext; -method name newInstance descriptor ([Ljava/lang/Class;Ljava/util/Map;)Ljavax/xml/bind/JAXBContext; -method name createValidator descriptor ()Ljavax/xml/bind/Validator; +field name JAXB_CONTEXT_FACTORY descriptor Ljava/lang/String; constantValue javax.xml.bind.JAXBContextFactory flags 19 method name newInstance descriptor ([Ljava/lang/Class;)Ljavax/xml/bind/JAXBContext; thrownTypes javax/xml/bind/JAXBException flags 89 signature ([Ljava/lang/Class<*>;)Ljavax/xml/bind/JAXBContext; method name newInstance descriptor ([Ljava/lang/Class;Ljava/util/Map;)Ljavax/xml/bind/JAXBContext; thrownTypes javax/xml/bind/JAXBException flags 9 signature ([Ljava/lang/Class<*>;Ljava/util/Map;)Ljavax/xml/bind/JAXBContext; method name createValidator descriptor ()Ljavax/xml/bind/Validator; thrownTypes javax/xml/bind/JAXBException flags 401 deprecated true runtimeAnnotations @Ljava/lang/Deprecated; diff --git a/src/jdk.compiler/share/data/symbols/jdk.management-8.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.management-8.sym.txt index ac0bdef06ac..15811f99cb7 100644 --- a/src/jdk.compiler/share/data/symbols/jdk.management-8.sym.txt +++ b/src/jdk.compiler/share/data/symbols/jdk.management-8.sym.txt @@ -1,5 +1,5 @@ # -# Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2015, 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 @@ -91,6 +91,10 @@ method name getThreadAllocatedBytes descriptor ([J)[J flags 401 method name isThreadAllocatedMemorySupported descriptor ()Z flags 401 method name isThreadAllocatedMemoryEnabled descriptor ()Z flags 401 method name setThreadAllocatedMemoryEnabled descriptor (Z)V flags 401 +method name getCurrentThreadAllocatedBytes descriptor ()J flags 1 +method name getTotalThreadAllocatedBytes descriptor ()J flags 1 +method name getThreadInfo descriptor ([JZZI)[Ljava/lang/management/ThreadInfo; flags 1 +method name dumpAllThreads descriptor (ZZI)[Ljava/lang/management/ThreadInfo; flags 1 class name com/sun/management/UnixOperatingSystemMXBean header extends java/lang/Object implements com/sun/management/OperatingSystemMXBean flags 601 classAnnotations @Ljdk/Profile+Annotation;(value=I3) runtimeAnnotations @Ljdk/Exported; diff --git a/src/jdk.compiler/share/data/symbols/jdk.management-9.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.management-9.sym.txt index 6df3114e44a..8ef9e4bb504 100644 --- a/src/jdk.compiler/share/data/symbols/jdk.management-9.sym.txt +++ b/src/jdk.compiler/share/data/symbols/jdk.management-9.sym.txt @@ -1,5 +1,5 @@ # -# Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2015, 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 @@ -48,6 +48,10 @@ header extends java/lang/Object implements java/lang/management/OperatingSystemM class name com/sun/management/ThreadMXBean header extends java/lang/Object implements java/lang/management/ThreadMXBean flags 601 +-method name getCurrentThreadAllocatedBytes descriptor ()J +-method name getTotalThreadAllocatedBytes descriptor ()J +-method name getThreadInfo descriptor ([JZZI)[Ljava/lang/management/ThreadInfo; +-method name dumpAllThreads descriptor (ZZI)[Ljava/lang/management/ThreadInfo; class name com/sun/management/UnixOperatingSystemMXBean header extends java/lang/Object implements com/sun/management/OperatingSystemMXBean flags 601 diff --git a/src/jdk.compiler/share/data/symbols/jdk.net-8.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.net-8.sym.txt new file mode 100644 index 00000000000..a579e8f59ec --- /dev/null +++ b/src/jdk.compiler/share/data/symbols/jdk.net-8.sym.txt @@ -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. 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. +# +# ########################################################## +# ### THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. ### +# ########################################################## +# +class name jdk/net/ExtendedSocketOptions +header extends java/lang/Object flags 31 classAnnotations @Ljdk/Profile+Annotation;(value=I1) runtimeAnnotations @Ljdk/Exported; +field name SO_FLOW_SLA descriptor Ljava/net/SocketOption; flags 19 signature Ljava/net/SocketOption; +field name TCP_KEEPIDLE descriptor Ljava/net/SocketOption; flags 19 signature Ljava/net/SocketOption; +field name TCP_KEEPINTERVAL descriptor Ljava/net/SocketOption; flags 19 signature Ljava/net/SocketOption; +field name TCP_KEEPCOUNT descriptor Ljava/net/SocketOption; flags 19 signature Ljava/net/SocketOption; + +class name jdk/net/NetworkPermission +header extends java/security/BasicPermission flags 31 classAnnotations @Ljdk/Profile+Annotation;(value=I1) runtimeAnnotations @Ljdk/Exported; +method name descriptor (Ljava/lang/String;)V flags 1 +method name descriptor (Ljava/lang/String;Ljava/lang/String;)V flags 1 + +class name jdk/net/SocketFlow +header extends java/lang/Object flags 21 classAnnotations @Ljdk/Profile+Annotation;(value=I1) runtimeAnnotations @Ljdk/Exported; +innerclass innerClass jdk/net/SocketFlow$Status outerClass jdk/net/SocketFlow innerClassName Status flags 4019 +field name NORMAL_PRIORITY descriptor I constantValue 1 flags 19 +field name HIGH_PRIORITY descriptor I constantValue 2 flags 19 +method name create descriptor ()Ljdk/net/SocketFlow; flags 9 +method name priority descriptor (I)Ljdk/net/SocketFlow; flags 1 +method name bandwidth descriptor (J)Ljdk/net/SocketFlow; flags 1 +method name priority descriptor ()I flags 1 +method name bandwidth descriptor ()J flags 1 +method name status descriptor ()Ljdk/net/SocketFlow$Status; flags 1 + +class name jdk/net/SocketFlow$Status +header extends java/lang/Enum flags 4031 signature Ljava/lang/Enum; runtimeAnnotations @Ljdk/Exported; +innerclass innerClass jdk/net/SocketFlow$Status outerClass jdk/net/SocketFlow innerClassName Status flags 4019 +field name NO_STATUS descriptor Ljdk/net/SocketFlow$Status; flags 4019 +field name OK descriptor Ljdk/net/SocketFlow$Status; flags 4019 +field name NO_PERMISSION descriptor Ljdk/net/SocketFlow$Status; flags 4019 +field name NOT_CONNECTED descriptor Ljdk/net/SocketFlow$Status; flags 4019 +field name NOT_SUPPORTED descriptor Ljdk/net/SocketFlow$Status; flags 4019 +field name ALREADY_CREATED descriptor Ljdk/net/SocketFlow$Status; flags 4019 +field name IN_PROGRESS descriptor Ljdk/net/SocketFlow$Status; flags 4019 +field name OTHER descriptor Ljdk/net/SocketFlow$Status; flags 4019 +method name values descriptor ()[Ljdk/net/SocketFlow$Status; flags 9 +method name valueOf descriptor (Ljava/lang/String;)Ljdk/net/SocketFlow$Status; flags 9 + +class name jdk/net/Sockets +header extends java/lang/Object flags 21 classAnnotations @Ljdk/Profile+Annotation;(value=I1) runtimeAnnotations @Ljdk/Exported; +method name setOption descriptor (Ljava/net/Socket;Ljava/net/SocketOption;Ljava/lang/Object;)V thrownTypes java/io/IOException flags 9 signature (Ljava/net/Socket;Ljava/net/SocketOption;TT;)V +method name getOption descriptor (Ljava/net/Socket;Ljava/net/SocketOption;)Ljava/lang/Object; thrownTypes java/io/IOException flags 9 signature (Ljava/net/Socket;Ljava/net/SocketOption;)TT; +method name setOption descriptor (Ljava/net/ServerSocket;Ljava/net/SocketOption;Ljava/lang/Object;)V thrownTypes java/io/IOException flags 9 signature (Ljava/net/ServerSocket;Ljava/net/SocketOption;TT;)V +method name getOption descriptor (Ljava/net/ServerSocket;Ljava/net/SocketOption;)Ljava/lang/Object; thrownTypes java/io/IOException flags 9 signature (Ljava/net/ServerSocket;Ljava/net/SocketOption;)TT; +method name setOption descriptor (Ljava/net/DatagramSocket;Ljava/net/SocketOption;Ljava/lang/Object;)V thrownTypes java/io/IOException flags 9 signature (Ljava/net/DatagramSocket;Ljava/net/SocketOption;TT;)V +method name getOption descriptor (Ljava/net/DatagramSocket;Ljava/net/SocketOption;)Ljava/lang/Object; thrownTypes java/io/IOException flags 9 signature (Ljava/net/DatagramSocket;Ljava/net/SocketOption;)TT; +method name supportedOptions descriptor (Ljava/lang/Class;)Ljava/util/Set; flags 9 signature (Ljava/lang/Class<*>;)Ljava/util/Set;>; + diff --git a/src/jdk.compiler/share/data/symbols/jdk.net-9.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.net-9.sym.txt index d52c33c546a..7db67409789 100644 --- a/src/jdk.compiler/share/data/symbols/jdk.net-9.sym.txt +++ b/src/jdk.compiler/share/data/symbols/jdk.net-9.sym.txt @@ -1,5 +1,5 @@ # -# Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2015, 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 @@ -32,51 +32,26 @@ header exports jdk/net requires name\u0020;java.base\u0020;flags\u0020;8000 flag class name jdk/net/ExtendedSocketOptions header extends java/lang/Object flags 31 innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 -field name SO_FLOW_SLA descriptor Ljava/net/SocketOption; flags 19 signature Ljava/net/SocketOption; +-field name TCP_KEEPIDLE descriptor Ljava/net/SocketOption; +-field name TCP_KEEPINTERVAL descriptor Ljava/net/SocketOption; +-field name TCP_KEEPCOUNT descriptor Ljava/net/SocketOption; class name jdk/net/NetworkPermission header extends java/security/BasicPermission flags 31 -method name descriptor (Ljava/lang/String;)V flags 1 -method name descriptor (Ljava/lang/String;Ljava/lang/String;)V flags 1 class name jdk/net/SocketFlow header extends java/lang/Object flags 21 innerclass innerClass jdk/net/SocketFlow$Status outerClass jdk/net/SocketFlow innerClassName Status flags 4019 innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 field name UNSET descriptor I constantValue -1 flags 19 -field name NORMAL_PRIORITY descriptor I constantValue 1 flags 19 -field name HIGH_PRIORITY descriptor I constantValue 2 flags 19 -method name create descriptor ()Ljdk/net/SocketFlow; flags 9 -method name priority descriptor (I)Ljdk/net/SocketFlow; flags 1 -method name bandwidth descriptor (J)Ljdk/net/SocketFlow; flags 1 -method name priority descriptor ()I flags 1 -method name bandwidth descriptor ()J flags 1 -method name status descriptor ()Ljdk/net/SocketFlow$Status; flags 1 method name toString descriptor ()Ljava/lang/String; flags 1 class name jdk/net/SocketFlow$Status header extends java/lang/Enum flags 4031 signature Ljava/lang/Enum; innerclass innerClass jdk/net/SocketFlow$Status outerClass jdk/net/SocketFlow innerClassName Status flags 4019 innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 -field name NO_STATUS descriptor Ljdk/net/SocketFlow$Status; flags 4019 -field name OK descriptor Ljdk/net/SocketFlow$Status; flags 4019 -field name NO_PERMISSION descriptor Ljdk/net/SocketFlow$Status; flags 4019 -field name NOT_CONNECTED descriptor Ljdk/net/SocketFlow$Status; flags 4019 -field name NOT_SUPPORTED descriptor Ljdk/net/SocketFlow$Status; flags 4019 -field name ALREADY_CREATED descriptor Ljdk/net/SocketFlow$Status; flags 4019 -field name IN_PROGRESS descriptor Ljdk/net/SocketFlow$Status; flags 4019 -field name OTHER descriptor Ljdk/net/SocketFlow$Status; flags 4019 -method name values descriptor ()[Ljdk/net/SocketFlow$Status; flags 9 -method name valueOf descriptor (Ljava/lang/String;)Ljdk/net/SocketFlow$Status; flags 9 class name jdk/net/Sockets header extends java/lang/Object flags 21 innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 -method name setOption descriptor (Ljava/net/Socket;Ljava/net/SocketOption;Ljava/lang/Object;)V thrownTypes java/io/IOException flags 9 signature (Ljava/net/Socket;Ljava/net/SocketOption;TT;)V -method name getOption descriptor (Ljava/net/Socket;Ljava/net/SocketOption;)Ljava/lang/Object; thrownTypes java/io/IOException flags 9 signature (Ljava/net/Socket;Ljava/net/SocketOption;)TT; -method name setOption descriptor (Ljava/net/ServerSocket;Ljava/net/SocketOption;Ljava/lang/Object;)V thrownTypes java/io/IOException flags 9 signature (Ljava/net/ServerSocket;Ljava/net/SocketOption;TT;)V -method name getOption descriptor (Ljava/net/ServerSocket;Ljava/net/SocketOption;)Ljava/lang/Object; thrownTypes java/io/IOException flags 9 signature (Ljava/net/ServerSocket;Ljava/net/SocketOption;)TT; -method name setOption descriptor (Ljava/net/DatagramSocket;Ljava/net/SocketOption;Ljava/lang/Object;)V thrownTypes java/io/IOException flags 9 signature (Ljava/net/DatagramSocket;Ljava/net/SocketOption;TT;)V -method name getOption descriptor (Ljava/net/DatagramSocket;Ljava/net/SocketOption;)Ljava/lang/Object; thrownTypes java/io/IOException flags 9 signature (Ljava/net/DatagramSocket;Ljava/net/SocketOption;)TT; -method name supportedOptions descriptor (Ljava/lang/Class;)Ljava/util/Set; flags 9 signature (Ljava/lang/Class<*>;)Ljava/util/Set;>; diff --git a/src/jdk.compiler/share/data/symbols/symbols b/src/jdk.compiler/share/data/symbols/symbols index 7793033d22f..34619bed887 100644 --- a/src/jdk.compiler/share/data/symbols/symbols +++ b/src/jdk.compiler/share/data/symbols/symbols @@ -30,7 +30,7 @@ #build.tools.symbolgenerator.CreateSymbols build-description-incremental symbols include.list # generate platforms 8:9:A:B:C:D:E:F:G:H:I:J:K:L:M:N:O:P -platform version 8 files java.activation-8.sym.txt:java.base-8.sym.txt:java.compiler-8.sym.txt:java.corba-8.sym.txt:java.datatransfer-8.sym.txt:java.desktop-8.sym.txt:java.instrument-8.sym.txt:java.logging-8.sym.txt:java.management-8.sym.txt:java.management.rmi-8.sym.txt:java.naming-8.sym.txt:java.prefs-8.sym.txt:java.rmi-8.sym.txt:java.scripting-8.sym.txt:java.security.jgss-8.sym.txt:java.security.sasl-8.sym.txt:java.sql-8.sym.txt:java.sql.rowset-8.sym.txt:java.transaction-8.sym.txt:java.xml-8.sym.txt:java.xml.bind-8.sym.txt:java.xml.crypto-8.sym.txt:java.xml.ws-8.sym.txt:java.xml.ws.annotation-8.sym.txt:jdk.httpserver-8.sym.txt:jdk.management-8.sym.txt:jdk.scripting.nashorn-8.sym.txt:jdk.sctp-8.sym.txt:jdk.security.auth-8.sym.txt:jdk.security.jgss-8.sym.txt +platform version 8 files java.activation-8.sym.txt:java.base-8.sym.txt:java.compiler-8.sym.txt:java.corba-8.sym.txt:java.datatransfer-8.sym.txt:java.desktop-8.sym.txt:java.instrument-8.sym.txt:java.logging-8.sym.txt:java.management-8.sym.txt:java.management.rmi-8.sym.txt:java.naming-8.sym.txt:java.prefs-8.sym.txt:java.rmi-8.sym.txt:java.scripting-8.sym.txt:java.security.jgss-8.sym.txt:java.security.sasl-8.sym.txt:java.sql-8.sym.txt:java.sql.rowset-8.sym.txt:java.transaction-8.sym.txt:java.xml-8.sym.txt:java.xml.bind-8.sym.txt:java.xml.crypto-8.sym.txt:java.xml.ws-8.sym.txt:java.xml.ws.annotation-8.sym.txt:jdk.httpserver-8.sym.txt:jdk.management-8.sym.txt:jdk.net-8.sym.txt:jdk.scripting.nashorn-8.sym.txt:jdk.sctp-8.sym.txt:jdk.security.auth-8.sym.txt:jdk.security.jgss-8.sym.txt platform version 9 base 8 files java.activation-9.sym.txt:java.base-9.sym.txt:java.compiler-9.sym.txt:java.corba-9.sym.txt:java.datatransfer-9.sym.txt:java.desktop-9.sym.txt:java.instrument-9.sym.txt:java.logging-9.sym.txt:java.management-9.sym.txt:java.management.rmi-9.sym.txt:java.naming-9.sym.txt:java.prefs-9.sym.txt:java.rmi-9.sym.txt:java.scripting-9.sym.txt:java.se-9.sym.txt:java.se.ee-9.sym.txt:java.security.jgss-9.sym.txt:java.security.sasl-9.sym.txt:java.smartcardio-9.sym.txt:java.sql-9.sym.txt:java.sql.rowset-9.sym.txt:java.transaction-9.sym.txt:java.xml-9.sym.txt:java.xml.bind-9.sym.txt:java.xml.crypto-9.sym.txt:java.xml.ws-9.sym.txt:java.xml.ws.annotation-9.sym.txt:jdk.accessibility-9.sym.txt:jdk.attach-9.sym.txt:jdk.charsets-9.sym.txt:jdk.compiler-9.sym.txt:jdk.crypto.cryptoki-9.sym.txt:jdk.crypto.ec-9.sym.txt:jdk.dynalink-9.sym.txt:jdk.editpad-9.sym.txt:jdk.hotspot.agent-9.sym.txt:jdk.httpserver-9.sym.txt:jdk.incubator.httpclient-9.sym.txt:jdk.jartool-9.sym.txt:jdk.javadoc-9.sym.txt:jdk.jcmd-9.sym.txt:jdk.jconsole-9.sym.txt:jdk.jdeps-9.sym.txt:jdk.jdi-9.sym.txt:jdk.jdwp.agent-9.sym.txt:jdk.jlink-9.sym.txt:jdk.jshell-9.sym.txt:jdk.jsobject-9.sym.txt:jdk.jstatd-9.sym.txt:jdk.localedata-9.sym.txt:jdk.management-9.sym.txt:jdk.management.agent-9.sym.txt:jdk.naming.dns-9.sym.txt:jdk.naming.rmi-9.sym.txt:jdk.net-9.sym.txt:jdk.pack-9.sym.txt:jdk.policytool-9.sym.txt:jdk.rmic-9.sym.txt:jdk.scripting.nashorn-9.sym.txt:jdk.sctp-9.sym.txt:jdk.security.auth-9.sym.txt:jdk.security.jgss-9.sym.txt:jdk.unsupported-9.sym.txt:jdk.xml.dom-9.sym.txt:jdk.zipfs-9.sym.txt platform version A base 9 files java.activation-A.sym.txt:java.base-A.sym.txt:java.compiler-A.sym.txt:java.corba-A.sym.txt:java.datatransfer-A.sym.txt:java.desktop-A.sym.txt:java.instrument-A.sym.txt:java.logging-A.sym.txt:java.management-A.sym.txt:java.management.rmi-A.sym.txt:java.naming-A.sym.txt:java.prefs-A.sym.txt:java.rmi-A.sym.txt:java.scripting-A.sym.txt:java.se-A.sym.txt:java.se.ee-A.sym.txt:java.security.jgss-A.sym.txt:java.security.sasl-A.sym.txt:java.smartcardio-A.sym.txt:java.sql-A.sym.txt:java.sql.rowset-A.sym.txt:java.transaction-A.sym.txt:java.xml-A.sym.txt:java.xml.bind-A.sym.txt:java.xml.crypto-A.sym.txt:java.xml.ws-A.sym.txt:java.xml.ws.annotation-A.sym.txt:jdk.accessibility-A.sym.txt:jdk.attach-A.sym.txt:jdk.charsets-A.sym.txt:jdk.compiler-A.sym.txt:jdk.crypto.cryptoki-A.sym.txt:jdk.crypto.ec-A.sym.txt:jdk.dynalink-A.sym.txt:jdk.editpad-A.sym.txt:jdk.hotspot.agent-A.sym.txt:jdk.httpserver-A.sym.txt:jdk.incubator.httpclient-A.sym.txt:jdk.jartool-A.sym.txt:jdk.javadoc-A.sym.txt:jdk.jcmd-A.sym.txt:jdk.jconsole-A.sym.txt:jdk.jdeps-A.sym.txt:jdk.jdi-A.sym.txt:jdk.jdwp.agent-A.sym.txt:jdk.jlink-A.sym.txt:jdk.jshell-A.sym.txt:jdk.jsobject-A.sym.txt:jdk.jstatd-A.sym.txt:jdk.localedata-A.sym.txt:jdk.management-A.sym.txt:jdk.management.agent-A.sym.txt:jdk.naming.dns-A.sym.txt:jdk.naming.rmi-A.sym.txt:jdk.net-A.sym.txt:jdk.pack-A.sym.txt:jdk.policytool-A.sym.txt:jdk.rmic-A.sym.txt:jdk.scripting.nashorn-A.sym.txt:jdk.sctp-A.sym.txt:jdk.security.auth-A.sym.txt:jdk.security.jgss-A.sym.txt:jdk.unsupported-A.sym.txt:jdk.xml.dom-A.sym.txt:jdk.zipfs-A.sym.txt platform version B base A files java.activation-B.sym.txt:java.base-B.sym.txt:java.compiler-B.sym.txt:java.corba-B.sym.txt:java.datatransfer-B.sym.txt:java.desktop-B.sym.txt:java.instrument-B.sym.txt:java.logging-B.sym.txt:java.management-B.sym.txt:java.management.rmi-B.sym.txt:java.naming-B.sym.txt:java.net.http-B.sym.txt:java.prefs-B.sym.txt:java.rmi-B.sym.txt:java.scripting-B.sym.txt:java.se-B.sym.txt:java.se.ee-B.sym.txt:java.security.jgss-B.sym.txt:java.security.sasl-B.sym.txt:java.smartcardio-B.sym.txt:java.sql-B.sym.txt:java.sql.rowset-B.sym.txt:java.transaction-B.sym.txt:java.transaction.xa-B.sym.txt:java.xml-B.sym.txt:java.xml.bind-B.sym.txt:java.xml.crypto-B.sym.txt:java.xml.ws-B.sym.txt:java.xml.ws.annotation-B.sym.txt:jdk.accessibility-B.sym.txt:jdk.attach-B.sym.txt:jdk.charsets-B.sym.txt:jdk.compiler-B.sym.txt:jdk.crypto.cryptoki-B.sym.txt:jdk.crypto.ec-B.sym.txt:jdk.dynalink-B.sym.txt:jdk.editpad-B.sym.txt:jdk.hotspot.agent-B.sym.txt:jdk.httpserver-B.sym.txt:jdk.incubator.httpclient-B.sym.txt:jdk.jartool-B.sym.txt:jdk.javadoc-B.sym.txt:jdk.jcmd-B.sym.txt:jdk.jconsole-B.sym.txt:jdk.jdeps-B.sym.txt:jdk.jdi-B.sym.txt:jdk.jdwp.agent-B.sym.txt:jdk.jfr-B.sym.txt:jdk.jlink-B.sym.txt:jdk.jshell-B.sym.txt:jdk.jsobject-B.sym.txt:jdk.jstatd-B.sym.txt:jdk.localedata-B.sym.txt:jdk.management-B.sym.txt:jdk.management.agent-B.sym.txt:jdk.management.jfr-B.sym.txt:jdk.naming.dns-B.sym.txt:jdk.naming.rmi-B.sym.txt:jdk.net-B.sym.txt:jdk.pack-B.sym.txt:jdk.rmic-B.sym.txt:jdk.scripting.nashorn-B.sym.txt:jdk.sctp-B.sym.txt:jdk.security.auth-B.sym.txt:jdk.security.jgss-B.sym.txt:jdk.unsupported-B.sym.txt:jdk.xml.dom-B.sym.txt:jdk.zipfs-B.sym.txt diff --git a/src/jdk.compiler/share/man/javac.md b/src/jdk.compiler/share/man/javac.md index 997023487b0..b8243cc78fb 100644 --- a/src/jdk.compiler/share/man/javac.md +++ b/src/jdk.compiler/share/man/javac.md @@ -208,8 +208,8 @@ file system locations may be directories, JAR files or JMOD files. `-deprecation` option is shorthand for `-Xlint:deprecation`. `--enable-preview` -: Enables preview language features. Used in conjunction with either - [`-source`](#option-source) or [`--release`](#option-release). +: Enables preview language features. Also disables the `preview` lint category. + Used in conjunction with either [`-source`](#option-source) or [`--release`](#option-release). `-encoding` *encoding* : Specifies character encoding used by source files, such as EUC-JP and @@ -557,11 +557,11 @@ file system locations may be directories, JAR files or JMOD files. section of the `javadoc` command documentation. `-Xlint` -: Enables all recommended warnings. In this release, enabling all available - warnings is recommended. +: Enables recommended lint warning categories. In this release, all available + lint warning categories are recommended. `-Xlint:`\[`-`\]*key*(`,`\[`-`\]*key*)\* -: Enables and/or disables warning categories using the one or more of the keys described +: Enables and/or disables lint warning categories using the one or more of the keys described below separated by commas. The keys `all` and `none` enable or disable all categories (respectively); other keys enable the corresponding category, or disable it if preceded by a hyphen (`-`). @@ -648,10 +648,9 @@ file system locations may be directories, JAR files or JMOD files. - `strictfp`: Warns about unnecessary use of the `strictfp` modifier. - - `synchronization`: Warns about synchronization attempts on instances - of value-based classes. This key is a deprecated alias for `identity`, - which has the same uses and effects. Users are encouraged to use the - `identity` category for all future and existing uses of `synchronization`. + - `synchronization`: Deprecated alias for `identity` with an identical + effect. Users are encouraged to use `identity` instead of `synchronization` + for all current and future uses. - `text-blocks`: Warns about inconsistent white space characters in text block indentation. @@ -667,9 +666,13 @@ file system locations may be directories, JAR files or JMOD files. - `none`: Disables all warning categories. - With the exception of `all` and `none`, the keys can be used with - the `@SuppressWarnings` annotation to suppress warnings in a part - of the source code being compiled. + The keys listed above may be used in `@SuppressWarnings` annotations to suppress + warnings within the annotated declaration, with the exception of: `all`, `none`, + `classfile`, `incubating`, `options`, `output-file-clash`, `processing`, and `path`. + + By default, the following lint warning categories are enabled: `dep-ann`, `identity`, + `incubating`, `module`, `opens`, `preview`, `removal`, `requires-transitive-automatic`, + and `strictfp`. See [Examples of Using -Xlint keys]. diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Mark.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Mark.java index 1ea34fe6cd2..c41372810a3 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Mark.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Mark.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -151,12 +151,6 @@ public boolean mustBePreserved() { public boolean hasLocker() { return ((value() & lockMaskInPlace) == lockedValue); } - public BasicLock locker() { - if (Assert.ASSERTS_ENABLED) { - Assert.that(hasLocker(), "check"); - } - return new BasicLock(valueAsAddress()); - } public boolean hasMonitor() { return ((value() & monitorValue) != 0); } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/BasicLock.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/BasicLock.java index 979e08cfb8a..6ca53b4c545 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/BasicLock.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/BasicLock.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -36,23 +36,11 @@ public class BasicLock extends VMObject { static { VM.registerVMInitializedObserver(new Observer() { public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); } }); } - private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { - Type type = db.lookupType("BasicLock"); - displacedHeaderField = type.getCIntegerField("_metadata"); - } - - private static CIntegerField displacedHeaderField; - public BasicLock(Address addr) { super(addr); } - - public Mark displacedHeader() { - return new Mark(addr.addOffsetTo(displacedHeaderField.getOffset())); - } } diff --git a/src/jdk.hotspot.agent/test/libproc/LibprocClient.java b/src/jdk.hotspot.agent/test/libproc/LibprocClient.java deleted file mode 100644 index 751c23ee92f..00000000000 --- a/src/jdk.hotspot.agent/test/libproc/LibprocClient.java +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -import sun.jvm.hotspot.oops.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.tools.*; -import sun.jvm.hotspot.utilities.*; - -/** - We don't run any of the "standard" SA command line tools for sanity - check. This is because the standard tools print addresses in hex - which could change legally. Also, textual comparison of output may - not match because of other reasons as well. This tool checks - validity of threads and frames logically. This class has reference - frame names from "known" threads. The debuggee is assumed to run - "LibprocTest.java". -*/ - -public class LibprocClient extends Tool { - - public void run() { - // try to get VM version and check - String version = VM.getVM().getVMRelease(); - Assert.that(version.startsWith("1.5"), "1.5 expected"); - - // try getting threads - Threads threads = VM.getVM().getThreads(); - boolean mainTested = false; - - // check frames of each thread - for (JavaThread cur = threads.first(); cur != null; cur = cur.next()) { - if (cur.isJavaThread()) { - String name = cur.getThreadName(); - // testing of basic frame walking for all threads - for (JavaVFrame vf = getLastJavaVFrame(cur); vf != null; vf = vf.javaSender()) { - checkFrame(vf); - } - - // special testing for "known" threads. For now, only "main" thread. - if (name.equals("main")) { - checkMainThread(cur); - mainTested = true; - } - } - } - Assert.that(mainTested, "main thread missing"); - } - - public static void main(String[] args) { - try { - LibprocClient lc = new LibprocClient(); - lc.start(args); - lc.getAgent().detach(); - System.out.println("\nPASSED\n"); - } catch (Exception exp) { - System.out.println("\nFAILED\n"); - exp.printStackTrace(); - } - } - - // -- Internals only below this point - private static JavaVFrame getLastJavaVFrame(JavaThread cur) { - RegisterMap regMap = cur.newRegisterMap(true); - Frame f = cur.getCurrentFrameGuess(); - if (f == null) { - System.err.println(" (Unable to get a top most frame)"); - return null; - } - VFrame vf = VFrame.newVFrame(f, regMap, cur, true, true); - if (vf == null) { - System.err.println(" (Unable to create vframe for topmost frame guess)"); - return null; - } - if (vf.isJavaFrame()) { - return (JavaVFrame) vf; - } - return (JavaVFrame) vf.javaSender(); - } - - private void checkMethodSignature(Symbol sig) { - SignatureIterator itr = new SignatureIterator(sig) { - public void doBool () {} - public void doChar () {} - public void doFloat () {} - public void doDouble() {} - public void doByte () {} - public void doShort () {} - public void doInt () {} - public void doLong () {} - public void doVoid () {} - public void doObject(int begin, int end) {} - public void doArray (int begin, int end) {} - }; - // this will throw RuntimeException for any invalid item in signature. - itr.iterate(); - } - - private void checkBCI(Method m, int bci) { - if (! m.isNative()) { - byte[] buf = m.getByteCode(); - Assert.that(bci >= 0 && bci < buf.length, "invalid bci, not in code range"); - if (m.hasLineNumberTable()) { - int lineNum = m.getLineNumberFromBCI(bci); - Assert.that(lineNum >= 0, "expecting non-negative line number"); - } - } - } - - private void checkMethodHolder(Method method) { - Klass klass = method.getMethodHolder(); - Assert.that(klass != null, "expecting non-null instance klass"); - } - - private void checkFrame(JavaVFrame vf) { - Method method = vf.getMethod(); - Assert.that(method != null, "expecting a non-null method here"); - Assert.that(method.getName() != null, "expecting non-null method name"); - checkMethodHolder(method); - checkMethodSignature(method.getSignature()); - checkBCI(method, vf.getBCI()); - } - - // from the test case LibprocTest.java - in the main thread we - // should see frames as below - private static String[] mainThreadMethods = new String[] { - "java.lang.Object.wait(long)", - "java.lang.Object.wait()", - "LibprocTest.main(java.lang.String[])" - }; - - private void checkMainThread(JavaThread thread) { - checkFrames(thread, mainThreadMethods); - } - - private void checkFrames(JavaThread thread, String[] expectedMethodNames) { - int i = 0; - for (JavaVFrame vf = getLastJavaVFrame(thread); vf != null; vf = vf.javaSender(), i++) { - Method m = vf.getMethod(); - Assert.that(m.externalNameAndSignature().equals(expectedMethodNames[i]), - "expected frame missing"); - } - } -} diff --git a/src/jdk.hotspot.agent/test/libproc/Makefile b/src/jdk.hotspot.agent/test/libproc/Makefile deleted file mode 100644 index c7b171bc633..00000000000 --- a/src/jdk.hotspot.agent/test/libproc/Makefile +++ /dev/null @@ -1,30 +0,0 @@ -# -# Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# 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. -# -# - -all: - javac LibprocTest.java - javac -classpath ../../build/classes LibprocClient.java - -clean: - rm -rf *.class diff --git a/src/jdk.hotspot.agent/test/libproc/README b/src/jdk.hotspot.agent/test/libproc/README deleted file mode 100644 index 928c43d3fe7..00000000000 --- a/src/jdk.hotspot.agent/test/libproc/README +++ /dev/null @@ -1,42 +0,0 @@ -# -# Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute 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. -# -# - -After making any changes to libproc.so, the shell scripts described -below can be run to verify that it does not break Java Serviceability -Agent. - -Setup: - -You need to have jdk 1.5 installed to run this test. Set environment -variable SA_JAVA to point to the java executable of jdk -1.5. Otherwise, the script picks-up 'java' from PATH. - -Running the tests: - -run libproctest.sh (32-bit debuggee) and libproctest64.sh (64-bit -debuggee) - -Interpreting result: - -"PASSED" or "FAILED" is printed in standard output. diff --git a/src/jdk.hotspot.agent/test/libproc/libproctest.sh b/src/jdk.hotspot.agent/test/libproc/libproctest.sh deleted file mode 100644 index 0ed1d1a4cf4..00000000000 --- a/src/jdk.hotspot.agent/test/libproc/libproctest.sh +++ /dev/null @@ -1,66 +0,0 @@ -#!/bin/ksh - -# -# Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# -# - -# This script is used to run consistency check of Serviceabilty Agent -# after making any libproc.so changes. Prints "PASSED" or "FAILED" in -# standard output. - -usage() { - echo "usage: $0" - echo " set SA_JAVA to be java executable from JDK 1.5" - exit 1 -} - -STARTDIR=`dirname $0` - -if [ "$1" == "-help" ]; then - usage -fi - -if [ "x$SA_JAVA" = "x" ]; then - SA_JAVA=java -fi - -# create java process with test case -tmp=/tmp/libproctest -rm -f $tmp -$SA_JAVA -classpath $STARTDIR LibprocTest > $tmp & -pid=$! -while [ ! -s $tmp ] ; do - # Kludge alert! - sleep 2 -done - -# dump core -gcore $pid -kill -9 $pid - - -# run libproc client -$SA_JAVA -showversion -cp $STARTDIR/../../build/classes::$STARTDIR/../sa.jar:$STARTDIR LibprocClient x core.$pid - -# delete core -rm -f core.$pid diff --git a/src/jdk.hotspot.agent/test/libproc/libproctest64.sh b/src/jdk.hotspot.agent/test/libproc/libproctest64.sh deleted file mode 100644 index 7791190743b..00000000000 --- a/src/jdk.hotspot.agent/test/libproc/libproctest64.sh +++ /dev/null @@ -1,65 +0,0 @@ -#!/bin/ksh - -# -# Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# -# - -# This script is used to run consistency check of Serviceabilty Agent -# after making any libproc.so changes. Prints "PASSED" or "FAILED" in -# standard output. - -usage() { - echo "usage: $0" - echo " set SA_JAVA to be the java executable from JDK 1.5" - exit 1 -} - -if [ "$1" == "-help" ]; then - usage -fi - -if [ "x$SA_JAVA" = "x" ]; then - SA_JAVA=java -fi - -STARTDIR=`dirname $0` - -# create java process with test case -tmp=/tmp/libproctest -rm -f $tmp -$SA_JAVA -d64 -classpath $STARTDIR LibprocTest > $tmp & -pid=$! -while [ ! -s $tmp ] ; do - # Kludge alert! - sleep 2 -done - -# dump core -gcore $pid -kill -9 $pid - -# run libproc client -$SA_JAVA -d64 -showversion -cp $STARTDIR/../../build/classes::$STARTDIR/../sa.jar:$STARTDIR LibprocClient x core.$pid - -# delete core -rm -f core.$pid diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float16.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float16.java index 45dd52175cc..b75adf350b6 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float16.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float16.java @@ -146,6 +146,10 @@ private Float16(short bits) { */ public static final Float16 NaN = valueOf(Float.NaN); + private static final Float16 ZERO = valueOf(0); + + private static final Float16 ONE = valueOf(1); + /** * A constant holding the largest positive finite value of type * {@code Float16}, @@ -222,6 +226,16 @@ private Float16(short bits) { */ public static final int BYTES = SIZE / Byte.SIZE; + /** + * The overflow threshold (for round to nearest) is MAX_VALUE + 1/2 ulp. + */ + private static final double OVERFLOW_THRESH = 0x1.ffcp15 + 0x0.002p15; + + /** + * The underflow threshold (for round to nearest) is MIN_VALUE * 0.5. + */ + private static final double UNDERFLOW_THRESH = 0x1.0p-24d * 0.5d; + /** * Returns a string representation of the {@code Float16} * argument. @@ -340,51 +354,51 @@ public static Float16 valueOf(float f) { * @param d a {@code double} */ public static Float16 valueOf(double d) { - long doppel = Double.doubleToRawLongBits(d); - - short sign_bit = (short)((doppel & 0x8000_0000_0000_0000L) >> 48); - if (Double.isNaN(d)) { // Have existing float code handle any attempts to // preserve NaN bits. return valueOf((float)d); } + long doppel = Double.doubleToRawLongBits(d); + short sign_bit = (short)((doppel & 0x8000_0000_0000_0000L) >> (64 - 16)); double abs_d = Math.abs(d); - // The overflow threshold is binary16 MAX_VALUE + 1/2 ulp - if (abs_d >= (0x1.ffcp15 + 0x0.002p15) ) { + if (abs_d >= OVERFLOW_THRESH) { // correctly signed infinity return new Float16((short)(sign_bit | 0x7c00)); } - // Smallest magnitude nonzero representable binary16 value - // is equal to 0x1.0p-24; half-way and smaller rounds to zero. - if (abs_d <= 0x1.0p-24d * 0.5d) { // Covers double zeros and subnormals. - return new Float16(sign_bit); // Positive or negative zero + if (abs_d <= UNDERFLOW_THRESH) { // Covers double zeros and subnormals. + // positive or negative zero + return new Float16(sign_bit); } // Dealing with finite values in exponent range of binary16 // (when rounding is done, could still round up) int exp = Math.getExponent(d); - assert -25 <= exp && exp <= 15; - - // For binary16 subnormals, beside forcing exp to -15, retain - // the difference expdelta = E_min - exp. This is the excess - // shift value, in addition to 42, to be used in the + assert + (MIN_EXPONENT - PRECISION) <= exp && + exp <= MAX_EXPONENT; + + // For target format subnormals, beside forcing exp to + // MIN_EXPONENT-1, retain the difference expdelta = E_min - + // exp. This is the excess shift value, in addition to the + // difference in precision bits, to be used in the // computations below. Further the (hidden) msb with value 1 // in d must be involved as well. int expdelta = 0; long msb = 0x0000_0000_0000_0000L; - if (exp < -14) { - expdelta = -14 - exp; // FIXME? - exp = -15; - msb = 0x0010_0000_0000_0000L; // should be 0x0020_... ? + if (exp < MIN_EXPONENT) { + expdelta = MIN_EXPONENT - exp; + exp = MIN_EXPONENT - 1; + msb = 0x0010_0000_0000_0000L; } long f_signif_bits = doppel & 0x000f_ffff_ffff_ffffL | msb; + int PRECISION_DIFF = Double.PRECISION - PRECISION; // 42 // Significand bits as if using rounding to zero (truncation). - short signif_bits = (short)(f_signif_bits >> (42 + expdelta)); + short signif_bits = (short)(f_signif_bits >> (PRECISION_DIFF + expdelta)); // For round to nearest even, determining whether or not to // round up (in magnitude) is a function of the least @@ -399,9 +413,9 @@ public static Float16 valueOf(double d) { // 1 1 1 // See "Computer Arithmetic Algorithms," Koren, Table 4.9 - long lsb = f_signif_bits & (1L << 42 + expdelta); - long round = f_signif_bits & (1L << 41 + expdelta); - long sticky = f_signif_bits & ((1L << 41 + expdelta) - 1); + long lsb = f_signif_bits & (1L << (PRECISION_DIFF + expdelta)); + long round = f_signif_bits & (1L << (PRECISION_DIFF - 1) + expdelta); + long sticky = f_signif_bits & ((1L << (PRECISION_DIFF - 1) + expdelta) - 1); if (round != 0 && ((lsb | sticky) != 0 )) { signif_bits++; @@ -412,7 +426,9 @@ public static Float16 valueOf(double d) { // to implement a carry out from rounding the significand. assert (0xf800 & signif_bits) == 0x0; - return new Float16((short)(sign_bit | ( ((exp + 15) << 10) + signif_bits ) )); + // Exponent bias adjust in the representation is equal to MAX_EXPONENT. + return new Float16((short)(sign_bit | + ( ((exp + MAX_EXPONENT) << (PRECISION - 1)) + signif_bits ) )); } /** @@ -600,7 +616,7 @@ private class BigDecimalConversion { * Float16}. */ private static final Float16[] FLOAT16_10_POW = { - Float16.valueOf(1), Float16.valueOf(10), Float16.valueOf(100), + Float16.ONE, Float16.valueOf(10), Float16.valueOf(100), Float16.valueOf(1_000), Float16.valueOf(10_000) }; @@ -637,14 +653,14 @@ private static BigInteger bigTenToThe(int scale) { private static Float16 fullFloat16Value(BigDecimal bd) { if (BigDecimal.ZERO.compareTo(bd) == 0) { - return Float16.valueOf(0); + return ZERO; } BigInteger w = bd.unscaledValue().abs(); int scale = bd.scale(); long qb = w.bitLength() - (long) Math.ceil(scale * L); Float16 signum = Float16.valueOf(bd.signum()); if (qb < Q_MIN_F16 - 2) { // qb < -26 - return Float16.multiply(signum, Float16.valueOf(0)); + return Float16.multiply(signum, ZERO); } if (qb > Q_MAX_F16 + P_F16 + 1) { // qb > 17 return Float16.multiply(signum, Float16.POSITIVE_INFINITY); @@ -717,7 +733,7 @@ public static Float16 valueOf(BigInteger bi) { public static boolean isNaN(Float16 f16) { final short bits = float16ToRawShortBits(f16); // A NaN value has all ones in its exponent and a non-zero significand - return ((bits & 0x7c00) == 0x7c00 && (bits & 0x03ff) != 0); + return ((bits & EXP_BIT_MASK) == EXP_BIT_MASK && (bits & SIGNIF_BIT_MASK) != 0); } /** @@ -736,8 +752,9 @@ public static boolean isNaN(Float16 f16) { * @see Double#isInfinite(double) */ public static boolean isInfinite(Float16 f16) { - return ((float16ToRawShortBits(f16) ^ - float16ToRawShortBits(POSITIVE_INFINITY)) & 0x7fff) == 0; + final short bits = float16ToRawShortBits(f16); + // An infinite value has all ones in its exponent and a zero significand + return ((bits & EXP_BIT_MASK) == EXP_BIT_MASK && (bits & SIGNIF_BIT_MASK) == 0); } /** @@ -757,7 +774,7 @@ public static boolean isInfinite(Float16 f16) { * @see Double#isFinite(double) */ public static boolean isFinite(Float16 f16) { - return (float16ToRawShortBits(f16) & (short)0x0000_7FFF) <= + return (float16ToRawShortBits(f16) & (EXP_BIT_MASK | SIGNIF_BIT_MASK)) <= float16ToRawShortBits(MAX_VALUE); } @@ -1551,7 +1568,7 @@ public static Float16 ulp(Float16 f16) { assert exp <= MAX_EXPONENT && exp >= MIN_EXPONENT; // ulp(x) is usually 2^(SIGNIFICAND_WIDTH-1)*(2^ilogb(x)) // Let float -> float16 conversion handle encoding issues. - yield scalb(valueOf(1), exp - (PRECISION - 1)); + yield scalb(ONE, exp - (PRECISION - 1)); } }; } @@ -1673,7 +1690,7 @@ public static Float16 scalb(Float16 v, int scaleFactor) { Float16Consts.SIGNIFICAND_WIDTH + 1; // Make sure scaling factor is in a reasonable range - scaleFactor = Math.max(Math.min(scaleFactor, MAX_SCALE), -MAX_SCALE); + scaleFactor = Math.clamp(scaleFactor, -MAX_SCALE, MAX_SCALE); int DoubleConsts_EXP_BIAS = 1023; /* @@ -1731,7 +1748,7 @@ public static Float16 copySign(Float16 magnitude, Float16 sign) { * @see Math#signum(double) */ public static Float16 signum(Float16 f) { - return (f.floatValue() == 0.0f || isNaN(f)) ? f : copySign(valueOf(1), f); + return (f.floatValue() == 0.0f || isNaN(f)) ? f : copySign(ONE, f); } // TODO: Temporary location for this functionality while Float16 diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/query/QueryPrinter.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/query/QueryPrinter.java index 0d0310dae5b..9d0ce279abd 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/query/QueryPrinter.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/query/QueryPrinter.java @@ -280,12 +280,14 @@ public static String getGrammarText() { MEDIAN: The numeric median MIN: The numeric minimum P90, P95, P99, P999: The numeric percentile, 90%, 95%, 99% or 99.9% + SET: All unique values in a comma-separated list STDEV: The numeric standard deviation SUM: The numeric sum UNIQUE: The unique number of occurrences of a value Null values are included, but ignored for numeric functions. If no aggregator function is specified, the first non-null value is used. - property, any of the following: + none No formatting for the column cell-height: Maximum height of a table cell missing:whitespace Replace missing values (N/A) with blank space normalized Normalize values between 0 and 1.0 for the column diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/query/view.ini b/src/jdk.jfr/share/classes/jdk/jfr/internal/query/view.ini index 1ab9840b28e..91decb1aa20 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/query/view.ini +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/query/view.ini @@ -290,18 +290,16 @@ table = "SELECT finalizableClass, LAST_BATCH(objects) AS O, LAST_BATCH(totalFina [jvm.gc] label = "Garbage Collections" -table = "COLUMN 'Start', 'GC ID', 'Type', 'Heap Before GC', 'Heap After GC', 'Longest Pause' +table = "COLUMN 'Start', 'GC ID', 'GC Name', 'Heap Before GC', 'Heap After GC', 'Longest Pause' FORMAT none, none, missing:Unknown, none, none, none - SELECT G.startTime, gcId, [Y|O].eventType.label, + SELECT G.startTime, gcId, G.name, B.heapUsed, A.heapUsed, longestPause FROM GarbageCollection AS G, GCHeapSummary AS B, - GCHeapSummary AS A, - OldGarbageCollection AS O, - YoungGarbageCollection AS Y + GCHeapSummary AS A WHERE B.when = 'Before GC' AND A.when = 'After GC' - GROUP BY gcId ORDER BY G.startTime" + GROUP BY gcId ORDER BY gcId" [jvm.gc-concurrent-phases] label = "Concurrent GC Phases" diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Query.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Query.java index d350b4215bf..ec0407a6f04 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Query.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Query.java @@ -73,27 +73,26 @@ public void displayOptionUsage(PrintStream p) { p.println(); p.println(" $ jfr query --verbose \"SELECT * FROM ObjectAllocationSample\" recording.jfr"); p.println(); - p.println(" $ jfr query --width 160 \"SELECT pid, path FROM SystemProcess\" recording.jfr"); + p.println(" $ jfr query --width 160 \"SELECT pid, commandLine FROM SystemProcess\" recording.jfr"); p.println(); p.println(" $ jfr query \"SELECT stackTrace.topFrame AS T, SUM(weight)"); p.println(" FROM ObjectAllocationSample GROUP BY T\" recording.jfr"); p.println(); - p.println("$ jfr JFR.query \"COLUMN 'Method', 'Percentage'"); - p.println(" FORMAT default, normalized;width:10"); - p.println(" SELECT stackTrace.topFrame AS T, COUNT(*) AS C"); - p.println(" GROUP BY T"); - p.println(" FROM ExecutionSample ORDER BY C DESC\" recording.jfr"); + p.println(" $ jfr query \"COLUMN 'Method', 'Percentage'"); + p.println(" FORMAT none, normalized"); + p.println(" SELECT stackTrace.topFrame AS T, COUNT(*) AS C"); + p.println(" FROM ExecutionSample GROUP BY T ORDER BY C DESC\" recording.jfr"); p.println(); - p.println("$ jcmd JFR.query \"COLUMN 'Start', 'GC ID', 'Heap Before GC',"); - p.println(" 'Heap After GC', 'Longest Pause'"); - p.println(" SELECT G.startTime, G.gcId, B.heapUsed,"); - p.println(" A.heapUsed, longestPause"); - p.println(" FROM GarbageCollection AS G,"); - p.println(" GCHeapSummary AS B,"); - p.println(" GCHeapSummary AS A"); - p.println(" WHERE B.when = 'Before GC' AND A.when = 'After GC'"); - p.println(" GROUP BY gcId"); - p.println(" ORDER BY G.startTime\" recording.jfr"); + p.println(" $ jfr query \"COLUMN 'Start', 'GC ID', 'Heap Before GC',"); + p.println(" 'Heap After GC', 'Longest Pause'"); + p.println(" SELECT G.startTime, G.gcId, B.heapUsed,"); + p.println(" A.heapUsed, longestPause"); + p.println(" FROM GarbageCollection AS G,"); + p.println(" GCHeapSummary AS B,"); + p.println(" GCHeapSummary AS A"); + p.println(" WHERE B.when = 'Before GC' AND A.when = 'After GC'"); + p.println(" GROUP BY gcId"); + p.println(" ORDER BY gcId\" recording.jfr"); p.println(); p.println("************************************ WARNING ******************************************"); p.println("The query command is only available in debug builds and is targeted towards OpenJDK"); diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java index 2d0c78c2474..790d5d877aa 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java @@ -31,6 +31,7 @@ import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; +import java.io.UncheckedIOException; import java.nio.file.Path; import java.util.ArrayList; import java.util.Arrays; @@ -67,7 +68,7 @@ final class DesktopIntegration extends ShellCustomAction { private static final List REPLACEMENT_STRING_IDS = List.of( COMMANDS_INSTALL, COMMANDS_UNINSTALL, SCRIPTS, COMMON_SCRIPTS); - private DesktopIntegration(BuildEnv env, LinuxPackage pkg, LinuxLauncher launcher) throws IOException { + private DesktopIntegration(BuildEnv env, LinuxPackage pkg, LinuxLauncher launcher) { associations = launcher.fileAssociations().stream().map( LinuxFileAssociation::create).toList(); @@ -88,10 +89,14 @@ private DesktopIntegration(BuildEnv env, LinuxPackage pkg, LinuxLauncher launche // This is additional launcher with explicit `no icon` configuration. withDesktopFile = false; } else { - final Path nullPath = null; - if (curIconResource.get().saveToFile(nullPath) != OverridableResource.Source.DefaultResource) { - // This launcher has custom icon configured. - withDesktopFile = true; + try { + if (curIconResource.get().saveToFile((Path)null) != OverridableResource.Source.DefaultResource) { + // This launcher has custom icon configured. + withDesktopFile = true; + } + } catch (IOException ex) { + // Should never happen as `saveToFile((Path)null)` should not perform any actual I/O operations. + throw new UncheckedIOException(ex); } } @@ -135,13 +140,13 @@ private DesktopIntegration(BuildEnv env, LinuxPackage pkg, LinuxLauncher launche return (LinuxLauncher)v; }).filter(l -> { return toRequest(l.shortcut()).orElse(true); - }).map(toFunction(l -> { + }).map(l -> { return new DesktopIntegration(env, pkg, l); - })).toList(); + }).toList(); } } - static ShellCustomAction create(BuildEnv env, Package pkg) throws IOException { + static ShellCustomAction create(BuildEnv env, Package pkg) { if (pkg.isRuntimeInstaller()) { return ShellCustomAction.nop(REPLACEMENT_STRING_IDS); } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java index d5b369ba23a..9e2ea63cc32 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebBundler.java @@ -25,362 +25,19 @@ package jdk.jpackage.internal; -import jdk.jpackage.internal.model.LinuxPackage; -import jdk.jpackage.internal.model.PackagerException; -import jdk.jpackage.internal.model.ConfigException; -import jdk.jpackage.internal.model.LinuxDebPackage; -import java.io.IOException; -import java.nio.file.FileVisitResult; -import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.SimpleFileVisitor; -import java.nio.file.attribute.BasicFileAttributes; - -import java.nio.file.attribute.PosixFilePermission; -import java.nio.file.attribute.PosixFilePermissions; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; import java.util.Map; -import java.util.Set; -import java.util.function.Function; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import jdk.internal.util.OperatingSystem; -import jdk.jpackage.internal.model.AppImageLayout; -import static jdk.jpackage.internal.util.function.ThrowingFunction.toFunction; -import static jdk.jpackage.internal.model.StandardPackageType.LINUX_DEB; +import jdk.jpackage.internal.model.LinuxDebPackage; +import jdk.jpackage.internal.model.PackagerException; +import jdk.jpackage.internal.model.StandardPackageType; +import jdk.jpackage.internal.util.Result; public class LinuxDebBundler extends LinuxPackageBundler { - private static final String TOOL_DPKG_DEB = "dpkg-deb"; - private static final String TOOL_DPKG = "dpkg"; - private static final String TOOL_FAKEROOT = "fakeroot"; - public LinuxDebBundler() { super(LinuxFromParams.DEB_PACKAGE); } - @Override - protected void doValidate(BuildEnv env, LinuxPackage pkg) throws ConfigException { - - // Show warning if license file is missing - if (pkg.licenseFile().isEmpty()) { - Log.verbose(I18N.getString("message.debs-like-licenses")); - } - } - - @Override - protected List getToolValidators() { - return Stream.of(TOOL_DPKG_DEB, TOOL_DPKG, TOOL_FAKEROOT).map( - ToolValidator::new).toList(); - } - - @Override - protected void createConfigFiles(Map replacementData, - BuildEnv env, LinuxPackage pkg) throws IOException { - prepareProjectConfig(replacementData, env, pkg); - adjustPermissionsRecursive(env.appImageDir()); - } - - @Override - protected Path buildPackageBundle(BuildEnv env, LinuxPackage pkg, - Path outputParentDir) throws PackagerException, IOException { - return buildDeb(env, pkg, outputParentDir); - } - - private static final Pattern PACKAGE_NAME_REGEX = Pattern.compile("^(^\\S+):"); - - @Override - protected void initLibProvidersLookup(LibProvidersLookup libProvidersLookup) { - - libProvidersLookup.setPackageLookup(file -> { - Path realPath = file.toRealPath(); - - try { - // Try the real path first as it works better on newer Ubuntu versions - return findProvidingPackages(realPath); - } catch (IOException ex) { - // Try the default path if differ - if (!realPath.toString().equals(file.toString())) { - return findProvidingPackages(file); - } else { - throw ex; - } - } - }); - } - - private static Stream findProvidingPackages(Path file) throws IOException { - // - // `dpkg -S` command does glob pattern lookup. If not the absolute path - // to the file is specified it might return mltiple package names. - // Even for full paths multiple package names can be returned as - // it is OK for multiple packages to provide the same file. `/opt` - // directory is such an example. So we have to deal with multiple - // packages per file situation. - // - // E.g.: `dpkg -S libc.so.6` command reports three packages: - // libc6-x32: /libx32/libc.so.6 - // libc6:amd64: /lib/x86_64-linux-gnu/libc.so.6 - // libc6-i386: /lib32/libc.so.6 - // `:amd64` is architecture suffix and can (should) be dropped. - // Still need to decide what package to choose from three. - // libc6-x32 and libc6-i386 both depend on libc6: - // $ dpkg -s libc6-x32 - // Package: libc6-x32 - // Status: install ok installed - // Priority: optional - // Section: libs - // Installed-Size: 10840 - // Maintainer: Ubuntu Developers - // Architecture: amd64 - // Source: glibc - // Version: 2.23-0ubuntu10 - // Depends: libc6 (= 2.23-0ubuntu10) - // - // We can dive into tracking dependencies, but this would be overly - // complicated. - // - // For simplicity lets consider the following rules: - // 1. If there is one item in `dpkg -S` output, accept it. - // 2. If there are multiple items in `dpkg -S` output and there is at - // least one item with the default arch suffix (DEB_ARCH), - // accept only these items. - // 3. If there are multiple items in `dpkg -S` output and there are - // no with the default arch suffix (DEB_ARCH), accept all items. - // So lets use this heuristics: don't accept packages for whom - // `dpkg -p` command fails. - // 4. Arch suffix should be stripped from accepted package names. - // - - Set archPackages = new HashSet<>(); - Set otherPackages = new HashSet<>(); - - var debArch = LinuxPackageArch.getValue(LINUX_DEB); - - Executor.of(TOOL_DPKG, "-S", file.toString()) - .saveOutput(true).executeExpectSuccess() - .getOutput().forEach(line -> { - Matcher matcher = PACKAGE_NAME_REGEX.matcher(line); - if (matcher.find()) { - String name = matcher.group(1); - if (name.endsWith(":" + debArch)) { - // Strip arch suffix - name = name.substring(0, - name.length() - (debArch.length() + 1)); - archPackages.add(name); - } else { - otherPackages.add(name); - } - } - }); - - if (!archPackages.isEmpty()) { - return archPackages.stream(); - } - return otherPackages.stream(); - } - - @Override - protected List verifyOutputBundle(BuildEnv env, LinuxPackage pkg, - Path packageBundle) { - List errors = new ArrayList<>(); - - String controlFileName = "control"; - - List properties = List.of( - new PackageProperty("Package", pkg.packageName(), - "APPLICATION_PACKAGE", controlFileName), - new PackageProperty("Version", ((LinuxDebPackage)pkg).versionWithRelease(), - "APPLICATION_VERSION_WITH_RELEASE", - controlFileName), - new PackageProperty("Architecture", pkg.arch(), "APPLICATION_ARCH", controlFileName)); - - List cmdline = new ArrayList<>(List.of(TOOL_DPKG_DEB, "-f", - packageBundle.toString())); - properties.forEach(property -> cmdline.add(property.name)); - try { - Map actualValues = Executor.of(cmdline.toArray(String[]::new)) - .saveOutput(true) - .executeExpectSuccess() - .getOutput().stream() - .map(line -> line.split(":\\s+", 2)) - .collect(Collectors.toMap( - components -> components[0], - components -> components[1])); - properties.forEach(property -> errors.add(property.verifyValue( - actualValues.get(property.name)))); - } catch (IOException ex) { - // Ignore error as it is not critical. Just report it. - Log.verbose(ex); - } - - return errors; - } - - /* - * set permissions with a string like "rwxr-xr-x" - * - * This cannot be directly backport to 22u which is built with 1.6 - */ - private void setPermissions(Path file, String permissions) { - Set filePermissions = - PosixFilePermissions.fromString(permissions); - try { - if (Files.exists(file)) { - Files.setPosixFilePermissions(file, filePermissions); - } - } catch (IOException ex) { - Log.error(ex.getMessage()); - Log.verbose(ex); - } - - } - - public static boolean isDebian() { - // we are just going to run "dpkg -s coreutils" and assume Debian - // or deritive if no error is returned. - try { - Executor.of(TOOL_DPKG, "-s", "coreutils").executeExpectSuccess(); - return true; - } catch (IOException e) { - // just fall thru - } - return false; - } - - private void adjustPermissionsRecursive(Path dir) throws IOException { - Files.walkFileTree(dir, new SimpleFileVisitor() { - @Override - public FileVisitResult visitFile(Path file, - BasicFileAttributes attrs) - throws IOException { - if (file.endsWith(".so") || !Files.isExecutable(file)) { - setPermissions(file, "rw-r--r--"); - } else if (Files.isExecutable(file)) { - setPermissions(file, "rwxr-xr-x"); - } - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult postVisitDirectory(Path dir, IOException e) - throws IOException { - if (e == null) { - setPermissions(dir, "rwxr-xr-x"); - return FileVisitResult.CONTINUE; - } else { - // directory iteration failed - throw e; - } - } - }); - } - - private class DebianFile { - - DebianFile(Path dstFilePath, String comment) { - this.dstFilePath = dstFilePath; - this.comment = comment; - } - - DebianFile setExecutable() { - permissions = "rwxr-xr-x"; - return this; - } - - void create(Map data, Function resourceFactory) - throws IOException { - resourceFactory.apply("template." + dstFilePath.getFileName().toString()) - .setCategory(I18N.getString(comment)) - .setSubstitutionData(data) - .saveToFile(dstFilePath); - if (permissions != null) { - setPermissions(dstFilePath, permissions); - } - } - - private final Path dstFilePath; - private final String comment; - private String permissions; - } - - private void prepareProjectConfig(Map data, BuildEnv env, LinuxPackage pkg) throws IOException { - - Path configDir = env.appImageDir().resolve("DEBIAN"); - List debianFiles = new ArrayList<>(); - debianFiles.add(new DebianFile( - configDir.resolve("control"), - "resource.deb-control-file")); - debianFiles.add(new DebianFile( - configDir.resolve("preinst"), - "resource.deb-preinstall-script").setExecutable()); - debianFiles.add(new DebianFile( - configDir.resolve("prerm"), - "resource.deb-prerm-script").setExecutable()); - debianFiles.add(new DebianFile( - configDir.resolve("postinst"), - "resource.deb-postinstall-script").setExecutable()); - debianFiles.add(new DebianFile( - configDir.resolve("postrm"), - "resource.deb-postrm-script").setExecutable()); - - ((LinuxDebPackage)pkg).relativeCopyrightFilePath().ifPresent(copyrightFile -> { - debianFiles.add(new DebianFile(env.appImageDir().resolve(copyrightFile), - "resource.copyright-file")); - }); - - for (DebianFile debianFile : debianFiles) { - debianFile.create(data, env::createResource); - } - } - - @Override - protected Map createReplacementData(BuildEnv env, LinuxPackage pkg) throws IOException { - Map data = new HashMap<>(); - - String licenseText = pkg.licenseFile().map(toFunction(Files::readString)).orElse("Unknown"); - - data.put("APPLICATION_MAINTAINER", ((LinuxDebPackage) pkg).maintainer()); - data.put("APPLICATION_SECTION", pkg.category().orElseThrow()); - data.put("APPLICATION_COPYRIGHT", pkg.app().copyright()); - data.put("APPLICATION_LICENSE_TEXT", licenseText); - data.put("APPLICATION_ARCH", pkg.arch()); - data.put("APPLICATION_INSTALLED_SIZE", Long.toString( - AppImageLayout.toPathGroup(env.appImageLayout()).sizeInBytes() >> 10)); - data.put("APPLICATION_HOMEPAGE", pkg.aboutURL().map( - value -> "Homepage: " + value).orElse("")); - data.put("APPLICATION_VERSION_WITH_RELEASE", ((LinuxDebPackage) pkg).versionWithRelease()); - - return data; - } - - private Path buildDeb(BuildEnv env, LinuxPackage pkg, Path outdir) throws IOException { - Path outFile = outdir.resolve(pkg.packageFileNameWithSuffix()); - Log.verbose(I18N.format("message.outputting-to-location", outFile.toAbsolutePath())); - - List cmdline = new ArrayList<>(); - cmdline.addAll(List.of(TOOL_FAKEROOT, TOOL_DPKG_DEB)); - if (Log.isVerbose()) { - cmdline.add("--verbose"); - } - cmdline.addAll(List.of("-b", env.appImageDir().toString(), - outFile.toAbsolutePath().toString())); - - // run dpkg - RetryExecutor.retryOnKnownErrorMessage( - "semop(1): encountered an error: Invalid argument").execute( - cmdline.toArray(String[]::new)); - - Log.verbose(I18N.format("message.output-to-location", outFile.toAbsolutePath())); - - return outFile; - } - @Override public String getName() { return I18N.getString("deb.bundler.name"); @@ -392,12 +49,28 @@ public String getID() { } @Override - public boolean supported(boolean runtimeInstaller) { - return OperatingSystem.isLinux() && (new ToolValidator(TOOL_DPKG_DEB).validate() == null); + public Path execute(Map params, Path outputParentDir) throws PackagerException { + + return Packager.build().outputDir(outputParentDir) + .pkg(LinuxFromParams.DEB_PACKAGE.fetchFrom(params)) + .env(BuildEnvFromParams.BUILD_ENV.fetchFrom(params)) + .pipelineBuilderMutatorFactory((env, pkg, outputDir) -> { + return new LinuxDebPackager(env, pkg, outputDir, sysEnv.orElseThrow()); + }).execute(LinuxPackagingPipeline.build()); + } + + @Override + protected Result sysEnv() { + return sysEnv; } @Override public boolean isDefault() { - return isDebian(); + return sysEnv.value() + .map(LinuxSystemEnvironment::nativePackageType) + .map(StandardPackageType.LINUX_DEB::equals) + .orElse(false); } + + private final Result sysEnv = LinuxDebSystemEnvironment.create(SYS_ENV); } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackager.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackager.java new file mode 100644 index 00000000000..64a0368e9a0 --- /dev/null +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebPackager.java @@ -0,0 +1,344 @@ +/* + * 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal; + +import static jdk.jpackage.internal.model.StandardPackageType.LINUX_DEB; +import static jdk.jpackage.internal.util.function.ThrowingFunction.toFunction; + +import java.io.IOException; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; +import java.nio.file.attribute.PosixFilePermission; +import java.nio.file.attribute.PosixFilePermissions; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.function.Function; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import jdk.jpackage.internal.PackagingPipeline.PackageTaskID; +import jdk.jpackage.internal.PackagingPipeline.PrimaryTaskID; +import jdk.jpackage.internal.model.AppImageLayout; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.LinuxDebPackage; + +final class LinuxDebPackager extends LinuxPackager { + + LinuxDebPackager(BuildEnv env, LinuxDebPackage pkg, Path outputDir, LinuxDebSystemEnvironment sysEnv) { + super(env, pkg, outputDir, sysEnv); + this.sysEnv = Objects.requireNonNull(sysEnv); + } + + @Override + protected void createConfigFiles(Map replacementData) throws IOException { + prepareProjectConfig(replacementData); + adjustPermissionsRecursive(); + } + + @Override + protected void initLibProvidersLookup(LibProvidersLookup libProvidersLookup) { + + libProvidersLookup.setPackageLookup(file -> { + Path realPath = file.toRealPath(); + + try { + // Try the real path first as it works better on newer Ubuntu versions + return findProvidingPackages(realPath, sysEnv.dpkg()); + } catch (IOException ex) { + // Try the default path if differ + if (!realPath.equals(file)) { + return findProvidingPackages(file, sysEnv.dpkg()); + } else { + throw ex; + } + } + }); + } + + @Override + protected List findErrorsInOutputPackage() throws IOException { + List errors = new ArrayList<>(); + + var controlFileName = "control"; + + List properties = List.of( + new PackageProperty("Package", pkg.packageName(), + "APPLICATION_PACKAGE", controlFileName), + new PackageProperty("Version", pkg.versionWithRelease(), + "APPLICATION_VERSION_WITH_RELEASE", + controlFileName), + new PackageProperty("Architecture", pkg.arch(), "APPLICATION_ARCH", controlFileName)); + + List cmdline = new ArrayList<>(List.of( + sysEnv.dpkgdeb().toString(), "-f", outputPackageFile().toString())); + + properties.forEach(property -> cmdline.add(property.name)); + + Map actualValues = Executor.of(cmdline.toArray(String[]::new)) + .saveOutput(true) + .executeExpectSuccess() + .getOutput().stream() + .map(line -> line.split(":\\s+", 2)) + .collect(Collectors.toMap( + components -> components[0], + components -> components[1])); + + for (var property : properties) { + Optional.ofNullable(property.verifyValue(actualValues.get(property.name))).ifPresent(errors::add); + } + + return errors; + } + + @Override + protected Map createReplacementData() throws IOException { + Map data = new HashMap<>(); + + String licenseText = pkg.licenseFile().map(toFunction(Files::readString)).orElse("Unknown"); + + data.put("APPLICATION_MAINTAINER", pkg.maintainer()); + data.put("APPLICATION_SECTION", pkg.category().orElseThrow()); + data.put("APPLICATION_COPYRIGHT", pkg.app().copyright()); + data.put("APPLICATION_LICENSE_TEXT", licenseText); + data.put("APPLICATION_ARCH", pkg.arch()); + data.put("APPLICATION_INSTALLED_SIZE", Long.toString( + AppImageLayout.toPathGroup(env.appImageLayout()).sizeInBytes() >> 10)); + data.put("APPLICATION_HOMEPAGE", pkg.aboutURL().map( + value -> "Homepage: " + value).orElse("")); + data.put("APPLICATION_VERSION_WITH_RELEASE", pkg.versionWithRelease()); + + return data; + } + + @Override + protected void buildPackage() throws IOException { + + Path debFile = outputPackageFile(); + + Log.verbose(I18N.format("message.outputting-to-location", debFile.toAbsolutePath())); + + List cmdline = new ArrayList<>(); + Stream.of(sysEnv.fakeroot(), sysEnv.dpkgdeb()).map(Path::toString).forEach(cmdline::add); + if (Log.isVerbose()) { + cmdline.add("--verbose"); + } + cmdline.addAll(List.of("-b", env.appImageDir().toString(), debFile.toAbsolutePath().toString())); + + // run dpkg + RetryExecutor.retryOnKnownErrorMessage( + "semop(1): encountered an error: Invalid argument").execute( + cmdline.toArray(String[]::new)); + + Log.verbose(I18N.format("message.output-to-location", debFile.toAbsolutePath())); + } + + @Override + public void accept(PackagingPipeline.Builder pipelineBuilder) { + super.accept(pipelineBuilder); + + // Build deb config files after app image contents are ready because + // it calculates the size of the image and saves the value in one of the config files. + pipelineBuilder.configuredTasks().filter(task -> { + return PackageTaskID.CREATE_CONFIG_FILES.equals(task.task()); + }).findFirst().orElseThrow() + .addDependencies(PrimaryTaskID.BUILD_APPLICATION_IMAGE, PrimaryTaskID.COPY_APP_IMAGE) + .add(); + } + + private void adjustPermissionsRecursive() throws IOException { + Files.walkFileTree(env.appImageDir(), new SimpleFileVisitor() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + if (file.endsWith(".so") || !Files.isExecutable(file)) { + Files.setPosixFilePermissions(file, SO_PERMISSIONS); + } else if (Files.isExecutable(file)) { + Files.setPosixFilePermissions(file, EXECUTABLE_PERMISSIONS); + } + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult postVisitDirectory(Path dir, IOException e) throws IOException { + if (e == null) { + Files.setPosixFilePermissions(dir, FOLDER_PERMISSIONS); + return FileVisitResult.CONTINUE; + } else { + // directory iteration failed + throw e; + } + } + }); + } + + private void prepareProjectConfig(Map data) throws IOException { + + Path configDir = env.appImageDir().resolve("DEBIAN"); + List debianFiles = new ArrayList<>(); + debianFiles.add(new DebianFile( + configDir.resolve("control"), + "resource.deb-control-file")); + debianFiles.add(new DebianFile( + configDir.resolve("preinst"), + "resource.deb-preinstall-script").setExecutable()); + debianFiles.add(new DebianFile( + configDir.resolve("prerm"), + "resource.deb-prerm-script").setExecutable()); + debianFiles.add(new DebianFile( + configDir.resolve("postinst"), + "resource.deb-postinstall-script").setExecutable()); + debianFiles.add(new DebianFile( + configDir.resolve("postrm"), + "resource.deb-postrm-script").setExecutable()); + + pkg.relativeCopyrightFilePath().ifPresent(copyrightFile -> { + debianFiles.add(new DebianFile(env.appImageDir().resolve(copyrightFile), + "resource.copyright-file")); + }); + + for (DebianFile debianFile : debianFiles) { + debianFile.create(data, env::createResource); + } + } + + private static Stream findProvidingPackages(Path file, Path dpkg) throws IOException { + // + // `dpkg -S` command does glob pattern lookup. If not the absolute path + // to the file is specified it might return mltiple package names. + // Even for full paths multiple package names can be returned as + // it is OK for multiple packages to provide the same file. `/opt` + // directory is such an example. So we have to deal with multiple + // packages per file situation. + // + // E.g.: `dpkg -S libc.so.6` command reports three packages: + // libc6-x32: /libx32/libc.so.6 + // libc6:amd64: /lib/x86_64-linux-gnu/libc.so.6 + // libc6-i386: /lib32/libc.so.6 + // `:amd64` is architecture suffix and can (should) be dropped. + // Still need to decide what package to choose from three. + // libc6-x32 and libc6-i386 both depend on libc6: + // $ dpkg -s libc6-x32 + // Package: libc6-x32 + // Status: install ok installed + // Priority: optional + // Section: libs + // Installed-Size: 10840 + // Maintainer: Ubuntu Developers + // Architecture: amd64 + // Source: glibc + // Version: 2.23-0ubuntu10 + // Depends: libc6 (= 2.23-0ubuntu10) + // + // We can dive into tracking dependencies, but this would be overly + // complicated. + // + // For simplicity lets consider the following rules: + // 1. If there is one item in `dpkg -S` output, accept it. + // 2. If there are multiple items in `dpkg -S` output and there is at + // least one item with the default arch suffix (DEB_ARCH), + // accept only these items. + // 3. If there are multiple items in `dpkg -S` output and there are + // no with the default arch suffix (DEB_ARCH), accept all items. + // So lets use this heuristics: don't accept packages for whom + // `dpkg -p` command fails. + // 4. Arch suffix should be stripped from accepted package names. + // + + Set archPackages = new HashSet<>(); + Set otherPackages = new HashSet<>(); + + var debArch = LinuxPackageArch.getValue(LINUX_DEB); + + Executor.of(dpkg.toString(), "-S", file.toString()) + .saveOutput(true).executeExpectSuccess() + .getOutput().forEach(line -> { + Matcher matcher = PACKAGE_NAME_REGEX.matcher(line); + if (matcher.find()) { + String name = matcher.group(1); + if (name.endsWith(":" + debArch)) { + // Strip arch suffix + name = name.substring(0, + name.length() - (debArch.length() + 1)); + archPackages.add(name); + } else { + otherPackages.add(name); + } + } + }); + + if (!archPackages.isEmpty()) { + return archPackages.stream(); + } + return otherPackages.stream(); + } + + + private static final class DebianFile { + + DebianFile(Path dstFilePath, String comment) { + this.dstFilePath = Objects.requireNonNull(dstFilePath); + this.comment = Objects.requireNonNull(comment); + } + + DebianFile setExecutable() { + permissions = EXECUTABLE_PERMISSIONS; + return this; + } + + void create(Map data, Function resourceFactory) + throws IOException { + resourceFactory.apply("template." + dstFilePath.getFileName().toString()) + .setCategory(I18N.getString(comment)) + .setSubstitutionData(data) + .saveToFile(dstFilePath); + if (permissions != null) { + Files.setPosixFilePermissions(dstFilePath, permissions); + } + } + + private final Path dstFilePath; + private final String comment; + private Set permissions; + } + + + private final LinuxDebSystemEnvironment sysEnv; + + private static final Pattern PACKAGE_NAME_REGEX = Pattern.compile("^(^\\S+):"); + + private static final Set EXECUTABLE_PERMISSIONS = PosixFilePermissions.fromString("rwxr-xr-x"); + private static final Set FOLDER_PERMISSIONS = PosixFilePermissions.fromString("rwxr-xr-x"); + private static final Set SO_PERMISSIONS = PosixFilePermissions.fromString("rw-r--r--"); +} diff --git a/src/jdk.hotspot.agent/test/libproc/LibprocTest.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebSystemEnvironment.java similarity index 56% rename from src/jdk.hotspot.agent/test/libproc/LibprocTest.java rename to src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebSystemEnvironment.java index a3e27a94ec0..5b5decb7a67 100644 --- a/src/jdk.hotspot.agent/test/libproc/LibprocTest.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebSystemEnvironment.java @@ -1,10 +1,12 @@ /* - * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. + * 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. + * 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 @@ -19,23 +21,16 @@ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. - * */ +package jdk.jpackage.internal; + +import static jdk.jpackage.internal.LinuxSystemEnvironment.mixin; + +import jdk.jpackage.internal.util.Result; -/** - This is test case run by debuggee for running LibprocClient.java. -*/ +public interface LinuxDebSystemEnvironment extends LinuxSystemEnvironment, LinuxDebSystemEnvironmentMixin { -public class LibprocTest { - public static void main(String[] args) throws Exception { - String myStr = ""; - System.out.println("main start"); - synchronized(myStr) { - try { - myStr.wait(); - } catch (InterruptedException ee) { - } - } - System.out.println("main end"); - } + static Result create(Result base) { + return mixin(LinuxDebSystemEnvironment.class, base, LinuxDebSystemEnvironmentMixin::create); + } } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebSystemEnvironmentMixin.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebSystemEnvironmentMixin.java new file mode 100644 index 00000000000..8688327b353 --- /dev/null +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxDebSystemEnvironmentMixin.java @@ -0,0 +1,59 @@ +/* + * 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 jdk.jpackage.internal; + +import java.nio.file.Path; +import java.util.Objects; +import java.util.stream.Stream; +import jdk.jpackage.internal.util.Result; + +public interface LinuxDebSystemEnvironmentMixin { + Path dpkg(); + Path dpkgdeb(); + Path fakeroot(); + + record Stub(Path dpkg, Path dpkgdeb, Path fakeroot) implements LinuxDebSystemEnvironmentMixin { + } + + static Result create() { + final var errors = Stream.of(Internal.TOOL_DPKG_DEB, Internal.TOOL_DPKG, Internal.TOOL_FAKEROOT) + .map(ToolValidator::new) + .map(ToolValidator::validate) + .filter(Objects::nonNull) + .toList(); + if (errors.isEmpty()) { + return Result.ofValue(new Stub(Internal.TOOL_DPKG, Internal.TOOL_DPKG_DEB, Internal.TOOL_FAKEROOT)); + } else { + return Result.ofErrors(errors); + } + } + + static final class Internal { + + private static final Path TOOL_DPKG_DEB = Path.of("dpkg-deb"); + private static final Path TOOL_DPKG = Path.of("dpkg"); + private static final Path TOOL_FAKEROOT = Path.of("fakeroot"); + } +} diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromParams.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromParams.java index ced77b1aa68..a8d109220dc 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromParams.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromParams.java @@ -39,9 +39,10 @@ import java.util.Map; import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.LinuxApplication; +import jdk.jpackage.internal.model.LinuxDebPackage; import jdk.jpackage.internal.model.LinuxLauncher; import jdk.jpackage.internal.model.LinuxLauncherMixin; -import jdk.jpackage.internal.model.LinuxPackage; +import jdk.jpackage.internal.model.LinuxRpmPackage; import jdk.jpackage.internal.model.StandardPackageType; final class LinuxFromParams { @@ -76,7 +77,7 @@ private static LinuxPackageBuilder createLinuxPackageBuilder( return pkgBuilder; } - private static LinuxPackage createLinuxRpmPackage( + private static LinuxRpmPackage createLinuxRpmPackage( Map params) throws ConfigException, IOException { final var superPkgBuilder = createLinuxPackageBuilder(params, LINUX_RPM); @@ -88,7 +89,7 @@ private static LinuxPackage createLinuxRpmPackage( return pkgBuilder.create(); } - private static LinuxPackage createLinuxDebPackage( + private static LinuxDebPackage createLinuxDebPackage( Map params) throws ConfigException, IOException { final var superPkgBuilder = createLinuxPackageBuilder(params, LINUX_DEB); @@ -97,16 +98,23 @@ private static LinuxPackage createLinuxDebPackage( MAINTAINER_EMAIL.copyInto(params, pkgBuilder::maintainerEmail); - return pkgBuilder.create(); + final var pkg = pkgBuilder.create(); + + // Show warning if license file is missing + if (pkg.licenseFile().isEmpty()) { + Log.verbose(I18N.getString("message.debs-like-licenses")); + } + + return pkg; } static final BundlerParamInfo APPLICATION = createApplicationBundlerParam( LinuxFromParams::createLinuxApplication); - static final BundlerParamInfo RPM_PACKAGE = createPackageBundlerParam( + static final BundlerParamInfo RPM_PACKAGE = createPackageBundlerParam( LinuxFromParams::createLinuxRpmPackage); - static final BundlerParamInfo DEB_PACKAGE = createPackageBundlerParam( + static final BundlerParamInfo DEB_PACKAGE = createPackageBundlerParam( LinuxFromParams::createLinuxDebPackage); private static final BundlerParamInfo LINUX_SHORTCUT_HINT = createStringBundlerParam( diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLaunchersAsServices.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLaunchersAsServices.java index 742f87b3a9f..b14404d67b1 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLaunchersAsServices.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxLaunchersAsServices.java @@ -38,7 +38,7 @@ */ public final class LinuxLaunchersAsServices extends UnixLaunchersAsServices { - private LinuxLaunchersAsServices(BuildEnv env, Package pkg) throws IOException { + private LinuxLaunchersAsServices(BuildEnv env, Package pkg) { super(env.appImageDir(), pkg.app(), REQUIRED_PACKAGES, launcher -> { return new LauncherImpl(env, pkg, launcher); }); @@ -58,7 +58,7 @@ protected Map createImpl() throws IOException { return data; } - static ShellCustomAction create(BuildEnv env, Package pkg) throws IOException { + static ShellCustomAction create(BuildEnv env, Package pkg) { if (pkg.isRuntimeInstaller()) { return ShellCustomAction.nop(LINUX_REPLACEMENT_STRING_IDS); } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java index 2f3e6da1e69..1f674c0be11 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackageBundler.java @@ -24,33 +24,16 @@ */ package jdk.jpackage.internal; -import java.io.IOException; -import java.nio.file.Path; -import java.text.MessageFormat; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.function.Predicate; -import java.util.stream.Stream; -import jdk.jpackage.internal.PackagingPipeline.PackageBuildEnv; -import jdk.jpackage.internal.PackagingPipeline.PackageTaskID; -import jdk.jpackage.internal.PackagingPipeline.PrimaryTaskID; -import jdk.jpackage.internal.model.AppImageLayout; import jdk.jpackage.internal.model.ConfigException; -import jdk.jpackage.internal.model.LinuxDebPackage; import jdk.jpackage.internal.model.LinuxPackage; -import jdk.jpackage.internal.model.Package; -import jdk.jpackage.internal.model.PackagerException; +import jdk.jpackage.internal.util.Result; abstract class LinuxPackageBundler extends AbstractBundler { LinuxPackageBundler(BundlerParamInfo pkgParam) { - this.pkgParam = pkgParam; - customActions = List.of(new CustomActionInstance( - DesktopIntegration::create), new CustomActionInstance( - LinuxLaunchersAsServices::create)); + this.pkgParam = Objects.requireNonNull(pkgParam); } @Override @@ -58,39 +41,32 @@ public final boolean validate(Map params) throws ConfigException { // Order is important! - LinuxPackage pkg = pkgParam.fetchFrom(params); - var env = BuildEnvFromParams.BUILD_ENV.fetchFrom(params); - - for (var validator: getToolValidators()) { - ConfigException ex = validator.validate(); - if (ex != null) { - throw ex; - } + pkgParam.fetchFrom(params); + BuildEnvFromParams.BUILD_ENV.fetchFrom(params); + + LinuxSystemEnvironment sysEnv; + try { + sysEnv = sysEnv().orElseThrow(); + } catch (RuntimeException ex) { + throw ConfigException.rethrowConfigException(ex); } if (!isDefault()) { - withFindNeededPackages = false; - Log.verbose(MessageFormat.format(I18N.getString( - "message.not-default-bundler-no-dependencies-lookup"), + Log.verbose(I18N.format( + "message.not-default-bundler-no-dependencies-lookup", getName())); - } else { - withFindNeededPackages = LibProvidersLookup.supported(); - if (!withFindNeededPackages) { - final String advice; - if ("deb".equals(getID())) { - advice = "message.deb-ldd-not-available.advice"; - } else { - advice = "message.rpm-ldd-not-available.advice"; - } - // Let user know package dependencies will not be generated. - Log.error(String.format("%s\n%s", I18N.getString( - "message.ldd-not-available"), I18N.getString(advice))); + } else if (!sysEnv.soLookupAvailable()) { + final String advice; + if ("deb".equals(getID())) { + advice = "message.deb-ldd-not-available.advice"; + } else { + advice = "message.rpm-ldd-not-available.advice"; } + // Let user know package dependencies will not be generated. + Log.error(String.format("%s\n%s", I18N.getString( + "message.ldd-not-available"), I18N.getString(advice))); } - // Packaging specific validation - doValidate(env, pkg); - return true; } @@ -100,148 +76,13 @@ public final String getBundleType() { } @Override - public final Path execute(Map params, - Path outputParentDir) throws PackagerException { - IOUtils.writableOutputDir(outputParentDir); - - // Order is important! - final LinuxPackage pkg = pkgParam.fetchFrom(params); - final var env = BuildEnvFromParams.BUILD_ENV.fetchFrom(params); - - final var pipelineBuilder = LinuxPackagingPipeline.build() - .excludeDirFromCopying(outputParentDir) - .task(PackageTaskID.CREATE_PACKAGE_FILE) - .packageAction(this::buildPackage) - .add(); - - final var createConfigFilesTaskBuilder = pipelineBuilder - .task(PackageTaskID.CREATE_CONFIG_FILES) - .packageAction(this::buildConfigFiles); - - if (pkg instanceof LinuxDebPackage) { - // Build deb config files after app image contents are ready because - // it calculates the size of the image and saves the value in one of the config files. - createConfigFilesTaskBuilder.addDependencies(PrimaryTaskID.BUILD_APPLICATION_IMAGE, PrimaryTaskID.COPY_APP_IMAGE); - } - - createConfigFilesTaskBuilder.add(); - - pipelineBuilder.create().execute(env, pkg, outputParentDir); - - return outputParentDir.resolve(pkg.packageFileNameWithSuffix()).toAbsolutePath(); - } - - private void buildConfigFiles(PackageBuildEnv env) throws PackagerException, IOException { - for (var ca : customActions) { - ca.init(env.env(), env.pkg()); - } - - Map data = createDefaultReplacementData(env.env(), env.pkg()); - - for (var ca : customActions) { - ShellCustomAction.mergeReplacementData(data, ca.instance.create()); - } - - data.putAll(createReplacementData(env.env(), env.pkg())); - - createConfigFiles(Collections.unmodifiableMap(data), env.env(), env.pkg()); - } - - private void buildPackage(PackageBuildEnv env) throws PackagerException, IOException { - Path packageBundle = buildPackageBundle(env.env(), env.pkg(), env.outputDir()); - - verifyOutputBundle(env.env(), env.pkg(), packageBundle).stream() - .filter(Objects::nonNull) - .forEachOrdered(ex -> { - Log.verbose(ex.getLocalizedMessage()); - Log.verbose(ex.getAdvice()); - }); - } - - private List getListOfNeededPackages(BuildEnv env) throws IOException { - - final List caPackages = customActions.stream() - .map(ca -> ca.instance) - .map(ShellCustomAction::requiredPackages) - .flatMap(List::stream).toList(); - - final List neededLibPackages; - if (withFindNeededPackages) { - LibProvidersLookup lookup = new LibProvidersLookup(); - initLibProvidersLookup(lookup); - - neededLibPackages = lookup.execute(env.appImageDir()); - } else { - neededLibPackages = Collections.emptyList(); - Log.info(I18N.getString("warning.foreign-app-image")); - } - - // Merge all package lists together. - // Filter out empty names, sort and remove duplicates. - List result = Stream.of(caPackages, neededLibPackages).flatMap( - List::stream).filter(Predicate.not(String::isEmpty)).sorted().distinct().toList(); - - Log.verbose(String.format("Required packages: %s", result)); - - return result; - } - - private Map createDefaultReplacementData(BuildEnv env, LinuxPackage pkg) throws IOException { - Map data = new HashMap<>(); - - data.put("APPLICATION_PACKAGE", pkg.packageName()); - data.put("APPLICATION_VENDOR", pkg.app().vendor()); - data.put("APPLICATION_VERSION", pkg.version()); - data.put("APPLICATION_DESCRIPTION", pkg.description()); - - String defaultDeps = String.join(", ", getListOfNeededPackages(env)); - String customDeps = pkg.additionalDependencies().orElse(""); - if (!customDeps.isEmpty() && !defaultDeps.isEmpty()) { - customDeps = ", " + customDeps; - } - data.put("PACKAGE_DEFAULT_DEPENDENCIES", defaultDeps); - data.put("PACKAGE_CUSTOM_DEPENDENCIES", customDeps); - - return data; + public boolean supported(boolean runtimeInstaller) { + return sysEnv().hasValue(); } - protected abstract List verifyOutputBundle( - BuildEnv env, LinuxPackage pkg, Path packageBundle); - - protected abstract void initLibProvidersLookup(LibProvidersLookup libProvidersLookup); - - protected abstract List getToolValidators(); - - protected abstract void doValidate(BuildEnv env, LinuxPackage pkg) - throws ConfigException; - - protected abstract Map createReplacementData( - BuildEnv env, LinuxPackage pkg) throws IOException; - - protected abstract void createConfigFiles( - Map replacementData, - BuildEnv env, LinuxPackage pkg) throws IOException; - - protected abstract Path buildPackageBundle( - BuildEnv env, LinuxPackage pkg, Path outputParentDir) throws - PackagerException, IOException; + protected abstract Result sysEnv(); private final BundlerParamInfo pkgParam; - private boolean withFindNeededPackages; - private final List customActions; - private static final class CustomActionInstance { - - CustomActionInstance(ShellCustomActionFactory factory) { - this.factory = factory; - } - - void init(BuildEnv env, Package pkg) throws IOException { - instance = factory.create(env, pkg); - Objects.requireNonNull(instance); - } - - private final ShellCustomActionFactory factory; - ShellCustomAction instance; - } + static final Result SYS_ENV = LinuxSystemEnvironment.create(); } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackager.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackager.java new file mode 100644 index 00000000000..806592904d1 --- /dev/null +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxPackager.java @@ -0,0 +1,184 @@ +/* + * 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 jdk.jpackage.internal; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.function.Consumer; +import java.util.function.Predicate; +import java.util.stream.Stream; +import jdk.jpackage.internal.PackagingPipeline.PackageTaskID; +import jdk.jpackage.internal.PackagingPipeline.PrimaryTaskID; +import jdk.jpackage.internal.PackagingPipeline.TaskID; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.LinuxPackage; +import jdk.jpackage.internal.model.PackagerException; + +abstract class LinuxPackager implements Consumer { + + LinuxPackager(BuildEnv env, T pkg, Path outputDir, LinuxSystemEnvironment sysEnv) { + this.env = Objects.requireNonNull(env); + this.pkg = Objects.requireNonNull(pkg); + this.outputDir = Objects.requireNonNull(outputDir); + this.withRequiredPackagesLookup = sysEnv.soLookupAvailable() && sysEnv.nativePackageType().equals(pkg.type()); + + customActions = List.of( + DesktopIntegration.create(env, pkg), + LinuxLaunchersAsServices.create(env, pkg)); + } + + enum LinuxPackageTaskID implements TaskID { + INIT_REQUIRED_PACKAGES, + VERIFY_PACKAGE + } + + @Override + public void accept(PackagingPipeline.Builder pipelineBuilder) { + pipelineBuilder.excludeDirFromCopying(outputDir) + .task(PackageTaskID.CREATE_CONFIG_FILES) + .action(this::buildConfigFiles) + .add() + .task(LinuxPackageTaskID.INIT_REQUIRED_PACKAGES) + .addDependencies(PrimaryTaskID.BUILD_APPLICATION_IMAGE, PrimaryTaskID.COPY_APP_IMAGE) + .addDependent(PackageTaskID.CREATE_CONFIG_FILES) + .action(this::initRequiredPackages) + .add() + .task(LinuxPackageTaskID.VERIFY_PACKAGE) + .addDependencies(PackageTaskID.CREATE_PACKAGE_FILE) + .addDependent(PrimaryTaskID.PACKAGE) + .action(this::verifyOutputPackage) + .add() + .task(PackageTaskID.CREATE_PACKAGE_FILE) + .action(this::buildPackage) + .add(); + } + + protected final Path outputPackageFile() { + return outputDir.resolve(pkg.packageFileNameWithSuffix()); + } + + protected abstract void buildPackage() throws IOException; + + protected abstract List findErrorsInOutputPackage() throws IOException; + + protected abstract void createConfigFiles(Map replacementData) throws IOException; + + protected abstract Map createReplacementData() throws IOException; + + protected abstract void initLibProvidersLookup(LibProvidersLookup libProvidersLookup); + + private void buildConfigFiles() throws PackagerException, IOException { + + final var data = createDefaultReplacementData(); + + for (var ca : customActions) { + ShellCustomAction.mergeReplacementData(data, ca.create()); + } + + data.putAll(createReplacementData()); + + createConfigFiles(Collections.unmodifiableMap(data)); + } + + private Map createDefaultReplacementData() { + Map data = new HashMap<>(); + + data.put("APPLICATION_PACKAGE", pkg.packageName()); + data.put("APPLICATION_VENDOR", pkg.app().vendor()); + data.put("APPLICATION_VERSION", pkg.version()); + data.put("APPLICATION_DESCRIPTION", pkg.description()); + + String defaultDeps = String.join(", ", requiredPackages); + String customDeps = pkg.additionalDependencies().orElse(""); + if (!customDeps.isEmpty() && !defaultDeps.isEmpty()) { + customDeps = ", " + customDeps; + } + data.put("PACKAGE_DEFAULT_DEPENDENCIES", defaultDeps); + data.put("PACKAGE_CUSTOM_DEPENDENCIES", customDeps); + + return data; + } + + private void initRequiredPackages() throws IOException { + + final List caPackages = customActions.stream() + .map(ShellCustomAction::requiredPackages) + .flatMap(List::stream).toList(); + + final List neededLibPackages; + if (withRequiredPackagesLookup) { + neededLibPackages = findRequiredPackages(); + } else { + neededLibPackages = Collections.emptyList(); + Log.info(I18N.getString("warning.foreign-app-image")); + } + + // Merge all package lists together. + // Filter out empty names, sort and remove duplicates. + Stream.of(caPackages, neededLibPackages) + .flatMap(List::stream) + .filter(Predicate.not(String::isEmpty)) + .sorted().distinct().forEach(requiredPackages::add); + + Log.verbose(String.format("Required packages: %s", requiredPackages)); + } + + private List findRequiredPackages() throws IOException { + var lookup = new LibProvidersLookup(); + initLibProvidersLookup(lookup); + return lookup.execute(env.appImageDir()); + } + + private void verifyOutputPackage() { + final List errors; + try { + errors = findErrorsInOutputPackage(); + } catch (Exception ex) { + // Ignore error as it is not critical. Just report it. + Log.verbose(ex); + return; + } + + for (var ex : errors) { + Log.verbose(ex.getLocalizedMessage()); + if (ex instanceof ConfigException cfgEx) { + Log.verbose(cfgEx.getAdvice()); + } + } + } + + protected final BuildEnv env; + protected final T pkg; + protected final Path outputDir; + private final boolean withRequiredPackagesLookup; + private final List requiredPackages = new ArrayList<>(); + private final List customActions; +} diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java index 350f70f11bc..2337a286011 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java @@ -25,189 +25,20 @@ package jdk.jpackage.internal; -import java.io.IOException; import java.nio.file.Path; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.stream.Collectors; -import jdk.internal.util.OperatingSystem; -import jdk.jpackage.internal.model.ConfigException; -import jdk.jpackage.internal.model.DottedVersion; -import jdk.jpackage.internal.model.LinuxPackage; import jdk.jpackage.internal.model.LinuxRpmPackage; -import jdk.jpackage.internal.model.Package; import jdk.jpackage.internal.model.PackagerException; +import jdk.jpackage.internal.model.StandardPackageType; +import jdk.jpackage.internal.util.Result; -/** - * There are two command line options to configure license information for RPM - * packaging: --linux-rpm-license-type and --license-file. Value of - * --linux-rpm-license-type command line option configures "License:" section - * of RPM spec. Value of --license-file command line option specifies a license - * file to be added to the package. License file is a sort of documentation file - * but it will be installed even if user selects an option to install the - * package without documentation. --linux-rpm-license-type is the primary option - * to set license information. --license-file makes little sense in case of RPM - * packaging. - */ public class LinuxRpmBundler extends LinuxPackageBundler { - private static final String DEFAULT_SPEC_TEMPLATE = "template.spec"; - - public static final String TOOL_RPM = "rpm"; - public static final String TOOL_RPMBUILD = "rpmbuild"; - public static final DottedVersion TOOL_RPMBUILD_MIN_VERSION = DottedVersion.lazy( - "4.10"); - public LinuxRpmBundler() { super(LinuxFromParams.RPM_PACKAGE); } - @Override - protected void doValidate(BuildEnv env, LinuxPackage pkg) throws ConfigException { - } - - private static ToolValidator createRpmbuildToolValidator() { - Pattern pattern = Pattern.compile(" (\\d+\\.\\d+)"); - return new ToolValidator(TOOL_RPMBUILD).setMinimalVersion( - TOOL_RPMBUILD_MIN_VERSION).setVersionParser(lines -> { - String versionString = lines.limit(1).collect( - Collectors.toList()).get(0); - Matcher matcher = pattern.matcher(versionString); - if (matcher.find()) { - return matcher.group(1); - } - return null; - }); - } - - @Override - protected List getToolValidators() { - return List.of(createRpmbuildToolValidator()); - } - - protected void createConfigFiles(Map replacementData, - BuildEnv env, LinuxPackage pkg) throws IOException { - Path specFile = specFile(env, pkg); - - // prepare spec file - env.createResource(DEFAULT_SPEC_TEMPLATE) - .setCategory(I18N.getString("resource.rpm-spec-file")) - .setSubstitutionData(replacementData) - .saveToFile(specFile); - } - - @Override - protected Path buildPackageBundle(BuildEnv env, LinuxPackage pkg, - Path outputParentDir) throws PackagerException, IOException { - return buildRPM(env, pkg, outputParentDir); - } - - private static Path installPrefix(LinuxPackage pkg) { - Path path = pkg.relativeInstallDir(); - if (!pkg.isInstallDirInUsrTree()) { - path = path.getParent(); - } - return Path.of("/").resolve(path); - } - - @Override - protected Map createReplacementData(BuildEnv env, LinuxPackage pkg) throws IOException { - Map data = new HashMap<>(); - - data.put("APPLICATION_RELEASE", pkg.release().orElseThrow()); - data.put("APPLICATION_PREFIX", installPrefix(pkg).toString()); - data.put("APPLICATION_DIRECTORY", Path.of("/").resolve(pkg.relativeInstallDir()).toString()); - data.put("APPLICATION_SUMMARY", pkg.app().name()); - data.put("APPLICATION_LICENSE_TYPE", ((LinuxRpmPackage)pkg).licenseType()); - - String licenseFile = pkg.licenseFile().map(v -> { - return v.toAbsolutePath().normalize().toString(); - }).orElse(null); - data.put("APPLICATION_LICENSE_FILE", licenseFile); - data.put("APPLICATION_GROUP", pkg.category().orElse("")); - - data.put("APPLICATION_URL", pkg.aboutURL().orElse("")); - - return data; - } - - @Override - protected void initLibProvidersLookup(LibProvidersLookup libProvidersLookup) { - libProvidersLookup.setPackageLookup(file -> { - return Executor.of(TOOL_RPM, - "-q", "--queryformat", "%{name}\\n", - "-q", "--whatprovides", file.toString()) - .saveOutput(true).executeExpectSuccess().getOutput().stream(); - }); - } - - @Override - protected List verifyOutputBundle(BuildEnv env, LinuxPackage pkg, - Path packageBundle) { - List errors = new ArrayList<>(); - - String specFileName = specFile(env, pkg).getFileName().toString(); - - try { - List properties = List.of( - new PackageProperty("Name", pkg.packageName(), - "APPLICATION_PACKAGE", specFileName), - new PackageProperty("Version", pkg.version(), - "APPLICATION_VERSION", specFileName), - new PackageProperty("Release", pkg.release().orElseThrow(), - "APPLICATION_RELEASE", specFileName), - new PackageProperty("Arch", pkg.arch(), null, specFileName)); - - List actualValues = Executor.of(TOOL_RPM, "-qp", "--queryformat", - properties.stream().map(entry -> String.format("%%{%s}", - entry.name)).collect(Collectors.joining("\\n")), - packageBundle.toString()).saveOutput(true).executeExpectSuccess().getOutput(); - - Iterator actualValuesIt = actualValues.iterator(); - properties.forEach(property -> errors.add(property.verifyValue( - actualValuesIt.next()))); - } catch (IOException ex) { - // Ignore error as it is not critical. Just report it. - Log.verbose(ex); - } - - return errors; - } - - private Path specFile(BuildEnv env, Package pkg) { - return env.buildRoot().resolve(Path.of("SPECS", pkg.packageName() + ".spec")); - } - - private Path buildRPM(BuildEnv env, Package pkg, Path outdir) throws IOException { - - Path rpmFile = outdir.toAbsolutePath().resolve(pkg.packageFileNameWithSuffix()); - - Log.verbose(I18N.format("message.outputting-bundle-location", rpmFile.getParent())); - - //run rpmbuild - Executor.of(TOOL_RPMBUILD, - "-bb", specFile(env, pkg).toAbsolutePath().toString(), - "--define", String.format("%%_sourcedir %s", - env.appImageDir().toAbsolutePath()), - // save result to output dir - "--define", String.format("%%_rpmdir %s", rpmFile.getParent()), - // do not use other system directories to build as current user - "--define", String.format("%%_topdir %s", - env.buildRoot().toAbsolutePath()), - "--define", String.format("%%_rpmfilename %s", rpmFile.getFileName()) - ).executeExpectSuccess(); - - Log.verbose(I18N.format("message.output-bundle-location", rpmFile.getParent())); - - return rpmFile; - } - @Override public String getName() { return I18N.getString("rpm.bundler.name"); @@ -219,12 +50,28 @@ public String getID() { } @Override - public boolean supported(boolean runtimeInstaller) { - return OperatingSystem.isLinux() && (createRpmbuildToolValidator().validate() == null); + public Path execute(Map params, Path outputParentDir) throws PackagerException { + + return Packager.build().outputDir(outputParentDir) + .pkg(LinuxFromParams.RPM_PACKAGE.fetchFrom(params)) + .env(BuildEnvFromParams.BUILD_ENV.fetchFrom(params)) + .pipelineBuilderMutatorFactory((env, pkg, outputDir) -> { + return new LinuxRpmPackager(env, pkg, outputDir, sysEnv.orElseThrow()); + }).execute(LinuxPackagingPipeline.build()); + } + + @Override + protected Result sysEnv() { + return sysEnv; } @Override public boolean isDefault() { - return !LinuxDebBundler.isDebian(); + return sysEnv.value() + .map(LinuxSystemEnvironment::nativePackageType) + .map(StandardPackageType.LINUX_RPM::equals) + .orElse(false); } + + private final Result sysEnv = LinuxRpmSystemEnvironment.create(SYS_ENV); } diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackager.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackager.java new file mode 100644 index 00000000000..60355d0d1a2 --- /dev/null +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmPackager.java @@ -0,0 +1,167 @@ +/* + * 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 jdk.jpackage.internal; + +import static java.util.stream.Collectors.joining; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.LinuxRpmPackage; + + +/** + * There are two command line options to configure license information for RPM + * packaging: --linux-rpm-license-type and --license-file. Value of + * --linux-rpm-license-type command line option configures "License:" section + * of RPM spec. Value of --license-file command line option specifies a license + * file to be added to the package. License file is a sort of documentation file + * but it will be installed even if user selects an option to install the + * package without documentation. --linux-rpm-license-type is the primary option + * to set license information. --license-file makes little sense in case of RPM + * packaging. + */ +final class LinuxRpmPackager extends LinuxPackager { + + LinuxRpmPackager(BuildEnv env, LinuxRpmPackage pkg, Path outputDir, LinuxRpmSystemEnvironment sysEnv) { + super(env, pkg, outputDir, sysEnv); + this.sysEnv = Objects.requireNonNull(sysEnv); + } + + @Override + protected void createConfigFiles(Map replacementData) throws IOException { + Path specFile = specFile(); + + // prepare spec file + env.createResource("template.spec") + .setCategory(I18N.getString("resource.rpm-spec-file")) + .setSubstitutionData(replacementData) + .saveToFile(specFile); + } + + @Override + protected Map createReplacementData() { + Map data = new HashMap<>(); + + data.put("APPLICATION_RELEASE", pkg.release().orElseThrow()); + data.put("APPLICATION_PREFIX", installPrefix().toString()); + data.put("APPLICATION_DIRECTORY", Path.of("/").resolve(pkg.relativeInstallDir()).toString()); + data.put("APPLICATION_SUMMARY", pkg.app().name()); + data.put("APPLICATION_LICENSE_TYPE", pkg.licenseType()); + + String licenseFile = pkg.licenseFile().map(v -> { + return v.toAbsolutePath().normalize().toString(); + }).orElse(null); + data.put("APPLICATION_LICENSE_FILE", licenseFile); + data.put("APPLICATION_GROUP", pkg.category().orElse("")); + + data.put("APPLICATION_URL", pkg.aboutURL().orElse("")); + + return data; + } + + @Override + protected void initLibProvidersLookup(LibProvidersLookup libProvidersLookup) { + libProvidersLookup.setPackageLookup(file -> { + return Executor.of(sysEnv.rpm().toString(), + "-q", "--queryformat", "%{name}\\n", + "-q", "--whatprovides", file.toString() + ).saveOutput(true).executeExpectSuccess().getOutput().stream(); + }); + } + + @Override + protected List findErrorsInOutputPackage() throws IOException { + List errors = new ArrayList<>(); + + var specFileName = specFile().getFileName().toString(); + + var properties = List.of( + new PackageProperty("Name", pkg.packageName(), + "APPLICATION_PACKAGE", specFileName), + new PackageProperty("Version", pkg.version(), + "APPLICATION_VERSION", specFileName), + new PackageProperty("Release", pkg.release().orElseThrow(), + "APPLICATION_RELEASE", specFileName), + new PackageProperty("Arch", pkg.arch(), null, specFileName)); + + var actualValues = Executor.of( + sysEnv.rpm().toString(), + "-qp", + "--queryformat", properties.stream().map(e -> String.format("%%{%s}", e.name)).collect(joining("\\n")), + outputPackageFile().toString() + ).saveOutput(true).executeExpectSuccess().getOutput(); + + for (int i = 0; i != properties.size(); i++) { + Optional.ofNullable(properties.get(i).verifyValue(actualValues.get(i))).ifPresent(errors::add); + } + + return errors; + } + + @Override + protected void buildPackage() throws IOException { + + Path rpmFile = outputPackageFile(); + + Log.verbose(I18N.format("message.outputting-bundle-location", rpmFile.getParent())); + + //run rpmbuild + Executor.of(sysEnv.rpmbuild().toString(), + "-bb", specFile().toAbsolutePath().toString(), + "--define", String.format("%%_sourcedir %s", + env.appImageDir().toAbsolutePath()), + // save result to output dir + "--define", String.format("%%_rpmdir %s", rpmFile.getParent()), + // do not use other system directories to build as current user + "--define", String.format("%%_topdir %s", + env.buildRoot().toAbsolutePath()), + "--define", String.format("%%_rpmfilename %s", rpmFile.getFileName()) + ).executeExpectSuccess(); + + Log.verbose(I18N.format("message.output-bundle-location", rpmFile.getParent())); + } + + private Path installPrefix() { + Path path = pkg.relativeInstallDir(); + if (!pkg.isInstallDirInUsrTree()) { + path = path.getParent(); + } + return Path.of("/").resolve(path); + } + + private Path specFile() { + return env.buildRoot().resolve(Path.of("SPECS", pkg.packageName() + ".spec")); + } + + private final LinuxRpmSystemEnvironment sysEnv; +} diff --git a/src/hotspot/cpu/aarch64/bytecodes_aarch64.hpp b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmSystemEnvironment.java similarity index 56% rename from src/hotspot/cpu/aarch64/bytecodes_aarch64.hpp rename to src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmSystemEnvironment.java index 1daf71388e3..58c10668227 100644 --- a/src/hotspot/cpu/aarch64/bytecodes_aarch64.hpp +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmSystemEnvironment.java @@ -1,11 +1,12 @@ /* - * Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2014, Red Hat Inc. All rights reserved. + * 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. + * 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 @@ -20,12 +21,16 @@ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. - * */ +package jdk.jpackage.internal; + +import static jdk.jpackage.internal.LinuxSystemEnvironment.mixin; -#ifndef CPU_AARCH64_BYTECODES_AARCH64_HPP -#define CPU_AARCH64_BYTECODES_AARCH64_HPP +import jdk.jpackage.internal.util.Result; -// No aarch64 specific bytecodes +public interface LinuxRpmSystemEnvironment extends LinuxSystemEnvironment, LinuxRpmSystemEnvironmentMixin { -#endif // CPU_AARCH64_BYTECODES_AARCH64_HPP + static Result create(Result base) { + return mixin(LinuxRpmSystemEnvironment.class, base, LinuxRpmSystemEnvironmentMixin::create); + } +} diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmSystemEnvironmentMixin.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmSystemEnvironmentMixin.java new file mode 100644 index 00000000000..b741495f5ed --- /dev/null +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmSystemEnvironmentMixin.java @@ -0,0 +1,74 @@ +/* + * 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 jdk.jpackage.internal; + +import java.nio.file.Path; +import java.util.Objects; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Stream; +import jdk.jpackage.internal.model.DottedVersion; +import jdk.jpackage.internal.util.Result; + +public interface LinuxRpmSystemEnvironmentMixin { + Path rpm(); + Path rpmbuild(); + + record Stub(Path rpm, Path rpmbuild) implements LinuxRpmSystemEnvironmentMixin { + } + + static Result create() { + + final var errors = Stream.of( + Internal.createRpmbuildToolValidator(), + new ToolValidator(Internal.TOOL_RPM) + ).map(ToolValidator::validate).filter(Objects::nonNull).toList(); + + if (errors.isEmpty()) { + return Result.ofValue(new Stub(Internal.TOOL_RPM, Internal.TOOL_RPMBUILD)); + } else { + return Result.ofErrors(errors); + } + } + + static final class Internal { + private static ToolValidator createRpmbuildToolValidator() { + Pattern pattern = Pattern.compile(" (\\d+\\.\\d+)"); + return new ToolValidator(TOOL_RPMBUILD).setMinimalVersion( + TOOL_RPMBUILD_MIN_VERSION).setVersionParser(lines -> { + String versionString = lines.limit(1).findFirst().orElseThrow(); + Matcher matcher = pattern.matcher(versionString); + if (matcher.find()) { + return matcher.group(1); + } + return null; + }); + } + + private static final Path TOOL_RPM = Path.of("rpm"); + private static final Path TOOL_RPMBUILD = Path.of("rpmbuild"); + private static final DottedVersion TOOL_RPMBUILD_MIN_VERSION = DottedVersion.lazy("4.10"); + } +} diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxSystemEnvironment.java b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxSystemEnvironment.java new file mode 100644 index 00000000000..1a70cc938b8 --- /dev/null +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxSystemEnvironment.java @@ -0,0 +1,111 @@ +/* + * 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 jdk.jpackage.internal; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.function.Supplier; +import jdk.jpackage.internal.model.PackageType; +import jdk.jpackage.internal.model.StandardPackageType; +import jdk.jpackage.internal.util.CompositeProxy; +import jdk.jpackage.internal.util.Result; + +public interface LinuxSystemEnvironment extends SystemEnvironment { + boolean soLookupAvailable(); + PackageType nativePackageType(); + + static Result create() { + return detectNativePackageType().map(LinuxSystemEnvironment::create).orElseGet(() -> { + return Result.ofError(new RuntimeException("Unknown native package type")); + }); + } + + static Optional detectNativePackageType() { + if (Internal.isDebian()) { + return Optional.of(StandardPackageType.LINUX_DEB); + } else if (Internal.isRpm()) { + return Optional.of(StandardPackageType.LINUX_RPM); + } else { + return Optional.empty(); + } + } + + static Result create(PackageType nativePackageType) { + return Result.ofValue(new Stub(LibProvidersLookup.supported(), + Objects.requireNonNull(nativePackageType))); + } + + static U createWithMixin(Class type, LinuxSystemEnvironment base, T mixin) { + return CompositeProxy.create(type, base, mixin); + } + + static Result mixin(Class type, + Result base, Supplier> mixinResultSupplier) { + final var mixin = mixinResultSupplier.get(); + + final List errors = new ArrayList<>(); + errors.addAll(base.errors()); + errors.addAll(mixin.errors()); + + if (errors.isEmpty()) { + return Result.ofValue(createWithMixin(type, base.orElseThrow(), mixin.orElseThrow())); + } else { + return Result.ofErrors(errors); + } + } + + record Stub(boolean soLookupAvailable, PackageType nativePackageType) implements LinuxSystemEnvironment { + } + + static final class Internal { + + private static boolean isDebian() { + // we are just going to run "dpkg -s coreutils" and assume Debian + // or derivative if no error is returned. + try { + Executor.of("dpkg", "-s", "coreutils").executeExpectSuccess(); + return true; + } catch (IOException e) { + // just fall thru + return false; + } + } + + private static boolean isRpm() { + // we are just going to run "rpm -q rpm" and assume RPM + // or derivative if no error is returned. + try { + Executor.of("rpm", "-q", "rpm").executeExpectSuccess(); + return true; + } catch (IOException e) { + // just fall thru + return false; + } + } + } +} diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/AppImageSigner.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/AppImageSigner.java index 7563dfa0ed3..571f163f682 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/AppImageSigner.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/AppImageSigner.java @@ -237,7 +237,7 @@ static Codesigners create(CodesignConfig signingCfg) { final var codesignExecutableFile = Codesign.build(signingCfg::toCodesignArgs).quiet(true).create().asConsumer(); final var codesignFile = Codesign.build(signingCfgWithoutEntitlements::toCodesignArgs).quiet(true).create().asConsumer(); - final var codesignDir = Codesign.build(signingCfgWithoutEntitlements::toCodesignArgs).force(true).create().asConsumer(); + final var codesignDir = Codesign.build(signingCfg::toCodesignArgs).force(true).create().asConsumer(); return new Codesigners(codesignFile, codesignExecutableFile, codesignDir); } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgBundler.java index d2c72765d7a..0ddb987dbee 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgBundler.java @@ -25,12 +25,14 @@ package jdk.jpackage.internal; -import java.nio.file.Files; import java.nio.file.Path; import java.util.Map; import java.util.Objects; +import java.util.Optional; import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.MacDmgPackage; import jdk.jpackage.internal.model.PackagerException; +import jdk.jpackage.internal.util.Result; public class MacDmgBundler extends MacBaseInstallerBundler { @@ -70,39 +72,27 @@ public boolean validate(Map params) public Path execute(Map params, Path outputParentDir) throws PackagerException { - final var pkg = MacFromParams.DMG_PACKAGE.fetchFrom(params); - var env = MacBuildEnvFromParams.BUILD_ENV.fetchFrom(params); + var pkg = MacFromParams.DMG_PACKAGE.fetchFrom(params); - final var packager = MacDmgPackager.build().outputDir(outputParentDir).pkg(pkg).env(env); + Log.verbose(I18N.format("message.building-dmg", pkg.app().name())); - MacDmgPackager.findSetFileUtility().ifPresent(packager::setFileUtility); - - return packager.execute(); + return Packager.build().outputDir(outputParentDir) + .pkg(pkg) + .env(MacBuildEnvFromParams.BUILD_ENV.fetchFrom(params)) + .pipelineBuilderMutatorFactory((env, _, outputDir) -> { + return new MacDmgPackager(env, pkg, outputDir, sysEnv.orElseThrow()); + }).execute(MacPackagingPipeline.build(Optional.of(pkg))); } @Override public boolean supported(boolean runtimeInstaller) { - return isSupported(); - } - - public static final String[] required = - {"/usr/bin/hdiutil", "/usr/bin/osascript"}; - public static boolean isSupported() { - try { - for (String s : required) { - Path f = Path.of(s); - if (!Files.exists(f) || !Files.isExecutable(f)) { - return false; - } - } - return true; - } catch (Exception e) { - return false; - } + return sysEnv.hasValue(); } @Override public boolean isDefault() { return true; } + + private final Result sysEnv = MacDmgSystemEnvironment.create(); } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackager.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackager.java index eb3ad3a76c8..6e13a2ff0c1 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackager.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgPackager.java @@ -36,106 +36,25 @@ import java.util.HashMap; import java.util.Map; import java.util.Objects; -import java.util.Optional; -import java.util.stream.Stream; +import java.util.function.Consumer; import jdk.jpackage.internal.PackagingPipeline.PackageTaskID; -import jdk.jpackage.internal.PackagingPipeline.StartupParameters; import jdk.jpackage.internal.PackagingPipeline.TaskID; import jdk.jpackage.internal.model.MacDmgPackage; -import jdk.jpackage.internal.model.PackagerException; import jdk.jpackage.internal.util.FileUtils; import jdk.jpackage.internal.util.PathGroup; -record MacDmgPackager(MacDmgPackage pkg, BuildEnv env, Path hdiutil, Path outputDir, Optional setFileUtility) { +record MacDmgPackager(BuildEnv env, MacDmgPackage pkg, Path outputDir, + MacDmgSystemEnvironment sysEnv) implements Consumer { MacDmgPackager { - Objects.requireNonNull(pkg); Objects.requireNonNull(env); - Objects.requireNonNull(hdiutil); + Objects.requireNonNull(pkg); Objects.requireNonNull(outputDir); - Objects.requireNonNull(setFileUtility); - } - - static Builder build() { - return new Builder(); + Objects.requireNonNull(sysEnv); } - static final class Builder extends PackagerBuilder { - - Builder hdiutil(Path v) { - hdiutil = v; - return this; - } - - Builder setFileUtility(Path v) { - setFileUtility = v; - return this; - } - - Path execute() throws PackagerException { - Log.verbose(MessageFormat.format(I18N.getString("message.building-dmg"), - pkg.app().name())); - - IOUtils.writableOutputDir(outputDir); - - return execute(MacPackagingPipeline.build(Optional.of(pkg))); - } - - @Override - protected void configurePackagingPipeline(PackagingPipeline.Builder pipelineBuilder, - StartupParameters startupParameters) { - final var packager = new MacDmgPackager(pkg, startupParameters.packagingEnv(), - validatedHdiutil(), outputDir, Optional.ofNullable(setFileUtility)); - packager.applyToPipeline(pipelineBuilder); - } - - private Path validatedHdiutil() { - return Optional.ofNullable(hdiutil).orElse(HDIUTIL); - } - - private Path hdiutil; - private Path setFileUtility; - } - - // Location of SetFile utility may be different depending on MacOS version - // We look for several known places and if none of them work will - // try to find it - static Optional findSetFileUtility() { - String typicalPaths[] = {"/Developer/Tools/SetFile", - "/usr/bin/SetFile", "/Developer/usr/bin/SetFile"}; - - final var setFilePath = Stream.of(typicalPaths).map(Path::of).filter(Files::isExecutable).findFirst(); - if (setFilePath.isPresent()) { - // Validate SetFile, if Xcode is not installed it will run, but exit with error - // code - try { - if (Executor.of(setFilePath.orElseThrow().toString(), "-h").setQuiet(true).execute() == 0) { - return setFilePath; - } - } catch (Exception ignored) { - // No need for generic find attempt. We found it, but it does not work. - // Probably due to missing xcode. - return Optional.empty(); - } - } - - // generic find attempt - try { - final var executor = Executor.of("/usr/bin/xcrun", "-find", "SetFile"); - final var code = executor.setQuiet(true).saveOutput(true).execute(); - if (code == 0 && executor.getOutput().isEmpty()) { - final var firstLine = executor.getOutput().getFirst(); - Path f = Path.of(firstLine); - if (Files.exists(f) && Files.isExecutable(f)) { - return Optional.of(f.toAbsolutePath()); - } - } - } catch (IOException ignored) {} - - return Optional.empty(); - } - - private void applyToPipeline(PackagingPipeline.Builder pipelineBuilder) { + @Override + public void accept(PackagingPipeline.Builder pipelineBuilder) { pipelineBuilder .excludeDirFromCopying(outputDir) .task(DmgPackageTaskID.COPY_DMG_CONTENT) @@ -318,7 +237,7 @@ private void buildDMG() throws IOException { // create temp image ProcessBuilder pb = new ProcessBuilder( - hdiutil.toString(), + sysEnv.hdiutil().toString(), "create", hdiUtilVerbosityFlag, "-srcfolder", normalizedAbsolutePathString(srcFolder), @@ -341,7 +260,7 @@ private void buildDMG() throws IOException { // We need extra room for icons and background image. When we providing // actual files to hdiutil, it will create DMG with ~50 megabytes extra room. pb = new ProcessBuilder( - hdiutil.toString(), + sysEnv.hdiutil().toString(), "create", hdiUtilVerbosityFlag, "-size", String.valueOf(size), @@ -357,7 +276,7 @@ private void buildDMG() throws IOException { // mount temp image pb = new ProcessBuilder( - hdiutil.toString(), + sysEnv.hdiutil().toString(), "attach", normalizedAbsolutePathString(protoDMG), hdiUtilVerbosityFlag, @@ -382,7 +301,7 @@ private void buildDMG() throws IOException { // to install-dir in DMG as critical error, since it can fail in // headless environment. try { - pb = new ProcessBuilder("/usr/bin/osascript", + pb = new ProcessBuilder(sysEnv.osascript().toString(), normalizedAbsolutePathString(volumeScript())); IOUtils.exec(pb, 180); // Wait 3 minutes. See JDK-8248248. } catch (IOException ex) { @@ -397,7 +316,7 @@ private void buildDMG() throws IOException { // NB: attributes of the root directory are ignored // when creating the volume // Therefore we have to do this after we mount image - if (setFileUtility.isPresent()) { + if (sysEnv.setFileUtility().isPresent()) { //can not find utility => keep going without icon try { volumeIconFile.toFile().setWritable(true); @@ -406,14 +325,14 @@ private void buildDMG() throws IOException { // "icnC" for the volume icon // (might not work on Mac 10.13 with old XCode) pb = new ProcessBuilder( - setFileUtility.orElseThrow().toString(), + sysEnv.setFileUtility().orElseThrow().toString(), "-c", "icnC", normalizedAbsolutePathString(volumeIconFile)); IOUtils.exec(pb); volumeIconFile.toFile().setReadOnly(); pb = new ProcessBuilder( - setFileUtility.orElseThrow().toString(), + sysEnv.setFileUtility().orElseThrow().toString(), "-a", "C", normalizedAbsolutePathString(mountedVolume)); IOUtils.exec(pb); @@ -428,7 +347,7 @@ private void buildDMG() throws IOException { } finally { // Detach the temporary image pb = new ProcessBuilder( - hdiutil.toString(), + sysEnv.hdiutil().toString(), "detach", hdiUtilVerbosityFlag, normalizedAbsolutePathString(mountedVolume)); @@ -451,7 +370,7 @@ private void buildDMG() throws IOException { // Now force to detach if it still attached if (Files.exists(mountedVolume)) { pb = new ProcessBuilder( - hdiutil.toString(), + sysEnv.hdiutil().toString(), "detach", "-force", hdiUtilVerbosityFlag, @@ -464,7 +383,7 @@ private void buildDMG() throws IOException { // Compress it to a new image pb = new ProcessBuilder( - hdiutil.toString(), + sysEnv.hdiutil().toString(), "convert", normalizedAbsolutePathString(protoDMG), hdiUtilVerbosityFlag, @@ -481,7 +400,7 @@ private void buildDMG() throws IOException { Files.copy(protoDMG, protoCopyDMG); try { pb = new ProcessBuilder( - hdiutil.toString(), + sysEnv.hdiutil().toString(), "convert", normalizedAbsolutePathString(protoCopyDMG), hdiUtilVerbosityFlag, @@ -496,7 +415,7 @@ private void buildDMG() throws IOException { //add license if needed if (pkg.licenseFile().isPresent()) { pb = new ProcessBuilder( - hdiutil.toString(), + sysEnv.hdiutil().toString(), "udifrez", normalizedAbsolutePathString(finalDMG), "-xml", @@ -527,6 +446,4 @@ private void buildDMG() throws IOException { private static final String TEMPLATE_BUNDLE_ICON = "JavaApp.icns"; private static final String DEFAULT_LICENSE_PLIST="lic_template.plist"; - - private static final Path HDIUTIL = Path.of("/usr/bin/hdiutil"); } diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgSystemEnvironment.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgSystemEnvironment.java new file mode 100644 index 00000000000..54eb0c6f4fe --- /dev/null +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgSystemEnvironment.java @@ -0,0 +1,94 @@ +/* + * 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 jdk.jpackage.internal; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Stream; +import jdk.jpackage.internal.util.Result; + +record MacDmgSystemEnvironment(Path hdiutil, Path osascript, Optional setFileUtility) implements SystemEnvironment { + + MacDmgSystemEnvironment { + } + + static Result create() { + final var errors = Stream.of(HDIUTIL, OSASCRIPT) + .map(ToolValidator::new) + .map(ToolValidator::checkExistsOnly) + .map(ToolValidator::validate) + .filter(Objects::nonNull) + .toList(); + if (errors.isEmpty()) { + return Result.ofValue(new MacDmgSystemEnvironment(HDIUTIL, OSASCRIPT, findSetFileUtility())); + } else { + return Result.ofErrors(errors); + } + } + + // Location of SetFile utility may be different depending on MacOS version + // We look for several known places and if none of them work will + // try to find it + private static Optional findSetFileUtility() { + String typicalPaths[] = {"/Developer/Tools/SetFile", + "/usr/bin/SetFile", "/Developer/usr/bin/SetFile"}; + + final var setFilePath = Stream.of(typicalPaths).map(Path::of).filter(Files::isExecutable).findFirst(); + if (setFilePath.isPresent()) { + // Validate SetFile, if Xcode is not installed it will run, but exit with error + // code + try { + if (Executor.of(setFilePath.orElseThrow().toString(), "-h").setQuiet(true).execute() == 0) { + return setFilePath; + } + } catch (Exception ignored) { + // No need for generic find attempt. We found it, but it does not work. + // Probably due to missing xcode. + return Optional.empty(); + } + } + + // generic find attempt + try { + final var executor = Executor.of("/usr/bin/xcrun", "-find", "SetFile"); + final var code = executor.setQuiet(true).saveOutput(true).execute(); + if (code == 0 && !executor.getOutput().isEmpty()) { + final var firstLine = executor.getOutput().getFirst(); + Path f = Path.of(firstLine); + if (new ToolValidator(f).checkExistsOnly().validate() == null) { + return Optional.of(f.toAbsolutePath()); + } + } + } catch (IOException ignored) {} + + return Optional.empty(); + } + + private static final Path HDIUTIL = Path.of("/usr/bin/hdiutil"); + private static final Path OSASCRIPT = Path.of("/usr/bin/osascript"); +} diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java index bc19e7c4a1a..e827f238db3 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java @@ -28,7 +28,9 @@ import java.nio.file.Path; import java.util.Map; import java.util.Objects; +import java.util.Optional; import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.MacPkgPackage; import jdk.jpackage.internal.model.PackagerException; public class MacPkgBundler extends MacBaseInstallerBundler { @@ -49,7 +51,7 @@ public boolean validate(Map params) try { Objects.requireNonNull(params); - final var pkgPkg = MacFromParams.PKG_PACKAGE.fetchFrom(params); + final var pkg = MacFromParams.PKG_PACKAGE.fetchFrom(params); // run basic validation to ensure requirements are met // we are not interested in return code, only possible exception @@ -72,12 +74,16 @@ public boolean validate(Map params) public Path execute(Map params, Path outputParentDir) throws PackagerException { - final var pkg = MacFromParams.PKG_PACKAGE.fetchFrom(params); - var env = MacBuildEnvFromParams.BUILD_ENV.fetchFrom(params); + var pkg = MacFromParams.PKG_PACKAGE.fetchFrom(params); - final var packager = MacPkgPackager.build().outputDir(outputParentDir).pkg(pkg).env(env); + Log.verbose(I18N.format("message.building-pkg", pkg.app().name())); - return packager.execute(); + return Packager.build().outputDir(outputParentDir) + .pkg(pkg) + .env(MacBuildEnvFromParams.BUILD_ENV.fetchFrom(params)) + .pipelineBuilderMutatorFactory((env, _, outputDir) -> { + return new MacPkgPackager(env, pkg, outputDir); + }).execute(MacPackagingPipeline.build(Optional.of(pkg))); } @Override diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackager.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackager.java index 1fb0b9bc160..891c5b120f5 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackager.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgPackager.java @@ -41,6 +41,7 @@ import java.util.Map; import java.util.Objects; import java.util.Optional; +import java.util.function.Consumer; import java.util.stream.Stream; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; @@ -52,15 +53,25 @@ import jdk.internal.util.Architecture; import jdk.internal.util.OSVersion; import jdk.jpackage.internal.PackagingPipeline.PackageTaskID; -import jdk.jpackage.internal.PackagingPipeline.StartupParameters; import jdk.jpackage.internal.PackagingPipeline.TaskID; import jdk.jpackage.internal.model.MacPkgPackage; -import jdk.jpackage.internal.model.PackagerException; import jdk.jpackage.internal.resources.ResourceLocator; import jdk.jpackage.internal.util.XmlUtils; import org.xml.sax.SAXException; -record MacPkgPackager(MacPkgPackage pkg, BuildEnv env, Optional services, Path outputDir) { +record MacPkgPackager(BuildEnv env, MacPkgPackage pkg, Optional services, + Path outputDir) implements Consumer { + + MacPkgPackager { + Objects.requireNonNull(env); + Objects.requireNonNull(pkg); + Objects.requireNonNull(services); + Objects.requireNonNull(outputDir); + } + + MacPkgPackager(BuildEnv env, MacPkgPackage pkg, Path outputDir) { + this(env, pkg, createServices(env, pkg), outputDir); + } enum PkgPackageTaskID implements TaskID { PREPARE_MAIN_SCRIPTS, @@ -69,37 +80,6 @@ enum PkgPackageTaskID implements TaskID { PREPARE_SERVICES } - static Builder build() { - return new Builder(); - } - - static final class Builder extends PackagerBuilder { - - Path execute() throws PackagerException { - Log.verbose(MessageFormat.format(I18N.getString("message.building-pkg"), - pkg.app().name())); - - IOUtils.writableOutputDir(outputDir); - - return execute(MacPackagingPipeline.build(Optional.of(pkg))); - } - - @Override - protected void configurePackagingPipeline(PackagingPipeline.Builder pipelineBuilder, - StartupParameters startupParameters) { - final var packager = new MacPkgPackager(pkg, startupParameters.packagingEnv(), createServices(), outputDir); - packager.applyToPipeline(pipelineBuilder); - } - - private Optional createServices() { - if (pkg.app().isService()) { - return Optional.of(Services.create(pkg, env)); - } else { - return Optional.empty(); - } - } - } - record InternalPackage(Path srcRoot, String identifier, Path path, List otherPkgbuildArgs) { InternalPackage { @@ -230,7 +210,8 @@ private String filename(MacPkgPackage pkg) { private final Optional nameSuffix; } - private void applyToPipeline(PackagingPipeline.Builder pipelineBuilder) { + @Override + public void accept(PackagingPipeline.Builder pipelineBuilder) { pipelineBuilder .excludeDirFromCopying(outputDir) .task(PkgPackageTaskID.PREPARE_MAIN_SCRIPTS) @@ -559,6 +540,14 @@ private void productbuild() throws IOException { IOUtils.exec(pb, false, null, true, Executor.INFINITE_TIMEOUT); } + private static Optional createServices(BuildEnv env, MacPkgPackage pkg) { + if (pkg.app().isService()) { + return Optional.of(Services.create(pkg, env)); + } else { + return Optional.empty(); + } + } + private static final String DEFAULT_BACKGROUND_IMAGE = "background_pkg.png"; private static final String DEFAULT_PDF = "product-def.plist"; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagerBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Packager.java similarity index 57% rename from src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagerBuilder.java rename to src/jdk.jpackage/share/classes/jdk/jpackage/internal/Packager.java index 4ba2f0fbda6..501fd64bdca 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/PackagerBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Packager.java @@ -26,50 +26,80 @@ import java.nio.file.Path; import java.util.Objects; -import jdk.jpackage.internal.PackagingPipeline.StartupParameters; +import java.util.Optional; +import java.util.function.Consumer; import jdk.jpackage.internal.model.Package; import jdk.jpackage.internal.model.PackagerException; -abstract class PackagerBuilder> { +final class Packager { - U pkg(T v) { + static Packager build() { + return new Packager<>(); + } + + Packager pkg(T v) { pkg = v; - return thiz(); + return this; } - U env(BuildEnv v) { + Packager env(BuildEnv v) { env = v; - return thiz(); + return this; } - U outputDir(Path v) { + Packager outputDir(Path v) { outputDir = v; - return thiz(); + return this; + } + + Packager pipelineBuilderMutatorFactory(PipelineBuilderMutatorFactory v) { + pipelineBuilderMutatorFactory = v; + return this; } - @SuppressWarnings("unchecked") - private U thiz() { - return (U)this; + T pkg() { + return Objects.requireNonNull(pkg); } - protected abstract void configurePackagingPipeline(PackagingPipeline.Builder pipelineBuilder, - StartupParameters startupParameters); + Path outputDir() { + return Objects.requireNonNull(outputDir); + } + + BuildEnv env() { + return Objects.requireNonNull(env); + } Path execute(PackagingPipeline.Builder pipelineBuilder) throws PackagerException { Objects.requireNonNull(pkg); Objects.requireNonNull(env); Objects.requireNonNull(outputDir); + IOUtils.writableOutputDir(outputDir); + final var startupParameters = pipelineBuilder.createStartupParameters(env, pkg, outputDir); - configurePackagingPipeline(pipelineBuilder, startupParameters); + pipelineBuilderMutatorFactory().ifPresent(factory -> { + factory.create(startupParameters.packagingEnv(), pkg, outputDir).accept(pipelineBuilder); + }); pipelineBuilder.create().execute(startupParameters); return outputDir.resolve(pkg.packageFileNameWithSuffix()); } - protected T pkg; - protected BuildEnv env; - protected Path outputDir; + + @FunctionalInterface + interface PipelineBuilderMutatorFactory { + Consumer create(BuildEnv env, T pkg, Path outputDir); + } + + + private Optional> pipelineBuilderMutatorFactory() { + return Optional.ofNullable(pipelineBuilderMutatorFactory); + } + + private T pkg; + private BuildEnv env; + private Path outputDir; + private PipelineBuilderMutatorFactory pipelineBuilderMutatorFactory; } diff --git a/src/hotspot/cpu/aarch64/bytecodes_aarch64.cpp b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/SystemEnvironment.java similarity index 72% rename from src/hotspot/cpu/aarch64/bytecodes_aarch64.cpp rename to src/jdk.jpackage/share/classes/jdk/jpackage/internal/SystemEnvironment.java index 119ad8baec3..de98e97c922 100644 --- a/src/hotspot/cpu/aarch64/bytecodes_aarch64.cpp +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/SystemEnvironment.java @@ -1,11 +1,12 @@ /* - * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2014, Red Hat Inc. All rights reserved. + * 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. + * 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 @@ -20,9 +21,8 @@ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. - * */ +package jdk.jpackage.internal; -#include "interpreter/bytecodes.hpp" - - +public interface SystemEnvironment { +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ToolValidator.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ToolValidator.java index f673ac7e33e..13e87d5cfa6 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ToolValidator.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ToolValidator.java @@ -24,36 +24,31 @@ */ package jdk.jpackage.internal; -import jdk.internal.util.OperatingSystem; -import jdk.jpackage.internal.model.ConfigException; -import jdk.jpackage.internal.model.DottedVersion; import java.io.IOException; +import java.nio.file.Files; import java.nio.file.Path; -import java.text.MessageFormat; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.atomic.AtomicBoolean; +import java.util.Objects; import java.util.function.BiFunction; import java.util.function.Function; import java.util.stream.Stream; +import jdk.internal.util.OperatingSystem; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.DottedVersion; -public final class ToolValidator { +final class ToolValidator { ToolValidator(String tool) { this(Path.of(tool)); } ToolValidator(Path toolPath) { - this.toolPath = toolPath; - args = new ArrayList<>(); - + this.toolPath = Objects.requireNonNull(toolPath); if (OperatingSystem.isLinux()) { setCommandLine("--version"); } - - setToolNotFoundErrorHandler(null); - setToolOldVersionErrorHandler(null); } ToolValidator setCommandLine(String... args) { @@ -67,7 +62,17 @@ ToolValidator setMinimalVersion(Comparable v) { } ToolValidator setMinimalVersion(DottedVersion v) { - return setMinimalVersion(t -> DottedVersion.compareComponents(v, DottedVersion.lazy(t))); + return setMinimalVersion(new Comparable() { + @Override + public int compareTo(String o) { + return DottedVersion.compareComponents(v, DottedVersion.lazy(o)); + } + + @Override + public String toString() { + return v.toString(); + } + }); } ToolValidator setVersionParser(Function, String> v) { @@ -75,69 +80,85 @@ ToolValidator setVersionParser(Function, String> v) { return this; } - ToolValidator setToolNotFoundErrorHandler( - BiFunction v) { + ToolValidator setToolNotFoundErrorHandler(Function v) { toolNotFoundErrorHandler = v; return this; } - ToolValidator setToolOldVersionErrorHandler(BiFunction v) { + ToolValidator setToolOldVersionErrorHandler(BiFunction v) { toolOldVersionErrorHandler = v; return this; } + ToolValidator checkExistsOnly(boolean v) { + checkExistsOnly = v; + return this; + } + + ToolValidator checkExistsOnly() { + return checkExistsOnly(true); + } + ConfigException validate() { + if (checkExistsOnly) { + if (Files.isExecutable(toolPath) && !Files.isDirectory(toolPath)) { + return null; + } else if (Files.exists(toolPath)) { + return new ConfigException( + I18N.format("error.tool-not-executable", toolPath), (String)null); + } else if (toolNotFoundErrorHandler != null) { + return toolNotFoundErrorHandler.apply(toolPath); + } else { + return new ConfigException( + I18N.format("error.tool-not-found", toolPath), + I18N.format("error.tool-not-found.advice", toolPath)); + } + } + List cmdline = new ArrayList<>(); cmdline.add(toolPath.toString()); - cmdline.addAll(args); + if (args != null) { + cmdline.addAll(args); + } - String name = IOUtils.getFileName(toolPath).toString(); - try { - ProcessBuilder pb = new ProcessBuilder(cmdline); - AtomicBoolean canUseTool = new AtomicBoolean(); - if (minimalVersion == null) { - // No version check. - canUseTool.setPlain(true); - } + boolean canUseTool[] = new boolean[1]; + if (minimalVersion == null) { + // No version check. + canUseTool[0] = true; + } - String[] version = new String[1]; - Executor.of(pb).setQuiet(true).setOutputConsumer(lines -> { + String[] version = new String[1]; + + try { + Executor.of(cmdline.toArray(String[]::new)).setQuiet(true).setOutputConsumer(lines -> { if (versionParser != null && minimalVersion != null) { version[0] = versionParser.apply(lines); - if (minimalVersion.compareTo(version[0]) < 0) { - canUseTool.setPlain(true); + if (version[0] != null && minimalVersion.compareTo(version[0]) <= 0) { + canUseTool[0] = true; } } }).execute(); - - if (!canUseTool.getPlain()) { - if (toolOldVersionErrorHandler != null) { - return toolOldVersionErrorHandler.apply(name, version[0]); - } - return new ConfigException(MessageFormat.format(I18N.getString( - "error.tool-old-version"), name, minimalVersion), - MessageFormat.format(I18N.getString( - "error.tool-old-version.advice"), name, - minimalVersion)); - } } catch (IOException e) { - if (toolNotFoundErrorHandler != null) { - return toolNotFoundErrorHandler.apply(name, e); - } - return new ConfigException(MessageFormat.format(I18N.getString( - "error.tool-not-found"), name, e.getMessage()), - MessageFormat.format(I18N.getString( - "error.tool-not-found.advice"), name), e); + return new ConfigException(I18N.format("error.tool-error", toolPath, e.getMessage()), null, e); } - // All good. Tool can be used. - return null; + if (canUseTool[0]) { + // All good. Tool can be used. + return null; + } else if (toolOldVersionErrorHandler != null) { + return toolOldVersionErrorHandler.apply(toolPath, version[0]); + } else { + return new ConfigException( + I18N.format("error.tool-old-version", toolPath, minimalVersion), + I18N.format("error.tool-old-version.advice", toolPath, minimalVersion)); + } } private final Path toolPath; private List args; private Comparable minimalVersion; private Function, String> versionParser; - private BiFunction toolNotFoundErrorHandler; - private BiFunction toolOldVersionErrorHandler; + private Function toolNotFoundErrorHandler; + private BiFunction toolOldVersionErrorHandler; + private boolean checkExistsOnly; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties index 684a97bc1bd..967549f6855 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties @@ -66,10 +66,13 @@ error.no-content-types-for-file-association.advice=Specify MIME type for File As error.too-many-content-types-for-file-association=More than one MIME types was specified for File Association number {0} error.too-many-content-types-for-file-association.advice=Specify only one MIME type for File Association number {0} -error.tool-not-found=Can not find {0}. Reason: {1} -error.tool-not-found.advice=Please install {0} -error.tool-old-version=Can not find {0} {1} or newer -error.tool-old-version.advice=Please install {0} {1} or newer +error.tool-error=Can not validate "{0}". Reason: {1} +error.tool-not-executable="{0}" is not executable +error.tool-not-found=Can not find "{0}" +error.tool-not-found.advice=Please install "{0}" +error.tool-old-version=Can not find "{0}" {1} or newer +error.tool-old-version.advice=Please install "{0}" {1} or newer + error.jlink.failed=jlink failed with: {0} error.blocked.option=jlink option [{0}] is not permitted in --jlink-options error.no.name=Name not specified with --name and cannot infer one from app-image diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PListReader.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PListReader.java index 211a55897d0..6d7532bbd74 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PListReader.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PListReader.java @@ -24,21 +24,141 @@ */ package jdk.jpackage.internal.util; +import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; + import java.io.ByteArrayInputStream; import java.io.IOException; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.NoSuchElementException; import java.util.Objects; import java.util.Optional; +import java.util.stream.Stream; import javax.xml.parsers.ParserConfigurationException; +import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathFactory; -import jdk.jpackage.internal.util.function.ThrowingSupplier; +import org.w3c.dom.Element; import org.w3c.dom.Node; import org.xml.sax.SAXException; +/** + * Property list (plist) file reader. + */ public final class PListReader { + public record Raw(String value, Type type) { + + public enum Type { + STRING, + BOOLEAN, + REAL, + INTEGER, + DATE, + DATA; + + private static Optional fromElementName(String name) { + switch (name) { + case "string" -> { + return Optional.of(STRING); + } + case "true" -> { + return Optional.of(BOOLEAN); + } + case "false" -> { + return Optional.of(BOOLEAN); + } + case "real" -> { + return Optional.of(REAL); + } + case "integer" -> { + return Optional.of(INTEGER); + } + case "date" -> { + return Optional.of(DATE); + } + case "data" -> { + return Optional.of(DATA); + } + default -> { + return Optional.empty(); + } + } + } + } + + public Raw { + Objects.requireNonNull(value); + Objects.requireNonNull(type); + } + + private static Optional tryCreate(Element e) { + return Type.fromElementName(e.getNodeName()).map(type -> { + if (type == Type.BOOLEAN) { + if ("true".equals(e.getNodeName())) { + return new Raw(Boolean.TRUE.toString(), type); + } else { + return new Raw(Boolean.FALSE.toString(), type); + } + } else { + return new Raw(e.getTextContent(), type); + } + }); + } + } + + /** + * Returns the contents of the the underlying "dict" element as a Map. + *

+ * The keys in the returned map are names of the properties. + *

+ * Values of nested "dict" properties are stored as {@code Map} + * or {@code PListReader} objects depending on the value of the + * {@code fetchDictionaries} parameter. + *

+ * Values of "array" properties are stored as {@code List} objects. + *

+ * Values of other properties are stored as {@code Raw} objects. + * + * @param fetchDictionaries controls the type of objects of nested "dict" + * elements. If the value is {@code true}, + * {@code Map} type is used, and + * {@code PListReader} type otherwise. + * @return the contents of the the underlying "dict" element as a Map + */ + public Map toMap(boolean fetchDictionaries) { + Map reply = new HashMap<>(); + var nodes = root.getChildNodes(); + for (int i = 0; i != nodes.getLength(); i++) { + if (nodes.item(i) instanceof Element e) { + tryCreateValue(e, fetchDictionaries).ifPresent(value -> { + final var query = "preceding-sibling::*[1]"; + Optional.ofNullable(toSupplier(() -> { + return (Node) XPathSingleton.INSTANCE.evaluate(query, e, XPathConstants.NODE); + }).get()).ifPresent(n -> { + if ("key".equals(n.getNodeName())) { + var keyName = n.getTextContent(); + reply.putIfAbsent(keyName, value); + } + }); + }); + } + } + + return reply; + } + + /** + * Returns the value of the given string property in the underlying "dict" + * element. + * + * @param keyName the name of a string property whose value to query + * @return the value of the string property with the specified name in the + * underlying "dict" element + * @throws NoSuchElementException if there is no string property with the given + * name in the underlying "dict" element + */ public String queryValue(String keyName) { final var node = getNode(keyName); switch (node.getNodeName()) { @@ -51,6 +171,38 @@ public String queryValue(String keyName) { } } + /** + * Returns the value of the given "dict" property in the underlying "dict" + * element. + * + * @param keyName the name of a "dict" property whose value to query + * @return the value of the "dict" property with the specified name in the + * underlying "dict" element + * @throws NoSuchElementException if there is no "dict" property with the given + * name in the underlying "dict" element + */ + public PListReader queryDictValue(String keyName) { + final var node = getNode(keyName); + switch (node.getNodeName()) { + case "dict" -> { + return new PListReader(node); + } + default -> { + throw new NoSuchElementException(); + } + } + } + + /** + * Returns the value of the given boolean property in the underlying "dict" + * element. + * + * @param keyName the name of a boolean property whose value to query + * @return the value of the boolean property with the specified name in the + * underlying "dict" element + * @throws NoSuchElementException if there is no string property with the given + * name in the underlying "dict" element + */ public boolean queryBoolValue(String keyName) { final var node = getNode(keyName); switch (node.getNodeName()) { @@ -66,13 +218,58 @@ public boolean queryBoolValue(String keyName) { } } - public List queryArrayValue(String keyName) { + /** + * Returns the value of the given array property in the underlying "dict" + * element as a list of strings. + *

+ * Processes the result of calling {@link #queryArrayValue(String)} on the + * specified property name by filtering {@link Raw} instances of type + * {@link Raw.Type#STRING}. + * + * @param keyName the name of an array property whose value to query + * @return the value of the array property with the specified name in the + * underlying "dict" element + * @throws NoSuchElementException if there is no array property with the given + * name in the underlying "dict" element + */ + public List queryStringArrayValue(String keyName) { + return queryArrayValue(keyName, false).map(v -> { + if (v instanceof Raw r) { + if (r.type() == Raw.Type.STRING) { + return r.value(); + } + } + return (String)null; + }).filter(Objects::nonNull).toList(); + } + + /** + * Returns the value of the given array property in the underlying "dict" + * element as a stream of {@link Object}-s. + *

+ * Values of "dict" array items are stored as {@code Map} or + * {@code PListReader} objects depending on the value of the + * {@code fetchDictionaries} parameter. + *

+ * Values of "array" array items are stored as {@code List} objects. + *

+ * Values of other types are stored as {@code Raw} objects. + * + * @param keyName the name of an array property whose value to query + * @param fetchDictionaries controls the type of objects of "dict" elements. If + * the value is {@code true}, + * {@code Map} type is used, and + * {@code PListReader} type otherwise. + * @return the value of the array property with the specified name in the + * underlying "dict" element + * @throws NoSuchElementException if there is no array key with the given name + * in the underlying "dict" element + */ + public Stream queryArrayValue(String keyName, boolean fetchDictionaries) { final var node = getNode(keyName); switch (node.getNodeName()) { case "array" -> { - return XmlUtils.toStream(node.getChildNodes()).filter(n -> { - return n.getNodeName().equals("string"); - }).map(Node::getTextContent).toList(); + return readArray(node, fetchDictionaries); } default -> { throw new NoSuchElementException(); @@ -80,21 +277,75 @@ public List queryArrayValue(String keyName) { } } - public PListReader(Node doc) { - this.root = Objects.requireNonNull(doc); + /** + * Creates plist reader from the given node. + *

+ * If the specified node is an element with the name "dict", the reader is bound + * to the specified node; otherwise, it is bound to the {@code /plist/dict} + * element in the document. + * + * @param node the node + * @throws NoSuchElementException if the specified node is not an element with + * name "dict" and there is no + * {@code /plist/dict} node in the document + */ + public PListReader(Node node) { + Objects.requireNonNull(node); + if (node.getNodeName().equals("dict")) { + this.root = node; + } else { + this.root = Optional.ofNullable(toSupplier(() -> { + return (Node) XPathSingleton.INSTANCE.evaluate("/plist[1]/dict[1]", node, XPathConstants.NODE); + }).get()).orElseThrow(NoSuchElementException::new); + } } public PListReader(byte[] xmlData) throws ParserConfigurationException, SAXException, IOException { this(XmlUtils.initDocumentBuilder().parse(new ByteArrayInputStream(xmlData))); } + private Optional tryCreateValue(Element e, boolean fetchDictionaries) { + switch (e.getNodeName()) { + case "dict" -> { + var plistReader = new PListReader(e); + if (fetchDictionaries) { + return Optional.of(plistReader.toMap(fetchDictionaries)); + } else { + return Optional.of(plistReader); + } + } + case "array" -> { + return Optional.of(readArray(e, fetchDictionaries).toList()); + } + default -> { + return Raw.tryCreate(e); + } + } + } + + private Stream readArray(Node node, boolean fetchDictionaries) { + return XmlUtils.toStream(node.getChildNodes()).map(n -> { + if (n instanceof Element e) { + return tryCreateValue(e, fetchDictionaries); + } else { + return Optional.empty(); + } + }).filter(Optional::isPresent).map(Optional::get); + } + private Node getNode(String keyName) { - final var xPath = XPathFactory.newInstance().newXPath(); - final var query = String.format("//*[preceding-sibling::key = \"%s\"][1]", keyName); - return Optional.ofNullable(ThrowingSupplier.toSupplier(() -> { - return (Node) xPath.evaluate(query, root, XPathConstants.NODE); + Objects.requireNonNull(keyName); + final var query = String.format("*[preceding-sibling::key = \"%s\"][1]", keyName); + return Optional.ofNullable(toSupplier(() -> { + return (Node) XPathSingleton.INSTANCE.evaluate(query, root, XPathConstants.NODE); }).get()).orElseThrow(NoSuchElementException::new); } + + private static final class XPathSingleton { + private static final XPath INSTANCE = XPathFactory.newInstance().newXPath(); + } + + private final Node root; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/Result.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/Result.java new file mode 100644 index 00000000000..7bd6408183a --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/Result.java @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.util; + +import static jdk.jpackage.internal.util.function.ExceptionBox.rethrowUnchecked; + +import java.util.Collection; +import java.util.List; +import java.util.Optional; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.function.UnaryOperator; +import java.util.stream.StreamSupport; + + +public record Result(Optional value, Collection errors) { + public Result { + if (value.isEmpty() == errors.isEmpty()) { + throw new IllegalArgumentException(); + } + + if (value.isEmpty() && errors.isEmpty()) { + throw new IllegalArgumentException("Error collection must be non-empty"); + } + + } + + public T orElseThrow() { + firstError().ifPresent(ex -> { + rethrowUnchecked(ex); + }); + return value.orElseThrow(); + } + + public boolean hasValue() { + return value.isPresent(); + } + + public boolean hasErrors() { + return !errors.isEmpty(); + } + + public Result map(Function conv) { + return new Result<>(value.map(conv), errors); + } + + public Result flatMap(Function> conv) { + return value.map(conv).orElseGet(() -> { + return new Result<>(Optional.empty(), errors); + }); + } + + public Result mapErrors(UnaryOperator> errorsMapper) { + return new Result<>(value, errorsMapper.apply(errors)); + } + + public Result mapErrors() { + return new Result<>(Optional.empty(), errors); + } + + public Result peekErrors(Consumer> consumer) { + if (hasErrors()) { + consumer.accept(errors); + } + return this; + } + + public Result peekValue(Consumer consumer) { + value.ifPresent(consumer); + return this; + } + + public Optional firstError() { + return errors.stream().findFirst(); + } + + public static Result create(Supplier supplier) { + try { + return ofValue(supplier.get()); + } catch (Exception ex) { + return ofError(ex); + } + } + + public static Result ofValue(T value) { + return new Result<>(Optional.of(value), List.of()); + } + + public static Result ofErrors(Collection errors) { + return new Result<>(Optional.empty(), List.copyOf(errors)); + } + + public static Result ofError(Exception error) { + return ofErrors(List.of(error)); + } + + public static boolean allHaveValues(Iterable> results) { + return StreamSupport.stream(results.spliterator(), false).allMatch(Result::hasValue); + } + + public static boolean allHaveValues(Result... results) { + return allHaveValues(List.of(results)); + } +} diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExeBundler.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExeBundler.java index 54f43f05715..9ce758eb3c7 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExeBundler.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExeBundler.java @@ -24,17 +24,11 @@ */ package jdk.jpackage.internal; -import static jdk.jpackage.internal.StandardBundlerParam.ICON; -import static jdk.jpackage.internal.util.function.ThrowingRunnable.toRunnable; - -import java.io.IOException; -import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.StandardCopyOption; import java.util.Map; import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.PackagerException; -import jdk.jpackage.internal.model.WinExePackage; +import jdk.jpackage.internal.model.WinMsiPackage; @SuppressWarnings("restricted") public class WinExeBundler extends AbstractBundler { @@ -79,63 +73,23 @@ public Path execute(Map params, Path outdir) throws PackagerException { // Order is important! - var pkg = WinFromParams.MSI_PACKAGE.fetchFrom(params); + var pkg = WinFromParams.EXE_PACKAGE.fetchFrom(params); var env = BuildEnvFromParams.BUILD_ENV.fetchFrom(params); - IOUtils.writableOutputDir(outdir); - - Path msiDir = env.buildRoot().resolve("msi"); - toRunnable(() -> Files.createDirectories(msiDir)).run(); - - // Write msi to temporary directory. - Path msi = msiBundler.execute(params, msiDir); - - try { - new ScriptRunner() - .setDirectory(msi.getParent()) - .setResourceCategoryId("resource.post-msi-script") - .setScriptNameSuffix("post-msi") - .setEnvironmentVariable("JpMsiFile", msi.toAbsolutePath().toString()) - .run(env, pkg.packageName()); - - var exePkg = new WinExePackageBuilder(pkg).icon(ICON.fetchFrom(params)).create(); - return buildEXE(env, exePkg, msi, outdir); - } catch (IOException|ConfigException ex) { - Log.verbose(ex); - throw new PackagerException(ex); - } + var msiOutputDir = env.buildRoot().resolve("msi"); + + return Packager.build().outputDir(msiOutputDir) + .pkg(pkg.msiPackage()) + .env(env) + .pipelineBuilderMutatorFactory((packagingEnv, msiPackage, _) -> { + var msiPackager = new WinMsiPackager(packagingEnv, msiPackage, + msiOutputDir, msiBundler.sysEnv.orElseThrow()); + var exePackager = new WinExePackager(packagingEnv, pkg, outdir, msiOutputDir); + return msiPackager.andThen(exePackager); + }).execute(WinPackagingPipeline.build()); } - private Path buildEXE(BuildEnv env, WinExePackage pkg, Path msi, - Path outdir) throws IOException { - - Log.verbose(I18N.format("message.outputting-to-location", outdir.toAbsolutePath())); - - // Copy template msi wrapper next to msi file - final Path exePath = msi.getParent().resolve(pkg.packageFileNameWithSuffix()); - - env.createResource("msiwrapper.exe") - .setCategory(I18N.getString("resource.installer-exe")) - .setPublicName("installer.exe") - .saveToFile(exePath); - - new ExecutableRebrander(pkg, env::createResource, resourceLock -> { - // Embed msi in msi wrapper exe. - embedMSI(resourceLock, msi.toAbsolutePath().toString()); - }).execute(env, exePath, pkg.icon()); - - Path dstExePath = outdir.resolve(exePath.getFileName()); - - Files.copy(exePath, dstExePath, StandardCopyOption.REPLACE_EXISTING); - - dstExePath.toFile().setExecutable(true); - - Log.verbose(I18N.format("message.output-location", outdir.toAbsolutePath())); - - return dstExePath; - } + static native int embedMSI(long resourceLock, String msiPath); private final WinMsiBundler msiBundler = new WinMsiBundler(); - - private static native int embedMSI(long resourceLock, String msiPath); } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackager.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackager.java new file mode 100644 index 00000000000..9a13a0f954d --- /dev/null +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExePackager.java @@ -0,0 +1,108 @@ +/* + * 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 jdk.jpackage.internal; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; +import java.util.Objects; +import java.util.function.Consumer; +import jdk.jpackage.internal.PackagingPipeline.PackageTaskID; +import jdk.jpackage.internal.PackagingPipeline.PrimaryTaskID; +import jdk.jpackage.internal.PackagingPipeline.TaskID; +import jdk.jpackage.internal.model.WinExePackage; + +final record WinExePackager(BuildEnv env, WinExePackage pkg, Path outputDir, Path msiOutputDir) implements Consumer { + + WinExePackager { + Objects.requireNonNull(env); + Objects.requireNonNull(pkg); + Objects.requireNonNull(outputDir); + Objects.requireNonNull(msiOutputDir); + } + + enum ExePackageTaskID implements TaskID { + RUN_POST_MSI_USER_SCRIPT, + WRAP_MSI_IN_EXE + } + + @Override + public void accept(PackagingPipeline.Builder pipelineBuilder) { + pipelineBuilder.excludeDirFromCopying(outputDir) + .task(ExePackageTaskID.RUN_POST_MSI_USER_SCRIPT) + .action(this::runPostMsiScript) + .addDependency(PackageTaskID.CREATE_PACKAGE_FILE) + .add() + .task(ExePackageTaskID.WRAP_MSI_IN_EXE) + .action(this::wrapMsiInExe) + .addDependency(ExePackageTaskID.RUN_POST_MSI_USER_SCRIPT) + .addDependent(PrimaryTaskID.PACKAGE) + .add(); + } + + private Path msi() { + return msiOutputDir.resolve(pkg.msiPackage().packageFileNameWithSuffix()); + } + + private void runPostMsiScript() throws IOException { + new ScriptRunner() + .setDirectory(msiOutputDir) + .setResourceCategoryId("resource.post-msi-script") + .setScriptNameSuffix("post-msi") + .setEnvironmentVariable("JpMsiFile", msi().toAbsolutePath().toString()) + .run(env, pkg.msiPackage().packageName()); + } + + private void wrapMsiInExe() throws IOException { + + Log.verbose(I18N.format("message.outputting-to-location", outputDir.toAbsolutePath())); + + final var msi = msi(); + + // Copy template msi wrapper next to msi file + final Path exePath = msi.getParent().resolve(pkg.packageFileNameWithSuffix()); + + env.createResource("msiwrapper.exe") + .setCategory(I18N.getString("resource.installer-exe")) + .setPublicName("installer.exe") + .saveToFile(exePath); + + new ExecutableRebrander(pkg, env::createResource, resourceLock -> { + // Embed msi in msi wrapper exe. + WinExeBundler.embedMSI(resourceLock, msi.toAbsolutePath().toString()); + }).execute(env, exePath, pkg.icon()); + + Path dstExePath = outputDir.resolve(exePath.getFileName()); + + Files.createDirectories(dstExePath.getParent()); + Files.copy(exePath, dstExePath, StandardCopyOption.REPLACE_EXISTING); + + dstExePath.toFile().setExecutable(true); + + Log.verbose(I18N.format("message.output-location", outputDir.toAbsolutePath())); + } +} diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinFromParams.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinFromParams.java index e2259535058..29c1b665f86 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinFromParams.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinFromParams.java @@ -31,6 +31,7 @@ import static jdk.jpackage.internal.FromParams.createPackageBuilder; import static jdk.jpackage.internal.FromParams.createPackageBundlerParam; import static jdk.jpackage.internal.FromParams.findLauncherShortcut; +import static jdk.jpackage.internal.StandardBundlerParam.ICON; import static jdk.jpackage.internal.StandardBundlerParam.RESOURCE_DIR; import static jdk.jpackage.internal.WinPackagingPipeline.APPLICATION_LAYOUT; import static jdk.jpackage.internal.model.StandardPackageType.WIN_MSI; @@ -41,6 +42,7 @@ import java.util.UUID; import jdk.jpackage.internal.model.ConfigException; import jdk.jpackage.internal.model.WinApplication; +import jdk.jpackage.internal.model.WinExePackage; import jdk.jpackage.internal.model.WinLauncher; import jdk.jpackage.internal.model.WinLauncherMixin; import jdk.jpackage.internal.model.WinMsiPackage; @@ -99,12 +101,26 @@ private static WinMsiPackage createWinMsiPackage(Map par return pkgBuilder.create(); } + private static WinExePackage createWinExePackage(Map params) throws ConfigException, IOException { + + final var msiPkg = MSI_PACKAGE.fetchFrom(params); + + final var pkgBuilder = new WinExePackageBuilder(msiPkg); + + ICON.copyInto(params, pkgBuilder::icon); + + return pkgBuilder.create(); + } + static final BundlerParamInfo APPLICATION = createApplicationBundlerParam( WinFromParams::createWinApplication); static final BundlerParamInfo MSI_PACKAGE = createPackageBundlerParam( WinFromParams::createWinMsiPackage); + static final BundlerParamInfo EXE_PACKAGE = createPackageBundlerParam( + WinFromParams::createWinExePackage); + private static final BundlerParamInfo WIN_MENU_HINT = createStringBundlerParam( Arguments.CLIOptions.WIN_MENU_HINT.getId()); diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java index 9bd0c679146..3ca26f38f82 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java @@ -27,115 +27,16 @@ import static jdk.jpackage.internal.model.ConfigException.rethrowConfigException; -import java.io.IOException; -import java.io.InputStream; -import java.io.UncheckedIOException; -import java.io.Writer; -import java.nio.charset.Charset; -import java.nio.file.FileSystems; -import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.PathMatcher; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.LinkedHashSet; -import java.util.List; import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.xpath.XPath; -import javax.xml.xpath.XPathConstants; -import javax.xml.xpath.XPathExpressionException; -import javax.xml.xpath.XPathFactory; -import jdk.jpackage.internal.PackagingPipeline.PackageBuildEnv; -import jdk.jpackage.internal.model.AppImageLayout; -import jdk.jpackage.internal.model.ApplicationLayout; import jdk.jpackage.internal.model.ConfigException; -import jdk.jpackage.internal.model.Package; import jdk.jpackage.internal.model.PackagerException; -import jdk.jpackage.internal.model.RuntimeLayout; import jdk.jpackage.internal.model.WinMsiPackage; -import org.w3c.dom.Document; -import org.w3c.dom.NodeList; -import org.xml.sax.SAXException; +import jdk.jpackage.internal.util.Result; -/** - * WinMsiBundler - * - * Produces .msi installer from application image. Uses WiX Toolkit to build - * .msi installer. - *

- * {@link #execute} method creates a number of source files with the description - * of installer to be processed by WiX tools. Generated source files are stored - * in "config" subdirectory next to "app" subdirectory in the root work - * directory. The following WiX source files are generated: - *

    - *
  • main.wxs. Main source file with the installer description - *
  • bundle.wxf. Source file with application and Java run-time directory tree - * description. - *
  • ui.wxf. Source file with UI description of the installer. - *
- * - *

- * main.wxs file is a copy of main.wxs resource from - * jdk.jpackage.internal.resources package. It is parametrized with the - * following WiX variables: - *

    - *
  • JpAppName. Name of the application. Set to the value of --name command - * line option - *
  • JpAppVersion. Version of the application. Set to the value of - * --app-version command line option - *
  • JpAppVendor. Vendor of the application. Set to the value of --vendor - * command line option - *
  • JpAppDescription. Description of the application. Set to the value of - * --description command line option - *
  • JpProductCode. Set to product code UUID of the application. Random value - * generated by jpackage every time {@link #execute} method is called - *
  • JpProductUpgradeCode. Set to upgrade code UUID of the application. Random - * value generated by jpackage every time {@link #execute} method is called if - * --win-upgrade-uuid command line option is not specified. Otherwise this - * variable is set to the value of --win-upgrade-uuid command line option - *
  • JpAllowUpgrades. Set to "yes", but all that matters is it is defined. - *
  • JpAllowDowngrades. Defined for application installers, and undefined for - * Java runtime installers. - *
  • JpConfigDir. Absolute path to the directory with generated WiX source - * files. - *
  • JpIsSystemWide. Set to "yes" if --win-per-user-install command line - * option was not specified. Undefined otherwise - *
  • JpAppSizeKb. Set to estimated size of the application in kilobytes - *
  • JpHelpURL. Set to value of --win-help-url command line option if it - * was specified. Undefined otherwise - *
  • JpAboutURL. Set to value of --about-url command line option if it - * was specified. Undefined otherwise - *
  • JpUpdateURL. Set to value of --win-update-url command line option if it - * was specified. Undefined otherwise - *
- * - *

- * ui.wxf file is generated based on --license-file, --win-shortcut-prompt, - * --win-dir-chooser command line options. It is parametrized with the following - * WiX variables: - *

    - *
  • JpLicenseRtf. Set to the value of --license-file command line option. - * Undefined if --license-file command line option was not specified - *
- */ public class WinMsiBundler extends AbstractBundler { public WinMsiBundler() { - wixFragments = Stream.of( - Map.entry("bundle.wxf", new WixAppImageFragmentBuilder()), - Map.entry("ui.wxf", new WixUiFragmentBuilder()), - Map.entry("os-condition.wxf", OSVersionCondition.createWixFragmentBuilder()) - ).map(e -> { - e.getValue().setOutputFileName(e.getKey()); - return e.getValue(); - }).toList(); } @Override @@ -156,10 +57,12 @@ public String getBundleType() { @Override public boolean supported(boolean platformInstaller) { try { - if (wixToolset == null) { - wixToolset = WixTool.createToolset(); + try { + sysEnv.orElseThrow(); + return true; + } catch (RuntimeException ex) { + ConfigException.rethrowConfigException(ex); } - return true; } catch (ConfigException ce) { Log.error(ce.getMessage()); if (ce.getAdvice() != null) { @@ -184,9 +87,7 @@ public boolean validate(Map params) WinFromParams.APPLICATION.fetchFrom(params); BuildEnvFromParams.BUILD_ENV.fetchFrom(params); - if (wixToolset == null) { - wixToolset = WixTool.createToolset(); - } + final var wixToolset = sysEnv.orElseThrow().wixToolset(); for (var tool : wixToolset.getType().getTools()) { Log.verbose(I18N.format("message.tool-version", @@ -194,367 +95,23 @@ public boolean validate(Map params) wixToolset.getVersion())); } - wixFragments.forEach(wixFragment -> wixFragment.setWixVersion(wixToolset.getVersion(), - wixToolset.getType())); - - wixFragments.stream().map(WixFragmentBuilder::getLoggableWixFeatures).flatMap( - List::stream).distinct().toList().forEach(Log::verbose); - return true; } catch (RuntimeException re) { throw rethrowConfigException(re); } } - private void prepareProto(Package pkg, BuildEnv env, AppImageLayout appImageLayout) throws - PackagerException, IOException { - - // Configure installer icon - if (appImageLayout instanceof RuntimeLayout runtimeLayout) { - // Use icon from java launcher. - // Assume java.exe exists in Java Runtime being packed. - // Ignore custom icon if any as we don't want to copy anything in - // Java Runtime image. - installerIcon = runtimeLayout.runtimeDirectory().resolve(Path.of("bin", "java.exe")); - } else if (appImageLayout instanceof ApplicationLayout appLayout) { - installerIcon = appLayout.launchersDirectory().resolve( - pkg.app().mainLauncher().orElseThrow().executableNameWithSuffix()); - } - installerIcon = installerIcon.toAbsolutePath(); - - pkg.licenseFile().ifPresent(licenseFile -> { - // need to copy license file to the working directory - // and convert to rtf if needed - Path destFile = env.configDir().resolve(licenseFile.getFileName()); - - try { - IOUtils.copyFile(licenseFile, destFile); - } catch (IOException ex) { - throw new UncheckedIOException(ex); - } - destFile.toFile().setWritable(true); - ensureByMutationFileIsRTF(destFile); - }); - } - @Override public Path execute(Map params, Path outputParentDir) throws PackagerException { - IOUtils.writableOutputDir(outputParentDir); - - // Order is important! - var pkg = WinFromParams.MSI_PACKAGE.fetchFrom(params); - var env = BuildEnvFromParams.BUILD_ENV.fetchFrom(params); - - WinPackagingPipeline.build() - .excludeDirFromCopying(outputParentDir) - .task(PackagingPipeline.PackageTaskID.CREATE_CONFIG_FILES) - .packageAction(this::prepareConfigFiles) - .add() - .task(PackagingPipeline.PackageTaskID.CREATE_PACKAGE_FILE) - .packageAction(this::buildPackage) - .add() - .create().execute(env, pkg, outputParentDir); - - return outputParentDir.resolve(pkg.packageFileNameWithSuffix()).toAbsolutePath(); - } - - private void prepareConfigFiles(PackageBuildEnv env) throws PackagerException, IOException { - prepareProto(env.pkg(), env.env(), env.resolvedLayout()); - for (var wixFragment : wixFragments) { - wixFragment.initFromParams(env.env(), env.pkg()); - wixFragment.addFilesToConfigRoot(); - } - - final var msiOut = env.outputDir().resolve(env.pkg().packageFileNameWithSuffix()); - - Log.verbose(I18N.format("message.preparing-msi-config", msiOut.toAbsolutePath())); - - final var wixVars = createWixVars(env); - - final var wixObjDir = env.env().buildRoot().resolve("wixobj"); - - final var configDir = env.env().configDir(); - - final var wixPipelineBuilder = WixPipeline.build() - .setWixObjDir(wixObjDir) - .setWorkDir(env.env().appImageDir()) - .addSource(configDir.resolve("main.wxs"), wixVars); - - for (var wixFragment : wixFragments) { - wixFragment.configureWixPipeline(wixPipelineBuilder); - } - - switch (wixToolset.getType()) { - case Wix3 -> { - wixPipelineBuilder.addLightOptions("-sice:ICE27"); - - if (!env.pkg().isSystemWideInstall()) { - wixPipelineBuilder.addLightOptions("-sice:ICE91"); - } - } - case Wix4 -> { - } - default -> { - throw new IllegalArgumentException(); - } - } - - var primaryWxlFiles = Stream.of("de", "en", "ja", "zh_CN").map(loc -> { - return configDir.resolve("MsiInstallerStrings_" + loc + ".wxl"); - }).toList(); - - var wixResources = new WixSourceConverter.ResourceGroup(wixToolset.getType()); - - // Copy standard l10n files. - for (var path : primaryWxlFiles) { - var name = path.getFileName().toString(); - wixResources.addResource(env.env().createResource(name).setPublicName(name).setCategory( - I18N.getString("resource.wxl-file")), path); - } - - wixResources.addResource(env.env().createResource("main.wxs").setPublicName("main.wxs"). - setCategory(I18N.getString("resource.main-wix-file")), configDir.resolve("main.wxs")); - - wixResources.addResource(env.env().createResource("overrides.wxi").setPublicName( - "overrides.wxi").setCategory(I18N.getString("resource.overrides-wix-file")), - configDir.resolve("overrides.wxi")); - - // Filter out custom l10n files that were already used to - // override primary l10n files. Ignore case filename comparison, - // both lists are expected to be short. - List customWxlFiles = env.env().resourceDir() - .map(WinMsiBundler::getWxlFilesFromDir) - .orElseGet(Collections::emptyList) - .stream() - .filter(custom -> primaryWxlFiles.stream().noneMatch(primary -> - primary.getFileName().toString().equalsIgnoreCase( - custom.getFileName().toString()))) - .peek(custom -> Log.verbose(I18N.format( - "message.using-custom-resource", String.format("[%s]", - I18N.getString("resource.wxl-file")), - custom.getFileName()))).toList(); - - // Copy custom l10n files. - for (var path : customWxlFiles) { - var name = path.getFileName().toString(); - wixResources.addResource(env.env().createResource(name).setPublicName(name). - setSourceOrder(OverridableResource.Source.ResourceDir).setCategory(I18N. - getString("resource.wxl-file")), configDir.resolve(name)); - } - - // Save all WiX resources into config dir. - wixResources.saveResources(); - - // All l10n files are supplied to WiX with "-loc", but only - // Cultures from custom files and a single primary Culture are - // included into "-cultures" list - for (var wxl : primaryWxlFiles) { - wixPipelineBuilder.addLightOptions("-loc", wxl.toString()); - } - - List cultures = new ArrayList<>(); - for (var wxl : customWxlFiles) { - wxl = configDir.resolve(wxl.getFileName()); - wixPipelineBuilder.addLightOptions("-loc", wxl.toString()); - cultures.add(getCultureFromWxlFile(wxl)); - } - - // Append a primary culture bases on runtime locale. - final Path primaryWxlFile = configDir.resolve( - I18N.getString("resource.wxl-file-name")); - cultures.add(getCultureFromWxlFile(primaryWxlFile)); - - // Build ordered list of unique cultures. - Set uniqueCultures = new LinkedHashSet<>(); - uniqueCultures.addAll(cultures); - switch (wixToolset.getType()) { - case Wix3 -> { - wixPipelineBuilder.addLightOptions(uniqueCultures.stream().collect(Collectors.joining(";", - "-cultures:", ""))); - } - case Wix4 -> { - uniqueCultures.forEach(culture -> { - wixPipelineBuilder.addLightOptions("-culture", culture); - }); - } - default -> { - throw new IllegalArgumentException(); - } - } - - Files.createDirectories(wixObjDir); - wixPipeline = wixPipelineBuilder.create(wixToolset); - } - - private void buildPackage(PackageBuildEnv env) throws PackagerException, IOException { - final var msiOut = env.outputDir().resolve(env.pkg().packageFileNameWithSuffix()); - Log.verbose(I18N.format("message.generating-msi", msiOut.toAbsolutePath())); - wixPipeline.buildMsi(msiOut.toAbsolutePath()); - } - - private Map createWixVars(PackageBuildEnv env) throws IOException { - Map data = new HashMap<>(); - - final var pkg = env.pkg(); - - data.put("JpProductCode", pkg.productCode().toString()); - data.put("JpProductUpgradeCode", pkg.upgradeCode().toString()); - - Log.verbose(I18N.format("message.product-code", pkg.productCode())); - Log.verbose(I18N.format("message.upgrade-code", pkg.upgradeCode())); - - data.put("JpAllowUpgrades", "yes"); - if (!pkg.isRuntimeInstaller()) { - data.put("JpAllowDowngrades", "yes"); - } - - data.put("JpAppName", pkg.packageName()); - data.put("JpAppDescription", pkg.description()); - data.put("JpAppVendor", pkg.app().vendor()); - data.put("JpAppVersion", pkg.version()); - if (Files.exists(installerIcon)) { - data.put("JpIcon", installerIcon.toString()); - } - - pkg.helpURL().ifPresent(value -> { - data.put("JpHelpURL", value); - }); - - pkg.updateURL().ifPresent(value -> { - data.put("JpUpdateURL", value); - }); - - pkg.aboutURL().ifPresent(value -> { - data.put("JpAboutURL", value); - }); - - data.put("JpAppSizeKb", Long.toString(AppImageLayout.toPathGroup( - env.resolvedLayout()).sizeInBytes() >> 10)); - - data.put("JpConfigDir", env.env().configDir().toAbsolutePath().toString()); - - if (pkg.isSystemWideInstall()) { - data.put("JpIsSystemWide", "yes"); - } - - return data; - } - - private static List getWxlFilesFromDir(Path dir) { - final String glob = "glob:**/*.wxl"; - final PathMatcher pathMatcher = FileSystems.getDefault().getPathMatcher( - glob); - - try (var walk = Files.walk(dir, 1)) { - return walk - .filter(Files::isReadable) - .filter(pathMatcher::matches) - .sorted((a, b) -> a.getFileName().toString().compareToIgnoreCase(b.getFileName().toString())) - .toList(); - } catch (IOException ex) { - throw new UncheckedIOException(ex); - } - } - - private static String getCultureFromWxlFile(Path wxlPath) { - try { - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setNamespaceAware(false); - DocumentBuilder builder = factory.newDocumentBuilder(); - - Document doc = builder.parse(wxlPath.toFile()); - - XPath xPath = XPathFactory.newInstance().newXPath(); - NodeList nodes = (NodeList) xPath.evaluate( - "//WixLocalization/@Culture", doc, XPathConstants.NODESET); - if (nodes.getLength() != 1) { - throw new IOException(I18N.format( - "error.extract-culture-from-wix-l10n-file", - wxlPath.toAbsolutePath().normalize())); - } - - return nodes.item(0).getNodeValue(); - } catch (XPathExpressionException | ParserConfigurationException - | SAXException ex) { - throw new UncheckedIOException(new IOException( - I18N.format("error.read-wix-l10n-file", wxlPath.toAbsolutePath().normalize()), ex)); - } catch (IOException ex) { - throw new UncheckedIOException(ex); - } - } - - private static void ensureByMutationFileIsRTF(Path f) { - try { - boolean existingLicenseIsRTF = false; - - try (InputStream fin = Files.newInputStream(f)) { - byte[] firstBits = new byte[7]; - - if (fin.read(firstBits) == firstBits.length) { - String header = new String(firstBits); - existingLicenseIsRTF = "{\\rtf1\\".equals(header); - } - } - - if (!existingLicenseIsRTF) { - List oldLicense = Files.readAllLines(f); - try (Writer w = Files.newBufferedWriter( - f, Charset.forName("Windows-1252"))) { - w.write("{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang1033" - + "{\\fonttbl{\\f0\\fnil\\fcharset0 Arial;}}\n" - + "\\viewkind4\\uc1\\pard\\sa200\\sl276" - + "\\slmult1\\lang9\\fs20 "); - oldLicense.forEach(l -> { - try { - for (char c : l.toCharArray()) { - // 0x00 <= ch < 0x20 Escaped (\'hh) - // 0x20 <= ch < 0x80 Raw(non - escaped) char - // 0x80 <= ch <= 0xFF Escaped(\ 'hh) - // 0x5C, 0x7B, 0x7D (special RTF characters - // \,{,})Escaped(\'hh) - // ch > 0xff Escaped (\\ud###?) - if (c < 0x10) { - w.write("\\'0"); - w.write(Integer.toHexString(c)); - } else if (c > 0xff) { - w.write("\\ud"); - w.write(Integer.toString(c)); - // \\uc1 is in the header and in effect - // so we trail with a replacement char if - // the font lacks that character - '?' - w.write("?"); - } else if ((c < 0x20) || (c >= 0x80) || - (c == 0x5C) || (c == 0x7B) || - (c == 0x7D)) { - w.write("\\'"); - w.write(Integer.toHexString(c)); - } else { - w.write(c); - } - } - // blank lines are interpreted as paragraph breaks - if (l.length() < 1) { - w.write("\\par"); - } else { - w.write(" "); - } - w.write("\r\n"); - } catch (IOException e) { - Log.verbose(e); - } - }); - w.write("}\r\n"); - } - } - } catch (IOException e) { - Log.verbose(e); - } + return Packager.build().outputDir(outputParentDir) + .pkg(WinFromParams.MSI_PACKAGE.fetchFrom(params)) + .env(BuildEnvFromParams.BUILD_ENV.fetchFrom(params)) + .pipelineBuilderMutatorFactory((env, pkg, outputDir) -> { + return new WinMsiPackager(env, pkg, outputDir, sysEnv.orElseThrow()); + }).execute(WinPackagingPipeline.build()); } - private Path installerIcon; - private WixToolset wixToolset; - private WixPipeline wixPipeline; - private final List wixFragments; + final Result sysEnv = WinSystemEnvironment.create(); } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackager.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackager.java new file mode 100644 index 00000000000..99b6c367fec --- /dev/null +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackager.java @@ -0,0 +1,486 @@ +/* + * 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 jdk.jpackage.internal; + +import java.io.IOException; +import java.io.InputStream; +import java.io.UncheckedIOException; +import java.io.Writer; +import java.nio.charset.Charset; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.PathMatcher; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.function.Consumer; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathExpressionException; +import javax.xml.xpath.XPathFactory; +import jdk.jpackage.internal.model.AppImageLayout; +import jdk.jpackage.internal.model.PackagerException; +import jdk.jpackage.internal.model.RuntimeLayout; +import jdk.jpackage.internal.model.WinMsiPackage; +import org.w3c.dom.Document; +import org.w3c.dom.NodeList; +import org.xml.sax.SAXException; + +/** + * WinMsiPackager + * + * Produces .msi installer from application image. Uses WiX Toolkit to build + * .msi installer. + *

+ * Creates a number of source files with the description + * of installer to be processed by WiX tools. Generated source files are stored + * in "config" subdirectory next to "app" subdirectory in the root work + * directory. The following WiX source files are generated: + *

    + *
  • main.wxs. Main source file with the installer description + *
  • bundle.wxf. Source file with application and Java run-time directory tree + * description. + *
  • ui.wxf. Source file with UI description of the installer. + *
+ * + *

+ * main.wxs file is a copy of main.wxs resource from + * jdk.jpackage.internal.resources package. It is parametrized with the + * following WiX variables: + *

    + *
  • JpAppName. Name of the application. Set to the value of --name command + * line option + *
  • JpAppVersion. Version of the application. Set to the value of + * --app-version command line option + *
  • JpAppVendor. Vendor of the application. Set to the value of --vendor + * command line option + *
  • JpAppDescription. Description of the application. Set to the value of + * --description command line option + *
  • JpProductCode. Set to product code UUID of the application. Random value + * generated by jpackage every time {@link #execute} method is called + *
  • JpProductUpgradeCode. Set to upgrade code UUID of the application. Random + * value generated by jpackage every time {@link #execute} method is called if + * --win-upgrade-uuid command line option is not specified. Otherwise this + * variable is set to the value of --win-upgrade-uuid command line option + *
  • JpAllowUpgrades. Set to "yes", but all that matters is it is defined. + *
  • JpAllowDowngrades. Defined for application installers, and undefined for + * Java runtime installers. + *
  • JpConfigDir. Absolute path to the directory with generated WiX source + * files. + *
  • JpIsSystemWide. Set to "yes" if --win-per-user-install command line + * option was not specified. Undefined otherwise + *
  • JpAppSizeKb. Set to estimated size of the application in kilobytes + *
  • JpHelpURL. Set to value of --win-help-url command line option if it + * was specified. Undefined otherwise + *
  • JpAboutURL. Set to value of --about-url command line option if it + * was specified. Undefined otherwise + *
  • JpUpdateURL. Set to value of --win-update-url command line option if it + * was specified. Undefined otherwise + *
+ * + *

+ * ui.wxf file is generated based on --license-file, --win-shortcut-prompt, + * --win-dir-chooser command line options. It is parametrized with the following + * WiX variables: + *

    + *
  • JpLicenseRtf. Set to the value of --license-file command line option. + * Undefined if --license-file command line option was not specified + *
+ */ +final class WinMsiPackager implements Consumer { + + WinMsiPackager(BuildEnv env, WinMsiPackage pkg, Path outputDir, WixToolset wixToolset) { + this.pkg = Objects.requireNonNull(pkg); + this.env = Objects.requireNonNull(env); + this.outputDir = Objects.requireNonNull(outputDir); + this.wixToolset = Objects.requireNonNull(wixToolset); + + wixFragments = Stream.of( + Map.entry("bundle.wxf", new WixAppImageFragmentBuilder()), + Map.entry("ui.wxf", new WixUiFragmentBuilder()), + Map.entry("os-condition.wxf", OSVersionCondition.createWixFragmentBuilder()) + ).map(e -> { + e.getValue().setOutputFileName(e.getKey()); + return e.getValue(); + }).toList(); + + // Configure installer icon + if (env.appImageLayout() instanceof RuntimeLayout runtimeLayout) { + // Use icon from java launcher. + // Assume java.exe exists in Java Runtime being packed. + // Ignore custom icon if any as we don't want to copy anything in + // Java Runtime image. + installerIcon = runtimeLayout.runtimeDirectory().resolve(Path.of("bin", "java.exe")).toAbsolutePath(); + } else { + installerIcon = env.asApplicationLayout().orElseThrow().launchersDirectory().resolve( + pkg.app().mainLauncher().orElseThrow().executableNameWithSuffix()).toAbsolutePath(); + } + + wixFragments.forEach(wixFragment -> wixFragment.setWixVersion(wixToolset.getVersion(), + wixToolset.getType())); + + wixFragments.stream().map(WixFragmentBuilder::getLoggableWixFeatures).flatMap( + List::stream).distinct().toList().forEach(Log::verbose); + } + + WinMsiPackager(BuildEnv env, WinMsiPackage pkg, Path outputDir, WinSystemEnvironment sysEnv) { + this(env, pkg, outputDir, sysEnv.wixToolset()); + } + + @Override + public void accept(PackagingPipeline.Builder pipelineBuilder) { + pipelineBuilder.excludeDirFromCopying(outputDir) + .task(PackagingPipeline.PackageTaskID.CREATE_CONFIG_FILES) + .action(this::prepareConfigFiles) + .add() + .task(PackagingPipeline.PackageTaskID.CREATE_PACKAGE_FILE) + .action(this::buildPackage) + .add(); + } + + private void prepareConfigFiles() throws PackagerException, IOException { + + pkg.licenseFile().ifPresent(licenseFile -> { + // need to copy license file to the working directory + // and convert to rtf if needed + Path destFile = env.configDir().resolve(licenseFile.getFileName()); + + try { + IOUtils.copyFile(licenseFile, destFile); + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + destFile.toFile().setWritable(true); + ensureByMutationFileIsRTF(destFile); + }); + + for (var wixFragment : wixFragments) { + wixFragment.initFromParams(env, pkg); + wixFragment.addFilesToConfigRoot(); + } + + final var msiOut = outputDir.resolve(pkg.packageFileNameWithSuffix()); + + Log.verbose(I18N.format("message.preparing-msi-config", msiOut.toAbsolutePath())); + + final var wixVars = createWixVars(); + + final var wixObjDir = env.buildRoot().resolve("wixobj"); + + final var configDir = env.configDir(); + + final var wixPipelineBuilder = WixPipeline.build() + .setWixObjDir(wixObjDir) + .setWorkDir(env.appImageDir()) + .addSource(configDir.resolve("main.wxs"), wixVars); + + for (var wixFragment : wixFragments) { + wixFragment.configureWixPipeline(wixPipelineBuilder); + } + + switch (wixToolset.getType()) { + case Wix3 -> { + wixPipelineBuilder.addLightOptions("-sice:ICE27"); + + if (!pkg.isSystemWideInstall()) { + wixPipelineBuilder.addLightOptions("-sice:ICE91"); + } + } + case Wix4 -> { + } + default -> { + throw new IllegalArgumentException(); + } + } + + var primaryWxlFiles = Stream.of("de", "en", "ja", "zh_CN").map(loc -> { + return configDir.resolve("MsiInstallerStrings_" + loc + ".wxl"); + }).toList(); + + var wixResources = new WixSourceConverter.ResourceGroup(wixToolset.getType()); + + // Copy standard l10n files. + for (var path : primaryWxlFiles) { + var name = path.getFileName().toString(); + wixResources.addResource(env.createResource(name).setPublicName(name).setCategory( + I18N.getString("resource.wxl-file")), path); + } + + wixResources.addResource(env.createResource("main.wxs").setPublicName("main.wxs"). + setCategory(I18N.getString("resource.main-wix-file")), configDir.resolve("main.wxs")); + + wixResources.addResource(env.createResource("overrides.wxi").setPublicName( + "overrides.wxi").setCategory(I18N.getString("resource.overrides-wix-file")), + configDir.resolve("overrides.wxi")); + + // Filter out custom l10n files that were already used to + // override primary l10n files. Ignore case filename comparison, + // both lists are expected to be short. + List customWxlFiles = env.resourceDir() + .map(WinMsiPackager::getWxlFilesFromDir) + .orElseGet(Collections::emptyList) + .stream() + .filter(custom -> primaryWxlFiles.stream().noneMatch(primary -> + primary.getFileName().toString().equalsIgnoreCase( + custom.getFileName().toString()))) + .peek(custom -> Log.verbose(I18N.format( + "message.using-custom-resource", String.format("[%s]", + I18N.getString("resource.wxl-file")), + custom.getFileName()))).toList(); + + // Copy custom l10n files. + for (var path : customWxlFiles) { + var name = path.getFileName().toString(); + wixResources.addResource(env.createResource(name).setPublicName(name). + setSourceOrder(OverridableResource.Source.ResourceDir).setCategory(I18N. + getString("resource.wxl-file")), configDir.resolve(name)); + } + + // Save all WiX resources into config dir. + wixResources.saveResources(); + + // All l10n files are supplied to WiX with "-loc", but only + // Cultures from custom files and a single primary Culture are + // included into "-cultures" list + for (var wxl : primaryWxlFiles) { + wixPipelineBuilder.addLightOptions("-loc", wxl.toString()); + } + + List cultures = new ArrayList<>(); + for (var wxl : customWxlFiles) { + wxl = configDir.resolve(wxl.getFileName()); + wixPipelineBuilder.addLightOptions("-loc", wxl.toString()); + cultures.add(getCultureFromWxlFile(wxl)); + } + + // Append a primary culture bases on runtime locale. + final Path primaryWxlFile = configDir.resolve( + I18N.getString("resource.wxl-file-name")); + cultures.add(getCultureFromWxlFile(primaryWxlFile)); + + // Build ordered list of unique cultures. + Set uniqueCultures = new LinkedHashSet<>(); + uniqueCultures.addAll(cultures); + switch (wixToolset.getType()) { + case Wix3 -> { + wixPipelineBuilder.addLightOptions(uniqueCultures.stream().collect(Collectors.joining(";", + "-cultures:", ""))); + } + case Wix4 -> { + uniqueCultures.forEach(culture -> { + wixPipelineBuilder.addLightOptions("-culture", culture); + }); + } + default -> { + throw new IllegalArgumentException(); + } + } + + Files.createDirectories(wixObjDir); + wixPipeline = wixPipelineBuilder.create(wixToolset); + } + + private void buildPackage() throws PackagerException, IOException { + final var msiOut = outputDir.resolve(pkg.packageFileNameWithSuffix()); + Log.verbose(I18N.format("message.generating-msi", msiOut.toAbsolutePath())); + wixPipeline.buildMsi(msiOut.toAbsolutePath()); + } + + private Map createWixVars() throws IOException { + Map data = new HashMap<>(); + + data.put("JpProductCode", pkg.productCode().toString()); + data.put("JpProductUpgradeCode", pkg.upgradeCode().toString()); + + Log.verbose(I18N.format("message.product-code", pkg.productCode())); + Log.verbose(I18N.format("message.upgrade-code", pkg.upgradeCode())); + + data.put("JpAllowUpgrades", "yes"); + if (!pkg.isRuntimeInstaller()) { + data.put("JpAllowDowngrades", "yes"); + } + + data.put("JpAppName", pkg.packageName()); + data.put("JpAppDescription", pkg.description()); + data.put("JpAppVendor", pkg.app().vendor()); + data.put("JpAppVersion", pkg.version()); + if (Files.exists(installerIcon)) { + data.put("JpIcon", installerIcon.toString()); + } + + pkg.helpURL().ifPresent(value -> { + data.put("JpHelpURL", value); + }); + + pkg.updateURL().ifPresent(value -> { + data.put("JpUpdateURL", value); + }); + + pkg.aboutURL().ifPresent(value -> { + data.put("JpAboutURL", value); + }); + + data.put("JpAppSizeKb", Long.toString(AppImageLayout.toPathGroup( + env.appImageLayout()).sizeInBytes() >> 10)); + + data.put("JpConfigDir", env.configDir().toAbsolutePath().toString()); + + if (pkg.isSystemWideInstall()) { + data.put("JpIsSystemWide", "yes"); + } + + return data; + } + + private static List getWxlFilesFromDir(Path dir) { + final String glob = "glob:**/*.wxl"; + final PathMatcher pathMatcher = FileSystems.getDefault().getPathMatcher( + glob); + + try (var walk = Files.walk(dir, 1)) { + return walk + .filter(Files::isReadable) + .filter(pathMatcher::matches) + .sorted((a, b) -> a.getFileName().toString().compareToIgnoreCase(b.getFileName().toString())) + .toList(); + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + } + + private static String getCultureFromWxlFile(Path wxlPath) { + try { + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setNamespaceAware(false); + DocumentBuilder builder = factory.newDocumentBuilder(); + + Document doc = builder.parse(wxlPath.toFile()); + + XPath xPath = XPathFactory.newInstance().newXPath(); + NodeList nodes = (NodeList) xPath.evaluate( + "//WixLocalization/@Culture", doc, XPathConstants.NODESET); + if (nodes.getLength() != 1) { + throw new RuntimeException(I18N.format( + "error.extract-culture-from-wix-l10n-file", + wxlPath.toAbsolutePath().normalize())); + } + + return nodes.item(0).getNodeValue(); + } catch (XPathExpressionException | ParserConfigurationException | SAXException ex) { + throw new RuntimeException(I18N.format( + "error.read-wix-l10n-file", wxlPath.toAbsolutePath().normalize()), ex); + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + } + + private static void ensureByMutationFileIsRTF(Path f) { + try { + boolean existingLicenseIsRTF = false; + + try (InputStream fin = Files.newInputStream(f)) { + byte[] firstBits = new byte[7]; + + if (fin.read(firstBits) == firstBits.length) { + String header = new String(firstBits); + existingLicenseIsRTF = "{\\rtf1\\".equals(header); + } + } + + if (!existingLicenseIsRTF) { + List oldLicense = Files.readAllLines(f); + try (Writer w = Files.newBufferedWriter( + f, Charset.forName("Windows-1252"))) { + w.write("{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang1033" + + "{\\fonttbl{\\f0\\fnil\\fcharset0 Arial;}}\n" + + "\\viewkind4\\uc1\\pard\\sa200\\sl276" + + "\\slmult1\\lang9\\fs20 "); + oldLicense.forEach(l -> { + try { + for (char c : l.toCharArray()) { + // 0x00 <= ch < 0x20 Escaped (\'hh) + // 0x20 <= ch < 0x80 Raw(non - escaped) char + // 0x80 <= ch <= 0xFF Escaped(\ 'hh) + // 0x5C, 0x7B, 0x7D (special RTF characters + // \,{,})Escaped(\'hh) + // ch > 0xff Escaped (\\ud###?) + if (c < 0x10) { + w.write("\\'0"); + w.write(Integer.toHexString(c)); + } else if (c > 0xff) { + w.write("\\ud"); + w.write(Integer.toString(c)); + // \\uc1 is in the header and in effect + // so we trail with a replacement char if + // the font lacks that character - '?' + w.write("?"); + } else if ((c < 0x20) || (c >= 0x80) || + (c == 0x5C) || (c == 0x7B) || + (c == 0x7D)) { + w.write("\\'"); + w.write(Integer.toHexString(c)); + } else { + w.write(c); + } + } + // blank lines are interpreted as paragraph breaks + if (l.length() < 1) { + w.write("\\par"); + } else { + w.write(" "); + } + w.write("\r\n"); + } catch (IOException e) { + Log.verbose(e); + } + }); + w.write("}\r\n"); + } + } + } catch (IOException e) { + Log.verbose(e); + } + } + + private final WinMsiPackage pkg; + private final BuildEnv env; + private final Path outputDir; + private final WixToolset wixToolset; + private final List wixFragments; + private final Path installerIcon; + private WixPipeline wixPipeline; +} diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinSystemEnvironment.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinSystemEnvironment.java new file mode 100644 index 00000000000..33b5a09a31b --- /dev/null +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinSystemEnvironment.java @@ -0,0 +1,41 @@ +/* + * 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 jdk.jpackage.internal; + +import static jdk.jpackage.internal.util.function.ThrowingSupplier.toSupplier; + +import java.util.Objects; +import jdk.jpackage.internal.util.Result; + +record WinSystemEnvironment(WixToolset wixToolset) implements SystemEnvironment { + + WinSystemEnvironment { + Objects.requireNonNull(wixToolset); + } + + static Result create() { + return Result.create(toSupplier(WixTool::createToolset)).map(WinSystemEnvironment::new); + } +} diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixTool.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixTool.java index 7e4353876b4..6e72511e080 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixTool.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixTool.java @@ -183,13 +183,12 @@ static Optional lookup(WixTool tool, Optional lookupDir) final boolean[] tooOld = new boolean[1]; final String[] parsedVersion = new String[1]; - final var validator = new ToolValidator(toolPath).setMinimalVersion(tool.minimalVersion). - setToolNotFoundErrorHandler((name, ex) -> { - return new ConfigException("", ""); - }).setToolOldVersionErrorHandler((name, version) -> { - tooOld[0] = true; - return null; - }); + final var validator = new ToolValidator(toolPath) + .setMinimalVersion(tool.minimalVersion) + .setToolOldVersionErrorHandler((name, version) -> { + tooOld[0] = true; + return null; + }); final Function, String> versionParser; diff --git a/src/jdk.jshell/share/classes/jdk/jshell/OuterWrapMap.java b/src/jdk.jshell/share/classes/jdk/jshell/OuterWrapMap.java index 6f7f3fe42c3..61fb3bdfc9a 100644 --- a/src/jdk.jshell/share/classes/jdk/jshell/OuterWrapMap.java +++ b/src/jdk.jshell/share/classes/jdk/jshell/OuterWrapMap.java @@ -73,7 +73,11 @@ private CompoundWrap wrappedInClass(String className, String imports, List OuterWrap wrapInClass(Set except, Collection plus, List snippets, List wraps) { - String imports = state.maps.packageAndImportsExcept(except, plus); + List extraImports = + plus.stream() + .map(psi -> psi.importLine(state)) + .toList(); + String imports = state.maps.packageAndImportsExcept(except, extraImports); // className is unique to the set of snippets and their version (seq) String className = REPL_CLASS_PREFIX + snippets.stream() .sorted((sn1, sn2) -> sn1.key().index() - sn2.key().index()) @@ -86,9 +90,16 @@ OuterWrap wrapInClass(Set except, Collection plus, } OuterWrap wrapInTrialClass(Wrap wrap) { - String imports = state.maps.packageAndImportsExcept(null, null); + return wrapInTrialClass(List.of(), List.of(), wrap); + } + + OuterWrap wrapInTrialClass(List extraImports, List preWraps, Wrap wrap) { + String imports = state.maps.packageAndImportsExcept(null, extraImports); + List allWraps = new ArrayList<>(); + allWraps.addAll(preWraps); + allWraps.add(wrap); CompoundWrap w = wrappedInClass(REPL_DOESNOTMATTER_CLASS_NAME, imports, - Collections.singletonList(wrap)); + allWraps); return new OuterWrap(w); } diff --git a/src/jdk.jshell/share/classes/jdk/jshell/SnippetMaps.java b/src/jdk.jshell/share/classes/jdk/jshell/SnippetMaps.java index bd0c9d86db3..992d97a7040 100644 --- a/src/jdk.jshell/share/classes/jdk/jshell/SnippetMaps.java +++ b/src/jdk.jshell/share/classes/jdk/jshell/SnippetMaps.java @@ -105,7 +105,7 @@ List snippetList() { return new ArrayList<>(snippets); } - String packageAndImportsExcept(Set except, Collection plus) { + String packageAndImportsExcept(Set except, Collection extraImports) { StringBuilder sb = new StringBuilder(); sb.append("package ").append(REPL_PACKAGE).append(";\n"); for (Snippet si : keyIndexToSnippet) { @@ -113,9 +113,7 @@ String packageAndImportsExcept(Set except, Collection plus) { sb.append(si.importLine(state)); } } - if (plus != null) { - plus.forEach(psi -> sb.append(psi.importLine(state))); - } + extraImports.forEach(sb::append); return sb.toString(); } diff --git a/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java b/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java index 045734d9f55..19bad110a5d 100644 --- a/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java +++ b/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java @@ -300,17 +300,8 @@ private List completionSuggestionsImpl(String code, int cursor, int[ identifier = m.group(); } } - code = code.substring(0, cursor); - if (code.trim().isEmpty()) { //TODO: comment handling - code += ";"; - } - boolean[] moduleImport = new boolean[1]; - OuterWrap codeWrap = switch (guessKind(code, moduleImport)) { - case IMPORT -> moduleImport[0] ? proc.outerMap.wrapImport(Wrap.simpleWrap(code), null) - : proc.outerMap.wrapImport(Wrap.simpleWrap(code + "any.any"), null); - case CLASS, METHOD -> proc.outerMap.wrapInTrialClass(Wrap.classMemberWrap(code)); - default -> proc.outerMap.wrapInTrialClass(Wrap.methodWrap(code)); - }; + + OuterWrap codeWrap = wrapCodeForCompletion(code, cursor, true); String[] requiredPrefix = new String[] {identifier}; return computeSuggestions(codeWrap, code, cursor, requiredPrefix, anchor).stream() .filter(s -> filteringText(s).startsWith(requiredPrefix[0]) && !s.continuation().equals(REPL_DOESNOTMATTER_CLASS_NAME)) @@ -1740,15 +1731,11 @@ public List documentation(String code, int cursor, boolean comput }; private List documentationImpl(String code, int cursor, boolean computeJavadoc) { - code = code.substring(0, cursor); - if (code.trim().isEmpty()) { //TODO: comment handling - code += ";"; - } - - if (guessKind(code) == Kind.IMPORT) + OuterWrap codeWrap = wrapCodeForCompletion(code, cursor, false); + if (codeWrap == null) { + //import: return Collections.emptyList(); - - OuterWrap codeWrap = proc.outerMap.wrapInTrialClass(Wrap.methodWrap(code)); + } return proc.taskFactory.analyze(codeWrap, List.of(keepParameterNames), at -> { SourcePositions sp = at.trees().getSourcePositions(); CompilationUnitTree topLevel = at.firstCuTree(); @@ -2303,7 +2290,8 @@ private void appendModulePaths(MemoryFileManager fm, Location loc, Collection { try { long lastModified = Files.getLastModifiedTime(p).toMillis(); @@ -2334,6 +2322,10 @@ private ClassIndex indexForPath(Path path) { } } + private static boolean isJRTMarkerFile(Path path) { + return path.equals(Paths.get(System.getProperty("java.home"), "lib", "modules")); + } + //create an index based on the content of the given dirs; the original JavaFileManager entry is originalPath. private ClassIndex doIndex(long timestamp, Path originalPath, Iterable dirs) { Set packages = new HashSet<>(); @@ -2429,6 +2421,99 @@ public static void waitCurrentBackgroundTasksFinished() throws Exception { INDEXER.submit(() -> {}).get(); } + private OuterWrap wrapCodeForCompletion(String code, int cursor, boolean wrapImports) { + code = code.substring(0, cursor); + if (code.trim().isEmpty()) { //TODO: comment handling + code += ";"; + } + + List imports = new ArrayList<>(); + List declarationParts = new ArrayList<>(); + String lastImport = null; + boolean lastImportIsModuleImport = false; + Wrap declarationWrap = null; + Wrap pendingWrap = null; + String input = code; + boolean cont = true; + int startOffset = 0; + + while (cont) { + if (lastImport != null) { + imports.add(lastImport); + lastImport = null; + } + if (declarationWrap != null) { + declarationParts.add(declarationWrap); + declarationWrap = null; + pendingWrap = null; + } + + String current; + SourceCodeAnalysis.CompletionInfo completeness = analyzeCompletion(input); + int newStartOffset; + + if (completeness.completeness().isComplete() && !completeness.remaining().isBlank()) { + current = input.substring(0, input.length() - completeness.remaining().length()); + newStartOffset = startOffset + input.length() - completeness.remaining().length(); + input = completeness.remaining(); + cont = true; + } else { + current = input; + cont = false; + newStartOffset = startOffset; + } + + boolean[] moduleImport = new boolean[1]; + + switch (guessKind(current, moduleImport)) { + case IMPORT -> { + lastImport = current; + lastImportIsModuleImport = moduleImport[0]; + } + case CLASS, METHOD -> { + pendingWrap = declarationWrap = Wrap.classMemberWrap(whitespaces(code, startOffset) + current); + } + case VARIABLE -> { + declarationWrap = Wrap.classMemberWrap(whitespaces(code, startOffset) + current); + pendingWrap = Wrap.methodWrap(whitespaces(code, startOffset) + current); + } + default -> { + pendingWrap = declarationWrap = Wrap.methodWrap(whitespaces(code, startOffset) + current); + } + } + + startOffset = newStartOffset; + } + + if (lastImport != null) { + if (wrapImports) { + return proc.outerMap.wrapImport(Wrap.simpleWrap(whitespaces(code, startOffset) + lastImport + (!lastImportIsModuleImport ? "any.any" : "")), null); + } else { + return null; + } + } + + if (pendingWrap != null) { + return proc.outerMap.wrapInTrialClass(imports, declarationParts, pendingWrap); + } + + throw new IllegalStateException("No pending wrap for: " + code); + } + + private static String whitespaces(String input, int offset) { + StringBuilder result = new StringBuilder(); + + for (int i = 0; i < offset; i++) { + if (input.charAt(i) == '\n') { + result.append('\n'); + } else { + result.append(' '); + } + } + + return result.toString(); + } + /** * A candidate for continuation of the given user's input. */ diff --git a/src/jdk.management/share/classes/com/sun/management/doc-files/threadDump.schema.json b/src/jdk.management/share/classes/com/sun/management/doc-files/threadDump.schema.json index 57ef5c8b859..bf52bb3915d 100644 --- a/src/jdk.management/share/classes/com/sun/management/doc-files/threadDump.schema.json +++ b/src/jdk.management/share/classes/com/sun/management/doc-files/threadDump.schema.json @@ -78,6 +78,10 @@ "description": "The blocker object responsible for the thread parking." } }, + "owner": { + "type": "string", + "description": "The thread identifier of the owner when the parkBlocker is an AbstractOwnableSynchronizer." + } "required": [ "object" ] @@ -115,9 +119,9 @@ "items": { "type": [ "string", - null + "null" ], - "description": "The object for which the monitor is owned by the thread, null if eliminated" + "description": "The object for which the monitor is owned by the thread, null if eliminated." } } }, diff --git a/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/InputNode.java b/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/InputNode.java index 48a000bf7b9..df1cbbacc0c 100644 --- a/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/InputNode.java +++ b/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/InputNode.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 @@ -32,6 +32,9 @@ */ public class InputNode extends Properties.Entity { + public static final String LABEL_PROPERTY = "label"; + public static final String COLOR_PROPERTY = "color"; + private int id; public InputNode(InputNode n) { @@ -51,6 +54,17 @@ public int getId() { return id; } + // Return the node properties that are present in the input graph, excluding + // properties computed by IGV itself. This is useful e.g. to produce the + // difference view, where nodes should be compared based only on their + // intrinsic characteristics. + public Properties getPrimaryProperties() { + Properties primaryProperties = new Properties(getProperties()); + primaryProperties.setProperty(LABEL_PROPERTY, null); + primaryProperties.setProperty(COLOR_PROPERTY, null); + return primaryProperties; + } + @Override public boolean equals(Object obj) { if (this == obj) { @@ -72,14 +86,14 @@ public String toString() { public void setCustomColor(Color color) { if (color != null) { String hexColor = String.format("#%08X", color.getRGB()); - getProperties().setProperty("color", hexColor); + getProperties().setProperty(COLOR_PROPERTY, hexColor); } else { - getProperties().setProperty("color", null); + getProperties().setProperty(COLOR_PROPERTY, null); } } public Color getCustomColor() { - String hexColor = getProperties().get("color"); + String hexColor = getProperties().get(COLOR_PROPERTY); if (hexColor != null) { try { String hex = hexColor.startsWith("#") ? hexColor.substring(1) : hexColor; diff --git a/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/serialization/Parser.java b/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/serialization/Parser.java index dfe60372eda..06887ba22f4 100644 --- a/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/serialization/Parser.java +++ b/src/utils/IdealGraphVisualizer/Data/src/main/java/com/sun/hotspot/igv/data/serialization/Parser.java @@ -81,7 +81,7 @@ public class Parser implements GraphParser { public static final String FROM_INDEX_PROPERTY = "fromIndex"; public static final String TO_INDEX_PROPERTY = "toIndex"; public static final String TO_INDEX_ALT_PROPERTY = "index"; - public static final String LABEL_PROPERTY = "label"; + public static final String EDGE_LABEL_PROPERTY = "label"; public static final String METHOD_ELEMENT = "method"; public static final String INLINE_ELEMENT = "inline"; public static final String BYTECODES_ELEMENT = "bytecodes"; @@ -655,7 +655,7 @@ protected InputEdge start() throws SAXException { toIndex = Integer.parseInt(toIndexString); } - label = readAttribute(LABEL_PROPERTY); + label = readAttribute(EDGE_LABEL_PROPERTY); type = readAttribute(TYPE_PROPERTY); from = lookupID(readRequiredAttribute(FROM_PROPERTY)); diff --git a/src/utils/IdealGraphVisualizer/Difference/src/main/java/com/sun/hotspot/igv/difference/Difference.java b/src/utils/IdealGraphVisualizer/Difference/src/main/java/com/sun/hotspot/igv/difference/Difference.java index c904e8c6083..89b1434663f 100644 --- a/src/utils/IdealGraphVisualizer/Difference/src/main/java/com/sun/hotspot/igv/difference/Difference.java +++ b/src/utils/IdealGraphVisualizer/Difference/src/main/java/com/sun/hotspot/igv/difference/Difference.java @@ -356,7 +356,7 @@ private static void markAsSame(InputEdge e) { private static void markAsChanged(InputNode n, InputNode firstNode, InputNode otherNode) { boolean difference = false; - for (Property p : otherNode.getProperties()) { + for (Property p : otherNode.getPrimaryProperties()) { String s = firstNode.getProperties().get(p.getName()); if (!p.getValue().equals(s)) { difference = true; @@ -364,7 +364,7 @@ private static void markAsChanged(InputNode n, InputNode firstNode, InputNode ot } } - for (Property p : firstNode.getProperties()) { + for (Property p : firstNode.getPrimaryProperties()) { String s = otherNode.getProperties().get(p.getName()); if (s == null && p.getValue().length() > 0) { difference = true; diff --git a/src/utils/IdealGraphVisualizer/Graph/src/main/java/com/sun/hotspot/igv/graph/Figure.java b/src/utils/IdealGraphVisualizer/Graph/src/main/java/com/sun/hotspot/igv/graph/Figure.java index d85e102f874..f212d1e8b1d 100644 --- a/src/utils/IdealGraphVisualizer/Graph/src/main/java/com/sun/hotspot/igv/graph/Figure.java +++ b/src/utils/IdealGraphVisualizer/Graph/src/main/java/com/sun/hotspot/igv/graph/Figure.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 @@ -371,7 +371,7 @@ public void updateLines() { // search is done on the node label (without line breaks). See also // class NodeQuickSearch in the View module. String label = inputNode.getProperties().resolveString(diagram.getNodeText()); - inputNode.getProperties().setProperty("label", label.replaceAll("\\R", " ")); + inputNode.getProperties().setProperty(InputNode.LABEL_PROPERTY, label.replaceAll("\\R", " ")); // Update figure dimensions, as these are affected by the node text. updateWidth(); diff --git a/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/NodeQuickSearch.java b/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/NodeQuickSearch.java index 254b8ca15ef..95d6e12d3c4 100644 --- a/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/NodeQuickSearch.java +++ b/src/utils/IdealGraphVisualizer/View/src/main/java/com/sun/hotspot/igv/view/NodeQuickSearch.java @@ -48,8 +48,6 @@ */ public class NodeQuickSearch implements SearchProvider { - private static final String DEFAULT_PROPERTY = "label"; - /** * Method is called by infrastructure when search operation was requested. * Implementors should evaluate given request and fill response object with @@ -72,7 +70,7 @@ public void evaluate(SearchRequest request, SearchResponse response) { String value; if (parts.length == 1) { - name = DEFAULT_PROPERTY; + name = InputNode.LABEL_PROPERTY; rawValue = parts[0]; value = ".*" + Pattern.quote(rawValue) + ".*"; } else { diff --git a/test/failure_handler/src/share/conf/common.properties b/test/failure_handler/src/share/conf/common.properties index 5cd2c1c13ca..295a7458d4b 100644 --- a/test/failure_handler/src/share/conf/common.properties +++ b/test/failure_handler/src/share/conf/common.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2015, 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,13 @@ args=%p ################################################################################ # process info to gather ################################################################################ +# It's important to retain the order of these actions and run the thread dump +# generating commands before the rest, to allow for capturing the test +# process' call stack as soon as the timeout has occurred. That reduces the chances +# of the test completing and thus missing crucial details from the thread dump +# while these timeout actions were being run. onTimeout=\ + thread_dump \ jinfo \ jcmd.compiler.codecache jcmd.compiler.codelist \ jcmd.compiler.queue \ @@ -63,9 +69,13 @@ jcmd.thread.dump_to_file.params.successArtifacts=JavaThread.dump.%p.%iterCount jcmd.thread.vthread_scheduler.args=%p Thread.vthread_scheduler +# use jstack to generate one thread dump +thread_dump.app=jstack +thread_dump.args=-e -l %p + jstack.app=jstack jstack.args=-e -l %p -jstack.params.repeat=6 +jstack.params.repeat=5 jhsdb.app=jhsdb jhsdb.jstack.live.default.args=jstack --pid %p diff --git a/test/hotspot/gtest/metaprogramming/test_logical.cpp b/test/hotspot/gtest/metaprogramming/test_logical.cpp deleted file mode 100644 index 8f2f1940a2b..00000000000 --- a/test/hotspot/gtest/metaprogramming/test_logical.cpp +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2020, 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 "metaprogramming/logical.hpp" -#include - -class TestBoolConstant { - static_assert(BoolConstant::value, "true"); - static_assert(!BoolConstant::value, "false"); -}; - -class TestConjunction { - class A : public std::true_type {}; - class B : public std::true_type {}; - class C : public std::false_type {}; - class D : public std::false_type {}; - - static_assert(Conjunction<>::value, "nullary value"); - - static_assert(Conjunction::value, "true value"); - static_assert(std::is_base_of>::value, "true type"); - - static_assert(!Conjunction::value, "false value"); - static_assert(std::is_base_of>::value, "false type"); - - static_assert(Conjunction::value, "true/true value"); - static_assert(std::is_base_of>::value, "true/true type"); - - static_assert(!Conjunction::value, "true/false value"); - static_assert(std::is_base_of>::value, "true/false type"); - - static_assert(!Conjunction::value, "false/true value"); - static_assert(std::is_base_of>::value, "false/true type"); - - static_assert(!Conjunction::value, "false/false value"); - static_assert(std::is_base_of>::value, "false/false type"); -}; - -class TestDisjunction { - class A : public std::true_type {}; - class B : public std::true_type {}; - class C : public std::false_type {}; - class D : public std::false_type {}; - - static_assert(!Disjunction<>::value, "nullary value"); - - static_assert(Disjunction::value, "true value"); - static_assert(std::is_base_of>::value, "true type"); - - static_assert(!Disjunction::value, "false value"); - static_assert(std::is_base_of>::value, "false type"); - - static_assert(Disjunction::value, "true/true value"); - static_assert(std::is_base_of>::value, "true/true type"); - - static_assert(Disjunction::value, "true/false value"); - static_assert(std::is_base_of>::value, "true/false type"); - - static_assert(Disjunction::value, "false/true value"); - static_assert(std::is_base_of>::value, "false/true type"); - - static_assert(!Disjunction::value, "false/false value"); - static_assert(std::is_base_of>::value, "false/false type"); -}; - -class TestNegation { - static_assert(Negation::value, "false -> true"); - static_assert(!Negation::value, "true -> false"); -}; diff --git a/test/hotspot/gtest/nmt/test_regions_tree.cpp b/test/hotspot/gtest/nmt/test_regions_tree.cpp index 394c863746e..a7f4a6962ca 100644 --- a/test/hotspot/gtest/nmt/test_regions_tree.cpp +++ b/test/hotspot/gtest/nmt/test_regions_tree.cpp @@ -41,46 +41,69 @@ TEST_VM_F(NMTRegionsTreeTest, ReserveCommitTwice) { NativeCallStack ncs; VMATree::RegionData rd = rt.make_region_data(ncs, mtTest); VMATree::RegionData rd2 = rt.make_region_data(ncs, mtGC); - VMATree::SummaryDiff diff; - diff = rt.reserve_mapping(0, 100, rd); - EXPECT_EQ(100, diff.tag[NMTUtil::tag_to_index(mtTest)].reserve); - diff = rt.commit_region(0, 50, ncs); - diff = rt.reserve_mapping(0, 100, rd); - EXPECT_EQ(0, diff.tag[NMTUtil::tag_to_index(mtTest)].reserve); - EXPECT_EQ(-50, diff.tag[NMTUtil::tag_to_index(mtTest)].commit); - diff = rt.reserve_mapping(0, 100, rd2); - EXPECT_EQ(-100, diff.tag[NMTUtil::tag_to_index(mtTest)].reserve); - EXPECT_EQ(100, diff.tag[NMTUtil::tag_to_index(mtGC)].reserve); - diff = rt.commit_region(0, 50, ncs); - EXPECT_EQ(0, diff.tag[NMTUtil::tag_to_index(mtGC)].reserve); - EXPECT_EQ(50, diff.tag[NMTUtil::tag_to_index(mtGC)].commit); - diff = rt.commit_region(0, 50, ncs); - EXPECT_EQ(0, diff.tag[NMTUtil::tag_to_index(mtTest)].reserve); - EXPECT_EQ(0, diff.tag[NMTUtil::tag_to_index(mtTest)].commit); + { + VMATree::SummaryDiff diff; + rt.reserve_mapping(0, 100, rd, diff); + EXPECT_EQ(100, diff.tag[NMTUtil::tag_to_index(mtTest)].reserve); + } + { + VMATree::SummaryDiff diff, not_used; + rt.commit_region(0, 50, ncs, not_used); + rt.reserve_mapping(0, 100, rd, diff); + EXPECT_EQ(0, diff.tag[NMTUtil::tag_to_index(mtTest)].reserve); + EXPECT_EQ(-50, diff.tag[NMTUtil::tag_to_index(mtTest)].commit); + } + { + VMATree::SummaryDiff diff; + rt.reserve_mapping(0, 100, rd2, diff); + EXPECT_EQ(-100, diff.tag[NMTUtil::tag_to_index(mtTest)].reserve); + EXPECT_EQ(100, diff.tag[NMTUtil::tag_to_index(mtGC)].reserve); + } + + { + VMATree::SummaryDiff diff1, diff2; + rt.commit_region(0, 50, ncs, diff1); + EXPECT_EQ(0, diff1.tag[NMTUtil::tag_to_index(mtGC)].reserve); + EXPECT_EQ(50, diff1.tag[NMTUtil::tag_to_index(mtGC)].commit); + rt.commit_region(0, 50, ncs, diff2); + EXPECT_EQ(0, diff2.tag[NMTUtil::tag_to_index(mtTest)].reserve); + EXPECT_EQ(0, diff2.tag[NMTUtil::tag_to_index(mtTest)].commit); + } } TEST_VM_F(NMTRegionsTreeTest, CommitUncommitRegion) { NativeCallStack ncs; VMATree::RegionData rd = rt.make_region_data(ncs, mtTest); - rt.reserve_mapping(0, 100, rd); - VMATree::SummaryDiff diff = rt.commit_region(0, 50, ncs); - EXPECT_EQ(0, diff.tag[NMTUtil::tag_to_index(mtTest)].reserve); - EXPECT_EQ(50, diff.tag[NMTUtil::tag_to_index(mtTest)].commit); - diff = rt.commit_region((address)60, 10, ncs); - EXPECT_EQ(0, diff.tag[NMTUtil::tag_to_index(mtTest)].reserve); - EXPECT_EQ(10, diff.tag[NMTUtil::tag_to_index(mtTest)].commit); - diff = rt.uncommit_region(0, 50); - EXPECT_EQ(0, diff.tag[NMTUtil::tag_to_index(mtTest)].reserve); - EXPECT_EQ(-50, diff.tag[NMTUtil::tag_to_index(mtTest)].commit); + VMATree::SummaryDiff not_used; + rt.reserve_mapping(0, 100, rd, not_used); + { + VMATree::SummaryDiff diff; + rt.commit_region(0, 50, ncs, diff); + EXPECT_EQ(0, diff.tag[NMTUtil::tag_to_index(mtTest)].reserve); + EXPECT_EQ(50, diff.tag[NMTUtil::tag_to_index(mtTest)].commit); + } + { + VMATree::SummaryDiff diff; + rt.commit_region((address)60, 10, ncs, diff); + EXPECT_EQ(0, diff.tag[NMTUtil::tag_to_index(mtTest)].reserve); + EXPECT_EQ(10, diff.tag[NMTUtil::tag_to_index(mtTest)].commit); + } + { + VMATree::SummaryDiff diff; + rt.uncommit_region(0, 50, diff); + EXPECT_EQ(0, diff.tag[NMTUtil::tag_to_index(mtTest)].reserve); + EXPECT_EQ(-50, diff.tag[NMTUtil::tag_to_index(mtTest)].commit); + } } TEST_VM_F(NMTRegionsTreeTest, FindReservedRegion) { NativeCallStack ncs; VMATree::RegionData rd = rt.make_region_data(ncs, mtTest); - rt.reserve_mapping(1000, 50, rd); - rt.reserve_mapping(1200, 50, rd); - rt.reserve_mapping(1300, 50, rd); - rt.reserve_mapping(1400, 50, rd); + VMATree::SummaryDiff not_used; + rt.reserve_mapping(1000, 50, rd, not_used); + rt.reserve_mapping(1200, 50, rd, not_used); + rt.reserve_mapping(1300, 50, rd, not_used); + rt.reserve_mapping(1400, 50, rd, not_used); ReservedMemoryRegion rmr; rmr = rt.find_reserved_region((address)1205); EXPECT_EQ(rmr.base(), (address)1200); @@ -95,10 +118,11 @@ TEST_VM_F(NMTRegionsTreeTest, FindReservedRegion) { TEST_VM_F(NMTRegionsTreeTest, VisitReservedRegions) { NativeCallStack ncs; VMATree::RegionData rd = rt.make_region_data(ncs, mtTest); - rt.reserve_mapping(1000, 50, rd); - rt.reserve_mapping(1200, 50, rd); - rt.reserve_mapping(1300, 50, rd); - rt.reserve_mapping(1400, 50, rd); + VMATree::SummaryDiff not_used; + rt.reserve_mapping(1000, 50, rd, not_used); + rt.reserve_mapping(1200, 50, rd, not_used); + rt.reserve_mapping(1300, 50, rd, not_used); + rt.reserve_mapping(1400, 50, rd, not_used); rt.visit_reserved_regions([&](const ReservedMemoryRegion& rgn) { EXPECT_EQ(((size_t)rgn.base()) % 100, 0UL); @@ -110,15 +134,16 @@ TEST_VM_F(NMTRegionsTreeTest, VisitReservedRegions) { TEST_VM_F(NMTRegionsTreeTest, VisitCommittedRegions) { NativeCallStack ncs; VMATree::RegionData rd = rt.make_region_data(ncs, mtTest); - rt.reserve_mapping(1000, 50, rd); - rt.reserve_mapping(1200, 50, rd); - rt.reserve_mapping(1300, 50, rd); - rt.reserve_mapping(1400, 50, rd); + VMATree::SummaryDiff not_used; + rt.reserve_mapping(1000, 50, rd, not_used); + rt.reserve_mapping(1200, 50, rd, not_used); + rt.reserve_mapping(1300, 50, rd, not_used); + rt.reserve_mapping(1400, 50, rd, not_used); - rt.commit_region((address)1010, 5UL, ncs); - rt.commit_region((address)1020, 5UL, ncs); - rt.commit_region((address)1030, 5UL, ncs); - rt.commit_region((address)1040, 5UL, ncs); + rt.commit_region((address)1010, 5UL, ncs, not_used); + rt.commit_region((address)1020, 5UL, ncs, not_used); + rt.commit_region((address)1030, 5UL, ncs, not_used); + rt.commit_region((address)1040, 5UL, ncs, not_used); ReservedMemoryRegion rmr((address)1000, 50); size_t count = 0; rt.visit_committed_regions(rmr, [&](CommittedMemoryRegion& crgn) { diff --git a/test/hotspot/gtest/nmt/test_vmatree.cpp b/test/hotspot/gtest/nmt/test_vmatree.cpp index cc4493a0e0f..eed2e5af0be 100644 --- a/test/hotspot/gtest/nmt/test_vmatree.cpp +++ b/test/hotspot/gtest/nmt/test_vmatree.cpp @@ -92,14 +92,15 @@ class NMTVMATreeTest : public testing::Test { // Adjacent reservations are merged if the properties match. void adjacent_2_nodes(const VMATree::RegionData& rd) { Tree tree; + VMATree::SummaryDiff not_used; for (int i = 0; i < 10; i++) { - tree.reserve_mapping(i * 100, 100, rd); + tree.reserve_mapping(i * 100, 100, rd, not_used); } EXPECT_EQ(2, count_nodes(tree)); // Reserving the exact same space again should result in still having only 2 nodes for (int i = 0; i < 10; i++) { - tree.reserve_mapping(i * 100, 100, rd); + tree.reserve_mapping(i * 100, 100, rd, not_used); } EXPECT_EQ(2, count_nodes(tree)); @@ -111,7 +112,7 @@ class NMTVMATreeTest : public testing::Test { // ... // 0--100 for (int i = 9; i >= 0; i--) { - tree2.reserve_mapping(i * 100, 100, rd); + tree2.reserve_mapping(i * 100, 100, rd, not_used); } EXPECT_EQ(2, count_nodes(tree2)); } @@ -119,16 +120,17 @@ class NMTVMATreeTest : public testing::Test { // After removing all ranges we should be left with an entirely empty tree void remove_all_leaves_empty_tree(const VMATree::RegionData& rd) { Tree tree; - tree.reserve_mapping(0, 100 * 10, rd); + VMATree::SummaryDiff not_used; + tree.reserve_mapping(0, 100 * 10, rd, not_used); for (int i = 0; i < 10; i++) { - tree.release_mapping(i * 100, 100); + tree.release_mapping(i * 100, 100, not_used); } EXPECT_EQ(nullptr, rbtree_root(tree)); // Other way around - tree.reserve_mapping(0, 100 * 10, rd); + tree.reserve_mapping(0, 100 * 10, rd, not_used); for (int i = 9; i >= 0; i--) { - tree.release_mapping(i * 100, 100); + tree.release_mapping(i * 100, 100, not_used); } EXPECT_EQ(nullptr, rbtree_root(tree)); } @@ -136,9 +138,10 @@ class NMTVMATreeTest : public testing::Test { // Committing in a whole reserved range results in 2 nodes void commit_whole(const VMATree::RegionData& rd) { Tree tree; - tree.reserve_mapping(0, 100 * 10, rd); + VMATree::SummaryDiff not_used; + tree.reserve_mapping(0, 100 * 10, rd, not_used); for (int i = 0; i < 10; i++) { - tree.commit_mapping(i * 100, 100, rd); + tree.commit_mapping(i * 100, 100, rd, not_used); } rbtree(tree).visit_in_order([&](TNode* x) { VMATree::StateType in = in_type_of(x); @@ -153,8 +156,9 @@ class NMTVMATreeTest : public testing::Test { // Committing in middle of reservation ends with a sequence of 4 nodes void commit_middle(const VMATree::RegionData& rd) { Tree tree; - tree.reserve_mapping(0, 100, rd); - tree.commit_mapping(50, 25, rd); + VMATree::SummaryDiff not_used; + tree.reserve_mapping(0, 100, rd, not_used); + tree.commit_mapping(50, 25, rd, not_used); size_t found[16]; size_t wanted[4] = {0, 50, 75, 100}; @@ -342,8 +346,9 @@ class NMTVMATreeTest : public testing::Test { TEST_VM_F(NMTVMATreeTest, OverlappingReservationsResultInTwoNodes) { VMATree::RegionData rd{si[0], mtTest}; Tree tree; + VMATree::SummaryDiff not_used; for (int i = 99; i >= 0; i--) { - tree.reserve_mapping(i * 100, 101, rd); + tree.reserve_mapping(i * 100, 101, rd, not_used); } EXPECT_EQ(2, count_nodes(tree)); } @@ -351,8 +356,9 @@ TEST_VM_F(NMTVMATreeTest, OverlappingReservationsResultInTwoNodes) { TEST_VM_F(NMTVMATreeTest, DuplicateReserve) { VMATree::RegionData rd{si[0], mtTest}; Tree tree; - tree.reserve_mapping(100, 100, rd); - tree.reserve_mapping(100, 100, rd); + VMATree::SummaryDiff not_used; + tree.reserve_mapping(100, 100, rd, not_used); + tree.reserve_mapping(100, 100, rd, not_used); EXPECT_EQ(2, count_nodes(tree)); VMATree::VMARBTree::Range r = tree.tree().find_enclosing_range(110); EXPECT_EQ(100, (int)(r.end->key() - r.start->key())); @@ -360,15 +366,16 @@ TEST_VM_F(NMTVMATreeTest, DuplicateReserve) { TEST_VM_F(NMTVMATreeTest, UseTagInplace) { Tree tree; + VMATree::SummaryDiff not_used; VMATree::RegionData rd_Test_cs0(si[0], mtTest); VMATree::RegionData rd_None_cs1(si[1], mtNone); - tree.reserve_mapping(0, 100, rd_Test_cs0); + tree.reserve_mapping(0, 100, rd_Test_cs0, not_used); // reserve: 0---------------------100 // commit: 20**********70 // uncommit: 30--40 // post-cond: 0---20**30--40**70----100 - tree.commit_mapping(20, 50, rd_None_cs1, true); - tree.uncommit_mapping(30, 10, rd_None_cs1); + tree.commit_mapping(20, 50, rd_None_cs1, not_used, true); + tree.uncommit_mapping(30, 10, rd_None_cs1, not_used); tree.visit_in_order([&](const TNode* node) { if (node->key() != 100) { EXPECT_EQ(mtTest, node->val().out.mem_tag()) << "failed at: " << node->key(); @@ -395,10 +402,11 @@ TEST_VM_F(NMTVMATreeTest, LowLevel) { { // Identical operation but different metadata should not merge Tree tree; + VMATree::SummaryDiff not_used; VMATree::RegionData rd_Test_cs0{si[0], mtTest}; VMATree::RegionData rd_NMT_cs1{si[1], mtNMT}; - tree.reserve_mapping(0, 100, rd_Test_cs0); - tree.reserve_mapping(100, 100, rd_NMT_cs1); + tree.reserve_mapping(0, 100, rd_Test_cs0, not_used); + tree.reserve_mapping(100, 100, rd_NMT_cs1, not_used); EXPECT_EQ(3, count_nodes(tree)); int found_nodes = 0; @@ -406,10 +414,11 @@ TEST_VM_F(NMTVMATreeTest, LowLevel) { { // Reserving after commit should overwrite commit Tree tree; + VMATree::SummaryDiff not_used; VMATree::RegionData rd_Test_cs0{si[0], mtTest}; VMATree::RegionData rd_NMT_cs1{si[1], mtNMT}; - tree.commit_mapping(50, 50, rd_NMT_cs1); - tree.reserve_mapping(0, 100, rd_Test_cs0); + tree.commit_mapping(50, 50, rd_NMT_cs1, not_used); + tree.reserve_mapping(0, 100, rd_Test_cs0, not_used); rbtree(tree).visit_in_order([&](const TNode* x) { EXPECT_TRUE(x->key() == 0 || x->key() == 100); if (x->key() == 0UL) { @@ -423,20 +432,22 @@ TEST_VM_F(NMTVMATreeTest, LowLevel) { { // Split a reserved region into two different reserved regions Tree tree; + VMATree::SummaryDiff not_used; VMATree::RegionData rd_Test_cs0{si[0], mtTest}; VMATree::RegionData rd_NMT_cs1{si[1], mtNMT}; VMATree::RegionData rd_None_cs0{si[0], mtNone}; - tree.reserve_mapping(0, 100, rd_Test_cs0); - tree.reserve_mapping(0, 50, rd_NMT_cs1); - tree.reserve_mapping(50, 50, rd_None_cs0); + tree.reserve_mapping(0, 100, rd_Test_cs0, not_used); + tree.reserve_mapping(0, 50, rd_NMT_cs1, not_used); + tree.reserve_mapping(50, 50, rd_None_cs0, not_used); EXPECT_EQ(3, count_nodes(tree)); } { // One big reserve + release leaves an empty tree VMATree::RegionData rd_NMT_cs0{si[0], mtNMT}; Tree tree; - tree.reserve_mapping(0, 500000, rd_NMT_cs0); - tree.release_mapping(0, 500000); + VMATree::SummaryDiff not_used; + tree.reserve_mapping(0, 500000, rd_NMT_cs0, not_used); + tree.release_mapping(0, 500000, not_used); EXPECT_EQ(nullptr, rbtree_root(tree)); } @@ -446,8 +457,9 @@ TEST_VM_F(NMTVMATreeTest, LowLevel) { VMATree::RegionData rd_NMT_cs0{si[0], mtNMT}; VMATree::RegionData rd_Test_cs1{si[1], mtTest}; Tree tree; - tree.reserve_mapping(0, 100, rd_NMT_cs0); - tree.commit_mapping(0, 100, rd_Test_cs1); + VMATree::SummaryDiff not_used; + tree.reserve_mapping(0, 100, rd_NMT_cs0, not_used); + tree.commit_mapping(0, 100, rd_Test_cs1, not_used); rbtree(tree).visit_range_in_order(0, 99999, [&](TNode* x) { if (x->key() == 0) { EXPECT_EQ(mtTest, x->val().out.reserved_regiondata().mem_tag); @@ -461,10 +473,11 @@ TEST_VM_F(NMTVMATreeTest, LowLevel) { { // Attempting to reserve or commit an empty region should not change the tree. Tree tree; + VMATree::SummaryDiff not_used; VMATree::RegionData rd_NMT_cs0{si[0], mtNMT}; - tree.reserve_mapping(0, 0, rd_NMT_cs0); + tree.reserve_mapping(0, 0, rd_NMT_cs0, not_used); EXPECT_EQ(nullptr, rbtree_root(tree)); - tree.commit_mapping(0, 0, rd_NMT_cs0); + tree.commit_mapping(0, 0, rd_NMT_cs0, not_used); EXPECT_EQ(nullptr, rbtree_root(tree)); } } @@ -520,8 +533,9 @@ TEST_VM_F(NMTVMATreeTest, SetTag) { {500, 600, mtClassShared, si, State::Reserved} }; VMATree tree; + VMATree::SummaryDiff not_used; - tree.reserve_mapping(0, 600, rd); + tree.reserve_mapping(0, 600, rd, not_used); tree.set_tag(0, 500, mtGC); tree.set_tag(500, 100, mtClassShared); @@ -540,6 +554,7 @@ TEST_VM_F(NMTVMATreeTest, SetTag) { {575, 600, mtClassShared, si, State::Reserved} }; VMATree tree; + VMATree::SummaryDiff not_used; // 0---------------------------------------------------600 // 100****225 @@ -548,11 +563,11 @@ TEST_VM_F(NMTVMATreeTest, SetTag) { // 0------100****225---------550***560---565***575-----600 // 0------100****225---500---550***560---565***575-----600 // <-------mtGC---------><-----------mtClassShared-------> - tree.reserve_mapping(0, 600, rd); + tree.reserve_mapping(0, 600, rd, not_used); // The committed areas - tree.commit_mapping(100, 125, rd); - tree.commit_mapping(550, 10, rd); - tree.commit_mapping(565, 10, rd); + tree.commit_mapping(100, 125, rd, not_used); + tree.commit_mapping(550, 10, rd, not_used); + tree.commit_mapping(565, 10, rd, not_used); // OK, set tag tree.set_tag(0, 500, mtGC); tree.set_tag(500, 100, mtClassShared); @@ -564,10 +579,11 @@ TEST_VM_F(NMTVMATreeTest, SetTag) { {0, 200, mtGC, si, State::Reserved} }; VMATree tree; + VMATree::SummaryDiff not_used; Tree::RegionData gc(si, mtGC); Tree::RegionData compiler(si, mtCompiler); - tree.reserve_mapping(0, 100, gc); - tree.reserve_mapping(100, 100, compiler); + tree.reserve_mapping(0, 100, gc, not_used); + tree.reserve_mapping(100, 100, compiler, not_used); tree.set_tag(0, 200, mtGC); expect_equivalent_form(expected, tree, __LINE__); } @@ -580,10 +596,11 @@ TEST_VM_F(NMTVMATreeTest, SetTag) { {100, 200, mtGC, si2, State::Reserved} }; VMATree tree; + VMATree::SummaryDiff not_used; Tree::RegionData gc(si1, mtGC); Tree::RegionData compiler(si2, mtCompiler); - tree.reserve_mapping(0, 100, gc); - tree.reserve_mapping(100, 100, compiler); + tree.reserve_mapping(0, 100, gc, not_used); + tree.reserve_mapping(100, 100, compiler, not_used); tree.set_tag(0, 200, mtGC); expect_equivalent_form(expected, tree, __LINE__); } @@ -595,8 +612,9 @@ TEST_VM_F(NMTVMATreeTest, SetTag) { {150, 200, mtCompiler, si, State::Reserved} }; VMATree tree; + VMATree::SummaryDiff not_used; Tree::RegionData compiler(si, mtCompiler); - tree.reserve_mapping(0, 200, compiler); + tree.reserve_mapping(0, 200, compiler, not_used); tree.set_tag(100, 50, mtGC); expect_equivalent_form(expected, tree, __LINE__); } @@ -608,10 +626,11 @@ TEST_VM_F(NMTVMATreeTest, SetTag) { {125, 200, mtCompiler, si, State::Reserved}, }; VMATree tree; + VMATree::SummaryDiff not_used; Tree::RegionData gc(si, mtGC); Tree::RegionData compiler(si, mtCompiler); - tree.reserve_mapping(0, 100, gc); - tree.reserve_mapping(100, 100, compiler); + tree.reserve_mapping(0, 100, gc, not_used); + tree.reserve_mapping(100, 100, compiler, not_used); tree.set_tag(75, 50, mtClass); expect_equivalent_form(expected, tree, __LINE__); } @@ -624,9 +643,10 @@ TEST_VM_F(NMTVMATreeTest, SetTag) { {80, 100, mtClassShared, si, State::Reserved} }; VMATree tree; + VMATree::SummaryDiff not_used; Tree::RegionData class_shared(si, mtClassShared); - tree.reserve_mapping(0, 50, class_shared); - tree.reserve_mapping(75, 25, class_shared); + tree.reserve_mapping(0, 50, class_shared, not_used); + tree.reserve_mapping(75, 25, class_shared, not_used); tree.set_tag(0, 80, mtGC); expect_equivalent_form(expected, tree, __LINE__); } @@ -636,8 +656,9 @@ TEST_VM_F(NMTVMATreeTest, SetTag) { {10, 20, mtCompiler, si, State::Reserved} }; VMATree tree; + VMATree::SummaryDiff not_used; Tree::RegionData class_shared(si, mtClassShared); - tree.reserve_mapping(10, 10, class_shared); + tree.reserve_mapping(10, 10, class_shared, not_used); tree.set_tag(0, 100, mtCompiler); expect_equivalent_form(expected, tree, __LINE__); } @@ -651,10 +672,11 @@ TEST_VM_F(NMTVMATreeTest, SetTag) { {99, 100, mtGC, si, State::Reserved} }; VMATree tree; + VMATree::SummaryDiff not_used; Tree::RegionData class_shared(si, mtClassShared); - tree.reserve_mapping(0, 100, class_shared); - tree.release_mapping(1, 49); - tree.release_mapping(75, 24); + tree.reserve_mapping(0, 100, class_shared, not_used); + tree.release_mapping(1, 49, not_used); + tree.release_mapping(75, 24, not_used); tree.set_tag(0, 100, mtGC); expect_equivalent_form(expected, tree, __LINE__); } @@ -666,7 +688,8 @@ TEST_VM_F(NMTVMATreeTest, SummaryAccounting) { Tree::RegionData rd_Test_cs0(NCS::StackIndex(), mtTest); Tree::RegionData rd_NMT_cs0(NCS::StackIndex(), mtNMT); Tree tree; - VMATree::SummaryDiff all_diff = tree.reserve_mapping(0, 100, rd_Test_cs0); + VMATree::SummaryDiff all_diff; + tree.reserve_mapping(0, 100, rd_Test_cs0, all_diff); // 1 2 3 4 5 6 7 8 9 10 11 // 01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.......... @@ -675,7 +698,7 @@ TEST_VM_F(NMTVMATreeTest, SummaryAccounting) { // . - free VMATree::SingleDiff diff = all_diff.tag[NMTUtil::tag_to_index(mtTest)]; EXPECT_EQ(100, diff.reserve); - all_diff = tree.reserve_mapping(50, 25, rd_NMT_cs0); + tree.reserve_mapping(50, 25, rd_NMT_cs0, all_diff); // 1 2 3 4 5 6 7 8 9 10 11 // 01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBCCCCCCCCCCCCCCCCCCCCCCCCC.......... @@ -692,7 +715,8 @@ TEST_VM_F(NMTVMATreeTest, SummaryAccounting) { { // Fully release reserved mapping Tree::RegionData rd_Test_cs0(NCS::StackIndex(), mtTest); Tree tree; - VMATree::SummaryDiff all_diff = tree.reserve_mapping(0, 100, rd_Test_cs0); + VMATree::SummaryDiff all_diff; + tree.reserve_mapping(0, 100, rd_Test_cs0, all_diff); // 1 2 3 4 5 6 7 8 9 10 11 // 01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.......... @@ -701,7 +725,7 @@ TEST_VM_F(NMTVMATreeTest, SummaryAccounting) { // . - free VMATree::SingleDiff diff = all_diff.tag[NMTUtil::tag_to_index(mtTest)]; EXPECT_EQ(100, diff.reserve); - all_diff = tree.release_mapping(0, 100); + tree.release_mapping(0, 100, all_diff); // 1 2 3 4 5 6 7 8 9 10 11 // 01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 // .............................................................................................................. @@ -712,7 +736,8 @@ TEST_VM_F(NMTVMATreeTest, SummaryAccounting) { { // Convert some of a released mapping to a committed one Tree::RegionData rd_Test_cs0(NCS::StackIndex(), mtTest); Tree tree; - VMATree::SummaryDiff all_diff = tree.reserve_mapping(0, 100, rd_Test_cs0); + VMATree::SummaryDiff all_diff; + tree.reserve_mapping(0, 100, rd_Test_cs0, all_diff); // 1 2 3 4 5 6 7 8 9 10 11 // 01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.......... @@ -721,7 +746,7 @@ TEST_VM_F(NMTVMATreeTest, SummaryAccounting) { // . - free VMATree::SingleDiff diff = all_diff.tag[NMTUtil::tag_to_index(mtTest)]; EXPECT_EQ(diff.reserve, 100); - all_diff = tree.commit_mapping(0, 100, rd_Test_cs0); + tree.commit_mapping(0, 100, rd_Test_cs0, all_diff); // 1 2 3 4 5 6 7 8 9 10 11 // 01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 // aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.......... @@ -735,7 +760,8 @@ TEST_VM_F(NMTVMATreeTest, SummaryAccounting) { { // Adjacent reserved mappings with same type Tree::RegionData rd_Test_cs0(NCS::StackIndex(), mtTest); Tree tree; - VMATree::SummaryDiff all_diff = tree.reserve_mapping(0, 10, rd_Test_cs0); + VMATree::SummaryDiff all_diff; + tree.reserve_mapping(0, 10, rd_Test_cs0, all_diff); // 1 2 // 01234567890123456789 // AAAAAAAAAA.......... @@ -744,7 +770,7 @@ TEST_VM_F(NMTVMATreeTest, SummaryAccounting) { // . - free VMATree::SingleDiff diff = all_diff.tag[NMTUtil::tag_to_index(mtTest)]; EXPECT_EQ(diff.reserve, 10); - all_diff = tree.reserve_mapping(10, 10, rd_Test_cs0); + tree.reserve_mapping(10, 10, rd_Test_cs0, all_diff); // 1 2 3 // 012345678901234567890123456789 // AAAAAAAAAAAAAAAAAAAA.......... @@ -758,7 +784,8 @@ TEST_VM_F(NMTVMATreeTest, SummaryAccounting) { Tree::RegionData rd_Test_cs0(NCS::StackIndex(), mtTest); Tree::RegionData rd_NMT_cs0(NCS::StackIndex(), mtNMT); Tree tree; - VMATree::SummaryDiff all_diff = tree.reserve_mapping(0, 10, rd_Test_cs0); + VMATree::SummaryDiff all_diff; + tree.reserve_mapping(0, 10, rd_Test_cs0, all_diff); // 1 2 // 01234567890123456789 // AAAAAAAAAA.......... @@ -767,7 +794,7 @@ TEST_VM_F(NMTVMATreeTest, SummaryAccounting) { // . - free VMATree::SingleDiff diff = all_diff.tag[NMTUtil::tag_to_index(mtTest)]; EXPECT_EQ(diff.reserve, 10); - all_diff = tree.reserve_mapping(10, 10, rd_NMT_cs0); + tree.reserve_mapping(10, 10, rd_NMT_cs0, all_diff); // 1 2 3 // 012345678901234567890123456789 // AAAAAAAAAABBBBBBBBBB.......... @@ -784,22 +811,23 @@ TEST_VM_F(NMTVMATreeTest, SummaryAccounting) { { // A commit with two previous commits inside of it should only register // the new memory in the commit diff. Tree tree; + VMATree::SummaryDiff diff; Tree::RegionData rd_Test_cs0(NCS::StackIndex(), mtTest); - tree.commit_mapping(16, 16, rd_Test_cs0); + tree.commit_mapping(16, 16, rd_Test_cs0, diff); // 1 2 3 4 // 0123456789012345678901234567890123456789 // ................aaaaaaaaaaaaaaaa.......... // Legend: // a - Test (committed) // . - free - tree.commit_mapping(32, 32, rd_Test_cs0); + tree.commit_mapping(32, 32, rd_Test_cs0, diff); // 1 2 3 4 5 6 7 // 0123456789012345678901234567890123456789012345678901234567890123456789 // ................aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.......... // Legend: // a - Test (committed) // . - free - VMATree::SummaryDiff diff = tree.commit_mapping(0, 64, rd_Test_cs0); + tree.commit_mapping(0, 64, rd_Test_cs0, diff); // 1 2 3 4 5 6 7 // 0123456789012345678901234567890123456789012345678901234567890123456789 // aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.......... @@ -814,11 +842,12 @@ TEST_VM_F(NMTVMATreeTest, SummaryAccounting) { TEST_VM_F(NMTVMATreeTest, SummaryAccountingReserveAsUncommit) { Tree tree; Tree::RegionData rd(NCS::StackIndex(), mtTest); - VMATree::SummaryDiff diff1 = tree.reserve_mapping(1200, 100, rd); - VMATree::SummaryDiff diff2 = tree.commit_mapping(1210, 50, rd); + VMATree::SummaryDiff diff1, diff2, diff3; + tree.reserve_mapping(1200, 100, rd, diff1); + tree.commit_mapping(1210, 50, rd, diff2); EXPECT_EQ(100, diff1.tag[NMTUtil::tag_to_index(mtTest)].reserve); EXPECT_EQ(50, diff2.tag[NMTUtil::tag_to_index(mtTest)].commit); - VMATree::SummaryDiff diff3 = tree.reserve_mapping(1220, 20, rd); + tree.reserve_mapping(1220, 20, rd, diff3); EXPECT_EQ(-20, diff3.tag[NMTUtil::tag_to_index(mtTest)].commit); EXPECT_EQ(0, diff3.tag[NMTUtil::tag_to_index(mtTest)].reserve); } @@ -951,13 +980,13 @@ TEST_VM_F(NMTVMATreeTest, TestConsistencyWithSimpleTracker) { VMATree::SummaryDiff simple_diff; if (kind == SimpleVMATracker::Reserved) { simple_diff = tr->reserve(start, size, stack, mem_tag); - tree_diff = tree.reserve_mapping(start, size, data); + tree.reserve_mapping(start, size, data, tree_diff); } else if (kind == SimpleVMATracker::Committed) { simple_diff = tr->commit(start, size, stack, mem_tag); - tree_diff = tree.commit_mapping(start, size, data); + tree.commit_mapping(start, size, data, tree_diff); } else { simple_diff = tr->release(start, size); - tree_diff = tree.release_mapping(start, size); + tree.release_mapping(start, size, tree_diff); } for (int j = 0; j < mt_number_of_tags; j++) { @@ -1024,33 +1053,34 @@ TEST_VM_F(NMTVMATreeTest, TestConsistencyWithSimpleTracker) { TEST_VM_F(NMTVMATreeTest, SummaryAccountingWhenUseTagInplace) { Tree tree; + VMATree::SummaryDiff diff; VMATree::RegionData rd_Test_cs0(si[0], mtTest); VMATree::RegionData rd_None_cs1(si[1], mtNone); -// 1 2 3 4 5 -// 012345678901234567890123456789012345678901234567890 -// .................................................. - tree.reserve_mapping(0, 50, rd_Test_cs0); -// 1 2 3 4 5 -// 012345678901234567890123456789012345678901234567890 -// rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr -VMATree::SummaryDiff diff = tree.commit_mapping(0, 25, rd_None_cs1, true); -// 1 2 3 4 5 -// 012345678901234567890123456789012345678901234567890 -// CCCCCCCCCCCCCCCCCCCCCCCCCrrrrrrrrrrrrrrrrrrrrrrrrr + // 1 2 3 4 5 + // 012345678901234567890123456789012345678901234567890 + // .................................................. + tree.reserve_mapping(0, 50, rd_Test_cs0, diff); + // 1 2 3 4 5 + // 012345678901234567890123456789012345678901234567890 + // rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr + tree.commit_mapping(0, 25, rd_None_cs1, diff, true); + // 1 2 3 4 5 + // 012345678901234567890123456789012345678901234567890 + // CCCCCCCCCCCCCCCCCCCCCCCCCrrrrrrrrrrrrrrrrrrrrrrrrr EXPECT_EQ(0, diff.tag[NMTUtil::tag_to_index(mtTest)].reserve); EXPECT_EQ(25, diff.tag[NMTUtil::tag_to_index(mtTest)].commit); - diff = tree.commit_mapping(30, 5, rd_None_cs1, true); -// 1 2 3 4 5 -// 012345678901234567890123456789012345678901234567890 -// CCCCCCCCCCCCCCCCCCCCCCCCCrrrrrCCCCCrrrrrrrrrrrrrrr + tree.commit_mapping(30, 5, rd_None_cs1, diff, true); + // 1 2 3 4 5 + // 012345678901234567890123456789012345678901234567890 + // CCCCCCCCCCCCCCCCCCCCCCCCCrrrrrCCCCCrrrrrrrrrrrrrrr EXPECT_EQ(0, diff.tag[NMTUtil::tag_to_index(mtTest)].reserve); EXPECT_EQ(5, diff.tag[NMTUtil::tag_to_index(mtTest)].commit); - diff = tree.uncommit_mapping(0, 25, rd_None_cs1); -// 1 2 3 4 5 -// 012345678901234567890123456789012345678901234567890 -// rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrCCCCCrrrrrrrrrrrrrrr + tree.uncommit_mapping(0, 25, rd_None_cs1, diff); + // 1 2 3 4 5 + // 012345678901234567890123456789012345678901234567890 + // rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrCCCCCrrrrrrrrrrrrrrr EXPECT_EQ(0, diff.tag[NMTUtil::tag_to_index(mtTest)].reserve); EXPECT_EQ(-25, diff.tag[NMTUtil::tag_to_index(mtTest)].commit); } @@ -1079,7 +1109,8 @@ TEST_VM_F(NMTVMATreeTest, SeparateStacksForCommitAndReserve) { {// Check committing into a reserved region inherits the call stacks Tree tree; - tree.reserve_mapping(0, 50, rd_Test_cs1); // reserve in an empty tree + VMATree::SummaryDiff diff; + tree.reserve_mapping(0, 50, rd_Test_cs1, diff); // reserve in an empty tree // Pre: empty tree. // Post: // 1 2 3 4 5 @@ -1091,7 +1122,7 @@ TEST_VM_F(NMTVMATreeTest, SeparateStacksForCommitAndReserve) { {-1 , si_1 , -1 }, {-1 , -1 , -1 }}; check_tree(tree, et1, __LINE__); - tree.commit_mapping(25, 10, rd_None_cs2, true); // commit at the middle of the region + tree.commit_mapping(25, 10, rd_None_cs2, diff, true); // commit at the middle of the region // Post: // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 @@ -1103,7 +1134,7 @@ TEST_VM_F(NMTVMATreeTest, SeparateStacksForCommitAndReserve) { {-1 , -1 , si_2 , -1 , -1 }}; check_tree(tree, et2, __LINE__); - tree.commit_mapping(0, 20, rd_None_cs2, true); // commit at the beginning of the region + tree.commit_mapping(0, 20, rd_None_cs2, diff, true); // commit at the beginning of the region // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 // CCCCCCCCCCCCCCCCCCCCrrrrrCCCCCCCCCCrrrrrrrrrrrrrrr. @@ -1114,7 +1145,7 @@ TEST_VM_F(NMTVMATreeTest, SeparateStacksForCommitAndReserve) { {-1 , si_2 , -1 , si_2 , -1 , -1 }}; check_tree(tree, et3, __LINE__); - tree.commit_mapping(40, 10, rd_None_cs2, true); // commit at the end of the region + tree.commit_mapping(40, 10, rd_None_cs2, diff, true); // commit at the end of the region // Post: // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 @@ -1128,7 +1159,8 @@ TEST_VM_F(NMTVMATreeTest, SeparateStacksForCommitAndReserve) { } {// committing overlapped regions does not destroy the old call-stacks Tree tree; - tree.reserve_mapping(0, 50, rd_Test_cs1); // reserving in an empty tree + VMATree::SummaryDiff diff; + tree.reserve_mapping(0, 50, rd_Test_cs1, diff); // reserving in an empty tree // Pre: empty tree. // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 @@ -1140,7 +1172,7 @@ TEST_VM_F(NMTVMATreeTest, SeparateStacksForCommitAndReserve) { {-1 , -1 , -1 }}; check_tree(tree, et1, __LINE__); - tree.commit_mapping(10, 10, rd_None_cs2, true); + tree.commit_mapping(10, 10, rd_None_cs2, diff, true); // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 // rrrrrrrrrrCCCCCCCCCCrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr @@ -1154,7 +1186,7 @@ TEST_VM_F(NMTVMATreeTest, SeparateStacksForCommitAndReserve) { SIndex si_3 = si[2]; VMATree::RegionData rd_Test_cs3(si_3, mtTest); // commit with overlap at the region's start - tree.commit_mapping(5, 10, rd_Test_cs3); + tree.commit_mapping(5, 10, rd_Test_cs3, diff); // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 // rrrrrCCCCCCCCCCCCCCCrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr @@ -1168,7 +1200,7 @@ TEST_VM_F(NMTVMATreeTest, SeparateStacksForCommitAndReserve) { SIndex si_4 = si[3]; VMATree::RegionData call_stack_4(si_4, mtTest); // commit with overlap at the region's end - tree.commit_mapping(15, 10, call_stack_4); + tree.commit_mapping(15, 10, call_stack_4, diff); // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 // rrrrrCCCCCCCCCCCCCCCCCCCCrrrrrrrrrrrrrrrrrrrrrrrrr @@ -1181,13 +1213,14 @@ TEST_VM_F(NMTVMATreeTest, SeparateStacksForCommitAndReserve) { } {// uncommit should not store any call-stack Tree tree; - tree.reserve_mapping(0, 50, rd_Test_cs1); + VMATree::SummaryDiff diff; + tree.reserve_mapping(0, 50, rd_Test_cs1, diff); - tree.commit_mapping(10, 10, rd_None_cs2, true); + tree.commit_mapping(10, 10, rd_None_cs2, diff, true); - tree.commit_mapping(0, 5, rd_None_cs2, true); + tree.commit_mapping(0, 5, rd_None_cs2, diff, true); - tree.uncommit_mapping(0, 3, rd_None_cs2); + tree.uncommit_mapping(0, 3, rd_None_cs2, diff); // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 // rrrCCrrrrrCCCCCCCCCCrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr @@ -1198,7 +1231,7 @@ TEST_VM_F(NMTVMATreeTest, SeparateStacksForCommitAndReserve) { {-1 , -1 , si_2 , -1 , si_2 , -1 , -1 }}; check_tree(tree, et1, __LINE__); - tree.uncommit_mapping(5, 10, rd_None_cs2); + tree.uncommit_mapping(5, 10, rd_None_cs2, diff); // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 // rrrCCrrrrrrrrrrCCCCCrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr. @@ -1214,8 +1247,9 @@ TEST_VM_F(NMTVMATreeTest, SeparateStacksForCommitAndReserve) { VMATree::RegionData call_stack_4(si_4, mtTest); Tree tree; - tree.reserve_mapping(0, 50, rd_Test_cs1); - tree.reserve_mapping(10, 10, call_stack_4); + VMATree::SummaryDiff diff; + tree.reserve_mapping(0, 50, rd_Test_cs1, diff); + tree.reserve_mapping(10, 10, call_stack_4, diff); // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 // rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr @@ -1228,7 +1262,8 @@ TEST_VM_F(NMTVMATreeTest, SeparateStacksForCommitAndReserve) { } {// commit without reserve Tree tree; - tree.commit_mapping(0, 50, rd_Test_cs1); + VMATree::SummaryDiff diff; + tree.commit_mapping(0, 50, rd_Test_cs1, diff); // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 // CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC @@ -1241,8 +1276,9 @@ TEST_VM_F(NMTVMATreeTest, SeparateStacksForCommitAndReserve) { } {// reserve after commit Tree tree; - tree.commit_mapping(0, 50, rd_None_cs2); - tree.reserve_mapping(0, 50, rd_Test_cs1); + VMATree::SummaryDiff diff; + tree.commit_mapping(0, 50, rd_None_cs2, diff); + tree.reserve_mapping(0, 50, rd_Test_cs1, diff); // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 // rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr @@ -1287,7 +1323,8 @@ TEST_VM_F(NMTVMATreeTest, OverlapTableRows0To3) { {-1 , -1 , -1 , -1 , -1 , -1 } }; create_tree(tree, pre, __LINE__); - VMATree::SummaryDiff diff = tree.commit_mapping(5, 20, rd_Test_cs2, false); + VMATree::SummaryDiff diff; + tree.commit_mapping(5, 20, rd_Test_cs2, diff, false); // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 // .....CCCCCCCCCCCCCCCCCCCC.......................... @@ -1314,7 +1351,8 @@ TEST_VM_F(NMTVMATreeTest, OverlapTableRows0To3) { {-1 , -1 , -1 , -1 , -1 , -1 } }; create_tree(tree, pre, __LINE__); - VMATree::SummaryDiff diff = tree.commit_mapping(5, 15, rd_Test_cs2, false); + VMATree::SummaryDiff diff; + tree.commit_mapping(5, 15, rd_Test_cs2, diff, false); // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 // .....CCCCCCCCCCCCCCC............................... @@ -1359,7 +1397,8 @@ TEST_VM_F(NMTVMATreeTest, OverlapTableRows4to7) { {-1 , -1 , -1 } }; create_tree(tree, pre, __LINE__); - VMATree::SummaryDiff diff = tree.commit_mapping(20, 20, rd_Test_cs2, false); + VMATree::SummaryDiff diff; + tree.commit_mapping(20, 20, rd_Test_cs2, diff, false); // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 // rrrrrrrrrr..........CCCCCCCCCCCCCCCCCCCC........... @@ -1386,7 +1425,8 @@ TEST_VM_F(NMTVMATreeTest, OverlapTableRows4to7) { {-1 , -1 , -1 } }; create_tree(tree, pre, __LINE__); - VMATree::SummaryDiff diff = tree.commit_mapping(10, 10, rd_Test_cs2, false); + VMATree::SummaryDiff diff; + tree.commit_mapping(10, 10, rd_Test_cs2, diff, false); // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 // .....rrrrrCCCCCCCCCC............................... @@ -1413,7 +1453,8 @@ TEST_VM_F(NMTVMATreeTest, OverlapTableRows4to7) { {-1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 } }; create_tree(tree, pre, __LINE__); - VMATree::SummaryDiff diff = tree.commit_mapping(7, 20, rd_Test_cs2, false); + VMATree::SummaryDiff diff; + tree.commit_mapping(7, 20, rd_Test_cs2, diff, false); // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 // rrrrr..CCCCCCCCCCCCCCCCCCCC........................ @@ -1440,7 +1481,8 @@ TEST_VM_F(NMTVMATreeTest, OverlapTableRows4to7) { {-1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 } }; create_tree(tree, pre, __LINE__); - VMATree::SummaryDiff diff = tree.commit_mapping(7, 13, rd_Test_cs2, false); + VMATree::SummaryDiff diff; + tree.commit_mapping(7, 13, rd_Test_cs2, diff, false); // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 // rrrrr..CCCCCCCCCCCCC............................... @@ -1492,7 +1534,8 @@ TEST_VM_F(NMTVMATreeTest, OverlapTableRows8to11) { {-1 , -1 , -1 } }; create_tree(tree, pre, __LINE__); - VMATree::SummaryDiff diff = tree.commit_mapping(10, 20, rd_Test_cs2, false); + VMATree::SummaryDiff diff; + tree.commit_mapping(10, 20, rd_Test_cs2, diff, false); // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 // rrrrrrrrrrCCCCCCCCCCCCCCCCCCCC..................... @@ -1519,7 +1562,8 @@ TEST_VM_F(NMTVMATreeTest, OverlapTableRows8to11) { {-1 , -1 , -1 } }; create_tree(tree, pre, __LINE__); - VMATree::SummaryDiff diff = tree.commit_mapping(0, 20, rd_Test_cs2, false); + VMATree::SummaryDiff diff; + tree.commit_mapping(0, 20, rd_Test_cs2, diff, false); // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 // CCCCCCCCCCCCCCCCCCCC............................... @@ -1546,7 +1590,8 @@ TEST_VM_F(NMTVMATreeTest, OverlapTableRows8to11) { {-1 , -1 , -1 , -1 , -1 , -1 , -1 } }; create_tree(tree, pre, __LINE__); - VMATree::SummaryDiff diff = tree.commit_mapping(5, 20, rd_Test_cs2, false); + VMATree::SummaryDiff diff; + tree.commit_mapping(5, 20, rd_Test_cs2, diff, false); // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 // .....CCCCCCCCCCCCCCCCCCCC.......................... @@ -1573,7 +1618,8 @@ TEST_VM_F(NMTVMATreeTest, OverlapTableRows8to11) { {-1 , -1 , -1 , -1 , -1 , -1 , -1 } }; create_tree(tree, pre, __LINE__); - VMATree::SummaryDiff diff = tree.commit_mapping(5, 15, rd_Test_cs2, false); + VMATree::SummaryDiff diff; + tree.commit_mapping(5, 15, rd_Test_cs2, diff, false); // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 // .....CCCCCCCCCCCCCCC............................... @@ -1619,7 +1665,8 @@ TEST_VM_F(NMTVMATreeTest, OverlapTableRows12to15) { {-1 , -1 , -1 } }; create_tree(tree, pre, __LINE__); - VMATree::SummaryDiff diff = tree.commit_mapping(5, 20, rd_Test_cs2, false); + VMATree::SummaryDiff diff; + tree.commit_mapping(5, 20, rd_Test_cs2, diff, false); // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 // .....CCCCCCCCCCCCCCCCCCCC.....rrrrrrrrrr........... @@ -1646,7 +1693,8 @@ TEST_VM_F(NMTVMATreeTest, OverlapTableRows12to15) { {-1 , -1 , -1 } }; create_tree(tree, pre, __LINE__); - VMATree::SummaryDiff diff = tree.commit_mapping(5, 20, rd_Test_cs2, false); + VMATree::SummaryDiff diff; + tree.commit_mapping(5, 20, rd_Test_cs2, diff, false); // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 // .....CCCCCCCCCCCCCCCCCCCCrrrrr..................... @@ -1673,7 +1721,8 @@ TEST_VM_F(NMTVMATreeTest, OverlapTableRows12to15) { {-1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 } }; create_tree(tree, pre, __LINE__); - VMATree::SummaryDiff diff = tree.commit_mapping(5, 20, rd_Test_cs2, false); + VMATree::SummaryDiff diff; + tree.commit_mapping(5, 20, rd_Test_cs2, diff, false); // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 // .....CCCCCCCCCCCCCCCCCCCC.....rrrrrrrrrr........... @@ -1700,7 +1749,8 @@ TEST_VM_F(NMTVMATreeTest, OverlapTableRows12to15) { {-1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 } }; create_tree(tree, pre, __LINE__); - VMATree::SummaryDiff diff = tree.commit_mapping(5, 15, rd_Test_cs2, false); + VMATree::SummaryDiff diff ; + tree.commit_mapping(5, 15, rd_Test_cs2, diff, false); // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 // .....CCCCCCCCCCCCCCC..........rrrrrrrrrr........... @@ -1745,7 +1795,8 @@ TEST_VM_F(NMTVMATreeTest, OverlapTableRows16to19) { {-1 , -1 , -1 , -1 , -1 } }; create_tree(tree, pre, __LINE__); - VMATree::SummaryDiff diff = tree.commit_mapping(15, 10, rd_Test_cs2, false); + VMATree::SummaryDiff diff; + tree.commit_mapping(15, 10, rd_Test_cs2, diff, false); // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 // rrrrrrrrrr.....CCCCCCCCCC.....rrrrrrrrrr........... @@ -1772,7 +1823,8 @@ TEST_VM_F(NMTVMATreeTest, OverlapTableRows16to19) { {-1 , -1 , -1 , -1 , -1 } }; create_tree(tree, pre, __LINE__); - VMATree::SummaryDiff diff = tree.commit_mapping(15, 10, rd_Test_cs2, false); + VMATree::SummaryDiff diff; + tree.commit_mapping(15, 10, rd_Test_cs2, diff, false); // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 // rrrrrrrrrr.....CCCCCCCCCCrrrrr..................... @@ -1799,7 +1851,8 @@ TEST_VM_F(NMTVMATreeTest, OverlapTableRows16to19) { {-1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 } }; create_tree(tree, pre, __LINE__); - VMATree::SummaryDiff diff = tree.commit_mapping(7, 20, rd_Test_cs2, false); + VMATree::SummaryDiff diff; + tree.commit_mapping(7, 20, rd_Test_cs2, diff, false); // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 // rrrrr..CCCCCCCCCCCCCCCCCCCC...rrrrrrrrrr........... @@ -1826,7 +1879,8 @@ TEST_VM_F(NMTVMATreeTest, OverlapTableRows16to19) { {-1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 } }; create_tree(tree, pre, __LINE__); - VMATree::SummaryDiff diff = tree.commit_mapping(7, 13, rd_Test_cs2, false); + VMATree::SummaryDiff diff; + tree.commit_mapping(7, 13, rd_Test_cs2, diff, false); // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 // rrrrr..CCCCCCCCCCCCC..........rrrrrrrrrr........... @@ -1872,7 +1926,8 @@ TEST_VM_F(NMTVMATreeTest, OverlapTableRows20to23) { {-1 , -1 , -1 , -1 , -1 } }; create_tree(tree, pre, __LINE__); - VMATree::SummaryDiff diff = tree.commit_mapping(10, 15, rd_Test_cs2, false); + VMATree::SummaryDiff diff; + tree.commit_mapping(10, 15, rd_Test_cs2, diff, false); // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 // rrrrrrrrrrCCCCCCCCCCCCCCC.....rrrrrrrrrr........... @@ -1899,7 +1954,8 @@ TEST_VM_F(NMTVMATreeTest, OverlapTableRows20to23) { {-1 , -1 , -1 , -1 , -1 } }; create_tree(tree, pre, __LINE__); - VMATree::SummaryDiff diff = tree.commit_mapping(10, 15, rd_Test_cs2, false); + VMATree::SummaryDiff diff; + tree.commit_mapping(10, 15, rd_Test_cs2, diff, false); // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 // rrrrrrrrrrCCCCCCCCCCCCCCCrrrrr..................... @@ -1926,7 +1982,8 @@ TEST_VM_F(NMTVMATreeTest, OverlapTableRows20to23) { {-1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 } }; create_tree(tree, pre, __LINE__); - VMATree::SummaryDiff diff = tree.commit_mapping(5, 20, rd_Test_cs2, false); + VMATree::SummaryDiff diff; + tree.commit_mapping(5, 20, rd_Test_cs2, diff, false); // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 // rrrrrCCCCCCCCCCCCCCCCCCCC.....rrrrrrrrrr........... @@ -1953,7 +2010,8 @@ TEST_VM_F(NMTVMATreeTest, OverlapTableRows20to23) { {-1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 } }; create_tree(tree, pre, __LINE__); - VMATree::SummaryDiff diff = tree.commit_mapping(5, 15, rd_Test_cs2, false); + VMATree::SummaryDiff diff; + tree.commit_mapping(5, 15, rd_Test_cs2, diff, false); // 1 2 3 4 5 // 012345678901234567890123456789012345678901234567890 // rrrrrCCCCCCCCCCCCCCC..........rrrrrrrrrr........... diff --git a/test/hotspot/gtest/runtime/test_os_linux.cpp b/test/hotspot/gtest/runtime/test_os_linux.cpp index 21133788a36..c8467784b0a 100644 --- a/test/hotspot/gtest/runtime/test_os_linux.cpp +++ b/test/hotspot/gtest/runtime/test_os_linux.cpp @@ -35,6 +35,7 @@ #include "unittest.hpp" #include +#include static bool using_explicit_hugepages() { return UseLargePages && !UseTransparentHugePages; } @@ -468,4 +469,27 @@ TEST_VM(os_linux, glibc_mallinfo_wrapper) { #endif // ADDRESS_SANITIZER #endif // __GLIBC__ +static void test_set_thread_name(const char* name, const char* expected) { + os::set_native_thread_name(name); + char buf[16]; + int rc = prctl(PR_GET_NAME, buf); + ASSERT_EQ(0, rc); + ASSERT_STREQ(buf, expected); +} + +TEST_VM(os_linux, set_thread_name) { + char buf[16]; + // retrieve current name + int rc = prctl(PR_GET_NAME, buf); + ASSERT_EQ(0, rc); + + test_set_thread_name("shortname", "shortname"); + test_set_thread_name("012345678901234", "012345678901234"); + test_set_thread_name("0123456789012345", "0123456..012345"); + test_set_thread_name("MyAllocationWorkerThread22", "MyAlloc..read22"); + + // restore current name + test_set_thread_name(buf, buf); +} + #endif // LINUX diff --git a/test/hotspot/gtest/runtime/test_virtualMemoryTracker.cpp b/test/hotspot/gtest/runtime/test_virtualMemoryTracker.cpp index 556b9876acc..4242302997a 100644 --- a/test/hotspot/gtest/runtime/test_virtualMemoryTracker.cpp +++ b/test/hotspot/gtest/runtime/test_virtualMemoryTracker.cpp @@ -94,6 +94,7 @@ class VirtualMemoryTrackerTest { RegionsTree* rtree = vmt.tree(); size_t size = 0x01000000; const address addr = (address)0x0000A000; + VMATree::SummaryDiff diff; vmt.add_reserved_region(addr, size, CALLER_PC, mtTest); @@ -115,45 +116,45 @@ class VirtualMemoryTrackerTest { // Commit adjacent regions with same stack { // Commit one region - rtree->commit_region(addr + cs, cs, stack); + rtree->commit_region(addr + cs, cs, stack, diff); R r[] = { {addr + cs, cs} }; check(vmt, rmr, r); } { // Commit adjacent - lower address - rtree->commit_region(addr, cs, stack); + rtree->commit_region(addr, cs, stack, diff); R r[] = { {addr, 2 * cs} }; check(vmt, rmr, r); } { // Commit adjacent - higher address - rtree->commit_region(addr + 2 * cs, cs, stack); + rtree->commit_region(addr + 2 * cs, cs, stack, diff); R r[] = { {addr, 3 * cs} }; check(vmt,rmr, r); } // Cleanup - rtree->uncommit_region(addr, 3 * cs); + rtree->uncommit_region(addr, 3 * cs, diff); ASSERT_EQ(vmt.committed_size(&rmr), 0u); // Commit adjacent regions with different stacks { // Commit one region - rtree->commit_region(addr + cs, cs, stack); + rtree->commit_region(addr + cs, cs, stack, diff); R r[] = { {addr + cs, cs} }; check(vmt, rmr, r); } { // Commit adjacent - lower address - rtree->commit_region(addr, cs, stack2); + rtree->commit_region(addr, cs, stack2, diff); R r[] = { {addr, cs}, {addr + cs, cs} }; check(vmt, rmr, r); } { // Commit adjacent - higher address - rtree->commit_region(addr + 2 * cs, cs, stack2); + rtree->commit_region(addr + 2 * cs, cs, stack2, diff); R r[] = { {addr, cs}, {addr + cs, cs}, {addr + 2 * cs, cs} }; @@ -161,12 +162,13 @@ class VirtualMemoryTrackerTest { } // Cleanup - rtree->uncommit_region(addr, 3 * cs); + rtree->uncommit_region(addr, 3 * cs, diff); ASSERT_EQ(vmt.committed_size(&rmr), 0u); } static void test_add_committed_region_adjacent_overlapping() { VirtualMemoryTracker vmt(true); + VMATree::SummaryDiff diff; RegionsTree* rtree = vmt.tree(); size_t size = 0x01000000; const address addr = (address)0x0000A000; @@ -190,46 +192,46 @@ class VirtualMemoryTrackerTest { // Commit adjacent and overlapping regions with same stack { // Commit two non-adjacent regions - rtree->commit_region(addr, 2 * cs, stack); - rtree->commit_region(addr + 3 * cs, 2 * cs, stack); + rtree->commit_region(addr, 2 * cs, stack, diff); + rtree->commit_region(addr + 3 * cs, 2 * cs, stack, diff); R r[] = { {addr, 2 * cs}, {addr + 3 * cs, 2 * cs} }; check(vmt, rmr, r); } { // Commit adjacent and overlapping - rtree->commit_region(addr + 2 * cs, 2 * cs, stack); + rtree->commit_region(addr + 2 * cs, 2 * cs, stack, diff); R r[] = { {addr, 5 * cs} }; check(vmt, rmr, r); } // revert to two non-adjacent regions - rtree->uncommit_region(addr + 2 * cs, cs); + rtree->uncommit_region(addr + 2 * cs, cs, diff); ASSERT_EQ(vmt.committed_size(&rmr), 4 * cs); { // Commit overlapping and adjacent - rtree->commit_region(addr + cs, 2 * cs, stack); + rtree->commit_region(addr + cs, 2 * cs, stack, diff); R r[] = { {addr, 5 * cs} }; check(vmt, rmr, r); } // Cleanup - rtree->uncommit_region(addr, 5 * cs); + rtree->uncommit_region(addr, 5 * cs, diff); ASSERT_EQ(vmt.committed_size(&rmr), 0u); // Commit adjacent and overlapping regions with different stacks { // Commit two non-adjacent regions - rtree->commit_region(addr, 2 * cs, stack); - rtree->commit_region(addr + 3 * cs, 2 * cs, stack); + rtree->commit_region(addr, 2 * cs, stack, diff); + rtree->commit_region(addr + 3 * cs, 2 * cs, stack, diff); R r[] = { {addr, 2 * cs}, {addr + 3 * cs, 2 * cs} }; check(vmt, rmr, r); } { // Commit adjacent and overlapping - rtree->commit_region(addr + 2 * cs, 2 * cs, stack2); + rtree->commit_region(addr + 2 * cs, 2 * cs, stack2, diff); R r[] = { {addr, 2 * cs}, {addr + 2 * cs, 2 * cs}, {addr + 4 * cs, cs} }; @@ -237,12 +239,12 @@ class VirtualMemoryTrackerTest { } // revert to two non-adjacent regions - rtree->commit_region(addr, 5 * cs, stack); - rtree->uncommit_region(addr + 2 * cs, cs); + rtree->commit_region(addr, 5 * cs, stack, diff); + rtree->uncommit_region(addr + 2 * cs, cs, diff); ASSERT_EQ(vmt.committed_size(&rmr), 4 * cs); { // Commit overlapping and adjacent - rtree->commit_region(addr + cs, 2 * cs, stack2); + rtree->commit_region(addr + cs, 2 * cs, stack2, diff); R r[] = { {addr, cs}, {addr + cs, 2 * cs}, {addr + 3 * cs, 2 * cs} }; @@ -254,6 +256,7 @@ class VirtualMemoryTrackerTest { static void test_add_committed_region_overlapping() { VirtualMemoryTracker vmt(true); + VMATree::SummaryDiff diff; RegionsTree* rtree = vmt.tree(); size_t size = 0x01000000; const address addr = (address)0x0000A000; @@ -279,77 +282,77 @@ class VirtualMemoryTrackerTest { // With same stack { // Commit one region - rtree->commit_region(addr, cs, stack); + rtree->commit_region(addr, cs, stack, diff); R r[] = { {addr, cs} }; check(vmt, rmr, r); } { // Commit the same region - rtree->commit_region(addr, cs, stack); + rtree->commit_region(addr, cs, stack, diff); R r[] = { {addr, cs} }; check(vmt, rmr, r); } { // Commit a succeeding region - rtree->commit_region(addr + cs, cs, stack); + rtree->commit_region(addr + cs, cs, stack, diff); R r[] = { {addr, 2 * cs} }; check(vmt, rmr, r); } { // Commit over two regions - rtree->commit_region(addr, 2 * cs, stack); + rtree->commit_region(addr, 2 * cs, stack, diff); R r[] = { {addr, 2 * cs} }; check(vmt, rmr, r); } {// Commit first part of a region - rtree->commit_region(addr, cs, stack); + rtree->commit_region(addr, cs, stack, diff); R r[] = { {addr, 2 * cs} }; check(vmt, rmr, r); } { // Commit second part of a region - rtree->commit_region(addr + cs, cs, stack); + rtree->commit_region(addr + cs, cs, stack, diff); R r[] = { {addr, 2 * cs} }; check(vmt, rmr, r); } { // Commit a third part - rtree->commit_region(addr + 2 * cs, cs, stack); + rtree->commit_region(addr + 2 * cs, cs, stack, diff); R r[] = { {addr, 3 * cs} }; check(vmt, rmr, r); } { // Commit in the middle of a region - rtree->commit_region(addr + 1 * cs, cs, stack); + rtree->commit_region(addr + 1 * cs, cs, stack, diff); R r[] = { {addr, 3 * cs} }; check(vmt, rmr, r); } // Cleanup - rtree->uncommit_region(addr, 3 * cs); + rtree->uncommit_region(addr, 3 * cs, diff); ASSERT_EQ(vmt.committed_size(&rmr), 0u); // With preceding region - rtree->commit_region(addr, cs, stack); - rtree->commit_region(addr + 2 * cs, 3 * cs, stack); + rtree->commit_region(addr, cs, stack, diff); + rtree->commit_region(addr + 2 * cs, 3 * cs, stack, diff); - rtree->commit_region(addr + 2 * cs, cs, stack); + rtree->commit_region(addr + 2 * cs, cs, stack, diff); { R r[] = { {addr, cs}, {addr + 2 * cs, 3 * cs} }; check(vmt, rmr, r); } - rtree->commit_region(addr + 3 * cs, cs, stack); + rtree->commit_region(addr + 3 * cs, cs, stack, diff); { R r[] = { {addr, cs}, {addr + 2 * cs, 3 * cs} }; check(vmt, rmr, r); } - rtree->commit_region(addr + 4 * cs, cs, stack); + rtree->commit_region(addr + 4 * cs, cs, stack, diff); { R r[] = { {addr, cs}, {addr + 2 * cs, 3 * cs} }; @@ -357,57 +360,57 @@ class VirtualMemoryTrackerTest { } // Cleanup - rtree->uncommit_region(addr, 5 * cs); + rtree->uncommit_region(addr, 5 * cs, diff); ASSERT_EQ(vmt.committed_size(&rmr), 0u); // With different stacks { // Commit one region - rtree->commit_region(addr, cs, stack); + rtree->commit_region(addr, cs, stack, diff); R r[] = { {addr, cs} }; check(vmt, rmr, r); } { // Commit the same region - rtree->commit_region(addr, cs, stack2); + rtree->commit_region(addr, cs, stack2, diff); R r[] = { {addr, cs} }; check(vmt, rmr, r); } { // Commit a succeeding region - rtree->commit_region(addr + cs, cs, stack); + rtree->commit_region(addr + cs, cs, stack, diff); R r[] = { {addr, cs}, {addr + cs, cs} }; check(vmt, rmr, r); } { // Commit over two regions - rtree->commit_region(addr, 2 * cs, stack); + rtree->commit_region(addr, 2 * cs, stack, diff); R r[] = { {addr, 2 * cs} }; check(vmt, rmr, r); } {// Commit first part of a region - rtree->commit_region(addr, cs, stack2); + rtree->commit_region(addr, cs, stack2, diff); R r[] = { {addr, cs}, {addr + cs, cs} }; check(vmt, rmr, r); } { // Commit second part of a region - rtree->commit_region(addr + cs, cs, stack2); + rtree->commit_region(addr + cs, cs, stack2, diff); R r[] = { {addr, 2 * cs} }; check(vmt, rmr, r); } { // Commit a third part - rtree->commit_region(addr + 2 * cs, cs, stack2); + rtree->commit_region(addr + 2 * cs, cs, stack2, diff); R r[] = { {addr, 3 * cs} }; check(vmt, rmr, r); } { // Commit in the middle of a region - rtree->commit_region(addr + 1 * cs, cs, stack); + rtree->commit_region(addr + 1 * cs, cs, stack, diff); R r[] = { {addr, cs}, {addr + cs, cs}, {addr + 2 * cs, cs} }; @@ -430,6 +433,7 @@ class VirtualMemoryTrackerTest { static void test_remove_uncommitted_region() { VirtualMemoryTracker vmt(true); + VMATree::SummaryDiff diff; RegionsTree* rtree = vmt.tree(); size_t size = 0x01000000; const address addr = (address)0x0000A000; @@ -451,105 +455,105 @@ class VirtualMemoryTrackerTest { const size_t cs = 0x1000; { // Commit regions - rtree->commit_region(addr, 3 * cs, stack); + rtree->commit_region(addr, 3 * cs, stack, diff); R r[] = { {addr, 3 * cs} }; check(vmt, rmr, r); // Remove only existing - rtree->uncommit_region(addr, 3 * cs); + rtree->uncommit_region(addr, 3 * cs, diff); check_empty(vmt, rmr); } { - rtree->commit_region(addr + 0 * cs, cs, stack); - rtree->commit_region(addr + 2 * cs, cs, stack); - rtree->commit_region(addr + 4 * cs, cs, stack); + rtree->commit_region(addr + 0 * cs, cs, stack, diff); + rtree->commit_region(addr + 2 * cs, cs, stack, diff); + rtree->commit_region(addr + 4 * cs, cs, stack, diff); { // Remove first - rtree->uncommit_region(addr, cs); + rtree->uncommit_region(addr, cs, diff); R r[] = { {addr + 2 * cs, cs}, {addr + 4 * cs, cs} }; check(vmt, rmr, r); } // add back - rtree->commit_region(addr, cs, stack); + rtree->commit_region(addr, cs, stack, diff); { // Remove middle - rtree->uncommit_region(addr + 2 * cs, cs); + rtree->uncommit_region(addr + 2 * cs, cs, diff); R r[] = { {addr + 0 * cs, cs}, {addr + 4 * cs, cs} }; check(vmt, rmr, r); } // add back - rtree->commit_region(addr + 2 * cs, cs, stack); + rtree->commit_region(addr + 2 * cs, cs, stack, diff); { // Remove end - rtree->uncommit_region(addr + 4 * cs, cs); + rtree->uncommit_region(addr + 4 * cs, cs, diff); R r[] = { {addr + 0 * cs, cs}, {addr + 2 * cs, cs} }; check(vmt, rmr, r); } - rtree->uncommit_region(addr, 5 * cs); + rtree->uncommit_region(addr, 5 * cs, diff); check_empty(vmt, rmr); } { // Remove larger region - rtree->commit_region(addr + 1 * cs, cs, stack); - rtree->uncommit_region(addr, 3 * cs); + rtree->commit_region(addr + 1 * cs, cs, stack, diff); + rtree->uncommit_region(addr, 3 * cs, diff); check_empty(vmt, rmr); } { // Remove smaller region - in the middle - rtree->commit_region(addr, 3 * cs, stack); - rtree->uncommit_region(addr + 1 * cs, cs); + rtree->commit_region(addr, 3 * cs, stack, diff); + rtree->uncommit_region(addr + 1 * cs, cs, diff); R r[] = { { addr + 0 * cs, cs}, { addr + 2 * cs, cs} }; check(vmt, rmr, r); - rtree->uncommit_region(addr, 3 * cs); + rtree->uncommit_region(addr, 3 * cs, diff); check_empty(vmt, rmr); } { // Remove smaller region - at the beginning - rtree->commit_region(addr, 3 * cs, stack); - rtree->uncommit_region(addr + 0 * cs, cs); + rtree->commit_region(addr, 3 * cs, stack, diff); + rtree->uncommit_region(addr + 0 * cs, cs, diff); R r[] = { { addr + 1 * cs, 2 * cs} }; check(vmt, rmr, r); - rtree->uncommit_region(addr, 3 * cs); + rtree->uncommit_region(addr, 3 * cs, diff); check_empty(vmt, rmr); } { // Remove smaller region - at the end - rtree->commit_region(addr, 3 * cs, stack); - rtree->uncommit_region(addr + 2 * cs, cs); + rtree->commit_region(addr, 3 * cs, stack, diff); + rtree->uncommit_region(addr + 2 * cs, cs, diff); R r[] = { { addr, 2 * cs} }; check(vmt, rmr, r); - rtree->uncommit_region(addr, 3 * cs); + rtree->uncommit_region(addr, 3 * cs, diff); check_empty(vmt, rmr); } { // Remove smaller, overlapping region - at the beginning - rtree->commit_region(addr + 1 * cs, 4 * cs, stack); - rtree->uncommit_region(addr, 2 * cs); + rtree->commit_region(addr + 1 * cs, 4 * cs, stack, diff); + rtree->uncommit_region(addr, 2 * cs, diff); R r[] = { { addr + 2 * cs, 3 * cs} }; check(vmt, rmr, r); - rtree->uncommit_region(addr + 1 * cs, 4 * cs); + rtree->uncommit_region(addr + 1 * cs, 4 * cs, diff); check_empty(vmt, rmr); } { // Remove smaller, overlapping region - at the end - rtree->commit_region(addr, 3 * cs, stack); - rtree->uncommit_region(addr + 2 * cs, 2 * cs); + rtree->commit_region(addr, 3 * cs, stack, diff); + rtree->uncommit_region(addr + 2 * cs, 2 * cs, diff); R r[] = { { addr, 2 * cs} }; check(vmt, rmr, r); - rtree->uncommit_region(addr, 3 * cs); + rtree->uncommit_region(addr, 3 * cs, diff); check_empty(vmt, rmr); } diff --git a/test/hotspot/jtreg/ProblemList-Virtual.txt b/test/hotspot/jtreg/ProblemList-Virtual.txt index 4216eddb885..3c74d7bf816 100644 --- a/test/hotspot/jtreg/ProblemList-Virtual.txt +++ b/test/hotspot/jtreg/ProblemList-Virtual.txt @@ -25,7 +25,6 @@ # Bugs serviceability/AsyncGetCallTrace/MyPackage/ASGCTBaseTest.java 8308026 generic-all -serviceability/jvmti/GetThreadListStackTraces/OneGetThreadListStackTraces.java 8308027 generic-all serviceability/jvmti/Heap/IterateHeapWithEscapeAnalysisEnabled.java 8264699 generic-all vmTestbase/vm/mlvm/indy/func/jvmti/mergeCP_indy2manyDiff_a/TestDescription.java 8308367 generic-all diff --git a/test/hotspot/jtreg/compiler/ccp/TestModValueMonotonic.java b/test/hotspot/jtreg/compiler/ccp/TestModValueMonotonic.java new file mode 100644 index 00000000000..346b07c547e --- /dev/null +++ b/test/hotspot/jtreg/compiler/ccp/TestModValueMonotonic.java @@ -0,0 +1,66 @@ +/* + * 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 8367967 + * @summary Ensure ModI/LNode::Value is monotonic with potential division by 0 + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:CompileOnly=compiler.ccp.TestModValueMonotonic::test* + * -XX:+StressCCP -XX:RepeatCompilation=100 -Xcomp compiler.ccp.TestModValueMonotonic + * @run main compiler.ccp.TestModValueMonotonic + */ +package compiler.ccp; + +public class TestModValueMonotonic { + static int iFld; + static long lFld; + static int limit = 1000; + static boolean flag; + + public static void main(String[] args) { + testInt(); + testLong(); + } + + static void testInt() { + int zero = 0; + + // Make sure loop is not counted such that it is not removed. Created a more complex graph for CCP. + for (int i = 1; i < limit; i*=4) { + zero = 34; + } + int three = flag ? 0 : 3; + iFld = three % zero; // phi[0..3] % phi[0..34] + } + + static void testLong() { + long zero = 0; + + // Make sure loop is not counted such that it is not removed. Created a more complex graph for CCP. + for (int i = 1; i < limit; i*=4) { + zero = 34; + } + long three = flag ? 0 : 3; + lFld = three % zero; // phi[0..3] % phi[0..34] + } +} diff --git a/test/hotspot/jtreg/compiler/floatingpoint/ScalarFPtoIntCastTest.java b/test/hotspot/jtreg/compiler/floatingpoint/ScalarFPtoIntCastTest.java new file mode 100644 index 00000000000..e8575cfe6b6 --- /dev/null +++ b/test/hotspot/jtreg/compiler/floatingpoint/ScalarFPtoIntCastTest.java @@ -0,0 +1,215 @@ +/* + * 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 8364305 +* @summary Test scalar float/double to integral cast +* @requires vm.compiler2.enabled +* @library /test/lib / +* @run main/othervm/native compiler.floatingpoint.ScalarFPtoIntCastTest +*/ + +package compiler.floatingpoint; + +import compiler.lib.ir_framework.*; +import compiler.lib.generators.Generator; +import static compiler.lib.generators.Generators.G; +import compiler.lib.verify.Verify; + +public class ScalarFPtoIntCastTest { + private static final int COUNT = 16; + + private float[] float_arr; + private double[] double_arr; + private long[] long_float_arr; + private long[] long_double_arr; + private int[] int_float_arr; + private int[] int_double_arr; + private short[] short_float_arr; + private short[] short_double_arr; + private byte[] byte_float_arr; + private byte[] byte_double_arr; + + private static final Generator genF = G.floats(); + private static final Generator genD = G.doubles(); + + public static void main(String[] args) { + TestFramework testFramework = new TestFramework(); + testFramework.start(); + } + + public ScalarFPtoIntCastTest() { + long_float_arr = new long[COUNT]; + long_double_arr = new long[COUNT]; + int_float_arr = new int[COUNT]; + int_double_arr = new int[COUNT]; + short_float_arr = new short[COUNT]; + short_double_arr = new short[COUNT]; + byte_float_arr = new byte[COUNT]; + byte_double_arr = new byte[COUNT]; + float_arr = new float[COUNT]; + double_arr = new double[COUNT]; + + G.fill(genF, float_arr); + G.fill(genD, double_arr); + for (int i = 0; i < COUNT; i++) { + long_float_arr[i] = (long) float_arr[i]; + long_double_arr[i] = (long) double_arr[i]; + int_float_arr[i] = (int) float_arr[i]; + int_double_arr[i] = (int) double_arr[i]; + short_float_arr[i] = (short) float_arr[i]; + short_double_arr[i] = (short) double_arr[i]; + byte_float_arr[i] = (byte) float_arr[i]; + byte_double_arr[i] = (byte) double_arr[i]; + } + } + + @Test + @IR(counts = {IRNode.CONV_F2I, "> 0"}) + @IR(counts = {IRNode.X86_SCONV_F2I, "> 0"}, + applyIfPlatform = {"x64", "true"}, + applyIfCPUFeature = {"avx10_2", "false"}) + @IR(counts = {IRNode.X86_SCONV_F2I_AVX10, "> 0"}, + applyIfCPUFeature = {"avx10_2", "true"}) + public void float2int() { + for (int i = 0; i < COUNT; i++) { + float float_val = float_arr[i]; + int computed = (int) float_val; + int expected = int_float_arr[i]; + Verify.checkEQ(computed, expected); + } + } + + @Test + @IR(counts = {IRNode.CONV_F2L, "> 0"}) + @IR(counts = {IRNode.X86_SCONV_F2L, "> 0"}, + applyIfPlatform = {"x64", "true"}, + applyIfCPUFeature = {"avx10_2", "false"}) + @IR(counts = {IRNode.X86_SCONV_F2L_AVX10, "> 0"}, + applyIfCPUFeature = {"avx10_2", "true"}) + public void float2long() { + for (int i = 0; i < COUNT; i++) { + float float_val = float_arr[i]; + long computed = (long) float_val; + long expected = long_float_arr[i]; + Verify.checkEQ(computed, expected); + } + } + + @Test + @IR(counts = {IRNode.CONV_F2I, "> 0"}) + @IR(counts = {IRNode.X86_SCONV_F2I, "> 0"}, + applyIfPlatform = {"x64", "true"}, + applyIfCPUFeature = {"avx10_2", "false"}) + @IR(counts = {IRNode.X86_SCONV_F2I_AVX10, "> 0"}, + applyIfCPUFeature = {"avx10_2", "true"}) + public void float2short() { + for (int i = 0; i < COUNT; i++) { + float float_val = float_arr[i]; + short computed = (short) float_val; + short expected = short_float_arr[i]; + Verify.checkEQ(computed, expected); + } + } + + @Test + @IR(counts = {IRNode.CONV_F2I, "> 0"}) + @IR(counts = {IRNode.X86_SCONV_F2I, "> 0"}, + applyIfPlatform = {"x64", "true"}, + applyIfCPUFeature = {"avx10_2", "false"}) + @IR(counts = {IRNode.X86_SCONV_F2I_AVX10, "> 0"}, + applyIfCPUFeature = {"avx10_2", "true"}) + public void float2byte() { + for (int i = 0; i < COUNT; i++) { + float float_val = float_arr[i]; + byte computed = (byte) float_val; + byte expected = byte_float_arr[i]; + Verify.checkEQ(computed, expected); + } + } + + @Test + @IR(counts = {IRNode.CONV_D2I, "> 0"}) + @IR(counts = {IRNode.X86_SCONV_D2I, "> 0"}, + applyIfPlatform = {"x64", "true"}, + applyIfCPUFeature = {"avx10_2", "false"}) + @IR(counts = {IRNode.X86_SCONV_D2I_AVX10, "> 0"}, + applyIfCPUFeature = {"avx10_2", "true"}) + public void double2int() { + for (int i = 0; i < COUNT; i++) { + double double_val = double_arr[i]; + int computed = (int) double_val; + int expected = int_double_arr[i]; + Verify.checkEQ(computed, expected); + } + } + + @Test + @IR(counts = {IRNode.CONV_D2L, "> 0"}) + @IR(counts = {IRNode.X86_SCONV_D2L, "> 0"}, + applyIfPlatform = {"x64", "true"}, + applyIfCPUFeature = {"avx10_2", "false"}) + @IR(counts = {IRNode.X86_SCONV_D2L_AVX10, "> 0"}, + applyIfCPUFeature = {"avx10_2", "true"}) + public void double2long() { + for (int i = 0; i < COUNT; i++) { + double double_val = double_arr[i]; + long computed = (long) double_val; + long expected = long_double_arr[i]; + Verify.checkEQ(computed, expected); + } + } + + @Test + @IR(counts = {IRNode.CONV_D2I, "> 0"}) + @IR(counts = {IRNode.X86_SCONV_D2I, "> 0"}, + applyIfPlatform = {"x64", "true"}, + applyIfCPUFeature = {"avx10_2", "false"}) + @IR(counts = {IRNode.X86_SCONV_D2I_AVX10, "> 0"}, + applyIfCPUFeature = {"avx10_2", "true"}) + public void double2short() { + for (int i = 0; i < COUNT; i++) { + double double_val = double_arr[i]; + short computed = (short) double_val; + short expected = short_double_arr[i]; + Verify.checkEQ(computed, expected); + } + } + + @Test + @IR(counts = {IRNode.CONV_D2I, "> 0"}) + @IR(counts = {IRNode.X86_SCONV_D2I, "> 0"}, + applyIfPlatform = {"x64", "true"}, + applyIfCPUFeature = {"avx10_2", "false"}) + @IR(counts = {IRNode.X86_SCONV_D2I_AVX10, "> 0"}, + applyIfCPUFeature = {"avx10_2", "true"}) + public void double2byte() { + for (int i = 0; i < COUNT; i++) { + double double_val = double_arr[i]; + byte computed = (byte) double_val; + byte expected = byte_double_arr[i]; + Verify.checkEQ(computed, expected); + } + } +} diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java index 88b34841e57..15378feb841 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java @@ -610,11 +610,31 @@ public class IRNode { beforeMatchingNameRegex(CONV, "Conv"); } + public static final String CONV_D2I = PREFIX + "CONV_D2I" + POSTFIX; + static { + beforeMatchingNameRegex(CONV_D2I, "ConvD2I"); + } + + public static final String CONV_D2L = PREFIX + "CONV_D2L" + POSTFIX; + static { + beforeMatchingNameRegex(CONV_D2L, "ConvD2L"); + } + public static final String CONV_F2HF = PREFIX + "CONV_F2HF" + POSTFIX; static { beforeMatchingNameRegex(CONV_F2HF, "ConvF2HF"); } + public static final String CONV_F2I = PREFIX + "CONV_F2I" + POSTFIX; + static { + beforeMatchingNameRegex(CONV_F2I, "ConvF2I"); + } + + public static final String CONV_F2L = PREFIX + "CONV_F2L" + POSTFIX; + static { + beforeMatchingNameRegex(CONV_F2L, "ConvF2L"); + } + public static final String CONV_I2L = PREFIX + "CONV_I2L" + POSTFIX; static { beforeMatchingNameRegex(CONV_I2L, "ConvI2L"); @@ -2675,6 +2695,66 @@ public class IRNode { machOnlyNameRegex(VSTOREMASK_TRUECOUNT, "vstoremask_truecount_neon"); } + public static final String X86_SCONV_D2I = PREFIX + "X86_SCONV_D2I" + POSTFIX; + static { + machOnlyNameRegex(X86_SCONV_D2I, "convD2I_reg_reg"); + } + + public static final String X86_SCONV_D2L = PREFIX + "X86_SCONV_D2L" + POSTFIX; + static { + machOnlyNameRegex(X86_SCONV_D2L, "convD2L_reg_reg"); + } + + public static final String X86_SCONV_F2I = PREFIX + "X86_SCONV_F2I" + POSTFIX; + static { + machOnlyNameRegex(X86_SCONV_F2I, "convF2I_reg_reg"); + } + + public static final String X86_SCONV_F2L = PREFIX + "X86_SCONV_F2L" + POSTFIX; + static { + machOnlyNameRegex(X86_SCONV_F2L, "convF2L_reg_reg"); + } + + public static final String X86_SCONV_D2I_AVX10 = PREFIX + "X86_SCONV2_D2I_AVX10" + POSTFIX; + static { + machOnlyNameRegex(X86_SCONV_D2I_AVX10, "convD2I_(reg_reg|reg_mem)_avx10"); + } + + public static final String X86_SCONV_D2L_AVX10 = PREFIX + "X86_SCONV_D2L_AVX10" + POSTFIX; + static { + machOnlyNameRegex(X86_SCONV_D2L_AVX10, "convD2L_(reg_reg|reg_mem)_avx10"); + } + + public static final String X86_SCONV_F2I_AVX10 = PREFIX + "X86_SCONV_F2I_AVX10" + POSTFIX; + static { + machOnlyNameRegex(X86_SCONV_F2I_AVX10, "convF2I_(reg_reg|reg_mem)_avx10"); + } + + public static final String X86_SCONV_F2L_AVX10 = PREFIX + "X86_SCONV_F2L_AVX10" + POSTFIX; + static { + machOnlyNameRegex(X86_SCONV_F2L_AVX10, "convF2L_(reg_reg|reg_mem)_avx10"); + } + + public static final String X86_VCAST_F2X = PREFIX + "X86_VCAST_F2X" + POSTFIX; + static { + machOnlyNameRegex(X86_VCAST_F2X, "castFtoX_reg_(av|eve)x"); + } + + public static final String X86_VCAST_D2X = PREFIX + "X86_VCAST_D2X" + POSTFIX; + static { + machOnlyNameRegex(X86_VCAST_D2X, "castDtoX_reg_(av|eve)x"); + } + + public static final String X86_VCAST_F2X_AVX10 = PREFIX + "X86_VCAST_F2X_AVX10" + POSTFIX; + static { + machOnlyNameRegex(X86_VCAST_F2X_AVX10, "castFtoX_(reg|mem)_avx10"); + } + + public static final String X86_VCAST_D2X_AVX10 = PREFIX + "X86_VCAST_D2X_AVX10" + POSTFIX; + static { + machOnlyNameRegex(X86_VCAST_D2X_AVX10, "castDtoX_(reg|mem)_avx10"); + } + public static final String XOR = PREFIX + "XOR" + POSTFIX; static { beforeMatchingNameRegex(XOR, "Xor(I|L)"); diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/test/IREncodingPrinter.java b/test/hotspot/jtreg/compiler/lib/ir_framework/test/IREncodingPrinter.java index 16b4654013a..c05124edcd7 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/test/IREncodingPrinter.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/test/IREncodingPrinter.java @@ -106,6 +106,7 @@ public class IREncodingPrinter { "avx512_fp16", "avx512_vnni", "avx512_vbmi", + "avx10_2", "bmi2", // AArch64 "sha3", diff --git a/test/hotspot/jtreg/compiler/vectorapi/VectorFPtoIntCastTest.java b/test/hotspot/jtreg/compiler/vectorapi/VectorFPtoIntCastTest.java index 8d5d872375f..1037a2989f9 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/VectorFPtoIntCastTest.java +++ b/test/hotspot/jtreg/compiler/vectorapi/VectorFPtoIntCastTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 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 @@ -23,8 +23,8 @@ /** * @test -* @bug 8287835 -* @summary Test float/double to integral cast +* @bug 8287835 8364305 +* @summary Test vector float/double to integral cast * @modules jdk.incubator.vector * @requires vm.compiler2.enabled * @library /test/lib / @@ -87,7 +87,11 @@ public VectorFPtoIntCastTest() { @Test @IR(counts = {IRNode.VECTOR_CAST_F2I, IRNode.VECTOR_SIZE_16, "> 0"}, - applyIfCPUFeature = {"avx512f", "true"}) + applyIfCPUFeatureOr = {"avx512f", "true", "avx10_2", "true"}) + @IR(counts = {IRNode.X86_VCAST_F2X, "> 0"}, + applyIfCPUFeatureAnd = {"avx512f", "true", "avx10_2", "false"}) + @IR(counts = {IRNode.X86_VCAST_F2X_AVX10, "> 0"}, + applyIfCPUFeature = {"avx10_2", "true"}) public void float2int() { var cvec = (IntVector)fvec512.convertShape(VectorOperators.F2I, ispec512, 0); cvec.intoArray(int_arr, 0); @@ -96,7 +100,7 @@ public void float2int() { public void checkf2int(int len) { for (int i = 0; i < len; i++) { - int expected = (int)float_arr[i]; + int expected = (int) float_arr[i]; if (int_arr[i] != expected) { throw new RuntimeException("Invalid result: int_arr[" + i + "] = " + int_arr[i] + " != " + expected); } @@ -105,7 +109,11 @@ public void checkf2int(int len) { @Test @IR(counts = {IRNode.VECTOR_CAST_F2L, IRNode.VECTOR_SIZE_8, "> 0"}, - applyIfCPUFeature = {"avx512dq", "true"}) + applyIfCPUFeatureOr = {"avx512dq", "true", "avx10_2", "true"}) + @IR(counts = {IRNode.X86_VCAST_F2X, "> 0"}, + applyIfCPUFeatureAnd = {"avx512dq", "true", "avx10_2", "false"}) + @IR(counts = {IRNode.X86_VCAST_F2X_AVX10, "> 0"}, + applyIfCPUFeature = {"avx10_2", "true"}) public void float2long() { var cvec = (LongVector)fvec512.convertShape(VectorOperators.F2L, lspec512, 0); cvec.intoArray(long_arr, 0); @@ -114,7 +122,7 @@ public void float2long() { public void checkf2long(int len) { for (int i = 0; i < len; i++) { - long expected = (long)float_arr[i]; + long expected = (long) float_arr[i]; if (long_arr[i] != expected) { throw new RuntimeException("Invalid result: long_arr[" + i + "] = " + long_arr[i] + " != " + expected); } @@ -123,7 +131,11 @@ public void checkf2long(int len) { @Test @IR(counts = {IRNode.VECTOR_CAST_F2S, IRNode.VECTOR_SIZE_16, "> 0"}, - applyIfCPUFeature = {"avx512f", "true"}) + applyIfCPUFeatureOr = {"avx512f", "true", "avx10_2", "true"}) + @IR(counts = {IRNode.X86_VCAST_F2X, "> 0"}, + applyIfCPUFeatureAnd = {"avx512f", "true", "avx10_2", "false"}) + @IR(counts = {IRNode.X86_VCAST_F2X_AVX10, "> 0"}, + applyIfCPUFeature = {"avx10_2", "true"}) public void float2short() { var cvec = (ShortVector)fvec512.convertShape(VectorOperators.F2S, sspec256, 0); cvec.intoArray(short_arr, 0); @@ -132,7 +144,7 @@ public void float2short() { public void checkf2short(int len) { for (int i = 0; i < len; i++) { - short expected = (short)float_arr[i]; + short expected = (short) float_arr[i]; if (short_arr[i] != expected) { throw new RuntimeException("Invalid result: short_arr[" + i + "] = " + short_arr[i] + " != " + expected); } @@ -141,7 +153,11 @@ public void checkf2short(int len) { @Test @IR(counts = {IRNode.VECTOR_CAST_F2B, IRNode.VECTOR_SIZE_16, "> 0"}, - applyIfCPUFeature = {"avx512f", "true"}) + applyIfCPUFeatureOr = {"avx512f", "true", "avx10_2", "true"}) + @IR(counts = {IRNode.X86_VCAST_F2X, "> 0"}, + applyIfCPUFeatureAnd = {"avx512f", "true", "avx10_2", "false"}) + @IR(counts = {IRNode.X86_VCAST_F2X_AVX10, "> 0"}, + applyIfCPUFeature = {"avx10_2", "true"}) public void float2byte() { var cvec = (ByteVector)fvec512.convertShape(VectorOperators.F2B, bspec128, 0); cvec.intoArray(byte_arr, 0); @@ -150,7 +166,7 @@ public void float2byte() { public void checkf2byte(int len) { for (int i = 0; i < len; i++) { - byte expected = (byte)float_arr[i]; + byte expected = (byte) float_arr[i]; if (byte_arr[i] != expected) { throw new RuntimeException("Invalid result: byte_arr[" + i + "] = " + byte_arr[i] + " != " + expected); } @@ -159,7 +175,11 @@ public void checkf2byte(int len) { @Test @IR(counts = {IRNode.VECTOR_CAST_D2I, IRNode.VECTOR_SIZE_8, "> 0"}, - applyIfCPUFeature = {"avx512f", "true"}) + applyIfCPUFeatureOr = {"avx512f", "true", "avx10_2", "true"}) + @IR(counts = {IRNode.X86_VCAST_D2X, "> 0"}, + applyIfCPUFeatureAnd = {"avx512f", "true", "avx10_2", "false"}) + @IR(counts = {IRNode.X86_VCAST_D2X_AVX10, "> 0"}, + applyIfCPUFeature = {"avx10_2", "true"}) public void double2int() { var cvec = (IntVector)dvec512.convertShape(VectorOperators.D2I, ispec256, 0); cvec.intoArray(int_arr, 0); @@ -168,7 +188,7 @@ public void double2int() { public void checkd2int(int len) { for (int i = 0; i < len; i++) { - int expected = (int)double_arr[i]; + int expected = (int) double_arr[i]; if (int_arr[i] != expected) { throw new RuntimeException("Invalid result: int_arr[" + i + "] = " + int_arr[i] + " != " + expected); } @@ -177,7 +197,11 @@ public void checkd2int(int len) { @Test @IR(counts = {IRNode.VECTOR_CAST_D2L, IRNode.VECTOR_SIZE_8, "> 0"}, - applyIfCPUFeature = {"avx512dq", "true"}) + applyIfCPUFeatureOr = {"avx512dq", "true", "avx10_2", "true"}) + @IR(counts = {IRNode.X86_VCAST_D2X, "> 0"}, + applyIfCPUFeatureAnd = {"avx512dq", "true", "avx10_2", "false"}) + @IR(counts = {IRNode.X86_VCAST_D2X_AVX10, "> 0"}, + applyIfCPUFeature = {"avx10_2", "true"}) public void double2long() { var cvec = (LongVector)dvec512.convertShape(VectorOperators.D2L, lspec512, 0); cvec.intoArray(long_arr, 0); @@ -186,7 +210,7 @@ public void double2long() { public void checkd2long(int len) { for (int i = 0; i < len; i++) { - long expected = (long)double_arr[i]; + long expected = (long) double_arr[i]; if (long_arr[i] != expected) { throw new RuntimeException("Invalid result: long_arr[" + i + "] = " + long_arr[i] + " != " + expected); } @@ -195,7 +219,11 @@ public void checkd2long(int len) { @Test @IR(counts = {IRNode.VECTOR_CAST_D2S, IRNode.VECTOR_SIZE_8, "> 0"}, - applyIfCPUFeature = {"avx512f", "true"}) + applyIfCPUFeatureOr = {"avx512f", "true", "avx10_2", "true"}) + @IR(counts = {IRNode.X86_VCAST_D2X, "> 0"}, + applyIfCPUFeatureAnd = {"avx512f", "true", "avx10_2", "false"}) + @IR(counts = {IRNode.X86_VCAST_D2X_AVX10, "> 0"}, + applyIfCPUFeature = {"avx10_2", "true"}) public void double2short() { var cvec = (ShortVector)dvec512.convertShape(VectorOperators.D2S, sspec128, 0); cvec.intoArray(short_arr, 0); @@ -204,7 +232,7 @@ public void double2short() { public void checkd2short(int len) { for (int i = 0; i < len; i++) { - short expected = (short)double_arr[i]; + short expected = (short) double_arr[i]; if (short_arr[i] != expected) { throw new RuntimeException("Invalid result: short_arr[" + i + "] = " + short_arr[i] + " != " + expected); } @@ -213,7 +241,11 @@ public void checkd2short(int len) { @Test @IR(counts = {IRNode.VECTOR_CAST_D2B, IRNode.VECTOR_SIZE_8, "> 0"}, - applyIfCPUFeature = {"avx512f", "true"}) + applyIfCPUFeatureOr = {"avx512f", "true", "avx10_2", "true"}) + @IR(counts = {IRNode.X86_VCAST_D2X, "> 0"}, + applyIfCPUFeatureAnd = {"avx512f", "true", "avx10_2", "false"}) + @IR(counts = {IRNode.X86_VCAST_D2X_AVX10, "> 0"}, + applyIfCPUFeature = {"avx10_2", "true"}) public void double2byte() { var cvec = (ByteVector)dvec512.convertShape(VectorOperators.D2B, bspec64, 0); cvec.intoArray(byte_arr, 0); @@ -222,7 +254,7 @@ public void double2byte() { public void checkd2byte(int len) { for (int i = 0; i < len; i++) { - byte expected = (byte)double_arr[i]; + byte expected = (byte) double_arr[i]; if (byte_arr[i] != expected) { throw new RuntimeException("Invalid result: byte_arr[" + i + "] = " + byte_arr[i] + " != " + expected); } diff --git a/test/hotspot/jtreg/compiler/vectorapi/VectorMaskCompareNotTest.java b/test/hotspot/jtreg/compiler/vectorapi/VectorMaskCompareNotTest.java index 851113ea4de..235093cceed 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/VectorMaskCompareNotTest.java +++ b/test/hotspot/jtreg/compiler/vectorapi/VectorMaskCompareNotTest.java @@ -35,6 +35,7 @@ * @library /test/lib / * @summary test combining vector not operation with compare * @modules jdk.incubator.vector + * @requires (os.arch != "riscv64" | (os.arch == "riscv64" & vm.cpu.features ~= ".*rvv.*")) * * @run driver compiler.vectorapi.VectorMaskCompareNotTest */ diff --git a/test/hotspot/jtreg/compiler/vectorization/runner/ArrayTypeConvertTest.java b/test/hotspot/jtreg/compiler/vectorization/runner/ArrayTypeConvertTest.java index 3fa636b42f7..4db973ff728 100644 --- a/test/hotspot/jtreg/compiler/vectorization/runner/ArrayTypeConvertTest.java +++ b/test/hotspot/jtreg/compiler/vectorization/runner/ArrayTypeConvertTest.java @@ -294,8 +294,12 @@ public double[] convertCharToDouble() { // ---------------- Convert F/D to I/L ---------------- @Test - @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx", "true", "rvv", "true"}, - counts = {IRNode.VECTOR_CAST_F2I, IRNode.VECTOR_SIZE + "min(max_float, max_int)", ">0"}) + @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx", "true", "avx10_2", "true", "rvv", "true"}, + counts = {IRNode.VECTOR_CAST_F2I, IRNode.VECTOR_SIZE + "min(max_float, max_int)", "> 0"}) + @IR(counts = {IRNode.X86_VCAST_F2X, "> 0"}, + applyIfCPUFeatureAnd = {"avx", "true", "avx10_2", "false"}) + @IR(counts = {IRNode.X86_VCAST_F2X_AVX10, "> 0"}, + applyIfCPUFeature = {"avx10_2", "true"}) public int[] convertFloatToInt() { int[] res = new int[SIZE]; for (int i = 0; i < SIZE; i++) { @@ -305,8 +309,12 @@ public int[] convertFloatToInt() { } @Test - @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx512dq", "true", "rvv", "true"}, - counts = {IRNode.VECTOR_CAST_F2L, IRNode.VECTOR_SIZE + "min(max_float, max_long)", ">0"}) + @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx512dq", "true", "avx10_2", "true", "rvv", "true"}, + counts = {IRNode.VECTOR_CAST_F2L, IRNode.VECTOR_SIZE + "min(max_float, max_long)", "> 0"}) + @IR(counts = {IRNode.X86_VCAST_F2X, "> 0"}, + applyIfCPUFeatureAnd = {"avx512dq", "true", "avx10_2", "false"}) + @IR(counts = {IRNode.X86_VCAST_F2X_AVX10, "> 0"}, + applyIfCPUFeature = {"avx10_2", "true"}) public long[] convertFloatToLong() { long[] res = new long[SIZE]; for (int i = 0; i < SIZE; i++) { @@ -316,8 +324,12 @@ public long[] convertFloatToLong() { } @Test - @IR(applyIfCPUFeatureOr = {"sve", "true", "avx", "true", "rvv", "true"}, - counts = {IRNode.VECTOR_CAST_D2I, IRNode.VECTOR_SIZE + "min(max_double, max_int)", ">0"}) + @IR(applyIfCPUFeatureOr = {"sve", "true", "avx", "true", "avx10_2", "true", "rvv", "true"}, + counts = {IRNode.VECTOR_CAST_D2I, IRNode.VECTOR_SIZE + "min(max_double, max_int)", "> 0"}) + @IR(counts = {IRNode.X86_VCAST_D2X, "> 0"}, + applyIfCPUFeatureAnd = {"avx", "true", "avx10_2", "false"}) + @IR(counts = {IRNode.X86_VCAST_D2X_AVX10, "> 0"}, + applyIfCPUFeature = {"avx10_2", "true"}) public int[] convertDoubleToInt() { int[] res = new int[SIZE]; for (int i = 0; i < SIZE; i++) { @@ -327,8 +339,12 @@ public int[] convertDoubleToInt() { } @Test - @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx512dq", "true", "rvv", "true"}, - counts = {IRNode.VECTOR_CAST_D2L, IRNode.VECTOR_SIZE + "min(max_double, max_long)", ">0"}) + @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx512dq", "true", "avx10_2", "true", "rvv", "true"}, + counts = {IRNode.VECTOR_CAST_D2L, IRNode.VECTOR_SIZE + "min(max_double, max_long)", "> 0"}) + @IR(counts = {IRNode.X86_VCAST_D2X, "> 0"}, + applyIfCPUFeatureAnd = {"avx512dq", "true", "avx10_2", "false"}) + @IR(counts = {IRNode.X86_VCAST_D2X_AVX10, "> 0"}, + applyIfCPUFeature = {"avx10_2", "true"}) public long[] convertDoubleToLong() { long[] res = new long[SIZE]; for (int i = 0; i < SIZE; i++) { @@ -339,9 +355,15 @@ public long[] convertDoubleToLong() { // ---------------- Convert F/D to Subword-I ---------------- @Test - @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx2", "true", "rvv", "true"}, + @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx2", "true", "avx10_2", "true", "rvv", "true"}, applyIfOr = {"AlignVector", "false", "UseCompactObjectHeaders", "false"}, - counts = {IRNode.VECTOR_CAST_F2S, IRNode.VECTOR_SIZE + "min(max_float, max_short)", ">0"}) + counts = {IRNode.VECTOR_CAST_F2S, IRNode.VECTOR_SIZE + "min(max_float, max_short)", "> 0"}) + @IR(counts = {IRNode.X86_VCAST_F2X, "> 0"}, + applyIfOr = {"AlignVector", "false", "UseCompactObjectHeaders", "false"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx10_2", "false"}) + @IR(counts = {IRNode.X86_VCAST_F2X_AVX10, "> 0"}, + applyIfOr = {"AlignVector", "false", "UseCompactObjectHeaders", "false"}, + applyIfCPUFeature = {"avx10_2", "true"}) public short[] convertFloatToShort() { short[] res = new short[SIZE]; for (int i = 0; i < SIZE; i++) { @@ -358,9 +380,15 @@ public short[] convertFloatToShort() { } @Test - @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx2", "true", "rvv", "true"}, + @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx2", "true", "avx10_2", "true", "rvv", "true"}, applyIfOr = {"AlignVector", "false", "UseCompactObjectHeaders", "false"}, - counts = {IRNode.VECTOR_CAST_F2S, IRNode.VECTOR_SIZE + "min(max_float, max_char)", ">0"}) + counts = {IRNode.VECTOR_CAST_F2S, IRNode.VECTOR_SIZE + "min(max_float, max_char)", "> 0"}) + @IR(counts = {IRNode.X86_VCAST_F2X, "> 0"}, + applyIfOr = {"AlignVector", "false", "UseCompactObjectHeaders", "false"}, + applyIfCPUFeatureAnd = {"avx2", "true", "avx10_2", "false"}) + @IR(counts = {IRNode.X86_VCAST_F2X_AVX10, "> 0"}, + applyIfOr = {"AlignVector", "false", "UseCompactObjectHeaders", "false"}, + applyIfCPUFeature = {"avx10_2", "true"}) public char[] convertFloatToChar() { char[] res = new char[SIZE]; for (int i = 0; i < SIZE; i++) { @@ -379,10 +407,16 @@ public char[] convertFloatToChar() { @Test @IR(applyIfCPUFeature = {"rvv", "true"}, applyIf = {"MaxVectorSize", ">=32"}, - counts = {IRNode.VECTOR_CAST_D2S, IRNode.VECTOR_SIZE + "min(max_double, max_short)", ">0"}) - @IR(applyIfCPUFeatureOr = {"sve", "true", "avx", "true"}, + counts = {IRNode.VECTOR_CAST_D2S, IRNode.VECTOR_SIZE + "min(max_double, max_short)", "> 0"}) + @IR(applyIfCPUFeatureOr = {"sve", "true", "avx", "true", "avx10_2", "true"}, + applyIf = {"MaxVectorSize", ">=16"}, + counts = {IRNode.VECTOR_CAST_D2S, IRNode.VECTOR_SIZE + "min(max_double, max_short)", "> 0"}) + @IR(counts = {IRNode.X86_VCAST_D2X, "> 0"}, applyIf = {"MaxVectorSize", ">=16"}, - counts = {IRNode.VECTOR_CAST_D2S, IRNode.VECTOR_SIZE + "min(max_double, max_short)", ">0"}) + applyIfCPUFeatureAnd = {"avx", "true", "avx10_2", "false"}) + @IR(counts = {IRNode.X86_VCAST_D2X_AVX10, "> 0"}, + applyIf = {"MaxVectorSize", ">=16"}, + applyIfCPUFeature = {"avx10_2", "true"}) public short[] convertDoubleToShort() { short[] res = new short[SIZE]; for (int i = 0; i < SIZE; i++) { @@ -393,11 +427,17 @@ public short[] convertDoubleToShort() { @Test @IR(applyIfCPUFeature = {"rvv", "true"}, - applyIf = {"MaxVectorSize", ">=32"}, - counts = {IRNode.VECTOR_CAST_D2S, IRNode.VECTOR_SIZE + "min(max_double, max_char)", ">0"}) - @IR(applyIfCPUFeatureOr = {"sve", "true", "avx", "true"}, + applyIf = {"MaxVectorSize", ">= 32"}, + counts = {IRNode.VECTOR_CAST_D2S, IRNode.VECTOR_SIZE + "min(max_double, max_char)", "> 0"}) + @IR(applyIfCPUFeatureOr = {"sve", "true", "avx", "true", "avx10_2", "true"}, + applyIf = {"MaxVectorSize", ">= 16"}, + counts = {IRNode.VECTOR_CAST_D2S, IRNode.VECTOR_SIZE + "min(max_double, max_char)", "> 0"}) + @IR(counts = {IRNode.X86_VCAST_D2X, "> 0"}, + applyIf = {"MaxVectorSize", ">=16"}, + applyIfCPUFeatureAnd = {"avx", "true", "avx10_2", "false"}) + @IR(counts = {IRNode.X86_VCAST_D2X_AVX10, "> 0"}, applyIf = {"MaxVectorSize", ">=16"}, - counts = {IRNode.VECTOR_CAST_D2S, IRNode.VECTOR_SIZE + "min(max_double, max_char)", ">0"}) + applyIfCPUFeature = {"avx10_2", "true"}) public char[] convertDoubleToChar() { char[] res = new char[SIZE]; for (int i = 0; i < SIZE; i++) { diff --git a/test/hotspot/jtreg/runtime/NMT/CommandLineDetail.java b/test/hotspot/jtreg/runtime/NMT/CommandLineDetail.java index 57f2302db30..a7561c7792e 100644 --- a/test/hotspot/jtreg/runtime/NMT/CommandLineDetail.java +++ b/test/hotspot/jtreg/runtime/NMT/CommandLineDetail.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -35,13 +35,14 @@ public class CommandLineDetail { - public static void main(String args[]) throws Exception { - - ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( - "-XX:NativeMemoryTracking=detail", - "-version"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); - output.shouldNotContain("error"); - output.shouldHaveExitValue(0); - } + public static void main(String args[]) throws Exception { + ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( + "-Xlog:nmt=warning", + "-XX:NativeMemoryTracking=detail", + "-version"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldNotContain("NMT initialization failed"); + output.shouldNotContain("Could not create the Java Virtual Machine."); + output.shouldHaveExitValue(0); + } } diff --git a/test/hotspot/jtreg/runtime/NMT/CommandLineSummary.java b/test/hotspot/jtreg/runtime/NMT/CommandLineSummary.java index 02b37a40ef4..381fe3eba34 100644 --- a/test/hotspot/jtreg/runtime/NMT/CommandLineSummary.java +++ b/test/hotspot/jtreg/runtime/NMT/CommandLineSummary.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -35,13 +35,14 @@ public class CommandLineSummary { - public static void main(String args[]) throws Exception { - - ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( - "-XX:NativeMemoryTracking=summary", - "-version"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); - output.shouldNotContain("error"); - output.shouldHaveExitValue(0); - } + public static void main(String args[]) throws Exception { + ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( + "-Xlog:nmt=warning", + "-XX:NativeMemoryTracking=summary", + "-version"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldNotContain("NMT initialization failed"); + output.shouldNotContain("Could not create the Java Virtual Machine."); + output.shouldHaveExitValue(0); + } } diff --git a/test/hotspot/jtreg/runtime/NMT/MallocLimitTest.java b/test/hotspot/jtreg/runtime/NMT/MallocLimitTest.java index a58ff861a29..8b711304a99 100644 --- a/test/hotspot/jtreg/runtime/NMT/MallocLimitTest.java +++ b/test/hotspot/jtreg/runtime/NMT/MallocLimitTest.java @@ -1,6 +1,6 @@ /* * Copyright (c) 2022 SAP SE. All rights reserved. - * Copyright (c) 2022, 2023, 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 @@ -47,7 +47,7 @@ * @requires vm.flagless * @modules java.base/jdk.internal.misc * @library /test/lib - * @run driver MallocLimitTest compiler-limit-fatal + * @run driver/timeout=480 MallocLimitTest compiler-limit-fatal */ /* diff --git a/test/hotspot/jtreg/runtime/cds/appcds/SignedJar.java b/test/hotspot/jtreg/runtime/cds/appcds/SignedJar.java index 1ad28f99408..9e6cb58bb7f 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/SignedJar.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/SignedJar.java @@ -50,8 +50,8 @@ public static void main(String[] args) throws Exception { String skipMsg = "Skipping Hello: Signed JAR"; String lambdaInArchive = "klasses.*=.*app.*Hello[$][$]Lambda.*hidden"; - String loadFromJar = ".class,load. Hello source: file:.*signed_hello.jar"; - String lambdaLoadFromHello = ".class.load. Hello[$][$]Lambda.*/0x.*source.*Hello"; + String loadFromJar = ".class,load\s*. Hello source: file:.*signed_hello.jar"; + String lambdaLoadFromHello = ".class.load\s*. Hello[$][$]Lambda.*/0x.*source.*Hello"; for (String mainArg : mainArgs) { output = TestCommon.dump(signedJar, TestCommon.list(mainClass), diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/JavaAgent.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/JavaAgent.java index 491a5bf1fa7..758d252f18d 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/JavaAgent.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/JavaAgent.java @@ -38,6 +38,7 @@ * @test id=dynamic * @bug 8362561 * @summary -javaagent is not allowed when creating dynamic CDS archive + * @requires vm.cds.supports.aot.class.linking * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds/test-classes * @build JavaAgent JavaAgentTransformer Util * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app.jar JavaAgentApp JavaAgentApp$ShouldBeTransformed diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/OldClassSupport.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/OldClassSupport.java index 42161b469bf..732ef4f2810 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/OldClassSupport.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/OldClassSupport.java @@ -65,6 +65,7 @@ public String classpath(RunMode runMode) { @Override public String[] vmArgs(RunMode runMode) { return new String[] { + "-Xlog:aot", "-Xlog:aot+class=debug", "-Xlog:aot+resolve=trace", }; diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/VerifierFailOver.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/VerifierFailOver.java index 50b47e4424d..8107e3fe0a3 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/VerifierFailOver.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/VerifierFailOver.java @@ -39,7 +39,7 @@ public class VerifierFailOver { public static void main(String... args) throws Exception { SimpleCDSAppTester.of("VerifierFailOver") - .addVmArgs("-Xlog:aot+class=debug") + .addVmArgs("-Xlog:aot,aot+class=debug") .classpath("app.jar") .appCommandLine("VerifierFailOverApp") .setTrainingChecker((OutputAnalyzer out) -> { diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BulkLoaderTest.java b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BulkLoaderTest.java index 9e43d00e872..482f8fb4ad0 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BulkLoaderTest.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotClassLinking/BulkLoaderTest.java @@ -118,7 +118,7 @@ public String classpath(RunMode runMode) { @Override public String[] vmArgs(RunMode runMode) { return new String[] { - "-Xlog:cds,aot+load,cds+class=debug,aot+class=debug", + "-Xlog:cds,aot,aot+load,cds+class=debug,aot+class=debug", "-XX:+AOTClassLinking", }; } diff --git a/test/hotspot/jtreg/serviceability/jvmti/GetThreadListStackTraces/OneGetThreadListStackTraces.java b/test/hotspot/jtreg/serviceability/jvmti/GetThreadListStackTraces/OneGetThreadListStackTraces.java index 349824af9ff..20012b70186 100644 --- a/test/hotspot/jtreg/serviceability/jvmti/GetThreadListStackTraces/OneGetThreadListStackTraces.java +++ b/test/hotspot/jtreg/serviceability/jvmti/GetThreadListStackTraces/OneGetThreadListStackTraces.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2020, NTT DATA. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -27,6 +27,7 @@ * @bug 8242428 * @summary Verifies JVMTI GetThreadListStackTraces API with thread_count = 1 * @requires vm.jvmti + * @requires test.thread.factory == null * @library /test/lib * @run main/othervm/native -agentlib:OneGetThreadListStackTraces OneGetThreadListStackTraces * diff --git a/test/hotspot/jtreg/vmTestbase/gc/gctests/AllocateWithoutOomTest/AllocateWithoutOomTest.java b/test/hotspot/jtreg/vmTestbase/gc/gctests/AllocateWithoutOomTest/AllocateWithoutOomTest.java index 51307bb996c..a1bd7acedeb 100644 --- a/test/hotspot/jtreg/vmTestbase/gc/gctests/AllocateWithoutOomTest/AllocateWithoutOomTest.java +++ b/test/hotspot/jtreg/vmTestbase/gc/gctests/AllocateWithoutOomTest/AllocateWithoutOomTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -37,7 +37,7 @@ * * @library /vmTestbase * /test/lib - * @run main/othervm + * @run main/othervm/timeout=480 * -XX:-UseGCOverheadLimit * gc.gctests.AllocateWithoutOomTest.AllocateWithoutOomTest */ diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM04/em04t001/em04t001.cpp b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM04/em04t001/em04t001.cpp index a7244db3441..a8d16a1ecae 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM04/em04t001/em04t001.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/scenarios/events/EM04/em04t001/em04t001.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 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 @@ -118,6 +118,13 @@ cbDynamicCodeGenerated2(jvmtiEnv *jvmti_env, const char *name, } +void JNICALL +cbVMDeath(jvmtiEnv* jvmti, JNIEnv* jni) { + if (!NSK_JVMTI_VERIFY(jvmti->DestroyRawMonitor(syncLock))) { + nsk_jvmti_setFailStatus(); + } +} + /* ============================================================================= */ static int @@ -138,6 +145,7 @@ int setCallBacks(int stage) { eventCallbacks.DynamicCodeGenerated = (stage == 1) ? cbDynamicCodeGenerated1 : cbDynamicCodeGenerated2; + eventCallbacks.VMDeath = &cbVMDeath; if (!NSK_JVMTI_VERIFY(jvmti->SetEventCallbacks(&eventCallbacks, sizeof(eventCallbacks)))) return NSK_FALSE; @@ -256,9 +264,6 @@ Agent_OnUnload(JavaVM *jvm) nsk_jvmti_setFailStatus(); } - if (!NSK_JVMTI_VERIFY(jvmti->DestroyRawMonitor(syncLock))) { - nsk_jvmti_setFailStatus(); - } } } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/EventHandler.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/EventHandler.java index 706b3550dcc..90a6edebd38 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/EventHandler.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/EventHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -345,12 +345,10 @@ public boolean eventReceived(Event event) { public boolean eventReceived(Event event) { if (event instanceof VMDisconnectEvent) { display("receieved VMDisconnect"); - synchronized(EventHandler.this) { - vmDisconnected = true; - status = 0; // OK finish - EventHandler.this.notifyAll(); - removeListener(this); - } + vmDisconnected = true; + status = 0; // OK finish + EventHandler.this.notifyAll(); + removeListener(this); return true; } return false; @@ -431,6 +429,10 @@ public void eventSetReceived(EventSet set) { } public boolean eventReceived(Event event) { + if (en.event != null) { + // If we already got the requested event, don't handle this one. + return false; + } EventSet set = en.set; en.set = null; // We'll reset it below if the event matches a request. for (int i = 0; i < requests.length; i++) { @@ -441,11 +443,9 @@ public boolean eventReceived(Event event) { if (request.equals(event.request())) { display("waitForRequestedEventCommon: Received event(" + event + ") for request(" + request + ")"); - synchronized (EventHandler.this) { - en.event = event; - en.set = set; - EventHandler.this.notifyAll(); - } + en.event = event; + en.set = set; + EventHandler.this.notifyAll(); return true; // event was handled } } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/TestDebuggerType1.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/TestDebuggerType1.java index aa40fd36fe5..78cfb9e8bba 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/TestDebuggerType1.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/TestDebuggerType1.java @@ -204,11 +204,9 @@ private void setCommunicationBreakpoint(ReferenceType refType, String methodName new EventHandler.EventListener() { public boolean eventReceived(Event event) { if (event instanceof BreakpointEvent && bpRequest.equals(event.request())) { - synchronized(eventHandler) { - display("Received communication breakpoint event."); - bpCount++; - eventHandler.notifyAll(); - } + display("Received communication breakpoint event."); + bpCount++; + eventHandler.notifyAll(); return true; } return false; diff --git a/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Compact_InternedStrings_Strings/TestDescription.java b/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Compact_InternedStrings_Strings/TestDescription.java index 4e11e51a894..ad7db17e412 100644 --- a/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Compact_InternedStrings_Strings/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Compact_InternedStrings_Strings/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,7 +36,7 @@ * * @library /vmTestbase * /test/lib - * @run main/othervm + * @run main/othervm/timeout=480 * -XX:-UseGCOverheadLimit * vm.gc.compact.Compact * -gp interned(randomString) diff --git a/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Compact_NonbranchyTree/TestDescription.java b/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Compact_NonbranchyTree/TestDescription.java index b058bb2c84d..be4f9f673b7 100644 --- a/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Compact_NonbranchyTree/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Compact_NonbranchyTree/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,7 +36,7 @@ * * @library /vmTestbase * /test/lib - * @run main/othervm + * @run main/othervm/timeout=480 * -XX:-UseGCOverheadLimit * vm.gc.compact.Compact * -gp nonbranchyTree(high) diff --git a/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Compact_NonbranchyTree_ArrayOf/TestDescription.java b/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Compact_NonbranchyTree_ArrayOf/TestDescription.java index 3beeaa76a84..2ca21ae2ee6 100644 --- a/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Compact_NonbranchyTree_ArrayOf/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Compact_NonbranchyTree_ArrayOf/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,7 +36,7 @@ * * @library /vmTestbase * /test/lib - * @run main/othervm + * @run main/othervm/timeout=480 * -XX:-UseGCOverheadLimit * vm.gc.compact.Compact * -gp nonbranchyTree(high) diff --git a/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Compact_NonbranchyTree_TwoFields/TestDescription.java b/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Compact_NonbranchyTree_TwoFields/TestDescription.java index c1421263a48..01dc687251b 100644 --- a/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Compact_NonbranchyTree_TwoFields/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Compact_NonbranchyTree_TwoFields/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,7 +36,7 @@ * * @library /vmTestbase * /test/lib - * @run main/othervm + * @run main/othervm/timeout=480 * -XX:-UseGCOverheadLimit * vm.gc.compact.Compact * -gp nonbranchyTree(high) diff --git a/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Compact_Strings/TestDescription.java b/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Compact_Strings/TestDescription.java index 207822c666b..9ba96b7e493 100644 --- a/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Compact_Strings/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Compact_Strings/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,7 +36,7 @@ * * @library /vmTestbase * /test/lib - * @run main/othervm + * @run main/othervm/timeout=480 * -XX:-UseGCOverheadLimit * vm.gc.compact.Compact * -gp randomString diff --git a/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Compact_Strings_InternedStrings/TestDescription.java b/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Compact_Strings_InternedStrings/TestDescription.java index 705e47ea68b..30dcfc7502e 100644 --- a/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Compact_Strings_InternedStrings/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Compact_Strings_InternedStrings/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,7 +36,7 @@ * * @library /vmTestbase * /test/lib - * @run main/othervm + * @run main/othervm/timeout=480 * -XX:-UseGCOverheadLimit * vm.gc.compact.Compact * -gp randomString diff --git a/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Compact_Strings_TwoFields/TestDescription.java b/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Compact_Strings_TwoFields/TestDescription.java index 7d5ddc36fcb..8a62d4b07eb 100644 --- a/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Compact_Strings_TwoFields/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Compact_Strings_TwoFields/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,7 +36,7 @@ * * @library /vmTestbase * /test/lib - * @run main/othervm + * @run main/othervm/timeout=480 * -XX:-UseGCOverheadLimit * vm.gc.compact.Compact * -gp randomString diff --git a/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Humongous_NonbranchyTree/TestDescription.java b/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Humongous_NonbranchyTree/TestDescription.java index 38c5b1e6bab..c9c117f0b0e 100644 --- a/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Humongous_NonbranchyTree/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Humongous_NonbranchyTree/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,7 +36,7 @@ * * @library /vmTestbase * /test/lib - * @run main/othervm + * @run main/othervm/timeout=480 * -XX:-UseGCOverheadLimit * vm.gc.compact.Compact * -gp nonbranchyTree(high) diff --git a/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Humongous_Strings/TestDescription.java b/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Humongous_Strings/TestDescription.java index 88d11739141..7d4b6ae3a21 100644 --- a/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Humongous_Strings/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/vm/gc/compact/Humongous_Strings/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,7 +36,7 @@ * * @library /vmTestbase * /test/lib - * @run main/othervm + * @run main/othervm/timeout=480 * -XX:-UseGCOverheadLimit * vm.gc.compact.Compact * -gp randomString diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 381c0c8b0be..1602baa9894 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -487,7 +487,6 @@ java/awt/Graphics2D/DrawString/RotTransText.java 8316878 linux-all java/awt/KeyboardFocusmanager/TypeAhead/ButtonActionKeyTest/ButtonActionKeyTest.java 8257529 windows-x64 java/awt/KeyboardFocusmanager/ConsumeNextMnemonicKeyTypedTest/ConsumeForModalDialogTest/ConsumeForModalDialogTest.java 8302787 windows-all java/awt/KeyboardFocusmanager/TypeAhead/MenuItemActivatedTest/MenuItemActivatedTest.java 8302787 windows-all -java/awt/KeyboardFocusmanager/ConsumeNextMnemonicKeyTypedTest/ConsumeNextMnemonicKeyTypedTest.java 8321303 linux-all java/awt/Dialog/MakeWindowAlwaysOnTop/MakeWindowAlwaysOnTop.java 8266243 macosx-aarch64 java/awt/Dialog/ChoiceModalDialogTest.java 8161475 macosx-all diff --git a/test/jdk/com/sun/crypto/provider/Cipher/ChaCha20/unittest/ChaCha20CipherUnitTest.java b/test/jdk/com/sun/crypto/provider/Cipher/ChaCha20/unittest/ChaCha20CipherUnitTest.java index 5216f48d5c3..892f3300d65 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/ChaCha20/unittest/ChaCha20CipherUnitTest.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/ChaCha20/unittest/ChaCha20CipherUnitTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, 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 @@ -23,7 +23,7 @@ /* * @test - * @bug 8153029 + * @bug 8153029 8360463 * @library /test/lib * @run main ChaCha20CipherUnitTest * @summary Unit test for com.sun.crypto.provider.ChaCha20Cipher. @@ -38,6 +38,7 @@ import java.util.HexFormat; import javax.crypto.Cipher; +import javax.crypto.NoSuchPaddingException; import javax.crypto.spec.ChaCha20ParameterSpec; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; @@ -66,32 +67,36 @@ public static void main(String[] args) throws Exception { private static void testTransformations() throws Exception { System.out.println("== transformations =="); - checkTransformation("ChaCha20", true); - checkTransformation("ChaCha20/None/NoPadding", true); - checkTransformation("ChaCha20-Poly1305", true); - checkTransformation("ChaCha20-Poly1305/None/NoPadding", true); - - checkTransformation("ChaCha20/ECB/NoPadding", false); - checkTransformation("ChaCha20/None/PKCS5Padding", false); - checkTransformation("ChaCha20-Poly1305/ECB/NoPadding", false); - checkTransformation("ChaCha20-Poly1305/None/PKCS5Padding", false); + Class NSAE = NoSuchAlgorithmException.class; + Class NSPE = NoSuchPaddingException.class; + + checkTransformation("ChaCha20", null); + checkTransformation("ChaCha20/None/NoPadding", null); + checkTransformation("ChaCha20-Poly1305", null); + checkTransformation("ChaCha20-Poly1305/None/NoPadding", null); + checkTransformation("ChaCha20/ECB/NoPadding", NSAE); + checkTransformation("ChaCha20/None/PKCS5Padding", NSPE); + checkTransformation("ChaCha20-Poly1305/ECB/NoPadding", NSAE); + checkTransformation("ChaCha20-Poly1305/None/PKCS5Padding", NSPE); } - private static void checkTransformation(String transformation, - boolean expected) throws Exception { + private static void checkTransformation(String transformation, Class exCls) + throws Exception { try { - Cipher.getInstance(transformation); - if (!expected) { - throw new RuntimeException( - "Unexpected transformation: " + transformation); + Cipher.getInstance(transformation, + System.getProperty("test.provider.name", "SunJCE")); + if (exCls != null) { + throw new RuntimeException("Expected Exception not thrown: " + + exCls); } else { - System.out.println("Expected transformation: " + transformation); + System.out.println(transformation + ": pass"); } - } catch (NoSuchAlgorithmException e) { - if (!expected) { - System.out.println("Unexpected transformation: " + transformation); + } catch (NoSuchAlgorithmException | NoSuchPaddingException e) { + if (e.getClass() != exCls) { + throw new RuntimeException("Unexpected Exception", e); } else { - throw new RuntimeException("Unexpected fail: " + transformation, e); + System.out.println(transformation + ": got expected " + + exCls.getName()); } } } diff --git a/test/jdk/com/sun/management/HotSpotDiagnosticMXBean/DumpThreads.java b/test/jdk/com/sun/management/HotSpotDiagnosticMXBean/DumpThreads.java index adf643749c7..77020491c29 100644 --- a/test/jdk/com/sun/management/HotSpotDiagnosticMXBean/DumpThreads.java +++ b/test/jdk/com/sun/management/HotSpotDiagnosticMXBean/DumpThreads.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8284161 8287008 8309406 8356870 + * @bug 8284161 8287008 8309406 8356870 8365057 * @summary Basic test for com.sun.management.HotSpotDiagnosticMXBean.dumpThreads * @requires vm.continuations * @modules java.base/jdk.internal.vm jdk.management @@ -425,7 +425,9 @@ void testParkedThread(ThreadFactory factory, boolean pinned) throws Exception { ThreadFields fields = findThread(tid, lines); assertNotNull(fields, "thread not found"); assertEquals("WAITING", fields.state()); - assertTrue(contains(lines, "- parking to wait for lines, String text) { .anyMatch(l -> l.contains(text)); } + /** + * Finds the line of a plain text thread dump containing the given text. + */ + private String find(List lines, String text) { + return lines.stream().map(String::trim) + .filter(l -> l.contains(text)) + .findAny() + .orElse(null); + } + /** * Dump threads to a file in plain text format, return the lines in the file. */ diff --git a/test/jdk/java/awt/Headless/HeadlessMalfunctionTest.java b/test/jdk/java/awt/Headless/HeadlessMalfunctionTest.java index 61ebf1df3e8..e9ae66492d4 100644 --- a/test/jdk/java/awt/Headless/HeadlessMalfunctionTest.java +++ b/test/jdk/java/awt/Headless/HeadlessMalfunctionTest.java @@ -38,7 +38,7 @@ * @run driver jdk.test.lib.helpers.ClassFileInstaller * HeadlessMalfunctionAgent * HeadlessMalfunctionAgent$1 - * @run driver HeadlessMalfunctionTest + * @run driver/timeout=240 HeadlessMalfunctionTest */ public class HeadlessMalfunctionTest { diff --git a/test/jdk/java/awt/KeyboardFocusmanager/ConsumeNextMnemonicKeyTypedTest/ConsumeNextMnemonicKeyTypedTest.java b/test/jdk/java/awt/KeyboardFocusmanager/ConsumeNextMnemonicKeyTypedTest/ConsumeNextMnemonicKeyTypedTest.java index 5b2dc2844f1..60c05fb05a6 100644 --- a/test/jdk/java/awt/KeyboardFocusmanager/ConsumeNextMnemonicKeyTypedTest/ConsumeNextMnemonicKeyTypedTest.java +++ b/test/jdk/java/awt/KeyboardFocusmanager/ConsumeNextMnemonicKeyTypedTest/ConsumeNextMnemonicKeyTypedTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,7 @@ /* @test @key headful - @bug 6346690 + @bug 6346690 8361606 8321303 @summary Tests that key_typed is consumed after mnemonic key_pressed is handled for a menu item. @library /test/lib @build jdk.test.lib.Platform diff --git a/test/jdk/java/awt/print/PrinterJob/PrintTextTest.java b/test/jdk/java/awt/print/PrinterJob/PrintTextTest.java index 7fb1167a847..06e71c4067f 100644 --- a/test/jdk/java/awt/print/PrinterJob/PrintTextTest.java +++ b/test/jdk/java/awt/print/PrinterJob/PrintTextTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 6425068 7157659 8029204 8132890 8148334 8344637 + * @bug 6425068 7156751 7157659 8029204 8132890 8148334 8344637 * @key printer * @summary Confirm that text prints where we expect to the length we expect. * @library /java/awt/regtesthelpers diff --git a/test/jdk/java/lang/ProcessHandle/TEST.properties b/test/jdk/java/lang/ProcessHandle/TEST.properties new file mode 100644 index 00000000000..c7e8a6850ca --- /dev/null +++ b/test/jdk/java/lang/ProcessHandle/TEST.properties @@ -0,0 +1 @@ +maxOutputSize=6000000 diff --git a/test/jdk/java/lang/StringBuilder/RacingSBThreads.java b/test/jdk/java/lang/StringBuilder/RacingSBThreads.java index 26f5cf9385a..8affa3feffa 100644 --- a/test/jdk/java/lang/StringBuilder/RacingSBThreads.java +++ b/test/jdk/java/lang/StringBuilder/RacingSBThreads.java @@ -28,7 +28,6 @@ * @run main/othervm -esa RacingSBThreads read * @run main/othervm -esa RacingSBThreads insert * @run main/othervm -esa RacingSBThreads append - * @run main/othervm -Xcomp RacingSBThreads */ import java.nio.CharBuffer; diff --git a/test/jdk/java/lang/Thread/virtual/Starvation.java b/test/jdk/java/lang/Thread/virtual/Starvation.java index c55ad3c2494..987c54c1a0c 100644 --- a/test/jdk/java/lang/Thread/virtual/Starvation.java +++ b/test/jdk/java/lang/Thread/virtual/Starvation.java @@ -25,7 +25,7 @@ * @requires vm.continuations * @library /test/lib * @bug 8345294 - * @run main/othervm/timeout=800/native --enable-native-access=ALL-UNNAMED Starvation 100000 + * @run main/othervm/native --enable-native-access=ALL-UNNAMED Starvation */ import java.time.Duration; @@ -37,9 +37,16 @@ public class Starvation { public static void main(String[] args) throws Exception { - int iterations = Integer.parseInt(args[0]); + int iterations; + if (args.length > 0) { + iterations = Integer.parseInt(args[0]); + } else { + int nprocs = Runtime.getRuntime().availableProcessors(); + iterations = 40_000 / nprocs; + } - for (int i = 0; i < iterations; i++) { + for (int i = 1; i <= iterations; i++) { + System.out.format("%s iteration %d of %d ...%n", Instant.now(), i, iterations); var exRef = new AtomicReference(); Thread thread = Thread.startVirtualThread(() -> { try { diff --git a/test/jdk/java/net/httpclient/RedirectTimeoutTest.java b/test/jdk/java/net/httpclient/RedirectTimeoutTest.java index be634398ba2..3e921879fe3 100644 --- a/test/jdk/java/net/httpclient/RedirectTimeoutTest.java +++ b/test/jdk/java/net/httpclient/RedirectTimeoutTest.java @@ -133,7 +133,7 @@ public void test(Version version, URI uri, URI redirectURI) throws InterruptedEx if (version == HTTP_3) { reqBuilder = reqBuilder.version(HTTP_3).setOption(H3_DISCOVERY, HTTP_3_URI_ONLY); } - HttpRequest request = reqBuilder + HttpRequest request = reqBuilder.copy() .GET() .version(version) .timeout(Duration.ofMillis(adjustTimeout(TIMEOUT_MILLIS))) diff --git a/test/jdk/java/net/httpclient/http3/H3ErrorHandlingTest.java b/test/jdk/java/net/httpclient/http3/H3ErrorHandlingTest.java index 10a3a3af8f2..4315fd36de5 100644 --- a/test/jdk/java/net/httpclient/http3/H3ErrorHandlingTest.java +++ b/test/jdk/java/net/httpclient/http3/H3ErrorHandlingTest.java @@ -34,6 +34,7 @@ import jdk.internal.net.quic.QuicVersion; import jdk.test.lib.net.SimpleSSLContext; import jdk.test.lib.net.URIBuilder; +import jdk.test.lib.Utils; import org.testng.IRetryAnalyzer; import org.testng.ITestResult; import org.testng.annotations.AfterClass; @@ -802,7 +803,7 @@ public void testStatelessReset() throws Exception { final HttpResponse response = client.sendAsync( request, BodyHandlers.discarding()) - .get(10, TimeUnit.SECONDS); + .get(Utils.adjustTimeout(10), TimeUnit.SECONDS); fail("Expected the request to fail, got " + response); } catch (Exception e) { final String expectedMsg = "stateless reset from peer"; @@ -943,7 +944,7 @@ private void triggerClose(String... reasons) throws Exception { final HttpResponse response = client.sendAsync( request, BodyHandlers.discarding()) - .get(10, TimeUnit.SECONDS); + .get(Utils.adjustTimeout(10), TimeUnit.SECONDS); fail("Expected the request to fail, got " + response); } catch (ExecutionException e) { System.out.println("Client exception [expected]: " + e); @@ -966,13 +967,13 @@ private void triggerError(CompletableFuture errorCF, Http3Erro final HttpResponse response = client.sendAsync( request, BodyHandlers.discarding()) - .get(10, TimeUnit.SECONDS); + .get(Utils.adjustTimeout(20), TimeUnit.SECONDS); fail("Expected the request to fail, got " + response); } catch (ExecutionException e) { System.out.println("Client exception [expected]: " + e); var cause = e.getCause(); assertTrue(cause instanceof ProtocolException, "Expected ProtocolException"); - TerminationCause terminationCause = errorCF.get(10, TimeUnit.SECONDS); + TerminationCause terminationCause = errorCF.get(Utils.adjustTimeout(10), TimeUnit.SECONDS); System.out.println("Server reason: \"" + terminationCause.getPeerVisibleReason()+'"'); final long actual = terminationCause.getCloseCode(); // expected @@ -989,13 +990,13 @@ private void triggerError(CompletableFuture errorCF, Http3Erro final HttpResponse response = client.sendAsync( request, BodyHandlers.discarding()) - .get(10, TimeUnit.SECONDS); + .get(Utils.adjustTimeout(10), TimeUnit.SECONDS); fail("Expected the request to fail, got " + response); } catch (ExecutionException e) { System.out.println("Client exception [expected]: " + e); var cause = e.getCause(); assertTrue(cause instanceof ProtocolException, "Expected ProtocolException"); - TerminationCause terminationCause = errorCF.get(10, TimeUnit.SECONDS); + TerminationCause terminationCause = errorCF.get(Utils.adjustTimeout(10), TimeUnit.SECONDS); System.out.println("Server reason: \"" + terminationCause.getPeerVisibleReason()+'"'); final long actual = terminationCause.getCloseCode(); // expected @@ -1019,13 +1020,13 @@ private void triggerPushError(CompletableFuture errorCF, Http3 BodyHandlers.discarding(), (initiatingRequest, pushPromiseRequest, acceptor) -> acceptor.apply(BodyHandlers.discarding()) - ).get(10, TimeUnit.SECONDS); + ).get(Utils.adjustTimeout(10), TimeUnit.SECONDS); fail("Expected the request to fail, got " + response); } catch (ExecutionException e) { System.out.println("Client exception [expected]: " + e); var cause = e.getCause(); assertTrue(cause instanceof ProtocolException, "Expected ProtocolException"); - TerminationCause terminationCause = errorCF.get(10, TimeUnit.SECONDS); + TerminationCause terminationCause = errorCF.get(Utils.adjustTimeout(10), TimeUnit.SECONDS); System.out.println("Server reason: \"" + terminationCause.getPeerVisibleReason()+'"'); final long actual = terminationCause.getCloseCode(); // expected diff --git a/test/jdk/java/nio/channels/DatagramChannel/StressNativeSignal.java b/test/jdk/java/nio/channels/DatagramChannel/StressNativeSignal.java index d6d2f083eca..cc726d19c0d 100644 --- a/test/jdk/java/nio/channels/DatagramChannel/StressNativeSignal.java +++ b/test/jdk/java/nio/channels/DatagramChannel/StressNativeSignal.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 @@ -36,42 +36,23 @@ import java.util.concurrent.CountDownLatch; public class StressNativeSignal { - private UDPThread udpThread; - private ServerSocketThread serverSocketThread; + private final UDPThread udpThread; + private final ServerSocketThread serverSocketThread; - StressNativeSignal() { + StressNativeSignal() throws IOException { serverSocketThread = initServerSocketThread(); - if (serverSocketThread != null) { - serverSocketThread.start(); - } + serverSocketThread.start(); udpThread = initUDPThread(); - if (udpThread != null) { - udpThread.start(); - } + udpThread.start(); } - private UDPThread initUDPThread() { - UDPThread aUDPThread = null; - try { - aUDPThread = new UDPThread(); - } catch (Exception z) { - System.err.println("failed to create and start a UDPThread"); - z.printStackTrace(); - } - return aUDPThread; + private UDPThread initUDPThread() throws IOException { + return new UDPThread(); } - private ServerSocketThread initServerSocketThread() { - ServerSocketThread aServerSocketThread = null; - try { - aServerSocketThread = new ServerSocketThread(); - - } catch (Exception z) { - System.err.println("failed to create and start a ServerSocketThread"); - z.printStackTrace(); - } - return aServerSocketThread; + private ServerSocketThread initServerSocketThread() throws IOException { + return new ServerSocketThread(); } public static void main(String[] args) throws Throwable { @@ -80,46 +61,39 @@ public static void main(String[] args) throws Throwable { test.shutdown(); } - public void shutdown() { - if ((udpThread != null) && udpThread.isAlive()) { + public void shutdown() throws InterruptedException, IOException { + if (udpThread != null && udpThread.isAlive()) { udpThread.terminate(); - try { - udpThread.join(); - } catch (Exception z) { - z.printStackTrace(System.err); - } + udpThread.join(); + } else { System.out.println("UDPThread test scenario was not run"); } - if ((serverSocketThread != null) && (serverSocketThread.isAlive())) { + if (serverSocketThread != null && serverSocketThread.isAlive()) { serverSocketThread.terminate(); - try { - serverSocketThread.join(); - } catch (Exception z) { - z.printStackTrace(System.err); - } + serverSocketThread.join(); } else { System.out.println("ServerSocketThread test scenario was not run"); } } - public void waitForTestThreadsToStart() { - if ((udpThread != null) && udpThread.isAlive()) { + public void waitForTestThreadsToStart() throws InterruptedException { + if (udpThread != null && udpThread.isAlive()) { udpThread.waitTestThreadStart(); } - if ((serverSocketThread != null) && (serverSocketThread.isAlive())) { + if (serverSocketThread != null && serverSocketThread.isAlive()) { serverSocketThread.waitTestThreadStart(); } } public class ServerSocketThread extends Thread { private volatile boolean shouldTerminate; - private ServerSocket socket; + private final ServerSocket socket; private final CountDownLatch threadStarted = new CountDownLatch(1); - public ServerSocketThread () throws Exception { - socket = new ServerSocket(1122); + public ServerSocketThread() throws IOException { + socket = new ServerSocket(0); } public void run() { @@ -129,7 +103,7 @@ public void run() { Socket client = socket.accept(); client.close(); throw new RuntimeException("Unexpected return from accept call"); - } catch (Exception z) { + } catch (IOException z) { System.err.println("ServerSocketThread: caught exception " + z.getClass().getName()); if (!shouldTerminate) { z.printStackTrace(System.err); @@ -141,7 +115,7 @@ public void terminate() { shouldTerminate = true; try { socket.close(); - } catch (Exception z) { + } catch (IOException z) { z.printStackTrace(System.err); // ignore } @@ -150,7 +124,7 @@ public void terminate() { public void waitTestThreadStart() { try { threadStarted.await(); - } catch (Exception z) { + } catch (InterruptedException z) { z.printStackTrace(System.err); // ignore } @@ -158,15 +132,14 @@ public void waitTestThreadStart() { } public class UDPThread extends Thread { - private DatagramChannel channel; + private final DatagramChannel channel; private volatile boolean shouldTerminate; private final CountDownLatch threadStarted = new CountDownLatch(1); - public UDPThread () throws Exception { - + public UDPThread() throws IOException { channel = DatagramChannel.open(); channel.setOption(StandardSocketOptions.SO_RCVBUF, 6553600); - channel.bind(new InetSocketAddress(19870)); + channel.bind(new InetSocketAddress(0)); } @Override @@ -191,7 +164,7 @@ public void terminate() { shouldTerminate = true; try { channel.close(); - } catch (Exception z) { + } catch (IOException z) { System.err.println("UDPThread: caught exception " + z.getClass().getName()); z.printStackTrace(System.err); // ignore @@ -201,7 +174,7 @@ public void terminate() { public void waitTestThreadStart() { try { threadStarted.await(); - } catch (Exception z) { + } catch (InterruptedException z) { z.printStackTrace(System.err); // ignore } diff --git a/test/jdk/java/text/Collator/RuleBasedCollatorTest.java b/test/jdk/java/text/Collator/RuleBasedCollatorTest.java index 429768b6bf1..cd1e8ca69c0 100644 --- a/test/jdk/java/text/Collator/RuleBasedCollatorTest.java +++ b/test/jdk/java/text/Collator/RuleBasedCollatorTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, 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 @@ -26,40 +26,45 @@ * @bug 4406815 8222969 8266784 * @summary RuleBasedCollatorTest uses very limited but selected test data * to test basic functionalities provided by RuleBasedCollator. - * @run testng/othervm RuleBasedCollatorTest + * @run junit/othervm RuleBasedCollatorTest */ +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + import java.text.CollationElementIterator; import java.text.CollationKey; -import java.text.RuleBasedCollator; import java.text.Collator; import java.text.ParseException; +import java.text.RuleBasedCollator; import java.util.Arrays; import java.util.Locale; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; -import org.testng.SkipException; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assumptions.assumeFalse; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class RuleBasedCollatorTest { - static RuleBasedCollator USC; - static String US_RULES; + private static RuleBasedCollator USC; + private static String US_RULES; - @BeforeClass - public void setup() { + @BeforeAll + void setup() { Collator c = Collator.getInstance(Locale.US); - if (!(c instanceof RuleBasedCollator)) { - throw new SkipException("skip tests."); - } + assumeFalse(!(c instanceof RuleBasedCollator), "skip tests."); USC = (RuleBasedCollator) c; US_RULES = USC.getRules(); } - @DataProvider(name = "rulesData") Object[][] rulesData() { //Basic Tailor String BASIC_TAILOR_RULES = "< b=c<\u00e6;A,a"; @@ -91,15 +96,15 @@ Object[][] rulesData() { }; } - @Test(dataProvider = "rulesData") - public void testRules(String rules, String[] testData, String[] expected) + @ParameterizedTest + @MethodSource("rulesData") + void testRules(String rules, String[] testData, String[] expected) throws ParseException { Arrays.sort(testData, new RuleBasedCollator(rules)); - assertEquals(testData, expected); + assertArrayEquals(expected, testData); } - @DataProvider(name = "FrenchSecondarySort") Object[][] FrenchSecondarySort() { return new Object[][] { { "\u0061\u00e1\u0061", "\u00e1\u0061\u0061", 1 }, @@ -111,8 +116,9 @@ Object[][] FrenchSecondarySort() { { "a", "\u1ea1", -1 } }; } - @Test(dataProvider = "FrenchSecondarySort") - public void testFrenchSecondarySort(String sData, String tData, + @ParameterizedTest + @MethodSource("FrenchSecondarySort") + void testFrenchSecondarySort(String sData, String tData, int expected) throws ParseException { String french_rule = "@"; String rules = US_RULES + french_rule; @@ -121,7 +127,6 @@ public void testFrenchSecondarySort(String sData, String tData, assertEquals(expected, result); } - @DataProvider(name = "ThaiLaoVowelConsonantSwapping") Object[][] ThaiLaoVowelConsonantSwapping() { return new Object[][] {{"\u0e44\u0e01", "\u0e40\u0e2e", -1},//swap {"\u0e2e\u0e40", "\u0e01\u0e44", 1},//no swap @@ -129,8 +134,9 @@ Object[][] ThaiLaoVowelConsonantSwapping() { }; } - @Test(dataProvider = "ThaiLaoVowelConsonantSwapping") - public void testThaiLaoVowelConsonantSwapping(String sData, String tData, + @ParameterizedTest + @MethodSource("ThaiLaoVowelConsonantSwapping") + void testThaiLaoVowelConsonantSwapping(String sData, String tData, int expected) throws ParseException { String thai_rule = "& Z < \u0e01 < \u0e2e <\u0e40 < \u0e44!"; String rules = US_RULES + thai_rule; @@ -140,16 +146,15 @@ public void testThaiLaoVowelConsonantSwapping(String sData, String tData, } @Test - public void testIgnorableCharacter() throws ParseException { + void testIgnorableCharacter() throws ParseException { String rule = "=f new RuleBasedCollator(rule)); } - @Test(expectedExceptions = NullPointerException.class) - public void testNullParseException() throws ParseException{ - new RuleBasedCollator(null); + @Test + void testNullParseException() { + assertThrows(NullPointerException.class, () -> new RuleBasedCollator(null)); } } diff --git a/test/jdk/java/text/Format/CompactNumberFormat/CompactFormatAndParseHelper.java b/test/jdk/java/text/Format/CompactNumberFormat/CompactFormatAndParseHelper.java index 3f3f1932e51..4d410f97b5d 100644 --- a/test/jdk/java/text/Format/CompactNumberFormat/CompactFormatAndParseHelper.java +++ b/test/jdk/java/text/Format/CompactNumberFormat/CompactFormatAndParseHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, 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 @@ -24,14 +24,15 @@ import java.text.NumberFormat; import java.text.ParseException; import java.text.ParsePosition; -import static org.testng.Assert.assertEquals; + +import static org.junit.jupiter.api.Assertions.assertEquals; class CompactFormatAndParseHelper { static void testFormat(NumberFormat cnf, Object number, String expected) { String result = cnf.format(number); - assertEquals(result, expected, "Incorrect formatting of the number '" + assertEquals(expected, result, "Incorrect formatting of the number '" + number + "'"); } @@ -46,11 +47,11 @@ static void testParse(NumberFormat cnf, String parseString, } if (returnType != null) { - assertEquals(number.getClass(), returnType, + assertEquals(returnType, number.getClass(), "Incorrect return type for string '" + parseString + "'"); } - assertEquals(number, expected, "Incorrect parsing of the string '" + assertEquals(expected, number, "Incorrect parsing of the string '" + parseString + "'"); } } diff --git a/test/jdk/java/text/Format/CompactNumberFormat/TestCNFRounding.java b/test/jdk/java/text/Format/CompactNumberFormat/TestCNFRounding.java index b4dddfa1df7..0ba9587a344 100644 --- a/test/jdk/java/text/Format/CompactNumberFormat/TestCNFRounding.java +++ b/test/jdk/java/text/Format/CompactNumberFormat/TestCNFRounding.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 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 @@ -20,21 +20,28 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + /* * @test * @bug 8177552 * @summary Checks the rounding of formatted number in compact number formatting - * @run testng/othervm TestCNFRounding + * @run junit/othervm TestCNFRounding */ +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + import java.math.RoundingMode; import java.text.NumberFormat; import java.util.List; import java.util.Locale; -import static org.testng.Assert.*; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestCNFRounding { private static final List MODES = List.of( @@ -46,7 +53,6 @@ public class TestCNFRounding { RoundingMode.CEILING, RoundingMode.FLOOR); - @DataProvider(name = "roundingData") Object[][] roundingData() { return new Object[][]{ // Number, half_even, half_up, half_down, up, down, ceiling, floor @@ -70,7 +76,6 @@ Object[][] roundingData() { {-4500, new String[]{"-4K", "-5K", "-4K", "-5K", "-4K", "-4K", "-5K"}},}; } - @DataProvider(name = "roundingFract") Object[][] roundingFract() { return new Object[][]{ // Number, half_even, half_up, half_down, up, down, ceiling, floor @@ -94,7 +99,6 @@ Object[][] roundingFract() { {-4500, new String[]{"-4.5K", "-4.5K", "-4.5K", "-4.5K", "-4.5K", "-4.5K", "-4.5K"}},}; } - @DataProvider(name = "rounding2Fract") Object[][] rounding2Fract() { return new Object[][]{ // Number, half_even, half_up, half_down @@ -118,37 +122,42 @@ Object[][] rounding2Fract() { {4686, new String[]{"4.69K", "4.69K", "4.69K"}},}; } - @Test(expectedExceptions = NullPointerException.class) - public void testNullMode() { - NumberFormat fmt = NumberFormat - .getCompactNumberInstance(Locale.US, NumberFormat.Style.SHORT); - fmt.setRoundingMode(null); + @Test + void testNullMode() { + assertThrows(NullPointerException.class, () -> { + NumberFormat fmt = NumberFormat + .getCompactNumberInstance(Locale.US, NumberFormat.Style.SHORT); + fmt.setRoundingMode(null); + }); } @Test - public void testDefaultRoundingMode() { + void testDefaultRoundingMode() { NumberFormat fmt = NumberFormat .getCompactNumberInstance(Locale.US, NumberFormat.Style.SHORT); - assertEquals(fmt.getRoundingMode(), RoundingMode.HALF_EVEN, + assertEquals(RoundingMode.HALF_EVEN, fmt.getRoundingMode(), "Default RoundingMode should be " + RoundingMode.HALF_EVEN); } - @Test(dataProvider = "roundingData") - public void testRounding(Object number, String[] expected) { + @ParameterizedTest + @MethodSource("roundingData") + void testRounding(Object number, String[] expected) { for (int index = 0; index < MODES.size(); index++) { testRoundingMode(number, expected[index], 0, MODES.get(index)); } } - @Test(dataProvider = "roundingFract") - public void testRoundingFract(Object number, String[] expected) { + @ParameterizedTest + @MethodSource("roundingFract") + void testRoundingFract(Object number, String[] expected) { for (int index = 0; index < MODES.size(); index++) { testRoundingMode(number, expected[index], 1, MODES.get(index)); } } - @Test(dataProvider = "rounding2Fract") - public void testRounding2Fract(Object number, String[] expected) { + @ParameterizedTest + @MethodSource("rounding2Fract") + void testRounding2Fract(Object number, String[] expected) { List rModes = List.of(RoundingMode.HALF_EVEN, RoundingMode.HALF_UP, RoundingMode.HALF_DOWN); for (int index = 0; index < rModes.size(); index++) { @@ -161,12 +170,12 @@ private void testRoundingMode(Object number, String expected, NumberFormat fmt = NumberFormat .getCompactNumberInstance(Locale.US, NumberFormat.Style.SHORT); fmt.setRoundingMode(rounding); - assertEquals(fmt.getRoundingMode(), rounding, + assertEquals(rounding, fmt.getRoundingMode(), "RoundingMode set is not returned by getRoundingMode"); fmt.setMinimumFractionDigits(fraction); String result = fmt.format(number); - assertEquals(result, expected, "Incorrect formatting of number " + assertEquals(expected, result, "Incorrect formatting of number " + number + " using rounding mode: " + rounding); } diff --git a/test/jdk/java/text/Format/CompactNumberFormat/TestClone.java b/test/jdk/java/text/Format/CompactNumberFormat/TestClone.java new file mode 100644 index 00000000000..42abc1be2ba --- /dev/null +++ b/test/jdk/java/text/Format/CompactNumberFormat/TestClone.java @@ -0,0 +1,95 @@ +/* + * 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 8368328 + * @summary Tests if CompactNumberFormat.clone() creates an independent object + * @run junit/othervm --add-opens java.base/java.text=ALL-UNNAMED TestClone + */ + +import java.lang.invoke.MethodHandles; +import java.text.CompactNumberFormat; +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.text.NumberFormat; +import java.util.Locale; +import java.util.stream.IntStream; +import java.util.stream.Stream; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotSame; + +public class TestClone { + // Concurrently parse numbers using cloned instances as originally + // reported in the bug. This test could produce false negative results, + // depending on the testing environment + @Test + void randomAccessTest() { + var original = + NumberFormat.getCompactNumberInstance(Locale.US, NumberFormat.Style.SHORT); + var threads = IntStream.range(0, 10) + .mapToObj(num -> new Thread(() -> { + var clone = (NumberFormat) original.clone(); + for (int i = 0; i < 1000; i++) { + assertDoesNotThrow(() -> + assertEquals(num, clone.parse(String.valueOf(num)).intValue())); + } + })).toList(); + threads.forEach(Thread::start); + threads.forEach(t -> { + try { + t.join(); + } catch (InterruptedException ie) { + throw new RuntimeException(ie); + } + }); + } + + private static Stream referenceFields() throws ClassNotFoundException { + return Stream.of( + Arguments.of("compactPatterns", String[].class), + Arguments.of("symbols", DecimalFormatSymbols.class), + Arguments.of("decimalFormat", DecimalFormat.class), + Arguments.of("defaultDecimalFormat", DecimalFormat.class), + Arguments.of("digitList", Class.forName("java.text.DigitList")) + ); + } + // Explicitly checks if the cloned object has its own references for + // "compactPatterns", "symbols", "decimalFormat", "defaultDecimalFormat", + // and "digitList" + @ParameterizedTest + @MethodSource("referenceFields") + void whiteBoxTest(String fieldName, Class type) throws Throwable { + var original = NumberFormat.getCompactNumberInstance(Locale.US, NumberFormat.Style.SHORT); + var clone = original.clone(); + var lookup = MethodHandles.privateLookupIn(CompactNumberFormat.class, MethodHandles.lookup()); + + assertNotSame(lookup.findGetter(CompactNumberFormat.class, fieldName, type).invoke(original), + lookup.findGetter(CompactNumberFormat.class, fieldName, type).invoke(clone)); + } +} diff --git a/test/jdk/java/text/Format/CompactNumberFormat/TestCompactNumber.java b/test/jdk/java/text/Format/CompactNumberFormat/TestCompactNumber.java index e9972f62f3e..b81226c00db 100644 --- a/test/jdk/java/text/Format/CompactNumberFormat/TestCompactNumber.java +++ b/test/jdk/java/text/Format/CompactNumberFormat/TestCompactNumber.java @@ -25,8 +25,14 @@ * @bug 8177552 8217721 8222756 8295372 8306116 8319990 8338690 8363972 * @summary Checks the functioning of compact number format * @modules jdk.localedata - * @run testng/othervm TestCompactNumber + * @run junit/othervm TestCompactNumber */ + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + import java.math.BigDecimal; import java.math.BigInteger; import java.text.FieldPosition; @@ -36,10 +42,11 @@ import java.text.ParsePosition; import java.util.Locale; import java.util.stream.Stream; -import static org.testng.Assert.*; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestCompactNumber { private static final NumberFormat FORMAT_DZ_LONG = NumberFormat @@ -106,7 +113,6 @@ public class TestCompactNumber { FORMAT_PT_LONG_FD4.setMaximumFractionDigits(4); } - @DataProvider(name = "format") Object[][] compactFormatData() { return new Object[][]{ // compact number format instance, number to format, formatted output @@ -378,7 +384,6 @@ Object[][] compactFormatData() { }; } - @DataProvider(name = "parse") Object[][] compactParseData() { return new Object[][]{ // compact number format instance, string to parse, parsed number, return type @@ -491,7 +496,6 @@ Object[][] compactParseData() { }; } - @DataProvider(name = "exceptionParse") Object[][] exceptionParseData() { return new Object[][]{ // compact number instance, string to parse, null (no o/p; must throw exception) @@ -508,7 +512,6 @@ Object[][] exceptionParseData() { }; } - @DataProvider(name = "invalidParse") Object[][] invalidParseData() { return new Object[][]{ // compact number instance, string to parse, parsed number @@ -542,7 +545,6 @@ Object[][] invalidParseData() { }; } - @DataProvider(name = "fieldPosition") Object[][] formatFieldPositionData() { return new Object[][]{ //compact number instance, number to format, field, start position, end position, formatted string @@ -588,7 +590,6 @@ Object[][] formatFieldPositionData() { {FORMAT_SE_SHORT, new BigDecimal("-48982865901234567890.98"), NumberFormat.Field.INTEGER, 1, 9, "\u221248982866\u00a0bn"},}; } - @DataProvider(name = "varParsePosition") Object[][] varParsePosition() { return new Object[][]{ // compact number instance, parse string, parsed number, @@ -616,73 +617,82 @@ Object[][] varParsePosition() { } @Test - public void testInstanceCreation() { + void testInstanceCreation() { Stream.of(NumberFormat.getAvailableLocales()).forEach(l -> NumberFormat .getCompactNumberInstance(l, NumberFormat.Style.SHORT).format(10000)); Stream.of(NumberFormat.getAvailableLocales()).forEach(l -> NumberFormat .getCompactNumberInstance(l, NumberFormat.Style.LONG).format(10000)); } - @Test(expectedExceptions = IllegalArgumentException.class) - public void testFormatWithNullParam() { - FORMAT_EN_US_SHORT.format(null); + @Test + void testFormatWithNullParam() { + assertThrows(IllegalArgumentException.class, () -> { + FORMAT_EN_US_SHORT.format(null); + }); } - @Test(dataProvider = "format") - public void testFormat(NumberFormat cnf, Object number, + @ParameterizedTest + @MethodSource("compactFormatData") + void testFormat(NumberFormat cnf, Object number, String expected) { CompactFormatAndParseHelper.testFormat(cnf, number, expected); } - @Test(dataProvider = "parse") - public void testParse(NumberFormat cnf, String parseString, + @ParameterizedTest + @MethodSource("compactParseData") + void testParse(NumberFormat cnf, String parseString, Number expected, Class returnType) throws ParseException { CompactFormatAndParseHelper.testParse(cnf, parseString, expected, null, returnType); } - @Test(dataProvider = "parse") - public void testParsePosition(NumberFormat cnf, String parseString, + @ParameterizedTest + @MethodSource("compactParseData") + void testParsePosition(NumberFormat cnf, String parseString, Number expected, Class returnType) throws ParseException { ParsePosition pos = new ParsePosition(0); CompactFormatAndParseHelper.testParse(cnf, parseString, expected, pos, returnType); - assertEquals(pos.getIndex(), parseString.length()); - assertEquals(pos.getErrorIndex(), -1); + assertEquals(parseString.length(), pos.getIndex()); + assertEquals(-1, pos.getErrorIndex()); } - @Test(dataProvider = "varParsePosition") - public void testVarParsePosition(NumberFormat cnf, String parseString, + @ParameterizedTest + @MethodSource("varParsePosition") + void testVarParsePosition(NumberFormat cnf, String parseString, Number expected, int startPosition, int indexPosition, int errPosition) throws ParseException { ParsePosition pos = new ParsePosition(startPosition); CompactFormatAndParseHelper.testParse(cnf, parseString, expected, pos, null); - assertEquals(pos.getIndex(), indexPosition); - assertEquals(pos.getErrorIndex(), errPosition); + assertEquals(indexPosition, pos.getIndex()); + assertEquals(errPosition, pos.getErrorIndex()); } - @Test(dataProvider = "exceptionParse", expectedExceptions = ParseException.class) - public void throwsParseException(NumberFormat cnf, String parseString, - Number expected) throws ParseException { - CompactFormatAndParseHelper.testParse(cnf, parseString, expected, null, null); + @ParameterizedTest + @MethodSource("exceptionParseData") + void throwsParseException(NumberFormat cnf, String parseString, + Number expected) { + assertThrows(ParseException.class, () -> CompactFormatAndParseHelper.testParse(cnf, parseString, expected, null, null)); } - @Test(dataProvider = "invalidParse") - public void testInvalidParse(NumberFormat cnf, String parseString, + @ParameterizedTest + @MethodSource("invalidParseData") + void testInvalidParse(NumberFormat cnf, String parseString, Number expected) throws ParseException { CompactFormatAndParseHelper.testParse(cnf, parseString, expected, null, null); } - @Test(dataProvider = "fieldPosition") - public void testFormatWithFieldPosition(NumberFormat nf, + @ParameterizedTest + @MethodSource("formatFieldPositionData") + void testFormatWithFieldPosition(NumberFormat nf, Object number, Format.Field field, int posStartExpected, int posEndExpected, String expected) { FieldPosition pos = new FieldPosition(field); StringBuffer buf = new StringBuffer(); StringBuffer result = nf.format(number, buf, pos); - assertEquals(result.toString(), expected, "Incorrect formatting of the number '" + assertEquals(expected, result.toString(), "Incorrect formatting of the number '" + number + "'"); - assertEquals(pos.getBeginIndex(), posStartExpected, "Incorrect start position" + assertEquals(posStartExpected, pos.getBeginIndex(), "Incorrect start position" + " while formatting the number '" + number + "', for the field " + field); - assertEquals(pos.getEndIndex(), posEndExpected, "Incorrect end position" + assertEquals(posEndExpected, pos.getEndIndex(), "Incorrect end position" + " while formatting the number '" + number + "', for the field " + field); } diff --git a/test/jdk/java/text/Format/CompactNumberFormat/TestCompactPatternsValidity.java b/test/jdk/java/text/Format/CompactNumberFormat/TestCompactPatternsValidity.java index 8476b568ba0..1f8f1041e9e 100644 --- a/test/jdk/java/text/Format/CompactNumberFormat/TestCompactPatternsValidity.java +++ b/test/jdk/java/text/Format/CompactNumberFormat/TestCompactPatternsValidity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, 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 @@ -25,9 +25,13 @@ * @bug 8177552 8217254 8251499 8281317 * @summary Checks the validity of compact number patterns specified through * CompactNumberFormat constructor - * @run testng/othervm TestCompactPatternsValidity + * @run junit/othervm TestCompactPatternsValidity */ +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + import java.math.BigDecimal; import java.math.BigInteger; import java.text.CompactNumberFormat; @@ -35,9 +39,10 @@ import java.text.ParseException; import java.util.List; import java.util.Locale; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import static org.junit.jupiter.api.Assertions.assertThrows; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestCompactPatternsValidity { // Max range 10^4 @@ -74,7 +79,6 @@ public class TestCompactPatternsValidity { private static final String[] COMPACT_PATTERN14 = new String[]{"", "", "", "{one:Kun other:0' 'Kun}"}; // from Somali in CLDR 38 - @DataProvider(name = "invalidPatterns") Object[][] invalidCompactPatterns() { return new Object[][] { // compact patterns @@ -90,7 +94,6 @@ Object[][] invalidCompactPatterns() { }; } - @DataProvider(name = "validPatternsFormat") Object[][] validPatternsFormat() { return new Object[][] { // compact patterns, numbers, expected output @@ -116,7 +119,6 @@ Object[][] validPatternsFormat() { }; } - @DataProvider(name = "validPatternsParse") Object[][] validPatternsParse() { return new Object[][] { // compact patterns, parse string, expected output @@ -136,7 +138,6 @@ Object[][] validPatternsParse() { }; } - @DataProvider(name = "validPatternsFormatWithPluralRules") Object[][] validPatternsFormatWithPluralRules() { return new Object[][] { // compact patterns, plural rules, numbers, expected output @@ -144,7 +145,6 @@ Object[][] validPatternsFormatWithPluralRules() { }; } - @DataProvider(name = "validPatternsParseWithPluralRules") Object[][] validPatternsParseWithPluralRules() { return new Object[][] { // compact patterns, plural rules, parse string, expected output @@ -152,15 +152,18 @@ Object[][] validPatternsParseWithPluralRules() { }; } - @Test(dataProvider = "invalidPatterns", - expectedExceptions = IllegalArgumentException.class) - public void testInvalidCompactPatterns(String[] compactPatterns) { - new CompactNumberFormat("#,##0.0#", DecimalFormatSymbols - .getInstance(Locale.US), compactPatterns); + @ParameterizedTest + @MethodSource("invalidCompactPatterns") + void testInvalidCompactPatterns(String[] compactPatterns) { + assertThrows(IllegalArgumentException.class, () -> { + new CompactNumberFormat("#,##0.0#", DecimalFormatSymbols + .getInstance(Locale.US), compactPatterns); + }); } - @Test(dataProvider = "validPatternsFormat") - public void testValidPatternsFormat(String[] compactPatterns, + @ParameterizedTest + @MethodSource("validPatternsFormat") + void testValidPatternsFormat(String[] compactPatterns, List numbers, List expected) { CompactNumberFormat fmt = new CompactNumberFormat("#,##0.0#", DecimalFormatSymbols.getInstance(Locale.US), compactPatterns); @@ -170,8 +173,9 @@ public void testValidPatternsFormat(String[] compactPatterns, } } - @Test(dataProvider = "validPatternsParse") - public void testValidPatternsParse(String[] compactPatterns, + @ParameterizedTest + @MethodSource("validPatternsParse") + void testValidPatternsParse(String[] compactPatterns, List parseString, List numbers) throws ParseException { CompactNumberFormat fmt = new CompactNumberFormat("#,##0.0#", DecimalFormatSymbols.getInstance(Locale.US), compactPatterns); @@ -181,8 +185,9 @@ public void testValidPatternsParse(String[] compactPatterns, } } - @Test(dataProvider = "validPatternsFormatWithPluralRules") - public void testValidPatternsFormatWithPluralRules(String[] compactPatterns, String pluralRules, + @ParameterizedTest + @MethodSource("validPatternsFormatWithPluralRules") + void testValidPatternsFormatWithPluralRules(String[] compactPatterns, String pluralRules, List numbers, List expected) { CompactNumberFormat fmt = new CompactNumberFormat("#,##0.0#", DecimalFormatSymbols.getInstance(Locale.US), compactPatterns, pluralRules); @@ -192,8 +197,9 @@ public void testValidPatternsFormatWithPluralRules(String[] compactPatterns, Str } } - @Test(dataProvider = "validPatternsParseWithPluralRules") - public void testValidPatternsParsewithPluralRules(String[] compactPatterns, String pluralRules, + @ParameterizedTest + @MethodSource("validPatternsParseWithPluralRules") + void testValidPatternsParsewithPluralRules(String[] compactPatterns, String pluralRules, List parseString, List numbers) throws ParseException { CompactNumberFormat fmt = new CompactNumberFormat("#,##0.0#", DecimalFormatSymbols.getInstance(Locale.US), compactPatterns, pluralRules); diff --git a/test/jdk/java/text/Format/CompactNumberFormat/TestEquality.java b/test/jdk/java/text/Format/CompactNumberFormat/TestEquality.java index 584f8c2c9bd..2ced18be171 100644 --- a/test/jdk/java/text/Format/CompactNumberFormat/TestEquality.java +++ b/test/jdk/java/text/Format/CompactNumberFormat/TestEquality.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, 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 @@ -20,25 +20,26 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + /* * @test * @bug 8177552 8222756 8327640 * @summary Checks the equals and hashCode method of CompactNumberFormat * @modules jdk.localedata - * @run testng/othervm TestEquality - * + * @run junit/othervm TestEquality */ +import org.junit.jupiter.api.Test; + import java.text.CompactNumberFormat; import java.text.DecimalFormatSymbols; import java.text.NumberFormat; import java.util.Locale; -import org.testng.annotations.Test; public class TestEquality { @Test - public void testEquality() { + void testEquality() { CompactNumberFormat cnf1 = (CompactNumberFormat) NumberFormat .getCompactNumberInstance(Locale.US, NumberFormat.Style.SHORT); @@ -160,7 +161,7 @@ private void checkEquals(CompactNumberFormat cnf1, CompactNumberFormat cnf2, } @Test - public void testHashCode() { + void testHashCode() { NumberFormat cnf1 = NumberFormat .getCompactNumberInstance(Locale.JAPAN, NumberFormat.Style.SHORT); NumberFormat cnf2 = NumberFormat @@ -175,7 +176,7 @@ public void testHashCode() { // Test the property of equals and hashCode i.e. two equal object must // always have the same hashCode @Test - public void testEqualsAndHashCode() { + void testEqualsAndHashCode() { NumberFormat cnf1 = NumberFormat .getCompactNumberInstance(Locale.of("hi", "IN"), NumberFormat.Style.SHORT); cnf1.setMinimumIntegerDigits(5); diff --git a/test/jdk/java/text/Format/CompactNumberFormat/TestFormatToCharacterIterator.java b/test/jdk/java/text/Format/CompactNumberFormat/TestFormatToCharacterIterator.java index fb18fa256ab..beb6c38aca8 100644 --- a/test/jdk/java/text/Format/CompactNumberFormat/TestFormatToCharacterIterator.java +++ b/test/jdk/java/text/Format/CompactNumberFormat/TestFormatToCharacterIterator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, 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 @@ -20,14 +20,20 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + /* * @test * @bug 8177552 * @summary Checks the functioning of * CompactNumberFormat.formatToCharacterIterator method * @modules jdk.localedata - * @run testng/othervm TestFormatToCharacterIterator + * @run junit/othervm TestFormatToCharacterIterator */ + +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + import java.math.BigDecimal; import java.math.BigInteger; import java.text.AttributedCharacterIterator; @@ -36,10 +42,10 @@ import java.text.NumberFormat; import java.util.Locale; import java.util.Set; -import static org.testng.Assert.assertEquals; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestFormatToCharacterIterator { private static final NumberFormat FORMAT_DZ = NumberFormat @@ -54,7 +60,6 @@ public class TestFormatToCharacterIterator { .getCompactNumberInstance(Locale.ENGLISH, NumberFormat.Style.LONG); - @DataProvider(name = "fieldPositions") Object[][] compactFieldPositionData() { return new Object[][]{ // compact format instance, number, resulted string, attributes/fields, attribute positions @@ -149,22 +154,23 @@ Object[][] compactFieldPositionData() { }; } - @Test(dataProvider = "fieldPositions") - public void testFormatToCharacterIterator(NumberFormat fmt, Object number, + @ParameterizedTest + @MethodSource("compactFieldPositionData") + void testFormatToCharacterIterator(NumberFormat fmt, Object number, String expected, Format.Field[] expectedFields, int[] positions) { AttributedCharacterIterator iterator = fmt.formatToCharacterIterator(number); - assertEquals(getText(iterator), expected, "Incorrect formatting of the number '" + assertEquals(expected, getText(iterator), "Incorrect formatting of the number '" + number + "'"); iterator.first(); // Check start and end index of the formatted string - assertEquals(iterator.getBeginIndex(), 0, "Incorrect start index: " + assertEquals(0, iterator.getBeginIndex(), "Incorrect start index: " + iterator.getBeginIndex() + " of the formatted string: " + expected); - assertEquals(iterator.getEndIndex(), expected.length(), "Incorrect end index: " + assertEquals(expected.length(), iterator.getEndIndex(), "Incorrect end index: " + iterator.getEndIndex() + " of the formatted string: " + expected); // Check the attributes returned by the formatToCharacterIterator - assertEquals(iterator.getAllAttributeKeys(), Set.of(expectedFields), + assertEquals(Set.of(expectedFields), iterator.getAllAttributeKeys(), "Attributes do not match while formatting number: " + number); // Check the begin and end index for attributes @@ -173,10 +179,10 @@ public void testFormatToCharacterIterator(NumberFormat fmt, Object number, do { int start = iterator.getRunStart(); int end = iterator.getRunLimit(); - assertEquals(start, positions[currentPosition], + assertEquals(positions[currentPosition], start, "Incorrect start position for the attribute(s): " + iterator.getAttributes().keySet()); - assertEquals(end, positions[currentPosition + 1], + assertEquals(positions[currentPosition + 1], end, "Incorrect end position for the attribute(s): " + iterator.getAttributes().keySet()); currentPosition = currentPosition + 2; diff --git a/test/jdk/java/text/Format/CompactNumberFormat/TestMutatingInstance.java b/test/jdk/java/text/Format/CompactNumberFormat/TestMutatingInstance.java index 47b176692fd..4cf5ce12f16 100644 --- a/test/jdk/java/text/Format/CompactNumberFormat/TestMutatingInstance.java +++ b/test/jdk/java/text/Format/CompactNumberFormat/TestMutatingInstance.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, 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 @@ -20,6 +20,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + /* * @test * @bug 8177552 @@ -27,8 +28,14 @@ * formatting parameters. For example, min fraction digits, grouping * size etc. * @modules jdk.localedata - * @run testng/othervm TestMutatingInstance + * @run junit/othervm TestMutatingInstance */ + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + import java.math.BigDecimal; import java.math.BigInteger; import java.text.CompactNumberFormat; @@ -36,10 +43,8 @@ import java.text.NumberFormat; import java.text.ParseException; import java.util.Locale; -import org.testng.annotations.BeforeTest; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestMutatingInstance { private static final NumberFormat FORMAT_FRACTION = NumberFormat @@ -61,8 +66,8 @@ public class TestMutatingInstance { "#,##0.0#", DecimalFormatSymbols.getInstance(Locale.US), new String[]{"", "", "", "", "00K", "", "", "", "", "", "", "", "", "", ""}); - @BeforeTest - public void mutateInstances() { + @BeforeAll + void mutateInstances() { FORMAT_FRACTION.setMinimumFractionDigits(2); FORMAT_GROUPING.setGroupingSize(3); FORMAT_GROUPING.setGroupingUsed(true); @@ -75,7 +80,6 @@ public void mutateInstances() { FORMAT_NO_PATTERNS.setMinimumFractionDigits(2); } - @DataProvider(name = "format") Object[][] compactFormatData() { return new Object[][]{ {FORMAT_FRACTION, 1900, "1.90 thousand"}, @@ -95,7 +99,6 @@ Object[][] compactFormatData() { {FORMAT_NO_PATTERNS, new BigDecimal(12346567890987654.32), "12,346,567,890,987,654"},}; } - @DataProvider(name = "parse") Object[][] compactParseData() { return new Object[][]{ {FORMAT_FRACTION, "190 thousand", 190000L}, @@ -106,14 +109,16 @@ Object[][] compactParseData() { {FORMAT_PARSEINTONLY, "12.345 thousand", 12000L},}; } - @Test(dataProvider = "format") - public void formatCompactNumber(NumberFormat nf, + @ParameterizedTest + @MethodSource("compactFormatData") + void formatCompactNumber(NumberFormat nf, Object number, String expected) { CompactFormatAndParseHelper.testFormat(nf, number, expected); } - @Test(dataProvider = "parse") - public void parseCompactNumber(NumberFormat nf, + @ParameterizedTest + @MethodSource("compactParseData") + void parseCompactNumber(NumberFormat nf, String parseString, Number expected) throws ParseException { CompactFormatAndParseHelper.testParse(nf, parseString, expected, null, null); } diff --git a/test/jdk/java/text/Format/CompactNumberFormat/TestParseBigDecimal.java b/test/jdk/java/text/Format/CompactNumberFormat/TestParseBigDecimal.java index dc88ce4de4a..422ced9d999 100644 --- a/test/jdk/java/text/Format/CompactNumberFormat/TestParseBigDecimal.java +++ b/test/jdk/java/text/Format/CompactNumberFormat/TestParseBigDecimal.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, 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 @@ -20,17 +20,19 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + /* * @test * @bug 8177552 8306116 8319990 * @summary Checks CNF.parse() when parseBigDecimal is set to true * @modules jdk.localedata - * @run testng/othervm TestParseBigDecimal + * @run junit/othervm TestParseBigDecimal */ -import org.testng.annotations.BeforeTest; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; import java.math.BigDecimal; import java.text.CompactNumberFormat; @@ -38,6 +40,7 @@ import java.text.ParseException; import java.util.Locale; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestParseBigDecimal { private static final CompactNumberFormat FORMAT_DZ_LONG = (CompactNumberFormat) NumberFormat @@ -64,8 +67,8 @@ public class TestParseBigDecimal { private static final CompactNumberFormat FORMAT_SE_SHORT = (CompactNumberFormat) NumberFormat .getCompactNumberInstance(Locale.of("se"), NumberFormat.Style.SHORT); - @BeforeTest - public void mutateInstances() { + @BeforeAll + void mutateInstances() { FORMAT_DZ_LONG.setParseBigDecimal(true); FORMAT_EN_US_SHORT.setParseBigDecimal(true); FORMAT_EN_LONG.setParseBigDecimal(true); @@ -76,7 +79,6 @@ public void mutateInstances() { FORMAT_SE_SHORT.setParseBigDecimal(true); } - @DataProvider(name = "parse") Object[][] compactParseData() { return new Object[][]{ // compact number format instance, string to parse, parsed number @@ -165,8 +167,9 @@ Object[][] compactParseData() { {FORMAT_SE_SHORT, "\u221212345679,89\u00a0bn", new BigDecimal("-12345679890000000000.00")},}; } - @Test(dataProvider = "parse") - public void testParse(NumberFormat cnf, String parseString, + @ParameterizedTest + @MethodSource("compactParseData") + void testParse(NumberFormat cnf, String parseString, Number expected) throws ParseException { CompactFormatAndParseHelper.testParse(cnf, parseString, expected, null, BigDecimal.class); } diff --git a/test/jdk/java/text/Format/CompactNumberFormat/TestPlurals.java b/test/jdk/java/text/Format/CompactNumberFormat/TestPlurals.java index bbaaa701d23..b8beb6135dd 100644 --- a/test/jdk/java/text/Format/CompactNumberFormat/TestPlurals.java +++ b/test/jdk/java/text/Format/CompactNumberFormat/TestPlurals.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 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 @@ -20,21 +20,27 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + /* * @test * @bug 8222756 * @summary Tests plurals support in CompactNumberFormat - * @run testng/othervm TestPlurals + * @run junit/othervm TestPlurals */ +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + import java.text.CompactNumberFormat; import java.text.DecimalFormatSymbols; import java.util.Locale; -import static org.testng.Assert.*; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestPlurals { private final static DecimalFormatSymbols DFS = DecimalFormatSymbols.getInstance(Locale.ROOT); @@ -45,7 +51,6 @@ public class TestPlurals { private final static String RULE_3 = "one:n%2=0andn/3=2;"; - @DataProvider Object[][] pluralRules() { return new Object[][]{ // rules, number, expected @@ -78,7 +83,6 @@ Object[][] pluralRules() { }; } - @DataProvider Object[][] invalidRules() { return new Object [][] { {"one:a = 1"}, @@ -92,27 +96,34 @@ Object[][] invalidRules() { }; } - @Test(expectedExceptions = NullPointerException.class) - public void testNullPluralRules() { - String[] pattern = {""}; - new CompactNumberFormat("#", DFS, PATTERN, null); + @Test + void testNullPluralRules() { + assertThrows(NullPointerException.class, () -> { + String[] pattern = {""}; + new CompactNumberFormat("#", DFS, PATTERN, null); + }); } - @Test(dataProvider = "pluralRules") - public void testPluralRules(String rules, Number n, String expected) { + @ParameterizedTest + @MethodSource("pluralRules") + void testPluralRules(String rules, Number n, String expected) { var cnp = new CompactNumberFormat("#", DFS, PATTERN, rules); - assertEquals(cnp.format(n), expected); + assertEquals(expected, cnp.format(n)); } - @Test(dataProvider = "invalidRules", expectedExceptions = IllegalArgumentException.class) - public void testInvalidRules(String rules) { - new CompactNumberFormat("#", DFS, PATTERN, rules); + @ParameterizedTest + @MethodSource("invalidRules") + void testInvalidRules(String rules) { + assertThrows(IllegalArgumentException.class, + () -> new CompactNumberFormat("#", DFS, PATTERN, rules)); } - @Test(expectedExceptions = IllegalArgumentException.class) - public void testLimitExceedingRules() { - String andCond = " and n = 1"; - String invalid = "one: n = 1" + andCond.repeat(2_048 / andCond.length()); - new CompactNumberFormat("#", DFS, PATTERN, invalid); + @Test + void testLimitExceedingRules() { + assertThrows(IllegalArgumentException.class, () -> { + String andCond = " and n = 1"; + String invalid = "one: n = 1" + andCond.repeat(2_048 / andCond.length()); + new CompactNumberFormat("#", DFS, PATTERN, invalid); + }); } } diff --git a/test/jdk/java/text/Format/CompactNumberFormat/TestSpecialValues.java b/test/jdk/java/text/Format/CompactNumberFormat/TestSpecialValues.java index e8ac2489faf..9bd0ef73830 100644 --- a/test/jdk/java/text/Format/CompactNumberFormat/TestSpecialValues.java +++ b/test/jdk/java/text/Format/CompactNumberFormat/TestSpecialValues.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 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 @@ -20,25 +20,29 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + /* * @test * @bug 8177552 * @summary Checks the formatting and parsing of special values * @modules jdk.localedata - * @run testng/othervm TestSpecialValues + * @run junit/othervm TestSpecialValues */ + +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + import java.text.NumberFormat; import java.text.ParseException; import java.util.Locale; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestSpecialValues { private static final NumberFormat FORMAT = NumberFormat .getCompactNumberInstance(Locale.US, NumberFormat.Style.SHORT); - @DataProvider(name = "formatSpecialValues") Object[][] formatSpecialValues() { return new Object[][]{ // number , formatted ouput @@ -53,7 +57,6 @@ Object[][] formatSpecialValues() { {Long.MAX_VALUE, "9223372T"},}; } - @DataProvider(name = "parseSpecialValues") Object[][] parseSpecialValues() { return new Object[][]{ // parse string, parsed number @@ -65,13 +68,15 @@ Object[][] parseSpecialValues() { {"-\u221E", Double.NEGATIVE_INFINITY},}; } - @Test(dataProvider = "formatSpecialValues") - public void testFormatSpecialValues(Object number, String expected) { + @ParameterizedTest + @MethodSource("formatSpecialValues") + void testFormatSpecialValues(Object number, String expected) { CompactFormatAndParseHelper.testFormat(FORMAT, number, expected); } - @Test(dataProvider = "parseSpecialValues") - public void testParseSpecialValues(String parseString, Number expected) + @ParameterizedTest + @MethodSource("parseSpecialValues") + void testParseSpecialValues(String parseString, Number expected) throws ParseException { CompactFormatAndParseHelper.testParse(FORMAT, parseString, expected, null, null); } diff --git a/test/jdk/java/text/Format/CompactNumberFormat/TestUExtensionOverride.java b/test/jdk/java/text/Format/CompactNumberFormat/TestUExtensionOverride.java index 099e6978b0b..f77908d84c4 100644 --- a/test/jdk/java/text/Format/CompactNumberFormat/TestUExtensionOverride.java +++ b/test/jdk/java/text/Format/CompactNumberFormat/TestUExtensionOverride.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, 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 @@ -20,23 +20,27 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + /* * @test * @bug 8177552 8221432 * @summary Checks the behaviour of Unicode BCP 47 U Extension with * compact number format * @modules jdk.localedata - * @run testng/othervm TestUExtensionOverride + * @run junit/othervm TestUExtensionOverride */ + +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + import java.text.NumberFormat; import java.text.ParseException; import java.util.Locale; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestUExtensionOverride { - @DataProvider(name = "compactFormatData") Object[][] compactFormatData() { return new Object[][]{ // locale, number, formatted string @@ -61,7 +65,6 @@ Object[][] compactFormatData() { "\u0967\u0968\u00a0k"},}; } - @DataProvider(name = "compactParseData") Object[][] compactParseData() { return new Object[][]{ // locale, parse string, parsed number @@ -87,16 +90,18 @@ Object[][] compactParseData() { "\u0967\u0968\u00a0k", 12000L},}; } - @Test(dataProvider = "compactFormatData") - public void testFormat(Locale locale, double num, + @ParameterizedTest + @MethodSource("compactFormatData") + void testFormat(Locale locale, double num, String expected) { NumberFormat cnf = NumberFormat.getCompactNumberInstance(locale, NumberFormat.Style.SHORT); CompactFormatAndParseHelper.testFormat(cnf, num, expected); } - @Test(dataProvider = "compactParseData") - public void testParse(Locale locale, String parseString, + @ParameterizedTest + @MethodSource("compactParseData") + void testParse(Locale locale, String parseString, Number expected) throws ParseException { NumberFormat cnf = NumberFormat.getCompactNumberInstance(locale, NumberFormat.Style.SHORT); diff --git a/test/jdk/java/text/Format/CompactNumberFormat/serialization/TestDeserializeCNF.java b/test/jdk/java/text/Format/CompactNumberFormat/serialization/TestDeserializeCNF.java index 0b4710f0086..563ae307762 100644 --- a/test/jdk/java/text/Format/CompactNumberFormat/serialization/TestDeserializeCNF.java +++ b/test/jdk/java/text/Format/CompactNumberFormat/serialization/TestDeserializeCNF.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 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 @@ -28,11 +28,12 @@ * @summary Checks deserialization of compact number format * @library /java/text/testlib * @build TestDeserializeCNF HexDumpReader - * @run testng/othervm TestDeserializeCNF + * @run junit/othervm TestDeserializeCNF */ -import org.testng.annotations.BeforeTest; -import org.testng.annotations.Test; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; import java.io.IOException; import java.io.InputStream; @@ -41,8 +42,10 @@ import java.text.CompactNumberFormat; import java.text.DecimalFormatSymbols; import java.util.Locale; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.assertEquals; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestDeserializeCNF { // This object is serialized in cnf1.ser.txt with HALF_UP @@ -60,8 +63,8 @@ public class TestDeserializeCNF { private static final String FILE_COMPACT_FORMAT1 = "cnf1.ser.txt"; private static final String FILE_COMPACT_FORMAT2 = "cnf2.ser.txt"; - @BeforeTest - public void mutateInstances() { + @BeforeAll + void mutateInstances() { COMPACT_FORMAT1.setRoundingMode(RoundingMode.HALF_UP); COMPACT_FORMAT1.setGroupingSize(3); COMPACT_FORMAT1.setParseBigDecimal(true); @@ -71,18 +74,18 @@ public void mutateInstances() { } @Test - public void testDeserialization() throws IOException, ClassNotFoundException { + void testDeserialization() throws IOException, ClassNotFoundException { try (InputStream istream1 = HexDumpReader.getStreamFromHexDump(FILE_COMPACT_FORMAT1); ObjectInputStream ois1 = new ObjectInputStream(istream1); InputStream istream2 = HexDumpReader.getStreamFromHexDump(FILE_COMPACT_FORMAT2); ObjectInputStream ois2 = new ObjectInputStream(istream2);) { CompactNumberFormat obj1 = (CompactNumberFormat) ois1.readObject(); - assertEquals(obj1, COMPACT_FORMAT1, "Deserialized instance is not" + assertEquals(COMPACT_FORMAT1, obj1, "Deserialized instance is not" + " equal to the instance serialized in " + FILE_COMPACT_FORMAT1); CompactNumberFormat obj2 = (CompactNumberFormat) ois2.readObject(); - assertEquals(obj2, COMPACT_FORMAT2, "Deserialized instance is not" + assertEquals(COMPACT_FORMAT2, obj2, "Deserialized instance is not" + " equal to the instance serialized in " + FILE_COMPACT_FORMAT2); } } diff --git a/test/jdk/java/text/Format/CompactNumberFormat/serialization/TestSerialization.java b/test/jdk/java/text/Format/CompactNumberFormat/serialization/TestSerialization.java index 574e6dc7905..b3a8cbadc76 100644 --- a/test/jdk/java/text/Format/CompactNumberFormat/serialization/TestSerialization.java +++ b/test/jdk/java/text/Format/CompactNumberFormat/serialization/TestSerialization.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, 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 @@ -20,16 +20,18 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + /* * @test * @bug 8177552 8327640 * @modules jdk.localedata * @summary Checks the serialization feature of CompactNumberFormat - * @run testng/othervm TestSerialization + * @run junit/othervm TestSerialization */ -import org.testng.annotations.BeforeTest; -import org.testng.annotations.Test; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; import java.io.FileInputStream; import java.io.FileOutputStream; @@ -40,8 +42,10 @@ import java.text.CompactNumberFormat; import java.text.NumberFormat; import java.util.Locale; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.assertEquals; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class TestSerialization { private static final NumberFormat FORMAT_HI = NumberFormat.getCompactNumberInstance( @@ -57,8 +61,8 @@ public class TestSerialization { private static final NumberFormat FORMAT_KO_KR = NumberFormat.getCompactNumberInstance( Locale.KOREA, NumberFormat.Style.SHORT); - @BeforeTest - public void mutateInstances() { + @BeforeAll + void mutateInstances() { FORMAT_HI.setMinimumFractionDigits(2); FORMAT_HI.setMinimumIntegerDigits(5); @@ -81,7 +85,7 @@ public void mutateInstances() { } @Test - public void testSerialization() throws IOException, ClassNotFoundException { + void testSerialization() throws IOException, ClassNotFoundException { // Serialize serialize("cdf.ser", FORMAT_HI, FORMAT_EN_US, FORMAT_JA_JP, FORMAT_FR_FR, FORMAT_DE_DE, FORMAT_KO_KR); // Deserialize @@ -104,13 +108,13 @@ private static void deserialize(String fileName, NumberFormat... formats) new FileInputStream(fileName))) { for (NumberFormat fmt : formats) { NumberFormat obj = (NumberFormat) os.readObject(); - assertEquals(fmt, obj, "Serialized and deserialized" + assertEquals(obj, fmt, "Serialized and deserialized" + " objects do not match"); long number = 123456789789L; String expected = fmt.format(number); String actual = obj.format(number); - assertEquals(actual, expected, "Serialized and deserialized" + assertEquals(expected, actual, "Serialized and deserialized" + " objects are expected to return same formatted" + " output for number: " + number); } diff --git a/test/jdk/java/text/Format/DateFormat/Bug8193444.java b/test/jdk/java/text/Format/DateFormat/Bug8193444.java index 6c5007bc851..b2fac85dd8a 100644 --- a/test/jdk/java/text/Format/DateFormat/Bug8193444.java +++ b/test/jdk/java/text/Format/DateFormat/Bug8193444.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 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 @@ -20,29 +20,32 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + /* * @test * @bug 8193444 * @summary Checks SimpleDateFormat.format/parse for the AIOOB exception when * formatting/parsing dates through a pattern string that contains a * sequence of 256 or more non-ASCII unicode characters. - * @run testng/othervm Bug8193444 + * @run junit/othervm Bug8193444 */ -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; + +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; -import static org.testng.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class Bug8193444 { private static final String NON_ASCII_CHAR = "\u263A"; - @DataProvider(name = "dateFormat") Object[][] dateFormatData() { return new Object[][]{ // short_length (between 0 and 254) @@ -53,8 +56,9 @@ Object[][] dateFormatData() { {257},}; } - @Test(dataProvider = "dateFormat") - public void testDateFormatAndParse(int length) + @ParameterizedTest + @MethodSource("dateFormatData") + void testDateFormatAndParse(int length) throws ParseException { String pattern = NON_ASCII_CHAR.repeat(length); @@ -66,7 +70,7 @@ public void testDateFormatAndParse(int length) // Since the tested format patterns do not contain any character // representing date/time field, those characters are not interpreted, // they are simply copied into the output string during formatting - assertEquals(result, pattern, "Failed to format the date using" + assertEquals(pattern, result, "Failed to format the date using" + " pattern of length: " + length); // The format pattern used by this SimpleDateFormat diff --git a/test/jdk/java/text/Format/DateFormat/CaseInsensitiveParseTest.java b/test/jdk/java/text/Format/DateFormat/CaseInsensitiveParseTest.java index 2331e36b2f9..51473710dbb 100644 --- a/test/jdk/java/text/Format/DateFormat/CaseInsensitiveParseTest.java +++ b/test/jdk/java/text/Format/DateFormat/CaseInsensitiveParseTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 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,14 +21,18 @@ * questions. */ -/** +/* * @test * @bug 8248434 * @modules jdk.localedata - * @run testng/othervm CaseInsensitiveParseTest * @summary Checks format/parse round trip in case-insensitive manner. + * @run junit/othervm CaseInsensitiveParseTest */ +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; @@ -37,36 +41,36 @@ import java.util.Locale; import java.util.stream.Stream; -import static org.testng.Assert.assertEquals; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class CaseInsensitiveParseTest { private final static String PATTERN = "GGGG/yyyy/MMMM/dddd/hhhh/mmmm/ss/aaaa"; private final static Date EPOCH = new Date(0L); - @DataProvider - private Object[][] locales() { + Object[][] locales() { return (Object[][])Arrays.stream(DateFormat.getAvailableLocales()) .map(Stream::of) .map(Stream::toArray) .toArray(Object[][]::new); } - @Test(dataProvider = "locales") - public void testUpperCase(Locale loc) throws ParseException { + @ParameterizedTest + @MethodSource("locales") + void testUpperCase(Locale loc) throws ParseException { SimpleDateFormat sdf = new SimpleDateFormat(PATTERN, loc); String formatted = sdf.format(EPOCH); - assertEquals(sdf.parse(formatted.toUpperCase(Locale.ROOT)), EPOCH, + assertEquals(EPOCH, sdf.parse(formatted.toUpperCase(Locale.ROOT)), "roundtrip failed for string '" + formatted + "', locale: " + loc); } - @Test(dataProvider = "locales") - public void testLowerCase(Locale loc) throws ParseException { + @ParameterizedTest + @MethodSource("locales") + void testLowerCase(Locale loc) throws ParseException { SimpleDateFormat sdf = new SimpleDateFormat(PATTERN, loc); String formatted = sdf.format(EPOCH); - assertEquals(sdf.parse(formatted.toLowerCase(Locale.ROOT)), EPOCH, + assertEquals(EPOCH, sdf.parse(formatted.toLowerCase(Locale.ROOT)), "roundtrip failed for string '" + formatted + "', locale: " + loc); } } diff --git a/test/jdk/java/text/Format/DateFormat/LocaleDateFormats.java b/test/jdk/java/text/Format/DateFormat/LocaleDateFormats.java index f5ebdccb91f..6ddddb2058d 100644 --- a/test/jdk/java/text/Format/DateFormat/LocaleDateFormats.java +++ b/test/jdk/java/text/Format/DateFormat/LocaleDateFormats.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 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,34 +21,38 @@ * questions. */ -/** +/* * @test * @bug 8080774 8174269 * @modules jdk.localedata - * @run testng LocaleDateFormats * @summary This file contains tests for JRE locales date formats + * @run junit LocaleDateFormats */ +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + import java.text.DateFormat; import java.util.Calendar; import java.util.Locale; -import static org.testng.Assert.assertEquals; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class LocaleDateFormats { - @Test(dataProvider = "dateFormats") - public void testDateFormat(Locale loc, int style, int year, int month, int date, String expectedString) { + @ParameterizedTest + @MethodSource("dateFormats") + void testDateFormat(Locale loc, int style, int year, int month, int date, String expectedString) { Calendar cal = Calendar.getInstance(loc); cal.set(year, month-1, date); // Create date formatter based on requested style and test locale DateFormat df = DateFormat.getDateInstance(style, loc); // Test the date format - assertEquals(df.format(cal.getTime()), expectedString); + assertEquals(expectedString, df.format(cal.getTime())); } - @DataProvider(name = "dateFormats" ) private Object[][] dateFormats() { return new Object[][] { //8080774 diff --git a/test/jdk/java/text/Format/DateFormat/SimpleDateFormatPatternTest.java b/test/jdk/java/text/Format/DateFormat/SimpleDateFormatPatternTest.java index bcf0022b092..e8ff262e0ab 100644 --- a/test/jdk/java/text/Format/DateFormat/SimpleDateFormatPatternTest.java +++ b/test/jdk/java/text/Format/DateFormat/SimpleDateFormatPatternTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 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 @@ -21,21 +21,25 @@ * questions. */ -/** +/* * @test * @bug 4326988 6990146 8231213 * @summary test SimpleDateFormat, check its pattern in the constructor - * @run testng/othervm SimpleDateFormatPatternTest + * @run junit/othervm SimpleDateFormatPatternTest */ -import java.lang.IllegalArgumentException; + +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + import java.text.DateFormat; import java.text.DateFormatSymbols; import java.text.SimpleDateFormat; import java.util.Locale; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import static org.junit.jupiter.api.Assertions.assertThrows; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class SimpleDateFormatPatternTest { private static String[] validPat = { "yyyy-MM-dd h.mm.ss.a z", @@ -136,90 +140,104 @@ private static Object[][] createPatternObj(String[] pattern){ return objArray; } - @DataProvider(name = "dfAllLocalesObj") Object[][] dfAllLocalesObj() { return dfAllLocalesObj; } - @DataProvider(name = "invalidPatternObj") Object[][] invalidPatternObj() { return invalidPatObj; } - @DataProvider(name = "validPatternObj") Object[][] validPatternObj() { return validPatObj; } //check Constructors for invalid pattern - @Test(dataProvider = "invalidPatternObj", - expectedExceptions = IllegalArgumentException.class) - public void testIllegalArgumentException1(String pattern, Locale loc) + @ParameterizedTest + @MethodSource("invalidPatternObj") + void testIllegalArgumentException1(String pattern, Locale loc) throws IllegalArgumentException { - Locale.setDefault(loc); - new SimpleDateFormat(pattern); + assertThrows(IllegalArgumentException.class, () -> { + Locale.setDefault(loc); + new SimpleDateFormat(pattern); + }); } - @Test(dataProvider = "invalidPatternObj", - expectedExceptions = IllegalArgumentException.class) - public void testIllegalArgumentException2(String pattern, Locale loc) + @ParameterizedTest + @MethodSource("invalidPatternObj") + void testIllegalArgumentException2(String pattern, Locale loc) throws IllegalArgumentException { - Locale.setDefault(loc); - new SimpleDateFormat(pattern, new DateFormatSymbols()); + assertThrows(IllegalArgumentException.class, () -> { + Locale.setDefault(loc); + new SimpleDateFormat(pattern, new DateFormatSymbols()); + }); } - @Test(dataProvider = "invalidPatternObj", - expectedExceptions = IllegalArgumentException.class) - public void testIllegalArgumentException3 (String pattern, Locale loc) + @ParameterizedTest + @MethodSource("invalidPatternObj") + void testIllegalArgumentException3 (String pattern, Locale loc) throws IllegalArgumentException { - Locale.setDefault(loc); - new SimpleDateFormat(pattern, Locale.getDefault()); + assertThrows(IllegalArgumentException.class, () -> { + Locale.setDefault(loc); + new SimpleDateFormat(pattern, Locale.getDefault()); + }); } - @Test(dataProvider = "invalidPatternObj", - expectedExceptions = IllegalArgumentException.class) - public void testIllegalArgumentException4(String pattern, Locale loc) + @ParameterizedTest + @MethodSource("invalidPatternObj") + void testIllegalArgumentException4(String pattern, Locale loc) throws IllegalArgumentException { - Locale.setDefault(loc); - new SimpleDateFormat().applyPattern(pattern); + assertThrows(IllegalArgumentException.class, () -> { + Locale.setDefault(loc); + new SimpleDateFormat().applyPattern(pattern); + }); } //check Constructors for null pattern - @Test(dataProvider = "dfAllLocalesObj", - expectedExceptions = NullPointerException.class) - public void testNullPointerException1(Locale loc) + @ParameterizedTest + @MethodSource("dfAllLocalesObj") + void testNullPointerException1(Locale loc) throws NullPointerException { - Locale.setDefault(loc); - new SimpleDateFormat(null); + assertThrows(NullPointerException.class, () -> { + Locale.setDefault(loc); + new SimpleDateFormat(null); + }); } - @Test(dataProvider = "dfAllLocalesObj", - expectedExceptions = NullPointerException.class) - public void testNullPointerException2(Locale loc) + @ParameterizedTest + @MethodSource("dfAllLocalesObj") + void testNullPointerException2(Locale loc) throws NullPointerException { - Locale.setDefault(loc); - new SimpleDateFormat(null, new DateFormatSymbols()); + assertThrows(NullPointerException.class, () -> { + Locale.setDefault(loc); + new SimpleDateFormat(null, new DateFormatSymbols()); + }); } - @Test(dataProvider = "dfAllLocalesObj", - expectedExceptions = NullPointerException.class) - public void testNullPointerException3(Locale loc) + @ParameterizedTest + @MethodSource("dfAllLocalesObj") + void testNullPointerException3(Locale loc) throws NullPointerException { - Locale.setDefault(loc); - new SimpleDateFormat(null, Locale.getDefault()); + assertThrows(NullPointerException.class, () -> { + Locale.setDefault(loc); + new SimpleDateFormat(null, Locale.getDefault()); + }); } - @Test(dataProvider = "dfAllLocalesObj", - expectedExceptions = NullPointerException.class) - public void testNullPointerException4(Locale loc) + @ParameterizedTest + @MethodSource("dfAllLocalesObj") + void testNullPointerException4(Locale loc) throws NullPointerException { - Locale.setDefault(loc); - new SimpleDateFormat().applyPattern(null); + assertThrows(NullPointerException.class, () -> { + Locale.setDefault(loc); + new SimpleDateFormat().applyPattern(null); + }); } - @Test(dataProvider = "validPatternObj") + @ParameterizedTest //check Constructors for valid pattern - public void testValidPattern(String pattern, Locale loc) { + @MethodSource("validPatternObj") + void testValidPattern(String pattern, Locale loc) { Locale.setDefault(loc); new SimpleDateFormat(pattern); new SimpleDateFormat(pattern, new DateFormatSymbols()); diff --git a/test/jdk/java/text/Format/DecimalFormat/CloneTest.java b/test/jdk/java/text/Format/DecimalFormat/CloneTest.java index f11d576a39a..dabdd137f5f 100644 --- a/test/jdk/java/text/Format/DecimalFormat/CloneTest.java +++ b/test/jdk/java/text/Format/DecimalFormat/CloneTest.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8354522 8358880 + * @bug 8354522 8358880 8367324 * @summary Check for cloning interference * @library /test/lib * @run junit/othervm --add-opens=java.base/java.text=ALL-UNNAMED CloneTest @@ -89,12 +89,6 @@ public void testClone() { Object digits = valFromDigitList(original, "digits"); assertNotSame(digits, valFromDigitList(dfClone, "digits")); - - Object data = valFromDigitList(original, "data"); - if (data != null) { - assertNotSame(data, valFromDigitList(dfClone, "data")); - } - assertEquals(digitListField.get(original), digitListField.get(dfClone)); } catch (ReflectiveOperationException e) { throw new SkippedException("reflective access in white-box test failed", e); diff --git a/test/jdk/java/text/Format/DecimalFormat/SetGroupingSizeTest.java b/test/jdk/java/text/Format/DecimalFormat/SetGroupingSizeTest.java index 07982b453c9..95044341290 100644 --- a/test/jdk/java/text/Format/DecimalFormat/SetGroupingSizeTest.java +++ b/test/jdk/java/text/Format/DecimalFormat/SetGroupingSizeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 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 @@ -26,28 +26,27 @@ * @bug 8212749 * @summary test whether input value check for * DecimalFormat.setGroupingSize(int) works correctly. - * @run testng/othervm SetGroupingSizeTest + * @run junit/othervm SetGroupingSizeTest */ +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + import java.text.DecimalFormat; -import static org.testng.Assert.assertEquals; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; -@Test public class SetGroupingSizeTest { - @DataProvider - public static Object[][] validGroupingSizes() { + static Object[][] validGroupingSizes() { return new Object[][] { { 0 }, { Byte.MAX_VALUE }, }; } - @DataProvider - public static Object[][] invalidGroupingSizes() { + static Object[][] invalidGroupingSizes() { return new Object[][] { { Byte.MIN_VALUE - 1 }, { Byte.MIN_VALUE }, @@ -58,17 +57,20 @@ public static Object[][] invalidGroupingSizes() { }; } - @Test(dataProvider = "validGroupingSizes") - public void test_validGroupingSize(int newVal) { + @ParameterizedTest + @MethodSource("validGroupingSizes") + void test_validGroupingSize(int newVal) { DecimalFormat df = new DecimalFormat(); df.setGroupingSize(newVal); - assertEquals(df.getGroupingSize(), newVal); + assertEquals(newVal, df.getGroupingSize()); } - @Test(dataProvider = "invalidGroupingSizes", - expectedExceptions = IllegalArgumentException.class) - public void test_invalidGroupingSize(int newVal) { - DecimalFormat df = new DecimalFormat(); - df.setGroupingSize(newVal); + @ParameterizedTest + @MethodSource("invalidGroupingSizes") + void test_invalidGroupingSize(int newVal) { + assertThrows(IllegalArgumentException.class, () -> { + DecimalFormat df = new DecimalFormat(); + df.setGroupingSize(newVal); + }); } } diff --git a/test/jdk/java/text/Format/NumberFormat/DFSMinusPerCentMill.java b/test/jdk/java/text/Format/NumberFormat/DFSMinusPerCentMill.java index a36eaf5f14f..418802261ff 100644 --- a/test/jdk/java/text/Format/NumberFormat/DFSMinusPerCentMill.java +++ b/test/jdk/java/text/Format/NumberFormat/DFSMinusPerCentMill.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 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 @@ -21,7 +21,7 @@ * questions. */ -/** +/* * @test * @bug 8220309 8230284 * @library /java/text/testlib @@ -29,17 +29,26 @@ * This test assumes CLDR has numbering systems for "arab" and * "arabext", and their minus/percent representations include * BiDi formatting control characters. - * @run testng/othervm DFSMinusPerCentMill + * @run junit/othervm DFSMinusPerCentMill */ -import java.io.*; -import java.util.*; -import java.text.*; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.text.NumberFormat; +import java.util.Locale; -import static org.testng.Assert.*; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class DFSMinusPerCentMill { private enum Type { NUMBER, PERCENT, CURRENCY, INTEGER, COMPACT, PERMILL @@ -49,7 +58,6 @@ private enum Type { private static final Locale US_ARABEXT = Locale.forLanguageTag("en-US-u-nu-arabext"); private static final double SRC_NUM = -1234.56; - @DataProvider Object[][] formatData() { return new Object[][] { // Locale, FormatStyle, expected format, expected single char symbol @@ -69,7 +77,6 @@ Object[][] formatData() { }; } - @DataProvider Object[][] charSymbols() { return new Object[][]{ // Locale, percent, per mille, minus sign @@ -78,8 +85,9 @@ Object[][] charSymbols() { }; } - @Test(dataProvider="formatData") - public void testFormatData(Locale l, Type style, String expected) { + @ParameterizedTest + @MethodSource("formatData") + void testFormatData(Locale l, Type style, String expected) { NumberFormat nf = null; switch (style) { case NUMBER: @@ -102,19 +110,20 @@ public void testFormatData(Locale l, Type style, String expected) { break; } - assertEquals(nf.format(SRC_NUM), expected); + assertEquals(expected, nf.format(SRC_NUM)); } - @Test(dataProvider="charSymbols") - public void testCharSymbols(Locale l, char percent, char permill, char minus) { + @ParameterizedTest + @MethodSource("charSymbols") + void testCharSymbols(Locale l, char percent, char permill, char minus) { DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(l); - assertEquals(dfs.getPercent(), percent); - assertEquals(dfs.getPerMill(), permill); - assertEquals(dfs.getMinusSign(), minus); + assertEquals(percent, dfs.getPercent()); + assertEquals(permill, dfs.getPerMill()); + assertEquals(minus, dfs.getMinusSign()); } @Test - public void testSerialization() throws Exception { + void testSerialization() throws Exception { DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(); ByteArrayOutputStream bos = new ByteArrayOutputStream(); new ObjectOutputStream(bos).writeObject(dfs); @@ -122,7 +131,7 @@ public void testSerialization() throws Exception { new ByteArrayInputStream(bos.toByteArray()) ).readObject(); - assertEquals(dfs, dfsSerialized); + assertEquals(dfsSerialized, dfs); // set minus/percent/permille dfs.setMinusSign('a'); @@ -134,6 +143,6 @@ public void testSerialization() throws Exception { new ByteArrayInputStream(bos.toByteArray()) ).readObject(); - assertEquals(dfs, dfsSerialized); + assertEquals(dfsSerialized, dfs); } } diff --git a/test/jdk/java/text/Format/NumberFormat/NumberRegression.java b/test/jdk/java/text/Format/NumberFormat/NumberRegression.java index dcc87643b2b..1b3452012cd 100644 --- a/test/jdk/java/text/Format/NumberFormat/NumberRegression.java +++ b/test/jdk/java/text/Format/NumberFormat/NumberRegression.java @@ -29,7 +29,8 @@ * 4098741 4099404 4101481 4106658 4106662 4106664 4108738 4110936 4122840 * 4125885 4134034 4134300 4140009 4141750 4145457 4147295 4147706 4162198 * 4162852 4167494 4170798 4176114 4179818 4212072 4212073 4216742 4217661 - * 4243011 4243108 4330377 4233840 4241880 4833877 8008577 8227313 8174269 + * 4243011 4243108 4330377 4233840 4241880 4833877 6177299 8008577 8227313 + * 8174269 * @summary Regression tests for NumberFormat and associated classes * @library /java/text/testlib * @build HexDumpReader TestUtils @@ -56,10 +57,13 @@ import java.math.BigDecimal; import java.io.*; import java.math.BigInteger; + import sun.util.resources.LocaleData; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.fail; public class NumberRegression { @@ -1847,6 +1851,41 @@ public void test8227313() throws ParseException { ", got: " + parsed); } } + + /** + * 6177299: DecimalFormat w/ multiplier applied may incorrectly return + * a Double as Long.MAX_VALUE. + */ + @Test + void largePosParseTest() { + var df = NumberFormat.getPercentInstance(Locale.ENGLISH); // Default w/ multiplier 100 + // Parsed string after multiplier applied is beyond long range + assertEquals(9.223372036854777E18, + assertDoesNotThrow(() -> df.parse("922,337,203,685,477,700,000%"))); + // Fails before 6177299 fix and returns as long + assertEquals(9.223372036854776E18, + assertDoesNotThrow(() -> df.parse("922,337,203,685,477,600,000%"))); + // Within long range -> Expect to get longs as long as ulp >= 1 + assertEquals((long) 9.223372036854775E18, + assertDoesNotThrow(() -> df.parse("922,337,203,685,477,500,000%"))); + } + + /** + * 6177299: Negative version of above test. + */ + @Test + void largeNegParseTest() { + var df = NumberFormat.getPercentInstance(Locale.ENGLISH); // Default w/ multiplier 100 + // Parsed string after multiplier applied is beyond long range + assertEquals(-9.223372036854777E18, + assertDoesNotThrow(() -> df.parse("-922,337,203,685,477,700,000%"))); + // Fails before 6177299 fix and returns as long + assertEquals(-9.223372036854776E18, + assertDoesNotThrow(() -> df.parse("-922,337,203,685,477,600,000%"))); + // Within long range -> Expect to get longs as long as ulp >= 1 + assertEquals((long) -9.223372036854775E18, + assertDoesNotThrow(() -> df.parse("-922,337,203,685,477,500,000%"))); + } } @SuppressWarnings("serial") diff --git a/test/jdk/java/text/Normalizer/SquareEraCharacterTest.java b/test/jdk/java/text/Normalizer/SquareEraCharacterTest.java index 7367badd811..9b669880fe9 100644 --- a/test/jdk/java/text/Normalizer/SquareEraCharacterTest.java +++ b/test/jdk/java/text/Normalizer/SquareEraCharacterTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 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 @@ -25,20 +25,20 @@ * @test * @bug 8221431 * @summary Tests decomposition of Japanese square era characters. - * @run testng/othervm SquareEraCharacterTest + * @run junit/othervm SquareEraCharacterTest */ -import static org.testng.Assert.assertEquals; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; import java.text.Normalizer; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; -@Test +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class SquareEraCharacterTest { - @DataProvider Object[][] squareEras() { return new Object[][] { @@ -51,12 +51,10 @@ Object[][] squareEras() { }; } - @Test(dataProvider="squareEras") - public void test_normalize(char squareChar, String expected) { - - assertEquals( - Normalizer.normalize(Character.toString(squareChar), Normalizer.Form.NFKD), - expected, + @ParameterizedTest + @MethodSource("squareEras") + void test_normalize(char squareChar, String expected) { + assertEquals(expected, Normalizer.normalize(Character.toString(squareChar), Normalizer.Form.NFKD), "decomposing " + Character.getName(squareChar) + "."); } } diff --git a/test/jdk/javax/net/ssl/DTLS/FragmentedFinished.java b/test/jdk/javax/net/ssl/DTLS/FragmentedFinished.java new file mode 100644 index 00000000000..2b6fd16005c --- /dev/null +++ b/test/jdk/javax/net/ssl/DTLS/FragmentedFinished.java @@ -0,0 +1,72 @@ +/* + * 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. + */ + +// SunJSSE does not support dynamic system properties, no way to re-use +// system properties in samevm/agentvm mode. + +/* + * @test + * @bug 8367133 + * @summary Verify that handshake succeeds when Finished message is fragmented + * @modules java.base/sun.security.util + * @library /test/lib + * @build DTLSOverDatagram + * @run main/othervm FragmentedFinished + */ + +import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLParameters; +import java.net.DatagramPacket; +import java.net.SocketAddress; +import java.util.ArrayList; +import java.util.List; + +public class FragmentedFinished extends DTLSOverDatagram { + private SSLEngine serverSSLEngine; + public static void main(String[] args) throws Exception { + FragmentedFinished testCase = new FragmentedFinished(); + testCase.runTest(testCase); + } + + @Override + SSLEngine createSSLEngine(boolean isClient) throws Exception { + SSLEngine sslEngine = super.createSSLEngine(isClient); + if (!isClient) { + serverSSLEngine = sslEngine; + } + return sslEngine; + } + + @Override + DatagramPacket createHandshakePacket(byte[] ba, SocketAddress socketAddr) { + if (ba.length < 30) { // detect ChangeCipherSpec + // Reduce the maximumPacketSize to force fragmentation + // of the Finished message + SSLParameters params = serverSSLEngine.getSSLParameters(); + params.setMaximumPacketSize(53); + serverSSLEngine.setSSLParameters(params); + } + + return super.createHandshakePacket(ba, socketAddr); + } +} diff --git a/test/jdk/jdk/incubator/vector/BasicFloat16ArithTests.java b/test/jdk/jdk/incubator/vector/BasicFloat16ArithTests.java index 0c08099031a..755745394fc 100644 --- a/test/jdk/jdk/incubator/vector/BasicFloat16ArithTests.java +++ b/test/jdk/jdk/incubator/vector/BasicFloat16ArithTests.java @@ -408,11 +408,10 @@ private static void checkGetExponent() { for(var testCase : testCases) { float arg = testCase[0]; float expected = testCase[1]; - // Exponents are in-range for Float16 - Float16 result = valueOfExact(getExponent(valueOfExact(arg))); + float result = (float)getExponent(valueOfExact(arg)); - if (Float.compare(expected, result.floatValue()) != 0) { - checkFloat16(result, expected, "getExponent(" + arg + ")"); + if (Float.compare(expected, result) != 0) { + checkFloat16(Float16.valueOf(result), expected, "getExponent(" + arg + ")"); } } return; @@ -444,8 +443,7 @@ private static void checkUlp() { for(var testCase : testCases) { float arg = testCase[0]; float expected = testCase[1]; - // Exponents are in-range for Float16 - Float16 result = ulp(valueOfExact(arg)); + Float16 result = ulp(valueOfExact(arg)); if (Float.compare(expected, result.floatValue()) != 0) { checkFloat16(result, expected, "ulp(" + arg + ")"); diff --git a/test/jdk/jdk/jfr/event/allocation/TestObjectAllocationSampleEventInitialWeight.java b/test/jdk/jdk/jfr/event/allocation/TestObjectAllocationSampleEventInitialWeight.java new file mode 100644 index 00000000000..598efd66a32 --- /dev/null +++ b/test/jdk/jdk/jfr/event/allocation/TestObjectAllocationSampleEventInitialWeight.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jfr.event.allocation; + +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.CountDownLatch; +import java.util.List; +import jdk.jfr.Recording; +import jdk.jfr.consumer.RecordedEvent; +import jdk.jfr.consumer.RecordingStream; +import jdk.test.lib.jfr.EventNames; +import jdk.test.lib.jfr.Events; + +/** + * @test + * @summary Tests that the VM maintains proper initialization state for ObjectAllocationSampleEvent. + * @requires vm.hasJFR + * @library /test/lib + * @run main/othervm -XX:+UseTLAB -XX:TLABSize=2k -XX:-ResizeTLAB jdk.jfr.event.allocation.TestObjectAllocationSampleEventInitialWeight + */ +public class TestObjectAllocationSampleEventInitialWeight { + private static final String EVENT_NAME = EventNames.ObjectAllocationSample; + private static final int OBJECT_SIZE = 4 * 1024; + private static final int OBJECTS_TO_ALLOCATE = 16; + private static final int OBJECTS_TO_ALLOCATE_BEFORE_RECORDING = 1024; + private static final long BEFORE_RECORDING_SAMPLE_WEIGHT = OBJECT_SIZE * OBJECTS_TO_ALLOCATE_BEFORE_RECORDING; + + // Make sure allocation isn't dead code eliminated. + public static byte[] tmp; + + public static void main(String... args) throws Exception { + test(); + // Test again to ensure reset logic works correctly for subsequent physical recordings. + test(); + } + + private static void test() throws Exception { + long currentThreadId = Thread.currentThread().threadId(); + allocate(OBJECTS_TO_ALLOCATE_BEFORE_RECORDING); + try (Recording r = new Recording()) { + r.enable(EVENT_NAME); + r.start(); + allocate(OBJECTS_TO_ALLOCATE); + r.stop(); + List events = Events.fromRecording(r); + Events.hasEvents(events); + for (RecordedEvent event : events) { + if (currentThreadId == event.getThread().getJavaThreadId()) { + if (event.getLong("weight") >= BEFORE_RECORDING_SAMPLE_WEIGHT) { + throw new RuntimeException("Sample weight is not below " + BEFORE_RECORDING_SAMPLE_WEIGHT); + } + } + } + } + } + + private static void allocate(int number) throws Exception { + for (int i = 0; i < number; ++i) { + tmp = new byte[OBJECT_SIZE]; + } + } +} diff --git a/test/jdk/jdk/jfr/event/runtime/TestActiveSettingEvent.java b/test/jdk/jdk/jfr/event/runtime/TestActiveSettingEvent.java index 92298eaece0..96e251aa077 100644 --- a/test/jdk/jdk/jfr/event/runtime/TestActiveSettingEvent.java +++ b/test/jdk/jdk/jfr/event/runtime/TestActiveSettingEvent.java @@ -245,28 +245,6 @@ private static void testSettingConfiguration(String configurationName) throws Ex System.out.println("Testing configuration " + configurationName); Configuration c = Configuration.getConfiguration(configurationName); Map settingValues = c.getSettings(); - // Don't want to add these settings to the jfc-files we ship since they - // are not useful to configure. They are however needed to make the test - // pass. - settingValues.put(EventNames.ActiveSetting + "#stackTrace", "false"); - settingValues.put(EventNames.ActiveSetting + "#threshold", "0 ns"); - settingValues.put(EventNames.ActiveRecording + "#stackTrace", "false"); - settingValues.put(EventNames.ActiveRecording + "#threshold", "0 ns"); - settingValues.put(EventNames.InitialSecurityProperty + "#threshold", "0 ns"); - settingValues.put(EventNames.JavaExceptionThrow + "#threshold", "0 ns"); - settingValues.put(EventNames.JavaErrorThrow + "#threshold", "0 ns"); - settingValues.put(EventNames.SecurityProperty + "#threshold", "0 ns"); - settingValues.put(EventNames.TLSHandshake + "#threshold", "0 ns"); - settingValues.put(EventNames.X509Certificate + "#threshold", "0 ns"); - settingValues.put(EventNames.X509Validation + "#threshold", "0 ns"); - settingValues.put(EventNames.ProcessStart + "#threshold", "0 ns"); - settingValues.put(EventNames.Deserialization + "#threshold", "0 ns"); - settingValues.put(EventNames.VirtualThreadStart + "#threshold", "0 ns"); - settingValues.put(EventNames.VirtualThreadEnd + "#stackTrace", "false"); - settingValues.put(EventNames.VirtualThreadEnd + "#threshold", "0 ns"); - settingValues.put(EventNames.VirtualThreadSubmitFailed + "#threshold", "0 ns"); - settingValues.put(EventNames.SecurityProviderService + "#threshold", "0 ns"); - try (Recording recording = new Recording(c)) { Map eventTypes = new HashMap<>(); for (EventType et : FlightRecorder.getFlightRecorder().getEventTypes()) { @@ -279,7 +257,11 @@ private static void testSettingConfiguration(String configurationName) throws Ex String settingName = type.getName() + "#" + s.getName(); String value = settingValues.get(settingName); if (value == null) { - throw new Exception("Could not find setting with name " + settingName); + String message = "Could not find setting with name " + settingName + "."; + if (settingName.equals("duration") || settingName.equals("stackTrace")) { + message += " Use @RemoveFields(\"" + settingName + "\") to drop the field."; + } + throw new Exception(message); } // Prefer to have ms unit in jfc file if (value.equals("0 ms")) { diff --git a/test/jdk/jdk/jfr/jcmd/TestJcmdView.java b/test/jdk/jdk/jfr/jcmd/TestJcmdView.java index 92e5c950f9b..206d6c7bc8f 100644 --- a/test/jdk/jdk/jfr/jcmd/TestJcmdView.java +++ b/test/jdk/jdk/jfr/jcmd/TestJcmdView.java @@ -163,7 +163,7 @@ private static void testTableView() throws Throwable { // Verify verbose heading output.shouldContain("(longestPause)"); // Verify row contents - output.shouldContain("Old Garbage Collection"); + output.shouldContain("G1"); // Verify verbose query output.shouldContain("SELECT"); } diff --git a/test/jdk/jdk/jfr/tool/TestView.java b/test/jdk/jdk/jfr/tool/TestView.java index 89c45c3e068..38174859b51 100644 --- a/test/jdk/jdk/jfr/tool/TestView.java +++ b/test/jdk/jdk/jfr/tool/TestView.java @@ -84,7 +84,7 @@ private static void testTableView(String recording) throws Throwable { // Verify verbose heading output.shouldContain("(longestPause)"); // Verify row contents - output.shouldContain("Old Garbage Collection"); + output.shouldContain("G1"); // Verify verbose query output.shouldContain("SELECT"); } diff --git a/test/jdk/sun/awt/font/TestDevTransform.java b/test/jdk/sun/awt/font/TestDevTransform.java index 2783401c0f2..39d4255f154 100644 --- a/test/jdk/sun/awt/font/TestDevTransform.java +++ b/test/jdk/sun/awt/font/TestDevTransform.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 @@ -22,9 +22,31 @@ */ /* - * @test + * @test id=dialog_double * @bug 4269775 8341535 * @summary Check that different text rendering APIs agree + * @run main/othervm TestDevTransform DIALOG DOUBLE + */ + +/* + * @test id=dialog_float + * @bug 4269775 8341535 + * @summary Check that different text rendering APIs agree + * @run main/othervm TestDevTransform DIALOG FLOAT + */ + +/* + * @test id=monospaced_double + * @bug 4269775 8341535 + * @summary Check that different text rendering APIs agree + * @run main/othervm TestDevTransform MONOSPACED DOUBLE + */ + +/* + * @test id=monospaced_float + * @bug 4269775 8341535 + * @summary Check that different text rendering APIs agree + * @run main/othervm TestDevTransform MONOSPACED FLOAT */ /** @@ -66,6 +88,8 @@ public class TestDevTransform { static String test = "This is only a test"; static double angle = Math.PI / 6.0; // Rotate 30 degrees static final int W = 400, H = 400; + static boolean useDialog; + static boolean useDouble; static void draw(Graphics2D g2d, TextLayout layout, float x, float y, float scalex) { @@ -101,9 +125,19 @@ static void init(Graphics2D g2d) { g2d.setColor(Color.white); g2d.fillRect(0, 0, W, H); g2d.setColor(Color.black); - g2d.scale(1.481f, 1.481); // Convert to 108 dpi + if (useDouble) { + g2d.scale(1.481, 1.481); // Convert to 108 dpi + } else { + g2d.scale(1.481f, 1.481f); // Convert to 108 dpi + } g2d.addRenderingHints(hints); - Font font = new Font(Font.DIALOG, Font.PLAIN, 12); + String name; + if (useDialog) { + name = Font.DIALOG; + } else { + name = Font.MONOSPACED; + } + Font font = new Font(name, Font.PLAIN, 12); g2d.setFont(font); } @@ -135,6 +169,12 @@ static void compare(BufferedImage bi1, String name1, BufferedImage bi2, String n } public static void main(String args[]) throws Exception { + if (args[0].equals("DIALOG")) { + useDialog = true; + } + if (args[1].equals("DOUBLE")) { + useDouble = true; + } BufferedImage tl_Image = new BufferedImage(W, H, BufferedImage.TYPE_INT_RGB); { diff --git a/test/jdk/sun/invoke/util/BytecodeDescriptorTest.java b/test/jdk/sun/invoke/util/BytecodeDescriptorTest.java new file mode 100644 index 00000000000..fa99c20e644 --- /dev/null +++ b/test/jdk/sun/invoke/util/BytecodeDescriptorTest.java @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8356022 + * @summary Tests for sun.invoke.util.BytecodeDescriptor + * @library /test/lib + * @modules java.base/sun.invoke.util + * @run junit BytecodeDescriptorTest + */ + +import java.lang.classfile.ClassFile; +import java.lang.constant.ClassDesc; +import java.util.List; +import java.util.Map; + +import jdk.test.lib.ByteCodeLoader; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import sun.invoke.util.BytecodeDescriptor; + +import static org.junit.jupiter.api.Assertions.*; + +class BytecodeDescriptorTest { + + private static final String FOO_NAME = "dummy.Foo"; + private static final String BAR_NAME = "dummy.Bar"; + private static final String FOO_DESC = "L" + FOO_NAME.replace('.', '/') + ";"; + private static final String BAR_DESC = "L" + BAR_NAME.replace('.', '/') + ";"; + private static final String DOES_NOT_EXIST_DESC = "Ldoes/not/Exist;"; + static Class foo1, foo2, bar1; + static ClassLoader cl1, cl2; + + @BeforeAll + static void setup() throws Throwable { + var fooBytes = ClassFile.of().build(ClassDesc.of(FOO_NAME), _ -> {}); + var barBytes = ClassFile.of().build(ClassDesc.of(BAR_NAME), _ -> {}); + cl1 = new ByteCodeLoader(Map.of(FOO_NAME, fooBytes, BAR_NAME, barBytes), ClassLoader.getSystemClassLoader()); + foo1 = cl1.loadClass(FOO_NAME); + bar1 = cl1.loadClass(BAR_NAME); + foo2 = ByteCodeLoader.load(FOO_NAME, fooBytes); + cl2 = foo2.getClassLoader(); + + // Sanity + assertNotSame(foo1, foo2); + assertNotSame(cl1, cl2); + assertSame(cl1, foo1.getClassLoader()); + assertSame(cl1, bar1.getClassLoader()); + assertNotSame(cl1, foo2.getClassLoader()); + assertEquals(FOO_DESC, foo1.descriptorString()); + assertEquals(FOO_DESC, foo2.descriptorString()); + assertEquals(BAR_DESC, bar1.descriptorString()); + } + + @Test + void testParseClass() throws ReflectiveOperationException { + assertSame(void.class, BytecodeDescriptor.parseClass("V", null), "void"); + assertSame(int.class, BytecodeDescriptor.parseClass("I", null), "primitive"); + assertSame(long[][].class, BytecodeDescriptor.parseClass("[[J", null), "array"); + assertSame(Object.class, BytecodeDescriptor.parseClass("Ljava/lang/Object;", null), "class or interface"); + assertThrows(IllegalArgumentException.class, () -> BytecodeDescriptor.parseClass("java/lang/Object", null), "internal name"); + assertThrows(IllegalArgumentException.class, () -> BytecodeDescriptor.parseClass("[V", null), "bad array"); + assertSame(Class.forName("[".repeat(255) + "I"), BytecodeDescriptor.parseClass("[".repeat(255) + "I", null), "good array"); + assertThrows(IllegalArgumentException.class, () -> BytecodeDescriptor.parseClass("[".repeat(256) + "I", null), "bad array"); + + assertSame(foo2, BytecodeDescriptor.parseClass(FOO_DESC, cl2), "class loader"); + assertThrows(TypeNotPresentException.class, () -> BytecodeDescriptor.parseClass(DOES_NOT_EXIST_DESC, null), "not existent"); + assertThrows(TypeNotPresentException.class, () -> BytecodeDescriptor.parseClass(BAR_DESC, cl2), "cross loader"); + } + + @Test + void testParseMethod() { + assertEquals(List.of(void.class), + BytecodeDescriptor.parseMethod("()V", null), + "no-arg"); + assertEquals(List.of(int.class, Object.class, long[].class, void.class), + BytecodeDescriptor.parseMethod("(ILjava/lang/Object;[J)V", null), + "sanity"); + assertThrows(IllegalArgumentException.class, + () -> BytecodeDescriptor.parseMethod("()", null), + "no return"); + assertThrows(IllegalArgumentException.class, + () -> BytecodeDescriptor.parseMethod("(V)V", null), + "bad arg"); + var voidInMsgIAE = assertThrows(IllegalArgumentException.class, + () -> BytecodeDescriptor.parseMethod("([V)I", null), + "bad arg"); + assertTrue(voidInMsgIAE.getMessage().contains("[V"), () -> "missing [V type in: '%s'".formatted(voidInMsgIAE.getMessage())); + assertThrows(IllegalArgumentException.class, + () -> BytecodeDescriptor.parseClass("([".repeat(256) + "I)J", null), + "bad arg"); + + assertEquals(List.of(foo1, bar1), + BytecodeDescriptor.parseMethod("(" + FOO_DESC + ")" + BAR_DESC, cl1), + "class loader"); + assertThrows(TypeNotPresentException.class, + () -> BytecodeDescriptor.parseMethod("(" + FOO_DESC + ")" + BAR_DESC, cl2), + "no bar"); + assertThrows(TypeNotPresentException.class, + () -> BytecodeDescriptor.parseMethod("(" + FOO_DESC + "V)V", null), + "first encounter TNPE"); + assertThrows(IllegalArgumentException.class, + () -> BytecodeDescriptor.parseMethod("(V" + FOO_DESC + ")V", null), + "first encounter IAE"); + } + +} diff --git a/test/jdk/sun/security/pkcs11/PKCS11Test.java b/test/jdk/sun/security/pkcs11/PKCS11Test.java index 56127f86792..8454f3ac463 100644 --- a/test/jdk/sun/security/pkcs11/PKCS11Test.java +++ b/test/jdk/sun/security/pkcs11/PKCS11Test.java @@ -779,7 +779,12 @@ private static Path fetchNssLib(String osId, Path libraryName) throws IOExceptio } private static Path fetchNssLib(Class clazz, Path libraryName) throws IOException { - Path p = ArtifactResolver.fetchOne(clazz); + Path p; + try { + p = ArtifactResolver.fetchOne(clazz); + } catch (IOException exc) { + throw new SkippedException("Could not find NSS", exc); + } return findNSSLibrary(p, libraryName); } diff --git a/test/jdk/sun/security/pkcs11/tls/tls12/FipsModeTLS12.java b/test/jdk/sun/security/pkcs11/tls/fips/FipsModeTLS.java similarity index 95% rename from test/jdk/sun/security/pkcs11/tls/tls12/FipsModeTLS12.java rename to test/jdk/sun/security/pkcs11/tls/fips/FipsModeTLS.java index c0af4d71498..a883239281c 100644 --- a/test/jdk/sun/security/pkcs11/tls/tls12/FipsModeTLS12.java +++ b/test/jdk/sun/security/pkcs11/tls/fips/FipsModeTLS.java @@ -24,16 +24,18 @@ /* * @test - * @bug 8029661 8325164 8368073 + * @bug 8029661 8325164 8368073 8368514 * @summary Test TLS 1.2 and TLS 1.3 * @modules java.base/sun.security.internal.spec * java.base/sun.security.util * java.base/com.sun.crypto.provider * @library /test/lib ../.. * @run main/othervm/timeout=120 -Djdk.tls.client.protocols=TLSv1.2 - * -Djdk.tls.useExtendedMasterSecret=false FipsModeTLS12 - * @comment SunPKCS11 does not support (TLS1.2) SunTlsExtendedMasterSecret yet - * @run main/othervm/timeout=120 -Djdk.tls.client.protocols=TLSv1.3 FipsModeTLS12 + * -Djdk.tls.useExtendedMasterSecret=false + * -Djdk.tls.client.enableSessionTicketExtension=false FipsModeTLS + * @comment SunPKCS11 does not support (TLS1.2) SunTlsExtendedMasterSecret yet. + * Stateless resumption doesn't currently work with NSS-FIPS, see JDK-8368669 + * @run main/othervm/timeout=120 -Djdk.tls.client.protocols=TLSv1.3 FipsModeTLS */ import java.io.File; @@ -73,7 +75,7 @@ import sun.security.internal.spec.TlsPrfParameterSpec; import sun.security.internal.spec.TlsRsaPremasterSecretParameterSpec; -public final class FipsModeTLS12 extends SecmodTest { +public final class FipsModeTLS extends SecmodTest { private static final boolean enableDebug = true; @@ -101,8 +103,9 @@ public static void main(String[] args) throws Exception { // Test against JCE testTlsAuthenticationCodeGeneration(); - // Self-integrity test (complete TLS 1.2 communication) - new testTLS12SunPKCS11Communication().run(); + // Self-integrity test (complete TLS communication) + testTLSSunPKCS11Communication.initSslContext(); + testTLSSunPKCS11Communication.run(); System.out.println("Test PASS - OK"); } else { @@ -269,15 +272,18 @@ private static void testTlsAuthenticationCodeGeneration() } } - private static class testTLS12SunPKCS11Communication { + private static class testTLSSunPKCS11Communication { public static void run() throws Exception { SSLEngine[][] enginesToTest = getSSLEnginesToTest(); - + boolean firstSession = true; for (SSLEngine[] engineToTest : enginesToTest) { SSLEngine clientSSLEngine = engineToTest[0]; SSLEngine serverSSLEngine = engineToTest[1]; - + // The first connection needs to do a full handshake. + // Verify that subsequent handshakes use resumption. + clientSSLEngine.setEnableSessionCreation(firstSession); + firstSession = false; // SSLEngine code based on RedhandshakeFinished.java boolean dataDone = false; @@ -400,14 +406,6 @@ private static SSLEngine[][] getSSLEnginesToTest() throws Exception { static private SSLEngine createSSLEngine(boolean client) throws Exception { SSLEngine ssle; - KeyManagerFactory kmf = KeyManagerFactory.getInstance("PKIX", "SunJSSE"); - kmf.init(ks, passphrase); - - TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX", "SunJSSE"); - tmf.init(ts); - - SSLContext sslCtx = SSLContext.getInstance("TLS", "SunJSSE"); - sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); ssle = sslCtx.createSSLEngine("localhost", 443); ssle.setUseClientMode(client); SSLParameters sslParameters = ssle.getSSLParameters(); @@ -431,6 +429,18 @@ static private SSLEngine createSSLEngine(boolean client) return ssle; } + + private static SSLContext sslCtx; + private static void initSslContext() throws Exception { + KeyManagerFactory kmf = KeyManagerFactory.getInstance("PKIX", "SunJSSE"); + kmf.init(ks, passphrase); + + TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX", "SunJSSE"); + tmf.init(ts); + + sslCtx = SSLContext.getInstance("TLS", "SunJSSE"); + sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); + } } private static void initialize() throws Exception { diff --git a/test/jdk/sun/security/pkcs11/tls/tls12/cert8.db b/test/jdk/sun/security/pkcs11/tls/fips/cert8.db similarity index 100% rename from test/jdk/sun/security/pkcs11/tls/tls12/cert8.db rename to test/jdk/sun/security/pkcs11/tls/fips/cert8.db diff --git a/test/jdk/sun/security/pkcs11/tls/tls12/cert9.db b/test/jdk/sun/security/pkcs11/tls/fips/cert9.db similarity index 100% rename from test/jdk/sun/security/pkcs11/tls/tls12/cert9.db rename to test/jdk/sun/security/pkcs11/tls/fips/cert9.db diff --git a/test/jdk/sun/security/pkcs11/tls/tls12/key3.db b/test/jdk/sun/security/pkcs11/tls/fips/key3.db similarity index 100% rename from test/jdk/sun/security/pkcs11/tls/tls12/key3.db rename to test/jdk/sun/security/pkcs11/tls/fips/key3.db diff --git a/test/jdk/sun/security/pkcs11/tls/tls12/key4.db b/test/jdk/sun/security/pkcs11/tls/fips/key4.db similarity index 100% rename from test/jdk/sun/security/pkcs11/tls/tls12/key4.db rename to test/jdk/sun/security/pkcs11/tls/fips/key4.db diff --git a/test/jdk/sun/security/pkcs11/tls/tls12/keystore b/test/jdk/sun/security/pkcs11/tls/fips/keystore similarity index 100% rename from test/jdk/sun/security/pkcs11/tls/tls12/keystore rename to test/jdk/sun/security/pkcs11/tls/fips/keystore diff --git a/test/jdk/sun/security/pkcs11/tls/tls12/nss.cfg b/test/jdk/sun/security/pkcs11/tls/fips/nss.cfg similarity index 100% rename from test/jdk/sun/security/pkcs11/tls/tls12/nss.cfg rename to test/jdk/sun/security/pkcs11/tls/fips/nss.cfg diff --git a/test/jdk/sun/security/pkcs11/tls/tls12/pkcs11.txt b/test/jdk/sun/security/pkcs11/tls/fips/pkcs11.txt similarity index 100% rename from test/jdk/sun/security/pkcs11/tls/tls12/pkcs11.txt rename to test/jdk/sun/security/pkcs11/tls/fips/pkcs11.txt diff --git a/test/jdk/sun/security/pkcs11/tls/tls12/secmod.db b/test/jdk/sun/security/pkcs11/tls/fips/secmod.db similarity index 100% rename from test/jdk/sun/security/pkcs11/tls/tls12/secmod.db rename to test/jdk/sun/security/pkcs11/tls/fips/secmod.db diff --git a/test/jdk/sun/security/ssl/SSLEngineImpl/SSLEngineEmptyFragments.java b/test/jdk/sun/security/ssl/SSLEngineImpl/SSLEngineEmptyFragments.java index f2aa8041b9a..837e607c009 100644 --- a/test/jdk/sun/security/ssl/SSLEngineImpl/SSLEngineEmptyFragments.java +++ b/test/jdk/sun/security/ssl/SSLEngineImpl/SSLEngineEmptyFragments.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 @@ -103,7 +103,7 @@ private void testAlertPacketNotHandshaking() throws Exception { try { unwrap(serverEngine, alert, serverIn); throw new RuntimeException("Expected exception was not thrown."); - } catch (SSLHandshakeException exc) { + } catch (SSLProtocolException exc) { log("Got the exception I wanted."); } } @@ -133,7 +133,7 @@ private void testAlertPacketMidHandshake() throws Exception { unwrap(serverEngine, alert, serverIn); log("Server unwrap was successful when it should have failed."); throw new RuntimeException("Expected exception was not thrown."); - } catch (SSLHandshakeException exc) { + } catch (SSLProtocolException exc) { log("Got the exception I wanted."); } } diff --git a/test/jdk/sun/security/ssl/SSLSocketImpl/SSLSocketEmptyFragments.java b/test/jdk/sun/security/ssl/SSLSocketImpl/SSLSocketEmptyFragments.java index dec93c1c199..de0ef43924d 100644 --- a/test/jdk/sun/security/ssl/SSLSocketImpl/SSLSocketEmptyFragments.java +++ b/test/jdk/sun/security/ssl/SSLSocketImpl/SSLSocketEmptyFragments.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 @@ -351,9 +351,9 @@ public static void main(String [] args) throws Exception { tests.executeTest( tests::testEmptyHandshakeRecord, SSLProtocolException.class); tests.executeTest( - tests::testEmptyAlertNotHandshaking, SSLHandshakeException.class); + tests::testEmptyAlertNotHandshaking, SSLProtocolException.class); tests.executeTest( - tests::testEmptyAlertDuringHandshake, SSLHandshakeException.class); + tests::testEmptyAlertDuringHandshake, SSLProtocolException.class); tests.executeTest( tests::testEmptyChangeCipherSpecMessage, SSLProtocolException.class); @@ -361,6 +361,6 @@ public static void main(String [] args) throws Exception { tests.executeTest( tests::testEmptyHandshakeRecord, SSLProtocolException.class); tests.executeTest( - tests::testEmptyAlertNotHandshaking, SSLHandshakeException.class); + tests::testEmptyAlertNotHandshaking, SSLProtocolException.class); } } diff --git a/test/jdk/sun/security/ssl/SignatureScheme/DisableCertSignAlgsExtForClientTLS12.java b/test/jdk/sun/security/ssl/SignatureScheme/DisableCertSignAlgsExtForClientTLS12.java new file mode 100644 index 00000000000..7d16e07e7b1 --- /dev/null +++ b/test/jdk/sun/security/ssl/SignatureScheme/DisableCertSignAlgsExtForClientTLS12.java @@ -0,0 +1,87 @@ +/* + * 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 8365820 + * @summary Apply certificate scope constraints to algorithms in + * "signature_algorithms" extension when + * "signature_algorithms_cert" extension is not being sent. + * This test covers the client side for TLSv1.2. + * @library /javax/net/ssl/templates + * /test/lib + * @run main/othervm DisableCertSignAlgsExtForClientTLS12 + */ + +import static jdk.test.lib.Asserts.assertEquals; +import static jdk.test.lib.Asserts.assertFalse; + +import java.security.Security; +import java.util.List; + +// Test disabled signature_algorithms_cert extension on the client side +// for TLSv1.2. +public class DisableCertSignAlgsExtForClientTLS12 extends + DisableSignatureSchemePerScopeTLS12 { + + protected DisableCertSignAlgsExtForClientTLS12() + throws Exception { + super(); + } + + public static void main(String[] args) throws Exception { + Security.setProperty( + "jdk.tls.disabledAlgorithms", DISABLED_CONSTRAINTS); + // Disable signature_algorithms_cert extension for the client. + System.setProperty("jdk.tls.client.disableExtensions", + "signature_algorithms_cert"); + new DisableCertSignAlgsExtForClientTLS12().run(); + } + + @Override + protected void checkClientHello() throws Exception { + // --- Check signature_algorithms extension --- + + // Get signature_algorithms extension signature schemes. + List sigAlgsSS = getSigSchemesCliHello( + extractHandshakeMsg(cTOs, TLS_HS_CLI_HELLO), + SIG_ALGS_EXT); + + // signature_algorithms extension MUST NOT contain disabled + // handshake signature scheme. + assertFalse(sigAlgsSS.contains(HANDSHAKE_DISABLED_SIG), + "Signature Scheme " + HANDSHAKE_DISABLED_SIG + + " present in ClientHello's signature_algorithms extension"); + + // signature_algorithms extension MUST NOT contain disabled + // certificate signature scheme. + assertFalse(sigAlgsSS.contains(CERTIFICATE_DISABLED_SIG), + "Signature Scheme " + CERTIFICATE_DISABLED_SIG + + " present in ClientHello's signature_algorithms extension"); + + // signature_algorithms_cert extension MUST NOT be present. + assertEquals(getSigSchemesCliHello(extractHandshakeMsg( + cTOs, TLS_HS_CLI_HELLO), SIG_ALGS_CERT_EXT).size(), 0, + "signature_algorithms_cert extension present in ClientHello"); + } +} diff --git a/test/jdk/sun/security/ssl/SignatureScheme/DisableCertSignAlgsExtForClientTLS13.java b/test/jdk/sun/security/ssl/SignatureScheme/DisableCertSignAlgsExtForClientTLS13.java new file mode 100644 index 00000000000..5f594cd2cdf --- /dev/null +++ b/test/jdk/sun/security/ssl/SignatureScheme/DisableCertSignAlgsExtForClientTLS13.java @@ -0,0 +1,89 @@ +/* + * 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 8365820 + * @summary Apply certificate scope constraints to algorithms in + * "signature_algorithms" extension when + * "signature_algorithms_cert" extension is not being sent. + * This test covers the client side for TLSv1.3. + * @library /javax/net/ssl/templates + * /test/lib + * @run main/othervm DisableCertSignAlgsExtForClientTLS13 + */ + +import static jdk.test.lib.Asserts.assertFalse; + +import java.security.Security; +import java.util.List; + +// Test disabled signature_algorithms_cert extension on the client side +// for TLSv1.3. +public class DisableCertSignAlgsExtForClientTLS13 extends + DisableCertSignAlgsExtForClientTLS12 { + + protected DisableCertSignAlgsExtForClientTLS13() + throws Exception { + super(); + } + + public static void main(String[] args) throws Exception { + Security.setProperty( + "jdk.tls.disabledAlgorithms", DISABLED_CONSTRAINTS); + // Disable signature_algorithms_cert extension for the client. + System.setProperty("jdk.tls.client.disableExtensions", + "signature_algorithms_cert"); + new DisableCertSignAlgsExtForClientTLS13().run(); + } + + @Override + protected String getProtocol() { + return "TLSv1.3"; + } + + @Override + protected void checkClientHello() throws Exception { + super.checkClientHello(); + + // Get signature_algorithms extension signature schemes. + List sigAlgsSS = getSigSchemesCliHello( + extractHandshakeMsg(cTOs, TLS_HS_CLI_HELLO), + SIG_ALGS_EXT); + + // These signature schemes MOST NOT be present in signature_algorithms + // extension. + TLS13_CERT_ONLY.forEach(ss -> + assertFalse(sigAlgsSS.contains(ss), "Signature Scheme " + ss + + " present in ClientHello's" + + " signature_algorithms extension")); + } + + // TLSv1.3 sends CertificateRequest signature schemes in + // signature_algorithms and signature_algorithms_cert extensions. Same as + // ClientHello, but they are encrypted. So we skip CertificateRequest + // signature schemes verification for TLSv1.3. + @Override + protected void checkCertificateRequest() { + } +} diff --git a/test/jdk/sun/security/ssl/SignatureScheme/DisableCertSignAlgsExtForServerTLS13.java b/test/jdk/sun/security/ssl/SignatureScheme/DisableCertSignAlgsExtForServerTLS13.java new file mode 100644 index 00000000000..4c93e4fc240 --- /dev/null +++ b/test/jdk/sun/security/ssl/SignatureScheme/DisableCertSignAlgsExtForServerTLS13.java @@ -0,0 +1,281 @@ +/* + * 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. + */ + +import static jdk.test.lib.Asserts.assertTrue; +import static jdk.test.lib.Utils.runAndCheckException; + +import java.io.IOException; +import java.math.BigInteger; +import java.net.SocketException; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.KeyStore; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import java.util.Date; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLHandshakeException; +import javax.net.ssl.SSLParameters; +import javax.net.ssl.SSLServerSocket; +import javax.net.ssl.TrustManagerFactory; +import jdk.test.lib.security.CertificateBuilder; +import sun.security.x509.AuthorityKeyIdentifierExtension; +import sun.security.x509.GeneralName; +import sun.security.x509.GeneralNames; +import sun.security.x509.KeyIdentifier; +import sun.security.x509.SerialNumber; +import sun.security.x509.X500Name; + +/* + * @test + * @bug 8365820 + * @summary Apply certificate scope constraints to algorithms in + * "signature_algorithms" extension when + * "signature_algorithms_cert" extension is not being sent. + * This test covers the server side for TLSv1.3. + * @modules java.base/sun.security.x509 + * java.base/sun.security.util + * @library /javax/net/ssl/templates + * /test/lib + * @run main/othervm DisableCertSignAlgsExtForServerTLS13 true + * @run main/othervm DisableCertSignAlgsExtForServerTLS13 false + */ + +/* + * Test disabled signature_algorithms_cert extension on the server side. + * + * CertificateRequest's extensions are encrypted in TLSv1.3. So we can't verify + * the content of the CertificateRequest's signature_algorithms extension + * directly like we do it for extensions in ClientHello message. + * Instead, we run a TLS handshake and check that certificate scope + * constraints are being applied to algorithms in "signature_algorithms" + * extension when "signature_algorithms_cert" extension is not being sent. + * + * Note that for TLSv1.2 disabling "signature_algorithms_cert" extension + * doesn't change anything for the signatures schemes list contained in + * CertificateRequest message. The TLSv1.2 CertificateRequest message + * doesn't contain extensions and includes the signatures schemes list + * directly (which is also an intersection of signature schemes allowed + * for handshake signatures and for the certificate signatures). + * This functionality is being tested by "DisableSignatureSchemePerScopeTLS12". + */ + +public class DisableCertSignAlgsExtForServerTLS13 extends SSLSocketTemplate { + + private static final String KEY_ALGORITHM = "RSA"; + private static final String SERVER_CERT_SIG_ALG = "RSASSA-PSS"; + // SHA256withRSA signature algorithm is not allowed for handshake + // signatures in TLSv1.3, but it's allowed for certificate + // signatures. This is regardless of jdk.tls.disabledAlgorithms + // configuration. We use this difference to construct our test. + private static final String CLIENT_CERT_SIG_ALG = "SHA256withRSA"; + private static final String TRUSTED_CERT_SIG_ALG = "RSASSA-PSS"; + + private final String protocol; + private X509Certificate trustedCert; + private X509Certificate serverCert; + private X509Certificate clientCert; + private KeyPair serverKeys; + private KeyPair clientKeys; + + protected DisableCertSignAlgsExtForServerTLS13( + String protocol) throws Exception { + super(); + this.protocol = protocol; + setupCertificates(); + } + + public static void main(String[] args) throws Exception { + if (args.length != 1) { + throw new RuntimeException("Wrong number of arguments"); + } + + boolean disabled = Boolean.parseBoolean(args[0]); + + // Disable signature_algorithms_cert extension on the server side. + if (disabled) { + System.setProperty("jdk.tls.server.disableExtensions", + "signature_algorithms_cert"); + } + + // Should always run fine on TLSv1.2 because SHA256withRSA signature + // algorithm is allowed for both handshake and certificates signatures + // in TLSv1.2. + new DisableCertSignAlgsExtForServerTLS13("TLSv1.2").run(); + + var tls13Test = new DisableCertSignAlgsExtForServerTLS13("TLSv1.3"); + + if (disabled) { + // Fails with "signature_algorithms_cert" extension disabled + // because in such case we use an intersection of signature + // schemes allowed for handshake signatures and for the certificate + // signatures for "signature_algorithms" extension. + runAndCheckException( + tls13Test::run, + localEx -> { + Throwable remoteEx = localEx.getSuppressed()[0]; + + for (Throwable ex : + new Throwable[]{localEx, remoteEx}) { + assertTrue((ex instanceof SSLHandshakeException + && ex.getMessage() + .contains("(certificate_required)") + // Sometimes we can get SocketException + // instead, depends on network setup. + || ex instanceof SocketException)); + } + }); + } else { + // Runs fine with "signature_algorithms_cert" extension present. + tls13Test.run(); + } + } + + @Override + protected void configureServerSocket(SSLServerSocket sslServerSocket) { + // Require a conforming certificate for the client. + SSLParameters sslParameters = sslServerSocket.getSSLParameters(); + sslParameters.setNeedClientAuth(true); + sslServerSocket.setSSLParameters(sslParameters); + } + + @Override + public SSLContext createServerSSLContext() throws Exception { + return getSSLContext( + trustedCert, serverCert, serverKeys.getPrivate(), protocol); + } + + @Override + public SSLContext createClientSSLContext() throws Exception { + return getSSLContext( + trustedCert, clientCert, clientKeys.getPrivate(), protocol); + } + + private static SSLContext getSSLContext( + X509Certificate trustedCertificate, X509Certificate keyCertificate, + PrivateKey privateKey, String protocol) + throws Exception { + + // create a key store + KeyStore ks = KeyStore.getInstance("PKCS12"); + ks.load(null, null); + + // import the trusted cert + ks.setCertificateEntry("TLS Signer", trustedCertificate); + + // generate certificate chain + Certificate[] chain = new Certificate[2]; + chain[0] = keyCertificate; + chain[1] = trustedCertificate; + + // import the key entry. + final char[] passphrase = "passphrase".toCharArray(); + ks.setKeyEntry("Whatever", privateKey, passphrase, chain); + + TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX"); + tmf.init(ks); + + // create SSL context + SSLContext ctx = SSLContext.getInstance(protocol); + + KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); + kmf.init(ks, passphrase); + + ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); + + return ctx; + } + + // Certificate-building helper methods. + + private void setupCertificates() throws Exception { + KeyPairGenerator kpg = KeyPairGenerator.getInstance( + KEY_ALGORITHM); + KeyPair caKeys = kpg.generateKeyPair(); + this.serverKeys = kpg.generateKeyPair(); + this.clientKeys = kpg.generateKeyPair(); + + this.trustedCert = createTrustedCert(caKeys); + + this.serverCert = customCertificateBuilder( + "O=Some-Org, L=Some-City, ST=Some-State, C=US", + serverKeys.getPublic(), caKeys.getPublic()) + .addBasicConstraintsExt(false, false, -1) + .build(trustedCert, caKeys.getPrivate(), SERVER_CERT_SIG_ALG); + + this.clientCert = customCertificateBuilder( + "CN=localhost, OU=SSL-Client, O=Some-Org, L=Some-City, ST=Some-State, C=US", + clientKeys.getPublic(), caKeys.getPublic()) + .addBasicConstraintsExt(false, false, -1) + .build(trustedCert, caKeys.getPrivate(), CLIENT_CERT_SIG_ALG); + } + + private static X509Certificate createTrustedCert(KeyPair caKeys) + throws Exception { + SecureRandom random = new SecureRandom(); + + KeyIdentifier kid = new KeyIdentifier(caKeys.getPublic()); + GeneralNames gns = new GeneralNames(); + GeneralName name = new GeneralName(new X500Name( + "O=Some-Org, L=Some-City, ST=Some-State, C=US")); + gns.add(name); + BigInteger serialNumber = BigInteger.valueOf( + random.nextLong(1000000) + 1); + return customCertificateBuilder( + "O=Some-Org, L=Some-City, ST=Some-State, C=US", + caKeys.getPublic(), caKeys.getPublic()) + .setSerialNumber(serialNumber) + .addExtension(new AuthorityKeyIdentifierExtension(kid, gns, + new SerialNumber(serialNumber))) + .addBasicConstraintsExt(true, true, -1) + .build(null, caKeys.getPrivate(), TRUSTED_CERT_SIG_ALG); + } + + private static CertificateBuilder customCertificateBuilder( + String subjectName, PublicKey publicKey, PublicKey caKey) + throws CertificateException, IOException { + SecureRandom random = new SecureRandom(); + + CertificateBuilder builder = new CertificateBuilder() + .setSubjectName(subjectName) + .setPublicKey(publicKey) + .setNotBefore( + Date.from(Instant.now().minus(1, ChronoUnit.HOURS))) + .setNotAfter(Date.from(Instant.now().plus(1, ChronoUnit.HOURS))) + .setSerialNumber( + BigInteger.valueOf(random.nextLong(1000000) + 1)) + .addSubjectKeyIdExt(publicKey) + .addAuthorityKeyIdExt(caKey); + builder.addKeyUsageExt( + new boolean[]{true, true, true, true, true, true}); + + return builder; + } +} diff --git a/test/jdk/sun/security/ssl/SignatureScheme/DisableSignatureSchemePerScopeTLS12.java b/test/jdk/sun/security/ssl/SignatureScheme/DisableSignatureSchemePerScopeTLS12.java index e2ee9f0889a..29a50dccefe 100644 --- a/test/jdk/sun/security/ssl/SignatureScheme/DisableSignatureSchemePerScopeTLS12.java +++ b/test/jdk/sun/security/ssl/SignatureScheme/DisableSignatureSchemePerScopeTLS12.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8349583 + * @bug 8349583 8365820 * @summary Add mechanism to disable signature schemes based on their TLS scope. * This test only covers TLS 1.2. * @library /javax/net/ssl/templates @@ -53,6 +53,17 @@ public class DisableSignatureSchemePerScopeTLS12 extends HANDSHAKE_DISABLED_SIG + " usage HandShakesignature, " + CERTIFICATE_DISABLED_SIG + " usage certificateSignature"; + // Signature schemes not supported in TLSv1.3 for the handshake + // regardless of jdk.tls.disabledAlgorithms configuration. + // In TLSv1.2 these are supported for both: handshake and certificate. + protected static final List TLS13_CERT_ONLY = List.of( + "ecdsa_sha1", + "rsa_pkcs1_sha1", + "rsa_pkcs1_sha256", + "rsa_pkcs1_sha384", + "rsa_pkcs1_sha512" + ); + protected DisableSignatureSchemePerScopeTLS12() throws Exception { super(); } @@ -120,13 +131,13 @@ protected void checkClientHello() throws Exception { assertTrue(sigAlgsCertSS.contains(HANDSHAKE_DISABLED_SIG), "Signature Scheme " + HANDSHAKE_DISABLED_SIG + " isn't present in ClientHello's" - + " signature_algorithms extension"); + + " signature_algorithms_cert extension"); // signature_algorithms_cert extension MUST NOT contain disabled // certificate signature scheme. assertFalse(sigAlgsCertSS.contains(CERTIFICATE_DISABLED_SIG), "Signature Scheme " + CERTIFICATE_DISABLED_SIG - + " present in ClientHello's signature_algorithms extension"); + + " present in ClientHello's signature_algorithms_cert extension"); } protected void checkCertificateRequest() throws Exception { diff --git a/test/jdk/sun/security/ssl/SignatureScheme/DisableSignatureSchemePerScopeTLS13.java b/test/jdk/sun/security/ssl/SignatureScheme/DisableSignatureSchemePerScopeTLS13.java index 5d5d445cb45..6f5d88052ff 100644 --- a/test/jdk/sun/security/ssl/SignatureScheme/DisableSignatureSchemePerScopeTLS13.java +++ b/test/jdk/sun/security/ssl/SignatureScheme/DisableSignatureSchemePerScopeTLS13.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8349583 + * @bug 8349583 8365820 * @summary Add mechanism to disable signature schemes based on their TLS scope. * This test only covers TLS 1.3. * @library /javax/net/ssl/templates @@ -41,15 +41,6 @@ public class DisableSignatureSchemePerScopeTLS13 extends DisableSignatureSchemePerScopeTLS12 { - // Signature schemes not supported in TLSv1.3 only for the handshake. - // This is regardless of jdk.tls.disabledAlgorithms configuration. - List NOT_SUPPORTED_FOR_HANDSHAKE = List.of( - "rsa_pkcs1_sha1", - "rsa_pkcs1_sha256", - "rsa_pkcs1_sha384", - "rsa_pkcs1_sha512" - ); - protected DisableSignatureSchemePerScopeTLS13() throws Exception { super(); } @@ -74,23 +65,24 @@ protected void checkClientHello() throws Exception { extractHandshakeMsg(cTOs, TLS_HS_CLI_HELLO), SIG_ALGS_EXT); - // Should not be present in signature_algorithms extension. - NOT_SUPPORTED_FOR_HANDSHAKE.forEach(ss -> - assertFalse(sigAlgsSS.contains(ss), - "Signature Scheme " + ss - + " present in ClientHello's signature_algorithms extension")); + // These signature schemes MOST NOT be present in signature_algorithms + // extension. + TLS13_CERT_ONLY.forEach(ss -> + assertFalse(sigAlgsSS.contains(ss), "Signature Scheme " + ss + + " present in ClientHello's" + + " signature_algorithms extension")); // Get signature_algorithms_cert extension signature schemes. List sigAlgsCertSS = getSigSchemesCliHello( extractHandshakeMsg(cTOs, TLS_HS_CLI_HELLO), SIG_ALGS_CERT_EXT); - // Should be present in signature_algorithms_cert extension. - NOT_SUPPORTED_FOR_HANDSHAKE.forEach(ss -> - assertTrue(sigAlgsCertSS.contains(ss), - "Signature Scheme " + ss + // These signature schemes MUST be present in + // signature_algorithms_cert extension. + TLS13_CERT_ONLY.forEach(ss -> + assertTrue(sigAlgsCertSS.contains(ss), "Signature Scheme " + ss + " isn't present in ClientHello's" - + " signature_algorithms extension")); + + " signature_algorithms_cert extension")); } // TLSv1.3 sends CertificateRequest signature schemes in diff --git a/test/jdk/tools/jpackage/TEST.properties b/test/jdk/tools/jpackage/TEST.properties index 58a82a9444b..7c799e4d320 100644 --- a/test/jdk/tools/jpackage/TEST.properties +++ b/test/jdk/tools/jpackage/TEST.properties @@ -22,5 +22,6 @@ modules = \ jdk.jpackage/jdk.jpackage.internal:+open \ jdk.jpackage/jdk.jpackage.internal.util \ jdk.jpackage/jdk.jpackage.internal.util.function \ + jdk.jpackage/jdk.jpackage.internal.resources \ java.base/jdk.internal.util \ jdk.jlink/jdk.tools.jlink.internal 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 49f565e27e9..6aacc261fb6 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java @@ -1085,7 +1085,9 @@ public static enum AppLayoutAssert { }), MAIN_LAUNCHER_FILES(cmd -> { if (!cmd.isRuntime()) { - new LauncherVerifier(cmd).verify(cmd, LauncherVerifier.Action.VERIFY_INSTALLED); + new LauncherVerifier(cmd).verify(cmd, + LauncherVerifier.Action.VERIFY_INSTALLED, + LauncherVerifier.Action.VERIFY_MAC_ENTITLEMENTS); } }), MAIN_JAR_FILE(cmd -> { diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherAsServiceVerifier.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherAsServiceVerifier.java index 42821822894..e1cd37fe8b4 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherAsServiceVerifier.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherAsServiceVerifier.java @@ -311,7 +311,7 @@ private static void verifyMacDaemonPlistFile(JPackageCommand cmd, var servicePlist = MacHelper.readPList(servicePlistFile); - var args = servicePlist.queryArrayValue("ProgramArguments"); + var args = servicePlist.queryStringArrayValue("ProgramArguments"); TKit.assertEquals(1, args.size(), "Check number of array elements in 'ProgramArguments' property in the property file"); TKit.assertEquals(installedLauncherPath.toString(), args.get(0), diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherVerifier.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherVerifier.java index b3ed030c69d..7bf01fdde05 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherVerifier.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherVerifier.java @@ -37,9 +37,14 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Stream; +import javax.xml.parsers.ParserConfigurationException; +import jdk.jpackage.internal.resources.ResourceLocator; +import jdk.jpackage.internal.util.PListReader; import jdk.jpackage.internal.util.function.ThrowingBiConsumer; +import jdk.jpackage.internal.util.function.ThrowingSupplier; import jdk.jpackage.test.AdditionalLauncher.PropertyFile; import jdk.jpackage.test.LauncherShortcut.StartupDirectory; +import org.xml.sax.SAXException; public final class LauncherVerifier { @@ -82,6 +87,11 @@ public enum Action { verifier.verifyInAppImageFile(cmd); } }), + VERIFY_MAC_ENTITLEMENTS((verifier, cmd) -> { + if (TKit.isOSX() && MacHelper.appImageSigned(cmd)) { + verifier.verifyMacEntitlements(cmd); + } + }), EXECUTE_LAUNCHER(LauncherVerifier::executeLauncher), ; @@ -96,7 +106,7 @@ private void apply(LauncherVerifier verifier, JPackageCommand cmd) { private final BiConsumer action; static final List VERIFY_APP_IMAGE = List.of( - VERIFY_ICON, VERIFY_DESCRIPTION, VERIFY_INSTALLED, VERIFY_APP_IMAGE_FILE + VERIFY_ICON, VERIFY_DESCRIPTION, VERIFY_INSTALLED, VERIFY_APP_IMAGE_FILE, VERIFY_MAC_ENTITLEMENTS ); static final List VERIFY_DEFAULTS = Stream.concat( @@ -323,6 +333,24 @@ private void verifyInAppImageFile(JPackageCommand cmd) { } } + private void verifyMacEntitlements(JPackageCommand cmd) throws ParserConfigurationException, SAXException, IOException { + Path launcherPath = cmd.appLauncherPath(name); + var entitlements = MacSignVerify.findEntitlements(launcherPath); + + TKit.assertTrue(entitlements.isPresent(), String.format("Check [%s] launcher is signed with entitlements", name)); + + Map expected; + if (cmd.hasArgument("--mac-entitlements")) { + expected = new PListReader(Files.readAllBytes(Path.of(cmd.getArgumentValue("--mac-entitlements")))).toMap(true); + } else if (cmd.hasArgument("--mac-app-store")) { + expected = DefaultEntitlements.APP_STORE; + } else { + expected = DefaultEntitlements.STANDARD; + } + + TKit.assertEquals(expected, entitlements.orElseThrow().toMap(true), String.format("Check [%s] launcher is signed with expected entitlements", name)); + } + private void executeLauncher(JPackageCommand cmd) throws IOException { Path launcherPath = cmd.appLauncherPath(name); @@ -362,6 +390,20 @@ private static Optional iconInResourceDir(JPackageCommand cmd, String laun }); } + + private static final class DefaultEntitlements { + private static Map loadFromResources(String resourceName) { + return ThrowingSupplier.toSupplier(() -> { + var bytes = ResourceLocator.class.getResourceAsStream("entitlements.plist").readAllBytes(); + return new PListReader(bytes).toMap(true); + }).get(); + } + + static final Map STANDARD = loadFromResources("entitlements.plist"); + static final Map APP_STORE = loadFromResources("sandbox.plist"); + } + + private final String name; private final Optional> javaOptions; private final Optional> arguments; diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java index f4feb3e2fde..37e395e1a3e 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java @@ -32,6 +32,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.List; +import java.util.NoSuchElementException; import java.util.Objects; import java.util.Optional; import java.util.Set; @@ -74,9 +75,23 @@ public static void withExplodedDmg(JPackageCommand cmd, Path mountPoint = null; try { - var plist = readPList(attachExecutor.getOutput()); - mountPoint = Path.of(plist.queryValue("mount-point")); + // One of "dict" items of "system-entities" array property should contain "mount-point" string property. + mountPoint = readPList(attachExecutor.getOutput()).queryArrayValue("system-entities", false).map(PListReader.class::cast).map(dict -> { + try { + return dict.queryValue("mount-point"); + } catch (NoSuchElementException ex) { + return (String)null; + } + }).filter(Objects::nonNull).map(Path::of).findFirst().orElseThrow(); + } finally { + if (mountPoint == null) { + TKit.trace("Unexpected plist file missing `system-entities` array:"); + attachExecutor.getOutput().forEach(TKit::trace); + TKit.trace("Done"); + } + } + try { // code here used to copy just or .app // We now have option to include arbitrary content, so we copy // everything in the mounted image. diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacSignVerify.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacSignVerify.java index 432433b4fd0..ae27e292bf6 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacSignVerify.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacSignVerify.java @@ -56,6 +56,17 @@ public static void assertAdhocSigned(Path path) { String.format("Check [%s] signed with adhoc signature", path)); } + public static Optional findEntitlements(Path path) { + final var exec = Executor.of("/usr/bin/codesign", "-d", "--entitlements", "-", "--xml", path.toString()).saveOutput().dumpOutput(); + final var result = exec.execute(); + var xml = result.stdout().getOutput(); + if (xml.isEmpty()) { + return Optional.empty(); + } else { + return Optional.of(MacHelper.readPList(xml)); + } + } + public static void assertUnsigned(Path path) { TKit.assertTrue(findSpctlSignOrigin(SpctlType.EXEC, path).isEmpty(), String.format("Check [%s] unsigned", path)); diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/ToolValidatorTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/ToolValidatorTest.java index c0acea5e3e7..b3660383e47 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/ToolValidatorTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/ToolValidatorTest.java @@ -23,33 +23,141 @@ package jdk.jpackage.internal; -import jdk.jpackage.internal.model.DottedVersion; -import jdk.jpackage.internal.model.ConfigException; -import java.nio.file.Path; -import jdk.internal.util.OperatingSystem; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; + +import java.nio.file.Path; +import java.util.Objects; +import java.util.Set; +import java.util.function.BiFunction; +import java.util.function.Function; +import jdk.internal.util.OperatingSystem; +import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.DottedVersion; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; +import org.junit.jupiter.params.provider.ValueSource; public class ToolValidatorTest { - @Test - public void testAvailable() { - assertNull(new ToolValidator(TOOL_JAVA).validate()); + @ParameterizedTest + @ValueSource(booleans = {true, false}) + public void testAvailable(boolean checkExistsOnly) { + assertNull(new ToolValidator(TOOL_JAVA).checkExistsOnly(checkExistsOnly).validate()); } @Test - public void testNotAvailable() { - assertValidationFailure(new ToolValidator(TOOL_UNKNOWN).validate(), true); + public void testAvailable_setCommandLine() { + // java doesn't recognize "--foo" command line option, but the validation will + // still pass as there is no minimal version specified and the validator ignores + // the exit code + assertNull(new ToolValidator(TOOL_JAVA).setCommandLine("--foo").validate()); + } + + enum TestAvailableMode { + NO_VERSION(null), + TOO_OLD("0.9"), + EQUALS("1.0"), + NEWER("1.1"); + + TestAvailableMode(String parsedVersion) { + this.parsedVersion = parsedVersion; + } + + final String parsedVersion; + } + + @ParameterizedTest + @EnumSource(TestAvailableMode.class) + public void testAvailable(TestAvailableMode mode) { + var minVer = TestAvailableMode.EQUALS.parsedVersion; + var err = new ToolValidator(TOOL_JAVA).setVersionParser(lines -> { + return mode.parsedVersion; + }).setMinimalVersion(DottedVersion.greedy(minVer)).validate(); + + if (Set.of(TestAvailableMode.NO_VERSION, TestAvailableMode.TOO_OLD).contains(mode)) { + var expectedMessage = I18N.format("error.tool-old-version", TOOL_JAVA, minVer); + var expectedAdvice = I18N.format("error.tool-old-version.advice", TOOL_JAVA, minVer); + + assertEquals(expectedMessage, err.getMessage()); + assertEquals(expectedAdvice, err.getAdvice()); + } else { + assertNull(err); + } + } + + @ParameterizedTest + @EnumSource(TestAvailableMode.class) + public void testAvailable_setToolOldVersionErrorHandler(TestAvailableMode mode) { + var handler = new ToolOldVersionErrorHandler(); + var minVer = TestAvailableMode.EQUALS.parsedVersion; + var err = new ToolValidator(TOOL_JAVA).setVersionParser(lines -> { + return mode.parsedVersion; + }).setMinimalVersion(DottedVersion.greedy(minVer)).setToolOldVersionErrorHandler(handler).validate(); + + if (Set.of(TestAvailableMode.NO_VERSION, TestAvailableMode.TOO_OLD).contains(mode)) { + assertSame(ToolOldVersionErrorHandler.ERR, err); + handler.verifyCalled(Path.of(TOOL_JAVA), mode.parsedVersion); + } else { + assertNull(err); + handler.verifyNotCalled(); + } + } + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + public void testNotAvailable(boolean checkExistsOnly, @TempDir Path dir) { + var err = new ToolValidator(dir.resolve("foo")).checkExistsOnly(checkExistsOnly).validate(); + if (checkExistsOnly) { + assertValidationFailure(err, false); + } else { + assertValidationFailureNoAdvice(err, !checkExistsOnly); + } + } + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + public void testToolIsDirectory(boolean checkExistsOnly, @TempDir Path dir) { + var err = new ToolValidator(dir).checkExistsOnly(checkExistsOnly).validate(); + assertValidationFailureNoAdvice(err, !checkExistsOnly); + } + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + public void testNotAvailable_setToolNotFoundErrorHandler(boolean checkExistsOnly, @TempDir Path dir) { + var handler = new ToolNotFoundErrorHandler(); + var err = new ToolValidator(dir.resolve("foo")).checkExistsOnly(checkExistsOnly) + .setToolNotFoundErrorHandler(handler) + .validate(); + if (checkExistsOnly) { + handler.verifyCalled(dir.resolve("foo")); + assertSame(ToolNotFoundErrorHandler.ERR, err); + } else { + handler.verifyNotCalled(); + assertValidationFailureNoAdvice(err, !checkExistsOnly); + } + } + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + public void testToolIsDirectory_setToolNotFoundErrorHandler(boolean checkExistsOnly, @TempDir Path dir) { + var handler = new ToolNotFoundErrorHandler(); + var err = new ToolValidator(dir).checkExistsOnly(checkExistsOnly).validate(); + handler.verifyNotCalled(); + assertValidationFailureNoAdvice(err, !checkExistsOnly); } @Test public void testVersionParserUsage() { // Without minimal version configured, version parser should not be used new ToolValidator(TOOL_JAVA).setVersionParser(unused -> { - throw new RuntimeException(); + throw new AssertionError(); }).validate(); // Minimal version is 1, actual is 10. Should be OK. @@ -81,9 +189,68 @@ private static void assertValidationFailure(ConfigException v, boolean withCause } } + private static void assertValidationFailureNoAdvice(ConfigException v, boolean withCause) { + assertNotNull(v); + assertNotEquals("", v.getMessage().strip()); + assertNull(v.getAdvice()); + if (withCause) { + assertNotNull(v.getCause()); + } else { + assertNull(v.getCause()); + } + } + + + private static final class ToolNotFoundErrorHandler implements Function { + + @Override + public ConfigException apply(Path tool) { + assertNotNull(tool); + this.tool = tool; + return ERR; + } + + void verifyCalled(Path expectedTool) { + assertEquals(Objects.requireNonNull(expectedTool), tool); + } + + void verifyNotCalled() { + assertNull(tool); + } + + private Path tool; + + static final ConfigException ERR = new ConfigException("no tool", "install the tool"); + } + + + private static final class ToolOldVersionErrorHandler implements BiFunction { + + @Override + public ConfigException apply(Path tool, String parsedVersion) { + assertNotNull(tool); + this.tool = tool; + this.parsedVersion = parsedVersion; + return ERR; + } + + void verifyCalled(Path expectedTool, String expectedParsedVersion) { + assertEquals(Objects.requireNonNull(expectedTool), tool); + assertEquals(expectedParsedVersion, parsedVersion); + } + + void verifyNotCalled() { + assertNull(tool); + } + + private Path tool; + private String parsedVersion; + + static final ConfigException ERR = new ConfigException("tool too old", "install the newer version"); + } + + private static final String TOOL_JAVA; - private static final String TOOL_UNKNOWN = Path.of(System.getProperty( - "java.home"), "bin").toString(); static { String fname = "java"; diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/PListReaderTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/PListReaderTest.java index d766505cf14..fe7d0c63870 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/PListReaderTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/PListReaderTest.java @@ -32,14 +32,18 @@ import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.NoSuchElementException; import java.util.Objects; import java.util.Optional; import java.util.function.BiFunction; +import java.util.stream.Stream; import javax.xml.parsers.ParserConfigurationException; +import jdk.jpackage.internal.util.PListReader.Raw; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.EnumSource; +import org.junit.jupiter.params.provider.EnumSource.Mode; import org.junit.jupiter.params.provider.MethodSource; import org.w3c.dom.Node; import org.xml.sax.InputSource; @@ -51,7 +55,23 @@ public class PListReaderTest { enum QueryType { STRING(PListReader::queryValue), BOOLEAN(PListReader::queryBoolValue), - STRING_ARRAY(PListReader::queryArrayValue); + DICT((plistReader, keyName) -> { + return plistReader.queryDictValue(keyName).toMap(true); + }), + STRING_ARRAY(PListReader::queryStringArrayValue), + RAW_ARRAY((plistReader, keyName) -> { + return plistReader.queryArrayValue(keyName, false).toList(); + }), + RAW_ARRAY_RECURSIVE((plistReader, keyName) -> { + return plistReader.queryArrayValue(keyName, true).toList(); + }), + TO_MAP((plistReader, _) -> { + return plistReader.toMap(false); + }), + TO_MAP_RECURSIVE((plistReader, _) -> { + return plistReader.toMap(true); + }), + ; QueryType(BiFunction queryMethod) { this.queryMethod = Objects.requireNonNull(queryMethod); @@ -65,10 +85,10 @@ T queryValue(PListReader pListReader, String keyName) { private final BiFunction queryMethod; } - public record QueryValueTestSpec(QueryType queryType, String keyName, Optional expectedValue, + public record TestSpec(QueryType queryType, Optional keyName, Optional expectedValue, Optional> expectedException, String... xml) { - public QueryValueTestSpec { + public TestSpec { Objects.requireNonNull(queryType); Objects.requireNonNull(keyName); Objects.requireNonNull(expectedValue); @@ -77,6 +97,14 @@ public record QueryValueTestSpec(QueryType queryType, String keyName, Optional {} + default -> { + throw new IllegalArgumentException(); + } + } + } } static final class Builder { @@ -91,7 +119,7 @@ Builder keyName(String v) { return this; } - Builder expectedValue(Object v) { + Builder expect(Object v) { expectedValue = v; if (v instanceof String) { queryType(QueryType.STRING); @@ -99,11 +127,13 @@ Builder expectedValue(Object v) { queryType(QueryType.BOOLEAN); } else if (v instanceof List) { queryType(QueryType.STRING_ARRAY); + } else if (v instanceof Map) { + queryType(QueryType.DICT); } return this; } - Builder expectedException(Class v) { + Builder expectException(Class v) { expectedException = v; return this; } @@ -113,8 +143,11 @@ Builder xml(String... v) { return this; } - QueryValueTestSpec create() { - return new QueryValueTestSpec(queryType, keyName, Optional.ofNullable(expectedValue), + TestSpec create() { + return new TestSpec( + queryType, + Optional.ofNullable(keyName), + Optional.ofNullable(expectedValue), validatedExpectedException(), xml); } @@ -137,12 +170,12 @@ void test() { final var plistReader = new PListReader(createXml(xml)); expectedValue.ifPresent(v -> { - final var actualValue = queryType.queryValue(plistReader, keyName); + final var actualValue = queryType.queryValue(plistReader, keyName.orElse(null)); assertEquals(v, actualValue); }); expectedException.ifPresent(v -> { - assertThrows(v, () -> queryType.queryValue(plistReader, keyName)); + assertThrows(v, () -> queryType.queryValue(plistReader, keyName.orElse(null))); }); } @@ -150,7 +183,9 @@ void test() { public String toString() { final var sb = new StringBuilder(); sb.append(queryType); - sb.append("; key=").append(keyName); + if (keyName != null) { + sb.append("; key=").append(keyName); + } expectedValue.ifPresent(v -> { sb.append("; expected="); sb.append(v); @@ -166,13 +201,13 @@ public String toString() { } @ParameterizedTest - @EnumSource(QueryType.class) + @EnumSource(mode = Mode.MATCH_NONE, names = {"TO_MAP.*"}) public void testNoSuchElement(QueryType queryType) { testSpec(queryType).create().test(); } @ParameterizedTest - @EnumSource(QueryType.class) + @EnumSource(mode = Mode.MATCH_NONE, names = {"TO_MAP.*"}) public void testWrongValueType(QueryType queryType) { final var builder = testSpec(queryType).xml( "string-key", @@ -182,33 +217,56 @@ public void testWrongValueType(QueryType queryType) { "boolean-false-key", "", "array-key", - "b"); + "b", + "dict-key", + "nested-dict-key345"); - List testSpecs = new ArrayList<>(); + List testSpecs = new ArrayList<>(); switch (queryType) { case STRING -> { testSpecs.add(builder.keyName("boolean-true-key").create()); testSpecs.add(builder.keyName("boolean-false-key").create()); testSpecs.add(builder.keyName("array-key").create()); + testSpecs.add(builder.keyName("dict-key").create()); } case BOOLEAN -> { testSpecs.add(builder.keyName("string-key").create()); testSpecs.add(builder.keyName("array-key").create()); + testSpecs.add(builder.keyName("dict-key").create()); } - case STRING_ARRAY -> { + case STRING_ARRAY, RAW_ARRAY, RAW_ARRAY_RECURSIVE -> { testSpecs.add(builder.keyName("string-key").create()); testSpecs.add(builder.keyName("boolean-true-key").create()); testSpecs.add(builder.keyName("boolean-false-key").create()); + testSpecs.add(builder.keyName("dict-key").create()); + } + case DICT -> { + testSpecs.add(builder.keyName("string-key").create()); + testSpecs.add(builder.keyName("boolean-true-key").create()); + testSpecs.add(builder.keyName("boolean-false-key").create()); + testSpecs.add(builder.keyName("array-key").create()); + } + case TO_MAP, TO_MAP_RECURSIVE -> { + throw new UnsupportedOperationException(); } } - testSpecs.forEach(QueryValueTestSpec::test); + testSpecs.forEach(TestSpec::test); + + builder.keyName(null).expect(Map.of( + "string-key", new Raw("a", Raw.Type.STRING), + "boolean-true-key", new Raw(Boolean.TRUE.toString(), Raw.Type.BOOLEAN), + "boolean-false-key", new Raw(Boolean.FALSE.toString(), Raw.Type.BOOLEAN), + "array-key", List.of(new Raw("b", Raw.Type.STRING)), + "dict-key", Map.of("nested-dict-key", new Raw("345", Raw.Type.INTEGER)) + )).queryType(QueryType.TO_MAP_RECURSIVE).create().test(); + } @ParameterizedTest @MethodSource - public void testQueryValue(QueryValueTestSpec testSpec) { + public void test(TestSpec testSpec) { testSpec.test(); } @@ -219,28 +277,190 @@ public void testByteArrayCtor() throws ParserConfigurationException, SAXExceptio assertEquals("A", actualValue); } - private static List testQueryValue() { - return List.of( - testSpec().expectedValue("A").xml("fooA").create(), - testSpec().expectedValue("").xml("foo").create(), - testSpec().xml("foo").create(), - testSpec().expectedValue(Boolean.TRUE).xml("foo").create(), - testSpec().expectedValue(Boolean.FALSE).xml("foo").create(), - testSpec(QueryType.BOOLEAN).xml("foo").create(), - testSpec(QueryType.BOOLEAN).xml("foo").create(), - testSpec().expectedValue(List.of("foo", "bar")).xml("foofoobar").create(), - testSpec().expectedValue(List.of()).xml("foo").create(), - testSpec(QueryType.STRING_ARRAY).xml("foo").create(), - testSpec().expectedValue("A").xml("fooAB").create(), - testSpec().expectedValue("A").xml("fooAfooB").create() + @Test + public void test_toMap() { + + var builder = testSpec(); + + builder.xml( + "AppName", + "Hello", + "", + "AppVersion", + "1.0", + "Release", + "", + "Debug", + "", + "ReleaseDate", + "2025-09-24T09:23:00Z", + "UserData", + "", + "", + " Foo", + " ", + " Str", + " ", + " Another Str", + " ", + " ", + " ", + " ", + "", + "Checksum", + "7841ff0076cdde93bdca02cfd332748c40620ce4", + "Plugins", + "", + " ", + " PluginName", + " Foo", + " Priority", + " 13", + " History", + " ", + " New File", + " Another New File", + " ", + " ", + " ", + " PluginName", + " Bar", + " Priority", + " 23", + " History", + " ", + " ", + "" ); + + var expected = Map.of( + "AppName", new Raw("Hello", Raw.Type.STRING), + "AppVersion", new Raw("1.0", Raw.Type.REAL), + "Release", new Raw(Boolean.TRUE.toString(), Raw.Type.BOOLEAN), + "Debug", new Raw(Boolean.FALSE.toString(), Raw.Type.BOOLEAN), + "ReleaseDate", new Raw("2025-09-24T09:23:00Z", Raw.Type.DATE), + "Checksum", new Raw("7841ff0076cdde93bdca02cfd332748c40620ce4", Raw.Type.DATA), + "UserData", Map.of( + "Foo", List.of( + new Raw("Str", Raw.Type.STRING), + List.of( + new Raw("Another Str", Raw.Type.STRING), + new Raw(Boolean.TRUE.toString(), Raw.Type.BOOLEAN), + new Raw(Boolean.FALSE.toString(), Raw.Type.BOOLEAN) + ) + ) + ), + "Plugins", List.of( + Map.of( + "PluginName", new Raw("Foo", Raw.Type.STRING), + "Priority", new Raw("13", Raw.Type.INTEGER), + "History", List.of( + new Raw("New File", Raw.Type.STRING), + new Raw("Another New File", Raw.Type.STRING) + ) + ), + Map.of( + "PluginName", new Raw("Bar", Raw.Type.STRING), + "Priority", new Raw("23", Raw.Type.REAL), + "History", List.of() + ) + ) + ); + + builder.expect(expected).queryType(QueryType.TO_MAP_RECURSIVE).create().test(); + } + + private static List test() { + + List data = new ArrayList<>(); + + Stream.of( + testSpec().expect("A").xml("fooA"), + testSpec().expect("A").xml("BfooA"), + testSpec().expect("").xml("foo some text "), + testSpec().xml("foo"), + testSpec().xml("foo"), + testSpec().xml("fooA"), + testSpec().expect(Boolean.TRUE).xml("foo"), + testSpec().expect(Boolean.FALSE).xml("foo"), + testSpec(QueryType.BOOLEAN).xml("foo"), + testSpec(QueryType.BOOLEAN).xml("foo"), + testSpec().expect(List.of("foo", "bar")).xml("foofoobar"), + testSpec().expect(List.of()).xml("foo"), + testSpec(QueryType.STRING_ARRAY).xml("foo"), + testSpec().expect("A").xml("fooAB"), + testSpec().expect("A").xml("fooAfooB"), + + testSpec().expect(Map.of()).xml("foo"), + + // + // Test that if there are multiple keys with the same name, all but the first are ignored. + // + testSpec().expect("A").xml("fooAfooBfooC"), + testSpec().expect("A").xml("fooAfooB"), + testSpec(QueryType.STRING).xml("fooBfooA"), + testSpec().expect(Boolean.TRUE).xml("foofoo"), + testSpec().expect(Boolean.TRUE).xml("foofoo"), + testSpec(QueryType.BOOLEAN).xml("foofoo"), + + // + // Test that it doesn't look up keys in nested "dict" or "array" elements. + // + testSpec().xml("foofooA"), + testSpec().expect("B").xml("barfooAfooB"), + testSpec().xml("foofooA"), + testSpec().expect("B").xml("barfooAfooB"), + + // + // Test empty arrays. + // + testSpec().expect(List.of()).queryType(QueryType.RAW_ARRAY_RECURSIVE).xml("foo"), + testSpec().expect(List.of()).queryType(QueryType.RAW_ARRAY).xml("foo") + + ).map(TestSpec.Builder::create).forEach(data::add); + + // + // Test toMap() method. + // + Stream.of( + testSpec().expect(Map.of()).xml(), + testSpec().expect(Map.of()).xml("foobar"), + testSpec().expect(Map.of()).xml("Abar"), + testSpec().expect(Map.of()).xml("A"), + testSpec().expect(Map.of()).xml("fooA"), + testSpec().expect(Map.of("foo", new Raw("A", Raw.Type.STRING))).xml("fooAB"), + testSpec().expect(Map.of("foo", new Raw("A", Raw.Type.STRING))).xml("fooA hello foo bye B"), + testSpec().expect(Map.of("foo", new Raw("A", Raw.Type.STRING), "Foo", new Raw("B", Raw.Type.STRING))).xml("fooAFooB") + ).map(builder -> { + return builder.queryType(QueryType.TO_MAP_RECURSIVE); + }).map(TestSpec.Builder::create).forEach(data::add); + + var arrayTestSpec = testSpec().expect(List.of( + new Raw("Hello", Raw.Type.STRING), + Map.of("foo", new Raw("Bye", Raw.Type.STRING)), + new Raw("integer", Raw.Type.INTEGER), + Map.of(), + new Raw(Boolean.TRUE.toString(), Raw.Type.BOOLEAN) + )).queryType(QueryType.RAW_ARRAY_RECURSIVE); + + Stream.of( + "HellofooByeinteger", + "HelloBingofooByeinteger", + "BHellofooByeByeeeinteger", + "HellobarfooByeinteger", + "HellofooByefooByeByeinteger" + ).map(xml -> { + return "foo" + xml + ""; + }).map(arrayTestSpec::xml).map(TestSpec.Builder::create).forEach(data::add); + + return data; } - private static QueryValueTestSpec.Builder testSpec() { - return new QueryValueTestSpec.Builder(); + private static TestSpec.Builder testSpec() { + return new TestSpec.Builder(); } - private static QueryValueTestSpec.Builder testSpec(QueryType queryType) { + private static TestSpec.Builder testSpec(QueryType queryType) { return testSpec().queryType(queryType); } @@ -248,7 +468,9 @@ private static String xmlToString(String ...xml) { final List content = new ArrayList<>(); content.add(""); content.add(""); + content.add(""); content.addAll(List.of(xml)); + content.add(""); content.add(""); return String.join("", content.toArray(String[]::new)); } diff --git a/test/jdk/tools/jpackage/macosx/MacFileAssociationsTest.java b/test/jdk/tools/jpackage/macosx/MacFileAssociationsTest.java index 81831f59da3..e6d8b41f05f 100644 --- a/test/jdk/tools/jpackage/macosx/MacFileAssociationsTest.java +++ b/test/jdk/tools/jpackage/macosx/MacFileAssociationsTest.java @@ -21,15 +21,16 @@ * questions. */ +import static java.util.Map.entry; + import java.nio.file.Path; import java.util.List; import java.util.Map; -import static java.util.Map.entry; -import jdk.jpackage.test.JPackageCommand; -import jdk.jpackage.test.TKit; -import jdk.jpackage.test.MacHelper; import jdk.jpackage.internal.util.PListReader; import jdk.jpackage.test.Annotations.Test; +import jdk.jpackage.test.JPackageCommand; +import jdk.jpackage.test.MacHelper; +import jdk.jpackage.test.TKit; /** * Tests generation of app image with --file-associations and mac additional file @@ -80,21 +81,26 @@ private static void checkStringValue(PListReader plist, String key, String value "Check value of %s plist key", key)); } - private static void checkBoolValue(PListReader plist, String key, Boolean value) { - Boolean result = plist.queryBoolValue(key); - TKit.assertEquals(value.toString(), result.toString(), String.format( + private static void checkBoolValue(PListReader plist, String key, boolean value) { + boolean result = plist.queryBoolValue(key); + TKit.assertEquals(value, result, String.format( "Check value of %s plist key", key)); } private static void checkArrayValue(PListReader plist, String key, List values) { - List result = plist.queryArrayValue(key); + List result = plist.queryStringArrayValue(key); TKit.assertStringListEquals(values, result, String.format( "Check value of %s plist key", key)); } private static void verifyPList(Path appImage) throws Exception { - var plist = MacHelper.readPListFromAppImage(appImage); + final var rootPlist = MacHelper.readPListFromAppImage(appImage); + + TKit.traceFileContents(appImage.resolve("Contents/Info.plist"), "Info.plist"); + + var plist = rootPlist.queryArrayValue("CFBundleDocumentTypes", false).findFirst().map(PListReader.class::cast).orElseThrow(); + checkStringValue(plist, "CFBundleTypeRole", "Viewer"); checkStringValue(plist, "LSHandlerRank", "Default"); checkStringValue(plist, "NSDocumentClass", "SomeClass"); @@ -103,10 +109,13 @@ private static void verifyPList(Path appImage) throws Exception { checkBoolValue(plist, "LSSupportsOpeningDocumentsInPlace", false); checkBoolValue(plist, "UISupportsDocumentBrowser", false); - checkArrayValue(plist, "NSExportableTypes", List.of("public.png", - "public.jpg")); + plist = rootPlist.queryArrayValue("UTExportedTypeDeclarations", false).findFirst().map(PListReader.class::cast).orElseThrow(); + + checkArrayValue(plist, "UTTypeConformsTo", List.of("public.image", "public.data")); + + plist = plist.queryDictValue("UTTypeTagSpecification"); + + checkArrayValue(plist, "NSExportableTypes", List.of("public.png", "public.jpg")); - checkArrayValue(plist, "UTTypeConformsTo", List.of("public.image", - "public.data")); } } diff --git a/test/langtools/ProblemList.txt b/test/langtools/ProblemList.txt index 59b5b240a29..9d61a20663d 100644 --- a/test/langtools/ProblemList.txt +++ b/test/langtools/ProblemList.txt @@ -52,8 +52,6 @@ jdk/jshell/UserJdiUserRemoteTest.java jdk/jshell/UserInputTest.java 8169536 generic-all jdk/jshell/ToolBasicTest.java 8265357 macosx-aarch64 jdk/jshell/HighlightUITest.java 8284144 generic-all -jdk/jshell/ToolSimpleTest.java 8366582 generic-all -jdk/jshell/ToolLocalSimpleTest.java 8366582 generic-all ########################################################################### # diff --git a/test/langtools/jdk/jshell/CompletionSuggestionTest.java b/test/langtools/jdk/jshell/CompletionSuggestionTest.java index 19f7b89a1b3..7907fa4d027 100644 --- a/test/langtools/jdk/jshell/CompletionSuggestionTest.java +++ b/test/langtools/jdk/jshell/CompletionSuggestionTest.java @@ -941,4 +941,14 @@ public void testAnnotation() { assertEval("import static java.lang.annotation.RetentionPolicy.*;"); assertCompletion("@AnnA(C|", true, "CLASS"); } + + @Test + public void testMultiSnippet() { + assertCompletion("String s = \"\"; s.len|", true, "length()"); + assertCompletion("String s() { return \"\"; } s().len|", true, "length()"); + assertCompletion("String s() { return \"\"; } import java.util.List; List.o|", true, "of("); + assertCompletion("String s() { return \"\"; } import java.ut| ", true, "util."); + assertCompletion("class S { public int length() { return 0; } } new S().len|", true, "length()"); + assertSignature("void f() { } f(|", "void f()"); + } } diff --git a/test/langtools/tools/javac/platform/CompilationTest.java b/test/langtools/tools/javac/platform/CompilationTest.java new file mode 100644 index 00000000000..93fb2fb2678 --- /dev/null +++ b/test/langtools/tools/javac/platform/CompilationTest.java @@ -0,0 +1,75 @@ +/* + * 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 8365060 + * @summary Verify javac can compile given snippets with --release + * @library /tools/lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * jdk.compiler/com.sun.tools.javac.platform + * jdk.compiler/com.sun.tools.javac.util:+open + * @build toolbox.ToolBox CompilationTest + * @run main CompilationTest + */ + +import java.io.IOException; +import java.net.URISyntaxException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import toolbox.JavacTask; +import toolbox.Task; +import toolbox.ToolBox; + +public class CompilationTest { + + private final ToolBox tb = new ToolBox(); + public static void main(String... args) throws IOException, URISyntaxException { + CompilationTest t = new CompilationTest(); + + t.testJdkNet(); + } + + void testJdkNet() throws IOException { + Path root = Paths.get("."); + Path classes = root.resolve("classes"); + Files.createDirectories(classes); + + new JavacTask(tb) + .outdir(classes) + .options("--release", "8", + "-XDrawDiagnostics") + .sources(""" + import jdk.net.ExtendedSocketOptions; + public class Test { + } + """) + .run() + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + } + +} diff --git a/test/langtools/tools/javac/sym/ElementStructureTest.java b/test/langtools/tools/javac/sym/ElementStructureTest.java index f1cc3cd91fe..14fa194501a 100644 --- a/test/langtools/tools/javac/sym/ElementStructureTest.java +++ b/test/langtools/tools/javac/sym/ElementStructureTest.java @@ -132,10 +132,10 @@ public class ElementStructureTest { (byte) 0x3D, (byte) 0xC1, (byte) 0xFE, (byte) 0xCB }; static final byte[] hash8 = new byte[] { - (byte) 0x10, (byte) 0xE6, (byte) 0xE8, (byte) 0x11, - (byte) 0xC8, (byte) 0x02, (byte) 0x63, (byte) 0x9B, - (byte) 0xAB, (byte) 0x11, (byte) 0x9E, (byte) 0x4F, - (byte) 0xFA, (byte) 0x00, (byte) 0x6D, (byte) 0x81 + (byte) 0x07, (byte) 0xAB, (byte) 0x0A, (byte) 0x8D, + (byte) 0x1C, (byte) 0x44, (byte) 0x6D, (byte) 0x71, + (byte) 0x07, (byte) 0x53, (byte) 0x59, (byte) 0x74, + (byte) 0x5B, (byte) 0x49, (byte) 0x60, (byte) 0xAD }; final static Map version2Hash = new HashMap<>(); @@ -283,7 +283,7 @@ void realClasses(String location, Predicate acceptor, Writer output, Str } JavaFileObject file = new ByteArrayJavaFileObject(data.toByteArray()); try (InputStream in = new ByteArrayInputStream(data.toByteArray())) { - String name = ClassFile.of().parse(in.readAllBytes()).thisClass().name().stringValue(); + String name = ClassFile.of().parse(in.readAllBytes()).thisClass().name().stringValue().replace("/", "."); className2File.put(name, file); file2ClassName.put(file, name); } catch (IOException ex) { @@ -514,6 +514,8 @@ private void writeConstant(Object value) throws IOException { out.write(Double.toHexString((Double) value)); } else if (value instanceof Float) { out.write(Float.toHexString((Float) value)); + } else if (value instanceof Character ch && Character.isSurrogate(ch)) { + out.write(Integer.toHexString(ch)); } else { out.write(String.valueOf(value)); } diff --git a/test/langtools/tools/javac/tree/TreePosTest.java b/test/langtools/tools/javac/tree/TreePosTest.java index 0ae62ca940d..9e6dcf61306 100644 --- a/test/langtools/tools/javac/tree/TreePosTest.java +++ b/test/langtools/tools/javac/tree/TreePosTest.java @@ -38,16 +38,11 @@ import java.io.PrintStream; import java.io.PrintWriter; import java.io.StringWriter; -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; -import java.nio.charset.Charset; +import java.io.UncheckedIOException; import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; -import java.util.Map; import java.util.Set; import javax.swing.DefaultComboBoxModel; import javax.swing.JComboBox; @@ -71,7 +66,7 @@ import com.sun.source.tree.CaseTree.CaseKind; import com.sun.source.tree.CompilationUnitTree; -import com.sun.source.util.JavacTask; +import com.sun.tools.javac.api.JavacTaskPool; import com.sun.tools.javac.api.JavacTool; import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.tree.EndPosTable; @@ -80,7 +75,6 @@ import com.sun.tools.javac.tree.JCTree.JCCase; import com.sun.tools.javac.tree.JCTree.JCClassDecl; import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; -import com.sun.tools.javac.tree.JCTree.JCImport; import com.sun.tools.javac.tree.JCTree.JCImportBase; import com.sun.tools.javac.tree.JCTree.JCMethodDecl; import com.sun.tools.javac.tree.JCTree.JCNewClass; @@ -90,7 +84,6 @@ import static com.sun.tools.javac.tree.JCTree.Tag.*; import static com.sun.tools.javac.util.Position.NOPOS; -import java.util.stream.Stream; /** * Utility and test program to check validity of tree positions for tree nodes. @@ -275,6 +268,7 @@ void test(File file) { PrintWriter pw = new PrintWriter(sw); Reporter r = new Reporter(pw); JavacTool tool = JavacTool.create(); + JavacTaskPool pool = new JavacTaskPool(1); StandardJavaFileManager fm = tool.getStandardFileManager(r, null, null); /** @@ -285,21 +279,25 @@ void test(File file) { * @throws TreePosTest.ParseException if any errors occur while parsing the file */ JCCompilationUnit read(File file) throws IOException, ParseException { - JavacTool tool = JavacTool.create(); r.errors = 0; Iterable files = fm.getJavaFileObjects(file); - JavacTask task = tool.getTask(pw, fm, r, List.of("-proc:none"), null, files); - Iterable trees = task.parse(); - pw.flush(); - if (r.errors > 0) - throw new ParseException(sw.toString()); - Iterator iter = trees.iterator(); - if (!iter.hasNext()) - throw new Error("no trees found"); - JCCompilationUnit t = (JCCompilationUnit) iter.next(); - if (iter.hasNext()) - throw new Error("too many trees found"); - return t; + return pool.getTask(pw, fm, r, List.of("-proc:none"), null, files, task -> { + try { + Iterable trees = task.parse(); + pw.flush(); + if (r.errors > 0) + throw new ParseException(sw.toString()); + Iterator iter = trees.iterator(); + if (!iter.hasNext()) + throw new Error("no trees found"); + JCCompilationUnit t = (JCCompilationUnit) iter.next(); + if (iter.hasNext()) + throw new Error("too many trees found"); + return t; + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + }); } /** @@ -546,7 +544,7 @@ public String toString() { /** * Thrown when errors are found parsing a java file. */ - private static class ParseException extends Exception { + private static class ParseException extends RuntimeException { ParseException(String msg) { super(msg); } diff --git a/test/lib/jdk/test/lib/artifacts/ArtifactResolver.java b/test/lib/jdk/test/lib/artifacts/ArtifactResolver.java index 83e381356a0..fb67ce83bbe 100644 --- a/test/lib/jdk/test/lib/artifacts/ArtifactResolver.java +++ b/test/lib/jdk/test/lib/artifacts/ArtifactResolver.java @@ -23,8 +23,7 @@ package jdk.test.lib.artifacts; -import jtreg.SkippedException; - +import java.io.IOException; import java.nio.file.Path; import java.util.HashMap; import java.util.Map; @@ -90,15 +89,15 @@ public static Path resolve(String name, Map artifactDescription, * @return the local path to the artifact. If the artifact is a compressed * file that gets unpacked, this path will point to the root * directory of the uncompressed file(s). - * @throws SkippedException thrown if the artifact cannot be found + * @throws IOException thrown if the artifact cannot be found */ - public static Path fetchOne(Class klass) { + public static Path fetchOne(Class klass) throws IOException { try { return ArtifactResolver.resolve(klass).entrySet().stream() .findAny().get().getValue(); } catch (ArtifactResolverException e) { Artifact artifact = klass.getAnnotation(Artifact.class); - throw new SkippedException("Cannot find the artifact " + artifact.name(), e); + throw new IOException("Cannot find the artifact " + artifact.name(), e); } } diff --git a/test/lib/jdk/test/lib/security/OpensslArtifactFetcher.java b/test/lib/jdk/test/lib/security/OpensslArtifactFetcher.java index 82252000154..6fa8cb2e408 100644 --- a/test/lib/jdk/test/lib/security/OpensslArtifactFetcher.java +++ b/test/lib/jdk/test/lib/security/OpensslArtifactFetcher.java @@ -23,6 +23,7 @@ package jdk.test.lib.security; +import java.io.IOException; import java.nio.file.Path; import jdk.test.lib.Platform; import jdk.test.lib.process.ProcessTools; @@ -49,42 +50,40 @@ public class OpensslArtifactFetcher { * * @return openssl binary path of the current version * @throws SkippedException if a valid version of OpenSSL cannot be found + * or if OpenSSL is not available on the target platform */ public static String getOpensslPath() { String path = getOpensslFromSystemProp(OPENSSL_BUNDLE_VERSION); if (path != null) { + System.out.println("Using OpenSSL from system property."); return path; } + path = getDefaultSystemOpensslPath(OPENSSL_BUNDLE_VERSION); if (path != null) { + System.out.println("Using OpenSSL from system."); return path; } + if (Platform.isX64()) { if (Platform.isLinux()) { - path = fetchOpenssl(LINUX_X64.class); + return fetchOpenssl(LINUX_X64.class); } else if (Platform.isOSX()) { - path = fetchOpenssl(MACOSX_X64.class); + return fetchOpenssl(MACOSX_X64.class); } else if (Platform.isWindows()) { - path = fetchOpenssl(WINDOWS_X64.class); + return fetchOpenssl(WINDOWS_X64.class); } } else if (Platform.isAArch64()) { if (Platform.isLinux()) { - path = fetchOpenssl(LINUX_AARCH64.class); + return fetchOpenssl(LINUX_AARCH64.class); } if (Platform.isOSX()) { - path = fetchOpenssl(MACOSX_AARCH64.class); + return fetchOpenssl(MACOSX_AARCH64.class); } } - if (!verifyOpensslVersion(path, OPENSSL_BUNDLE_VERSION)) { - String exMsg = "Can't find the version: " - + OpensslArtifactFetcher.getTestOpensslBundleVersion() - + " of openssl binary on this machine, please install" - + " and set openssl path with property 'test.openssl.path'"; - throw new SkippedException(exMsg); - } else { - return path; - } + throw new SkippedException(String.format("No OpenSSL %s found for %s/%s", + OPENSSL_BUNDLE_VERSION, Platform.getOsName(), Platform.getOsArch())); } private static String getOpensslFromSystemProp(String version) { @@ -120,9 +119,13 @@ private static boolean verifyOpensslVersion(String path, String version) { } private static String fetchOpenssl(Class clazz) { - return ArtifactResolver.fetchOne(clazz) - .resolve("openssl", "bin", "openssl") - .toString(); + try { + return ArtifactResolver.fetchOne(clazz) + .resolve("openssl", "bin", "openssl") + .toString(); + } catch (IOException exc) { + throw new SkippedException("Could not find openssl", exc); + } } // retrieve the provider directory path from /bin/openssl diff --git a/test/lib/jdk/test/lib/threaddump/ThreadDump.java b/test/lib/jdk/test/lib/threaddump/ThreadDump.java index f4964a9521f..ca728e625fc 100644 --- a/test/lib/jdk/test/lib/threaddump/ThreadDump.java +++ b/test/lib/jdk/test/lib/threaddump/ThreadDump.java @@ -296,6 +296,16 @@ public String parkBlocker() { return getStringProperty("parkBlocker", "object"); } + /** + * Returns the owner of the parkBlocker if the parkBlocker is an AbstractOwnableSynchronizer. + */ + public OptionalLong parkBlockerOwner() { + String owner = getStringProperty("parkBlocker", "owner"); + return (owner != null) + ? OptionalLong.of(Long.parseLong(owner)) + : OptionalLong.empty(); + } + /** * Returns the object that the thread is blocked entering its monitor. */ diff --git a/test/micro/org/openjdk/bench/java/text/DefFormatterBench.java b/test/micro/org/openjdk/bench/java/text/DefFormatterBench.java index 1da18cc97a0..cd49469c15d 100644 --- a/test/micro/org/openjdk/bench/java/text/DefFormatterBench.java +++ b/test/micro/org/openjdk/bench/java/text/DefFormatterBench.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 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,13 +22,16 @@ */ package org.openjdk.bench.java.text; +import java.math.BigDecimal; import java.text.NumberFormat; import java.util.Locale; import java.util.concurrent.TimeUnit; +import java.util.stream.DoubleStream; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Level; import org.openjdk.jmh.annotations.Measurement; import org.openjdk.jmh.annotations.Mode; import org.openjdk.jmh.annotations.OperationsPerInvocation; @@ -50,25 +53,52 @@ @State(Scope.Benchmark) public class DefFormatterBench { + public static final int VALUES_SIZE = 13; public double[] values; + public BigDecimal[] bdLargeValues; + public BigDecimal[] bdSmallValues; - @Setup + @Setup(Level.Invocation) public void setup() { values = new double[] { 1.23, 1.49, 1.80, 1.7, 0.0, -1.49, -1.50, 9999.9123, 1.494, 1.495, 1.03, 25.996, -25.996 }; + + bdLargeValues = DoubleStream.of(values) + .mapToObj(BigDecimal::new) + .toArray(BigDecimal[]::new); + + bdSmallValues = DoubleStream.of(values) + .mapToObj(BigDecimal::valueOf) + .toArray(BigDecimal[]::new); } private DefNumberFormat dnf = new DefNumberFormat(); @Benchmark - @OperationsPerInvocation(13) + @OperationsPerInvocation(VALUES_SIZE) public void testDefNumberFormatter(final Blackhole blackhole) { for (double value : values) { blackhole.consume(this.dnf.format(value)); } } + @Benchmark + @OperationsPerInvocation(VALUES_SIZE) + public void testSmallBigDecDefNumberFormatter(final Blackhole blackhole) { + for (BigDecimal value : bdSmallValues) { + blackhole.consume(this.dnf.format(value)); + } + } + + @Benchmark + @OperationsPerInvocation(VALUES_SIZE) + public void testLargeBigDecDefNumberFormatter(final Blackhole blackhole) { + for (BigDecimal value : bdLargeValues) { + blackhole.consume(this.dnf.format(value)); + } + } + public static void main(String... args) throws Exception { Options opts = new OptionsBuilder().include(DefFormatterBench.class.getSimpleName()).shouldDoGC(true).build(); new Runner(opts).run(); @@ -88,5 +118,9 @@ public DefNumberFormat() { public String format(final double d) { return this.n.format(d); } + + public String format(final BigDecimal bd) { + return this.n.format(bd); + } } }