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

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

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

  • {@code mm} is the minute within the hour ({@code 00} through * {@code 59}), as two decimal digits. *
  • {@code ss} is the second within the minute ({@code 00} through - * {@code 61}, as two decimal digits. + * {@code 61}), as two decimal digits. *
  • {@code zzz} is the time zone (and may reflect daylight saving * time). Standard time zone abbreviations include those * recognized by the method {@code parse}. If time zone From 98562166e4a4c8921709014423c6cbc993aa0d97 Mon Sep 17 00:00:00 2001 From: Zdenek Zambersky Date: Mon, 5 Aug 2024 15:09:45 +0000 Subject: [PATCH 13/17] 8336928: GHA: Bundle artifacts removal broken Reviewed-by: ihse --- .github/workflows/main.yml | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 067548b9768e3..b16335b7091c2 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -363,26 +363,23 @@ jobs: - test-windows-x64 steps: - # Hack to get hold of the api environment variables that are only defined for actions - - name: 'Get API configuration' - id: api - uses: actions/github-script@v7 - with: - script: 'return { url: process.env["ACTIONS_RUNTIME_URL"], token: process.env["ACTIONS_RUNTIME_TOKEN"] }' - - name: 'Remove bundle artifacts' run: | # Find and remove all bundle artifacts - ALL_ARTIFACT_URLS="$(curl -s \ - -H 'Accept: application/json;api-version=6.0-preview' \ - -H 'Authorization: Bearer ${{ fromJson(steps.api.outputs.result).token }}' \ - '${{ fromJson(steps.api.outputs.result).url }}_apis/pipelines/workflows/${{ github.run_id }}/artifacts?api-version=6.0-preview')" - BUNDLE_ARTIFACT_URLS="$(echo "$ALL_ARTIFACT_URLS" | jq -r -c '.value | map(select(.name|startswith("bundles-"))) | .[].url')" - for url in $BUNDLE_ARTIFACT_URLS; do - echo "Removing $url" - curl -s \ - -H 'Accept: application/json;api-version=6.0-preview' \ - -H 'Authorization: Bearer ${{ fromJson(steps.api.outputs.result).token }}' \ - -X DELETE "$url" \ + # See: https://docs.github.com/en/rest/actions/artifacts?apiVersion=2022-11-28 + ALL_ARTIFACT_IDS="$(curl -sL \ + -H 'Accept: application/vnd.github+json' \ + -H 'Authorization: Bearer ${{ github.token }}' \ + -H 'X-GitHub-Api-Version: 2022-11-28' \ + '${{ github.api_url }}/repos/${{ github.repository }}/actions/runs/${{ github.run_id }}/artifacts')" + BUNDLE_ARTIFACT_IDS="$(echo "$ALL_ARTIFACT_IDS" | jq -r -c '.artifacts | map(select(.name|startswith("bundles-"))) | .[].id')" + for id in $BUNDLE_ARTIFACT_IDS; do + echo "Removing $id" + curl -sL \ + -X DELETE \ + -H 'Accept: application/vnd.github+json' \ + -H 'Authorization: Bearer ${{ github.token }}' \ + -H 'X-GitHub-Api-Version: 2022-11-28' \ + "${{ github.api_url }}/repos/${{ github.repository }}/actions/artifacts/$id" \ || echo "Failed to remove bundle" done From e68df528f80cff3a5564a12b7ec71a920800ce28 Mon Sep 17 00:00:00 2001 From: Damon Nguyen Date: Mon, 5 Aug 2024 16:48:18 +0000 Subject: [PATCH 14/17] 8337054: JDK 23 RDP2 L10n resource files update Reviewed-by: naoto, jlu --- .../tools/javac/resources/compiler_de.properties | 9 +++++---- .../tools/javac/resources/compiler_ja.properties | 9 +++++---- .../javac/resources/compiler_zh_CN.properties | 15 ++++++++------- .../javac/resources/launcher_zh_CN.properties | 2 +- .../toolkit/resources/doclets_de.properties | 4 ++-- .../toolkit/resources/doclets_ja.properties | 4 ++-- .../toolkit/resources/doclets_zh_CN.properties | 4 ++-- 7 files changed, 25 insertions(+), 22 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler_de.properties b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler_de.properties index dfbeb0fd0b715..33063b6558d3a 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler_de.properties +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler_de.properties @@ -2305,13 +2305,14 @@ compiler.err.this.as.identifier=Ab Release 8 ist "this" nur als Parametername f compiler.err.receiver.parameter.not.applicable.constructor.toplevel.class=receiver-Parameter nicht für Konstruktor der obersten Klasse anwendbar -# TODO 308: make a better error message +# 0: fragment, 1: symbol, 2: annotated-type +compiler.err.type.annotation.inadmissible={0} wurde hier nicht erwartet\n(Um einen qualifizierten Typ zu annotieren, schreiben Sie {1}.{2}) + # 0: annotation -compiler.err.cant.type.annotate.scoping.1=Scoping-Konstrukt kann nicht mit type-use-Annotation versehen werden: {0} +compiler.misc.type.annotation.1=Typannotation {0} ist -# TODO 308: make a better error message # 0: list of annotation -compiler.err.cant.type.annotate.scoping=Scoping-Konstrukt kann nicht mit type-use-Annotationen versehen werden: {0} +compiler.misc.type.annotation=Typannotationen {0} sind # 0: type, 1: type compiler.err.incorrect.receiver.name=Der Empfängername stimmt nicht mit dem einschließenden Klassentyp überein\nErforderlich: {0}\nErmittelt: {1} diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler_ja.properties b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler_ja.properties index 4d98e4cabccba..818b5fb70668b 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler_ja.properties +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler_ja.properties @@ -2305,13 +2305,14 @@ compiler.err.this.as.identifier=リリース8から''this''は受信タイプの compiler.err.receiver.parameter.not.applicable.constructor.toplevel.class=受取り側パラメータは最上位レベル・クラスのコンストラクタに適用できません -# TODO 308: make a better error message +# 0: fragment, 1: symbol, 2: annotated-type +compiler.err.type.annotation.inadmissible=ここでは{0}は予期されていません\n(修飾されたタイプに注釈を付けるには、{1}.{2}と記述します) + # 0: annotation -compiler.err.cant.type.annotate.scoping.1=スコープ・コンストラクトを型使用注釈で注釈付けすることはできません: {0} +compiler.misc.type.annotation.1=タイプ注釈{0}は -# TODO 308: make a better error message # 0: list of annotation -compiler.err.cant.type.annotate.scoping=スコープ・コンストラクトを型使用注釈で注釈付けすることはできません: {0} +compiler.misc.type.annotation=タイプ注釈{0}は # 0: type, 1: type compiler.err.incorrect.receiver.name=受取り側の名前が、包含するクラス・タイプと一致しません\n必須: {0}\n検出: {1} diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler_zh_CN.properties b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler_zh_CN.properties index 81452f23a0d55..54298cb23b912 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler_zh_CN.properties +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler_zh_CN.properties @@ -93,7 +93,7 @@ compiler.err.abstract.cant.be.instantiated={0}是抽象的; 无法实例化 compiler.err.abstract.meth.cant.have.body=抽象方法不能有主体 # 0: kind name, 1: symbol -compiler.err.already.annotated={0} {1}已进行注释 +compiler.err.already.annotated={0} {1} 已进行批注 # 0: kind name, 1: symbol, 2: kind name, 3: symbol compiler.err.already.defined=已在{2} {3}中定义了{0} {1} @@ -642,7 +642,7 @@ compiler.err.malformed.fp.lit=浮点文字的格式错误 compiler.err.method.does.not.override.superclass=方法不会覆盖或实现超类型的方法 -compiler.err.static.methods.cannot.be.annotated.with.override=不能使用 @Override 注释静态方法 +compiler.err.static.methods.cannot.be.annotated.with.override=不能使用 @Override 对静态方法进行批注 compiler.err.missing.meth.body.or.decl.abstract=缺少方法主体, 或声明抽象 @@ -1638,7 +1638,7 @@ compiler.warn.unchecked.varargs.non.reifiable.type=参数化 vararg 类型{0}的 # 0: symbol compiler.warn.varargs.unsafe.use.varargs.param=Varargs 方法可能导致来自不可具体化 varargs 参数 {0} 的堆污染 -compiler.warn.missing.deprecated.annotation=未使用 @Deprecated 对已过时的项目进行注释 +compiler.warn.missing.deprecated.annotation=未使用 @Deprecated 对已过时的项目进行批注 # 0: kind name compiler.warn.deprecated.annotation.has.no.effect=@Deprecated 批注对此 {0} 声明没有任何效果 @@ -2305,13 +2305,14 @@ compiler.err.this.as.identifier=从发行版 8 开始,''this'' 只能作为接 compiler.err.receiver.parameter.not.applicable.constructor.toplevel.class=接收方参数不适用于顶层类的构造器 -# TODO 308: make a better error message +# 0: fragment, 1: symbol, 2: annotated-type +compiler.err.type.annotation.inadmissible={0} 不应出现在此处\n(要对限定类型进行批注,请编写 {1}.{2}) + # 0: annotation -compiler.err.cant.type.annotate.scoping.1=无法使用 type-use 批注 {0} 来批注确定作用域结构 +compiler.misc.type.annotation.1=类型批注 {0} 为 -# TODO 308: make a better error message # 0: list of annotation -compiler.err.cant.type.annotate.scoping=无法使用 type-use 批注 {0} 来批注确定作用域结构 +compiler.misc.type.annotation=类型批注 {0} 为 # 0: type, 1: type compiler.err.incorrect.receiver.name=接收方名称与封闭类类型不匹配\n需要: {0}\n找到: {1} diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/launcher_zh_CN.properties b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/launcher_zh_CN.properties index ee666cc02c11d..9382ac9e348e4 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/launcher_zh_CN.properties +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/launcher_zh_CN.properties @@ -120,7 +120,7 @@ launcher.err.cant.read.file=读取源文件 {0} 时出错:{1} launcher.err.no.value.for.option=没有为选项 {0} 指定值 # 0: string -launcher.err.invalid.value.for.source=--source 选项的值无效:{0}\n +launcher.err.invalid.value.for.source=--source 选项的值无效:{0} launcher.err.unnamed.pkg.not.allowed.named.modules=命名模块中不允许未命名程序包 diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets_de.properties b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets_de.properties index 4e84cdc52c77f..7ab2d3fc1dcaf 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets_de.properties +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets_de.properties @@ -278,9 +278,9 @@ doclet.record_constructor_doc.param_name=Wert für die Datensatzkomponente {0} doclet.record_equals_doc.fullbody.head=Gibt an, ob ein anderes Objekt diesem gleich ("equal to") ist. Die Objekte sind gleich, wenn das andere Objekt der gleichen Klasse angehört und alle Datensatzkomponenten gleich sind. -doclet.record_equals_doc.fullbody.tail.both=Referenzkomponenten werden verglichen mit {@link java.util.Objects#equals(Object,Object) Objects::equals(Object,Object)}; primitive Komponenten werden verglichen mit "==". +doclet.record_equals_doc.fullbody.tail.both=Referenzkomponenten werden verglichen mit {@link java.util.Objects#equals(Object,Object) Objects::equals(Object,Object)}. Primitive Komponenten werden mit der compare-Methode aus den entsprechenden Wrapper-Klassen verglichen. -doclet.record_equals_doc.fullbody.tail.primitive=Alle Komponenten in dieser Datensatzklasse werden verglichen mit "==". +doclet.record_equals_doc.fullbody.tail.primitive=Alle Komponenten dieser Datensatzklasse werden mit der compare-Methode aus den entsprechenden Wrapper-Klassen verglichen. doclet.record_equals_doc.fullbody.tail.reference=Alle Komponenten in dieser Datensatzklasse werden verglichen mit {@link java.util.Objects#equals(Object,Object) Objects::equals(Object,Object)}. diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets_ja.properties b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets_ja.properties index 515df706272d8..1b00ea9fbc02c 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets_ja.properties +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets_ja.properties @@ -278,9 +278,9 @@ doclet.record_constructor_doc.param_name={0}レコード・コンポーネント doclet.record_equals_doc.fullbody.head=他のオブジェクトがこれと"等しい"かどうかを示します。他のオブジェクトが同じクラスであり、すべてのレコード・コンポーネントが等しい場合、オブジェクトは等しくなります。 -doclet.record_equals_doc.fullbody.tail.both=参照コンポーネントは{@link java.util.Objects#equals(Object,Object) Objects::equals(Object,Object)}と比較され、プリミティブ・コンポーネントは'=='と比較されます。 +doclet.record_equals_doc.fullbody.tail.both=参照コンポーネントは{@link java.util.Objects#equals(Object,Object) Objects::equals(Object,Object)}と比較され、プリミティブ・コンポーネントは対応するラッパー・クラスのcompareメソッドで比較されます。 -doclet.record_equals_doc.fullbody.tail.primitive=このレコード・クラスのすべてのコンポーネントは'=='と比較されます。 +doclet.record_equals_doc.fullbody.tail.primitive=このレコード・クラスのすべてのコンポーネントは対応するラッパー・クラスのcompareメソッドで比較されます。 doclet.record_equals_doc.fullbody.tail.reference=このレコード・クラスのすべてのコンポーネントは{@link java.util.Objects#equals(Object,Object) Objects::equals(Object,Object)}と比較されます。 diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets_zh_CN.properties b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets_zh_CN.properties index d01d42faa56a4..e9786173c5f1d 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets_zh_CN.properties +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets_zh_CN.properties @@ -278,9 +278,9 @@ doclet.record_constructor_doc.param_name={0} 记录组件的值 doclet.record_equals_doc.fullbody.head=指示某个其他对象是否“等于”此对象。如果两个对象属于同一个类,而且所有记录组件都相等,则这两个对象相等。 -doclet.record_equals_doc.fullbody.tail.both=使用 {@link java.util.Objects#equals(Object,Object) Objects::equals(Object,Object)} 对参考组件进行比较;使用 '==' 对基元组件进行比较 +doclet.record_equals_doc.fullbody.tail.both=使用 {@link java.util.Objects#equals(Object,Object) Objects::equals(Object,Object)} 对参考组件进行比较;使用 compare 方法从对应的包装类对基元组件进行比较。 -doclet.record_equals_doc.fullbody.tail.primitive=此记录类中的所有组件都使用 '==' 进行比较。 +doclet.record_equals_doc.fullbody.tail.primitive=此记录类中的所有组件都使用 compare 方法从对应的包装类进行比较。 doclet.record_equals_doc.fullbody.tail.reference=此记录类中的所有组件都使用 {@link java.util.Objects#equals(Object,Object) Objects::equals(Object,Object)} 进行比较。 From 807186ffc6a0a9f2515a66329c2a98a43385463c Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Mon, 5 Aug 2024 16:53:30 +0000 Subject: [PATCH 15/17] 8337784: Fix simple -Wzero-as-null-pointer-constant warnings in linux/posix code Reviewed-by: stefank, shade --- src/hotspot/os/linux/os_linux.cpp | 4 ++-- src/hotspot/os/posix/perfMemory_posix.cpp | 4 ++-- src/hotspot/os/posix/signals_posix.cpp | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index 1c735f1b3c9d8..d4699567733b2 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -864,7 +864,7 @@ static void *thread_native_entry(Thread *thread) { log_info(os, thread)("Thread finished (tid: " UINTX_FORMAT ", pthread id: " UINTX_FORMAT ").", os::current_thread_id(), (uintx) pthread_self()); - return 0; + return nullptr; } // On Linux, glibc places static TLS blocks (for __thread variables) on @@ -4449,7 +4449,7 @@ void os::init(void) { check_pax(); // Check the availability of MADV_POPULATE_WRITE. - FLAG_SET_DEFAULT(UseMadvPopulateWrite, (::madvise(0, 0, MADV_POPULATE_WRITE) == 0)); + FLAG_SET_DEFAULT(UseMadvPopulateWrite, (::madvise(nullptr, 0, MADV_POPULATE_WRITE) == 0)); os::Posix::init(); } diff --git a/src/hotspot/os/posix/perfMemory_posix.cpp b/src/hotspot/os/posix/perfMemory_posix.cpp index 4339a21ae4e92..56bc8a1ef6b81 100644 --- a/src/hotspot/os/posix/perfMemory_posix.cpp +++ b/src/hotspot/os/posix/perfMemory_posix.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2021 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -1329,7 +1329,7 @@ void PerfMemory::attach(int vmid, char** addrp, size_t* sizep, TRAPS) { // void PerfMemory::detach(char* addr, size_t bytes) { - assert(addr != 0, "address sanity check"); + assert(addr != nullptr, "address sanity check"); assert(bytes > 0, "capacity sanity check"); if (PerfMemory::contains(addr) || PerfMemory::contains(addr + bytes - 1)) { diff --git a/src/hotspot/os/posix/signals_posix.cpp b/src/hotspot/os/posix/signals_posix.cpp index a9d3bb9284c49..6a14d0a485643 100644 --- a/src/hotspot/os/posix/signals_posix.cpp +++ b/src/hotspot/os/posix/signals_posix.cpp @@ -1719,7 +1719,7 @@ static int SR_initialize() { struct sigaction act; char *s; // Get signal number to use for suspend/resume - if ((s = ::getenv("_JAVA_SR_SIGNUM")) != 0) { + if ((s = ::getenv("_JAVA_SR_SIGNUM")) != nullptr) { int sig; bool result = parse_integer(s, &sig); if (result && sig > MAX2(SIGSEGV, SIGBUS) && // See 4355769. @@ -1742,7 +1742,7 @@ static int SR_initialize() { pthread_sigmask(SIG_BLOCK, nullptr, &act.sa_mask); remove_error_signals_from_set(&(act.sa_mask)); - if (sigaction(PosixSignals::SR_signum, &act, 0) == -1) { + if (sigaction(PosixSignals::SR_signum, &act, nullptr) == -1) { return -1; } From 42652b2e5350bcab6fceb0148be8bf3d65a0e173 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Mon, 5 Aug 2024 16:57:11 +0000 Subject: [PATCH 16/17] 8337787: Fix -Wzero-as-null-pointer-constant warnings when JVMTI feature is disabled Reviewed-by: ayang, sspitsyn --- src/hotspot/share/prims/jvmtiExport.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/prims/jvmtiExport.hpp b/src/hotspot/share/prims/jvmtiExport.hpp index 36df28f271677..e98020aef1d3b 100644 --- a/src/hotspot/share/prims/jvmtiExport.hpp +++ b/src/hotspot/share/prims/jvmtiExport.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -287,10 +287,10 @@ class JvmtiExport : public AllStatic { } // field access management - static address get_field_access_count_addr() NOT_JVMTI_RETURN_(0); + static address get_field_access_count_addr() NOT_JVMTI_RETURN_(nullptr); // field modification management - static address get_field_modification_count_addr() NOT_JVMTI_RETURN_(0); + static address get_field_modification_count_addr() NOT_JVMTI_RETURN_(nullptr); // ----------------- From 08f697f4fcbcdd912c3aa5f331fbf8212906465f Mon Sep 17 00:00:00 2001 From: Christoph Langer Date: Mon, 5 Aug 2024 17:58:12 +0000 Subject: [PATCH 17/17] 8337819: Update GHA JDKs to 22.0.2 Reviewed-by: mbaesken, ihse, shade --- make/conf/github-actions.conf | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/make/conf/github-actions.conf b/make/conf/github-actions.conf index deb5e36f60572..3cb56b47b50b8 100644 --- a/make/conf/github-actions.conf +++ b/make/conf/github-actions.conf @@ -29,17 +29,17 @@ GTEST_VERSION=1.14.0 JTREG_VERSION=7.4+1 LINUX_X64_BOOT_JDK_EXT=tar.gz -LINUX_X64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk22/830ec9fcccef480bb3e73fb7ecafe059/36/GPL/openjdk-22_linux-x64_bin.tar.gz -LINUX_X64_BOOT_JDK_SHA256=4d65cc6ed28711768fd72c2043a7925f7c83f5f51bb64970bd9d52f7791fc6ac - -MACOS_X64_BOOT_JDK_EXT=tar.gz -MACOS_X64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk22/830ec9fcccef480bb3e73fb7ecafe059/36/GPL/openjdk-22_macos-x64_bin.tar.gz -MACOS_X64_BOOT_JDK_SHA256=ae31fe10916429e3fe284266095067a5ce9fecbdc03ff1a079d20459f731ca36 +LINUX_X64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk22.0.2/c9ecb94cd31b495da20a27d4581645e8/9/GPL/openjdk-22.0.2_linux-x64_bin.tar.gz +LINUX_X64_BOOT_JDK_SHA256=41536f115668308ecf4eba92aaf6acaeb0936225828b741efd83b6173ba82963 MACOS_AARCH64_BOOT_JDK_EXT=tar.gz -MACOS_AARCH64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk22/830ec9fcccef480bb3e73fb7ecafe059/36/GPL/openjdk-22_macos-aarch64_bin.tar.gz -MACOS_AARCH64_BOOT_JDK_SHA256=d10f82429d01047968c52c7975c326388cb5d212791e14c1de21c987463a4b53 +MACOS_AARCH64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk22.0.2/c9ecb94cd31b495da20a27d4581645e8/9/GPL/openjdk-22.0.2_macos-aarch64_bin.tar.gz +MACOS_AARCH64_BOOT_JDK_SHA256=3dab98730234e1a87aec14bcb8171d2cae101e96ff4eed1dab96abbb08e843fd + +MACOS_X64_BOOT_JDK_EXT=tar.gz +MACOS_X64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk22.0.2/c9ecb94cd31b495da20a27d4581645e8/9/GPL/openjdk-22.0.2_macos-x64_bin.tar.gz +MACOS_X64_BOOT_JDK_SHA256=e8b3ec7a7077711223d31156e771f11723cd7af31c2017f1bd2eda20855940fb WINDOWS_X64_BOOT_JDK_EXT=zip -WINDOWS_X64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk22/830ec9fcccef480bb3e73fb7ecafe059/36/GPL/openjdk-22_windows-x64_bin.zip -WINDOWS_X64_BOOT_JDK_SHA256=8f5138fecb53c08c20abd4fa6812f9400051f3852582a2142ffda0dff73a5824 +WINDOWS_X64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk22.0.2/c9ecb94cd31b495da20a27d4581645e8/9/GPL/openjdk-22.0.2_windows-x64_bin.zip +WINDOWS_X64_BOOT_JDK_SHA256=f2a9b9ab944e71a64637fcdc6b13a1188cf02d4eb9ecf71dc927e98b3e45f5dc