From f6e7713bb653811423eeb2515c2f69b437750326 Mon Sep 17 00:00:00 2001 From: Matthew Donovan Date: Thu, 19 Dec 2024 13:19:56 +0000 Subject: [PATCH 01/36] 8339356: Test javax/net/ssl/SSLSocket/Tls13PacketSize.java failed with java.net.SocketException: An established connection was aborted by the software in your host machine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Daniel JeliƄski Reviewed-by: djelinski --- test/jdk/javax/net/ssl/SSLSocket/Tls13PacketSize.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/jdk/javax/net/ssl/SSLSocket/Tls13PacketSize.java b/test/jdk/javax/net/ssl/SSLSocket/Tls13PacketSize.java index b8e2410643b..0e34f4865ab 100644 --- a/test/jdk/javax/net/ssl/SSLSocket/Tls13PacketSize.java +++ b/test/jdk/javax/net/ssl/SSLSocket/Tls13PacketSize.java @@ -72,6 +72,10 @@ protected void runServerApplication(SSLSocket socket) throws Exception { sslOS.write(appData); sslOS.flush(); + int drained = 1; + while (drained < appData.length) { + drained += sslIS.read(appData, drained, appData.length - drained); + } } /* From 572ce269d0cf7974ad5299edbff596a36d0692a9 Mon Sep 17 00:00:00 2001 From: Patricio Chilano Mateo Date: Thu, 19 Dec 2024 14:45:27 +0000 Subject: [PATCH 02/36] 8345266: java/util/concurrent/locks/StampedLock/OOMEInStampedLock.java JTREG_TEST_THREAD_FACTORY=Virtual fails with OOME Reviewed-by: dholmes, alanb, coleenp --- src/hotspot/share/runtime/continuation.cpp | 62 ++++---- test/jdk/ProblemList-Virtual.txt | 2 - .../Thread/virtual/MonitorEnterWaitOOME.java | 148 ++++++++++++++++++ 3 files changed, 183 insertions(+), 29 deletions(-) create mode 100644 test/jdk/java/lang/Thread/virtual/MonitorEnterWaitOOME.java diff --git a/src/hotspot/share/runtime/continuation.cpp b/src/hotspot/share/runtime/continuation.cpp index fd9e4615498..d21e87ab746 100644 --- a/src/hotspot/share/runtime/continuation.cpp +++ b/src/hotspot/share/runtime/continuation.cpp @@ -60,14 +60,14 @@ JVM_END #if INCLUDE_JVMTI class JvmtiUnmountBeginMark : public StackObj { Handle _vthread; - JavaThread* _target; + JavaThread* _current; freeze_result _result; bool _failed; public: JvmtiUnmountBeginMark(JavaThread* t) : - _vthread(t, t->vthread()), _target(t), _result(freeze_pinned_native), _failed(false) { - assert(!_target->is_in_VTMS_transition(), "must be"); + _vthread(t, t->vthread()), _current(t), _result(freeze_pinned_native), _failed(false) { + assert(!_current->is_in_VTMS_transition(), "must be"); if (JvmtiVTMSTransitionDisabler::VTMS_notify_jvmti_events()) { JvmtiVTMSTransitionDisabler::VTMS_vthread_unmount((jthread)_vthread.raw_value(), true); @@ -75,26 +75,26 @@ class JvmtiUnmountBeginMark : public StackObj { // Don't preempt if there is a pending popframe or earlyret operation. This can // be installed in start_VTMS_transition() so we need to check it here. if (JvmtiExport::can_pop_frame() || JvmtiExport::can_force_early_return()) { - JvmtiThreadState* state = _target->jvmti_thread_state(); - if (_target->has_pending_popframe() || (state != nullptr && state->is_earlyret_pending())) { + JvmtiThreadState* state = _current->jvmti_thread_state(); + if (_current->has_pending_popframe() || (state != nullptr && state->is_earlyret_pending())) { _failed = true; } } // Don't preempt in case there is an async exception installed since // we would incorrectly throw it during the unmount logic in the carrier. - if (_target->has_async_exception_condition()) { + if (_current->has_async_exception_condition()) { _failed = true; } } else { - _target->set_is_in_VTMS_transition(true); + _current->set_is_in_VTMS_transition(true); java_lang_Thread::set_is_in_VTMS_transition(_vthread(), true); } } ~JvmtiUnmountBeginMark() { - assert(!_target->is_suspended(), "must be"); + assert(!_current->is_suspended(), "must be"); - assert(_target->is_in_VTMS_transition(), "must be"); + assert(_current->is_in_VTMS_transition(), "must be"); assert(java_lang_Thread::is_in_VTMS_transition(_vthread()), "must be"); // Read it again since for late binding agents the flag could have @@ -106,7 +106,7 @@ class JvmtiUnmountBeginMark : public StackObj { if (jvmti_present) { JvmtiVTMSTransitionDisabler::VTMS_vthread_mount((jthread)_vthread.raw_value(), false); } else { - _target->set_is_in_VTMS_transition(false); + _current->set_is_in_VTMS_transition(false); java_lang_Thread::set_is_in_VTMS_transition(_vthread(), false); } } @@ -115,51 +115,59 @@ class JvmtiUnmountBeginMark : public StackObj { bool failed() { return _failed; } }; -static bool is_vthread_safe_to_preempt_for_jvmti(JavaThread* target) { - if (target->is_in_VTMS_transition()) { - // We caught target at the end of a mount transition. +static bool is_vthread_safe_to_preempt_for_jvmti(JavaThread* current) { + if (current->is_in_VTMS_transition()) { + // We are at the end of a mount transition. return false; } return true; } #endif // INCLUDE_JVMTI -static bool is_vthread_safe_to_preempt(JavaThread* target, oop vthread) { +static bool is_vthread_safe_to_preempt(JavaThread* current, oop vthread) { assert(java_lang_VirtualThread::is_instance(vthread), ""); if (java_lang_VirtualThread::state(vthread) != java_lang_VirtualThread::RUNNING) { // inside transition return false; } - return JVMTI_ONLY(is_vthread_safe_to_preempt_for_jvmti(target)) NOT_JVMTI(true); + return JVMTI_ONLY(is_vthread_safe_to_preempt_for_jvmti(current)) NOT_JVMTI(true); } typedef freeze_result (*FreezeContFnT)(JavaThread*, intptr_t*); -static void verify_preempt_preconditions(JavaThread* target, oop continuation) { - assert(target == JavaThread::current(), "no support for external preemption"); - assert(target->has_last_Java_frame(), ""); - assert(!target->preempting(), ""); - assert(target->last_continuation() != nullptr, ""); - assert(target->last_continuation()->cont_oop(target) == continuation, ""); +static void verify_preempt_preconditions(JavaThread* current, oop continuation) { + assert(current == JavaThread::current(), "no support for external preemption"); + assert(current->has_last_Java_frame(), ""); + assert(!current->preempting(), ""); + assert(current->last_continuation() != nullptr, ""); + assert(current->last_continuation()->cont_oop(current) == continuation, ""); assert(Continuation::continuation_scope(continuation) == java_lang_VirtualThread::vthread_scope(), ""); - assert(!target->has_pending_exception(), ""); + assert(!current->has_pending_exception(), ""); } -freeze_result Continuation::try_preempt(JavaThread* target, oop continuation) { - verify_preempt_preconditions(target, continuation); +freeze_result Continuation::try_preempt(JavaThread* current, oop continuation) { + verify_preempt_preconditions(current, continuation); if (LockingMode == LM_LEGACY) { return freeze_unsupported; } - if (!is_vthread_safe_to_preempt(target, target->vthread())) { + if (!is_vthread_safe_to_preempt(current, current->vthread())) { return freeze_pinned_native; } - JVMTI_ONLY(JvmtiUnmountBeginMark jubm(target);) + JVMTI_ONLY(JvmtiUnmountBeginMark jubm(current);) JVMTI_ONLY(if (jubm.failed()) return freeze_pinned_native;) - freeze_result res = CAST_TO_FN_PTR(FreezeContFnT, freeze_preempt_entry())(target, target->last_Java_sp()); + freeze_result res = CAST_TO_FN_PTR(FreezeContFnT, freeze_preempt_entry())(current, current->last_Java_sp()); log_trace(continuations, preempt)("try_preempt: %d", res); JVMTI_ONLY(jubm.set_result(res);) + + if (current->has_pending_exception()) { + assert(res == freeze_exception, "expecting an exception result from freeze"); + // We don't want to throw exceptions, especially when returning + // from monitorenter since the compiler does not expect one. We + // just ignore the exception and pin the vthread to the carrier. + current->clear_pending_exception(); + } return res; } diff --git a/test/jdk/ProblemList-Virtual.txt b/test/jdk/ProblemList-Virtual.txt index eabac31ca34..d7692b578cd 100644 --- a/test/jdk/ProblemList-Virtual.txt +++ b/test/jdk/ProblemList-Virtual.txt @@ -44,8 +44,6 @@ javax/management/remote/mandatory/connection/DeadLockTest.java 8309069 windows-x javax/management/remote/mandatory/connection/ConnectionTest.java 8308352 windows-x64 -java/util/concurrent/locks/StampedLock/OOMEInStampedLock.java 8345266 generic-all - ########## ## Tests incompatible with virtual test thread factory. ## There is no goal to run all test with virtual test thread factory. diff --git a/test/jdk/java/lang/Thread/virtual/MonitorEnterWaitOOME.java b/test/jdk/java/lang/Thread/virtual/MonitorEnterWaitOOME.java new file mode 100644 index 00000000000..4978e2a4b69 --- /dev/null +++ b/test/jdk/java/lang/Thread/virtual/MonitorEnterWaitOOME.java @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test id=monitorenter + * @bug 8345266 + * @summary Test OOM while trying to unmount vthread on monitorenter + * @requires vm.continuations & vm.gc.G1 & vm.opt.DisableExplicitGC != "true" + * @library /test/lib + * @run main/othervm -XX:+UseG1GC -Xmx48M MonitorEnterWaitOOME false + */ + +/* + * @test id=timedwait + * @summary Test OOM while trying to unmount vthread on Object.wait + * @requires vm.continuations & vm.gc.G1 & vm.opt.DisableExplicitGC != "true" + * @library /test/lib + * @run main/othervm -XX:+UseG1GC -Xmx48M MonitorEnterWaitOOME true 5 + */ + +/* + * @test id=untimedwait + * @summary Test OOM while trying to unmount vthread on Object.wait + * @requires vm.continuations & vm.gc.G1 & vm.opt.DisableExplicitGC != "true" + * @library /test/lib + * @run main/othervm -XX:+UseG1GC -Xmx48M MonitorEnterWaitOOME true 0 + */ + +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; + +import jdk.test.lib.thread.VThreadRunner; + +public class MonitorEnterWaitOOME { + static volatile Object data; + static Thread.State dummyState = Thread.State.RUNNABLE; // load java.lang.Thread$State + + public static void main(String[] args) throws Throwable { + final boolean testWait = args.length >= 1 ? Boolean.parseBoolean(args[0]) : false; + final long timeout = testWait && args.length == 2 ? Long.parseLong(args[1]) : 0L; + + VThreadRunner.ensureParallelism(2); + + Thread vthread; + var lock = new Object(); + var canFillHeap = new AtomicBoolean(); + var heapFilled = new AtomicBoolean(); + var heapCollected = new AtomicBoolean(); + var exRef = new AtomicReference(); + synchronized (lock) { + vthread = Thread.ofVirtual().start(() -> { + try { + awaitTrue(canFillHeap); + data = fillHeap(); + heapFilled.set(true); + synchronized (lock) { + if (testWait) { + lock.wait(timeout); + } + } + data = null; + System.gc(); + heapCollected.set(true); + } catch (Throwable e) { + data = null; + System.gc(); // avoid nested OOME + exRef.set(e); + } + }); + canFillHeap.set(true); + awaitTrue(heapFilled); + awaitState(vthread, Thread.State.BLOCKED); + } + if (testWait && timeout == 0) { + awaitState(vthread, Thread.State.WAITING); + synchronized (lock) { + lock.notify(); + } + } + joinVThread(vthread, heapCollected, exRef); + assert exRef.get() == null; + } + + private static Object[] fillHeap() { + Object[] first = null, last = null; + int size = 1 << 20; + while (size > 0) { + try { + Object[] array = new Object[size]; + if (first == null) { + first = array; + } else { + last[0] = array; + } + last = array; + } catch (OutOfMemoryError oome) { + size = size >>> 1; + } + } + return first; + } + + private static void awaitTrue(AtomicBoolean ready) { + // Don't call anything that might allocate from the Java heap. + while (!ready.get()) { + Thread.onSpinWait(); + } + } + + private static void awaitState(Thread thread, Thread.State expectedState) { + // Don't call anything that might allocate from the Java heap. + while (thread.getState() != expectedState) { + Thread.onSpinWait(); + } + } + + private static void joinVThread(Thread vthread, AtomicBoolean ready, AtomicReference exRef) throws Throwable { + // Don't call anything that might allocate from the Java heap until ready is set. + while (!ready.get()) { + Throwable ex = exRef.get(); + if (ex != null) { + throw ex; + } + Thread.onSpinWait(); + } + vthread.join(); + } +} From 2344a1a917ec6f6380a8187af9f6c369ac3da6cb Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Thu, 19 Dec 2024 16:00:59 +0000 Subject: [PATCH 03/36] 8345732: Provide helpers for using PartialArrayState Reviewed-by: tschatzl, ayang, zgu, iwalulya --- .../share/gc/g1/g1ParScanThreadState.cpp | 105 +++++++--------- .../share/gc/g1/g1ParScanThreadState.hpp | 16 ++- src/hotspot/share/gc/g1/g1YoungCollector.cpp | 6 + .../share/gc/parallel/psPromotionManager.cpp | 113 ++++++------------ .../share/gc/parallel/psPromotionManager.hpp | 23 ++-- .../gc/parallel/psPromotionManager.inline.hpp | 13 +- src/hotspot/share/gc/parallel/psScavenge.cpp | 3 +- .../share/gc/shared/partialArraySplitter.cpp | 42 +++++++ .../share/gc/shared/partialArraySplitter.hpp | 104 ++++++++++++++++ .../gc/shared/partialArraySplitter.inline.hpp | 83 +++++++++++++ .../share/gc/shared/partialArrayTaskStats.cpp | 92 ++++++++++++++ .../share/gc/shared/partialArrayTaskStats.hpp | 107 +++++++++++++++++ src/hotspot/share/gc/shared/taskqueue.hpp | 14 --- src/hotspot/share/utilities/macros.hpp | 15 +++ 14 files changed, 551 insertions(+), 185 deletions(-) create mode 100644 src/hotspot/share/gc/shared/partialArraySplitter.cpp create mode 100644 src/hotspot/share/gc/shared/partialArraySplitter.hpp create mode 100644 src/hotspot/share/gc/shared/partialArraySplitter.inline.hpp create mode 100644 src/hotspot/share/gc/shared/partialArrayTaskStats.cpp create mode 100644 src/hotspot/share/gc/shared/partialArrayTaskStats.hpp diff --git a/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp b/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp index f3b7e87bc78..5762d079728 100644 --- a/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp +++ b/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp @@ -35,8 +35,9 @@ #include "gc/g1/g1Trace.hpp" #include "gc/g1/g1YoungGCAllocationFailureInjector.inline.hpp" #include "gc/shared/continuationGCSupport.inline.hpp" +#include "gc/shared/partialArraySplitter.inline.hpp" #include "gc/shared/partialArrayState.hpp" -#include "gc/shared/partialArrayTaskStepper.inline.hpp" +#include "gc/shared/partialArrayTaskStats.hpp" #include "gc/shared/stringdedup/stringDedup.hpp" #include "gc/shared/taskqueue.inline.hpp" #include "memory/allocation.inline.hpp" @@ -80,8 +81,7 @@ G1ParScanThreadState::G1ParScanThreadState(G1CollectedHeap* g1h, _surviving_young_words(nullptr), _surviving_words_length(collection_set->young_region_length() + 1), _old_gen_is_full(false), - _partial_array_state_allocator(g1h->partial_array_state_manager()), - _partial_array_stepper(num_workers, ParGCArrayScanChunk), + _partial_array_splitter(g1h->partial_array_state_manager(), num_workers), _string_dedup_requests(), _max_num_optional_regions(collection_set->optional_region_length()), _numa(g1h->numa()), @@ -169,9 +169,12 @@ void G1ParScanThreadState::verify_task(oop* task) const { } void G1ParScanThreadState::verify_task(PartialArrayState* task) const { - // Must be in the collection set--it's already been copied. - oop p = task->source(); - assert(_g1h->is_in_cset(p), "p=" PTR_FORMAT, p2i(p)); + assert(task != nullptr, "invariant"); + // Source isn't used for processing, so not recorded in task. + assert(task->source() == nullptr, "invariant"); + oop p = task->destination(); + assert(_g1h->is_in_reserved(p), + "task=" PTR_FORMAT " dest=" PTR_FORMAT, p2i(task), p2i(p)); } void G1ParScanThreadState::verify_task(ScannerTask task) const { @@ -222,38 +225,17 @@ void G1ParScanThreadState::do_oop_evac(T* p) { } MAYBE_INLINE_EVACUATION -void G1ParScanThreadState::do_partial_array(PartialArrayState* state) { - oop to_obj = state->destination(); - -#ifdef ASSERT - oop from_obj = state->source(); - assert(_g1h->is_in_reserved(from_obj), "must be in heap."); - assert(from_obj->is_forwarded(), "must be forwarded"); - assert(from_obj != to_obj, "should not be chunking self-forwarded objects"); - assert(to_obj->is_objArray(), "must be obj array"); -#endif // ASSERT - - objArrayOop to_array = objArrayOop(to_obj); - - // Claim a chunk and get number of additional tasks to enqueue. - PartialArrayTaskStepper::Step step = _partial_array_stepper.next(state); - // Push any additional partial scan tasks needed. Pushed before processing - // the claimed chunk to allow other workers to steal while we're processing. - if (step._ncreate > 0) { - state->add_references(step._ncreate); - for (uint i = 0; i < step._ncreate; ++i) { - push_on_queue(ScannerTask(state)); - } - } - +void G1ParScanThreadState::do_partial_array(PartialArrayState* state, bool stolen) { + // Access state before release by claim(). + objArrayOop to_array = objArrayOop(state->destination()); + PartialArraySplitter::Claim claim = + _partial_array_splitter.claim(state, _task_queue, stolen); G1HeapRegionAttr dest_attr = _g1h->region_attr(to_array); G1SkipCardEnqueueSetter x(&_scanner, dest_attr.is_new_survivor()); // Process claimed task. to_array->oop_iterate_range(&_scanner, - checked_cast(step._index), - checked_cast(step._index + _partial_array_stepper.chunk_size())); - // Release reference to the state, now that we're done with it. - _partial_array_state_allocator.release(state); + checked_cast(claim._start), + checked_cast(claim._end)); } MAYBE_INLINE_EVACUATION @@ -265,27 +247,10 @@ void G1ParScanThreadState::start_partial_objarray(G1HeapRegionAttr dest_attr, assert(to_obj->is_objArray(), "precondition"); objArrayOop to_array = objArrayOop(to_obj); - size_t array_length = to_array->length(); - PartialArrayTaskStepper::Step step = _partial_array_stepper.start(array_length); - - // Push any needed partial scan tasks. Pushed before processing the - // initial chunk to allow other workers to steal while we're processing. - if (step._ncreate > 0) { - assert(step._index < array_length, "invariant"); - assert(((array_length - step._index) % _partial_array_stepper.chunk_size()) == 0, - "invariant"); - PartialArrayState* state = - _partial_array_state_allocator.allocate(from_obj, to_obj, - step._index, - array_length, - step._ncreate); - for (uint i = 0; i < step._ncreate; ++i) { - push_on_queue(ScannerTask(state)); - } - } else { - assert(step._index == array_length, "invariant"); - } + size_t initial_chunk_size = + // The source array is unused when processing states. + _partial_array_splitter.start(_task_queue, nullptr, to_array, array_length); // Skip the card enqueue iff the object (to_array) is in survivor region. // However, G1HeapRegion::is_survivor() is too expensive here. @@ -296,18 +261,18 @@ void G1ParScanThreadState::start_partial_objarray(G1HeapRegionAttr dest_attr, // Process the initial chunk. No need to process the type in the // klass, as it will already be handled by processing the built-in // module. - to_array->oop_iterate_range(&_scanner, 0, checked_cast(step._index)); + to_array->oop_iterate_range(&_scanner, 0, checked_cast(initial_chunk_size)); } MAYBE_INLINE_EVACUATION -void G1ParScanThreadState::dispatch_task(ScannerTask task) { +void G1ParScanThreadState::dispatch_task(ScannerTask task, bool stolen) { verify_task(task); if (task.is_narrow_oop_ptr()) { do_oop_evac(task.to_narrow_oop_ptr()); } else if (task.is_oop_ptr()) { do_oop_evac(task.to_oop_ptr()); } else { - do_partial_array(task.to_partial_array_state()); + do_partial_array(task.to_partial_array_state(), stolen); } } @@ -320,11 +285,11 @@ void G1ParScanThreadState::trim_queue_to_threshold(uint threshold) { do { while (_task_queue->pop_overflow(task)) { if (!_task_queue->try_push_to_taskqueue(task)) { - dispatch_task(task); + dispatch_task(task, false); } } while (_task_queue->pop_local(task, threshold)) { - dispatch_task(task); + dispatch_task(task, false); } } while (!_task_queue->overflow_empty()); } @@ -333,7 +298,7 @@ ATTRIBUTE_FLATTEN void G1ParScanThreadState::steal_and_trim_queue(G1ScannerTasksQueueSet* task_queues) { ScannerTask stolen_task; while (task_queues->steal(_worker_id, stolen_task)) { - dispatch_task(stolen_task); + dispatch_task(stolen_task, true); // Processing stolen task may have added tasks to our queue. trim_queue(); } @@ -717,6 +682,14 @@ void G1ParScanThreadState::update_numa_stats(uint node_index) { } } +#if TASKQUEUE_STATS + +PartialArrayTaskStats* G1ParScanThreadState::partial_array_task_stats() { + return _partial_array_splitter.stats(); +} + +#endif // TASKQUEUE_STATS + G1ParScanThreadStateSet::G1ParScanThreadStateSet(G1CollectedHeap* g1h, uint num_workers, G1CollectionSet* collection_set, @@ -744,3 +717,15 @@ G1ParScanThreadStateSet::~G1ParScanThreadStateSet() { FREE_C_HEAP_ARRAY(size_t, _surviving_young_words_total); FREE_C_HEAP_ARRAY(BufferNodeList, _rdc_buffers); } + +#if TASKQUEUE_STATS + +void G1ParScanThreadStateSet::print_partial_array_task_stats() { + auto get_stats = [&](uint i) { + return state_for_worker(i)->partial_array_task_stats(); + }; + PartialArrayTaskStats::log_set(_num_workers, get_stats, + "Partial Array Task Stats"); +} + +#endif // TASKQUEUE_STATS diff --git a/src/hotspot/share/gc/g1/g1ParScanThreadState.hpp b/src/hotspot/share/gc/g1/g1ParScanThreadState.hpp index 27aa29ee30c..f5dccaee9cf 100644 --- a/src/hotspot/share/gc/g1/g1ParScanThreadState.hpp +++ b/src/hotspot/share/gc/g1/g1ParScanThreadState.hpp @@ -32,8 +32,8 @@ #include "gc/shared/ageTable.hpp" #include "gc/shared/copyFailedInfo.hpp" #include "gc/shared/gc_globals.hpp" +#include "gc/shared/partialArraySplitter.hpp" #include "gc/shared/partialArrayState.hpp" -#include "gc/shared/partialArrayTaskStepper.hpp" #include "gc/shared/stringdedup/stringDedup.hpp" #include "gc/shared/taskqueue.hpp" #include "memory/allocation.hpp" @@ -84,8 +84,7 @@ class G1ParScanThreadState : public CHeapObj { // Indicates whether in the last generation (old) there is no more space // available for allocation. bool _old_gen_is_full; - PartialArrayStateAllocator _partial_array_state_allocator; - PartialArrayTaskStepper _partial_array_stepper; + PartialArraySplitter _partial_array_splitter; StringDedup::Requests _string_dedup_requests; G1CardTable* ct() { return _ct; } @@ -163,8 +162,12 @@ class G1ParScanThreadState : public CHeapObj { // HeapWords copied. size_t flush_stats(size_t* surviving_young_words, uint num_workers, BufferNodeList* buffer_log); +#if TASKQUEUE_STATS + PartialArrayTaskStats* partial_array_task_stats(); +#endif // TASKQUEUE_STATS + private: - void do_partial_array(PartialArrayState* state); + void do_partial_array(PartialArrayState* state, bool stolen); void start_partial_objarray(G1HeapRegionAttr dest_dir, oop from, oop to); HeapWord* allocate_copy_slow(G1HeapRegionAttr* dest_attr, @@ -187,7 +190,7 @@ class G1ParScanThreadState : public CHeapObj { // This method is applied to the fields of the objects that have just been copied. template void do_oop_evac(T* p); - void dispatch_task(ScannerTask task); + void dispatch_task(ScannerTask task, bool stolen); // Tries to allocate word_sz in the PLAB of the next "generation" after trying to // allocate into dest. Previous_plab_refill_failed indicates whether previous @@ -259,6 +262,9 @@ class G1ParScanThreadStateSet : public StackObj { void flush_stats(); void record_unused_optional_region(G1HeapRegion* hr); +#if TASKQUEUE_STATS + void print_partial_array_task_stats(); +#endif // TASKQUEUE_STATS G1ParScanThreadState* state_for_worker(uint worker_id); uint num_workers() const { return _num_workers; } diff --git a/src/hotspot/share/gc/g1/g1YoungCollector.cpp b/src/hotspot/share/gc/g1/g1YoungCollector.cpp index 13c4e9949ed..2af5658f98e 100644 --- a/src/hotspot/share/gc/g1/g1YoungCollector.cpp +++ b/src/hotspot/share/gc/g1/g1YoungCollector.cpp @@ -1013,6 +1013,12 @@ void G1YoungCollector::post_evacuate_collection_set(G1EvacInfo* evacuation_info, allocator()->release_gc_alloc_regions(evacuation_info); +#if TASKQUEUE_STATS + // Logging uses thread states, which are deleted by cleanup, so this must + // be done before cleanup. + per_thread_states->print_partial_array_task_stats(); +#endif // TASKQUEUE_STATS + post_evacuate_cleanup_1(per_thread_states); post_evacuate_cleanup_2(per_thread_states, evacuation_info); diff --git a/src/hotspot/share/gc/parallel/psPromotionManager.cpp b/src/hotspot/share/gc/parallel/psPromotionManager.cpp index 525285471c7..69fdde5ea9f 100644 --- a/src/hotspot/share/gc/parallel/psPromotionManager.cpp +++ b/src/hotspot/share/gc/parallel/psPromotionManager.cpp @@ -31,8 +31,8 @@ #include "gc/parallel/psScavenge.inline.hpp" #include "gc/shared/continuationGCSupport.inline.hpp" #include "gc/shared/gcTrace.hpp" +#include "gc/shared/partialArraySplitter.inline.hpp" #include "gc/shared/partialArrayState.hpp" -#include "gc/shared/partialArrayTaskStepper.inline.hpp" #include "gc/shared/preservedMarks.inline.hpp" #include "gc/shared/taskqueue.inline.hpp" #include "logging/log.hpp" @@ -121,7 +121,7 @@ void PSPromotionManager::pre_scavenge() { bool PSPromotionManager::post_scavenge(YoungGCTracer& gc_tracer) { bool promotion_failure_occurred = false; - TASKQUEUE_STATS_ONLY(print_taskqueue_stats()); + TASKQUEUE_STATS_ONLY(print_and_reset_taskqueue_stats()); for (uint i = 0; i < ParallelGCThreads; i++) { PSPromotionManager* manager = manager_array(i); assert(manager->claimed_stack_depth()->is_empty(), "should be empty"); @@ -145,49 +145,29 @@ bool PSPromotionManager::post_scavenge(YoungGCTracer& gc_tracer) { } #if TASKQUEUE_STATS -void -PSPromotionManager::print_local_stats(outputStream* const out, uint i) const { - #define FMT " " SIZE_FORMAT_W(10) - out->print_cr("%3u" FMT FMT FMT FMT, - i, _array_chunk_pushes, _array_chunk_steals, - _arrays_chunked, _array_chunks_processed); - #undef FMT -} - -static const char* const pm_stats_hdr[] = { - " ----partial array---- arrays array", - "thr push steal chunked chunks", - "--- ---------- ---------- ---------- ----------" -}; - -void PSPromotionManager::print_taskqueue_stats() { - if (!log_is_enabled(Trace, gc, task, stats)) { - return; - } - Log(gc, task, stats) log; - ResourceMark rm; - LogStream ls(log.trace()); - stack_array_depth()->print_taskqueue_stats(&ls, "Oop Queue"); +void PSPromotionManager::print_and_reset_taskqueue_stats() { + stack_array_depth()->print_and_reset_taskqueue_stats("Oop Queue"); - const uint hlines = sizeof(pm_stats_hdr) / sizeof(pm_stats_hdr[0]); - for (uint i = 0; i < hlines; ++i) ls.print_cr("%s", pm_stats_hdr[i]); + auto get_pa_stats = [&](uint i) { + return manager_array(i)->partial_array_task_stats(); + }; + PartialArrayTaskStats::log_set(ParallelGCThreads, get_pa_stats, + "Partial Array Task Stats"); for (uint i = 0; i < ParallelGCThreads; ++i) { - manager_array(i)->print_local_stats(&ls, i); + get_pa_stats(i)->reset(); } } -void PSPromotionManager::reset_stats() { - claimed_stack_depth()->stats.reset(); - _array_chunk_pushes = _array_chunk_steals = 0; - _arrays_chunked = _array_chunks_processed = 0; +PartialArrayTaskStats* PSPromotionManager::partial_array_task_stats() { + return _partial_array_splitter.stats(); } + #endif // TASKQUEUE_STATS // Most members are initialized either by initialize() or reset(). PSPromotionManager::PSPromotionManager() - : _partial_array_state_allocator(_partial_array_state_manager), - _partial_array_stepper(ParallelGCThreads, ParGCArrayScanChunk) + : _partial_array_splitter(_partial_array_state_manager, ParallelGCThreads) { // We set the old lab's start array. _old_lab.set_start_array(old_gen()->start_array()); @@ -221,8 +201,6 @@ void PSPromotionManager::reset() { _old_gen_is_full = false; _promotion_failed_info.reset(); - - TASKQUEUE_STATS_ONLY(reset_stats()); } void PSPromotionManager::register_preserved_marks(PreservedMarks* preserved_marks) { @@ -246,12 +224,12 @@ void PSPromotionManager::drain_stacks_depth(bool totally_drain) { // claimed stack while we work. while (tq->pop_overflow(task)) { if (!tq->try_push_to_taskqueue(task)) { - process_popped_location_depth(task); + process_popped_location_depth(task, false); } } while (tq->pop_local(task, threshold)) { - process_popped_location_depth(task); + process_popped_location_depth(task, false); } } while (!tq->overflow_empty()); @@ -279,9 +257,8 @@ void PSPromotionManager::flush_labs() { } } -template void PSPromotionManager::process_array_chunk_work( - oop obj, - int start, int end) { +template +void PSPromotionManager::process_array_chunk_work(oop obj, int start, int end) { assert(start <= end, "invariant"); T* const base = (T*)objArrayOop(obj)->base(); T* p = base + start; @@ -292,29 +269,18 @@ template void PSPromotionManager::process_array_chunk_work( } } -void PSPromotionManager::process_array_chunk(PartialArrayState* state) { - TASKQUEUE_STATS_ONLY(++_array_chunks_processed); - - // Claim a chunk. Push additional tasks before processing the claimed - // chunk to allow other workers to steal while we're processing. - PartialArrayTaskStepper::Step step = _partial_array_stepper.next(state); - if (step._ncreate > 0) { - state->add_references(step._ncreate); - for (uint i = 0; i < step._ncreate; ++i) { - push_depth(ScannerTask(state)); - } - TASKQUEUE_STATS_ONLY(_array_chunk_pushes += step._ncreate); - } - int start = checked_cast(step._index); - int end = checked_cast(step._index + _partial_array_stepper.chunk_size()); - assert(start < end, "invariant"); +void PSPromotionManager::process_array_chunk(PartialArrayState* state, bool stolen) { + // Access before release by claim(). + oop new_obj = state->destination(); + PartialArraySplitter::Claim claim = + _partial_array_splitter.claim(state, &_claimed_stack_depth, stolen); + int start = checked_cast(claim._start); + int end = checked_cast(claim._end); if (UseCompressedOops) { - process_array_chunk_work(state->destination(), start, end); + process_array_chunk_work(new_obj, start, end); } else { - process_array_chunk_work(state->destination(), start, end); + process_array_chunk_work(new_obj, start, end); } - // Release reference to state, now that we're done with it. - _partial_array_state_allocator.release(state); } void PSPromotionManager::push_objArray(oop old_obj, oop new_obj) { @@ -322,25 +288,16 @@ void PSPromotionManager::push_objArray(oop old_obj, oop new_obj) { assert(old_obj->forwardee() == new_obj, "precondition"); assert(new_obj->is_objArray(), "precondition"); - size_t array_length = objArrayOop(new_obj)->length(); - PartialArrayTaskStepper::Step step = _partial_array_stepper.start(array_length); - - if (step._ncreate > 0) { - TASKQUEUE_STATS_ONLY(++_arrays_chunked); - PartialArrayState* state = - _partial_array_state_allocator.allocate(old_obj, new_obj, - step._index, - array_length, - step._ncreate); - for (uint i = 0; i < step._ncreate; ++i) { - push_depth(ScannerTask(state)); - } - TASKQUEUE_STATS_ONLY(_array_chunk_pushes += step._ncreate); - } + objArrayOop to_array = objArrayOop(new_obj); + size_t array_length = to_array->length(); + size_t initial_chunk_size = + // The source array is unused when processing states. + _partial_array_splitter.start(&_claimed_stack_depth, nullptr, to_array, array_length); + int end = checked_cast(initial_chunk_size); if (UseCompressedOops) { - process_array_chunk_work(new_obj, 0, checked_cast(step._index)); + process_array_chunk_work(to_array, 0, end); } else { - process_array_chunk_work(new_obj, 0, checked_cast(step._index)); + process_array_chunk_work(to_array, 0, end); } } diff --git a/src/hotspot/share/gc/parallel/psPromotionManager.hpp b/src/hotspot/share/gc/parallel/psPromotionManager.hpp index a6de8623281..9397ad52a9b 100644 --- a/src/hotspot/share/gc/parallel/psPromotionManager.hpp +++ b/src/hotspot/share/gc/parallel/psPromotionManager.hpp @@ -28,8 +28,9 @@ #include "gc/parallel/psPromotionLAB.hpp" #include "gc/shared/copyFailedInfo.hpp" #include "gc/shared/gcTrace.hpp" +#include "gc/shared/partialArraySplitter.hpp" #include "gc/shared/partialArrayState.hpp" -#include "gc/shared/partialArrayTaskStepper.hpp" +#include "gc/shared/partialArrayTaskStats.hpp" #include "gc/shared/preservedMarks.hpp" #include "gc/shared/stringdedup/stringDedup.hpp" #include "gc/shared/taskqueue.hpp" @@ -67,15 +68,8 @@ class PSPromotionManager { static MutableSpace* _young_space; #if TASKQUEUE_STATS - size_t _array_chunk_pushes; - size_t _array_chunk_steals; - size_t _arrays_chunked; - size_t _array_chunks_processed; - - void print_local_stats(outputStream* const out, uint i) const; - static void print_taskqueue_stats(); - - void reset_stats(); + static void print_and_reset_taskqueue_stats(); + PartialArrayTaskStats* partial_array_task_stats(); #endif // TASKQUEUE_STATS PSYoungPromotionLAB _young_lab; @@ -88,8 +82,7 @@ class PSPromotionManager { uint _target_stack_size; static PartialArrayStateManager* _partial_array_state_manager; - PartialArrayStateAllocator _partial_array_state_allocator; - PartialArrayTaskStepper _partial_array_stepper; + PartialArraySplitter _partial_array_splitter; uint _min_array_size_for_chunking; PreservedMarks* _preserved_marks; @@ -105,7 +98,7 @@ class PSPromotionManager { template void process_array_chunk_work(oop obj, int start, int end); - void process_array_chunk(PartialArrayState* state); + void process_array_chunk(PartialArrayState* state, bool stolen); void push_objArray(oop old_obj, oop new_obj); void push_depth(ScannerTask task); @@ -164,7 +157,7 @@ class PSPromotionManager { return claimed_stack_depth()->is_empty(); } - inline void process_popped_location_depth(ScannerTask task); + inline void process_popped_location_depth(ScannerTask task, bool stolen); static bool should_scavenge(oop* p, bool check_to_space = false); static bool should_scavenge(narrowOop* p, bool check_to_space = false); @@ -174,8 +167,6 @@ class PSPromotionManager { template inline void claim_or_forward_depth(T* p); - TASKQUEUE_STATS_ONLY(inline void record_steal(ScannerTask task);) - void push_contents(oop obj); void push_contents_bounded(oop obj, HeapWord* left, HeapWord* right); }; diff --git a/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp b/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp index ed517c06a40..4f3d135c919 100644 --- a/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp +++ b/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp @@ -331,10 +331,11 @@ inline void PSPromotionManager::copy_and_push_safe_barrier(T* p) { } } -inline void PSPromotionManager::process_popped_location_depth(ScannerTask task) { +inline void PSPromotionManager::process_popped_location_depth(ScannerTask task, + bool stolen) { if (task.is_partial_array_state()) { assert(PSChunkLargeArrays, "invariant"); - process_array_chunk(task.to_partial_array_state()); + process_array_chunk(task.to_partial_array_state(), stolen); } else { if (task.is_narrow_oop_ptr()) { assert(UseCompressedOops, "Error"); @@ -349,12 +350,4 @@ inline bool PSPromotionManager::steal_depth(int queue_num, ScannerTask& t) { return stack_array_depth()->steal(queue_num, t); } -#if TASKQUEUE_STATS -void PSPromotionManager::record_steal(ScannerTask task) { - if (task.is_partial_array_state()) { - ++_array_chunk_steals; - } -} -#endif // TASKQUEUE_STATS - #endif // SHARE_GC_PARALLEL_PSPROMOTIONMANAGER_INLINE_HPP diff --git a/src/hotspot/share/gc/parallel/psScavenge.cpp b/src/hotspot/share/gc/parallel/psScavenge.cpp index 7701cea313b..101f06b8fe0 100644 --- a/src/hotspot/share/gc/parallel/psScavenge.cpp +++ b/src/hotspot/share/gc/parallel/psScavenge.cpp @@ -128,8 +128,7 @@ static void steal_work(TaskTerminator& terminator, uint worker_id) { while (true) { ScannerTask task; if (PSPromotionManager::steal_depth(worker_id, task)) { - TASKQUEUE_STATS_ONLY(pm->record_steal(task)); - pm->process_popped_location_depth(task); + pm->process_popped_location_depth(task, true); pm->drain_stacks_depth(true); } else { if (terminator.offer_termination()) { diff --git a/src/hotspot/share/gc/shared/partialArraySplitter.cpp b/src/hotspot/share/gc/shared/partialArraySplitter.cpp new file mode 100644 index 00000000000..30a9a802bdb --- /dev/null +++ b/src/hotspot/share/gc/shared/partialArraySplitter.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "gc/shared/gc_globals.hpp" +#include "gc/shared/partialArraySplitter.hpp" +#include "gc/shared/partialArrayState.hpp" +#include "utilities/macros.hpp" + +PartialArraySplitter::PartialArraySplitter(PartialArrayStateManager* manager, + uint num_workers) + : _allocator(manager), + _stepper(num_workers, ParGCArrayScanChunk) + TASKQUEUE_STATS_ONLY(COMMA _stats()) +{} + +#if TASKQUEUE_STATS +PartialArrayTaskStats* PartialArraySplitter::stats() { + return &_stats; +} +#endif // TASKQUEUE_STATS diff --git a/src/hotspot/share/gc/shared/partialArraySplitter.hpp b/src/hotspot/share/gc/shared/partialArraySplitter.hpp new file mode 100644 index 00000000000..0dd2072c590 --- /dev/null +++ b/src/hotspot/share/gc/shared/partialArraySplitter.hpp @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_GC_SHARED_PARTIALARRAYSPLITTER_HPP +#define SHARE_GC_SHARED_PARTIALARRAYSPLITTER_HPP + +#include "gc/shared/partialArrayState.hpp" +#include "gc/shared/partialArrayTaskStats.hpp" +#include "gc/shared/partialArrayTaskStepper.hpp" +#include "oops/oop.hpp" +#include "utilities/globalDefinitions.hpp" +#include "utilities/macros.hpp" + +class outputStream; + +// Helper class for splitting the processing of a large objArray into multiple +// tasks, to permit multiple threads to work on different pieces of the array +// in parallel. +class PartialArraySplitter { + PartialArrayStateAllocator _allocator; + PartialArrayTaskStepper _stepper; + TASKQUEUE_STATS_ONLY(PartialArrayTaskStats _stats;) + +public: + PartialArraySplitter(PartialArrayStateManager* manager, uint num_workers); + ~PartialArraySplitter() = default; + + NONCOPYABLE(PartialArraySplitter); + + // Setup to process an objArray in chunks. + // + // from_array is the array found by the collector that needs processing. It + // may be null if to_array contains everything needed for processing. + // + // to_array is an unprocessed (possibly partial) copy of from_array, or null + // if a copy of from_array is not required. + // + // length is their length in elements. + // + // If t is a ScannerTask, queue->push(t) must be a valid expression. The + // result of that expression is ignored. + // + // Returns the size of the initial chunk that is to be processed by the + // caller. + // + // Adds PartialArrayState ScannerTasks to the queue if needed to process the + // array in chunks. This permits other workers to steal and process them + // even while the caller is processing the initial chunk. If length doesn't + // exceed the chunk size then the result will be length, indicating the + // caller is to process the entire array. In this case, no tasks will have + // been added to the queue. + template + size_t start(Queue* queue, + objArrayOop from_array, + objArrayOop to_array, + size_t length); + + // Result type for claim(), carrying multiple values. Provides the claimed + // chunk's start and end array indices. + struct Claim { + size_t _start; + size_t _end; + }; + + // Claims a chunk from state, returning the index range for that chunk. The + // caller is expected to process that chunk. Adds more state-based tasks to + // the queue if needed, permitting other workers to steal and process them + // even while the caller is processing this claim. + // + // Releases the state. Callers must not use state after the call to this + // function. The state may have been recycled and reused. + // + // The queue has the same requirements as for start(). + // + // stolen indicates whether the state task was obtained from this queue or + // stolen from some other queue. + template + Claim claim(PartialArrayState* state, Queue* queue, bool stolen); + + TASKQUEUE_STATS_ONLY(PartialArrayTaskStats* stats();) +}; + +#endif // SHARE_GC_SHARED_PARTIALARRAYSPLITTER_HPP diff --git a/src/hotspot/share/gc/shared/partialArraySplitter.inline.hpp b/src/hotspot/share/gc/shared/partialArraySplitter.inline.hpp new file mode 100644 index 00000000000..abb0cf13101 --- /dev/null +++ b/src/hotspot/share/gc/shared/partialArraySplitter.inline.hpp @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_GC_SHARED_PARTIALARRAYSPLITTER_INLINE_HPP +#define SHARE_GC_SHARED_PARTIALARRAYSPLITTER_INLINE_HPP + +#include "gc/shared/partialArraySplitter.hpp" + +#include "gc/shared/partialArrayTaskStats.hpp" +#include "gc/shared/partialArrayTaskStepper.inline.hpp" +#include "gc/shared/taskqueue.inline.hpp" +#include "oops/oop.hpp" +#include "utilities/debug.hpp" +#include "utilities/globalDefinitions.hpp" +#include "utilities/macros.hpp" + +template +size_t PartialArraySplitter::start(Queue* queue, + objArrayOop source, + objArrayOop destination, + size_t length) { + PartialArrayTaskStepper::Step step = _stepper.start(length); + // Push initial partial scan tasks. + if (step._ncreate > 0) { + TASKQUEUE_STATS_ONLY(_stats.inc_split();); + TASKQUEUE_STATS_ONLY(_stats.inc_pushed(step._ncreate);) + PartialArrayState* state = + _allocator.allocate(source, destination, step._index, length, step._ncreate); + for (uint i = 0; i < step._ncreate; ++i) { + queue->push(ScannerTask(state)); + } + } else { + assert(step._index == length, "invariant"); + } + return step._index; +} + +template +PartialArraySplitter::Claim +PartialArraySplitter::claim(PartialArrayState* state, Queue* queue, bool stolen) { +#if TASKQUEUE_STATS + if (stolen) _stats.inc_stolen(); + _stats.inc_processed(); +#endif // TASKQUEUE_STATS + + // Claim a chunk and get number of additional tasks to enqueue. + PartialArrayTaskStepper::Step step = _stepper.next(state); + // Push additional tasks. + if (step._ncreate > 0) { + TASKQUEUE_STATS_ONLY(_stats.inc_pushed(step._ncreate);) + // Adjust reference count for tasks being added to the queue. + state->add_references(step._ncreate); + for (uint i = 0; i < step._ncreate; ++i) { + queue->push(ScannerTask(state)); + } + } + // Release state, decrementing refcount, now that we're done with it. + _allocator.release(state); + return Claim{step._index, step._index + _stepper.chunk_size()}; +} + +#endif // SHARE_GC_SHARED_PARTIALARRAYSPLITTER_INLINE_HPP diff --git a/src/hotspot/share/gc/shared/partialArrayTaskStats.cpp b/src/hotspot/share/gc/shared/partialArrayTaskStats.cpp new file mode 100644 index 00000000000..210be11b925 --- /dev/null +++ b/src/hotspot/share/gc/shared/partialArrayTaskStats.cpp @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "gc/shared/partialArrayTaskStats.hpp" +#include "logging/log.hpp" +#include "logging/logHandle.hpp" +#include "logging/logStream.hpp" +#include "utilities/globalDefinitions.hpp" +#include "utilities/growableArray.hpp" +#include "utilities/macros.hpp" +#include "utilities/ostream.hpp" + +#if TASKQUEUE_STATS + +PartialArrayTaskStats::PartialArrayTaskStats() + : _split(0), _pushed(0), _stolen(0), _processed(0) +{} + +void PartialArrayTaskStats::accumulate(const PartialArrayTaskStats& stats) { + _split += stats._split; + _pushed += stats._pushed; + _stolen += stats._stolen; + _processed += stats._processed; +} + +void PartialArrayTaskStats::reset() { + *this = PartialArrayTaskStats(); +} + +LogTargetHandle PartialArrayTaskStats::log_target() { + LogTarget(Trace, gc, task, stats) lt; + return LogTargetHandle(lt); +} + +bool PartialArrayTaskStats::is_log_enabled() { + return log_target().is_enabled(); +} + +static const char* const stats_hdr[] = { + " ----partial array---- arrays array", + "thread push steal chunked chunks", + "------ ---------- ---------- ---------- ----------" +}; + +void PartialArrayTaskStats::print_header(outputStream* s, const char* title) { + s->print_cr("%s:", title); + for (uint i = 0; i < ARRAY_SIZE(stats_hdr); ++i) { + s->print_cr("%s", stats_hdr[i]); + } +} + +void PartialArrayTaskStats::print_values_impl(outputStream* s) const { + // 10 digits for each counter, matching the segments in stats_hdr. + s->print_cr(" %10zu %10zu %10zu %10zu", + _pushed, _stolen, _split, _processed); +} + +void PartialArrayTaskStats::print_values(outputStream* s, uint id) const { + // 6 digits for thread number, matching the segement in stats_hdr. + s->print("%6u", id); + print_values_impl(s); +} + +void PartialArrayTaskStats::print_total(outputStream* s) const { + // 6 characters for "total" id, matching the segment in stats_hdr. + s->print("%6s", "total"); + print_values_impl(s); +} + +#endif // TASKQUEUE_STATS diff --git a/src/hotspot/share/gc/shared/partialArrayTaskStats.hpp b/src/hotspot/share/gc/shared/partialArrayTaskStats.hpp new file mode 100644 index 00000000000..e02a9f460b0 --- /dev/null +++ b/src/hotspot/share/gc/shared/partialArrayTaskStats.hpp @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_GC_SHARED_PARTIALARRAYTASKSTATS_HPP +#define SHARE_GC_SHARED_PARTIALARRAYTASKSTATS_HPP + +#include "logging/logHandle.hpp" +#include "logging/logStream.hpp" +#include "utilities/globalDefinitions.hpp" + +#if TASKQUEUE_STATS + +class outputStream; + +// Repository for collecting and reporting statistics about partial array task +// processing. Not thread-safe; each processing thread should have its own +// stats object. +class PartialArrayTaskStats { + size_t _split; + size_t _pushed; + size_t _stolen; + size_t _processed; + + static LogTargetHandle log_target(); + static bool is_log_enabled(); + static void print_header(outputStream* s, const char* title); + void print_values(outputStream* s, uint id) const; + void print_total(outputStream* s) const; + void print_values_impl(outputStream* s) const; + + void accumulate(const PartialArrayTaskStats& stats); + +public: + // All counters are initially zero. + PartialArrayTaskStats(); + + // Trivially copied and destroyed. + + // Number of arrays split into partial array tasks. + size_t split() const { return _split; } + + // Number of partial array tasks pushed onto a queue. + size_t pushed() const { return _pushed; } + + // Number of partial array tasks stolen from some other queue. + size_t stolen() const { return _stolen; } + + // Number of partial array tasks processed. + size_t processed() const { return _processed; } + + void inc_split() { _split += 1; } + void inc_pushed(size_t n) { _pushed += n; } + void inc_stolen() { _stolen += 1; } + void inc_processed() { _processed += 1; } + + // Set all counters to zero. + void reset(); + + // Log a table of statistics, if logging is enabled (gc+task+stats=trace). + // + // num_stats: The number of stats objects to include in the table, one row + // for each. + // + // access: A function taking a uint value < num_stats, and returning a + // pointer to the corresponding stats object. + // + // title: A string title for the table. + template + static void log_set(uint num_stats, StatsAccess access, const char* title) { + if (is_log_enabled()) { + LogStream ls(log_target()); + PartialArrayTaskStats total; + print_header(&ls, title); + for (uint i = 0; i < num_stats; ++i) { + const PartialArrayTaskStats* stats = access(i); + stats->print_values(&ls, i); + total.accumulate(*stats); + } + total.print_total(&ls); + } + } +}; + +#endif // TASKQUEUE_STATS + +#endif // SHARE_GC_SHARED_PARTIALARRAYTASKSTATS_HPP diff --git a/src/hotspot/share/gc/shared/taskqueue.hpp b/src/hotspot/share/gc/shared/taskqueue.hpp index efbc1882fbe..a6ab5741048 100644 --- a/src/hotspot/share/gc/shared/taskqueue.hpp +++ b/src/hotspot/share/gc/shared/taskqueue.hpp @@ -34,20 +34,6 @@ #include "utilities/ostream.hpp" #include "utilities/stack.hpp" -// Simple TaskQueue stats that are collected by default in debug builds. - -#if !defined(TASKQUEUE_STATS) && defined(ASSERT) -#define TASKQUEUE_STATS 1 -#elif !defined(TASKQUEUE_STATS) -#define TASKQUEUE_STATS 0 -#endif - -#if TASKQUEUE_STATS -#define TASKQUEUE_STATS_ONLY(code) code -#else -#define TASKQUEUE_STATS_ONLY(code) -#endif // TASKQUEUE_STATS - #if TASKQUEUE_STATS class TaskQueueStats { public: diff --git a/src/hotspot/share/utilities/macros.hpp b/src/hotspot/share/utilities/macros.hpp index b14905ff8e2..5c3cfaa0dd5 100644 --- a/src/hotspot/share/utilities/macros.hpp +++ b/src/hotspot/share/utilities/macros.hpp @@ -358,6 +358,21 @@ #define NOT_CHECK_UNHANDLED_OOPS(code) code #endif // CHECK_UNHANDLED_OOPS +// Enable collection of TaskQueue statistics. +// Enabled by default in debug builds. Otherwise, disabled by default. +#ifndef TASKQUEUE_STATS +#ifdef ASSERT +#define TASKQUEUE_STATS 1 +#else +#define TASKQUEUE_STATS 0 +#endif // ASSERT +#endif // TASKQUEUE_STATS +#if TASKQUEUE_STATS +#define TASKQUEUE_STATS_ONLY(code) code +#else +#define TASKQUEUE_STATS_ONLY(code) +#endif // TASKQUEUE_STATS + #ifdef ASSERT #define DEBUG_ONLY(code) code #define NOT_DEBUG(code) From 2649a97332b4af4f6eebc0c83af77e1c77760644 Mon Sep 17 00:00:00 2001 From: Roland Westrelin Date: Thu, 19 Dec 2024 16:09:41 +0000 Subject: [PATCH 04/36] 8332827: [REDO] C2: crash in compiled code because of dependency on removed range check CastIIs Reviewed-by: epeter, chagedorn --- src/hotspot/share/opto/castnode.cpp | 58 ++- src/hotspot/share/opto/castnode.hpp | 2 + src/hotspot/share/opto/compile.cpp | 21 +- src/hotspot/share/opto/node.cpp | 12 + src/hotspot/share/opto/node.hpp | 7 + ...yAccessAboveRCAfterRCCastIIEliminated.java | 474 ++++++++++++++++++ .../TestRangeCheckCastIISplitThruPhi.java | 106 ++++ .../TestVectorizationNegativeScale.java | 63 +++ 8 files changed, 713 insertions(+), 30 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/rangechecks/TestArrayAccessAboveRCAfterRCCastIIEliminated.java create mode 100644 test/hotspot/jtreg/compiler/rangechecks/TestRangeCheckCastIISplitThruPhi.java create mode 100644 test/hotspot/jtreg/compiler/vectorization/TestVectorizationNegativeScale.java diff --git a/src/hotspot/share/opto/castnode.cpp b/src/hotspot/share/opto/castnode.cpp index 63ed54df4fd..600cf7503db 100644 --- a/src/hotspot/share/opto/castnode.cpp +++ b/src/hotspot/share/opto/castnode.cpp @@ -213,19 +213,15 @@ const Type* CastIINode::Value(PhaseGVN* phase) const { // Similar to ConvI2LNode::Value() for the same reasons // see if we can remove type assertion after loop opts - // But here we have to pay extra attention: - // Do not narrow the type of range check dependent CastIINodes to - // avoid corruption of the graph if a CastII is replaced by TOP but - // the corresponding range check is not removed. - if (!_range_check_dependency) { - res = widen_type(phase, res, T_INT); - } + res = widen_type(phase, res, T_INT); return res; } -static Node* find_or_make_integer_cast(PhaseIterGVN* igvn, Node* parent, Node* control, const TypeInteger* type, ConstraintCastNode::DependencyType dependency, BasicType bt) { - Node* n = ConstraintCastNode::make_cast_for_basic_type(control, parent, type, dependency, bt); +Node* ConstraintCastNode::find_or_make_integer_cast(PhaseIterGVN* igvn, Node* parent, const TypeInteger* type) const { + Node* n = clone(); + n->set_req(1, parent); + n->as_ConstraintCast()->set_type(type); Node* existing = igvn->hash_find_insert(n); if (existing != nullptr) { n->destruct(igvn); @@ -239,13 +235,14 @@ Node *CastIINode::Ideal(PhaseGVN *phase, bool can_reshape) { if (progress != nullptr) { return progress; } - if (can_reshape && !_range_check_dependency && !phase->C->post_loop_opts_phase()) { + if (can_reshape && !phase->C->post_loop_opts_phase()) { // makes sure we run ::Value to potentially remove type assertion after loop opts phase->C->record_for_post_loop_opts_igvn(this); } - if (!_range_check_dependency) { + if (!_range_check_dependency || phase->C->post_loop_opts_phase()) { return optimize_integer_cast(phase, T_INT); } + phase->C->record_for_post_loop_opts_igvn(this); return nullptr; } @@ -254,13 +251,6 @@ Node* CastIINode::Identity(PhaseGVN* phase) { if (progress != this) { return progress; } - if (_range_check_dependency) { - if (phase->C->post_loop_opts_phase()) { - return this->in(1); - } else { - phase->C->record_for_post_loop_opts_igvn(this); - } - } return this; } @@ -289,6 +279,34 @@ CastIINode* CastIINode::pin_array_access_node() const { return nullptr; } +void CastIINode::remove_range_check_cast(Compile* C) { + if (has_range_check()) { + // Range check CastII nodes feed into an address computation subgraph. Remove them to let that subgraph float freely. + // For memory access or integer divisions nodes that depend on the cast, record the dependency on the cast's control + // as a precedence edge, so they can't float above the cast in case that cast's narrowed type helped eliminate a + // range check or a null divisor check. + assert(in(0) != nullptr, "All RangeCheck CastII must have a control dependency"); + ResourceMark rm; + Unique_Node_List wq; + wq.push(this); + for (uint next = 0; next < wq.size(); ++next) { + Node* m = wq.at(next); + for (DUIterator_Fast imax, i = m->fast_outs(imax); i < imax; i++) { + Node* use = m->fast_out(i); + if (use->is_Mem() || use->is_div_or_mod(T_INT) || use->is_div_or_mod(T_LONG)) { + use->ensure_control_or_add_prec(in(0)); + } else if (!use->is_CFG() && !use->is_Phi()) { + wq.push(use); + } + } + } + subsume_by(in(1), C); + if (outcnt() == 0) { + disconnect_inputs(C); + } + } +} + const Type* CastLLNode::Value(PhaseGVN* phase) const { const Type* res = ConstraintCastNode::Value(phase); @@ -489,8 +507,8 @@ Node* ConstraintCastNode::optimize_integer_cast(PhaseGVN* phase, BasicType bt) { Node* x = z->in(1); Node* y = z->in(2); - Node* cx = find_or_make_integer_cast(igvn, x, in(0), rx, _dependency, bt); - Node* cy = find_or_make_integer_cast(igvn, y, in(0), ry, _dependency, bt); + Node* cx = find_or_make_integer_cast(igvn, x, rx); + Node* cy = find_or_make_integer_cast(igvn, y, ry); if (op == Op_Add(bt)) { return AddNode::make(cx, cy, bt); } else { diff --git a/src/hotspot/share/opto/castnode.hpp b/src/hotspot/share/opto/castnode.hpp index c193d406f93..e6ef7b06065 100644 --- a/src/hotspot/share/opto/castnode.hpp +++ b/src/hotspot/share/opto/castnode.hpp @@ -45,6 +45,7 @@ class ConstraintCastNode: public TypeNode { virtual uint size_of() const; virtual uint hash() const; // Check the type const Type* widen_type(const PhaseGVN* phase, const Type* res, BasicType bt) const; + Node* find_or_make_integer_cast(PhaseIterGVN* igvn, Node* parent, const TypeInteger* type) const; private: // PhiNode::Ideal() transforms a Phi that merges a single uncasted value into a single cast pinned at the region. @@ -121,6 +122,7 @@ class CastIINode: public ConstraintCastNode { } CastIINode* pin_array_access_node() const; + void remove_range_check_cast(Compile* C); #ifndef PRODUCT virtual void dump_spec(outputStream* st) const; diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index 10af40a54e6..2da8e27d95c 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -3146,6 +3146,13 @@ void Compile::handle_div_mod_op(Node* n, BasicType bt, bool is_unsigned) { // Replace them with a fused divmod if supported if (Matcher::has_match_rule(Op_DivModIL(bt, is_unsigned))) { DivModNode* divmod = DivModNode::make(n, bt, is_unsigned); + // If the divisor input for a Div (or Mod etc.) is not zero, then the control input of the Div is set to zero. + // It could be that the divisor input is found not zero because its type is narrowed down by a CastII in the + // subgraph for that input. Range check CastIIs are removed during final graph reshape. To preserve the dependency + // carried by a CastII, precedence edges are added to the Div node. We need to transfer the precedence edges to the + // DivMod node so the dependency is not lost. + divmod->add_prec_from(n); + divmod->add_prec_from(d); d->subsume_by(divmod->div_proj(), this); n->subsume_by(divmod->mod_proj(), this); } else { @@ -3431,6 +3438,10 @@ void Compile::final_graph_reshaping_main_switch(Node* n, Final_Reshape_Counts& f } break; } + case Op_CastII: { + n->as_CastII()->remove_range_check_cast(this); + break; + } #ifdef _LP64 case Op_CmpP: // Do this transformation here to preserve CmpPNode::sub() and @@ -3582,16 +3593,6 @@ void Compile::final_graph_reshaping_main_switch(Node* n, Final_Reshape_Counts& f #endif -#ifdef ASSERT - case Op_CastII: - // Verify that all range check dependent CastII nodes were removed. - if (n->isa_CastII()->has_range_check()) { - n->dump(3); - assert(false, "Range check dependent CastII node was not removed"); - } - break; -#endif - case Op_ModI: handle_div_mod_op(n, T_INT, false); break; diff --git a/src/hotspot/share/opto/node.cpp b/src/hotspot/share/opto/node.cpp index cf371bb3fff..270bbc10a0d 100644 --- a/src/hotspot/share/opto/node.cpp +++ b/src/hotspot/share/opto/node.cpp @@ -2894,6 +2894,15 @@ void Node::ensure_control_or_add_prec(Node* c) { } } +void Node::add_prec_from(Node* n) { + for (uint i = n->req(); i < n->len(); i++) { + Node* prec = n->in(i); + if (prec != nullptr) { + add_prec(prec); + } + } +} + bool Node::is_dead_loop_safe() const { if (is_Phi()) { return true; @@ -2917,6 +2926,9 @@ bool Node::is_dead_loop_safe() const { return false; } +bool Node::is_div_or_mod(BasicType bt) const { return Opcode() == Op_Div(bt) || Opcode() == Op_Mod(bt) || + Opcode() == Op_UDiv(bt) || Opcode() == Op_UMod(bt); } + //============================================================================= //------------------------------yank------------------------------------------- // Find and remove diff --git a/src/hotspot/share/opto/node.hpp b/src/hotspot/share/opto/node.hpp index 8ff778ed493..50ae1deecbf 100644 --- a/src/hotspot/share/opto/node.hpp +++ b/src/hotspot/share/opto/node.hpp @@ -1166,6 +1166,7 @@ class Node { // Set control or add control as precedence edge void ensure_control_or_add_prec(Node* c); + void add_prec_from(Node* n); // Visit boundary uses of the node and apply a callback function for each. // Recursively traverse uses, stopping and applying the callback when @@ -1277,6 +1278,8 @@ class Node { // Whether this is a memory phi node bool is_memory_phi() const { return is_Phi() && bottom_type() == Type::MEMORY; } + bool is_div_or_mod(BasicType bt) const; + //----------------- Printing, etc #ifndef PRODUCT public: @@ -2060,6 +2063,10 @@ Op_IL(URShift) Op_IL(LShift) Op_IL(Xor) Op_IL(Cmp) +Op_IL(Div) +Op_IL(Mod) +Op_IL(UDiv) +Op_IL(UMod) inline int Op_ConIL(BasicType bt) { assert(bt == T_INT || bt == T_LONG, "only for int or longs"); diff --git a/test/hotspot/jtreg/compiler/rangechecks/TestArrayAccessAboveRCAfterRCCastIIEliminated.java b/test/hotspot/jtreg/compiler/rangechecks/TestArrayAccessAboveRCAfterRCCastIIEliminated.java new file mode 100644 index 00000000000..87e87842af3 --- /dev/null +++ b/test/hotspot/jtreg/compiler/rangechecks/TestArrayAccessAboveRCAfterRCCastIIEliminated.java @@ -0,0 +1,474 @@ +/* + * Copyright (c) 2024, Red Hat, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8332827 + * @summary [REDO] C2: crash in compiled code because of dependency on removed range check CastIIs + * + * @run main/othervm -XX:-TieredCompilation -XX:-UseOnStackReplacement -XX:-BackgroundCompilation + * -XX:CompileCommand=dontinline,TestArrayAccessAboveRCAfterRCCastIIEliminated::notInlined + * TestArrayAccessAboveRCAfterRCCastIIEliminated + * @run main/othervm -XX:-TieredCompilation -XX:-UseOnStackReplacement -XX:-BackgroundCompilation + * -XX:CompileCommand=dontinline,TestArrayAccessAboveRCAfterRCCastIIEliminated::notInlined + * -XX:+UnlockDiagnosticVMOptions -XX:+StressGCM TestArrayAccessAboveRCAfterRCCastIIEliminated + * @run main TestArrayAccessAboveRCAfterRCCastIIEliminated + * @run main/othervm -XX:CompileCommand=dontinline,TestArrayAccessAboveRCAfterRCCastIIEliminated::notInlined + * TestArrayAccessAboveRCAfterRCCastIIEliminated + * + */ + +public class TestArrayAccessAboveRCAfterRCCastIIEliminated { + private static int intField; + private static long longField; + private static volatile int volatileField; + + public static void main(String[] args) { + int[] array = new int[100]; + for (int i = 0; i < 20_000; i++) { + test1(9, 10, 1, true); + test1(9, 10, 1, false); + test2(9, 10, 1, true); + test2(9, 10, 1, false); + test3(9, 10, 1, true); + test3(9, 10, 1, false); + test4(9, 10, 1, true); + test4(9, 10, 1, false); + test5(9, 10, 1, true); + test5(9, 10, 1, false); + test6(9, 10, 1, true); + test6(9, 10, 1, false); + test7(9, 10, 1, true); + test7(9, 10, 1, false); + test8(9, 10, 1, true); + test8(9, 10, 1, false); + test9(9, 10, 1, true); + test9(9, 10, 1, false); + test10(9, 10, 1, true); + test10(9, 10, 1, false); + test11(9, 10, 1, true); + test11(9, 10, 1, false); + test12(9, 10, 1, true); + test12(9, 10, 1, false); + test13(9, 10, 1, true); + test13(9, 10, 1, false); + } + try { + test1(-1, 10, 1, true); + } catch (ArrayIndexOutOfBoundsException arrayIndexOutOfBoundsException) { + } + try { + test2(-1, 10, 1, true); + } catch (ArrayIndexOutOfBoundsException arrayIndexOutOfBoundsException) { + } + try { + test3(-1, 10, 1, true); + } catch (ArrayIndexOutOfBoundsException arrayIndexOutOfBoundsException) { + } + try { + test4(-1, 10, 1, true); + } catch (ArrayIndexOutOfBoundsException arrayIndexOutOfBoundsException) { + } + try { + test5(-1, 10, 1, true); + } catch (ArrayIndexOutOfBoundsException arrayIndexOutOfBoundsException) { + } + try { + test6(-1, 10, 1, true); + } catch (ArrayIndexOutOfBoundsException arrayIndexOutOfBoundsException) { + } + try { + test7(-1, 10, 1, true); + } catch (ArrayIndexOutOfBoundsException arrayIndexOutOfBoundsException) { + } + try { + test8(-1, 10, 1, true); + } catch (ArrayIndexOutOfBoundsException arrayIndexOutOfBoundsException) { + } + try { + test9(-1, 10, 1, true); + } catch (ArrayIndexOutOfBoundsException arrayIndexOutOfBoundsException) { + } + try { + test10(-1, 10, 1, true); + } catch (ArrayIndexOutOfBoundsException arrayIndexOutOfBoundsException) { + } + try { + test11(-1, 10, 1, true); + } catch (ArrayIndexOutOfBoundsException arrayIndexOutOfBoundsException) { + } + try { + test12(-1, 10, 1, true); + } catch (ArrayIndexOutOfBoundsException arrayIndexOutOfBoundsException) { + } + try { + test13(-1, 10, 1, true); + } catch (ArrayIndexOutOfBoundsException arrayIndexOutOfBoundsException) { + } + } + + private static void test1(int i, int j, int flag, boolean flag2) { + i = Math.min(i, 9); + int[] array = new int[10]; + notInlined(array); + if (flag == 0) { + } + if (flag2) { + float[] newArray = new float[j]; + newArray[i] = 42; + float[] otherArray = new float[i]; + if (flag == 0) { + } + intField = array[otherArray.length]; + } else { + float[] newArray = new float[j]; + newArray[i] = 42; + float[] otherArray = new float[i]; + if (flag == 0) { + } + intField = array[otherArray.length]; + } + for (int k = 0; k < 10; k++) { + + } + } + + private static void test2(int i, int j, int flag, boolean flag2) { + i = Math.min(i, 9); + int[] array = new int[10]; + notInlined(array); + if (flag == 0) { + } + if (flag2) { + float[] newArray = new float[j]; + newArray[i] = 42; + float[] otherArray = new float[i]; + if (flag == 0) { + } + intField = 1 / (otherArray.length + 1); + } else { + float[] newArray = new float[j]; + newArray[i] = 42; + float[] otherArray = new float[i]; + if (flag == 0) { + } + intField = 1 / (otherArray.length + 1); + } + for (int k = 0; k < 10; k++) { + + } + } + + private static void test3(int i, int j, int flag, boolean flag2) { + i = Math.min(i, 9); + int[] array = new int[10]; + notInlined(array); + if (flag == 0) { + } + if (flag2) { + float[] newArray = new float[j]; + newArray[i] = 42; + float[] otherArray = new float[i]; + if (flag == 0) { + } + longField = 1L / (otherArray.length + 1); + } else { + float[] newArray = new float[j]; + newArray[i] = 42; + float[] otherArray = new float[i]; + if (flag == 0) { + } + longField = 1L / (otherArray.length + 1); + } + for (int k = 0; k < 10; k++) { + + } + } + + private static void test4(int i, int j, int flag, boolean flag2) { + i = Math.min(i, 9); + int[] array = new int[10]; + notInlined(array); + if (flag == 0) { + } + if (flag2) { + float[] newArray = new float[j]; + newArray[i] = 42; + float[] otherArray = new float[i]; + if (flag == 0) { + } + intField = 1 % (otherArray.length + 1); + } else { + float[] newArray = new float[j]; + newArray[i] = 42; + float[] otherArray = new float[i]; + if (flag == 0) { + } + intField = 1 % (otherArray.length + 1); + } + for (int k = 0; k < 10; k++) { + + } + } + + private static void test5(int i, int j, int flag, boolean flag2) { + i = Math.min(i, 9); + int[] array = new int[10]; + notInlined(array); + if (flag == 0) { + } + if (flag2) { + float[] newArray = new float[j]; + newArray[i] = 42; + float[] otherArray = new float[i]; + if (flag == 0) { + } + longField = 1L % (otherArray.length + 1); + } else { + float[] newArray = new float[j]; + newArray[i] = 42; + float[] otherArray = new float[i]; + if (flag == 0) { + } + longField = 1L % (otherArray.length + 1); + } + for (int k = 0; k < 10; k++) { + + } + } + + private static void test6(int i, int j, int flag, boolean flag2) { + i = Math.min(i, 9); + int[] array = new int[10]; + notInlined(array); + if (flag == 0) { + } + if (flag2) { + float[] newArray = new float[j]; + newArray[i] = 42; + float[] otherArray = new float[i]; + if (flag == 0) { + } + intField = 1 % (otherArray.length + 1) + 1 / (otherArray.length + 1); + } else { + float[] newArray = new float[j]; + newArray[i] = 42; + float[] otherArray = new float[i]; + if (flag == 0) { + } + intField = 1 % (otherArray.length + 1) + 1 / (otherArray.length + 1); + } + for (int k = 0; k < 10; k++) { + + } + } + + private static void test7(int i, int j, int flag, boolean flag2) { + i = Math.min(i, 9); + int[] array = new int[10]; + notInlined(array); + if (flag == 0) { + } + if (flag2) { + float[] newArray = new float[j]; + newArray[i] = 42; + float[] otherArray = new float[i]; + if (flag == 0) { + } + longField = 1L % (otherArray.length + 1) + 1L / (otherArray.length + 1); + } else { + float[] newArray = new float[j]; + newArray[i] = 42; + float[] otherArray = new float[i]; + if (flag == 0) { + } + longField = 1L % (otherArray.length + 1) + 1L / (otherArray.length + 1); + } + for (int k = 0; k < 10; k++) { + + } + } + private static void test8(int i, int j, int flag, boolean flag2) { + i = Math.min(i, 9); + int[] array = new int[10]; + notInlined(array); + if (flag == 0) { + } + if (flag2) { + float[] newArray = new float[j]; + newArray[i] = 42; + float[] otherArray = new float[i]; + if (flag == 0) { + } + intField = Integer.divideUnsigned(1, (otherArray.length + 1)); + } else { + float[] newArray = new float[j]; + newArray[i] = 42; + float[] otherArray = new float[i]; + if (flag == 0) { + } + intField = Integer.divideUnsigned(1, (otherArray.length + 1)); + } + for (int k = 0; k < 10; k++) { + + } + } + + private static void test9(int i, int j, int flag, boolean flag2) { + i = Math.min(i, 9); + int[] array = new int[10]; + notInlined(array); + if (flag == 0) { + } + if (flag2) { + float[] newArray = new float[j]; + newArray[i] = 42; + float[] otherArray = new float[i]; + if (flag == 0) { + } + longField = Long.divideUnsigned(1L, (otherArray.length + 1)); + } else { + float[] newArray = new float[j]; + newArray[i] = 42; + float[] otherArray = new float[i]; + if (flag == 0) { + } + longField = Long.divideUnsigned(1L, (otherArray.length + 1)); + } + for (int k = 0; k < 10; k++) { + + } + } + + private static void test10(int i, int j, int flag, boolean flag2) { + i = Math.min(i, 9); + int[] array = new int[10]; + notInlined(array); + if (flag == 0) { + } + if (flag2) { + float[] newArray = new float[j]; + newArray[i] = 42; + float[] otherArray = new float[i]; + if (flag == 0) { + } + intField = Integer.remainderUnsigned(1, (otherArray.length + 1)); + } else { + float[] newArray = new float[j]; + newArray[i] = 42; + float[] otherArray = new float[i]; + if (flag == 0) { + } + intField = Integer.remainderUnsigned(1, (otherArray.length + 1)); + } + for (int k = 0; k < 10; k++) { + + } + } + + private static void test11(int i, int j, int flag, boolean flag2) { + i = Math.min(i, 9); + int[] array = new int[10]; + notInlined(array); + if (flag == 0) { + } + if (flag2) { + float[] newArray = new float[j]; + newArray[i] = 42; + float[] otherArray = new float[i]; + if (flag == 0) { + } + longField = Long.remainderUnsigned(1L, (otherArray.length + 1)); + } else { + float[] newArray = new float[j]; + newArray[i] = 42; + float[] otherArray = new float[i]; + if (flag == 0) { + } + longField = Long.remainderUnsigned(1L, (otherArray.length + 1)); + } + for (int k = 0; k < 10; k++) { + + } + } + + private static void test12(int i, int j, int flag, boolean flag2) { + i = Math.min(i, 9); + int[] array = new int[10]; + notInlined(array); + if (flag == 0) { + } + if (flag2) { + float[] newArray = new float[j]; + newArray[i] = 42; + float[] otherArray = new float[i]; + if (flag == 0) { + } + intField = Integer.divideUnsigned(1, (otherArray.length + 1)) + + Integer.remainderUnsigned(1, (otherArray.length + 1)); + } else { + float[] newArray = new float[j]; + newArray[i] = 42; + float[] otherArray = new float[i]; + if (flag == 0) { + } + intField = Integer.divideUnsigned(1, (otherArray.length + 1)) + + Integer.remainderUnsigned(1, (otherArray.length + 1)); + } + for (int k = 0; k < 10; k++) { + + } + } + + private static void test13(int i, int j, int flag, boolean flag2) { + i = Math.min(i, 9); + int[] array = new int[10]; + notInlined(array); + if (flag == 0) { + } + if (flag2) { + float[] newArray = new float[j]; + newArray[i] = 42; + float[] otherArray = new float[i]; + if (flag == 0) { + } + longField = Long.remainderUnsigned(1L, (otherArray.length + 1)) + + Long.divideUnsigned(1L, (otherArray.length + 1)); + } else { + float[] newArray = new float[j]; + newArray[i] = 42; + float[] otherArray = new float[i]; + if (flag == 0) { + } + longField = Long.remainderUnsigned(1L, (otherArray.length + 1)) + + Long.divideUnsigned(1L, (otherArray.length + 1)); + } + for (int k = 0; k < 10; k++) { + + } + } + + private static void notInlined(int[] array) { + + } +} diff --git a/test/hotspot/jtreg/compiler/rangechecks/TestRangeCheckCastIISplitThruPhi.java b/test/hotspot/jtreg/compiler/rangechecks/TestRangeCheckCastIISplitThruPhi.java new file mode 100644 index 00000000000..1f36ca1c9cb --- /dev/null +++ b/test/hotspot/jtreg/compiler/rangechecks/TestRangeCheckCastIISplitThruPhi.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2024, Red Hat, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8332827 + * @summary [REDO] C2: crash in compiled code because of dependency on removed range check CastIIs + * + * @run main/othervm -XX:-TieredCompilation -XX:-UseOnStackReplacement -XX:-BackgroundCompilation TestRangeCheckCastIISplitThruPhi + * @run main TestRangeCheckCastIISplitThruPhi + * + */ + +import java.util.Arrays; + +public class TestRangeCheckCastIISplitThruPhi { + private static volatile int volatileField; + + public static void main(String[] args) { + int[] array = new int[100]; + int[] baseline = null; + for (int i = 0; i < 20_000; i++) { + Arrays.fill(array, 0); + test1(array); + if (baseline == null) { + baseline = array.clone(); + } else { + boolean failures = false; + for (int j = 0; j < array.length; j++) { + if (array[j] != baseline[j]) { + System.out.println("XXX @" + j + " " + array[j] + " != " + baseline[j]); + failures = true; + } + } + if (failures) { + throw new RuntimeException(); + } + } + test2(array, true); + test2(array, false); + } + } + + private static void test1(int[] array) { + int[] array2 = new int[100]; + int j = 4; + int i = 3; + int k; + for (k = 1; k < 2; k *= 2) { + + } + int stride = k / 2; + do { + synchronized (new Object()) { + } + array2[j-1] = 42; + array[j+1] = 42; + j = i; + i -= stride; + } while (i >= 0); + } + + private static void test2(int[] array, boolean flag) { + int[] array2 = new int[100]; + int j = 4; + int i = 3; + int k; + for (k = 1; k < 2; k *= 2) { + + } + int stride = k / 2; + if (flag) { + volatileField = 42; + array[0] = 42; + } else { + do { + synchronized (new Object()) { + } + array2[j - 1] = 42; + array[j + 1] = 42; + j = i; + i -= stride; + } while (i >= 0); + } + } +} diff --git a/test/hotspot/jtreg/compiler/vectorization/TestVectorizationNegativeScale.java b/test/hotspot/jtreg/compiler/vectorization/TestVectorizationNegativeScale.java new file mode 100644 index 00000000000..58464880070 --- /dev/null +++ b/test/hotspot/jtreg/compiler/vectorization/TestVectorizationNegativeScale.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2024, Red Hat, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8332827 + * @summary [REDO] C2: crash in compiled code because of dependency on removed range check CastIIs + * + * @library /test/lib / + * @run driver TestVectorizationNegativeScale + * + */ + +import compiler.lib.ir_framework.*; + +import java.util.Arrays; + +public class TestVectorizationNegativeScale { + public static void main(String[] args) { + TestFramework.run(); + } + + static byte[] array = new byte[1000]; + + @Test + @IR(counts = { IRNode.STORE_VECTOR , ">= 1"}) + private static void test1(byte[] array, int start) { + for (int i = start; i < array.length; i++) { + array[array.length - i - 1] = 0x42; + } + } + + @Run(test = "test1") + private static void test1Runner() { + Arrays.fill(array, (byte)0); + test1(array, 0); + for (int j = 0; j < array.length; j++) { + if (array[j] != 0x42) { + throw new RuntimeException("For index " + j + ": " + array[j]); + } + } + } +} From 4d77dbad4e15c5392878e7bc91cd8eb7ce49a482 Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Thu, 19 Dec 2024 16:16:58 +0000 Subject: [PATCH 05/36] 8346576: Remove vmTestbase/gc/memory/Nio/Nio.java from test/hotspot/jtreg/ProblemList.txt Reviewed-by: alanb, jpai, mli --- test/hotspot/jtreg/ProblemList.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index 583ae68ff50..e17b5a9b600 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -171,7 +171,6 @@ vmTestbase/nsk/jvmti/scenarios/capability/CM03/cm03t001/TestDescription.java 807 vmTestbase/nsk/jvmti/InterruptThread/intrpthrd003/TestDescription.java 8288911 macosx-all vmTestbase/gc/lock/jni/jnilock002/TestDescription.java 8192647 generic-all -vmTestbase/gc/memory/Nio/Nio.java 8340728 generic-all vmTestbase/jit/escape/LockCoarsening/LockCoarsening001.java 8148743 generic-all vmTestbase/jit/escape/LockCoarsening/LockCoarsening002.java 8208259 generic-all From b2811a0ccd9664d11770980c47424ab6723cbbc9 Mon Sep 17 00:00:00 2001 From: Weijun Wang Date: Thu, 19 Dec 2024 21:35:55 +0000 Subject: [PATCH 06/36] 8340493: Fix some Asserts failure messages Reviewed-by: valeriep, djelinski --- .../provider/KDF/HKDFBasicFunctionsTest.java | 6 +- test/jdk/sun/security/ec/ECDHPrimitive.java | 4 +- .../security/provider/acvp/ML_DSA_Test.java | 6 +- .../security/provider/acvp/ML_KEM_Test.java | 10 +-- .../sun/security/provider/acvp/SHA_Test.java | 16 ++-- test/lib-test/jdk/test/lib/AssertsTest.java | 41 ++++++++- .../lib/security/FixedSecureRandomTest.java | 6 +- test/lib/jdk/test/lib/Asserts.java | 84 +++++++++---------- 8 files changed, 103 insertions(+), 70 deletions(-) diff --git a/test/jdk/com/sun/crypto/provider/KDF/HKDFBasicFunctionsTest.java b/test/jdk/com/sun/crypto/provider/KDF/HKDFBasicFunctionsTest.java index 2697ba57641..b309d1ce8df 100644 --- a/test/jdk/com/sun/crypto/provider/KDF/HKDFBasicFunctionsTest.java +++ b/test/jdk/com/sun/crypto/provider/KDF/HKDFBasicFunctionsTest.java @@ -52,14 +52,14 @@ public static void main(String[] args) throws Exception { var extractAndExpand = HKDFParameterSpec.ofExtract().addIKM(ikm).addSalt(salt).thenExpand(info, len); var okm2 = kdf.deriveKey("OKM", extractAndExpand); - Asserts.assertEqualsByteArray(prk.getEncoded(), expectedPrk, + Asserts.assertEqualsByteArray(expectedPrk, prk.getEncoded(), "the PRK must match the expected value"); - Asserts.assertEqualsByteArray(okm1.getEncoded(), expectedOkm, + Asserts.assertEqualsByteArray(expectedOkm, okm1.getEncoded(), "the OKM must match the expected value " + "(expand)"); - Asserts.assertEqualsByteArray(okm2.getEncoded(), expectedOkm, + Asserts.assertEqualsByteArray(expectedOkm, okm2.getEncoded(), "the OKM must match the expected value " + "(extract expand)"); diff --git a/test/jdk/sun/security/ec/ECDHPrimitive.java b/test/jdk/sun/security/ec/ECDHPrimitive.java index b41b93bc5ff..3ed0a9d34a3 100644 --- a/test/jdk/sun/security/ec/ECDHPrimitive.java +++ b/test/jdk/sun/security/ec/ECDHPrimitive.java @@ -118,7 +118,7 @@ private static void runTest(ECParameterSpec ecParams, byte[] secret = ka.generateSecret(); byte[] expectedSecret = values.get("ZIUT"); - Asserts.assertEqualsByteArray(secret, expectedSecret, "Incorrect secret value"); + Asserts.assertEqualsByteArray(expectedSecret, secret, "Incorrect secret value"); int testIndex = values.get("COUNT")[0]; System.out.println("Test " + testIndex + " passed."); } @@ -141,4 +141,4 @@ private static void addKeyValue(String line, Map values) { private static String lookupName(String name) { return NAME_MAP.get(name); } -} \ No newline at end of file +} diff --git a/test/jdk/sun/security/provider/acvp/ML_DSA_Test.java b/test/jdk/sun/security/provider/acvp/ML_DSA_Test.java index 657c01e4aa8..d8e72581b52 100644 --- a/test/jdk/sun/security/provider/acvp/ML_DSA_Test.java +++ b/test/jdk/sun/security/provider/acvp/ML_DSA_Test.java @@ -76,8 +76,8 @@ static void keyGenTest(JSONValue kat, Provider p) throws Exception { var kp = g.generateKeyPair(); var pk = f.getKeySpec(kp.getPublic(), EncodedKeySpec.class).getEncoded(); var sk = f.getKeySpec(kp.getPrivate(), EncodedKeySpec.class).getEncoded(); - Asserts.assertEqualsByteArray(pk, toByteArray(c.get("pk").asString())); - Asserts.assertEqualsByteArray(sk, toByteArray(c.get("sk").asString())); + Asserts.assertEqualsByteArray(toByteArray(c.get("pk").asString()), pk); + Asserts.assertEqualsByteArray(toByteArray(c.get("sk").asString()), sk); } System.out.println(); } @@ -104,7 +104,7 @@ static void sigGenTest(JSONValue kat, Provider p) throws Exception { s.update(toByteArray(c.get("message").asString())); var sig = s.sign(); Asserts.assertEqualsByteArray( - sig, toByteArray(c.get("signature").asString())); + toByteArray(c.get("signature").asString()), sig); } System.out.println(); } diff --git a/test/jdk/sun/security/provider/acvp/ML_KEM_Test.java b/test/jdk/sun/security/provider/acvp/ML_KEM_Test.java index 46f394adbdf..c46c6a99e6d 100644 --- a/test/jdk/sun/security/provider/acvp/ML_KEM_Test.java +++ b/test/jdk/sun/security/provider/acvp/ML_KEM_Test.java @@ -70,8 +70,8 @@ static void keyGenTest(JSONValue kat, Provider p) throws Exception { var kp = g.generateKeyPair(); var pk = f.getKeySpec(kp.getPublic(), EncodedKeySpec.class).getEncoded(); var sk = f.getKeySpec(kp.getPrivate(), EncodedKeySpec.class).getEncoded(); - Asserts.assertEqualsByteArray(pk, toByteArray(c.get("ek").asString())); - Asserts.assertEqualsByteArray(sk, toByteArray(c.get("dk").asString())); + Asserts.assertEqualsByteArray(toByteArray(c.get("ek").asString()), pk); + Asserts.assertEqualsByteArray(toByteArray(c.get("dk").asString()), sk); } System.out.println(); } @@ -97,9 +97,9 @@ static void encapDecapTest(JSONValue kat, Provider p) throws Exception { ek, new FixedSecureRandom(toByteArray(c.get("m").asString()))); var enc = e.encapsulate(); Asserts.assertEqualsByteArray( - enc.encapsulation(), toByteArray(c.get("c").asString())); + toByteArray(c.get("c").asString()), enc.encapsulation()); Asserts.assertEqualsByteArray( - enc.key().getEncoded(), toByteArray(c.get("k").asString())); + toByteArray(c.get("k").asString()), enc.key().getEncoded()); } System.out.println(); } else if (function.equals("decapsulation")) { @@ -112,7 +112,7 @@ static void encapDecapTest(JSONValue kat, Provider p) throws Exception { System.out.print(c.get("tcId").asString() + " "); var d = g.newDecapsulator(dk); var k = d.decapsulate(toByteArray(c.get("c").asString())); - Asserts.assertEqualsByteArray(k.getEncoded(), toByteArray(c.get("k").asString())); + Asserts.assertEqualsByteArray(toByteArray(c.get("k").asString()), k.getEncoded()); } System.out.println(); } diff --git a/test/jdk/sun/security/provider/acvp/SHA_Test.java b/test/jdk/sun/security/provider/acvp/SHA_Test.java index 3e5d4bb2521..4a64fb00c8c 100644 --- a/test/jdk/sun/security/provider/acvp/SHA_Test.java +++ b/test/jdk/sun/security/provider/acvp/SHA_Test.java @@ -46,8 +46,8 @@ public static void run(JSONValue kat, Provider provider) throws Exception { var msg = toByteArray(c.get("msg").asString()); var len = Integer.parseInt(c.get("len").asString()); if (msg.length * 8 == len) { - Asserts.assertEqualsByteArray(md.digest(msg), - toByteArray(c.get("md").asString())); + Asserts.assertEqualsByteArray( + toByteArray(c.get("md").asString()), md.digest(msg)); } else { System.out.print("bits "); } @@ -70,8 +70,8 @@ public static void run(JSONValue kat, Provider provider) throws Exception { } MD = md.digest(MD); } - Asserts.assertEqualsByteArray(MD, - toByteArray(r.get("md").asString())); + Asserts.assertEqualsByteArray( + toByteArray(r.get("md").asString()), MD); SEED = MD; } else { var A = SEED; @@ -88,8 +88,8 @@ public static void run(JSONValue kat, Provider provider) throws Exception { B = C; C = MD; } - Asserts.assertEqualsByteArray(MD, - toByteArray(r.get("md").asString())); + Asserts.assertEqualsByteArray( + toByteArray(r.get("md").asString()), MD); SEED = MD; } } @@ -110,8 +110,8 @@ public static void run(JSONValue kat, Provider provider) throws Exception { md.update(ct); cc += clen; } - Asserts.assertEqualsByteArray(md.digest(), - toByteArray(c.get("md").asString())); + Asserts.assertEqualsByteArray( + toByteArray(c.get("md").asString()), md.digest()); } } default -> throw new UnsupportedOperationException( diff --git a/test/lib-test/jdk/test/lib/AssertsTest.java b/test/lib-test/jdk/test/lib/AssertsTest.java index 9acb6be98c5..62db122e672 100644 --- a/test/lib-test/jdk/test/lib/AssertsTest.java +++ b/test/lib-test/jdk/test/lib/AssertsTest.java @@ -25,12 +25,12 @@ import java.lang.SuppressWarnings; import java.util.Arrays; -import java.util.HexFormat; import static jdk.test.lib.Asserts.*; /* * @test + * @bug 8340493 * @library /test/lib * @summary Tests the different assertions in the Assert class */ @@ -49,6 +49,29 @@ public String toString() { } } + // equals() always returns true + public static class Bar { + private final int i; + public Bar(int i) { + this.i = i; + } + + @Override + public int hashCode() { + return 0; + } + + @Override + public boolean equals(Object obj) { + return true; + } + + @Override + public String toString() { + return Integer.toString(i); + } + } + public static void main(String[] args) throws Exception { testLessThan(); testLessThanOrEqual(); @@ -62,6 +85,19 @@ public static void main(String[] args) throws Exception { testTrue(); testFalse(); testFail(); + + testErrorMessages(); + } + + public static void testErrorMessages() throws Exception { + try { + Asserts.assertNotEquals(new Bar(1), new Bar(2)); + throw new Exception("Should fail"); + } catch (RuntimeException e) { + if (!e.getMessage().contains("was 2")) { + throw new Exception("msg is " + e.getMessage()); + } + } } private static void testLessThan() throws Exception { @@ -216,8 +252,7 @@ private static > void expectFail(Assertion assertion, T " to throw a RuntimeException"); } - private static void expectPass(Assertion assertion, byte[] b1, byte[] b2) - throws Exception { + private static void expectPass(Assertion assertion, byte[] b1, byte[] b2) { if (assertion == Assertion.EQBA) { String msg = "Expected " + Assertion.asString("assertEqualsByteArray", Arrays.toString(b1), Arrays.toString(b2)) + " to pass"; diff --git a/test/lib-test/jdk/test/lib/security/FixedSecureRandomTest.java b/test/lib-test/jdk/test/lib/security/FixedSecureRandomTest.java index bdebc9e0a8c..cfe86bac49f 100644 --- a/test/lib-test/jdk/test/lib/security/FixedSecureRandomTest.java +++ b/test/lib-test/jdk/test/lib/security/FixedSecureRandomTest.java @@ -35,13 +35,13 @@ public static void main(String[] args) throws Exception { new byte[] {4, 5, 6}); var b1 = new byte[2]; fsr.nextBytes(b1); - Asserts.assertEqualsByteArray(b1, new byte[] {1, 2}); + Asserts.assertEqualsByteArray(new byte[] {1, 2}, b1); Asserts.assertTrue(fsr.hasRemaining()); fsr.nextBytes(b1); - Asserts.assertEqualsByteArray(b1, new byte[] {3, 4}); + Asserts.assertEqualsByteArray(new byte[] {3, 4}, b1); Asserts.assertTrue(fsr.hasRemaining()); fsr.nextBytes(b1); - Asserts.assertEqualsByteArray(b1, new byte[] {5, 6}); + Asserts.assertEqualsByteArray(new byte[] {5, 6}, b1); Asserts.assertFalse(fsr.hasRemaining()); Utils.runAndCheckException(() -> fsr.nextBytes(b1), IllegalStateException.class); diff --git a/test/lib/jdk/test/lib/Asserts.java b/test/lib/jdk/test/lib/Asserts.java index 893f1a1a737..1f23a64f811 100644 --- a/test/lib/jdk/test/lib/Asserts.java +++ b/test/lib/jdk/test/lib/Asserts.java @@ -234,59 +234,58 @@ public static void assertSame(Object lhs, Object rhs, String msg) { } /** - * Asserts that {@code lhs} is the same byte array as {@code rhs}. + * Asserts that {@code actual} has the same content as {@code expected}. * - * @param lhs The left hand side of the comparison. - * @param rhs The right hand side of the comparison. + * @param expected The expected value + * @param actual The actual value * @throws RuntimeException if the assertion is not true. * @see #assertEqualsByteArray(byte[], byte[], String) */ - public static void assertEqualsByteArray(byte[] lhs, byte[] rhs) { - assertEqualsByteArray(lhs, rhs, null); + public static void assertEqualsByteArray(byte[] expected, byte[] actual) { + assertEqualsByteArray(expected, actual, null); } /** - * Asserts that {@code lhs} is not the same byte array as {@code rhs}. + * Asserts that {@code actual} does not have the same content as {@code unexpected}. * - * @param lhs The left hand side of the comparison. - * @param rhs The right hand side of the comparison. + * @param unexpected The unexpected value + * @param actual The actual value * @throws RuntimeException if the assertion is not true. * @see #assertNotEqualsByteArray(byte[], byte[], String) */ - public static void assertNotEqualsByteArray(byte[] lhs, byte[] rhs) { - assertNotEqualsByteArray(lhs, rhs, null); + public static void assertNotEqualsByteArray(byte[] unexpected, byte[] actual) { + assertNotEqualsByteArray(unexpected, actual, null); } /** - * Asserts that {@code lhs} is the same byte array as {@code rhs}. + * Asserts that {@code actual} is the same byte array as {@code expected}. * - * @param lhs The left hand side of the comparison. - * @param rhs The right hand side of the comparison. + * @param expected The expected value + * @param actual The actual value * @param msg A description of the assumption; {@code null} for a default message. * @throws RuntimeException if the assertion is not true. */ - public static void assertEqualsByteArray(byte[] lhs, byte[] rhs, String msg) { - if (!Arrays.equals(lhs, rhs)) { + public static void assertEqualsByteArray(byte[] expected, byte[] actual, String msg) { + if (!Arrays.equals(expected, actual)) { msg = Objects.toString(msg, "assertEqualsByteArray") - + ": expected " + HexFormat.of().formatHex(lhs) - + " to equal " + HexFormat.of().formatHex(rhs); + + ": expected " + HexFormat.of().formatHex(expected) + + " but was " + HexFormat.of().formatHex(actual); fail(msg); } } /** - * Asserts that {@code lhs} is not the same byte array as {@code rhs}. + * Asserts that {@code actual} is not the same byte array as {@code unexpected}. * - * @param lhs The left hand side of the comparison. - * @param rhs The right hand side of the comparison. + * @param unexpected The unexpected value + * @param actual The actual value * @param msg A description of the assumption; {@code null} for a default message. * @throws RuntimeException if the assertion is not true. */ - public static void assertNotEqualsByteArray(byte[] lhs, byte[] rhs, String msg) { - if (Arrays.equals(lhs, rhs)) { + public static void assertNotEqualsByteArray(byte[] unexpected, byte[] actual, String msg) { + if (Arrays.equals(unexpected, actual)) { msg = Objects.toString(msg, "assertNotEqualsByteArray") - + ": expected " + HexFormat.of().formatHex(lhs) - + " to not equal " + HexFormat.of().formatHex(rhs); + + ": expected not equals but was " + HexFormat.of().formatHex(actual); fail(msg); } } @@ -404,50 +403,49 @@ public static > void assertGreaterThan(T lhs, T rhs, Str /** * Shorthand for {@link #assertNotEquals(Object, Object)}. * - * @param lhs The left hand side of the comparison. - * @param rhs The right hand side of the comparison. + * @param unexpected The unexpected value + * @param actual The actual value * @see #assertNotEquals(Object, Object) */ - public static void assertNE(Object lhs, Object rhs) { - assertNotEquals(lhs, rhs); + public static void assertNE(Object unexpected, Object actual) { + assertNotEquals(unexpected, actual); } /** * Shorthand for {@link #assertNotEquals(Object, Object, String)}. * - * @param lhs The left hand side of the comparison. - * @param rhs The right hand side of the comparison. + * @param unexpected The unexpected value + * @param actual The actual value * @param msg A description of the assumption; {@code null} for a default message. * @see #assertNotEquals(Object, Object, String) */ - public static void assertNE(Object lhs, Object rhs, String msg) { - assertNotEquals(lhs, rhs, msg); + public static void assertNE(Object unexpected, Object actual, String msg) { + assertNotEquals(unexpected, actual, msg); } /** * Calls {@link #assertNotEquals(Object, Object, String)} with a default message. * - * @param lhs The left hand side of the comparison. - * @param rhs The right hand side of the comparison. + * @param unexpected The unexpected value + * @param actual The actual value * @see #assertNotEquals(Object, Object, String) */ - public static void assertNotEquals(Object lhs, Object rhs) { - assertNotEquals(lhs, rhs, null); + public static void assertNotEquals(Object unexpected, Object actual) { + assertNotEquals(unexpected, actual, null); } /** - * Asserts that {@code lhs} is not equal to {@code rhs}. + * Asserts that {@code actual} is not equal to {@code unexpected}. * - * @param lhs The left hand side of the comparison. - * @param rhs The right hand side of the comparison. + * @param unexpected The unexpected value + * @param actual The actual value * @param msg A description of the assumption; {@code null} for a default message. * @throws RuntimeException if the assertion is not true. */ - public static void assertNotEquals(Object lhs, Object rhs, String msg) { - if ((lhs == rhs) || (lhs != null && lhs.equals(rhs))) { + public static void assertNotEquals(Object unexpected, Object actual, String msg) { + if ((unexpected == actual) || (unexpected != null && unexpected.equals(actual))) { msg = Objects.toString(msg, "assertNotEquals") - + ": expected " + Objects.toString(lhs) - + " to not equal " + Objects.toString(rhs); + + ": expected not equals but was " + Objects.toString(actual); fail(msg); } } From 35fafbc5974e81c26ac4fd16bc1f423f803470d0 Mon Sep 17 00:00:00 2001 From: Emanuel Peter Date: Fri, 20 Dec 2024 06:52:22 +0000 Subject: [PATCH 07/36] 8346106: Verify.checkEQ: testing utility for recursive value verification Reviewed-by: kvn, tweidmann --- .../jtreg/compiler/lib/verify/Verify.java | 309 +++++++++++++ .../compiler/lib/verify/VerifyException.java | 39 ++ .../examples/TestVerifyInCheckMethod.java | 76 ++++ .../verify/tests/TestVerify.java | 419 ++++++++++++++++++ 4 files changed, 843 insertions(+) create mode 100644 test/hotspot/jtreg/compiler/lib/verify/Verify.java create mode 100644 test/hotspot/jtreg/compiler/lib/verify/VerifyException.java create mode 100644 test/hotspot/jtreg/testlibrary_tests/verify/examples/TestVerifyInCheckMethod.java create mode 100644 test/hotspot/jtreg/testlibrary_tests/verify/tests/TestVerify.java diff --git a/test/hotspot/jtreg/compiler/lib/verify/Verify.java b/test/hotspot/jtreg/compiler/lib/verify/Verify.java new file mode 100644 index 00000000000..085ec591b0c --- /dev/null +++ b/test/hotspot/jtreg/compiler/lib/verify/Verify.java @@ -0,0 +1,309 @@ +/* + * 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 compiler.lib.verify; + +import java.util.Optional; +import java.lang.foreign.*; + +/** + * The {@link Verify} class provides a single {@link Verify#checkEQ} static method, which recursively + * compares the two {@link Object}s by value. It deconstructs {@link Object[]}, compares boxed primitive + * types, and compares the content of arrays and {@link MemorySegment}s. + * + * When a comparison fail, then methods print helpful messages, before throwing a {@link VerifyException}. + */ +public final class Verify { + + private Verify() {} + + /** + * Verify the content of two Objects, possibly recursively. Only limited types are implemented. + * + * @param a First object to be recursively compared with the second. + * @param b Second object to be recursively compared with the first. + * @throws VerifyException If the comparison fails. + */ + public static void checkEQ(Object a, Object b) { + checkEQ(a, b, ""); + } + + /** + * Verify the content of two Objects, possibly recursively. Only limited types are implemented. + */ + private static void checkEQ(Object a, Object b, String context) { + // Both null + if (a == null && b == null) { + return; + } + + // Null mismatch + if (a == null || b == null) { + System.err.println("ERROR: Verify.checkEQ failed: null mismatch"); + print(a, "a " + context); + print(b, "b " + context); + throw new VerifyException("Object array null mismatch."); + } + + // Class mismatch + Class ca = a.getClass(); + Class cb = b.getClass(); + if (ca != cb) { + System.err.println("ERROR: Verify.checkEQ failed: class mismatch."); + System.err.println(" " + ca.getName() + " vs " + cb.getName()); + print(a, "a " + context); + print(b, "b " + context); + throw new VerifyException("Object class mismatch."); + } + + switch (a) { + case Object[] x -> checkEQimpl(x, (Object[])b, context); + case Byte x -> checkEQimpl(x, ((Byte)b).byteValue(), context); + case Character x -> checkEQimpl(x, ((Character)b).charValue(), context); + case Short x -> checkEQimpl(x, ((Short)b).shortValue(), context); + case Integer x -> checkEQimpl(x, ((Integer)b).intValue(), context); + case Long x -> checkEQimpl(x, ((Long)b).longValue(), context); + case Float x -> checkEQimpl(x, ((Float)b).floatValue(), context); + case Double x -> checkEQimpl(x, ((Double)b).doubleValue(), context); + case byte[] x -> checkEQimpl(x, (byte[])b, context); + case char[] x -> checkEQimpl(x, (char[])b, context); + case short[] x -> checkEQimpl(x, (short[])b, context); + case int[] x -> checkEQimpl(x, (int[])b, context); + case long[] x -> checkEQimpl(x, (long[])b, context); + case float[] x -> checkEQimpl(x, (float[])b, context); + case double[] x -> checkEQimpl(x, (double[])b, context); + case MemorySegment x -> checkEQimpl(x, (MemorySegment) b, context); + default -> { + System.err.println("ERROR: Verify.checkEQ failed: type not supported: " + ca.getName()); + print(a, "a " + context); + print(b, "b " + context); + throw new VerifyException("Object array type not supported: " + ca.getName()); + } + } + } + + /** + * Verify that two bytes are identical. + */ + private static void checkEQimpl(byte a, byte b, String context) { + if (a != b) { + System.err.println("ERROR: Verify.checkEQ failed: value mismatch: " + a + " vs " + b + " for " + context); + throw new VerifyException("Value mismatch: " + a + " vs " + b); + } + } + + /** + * Verify that two chars are identical. + */ + private static void checkEQimpl(char a, char b, String context) { + if (a != b) { + System.err.println("ERROR: Verify.checkEQ failed: value mismatch: " + (int)a + " vs " + (int)b + " for " + context); + throw new VerifyException("Value mismatch: " + (int)a + " vs " + (int)b); + } + } + + /** + * Verify that two shorts are identical. + */ + private static void checkEQimpl(short a, short b, String context) { + if (a != b) { + System.err.println("ERROR: Verify.checkEQ failed: value mismatch: " + (int)a + " vs " + (int)b + " for " + context); + throw new VerifyException("Value mismatch: " + (int)a + " vs " + (int)b); + } + } + + /** + * Verify that two ints are identical. + */ + private static void checkEQimpl(int a, int b, String context) { + if (a != b) { + System.err.println("ERROR: Verify.checkEQ failed: value mismatch: " + a + " vs " + b + " for " + context); + throw new VerifyException("Value mismatch: " + a + " vs " + b); + } + } + + /** + * Verify that two longs are identical. + */ + private static void checkEQimpl(long a, long b, String context) { + if (a != b) { + System.err.println("ERROR: Verify.checkEQ failed: value mismatch: " + a + " vs " + b + " for " + context); + throw new VerifyException("Value mismatch: " + a + " vs " + b); + } + } + + /** + * Verify that two floats have identical bits. + */ + private static void checkEQimpl(float a, float b, String context) { + if (Float.floatToRawIntBits(a) != Float.floatToRawIntBits(b)) { + System.err.println("ERROR: Verify.checkEQ failed: value mismatch for " + context); + System.err.println(" Values: " + a + " vs " + b); + System.err.println(" Values: " + Float.floatToRawIntBits(a) + " vs " + Float.floatToRawIntBits(b)); + throw new VerifyException("Value mismatch: " + a + " vs " + b); + } + } + + /** + * Verify that two doubles have identical bits. + */ + private static void checkEQimpl(double a, double b, String context) { + if (Double.doubleToRawLongBits(a) != Double.doubleToRawLongBits(b)) { + System.err.println("ERROR: Verify.checkEQ failed: value mismatch for " + context); + System.err.println(" Values: " + a + " vs " + b); + System.err.println(" Values: " + Double.doubleToRawLongBits(a) + " vs " + Double.doubleToRawLongBits(b)); + throw new VerifyException("Value mismatch: " + a + " vs " + b); + } + } + + /** + * Verify that the content of two MemorySegments is identical. Note: we do not check the + * backing type, only the size and content. + */ + private static void checkEQimpl(MemorySegment a, MemorySegment b, String context) { + long offset = a.mismatch(b); + if (offset == -1) { return; } + + // Print some general info + System.err.println("ERROR: Verify.checkEQ failed for: " + context); + + printMemorySegment(a, "a " + context); + printMemorySegment(b, "b " + context); + + // (1) Mismatch on size + if (a.byteSize() != b.byteSize()) { + throw new VerifyException("MemorySegment byteSize mismatch."); + } + + // (2) Value mismatch + System.err.println(" Value mismatch at byte offset: " + offset); + printMemorySegmentValue(a, offset, 16); + printMemorySegmentValue(b, offset, 16); + throw new VerifyException("MemorySegment value mismatch."); + } + + /** + * Verify that the content of two byte arrays is identical. + */ + private static void checkEQimpl(byte[] a, byte[] b, String context) { + checkEQimpl(MemorySegment.ofArray(a), MemorySegment.ofArray(b), context); + } + + /** + * Verify that the content of two char arrays is identical. + */ + private static void checkEQimpl(char[] a, char[] b, String context) { + checkEQimpl(MemorySegment.ofArray(a), MemorySegment.ofArray(b), context); + } + + /** + * Verify that the content of two short arrays is identical. + */ + private static void checkEQimpl(short[] a, short[] b, String context) { + checkEQimpl(MemorySegment.ofArray(a), MemorySegment.ofArray(b), context); + } + + /** + * Verify that the content of two int arrays is identical. + */ + private static void checkEQimpl(int[] a, int[] b, String context) { + checkEQimpl(MemorySegment.ofArray(a), MemorySegment.ofArray(b), context); + } + + /** + * Verify that the content of two long arrays is identical. + */ + private static void checkEQimpl(long[] a, long[] b, String context) { + checkEQimpl(MemorySegment.ofArray(a), MemorySegment.ofArray(b), context); + } + + /** + * Verify that the content of two float arrays is identical. + */ + private static void checkEQimpl(float[] a, float[] b, String context) { + checkEQimpl(MemorySegment.ofArray(a), MemorySegment.ofArray(b), context); + } + + /** + * Verify that the content of two double arrays is identical. + */ + private static void checkEQimpl(double[] a, double[] b, String context) { + checkEQimpl(MemorySegment.ofArray(a), MemorySegment.ofArray(b), context); + } + + /** + * Verify that the content of two Object arrays is identical, recursively: + * every element is compared with checkEQimpl for the corresponding type. + */ + private static void checkEQimpl(Object[] a, Object[] b, String context) { + // (1) Length mismatch + if (a.length != b.length) { + System.err.println("ERROR: Verify.checkEQ failed: length mismatch: " + a.length + " vs " + b.length); + throw new VerifyException("Object array length mismatch."); + } + + for (int i = 0; i < a.length; i++) { + // Recursive checkEQ call. + checkEQ(a[i], b[i], "[" + i + "]" + context); + } + } + + private static void print(Object a, String context) { + if (a == null) { + System.err.println(" " + context + ": null"); + } else { + System.err.println(" " + context + ": " + a); + } + } + + private static void printMemorySegment(MemorySegment a, String context) { + Optional maybeBase = a.heapBase(); + System.err.println(" " + context + " via MemorySegment:"); + if (maybeBase.isEmpty()) { + System.err.println(" no heap base (native)."); + } else { + Object base = maybeBase.get(); + System.err.println(" heap base: " + base); + } + System.err.println(" address: " + a.address()); + System.err.println(" byteSize: " + a.byteSize()); + } + + private static void printMemorySegmentValue(MemorySegment a, long offset, int range) { + long start = Long.max(offset - range, 0); + long end = Long.min(offset + range, a.byteSize()); + for (long i = start; i < end; i++) { + byte b = a.get(ValueLayout.JAVA_BYTE, i); + System.err.print(String.format("%02x ", b)); + } + System.err.println(""); + for (long i = start; i < end; i++) { + if (i == offset) { + System.err.print("^^ "); + } else { + System.err.print(" "); + } + } + System.err.println(""); + } +} diff --git a/test/hotspot/jtreg/compiler/lib/verify/VerifyException.java b/test/hotspot/jtreg/compiler/lib/verify/VerifyException.java new file mode 100644 index 00000000000..e54a0cbef95 --- /dev/null +++ b/test/hotspot/jtreg/compiler/lib/verify/VerifyException.java @@ -0,0 +1,39 @@ +/* + * 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 compiler.lib.verify; + +/** + * Exception thrown in verification. + */ +public class VerifyException extends RuntimeException { + + /** + * Creates a new verification exception. + * + * @param message Exception message for context when debugging. + */ + public VerifyException(String message) { + super("Value verification failed:" + System.lineSeparator() + message); + } +} diff --git a/test/hotspot/jtreg/testlibrary_tests/verify/examples/TestVerifyInCheckMethod.java b/test/hotspot/jtreg/testlibrary_tests/verify/examples/TestVerifyInCheckMethod.java new file mode 100644 index 00000000000..c8b4d470d99 --- /dev/null +++ b/test/hotspot/jtreg/testlibrary_tests/verify/examples/TestVerifyInCheckMethod.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Example test to show Verify.checkEQ with IR framework. + * @modules java.base/jdk.internal.misc + * @library /test/lib / + * @run driver verify.examples.TestVerifyInCheckMethod + */ + +package verify.examples; + +import compiler.lib.verify.*; +import compiler.lib.ir_framework.*; + +/** + * Example to show the use of Verify.checkEQ in @Check method. + */ +public class TestVerifyInCheckMethod { + public static int[] INPUT_A = new int[100]; + static { + for (int i = 0; i < INPUT_A.length; i++) { + INPUT_A[i] = i; + } + } + public static float INPUT_B = 42; + + // Must make sure to clone input arrays, if it is mutated in the test. + public static Object GOLD = test(INPUT_A.clone(), INPUT_B);; + + public static void main(String[] args) { + TestFramework.run(); + } + + @Setup + public static Object[] setup() { + // Must make sure to clone input arrays, if it is mutated in the test. + return new Object[] {INPUT_A.clone(), INPUT_B}; + } + + @Test + @Arguments(setup = "setup") + public static Object test(int[] a, float b) { + for (int i = 0; i < a.length; i++) { + a[i] = (int)(a[i] * b); + } + // Since we have more than one value, we wrap them in an Object[]. + return new Object[] {a, b}; + } + + @Check(test = "test") + public static void check(Object result) { + Verify.checkEQ(result, GOLD); + } +} diff --git a/test/hotspot/jtreg/testlibrary_tests/verify/tests/TestVerify.java b/test/hotspot/jtreg/testlibrary_tests/verify/tests/TestVerify.java new file mode 100644 index 00000000000..bdfeeb149eb --- /dev/null +++ b/test/hotspot/jtreg/testlibrary_tests/verify/tests/TestVerify.java @@ -0,0 +1,419 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Test functionality of IntGenerator implementations. + * @modules java.base/jdk.internal.misc + * @library /test/lib / + * @run driver verify.tests.TestVerify + */ + +package verify.tests; + +import java.lang.foreign.*; +import java.util.Random; +import jdk.test.lib.Utils; + +import compiler.lib.verify.*; + +public class TestVerify { + private static final Random RANDOM = Utils.getRandomInstance(); + + public static void main(String[] args) { + // Test consecutive memory: array, MemorySegment, etc. + testArrayByte(); + testArrayChar(); + testArrayShort(); + testArrayInt(); + testArrayLong(); + testArrayFloat(); + testArrayDouble(); + testNativeMemorySegment(); + + // Test recursive data: Object array of values, etc. + testRecursive(); + } + + public static void testArrayByte() { + byte[] a = new byte[1000]; + byte[] b = new byte[1001]; + byte[] c = new byte[1000]; + + Verify.checkEQ(a, a); + Verify.checkEQ(b, b); + Verify.checkEQ(a, c); + Verify.checkEQ(c, a); + + Verify.checkEQ(MemorySegment.ofArray(a), MemorySegment.ofArray(a)); + Verify.checkEQ(MemorySegment.ofArray(b), MemorySegment.ofArray(b)); + Verify.checkEQ(MemorySegment.ofArray(a), MemorySegment.ofArray(c)); + Verify.checkEQ(MemorySegment.ofArray(c), MemorySegment.ofArray(a)); + + // Size mismatch + checkNE(a, b); + + // Size mismatch + checkNE(MemorySegment.ofArray(a), MemorySegment.ofArray(b)); + + c[RANDOM.nextInt(c.length)] = 1; + + // Value mismatch + checkNE(a, c); + + // Value mismatch + checkNE(MemorySegment.ofArray(a), MemorySegment.ofArray(c)); + } + + + public static void testArrayShort() { + short[] a = new short[1000]; + short[] b = new short[1001]; + short[] c = new short[1000]; + + Verify.checkEQ(a, a); + Verify.checkEQ(b, b); + Verify.checkEQ(a, c); + Verify.checkEQ(c, a); + + Verify.checkEQ(MemorySegment.ofArray(a), MemorySegment.ofArray(a)); + Verify.checkEQ(MemorySegment.ofArray(b), MemorySegment.ofArray(b)); + Verify.checkEQ(MemorySegment.ofArray(a), MemorySegment.ofArray(c)); + Verify.checkEQ(MemorySegment.ofArray(c), MemorySegment.ofArray(a)); + + // Size mismatch + checkNE(a, b); + + // Size mismatch + checkNE(MemorySegment.ofArray(a), MemorySegment.ofArray(b)); + + c[RANDOM.nextInt(c.length)] = 1; + + // Value mismatch + checkNE(a, c); + + // Value mismatch + checkNE(MemorySegment.ofArray(a), MemorySegment.ofArray(c)); + } + + + public static void testArrayChar() { + char[] a = new char[1000]; + char[] b = new char[1001]; + char[] c = new char[1000]; + + Verify.checkEQ(a, a); + Verify.checkEQ(b, b); + Verify.checkEQ(a, c); + Verify.checkEQ(c, a); + + Verify.checkEQ(MemorySegment.ofArray(a), MemorySegment.ofArray(a)); + Verify.checkEQ(MemorySegment.ofArray(b), MemorySegment.ofArray(b)); + Verify.checkEQ(MemorySegment.ofArray(a), MemorySegment.ofArray(c)); + Verify.checkEQ(MemorySegment.ofArray(c), MemorySegment.ofArray(a)); + + // Size mismatch + checkNE(a, b); + + // Size mismatch + checkNE(MemorySegment.ofArray(a), MemorySegment.ofArray(b)); + + c[RANDOM.nextInt(c.length)] = 1; + + // Value mismatch + checkNE(a, c); + + // Value mismatch + checkNE(MemorySegment.ofArray(a), MemorySegment.ofArray(c)); + } + + + public static void testArrayInt() { + int[] a = new int[1000]; + int[] b = new int[1001]; + int[] c = new int[1000]; + + Verify.checkEQ(a, a); + Verify.checkEQ(b, b); + Verify.checkEQ(a, c); + Verify.checkEQ(c, a); + + Verify.checkEQ(MemorySegment.ofArray(a), MemorySegment.ofArray(a)); + Verify.checkEQ(MemorySegment.ofArray(b), MemorySegment.ofArray(b)); + Verify.checkEQ(MemorySegment.ofArray(a), MemorySegment.ofArray(c)); + Verify.checkEQ(MemorySegment.ofArray(c), MemorySegment.ofArray(a)); + + // Size mismatch + checkNE(a, b); + + // Size mismatch + checkNE(MemorySegment.ofArray(a), MemorySegment.ofArray(b)); + + c[RANDOM.nextInt(c.length)] = 1; + + // Value mismatch + checkNE(a, c); + + // Value mismatch + checkNE(MemorySegment.ofArray(a), MemorySegment.ofArray(c)); + } + + + public static void testArrayLong() { + long[] a = new long[1000]; + long[] b = new long[1001]; + long[] c = new long[1000]; + + Verify.checkEQ(a, a); + Verify.checkEQ(b, b); + Verify.checkEQ(a, c); + Verify.checkEQ(c, a); + + Verify.checkEQ(MemorySegment.ofArray(a), MemorySegment.ofArray(a)); + Verify.checkEQ(MemorySegment.ofArray(b), MemorySegment.ofArray(b)); + Verify.checkEQ(MemorySegment.ofArray(a), MemorySegment.ofArray(c)); + Verify.checkEQ(MemorySegment.ofArray(c), MemorySegment.ofArray(a)); + + // Size mismatch + checkNE(a, b); + + // Size mismatch + checkNE(MemorySegment.ofArray(a), MemorySegment.ofArray(b)); + + c[RANDOM.nextInt(c.length)] = 1; + + // Value mismatch + checkNE(a, c); + + // Value mismatch + checkNE(MemorySegment.ofArray(a), MemorySegment.ofArray(c)); + } + + + public static void testArrayFloat() { + float[] a = new float[1000]; + float[] b = new float[1001]; + float[] c = new float[1000]; + + Verify.checkEQ(a, a); + Verify.checkEQ(b, b); + Verify.checkEQ(a, c); + Verify.checkEQ(c, a); + + Verify.checkEQ(MemorySegment.ofArray(a), MemorySegment.ofArray(a)); + Verify.checkEQ(MemorySegment.ofArray(b), MemorySegment.ofArray(b)); + Verify.checkEQ(MemorySegment.ofArray(a), MemorySegment.ofArray(c)); + Verify.checkEQ(MemorySegment.ofArray(c), MemorySegment.ofArray(a)); + + // Size mismatch + checkNE(a, b); + + // Size mismatch + checkNE(MemorySegment.ofArray(a), MemorySegment.ofArray(b)); + + c[RANDOM.nextInt(c.length)] = 1; + + // Value mismatch + checkNE(a, c); + + // Value mismatch + checkNE(MemorySegment.ofArray(a), MemorySegment.ofArray(c)); + } + + + public static void testArrayDouble() { + double[] a = new double[1000]; + double[] b = new double[1001]; + double[] c = new double[1000]; + + Verify.checkEQ(a, a); + Verify.checkEQ(b, b); + Verify.checkEQ(a, c); + Verify.checkEQ(c, a); + + Verify.checkEQ(MemorySegment.ofArray(a), MemorySegment.ofArray(a)); + Verify.checkEQ(MemorySegment.ofArray(b), MemorySegment.ofArray(b)); + Verify.checkEQ(MemorySegment.ofArray(a), MemorySegment.ofArray(c)); + Verify.checkEQ(MemorySegment.ofArray(c), MemorySegment.ofArray(a)); + + // Size mismatch + checkNE(a, b); + + // Size mismatch + checkNE(MemorySegment.ofArray(a), MemorySegment.ofArray(b)); + + c[RANDOM.nextInt(c.length)] = 1; + + // Value mismatch + checkNE(a, c); + + // Value mismatch + checkNE(MemorySegment.ofArray(a), MemorySegment.ofArray(c)); + } + + public static void testNativeMemorySegment() { + MemorySegment a = Arena.ofAuto().allocate(1000, 1); + MemorySegment b = Arena.ofAuto().allocate(1001, 1); + MemorySegment c = Arena.ofAuto().allocate(1000, 1); + + Verify.checkEQ(a, a); + Verify.checkEQ(b, b); + Verify.checkEQ(a, c); + Verify.checkEQ(c, a); + + // Size mismatch + checkNE(a, b); + + c.set(ValueLayout.JAVA_BYTE, RANDOM.nextLong(c.byteSize()), (byte)1); + + // Value mismatch + checkNE(a, c); + } + + public static void testRecursive() { + Verify.checkEQ(null, null); + + // Null mismatch + checkNE(42, null); + + byte[] a = new byte[1000]; + int[] b = new int[1000]; + int[] c = new int[1001]; + int[] d = new int[1000]; + + Object[] o1 = new Object[]{a, a}; + Object[] o2 = new Object[]{a, a, a}; + Object[] o3 = new Object[]{a, a, null}; + Object[] o4 = new Object[]{a, a, b}; + Object[] o5 = new Object[]{a, a, c}; + Object[] o6 = new Object[]{a, a, d}; + + Verify.checkEQ(o1, o1); + Verify.checkEQ(o2, o2); + Verify.checkEQ(o3, o3); + Verify.checkEQ(o4, o6); + + // Size mismatch + checkNE(o1, o2); + + // First level value mismatch: a vs null on position 2 + checkNE(o2, o3); + + // First level class mismatch: byte[] vs int[] + checkNE(o2, o4); + + // Second level length mismatch on arrays b and c. + checkNE(o4, o5); + + d[RANDOM.nextInt(d.length)] = 1; + + // Second level value mismatch between b and d. + checkNE(o4, o6); + + // Now test all primitive array types. + byte[] aB = new byte[100]; + char[] aC = new char[100]; + short[] aS = new short[100]; + int[] aI = new int[100]; + long[] aL = new long[100]; + float[] aF = new float[100]; + double[] aD = new double[100]; + + Verify.checkEQ(new Object[] {aB, aC, aS, aI, aL, aF, aD}, new Object[] {aB, aC, aS, aI, aL, aF, aD}); + + // First level class mismatch: char[] vs short[] + checkNE(new Object[] {aC}, new Object[] {aS}); + + // Verify MemorySegment + MemorySegment mC = MemorySegment.ofArray(aC); + MemorySegment mS = MemorySegment.ofArray(aS); + Verify.checkEQ(new Object[] {mC}, new Object[] {mC}); + Verify.checkEQ(new Object[] {mS}, new Object[] {mS}); + + // Second level type mismatch: backing type short[] vs char[] + checkNE(new Object[] {mC}, new Object[] {mS}); + + // Second level type mismatch: backing type int[] vs char[] + MemorySegment mI = MemorySegment.ofArray(aI); + checkNE(new Object[] {mI}, new Object[] {mC}); + + // Verify boxed primitives: + Byte bb1 = 42; + Byte bb2 = 42; + Byte bb3 = 11; + + Verify.checkEQ(new Object[] {(byte)42}, new Object[] {(byte)42}); + Verify.checkEQ(new Object[] {(byte)42}, new Object[] {bb1}); + Verify.checkEQ(new Object[] {bb1}, new Object[] {bb2}); + + // Second level value mismatch: 42 vs 11 + checkNE(new Object[] {bb1}, new Object[] {bb3}); + + Verify.checkEQ((byte)42, (byte)42); + Verify.checkEQ((short)42, (short)42); + Verify.checkEQ((char)42, (char)42); + Verify.checkEQ((int)42, (int)42); + Verify.checkEQ((long)42, (long)42); + Verify.checkEQ((float)42, (float)42); + Verify.checkEQ((double)42, (double)42); + + // Boxed type mismatch: float vs int + checkNE((int)42, (float)42); + + // Boxed value mismatch. + for (int i = 0; i < 10; i++) { + byte v1 = (byte)RANDOM.nextInt(); + byte v2 = (byte)(v1 ^ (1 << RANDOM.nextInt(8))); + checkNE(v1, v2); + } + for (int i = 0; i < 10; i++) { + char v1 = (char)RANDOM.nextInt(); + char v2 = (char)(v1 ^ (1 << RANDOM.nextInt(16))); + checkNE(v1, v2); + } + for (int i = 0; i < 10; i++) { + char v1 = (char)RANDOM.nextInt(); + char v2 = (char)(v1 ^ (1 << RANDOM.nextInt(16))); + checkNE(v1, v2); + } + for (int i = 0; i < 10; i++) { + int v1 = (int)RANDOM.nextInt(); + int v2 = (int)(v1 ^ (1 << RANDOM.nextInt(32))); + checkNE(v1, v2); + checkNE(Float.intBitsToFloat(v1), Float.intBitsToFloat(v2)); + } + for (int i = 0; i < 10; i++) { + long v1 = (long)RANDOM.nextLong(); + long v2 = (long)(v1 ^ (1L << RANDOM.nextInt(64))); + checkNE(v1, v2); + checkNE(Double.longBitsToDouble(v1), Double.longBitsToDouble(v2)); + } + } + + public static void checkNE(Object a, Object b) { + try { + Verify.checkEQ(a, b); + throw new RuntimeException("Should have thrown"); + } catch (VerifyException e) {} + } +} From 54f34750edb284f4a49fb86c3939491211eb98fe Mon Sep 17 00:00:00 2001 From: liyazzi Date: Fri, 20 Dec 2024 07:05:42 +0000 Subject: [PATCH 08/36] 8331467: FileSystems.getDefault fails with ClassNotFoundException if custom default provider is in run-time image Reviewed-by: alanb, jpai --- .../internal/jimage/ImageReaderFactory.java | 24 +++++++++++++++---- .../java/nio/file/spi/SetDefaultProvider.java | 4 +--- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/src/java.base/share/classes/jdk/internal/jimage/ImageReaderFactory.java b/src/java.base/share/classes/jdk/internal/jimage/ImageReaderFactory.java index 24ac9bfc18a..2ecec20d6f9 100644 --- a/src/java.base/share/classes/jdk/internal/jimage/ImageReaderFactory.java +++ b/src/java.base/share/classes/jdk/internal/jimage/ImageReaderFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,8 +27,9 @@ import java.io.IOException; import java.io.UncheckedIOException; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.concurrent.ConcurrentHashMap; import java.util.Map; import java.util.Objects; @@ -47,8 +48,23 @@ public class ImageReaderFactory { private ImageReaderFactory() {} private static final String JAVA_HOME = System.getProperty("java.home"); - private static final Path BOOT_MODULES_JIMAGE = - Paths.get(JAVA_HOME, "lib", "modules"); + private static final Path BOOT_MODULES_JIMAGE; + + static { + FileSystem fs; + if (ImageReaderFactory.class.getClassLoader() == null) { + try { + fs = (FileSystem) Class.forName("sun.nio.fs.DefaultFileSystemProvider") + .getMethod("theFileSystem") + .invoke(null); + } catch (Exception e) { + throw new ExceptionInInitializerError(e); + } + } else { + fs = FileSystems.getDefault(); + } + BOOT_MODULES_JIMAGE = fs.getPath(JAVA_HOME, "lib", "modules"); + } private static final Map readers = new ConcurrentHashMap<>(); diff --git a/test/jdk/java/nio/file/spi/SetDefaultProvider.java b/test/jdk/java/nio/file/spi/SetDefaultProvider.java index a8581dc0e7a..ea154b5952e 100644 --- a/test/jdk/java/nio/file/spi/SetDefaultProvider.java +++ b/test/jdk/java/nio/file/spi/SetDefaultProvider.java @@ -23,7 +23,7 @@ /* * @test - * @bug 4313887 7006126 8142968 8178380 8183320 8210112 8266345 8263940 + * @bug 4313887 7006126 8142968 8178380 8183320 8210112 8266345 8263940 8331467 * @modules jdk.jartool jdk.jlink * @library /test/lib * @build testfsp/* testapp/* @@ -45,7 +45,6 @@ import jdk.test.lib.process.ProcessTools; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.BeforeAll; import static org.junit.jupiter.api.Assertions.*; @@ -124,7 +123,6 @@ void testFspOnModulePath2() throws Exception { /** * Test file system provider linked into run-time image. */ - @Disabled @Test void testFspInRuntimeImage() throws Exception { String image = "image"; From 85e024d92dde5ef9c375a27af57c7df177369557 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Fri, 20 Dec 2024 07:45:40 +0000 Subject: [PATCH 09/36] 8346605: AIX fastdebug build fails in memoryReserver.cpp after JDK-8345655 Reviewed-by: stefank, lucy, mdoerr --- src/hotspot/share/memory/memoryReserver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/memory/memoryReserver.cpp b/src/hotspot/share/memory/memoryReserver.cpp index b8774c30ab0..d68736c7f2a 100644 --- a/src/hotspot/share/memory/memoryReserver.cpp +++ b/src/hotspot/share/memory/memoryReserver.cpp @@ -30,7 +30,7 @@ #include "oops/markWord.hpp" #include "runtime/globals_extension.hpp" #include "runtime/java.hpp" -#include "runtime/os.hpp" +#include "runtime/os.inline.hpp" #include "utilities/formatBuffer.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/powerOfTwo.hpp" From cf28fd4cbc6507eb69fcfeb33622316eb5b6b0c5 Mon Sep 17 00:00:00 2001 From: Evgeny Nikitin Date: Fri, 20 Dec 2024 08:24:18 +0000 Subject: [PATCH 10/36] 8322983: Virtual Threads: exclude 2 tests Reviewed-by: jpai, lmesnik, syan --- test/hotspot/jtreg/ProblemList-Virtual.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/hotspot/jtreg/ProblemList-Virtual.txt b/test/hotspot/jtreg/ProblemList-Virtual.txt index 34aead4a16c..b5bb2c72779 100644 --- a/test/hotspot/jtreg/ProblemList-Virtual.txt +++ b/test/hotspot/jtreg/ProblemList-Virtual.txt @@ -104,7 +104,9 @@ gc/g1/TestMixedGCLiveThreshold.java#25percent 8334759 windows-x64 gc/arguments/TestNewSizeThreadIncrease.java 0000000 generic-all gc/g1/TestSkipRebuildRemsetPhase.java 0000000 generic-all +runtime/classFileParserBug/TestEmptyBootstrapMethodsAttr.java JDK-8346442 generic-all runtime/ErrorHandling/MachCodeFramesInErrorFile.java 0000000 generic-all +runtime/logging/LoaderConstraintsTest.java JDK-8346442 generic-all runtime/Thread/AsyncExceptionOnMonitorEnter.java 0000000 generic-all runtime/Thread/StopAtExit.java 0000000 generic-all runtime/handshake/HandshakeWalkStackTest.java 0000000 generic-all From 2a68f741884e73c9ed8e5222e57f5ecb088b3cf7 Mon Sep 17 00:00:00 2001 From: Nizar Benalla Date: Fri, 20 Dec 2024 10:16:04 +0000 Subject: [PATCH 11/36] 8346128: Comparison build fails due to difference in LabelTarget.html Reviewed-by: jlahoda, liach, prappo --- .../classes/java/lang/classfile/instruction/LabelTarget.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/LabelTarget.java b/src/java.base/share/classes/java/lang/classfile/instruction/LabelTarget.java index c5b49973133..94ac1839c75 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/LabelTarget.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/LabelTarget.java @@ -55,7 +55,7 @@ * {@snippet lang=java : * cob.with(lt); // @link substring="with" target="CodeBuilder#with" * // @link substring="labelBinding" target="CodeBuilder#labelBinding" : - * cob.labelBinding(lt.label()); // @link substring="label" target="#label" + * cob.labelBinding(lt.label()); // @link regex="label(?=\()" target="#label" * } * * @see Label From 054c644ea6ea38e54abc81e231977106d04bb69e Mon Sep 17 00:00:00 2001 From: Nizar Benalla Date: Fri, 20 Dec 2024 10:17:21 +0000 Subject: [PATCH 12/36] 8346667: Doccheck: warning about missing before

Reviewed-by: psandoz --- .../share/classes/jdk/incubator/vector/VectorMask.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorMask.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorMask.java index f5ce894b13f..cdf5b589be7 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorMask.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorMask.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, 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 @@ -108,8 +108,6 @@ * } * * - * @param the boxed version of {@code ETYPE}, - * the element type of a vector * *

Value-based classes and identity operations

* @@ -128,6 +126,9 @@ * {@code static final} constants, but storing them in other Java * fields or in array elements, while semantically valid, may incur * performance penalties. + * + * @param the boxed version of {@code ETYPE}, + * the element type of a vector */ @SuppressWarnings("exports") public abstract class VectorMask extends jdk.internal.vm.vector.VectorSupport.VectorMask { From bcb1bdaae772c752d54939dae3a0d95892acc228 Mon Sep 17 00:00:00 2001 From: Severin Gehwolf Date: Fri, 20 Dec 2024 12:35:35 +0000 Subject: [PATCH 13/36] 8345259: Disallow ALL-MODULE-PATH without explicit --module-path Reviewed-by: mchung --- .../jdk/tools/jlink/internal/JlinkTask.java | 49 +++-- .../tools/jlink/resources/jlink.properties | 4 +- test/jdk/tools/jlink/IntegrationTest.java | 2 +- test/jdk/tools/jlink/JLinkTest.java | 8 +- test/jdk/tools/jlink/basic/AllModulePath.java | 194 ++++++++++++------ test/jdk/tools/jlink/basic/BasicTest.java | 64 +++--- 6 files changed, 214 insertions(+), 107 deletions(-) diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java index 6717d5517d1..928b9a47934 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java @@ -277,14 +277,6 @@ int run(String[] args) { return EXIT_OK; } - if (options.modulePath.isEmpty()) { - // no --module-path specified - try to set $JAVA_HOME/jmods if that exists - Path jmods = getDefaultModulePath(); - if (jmods != null) { - options.modulePath.add(jmods); - } - } - JlinkConfiguration config = initJlinkConfig(); outputPath = config.getOutput(); if (options.suggestProviders) { @@ -377,8 +369,13 @@ public static void createImage(JlinkConfiguration config, // the token for "all modules on the module path" private static final String ALL_MODULE_PATH = "ALL-MODULE-PATH"; private JlinkConfiguration initJlinkConfig() throws BadArgs { + // Empty module path not allowed with ALL-MODULE-PATH in --add-modules + if (options.addMods.contains(ALL_MODULE_PATH) && options.modulePath.isEmpty()) { + throw taskHelper.newBadArgs("err.no.module.path"); + } ModuleFinder appModuleFinder = newModuleFinder(options.modulePath); ModuleFinder finder = appModuleFinder; + boolean isLinkFromRuntime = false; if (!appModuleFinder.find("java.base").isPresent()) { // If the application module finder doesn't contain the @@ -393,8 +390,9 @@ private JlinkConfiguration initJlinkConfig() throws BadArgs { // include the java.base module. Path defModPath = getDefaultModulePath(); if (defModPath != null) { - options.modulePath.add(defModPath); - finder = newModuleFinder(options.modulePath); + List combinedPaths = new ArrayList<>(options.modulePath); + combinedPaths.add(defModPath); + finder = newModuleFinder(combinedPaths); } // We've just added the default module path ('jmods'). If we still // don't find java.base, we must resolve JDK modules from the @@ -419,8 +417,31 @@ private JlinkConfiguration initJlinkConfig() throws BadArgs { Set roots = new HashSet<>(); for (String mod : options.addMods) { if (mod.equals(ALL_MODULE_PATH)) { - ModuleFinder mf = newLimitedFinder(finder, options.limitMods, - Set.of()); + // Using --limit-modules with ALL-MODULE-PATH is an error + if (!options.limitMods.isEmpty()) { + throw taskHelper.newBadArgs("err.limit.modules"); + } + // all observable modules in the app module path are roots + Set initialRoots = appModuleFinder.findAll() + .stream() + .map(ModuleReference::descriptor) + .map(ModuleDescriptor::name) + .collect(Collectors.toSet()); + + // Error if no module is found on the app module path + if (initialRoots.isEmpty()) { + String modPath = options.modulePath.stream() + .map(a -> a.toString()) + .collect(Collectors.joining(", ")); + throw taskHelper.newBadArgs("err.empty.module.path", modPath); + } + + // Use a module finder with limited observability, as determined + // by initialRoots, to find the observable modules from the + // application module path (--module-path option) only. We must + // not include JDK modules from the default module path or the + // run-time image. + ModuleFinder mf = limitFinder(finder, initialRoots, Set.of()); mf.findAll() .stream() .map(ModuleReference::descriptor) @@ -430,7 +451,7 @@ private JlinkConfiguration initJlinkConfig() throws BadArgs { roots.add(mod); } } - finder = newLimitedFinder(finder, options.limitMods, roots); + finder = limitFinder(finder, options.limitMods, roots); // --keep-packaged-modules doesn't make sense as we are not linking // from packaged modules to begin with. @@ -497,7 +518,7 @@ public static Path getDefaultModulePath() { * specified in {@code limitMods} plus other modules specified in the * {@code roots} set. */ - public static ModuleFinder newLimitedFinder(ModuleFinder finder, + public static ModuleFinder limitFinder(ModuleFinder finder, Set limitMods, Set roots) { // if limitMods is specified then limit the universe diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/jlink.properties b/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/jlink.properties index b5880a35561..a491b758ea0 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/jlink.properties +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/jlink.properties @@ -127,7 +127,9 @@ err.runtime.link.packaged.mods=This JDK has no packaged modules.\ err.runtime.link.modified.file={0} has been modified err.runtime.link.patched.module=jlink does not support linking from the run-time image\ \ when running on a patched runtime with --patch-module -err.empty.module.path=empty module path +err.no.module.path=--module-path option must be specified with --add-modules ALL-MODULE-PATH +err.empty.module.path=No module found in module path ''{0}'' with --add-modules ALL-MODULE-PATH +err.limit.modules=--limit-modules not allowed with --add-modules ALL-MODULE-PATH err.jlink.version.mismatch=jlink version {0}.{1} does not match target java.base version {2}.{3} err.automatic.module:automatic module cannot be used with jlink: {0} from {1} err.unknown.byte.order:unknown byte order {0} diff --git a/test/jdk/tools/jlink/IntegrationTest.java b/test/jdk/tools/jlink/IntegrationTest.java index 7f3dc223461..5a8d0bce15a 100644 --- a/test/jdk/tools/jlink/IntegrationTest.java +++ b/test/jdk/tools/jlink/IntegrationTest.java @@ -157,7 +157,7 @@ private static void test() throws Exception { boolean linkFromRuntime = false; JlinkConfiguration config = new Jlink.JlinkConfiguration(output, mods, - JlinkTask.newLimitedFinder(JlinkTask.newModuleFinder(modulePaths), limits, mods), + JlinkTask.limitFinder(JlinkTask.newModuleFinder(modulePaths), limits, mods), linkFromRuntime, false /* ignore modified runtime */, false /* generate run-time image */); diff --git a/test/jdk/tools/jlink/JLinkTest.java b/test/jdk/tools/jlink/JLinkTest.java index c0fabe06a8c..0b7de201ac9 100644 --- a/test/jdk/tools/jlink/JLinkTest.java +++ b/test/jdk/tools/jlink/JLinkTest.java @@ -27,17 +27,15 @@ import java.lang.module.ModuleDescriptor; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.spi.ToolProvider; import java.util.stream.Collectors; import java.util.stream.IntStream; import java.util.stream.Stream; -import jdk.tools.jlink.plugin.Plugin; import jdk.tools.jlink.internal.PluginRepository; +import jdk.tools.jlink.plugin.Plugin; import tests.Helper; import tests.JImageGenerator; @@ -135,11 +133,11 @@ public static void main(String[] args) throws Exception { { // No --module-path specified. --add-modules ALL-MODULE-PATH specified. - String imageDir = "bug8189777-all-module-path"; + String imageDir = "bug8345259-all-module-path"; JImageGenerator.getJLinkTask() .output(helper.createNewImageDir(imageDir)) .addMods("ALL-MODULE-PATH") - .call().assertSuccess(); + .call().assertFailure(); } { diff --git a/test/jdk/tools/jlink/basic/AllModulePath.java b/test/jdk/tools/jlink/basic/AllModulePath.java index ba6cc08bd47..a05f2d06d86 100644 --- a/test/jdk/tools/jlink/basic/AllModulePath.java +++ b/test/jdk/tools/jlink/basic/AllModulePath.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,45 +21,52 @@ * questions. */ -/* - * @test - * @summary jlink test of --add-module ALL-MODULE-PATH - * @library /test/lib - * @modules jdk.compiler - * @build jdk.test.lib.process.ProcessTools - * jdk.test.lib.process.OutputAnalyzer - * jdk.test.lib.compiler.CompilerUtils - * @run testng AllModulePath - */ +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; -import java.io.File; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.PrintWriter; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; -import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; import java.util.spi.ToolProvider; - -import jdk.test.lib.compiler.CompilerUtils; -import jdk.test.lib.process.ProcessTools; +import java.util.stream.Collectors; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; -import static org.testng.Assert.*; +import jdk.test.lib.compiler.CompilerUtils; +import jdk.test.lib.process.ProcessTools; +import jdk.tools.jlink.internal.LinkableRuntimeImage; +import tests.Helper; +import tests.Result; + +/* + * @test + * @bug 8345259 + * @summary jlink test of --add-module ALL-MODULE-PATH + * @library ../../lib /test/lib + * @modules jdk.compiler + * java.base/jdk.internal.jimage + * jdk.jlink/jdk.tools.jlink.internal + * jdk.jlink/jdk.tools.jimage + * @build jdk.test.lib.process.ProcessTools + * jdk.test.lib.process.OutputAnalyzer + * jdk.test.lib.compiler.CompilerUtils + * @run testng/othervm -Duser.language=en -Duser.country=US AllModulePath + */ public class AllModulePath { - private final Path JMODS = Paths.get(System.getProperty("test.jdk")).resolve("jmods"); - private final Path SRC = Paths.get(System.getProperty("test.src")).resolve("src"); - private final Path MODS = Paths.get("mods"); + private static final Path JMODS = Paths.get(System.getProperty("test.jdk")).resolve("jmods"); + private static final Path SRC = Paths.get(System.getProperty("test.src")).resolve("src"); + private static final Path MODS = Paths.get("mods"); + private static final boolean LINKABLE_RUNTIME = LinkableRuntimeImage.isLinkableRuntime(); + private static final boolean JMODS_EXIST = Files.exists(JMODS); private final static Set MODULES = Set.of("test", "m1"); @@ -67,12 +74,22 @@ public class AllModulePath { .orElseThrow(() -> new RuntimeException("jlink tool not found") ); + private static Helper HELPER; + + private static boolean isExplodedJDKImage() { + if (!JMODS_EXIST && !LINKABLE_RUNTIME) { + System.err.println("Test skipped. Not a linkable runtime and no JMODs"); + return true; + } + return false; + } @BeforeClass public void setup() throws Throwable { - if (Files.notExists(JMODS)) { + if (isExplodedJDKImage()) { return; } + HELPER = Helper.newHelper(LINKABLE_RUNTIME); Files.createDirectories(MODS); @@ -84,60 +101,114 @@ public void setup() throws Throwable { } } + /* + * --add-modules ALL-MODULE-PATH with an existing module-path. + */ @Test public void testAllModulePath() throws Throwable { - if (Files.notExists(JMODS)) { + if (isExplodedJDKImage()) { return; } - // create custom image - Path image = Paths.get("image"); - createImage(image, "--add-modules", "ALL-MODULE-PATH"); + Path image = HELPER.createNewImageDir("image"); + List opts = List.of("--module-path", MODS.toString(), + "--output", image.toString(), + "--add-modules", "ALL-MODULE-PATH"); + createImage(image, opts, true /* success */); Set modules = new HashSet<>(); - Files.find(JMODS, 1, (Path p, BasicFileAttributes attr) -> - p.toString().endsWith(".jmod")) - .map(p -> JMODS.relativize(p).toString()) - .map(n -> n.substring(0, n.length()-5)) - .forEach(modules::add); + // java.base is a dependency of any external module + modules.add("java.base"); modules.add("m1"); modules.add("test"); checkModules(image, modules); } + /* + * --add-modules ALL-MODULE-PATH with --limit-modules is an error + */ @Test public void testLimitModules() throws Throwable { - if (Files.notExists(JMODS)) { + if (isExplodedJDKImage()) { return; } - - // create custom image - Path image = Paths.get("image1"); - createImage(image, - "--add-modules", "ALL-MODULE-PATH", - "--limit-modules", "m1"); - - checkModules(image, Set.of("m1", "java.base")); + Path targetPath = HELPER.createNewImageDir("all-mods-limit-mods"); + String moduleName = "com.baz.runtime"; + Result result = HELPER.generateDefaultJModule(moduleName, "jdk.jfr"); + Path customModulePath = result.getFile().getParent(); + List allArgs = List.of("--add-modules", "ALL-MODULE-PATH", + "--limit-modules", "jdk.jfr", + "--module-path", customModulePath.toString(), + "--output", targetPath.toString()); + JlinkOutput allOut = createImage(targetPath, allArgs, false /* success */); + String actual = allOut.stdout.trim(); + String expected = "Error: --limit-modules not allowed with --add-modules ALL-MODULE-PATH"; + assertEquals(actual, expected); } + + /* + * --add-modules *includes* ALL-MODULE-PATH with an existing module path + */ @Test public void testAddModules() throws Throwable { - if (Files.notExists(JMODS)) { + if (isExplodedJDKImage()) { return; } // create custom image - Path image = Paths.get("image2"); - createImage(image, - "--add-modules", "m1,test", - "--add-modules", "ALL-MODULE-PATH", - "--limit-modules", "java.base"); + Path image = HELPER.createNewImageDir("image2"); + List opts = List.of("--module-path", MODS.toString(), + "--output", image.toString(), + "--add-modules", "m1", + "--add-modules", "ALL-MODULE-PATH"); + createImage(image, opts, true /* success */); checkModules(image, Set.of("m1", "test", "java.base")); } /* - * check the modules linked in the image + * No --module-path with --add-modules ALL-MODULE-PATH is an error. + */ + @Test + public void noModulePath() throws IOException { + if (isExplodedJDKImage()) { + return; + } + Path targetPath = HELPER.createNewImageDir("all-mod-path-no-mod-path"); + List allArgs = List.of("--add-modules", "ALL-MODULE-PATH", + "--output", targetPath.toString()); + JlinkOutput allOut = createImage(targetPath, allArgs, false /* expect failure */); + String expected = "Error: --module-path option must be specified with --add-modules ALL-MODULE-PATH"; + assertEquals(allOut.stdout.trim(), expected); + } + + /* + * --module-path not-exist and --add-modules ALL-MODULE-PATH is an error. + */ + @Test + public void modulePathEmpty() throws IOException { + if (isExplodedJDKImage()) { + return; + } + Path targetPath = HELPER.createNewImageDir("all-mod-path-not-existing"); + String strNotExists = "not-exist"; + Path notExists = Path.of(strNotExists); + if (Files.exists(notExists)) { + throw new AssertionError("Test setup error, path must not exist!"); + } + List allArgs = List.of("--add-modules", "ALL-MODULE-PATH", + "--module-path", notExists.toString(), + "--output", targetPath.toString()); + + JlinkOutput allOut = createImage(targetPath, allArgs, false /* expect failure */); + String actual = allOut.stdout.trim(); + assertTrue(actual.startsWith("Error: No module found in module path")); + assertTrue(actual.contains(strNotExists)); + } + + /* + * check the modules linked in the image using m1/p.ListModules */ private void checkModules(Path image, Set modules) throws Throwable { Path cmd = findTool(image, "java"); @@ -164,16 +235,19 @@ private Path findTool(Path image, String tool) { return cmd; } - private void createImage(Path image, String... options) throws IOException { - String modulepath = JMODS.toString() + File.pathSeparator + MODS.toString(); - List opts = List.of("--module-path", modulepath, - "--output", image.toString()); - String[] args = Stream.concat(opts.stream(), Arrays.stream(options)) - .toArray(String[]::new); - - System.out.println("jlink " + Arrays.stream(args).collect(Collectors.joining(" "))); - PrintWriter pw = new PrintWriter(System.out); - int rc = JLINK_TOOL.run(pw, pw, args); - assertTrue(rc == 0); + private JlinkOutput createImage(Path image, List args, boolean success) throws IOException { + System.out.println("jlink " + args.stream().collect(Collectors.joining(" "))); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + PrintWriter out = new PrintWriter(baos); + ByteArrayOutputStream berrOs = new ByteArrayOutputStream(); + PrintWriter err = new PrintWriter(berrOs); + int rc = JLINK_TOOL.run(out, err, args.toArray(String[]::new)); + String stdOut = new String(baos.toByteArray()); + String stdErr = new String(berrOs.toByteArray()); + assertEquals(rc == 0, success, String.format("Output was: %nstdout: %s%nstderr: %s%n", stdOut, stdErr)); + return new JlinkOutput(stdErr, stdOut); } + + private static record JlinkOutput(String stderr, String stdout) {}; } diff --git a/test/jdk/tools/jlink/basic/BasicTest.java b/test/jdk/tools/jlink/basic/BasicTest.java index a771d4d0002..1a14e620fa6 100644 --- a/test/jdk/tools/jlink/basic/BasicTest.java +++ b/test/jdk/tools/jlink/basic/BasicTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,21 +21,6 @@ * questions. */ -/* - * @test - * @summary Basic test of jlink to create jmods and images - * @author Andrei Eremeev - * @library /test/lib - * @modules java.base/jdk.internal.module - * jdk.jlink - * jdk.compiler - * @build jdk.test.lib.process.ProcessTools - * jdk.test.lib.process.OutputAnalyzer - * jdk.test.lib.compiler.CompilerUtils - * jdk.test.lib.util.JarUtils - * @run main BasicTest - */ - import java.io.File; import java.io.PrintWriter; import java.nio.file.Files; @@ -50,7 +35,22 @@ import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools; import jdk.test.lib.util.JarUtils; +import jdk.tools.jlink.internal.LinkableRuntimeImage; +/* + * @test + * @summary Basic test of jlink to create jmods and images + * @author Andrei Eremeev + * @library /test/lib + * @modules java.base/jdk.internal.module + * jdk.jlink/jdk.tools.jlink.internal + * jdk.compiler + * @build jdk.test.lib.process.ProcessTools + * jdk.test.lib.process.OutputAnalyzer + * jdk.test.lib.compiler.CompilerUtils + * jdk.test.lib.util.JarUtils + * @run main/othervm BasicTest + */ public class BasicTest { static final ToolProvider JMOD_TOOL = ToolProvider.findFirst("jmod") .orElseThrow(() -> @@ -62,21 +62,31 @@ public class BasicTest { new RuntimeException("jlink tool not found") ); - private final String TEST_MODULE = "test"; - private final Path jdkHome = Paths.get(System.getProperty("test.jdk")); - private final Path jdkMods = jdkHome.resolve("jmods"); - private final Path testSrc = Paths.get(System.getProperty("test.src")); - private final Path src = testSrc.resolve("src").resolve(TEST_MODULE); - private final Path classes = Paths.get("classes"); - private final Path jmods = Paths.get("jmods"); - private final Path jars = Paths.get("jars"); + private static final String TEST_MODULE = "test"; + private static final Path jdkHome = Paths.get(System.getProperty("test.jdk")); + private static final Path jdkMods = jdkHome.resolve("jmods"); + private static final boolean JMODS_EXIST = Files.exists(jdkMods); + private static final boolean LINKABLE_RUNTIME = LinkableRuntimeImage.isLinkableRuntime(); + private static final Path testSrc = Paths.get(System.getProperty("test.src")); + private static final Path src = testSrc.resolve("src").resolve(TEST_MODULE); + private static final Path classes = Paths.get("classes"); + private static final Path jmods = Paths.get("jmods"); + private static final Path jars = Paths.get("jars"); public static void main(String[] args) throws Throwable { new BasicTest().run(); } + private static boolean isExplodedJDKImage() { + if (!JMODS_EXIST && !LINKABLE_RUNTIME) { + System.err.println("Test skipped. Not a linkable runtime and no JMODs"); + return true; + } + return false; + } + public void run() throws Throwable { - if (Files.notExists(jdkMods)) { + if (isExplodedJDKImage()) { return; } @@ -146,8 +156,10 @@ private void execute(Path image, String scriptName) throws Throwable { private void runJlink(Path image, String modName, String... options) { List args = new ArrayList<>(); + String modPathArg = (JMODS_EXIST ? jdkMods + File.pathSeparator : "") + + jmods; Collections.addAll(args, - "--module-path", jdkMods + File.pathSeparator + jmods, + "--module-path", modPathArg, "--add-modules", modName, "--output", image.toString()); Collections.addAll(args, options); From d2a48634b872b65668b57d3975f805277ae96f83 Mon Sep 17 00:00:00 2001 From: William Kemper Date: Fri, 20 Dec 2024 17:30:17 +0000 Subject: [PATCH 14/36] 8346690: Shenandoah: Fix log message for end of GC usage report Reviewed-by: ysr, kdnilsen --- .../gc/shenandoah/shenandoahGeneration.cpp | 33 ++++++++++--------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp index 2bebac05f15..c72940c3c3a 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp @@ -205,21 +205,24 @@ void ShenandoahGeneration::log_status(const char *msg) const { // Not under a lock here, so read each of these once to make sure // byte size in proper unit and proper unit for byte size are consistent. - size_t v_used = used(); - size_t v_used_regions = used_regions_size(); - size_t v_soft_max_capacity = soft_max_capacity(); - size_t v_max_capacity = max_capacity(); - size_t v_available = available(); - size_t v_humongous_waste = get_humongous_waste(); - LogGcInfo::print("%s: %s generation used: " SIZE_FORMAT "%s, used regions: " SIZE_FORMAT "%s, " - "humongous waste: " SIZE_FORMAT "%s, soft capacity: " SIZE_FORMAT "%s, max capacity: " SIZE_FORMAT "%s, " - "available: " SIZE_FORMAT "%s", msg, name(), - byte_size_in_proper_unit(v_used), proper_unit_for_byte_size(v_used), - byte_size_in_proper_unit(v_used_regions), proper_unit_for_byte_size(v_used_regions), - byte_size_in_proper_unit(v_humongous_waste), proper_unit_for_byte_size(v_humongous_waste), - byte_size_in_proper_unit(v_soft_max_capacity), proper_unit_for_byte_size(v_soft_max_capacity), - byte_size_in_proper_unit(v_max_capacity), proper_unit_for_byte_size(v_max_capacity), - byte_size_in_proper_unit(v_available), proper_unit_for_byte_size(v_available)); + const size_t v_used = used(); + const size_t v_used_regions = used_regions_size(); + const size_t v_soft_max_capacity = soft_max_capacity(); + const size_t v_max_capacity = max_capacity(); + const size_t v_available = available(); + const size_t v_humongous_waste = get_humongous_waste(); + + const LogGcInfo target; + LogStream ls(target); + ls.print("%s: ", msg); + if (_type != NON_GEN) { + ls.print("%s generation ", name()); + } + + ls.print_cr("used: " PROPERFMT ", used regions: " PROPERFMT ", humongous waste: " PROPERFMT + ", soft capacity: " PROPERFMT ", max capacity: " PROPERFMT ", available: " PROPERFMT, + PROPERFMTARGS(v_used), PROPERFMTARGS(v_used_regions), PROPERFMTARGS(v_humongous_waste), + PROPERFMTARGS(v_soft_max_capacity), PROPERFMTARGS(v_max_capacity), PROPERFMTARGS(v_available)); } void ShenandoahGeneration::reset_mark_bitmap() { From b8e40b9c2dfecdad9096015c1aa208ea077db7f5 Mon Sep 17 00:00:00 2001 From: William Kemper Date: Fri, 20 Dec 2024 17:32:33 +0000 Subject: [PATCH 15/36] 8346688: GenShen: Missing metadata trigger log message Reviewed-by: ysr, kdnilsen --- src/hotspot/share/gc/shenandoah/shenandoahRegulatorThread.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRegulatorThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahRegulatorThread.cpp index 696e0a9b695..f8e0e7125ac 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahRegulatorThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahRegulatorThread.cpp @@ -64,7 +64,8 @@ void ShenandoahRegulatorThread::regulate_young_and_old_cycles() { if (mode == ShenandoahGenerationalControlThread::none) { if (should_start_metaspace_gc()) { if (request_concurrent_gc(GLOBAL)) { - log_debug(gc)("Heuristics request for global (unload classes) accepted."); + // Some of vmTestbase/metaspace tests depend on following line to count GC cycles + _global_heuristics->log_trigger("%s", GCCause::to_string(GCCause::_metadata_GC_threshold)); } } else { if (_young_heuristics->should_start_gc()) { From 7ba969a576eb92446e40587fecf98e1e4aba8883 Mon Sep 17 00:00:00 2001 From: Mandy Chung Date: Fri, 20 Dec 2024 20:08:42 +0000 Subject: [PATCH 16/36] 8346739: jpackage tests failed after JDK-8345259 Reviewed-by: kcr, asemenyuk --- .../tools/jpackage/share/RuntimeImageSymbolicLinksTest.java | 2 ++ test/jdk/tools/jpackage/share/RuntimeImageTest.java | 2 ++ test/jdk/tools/jpackage/share/RuntimePackageTest.java | 3 +++ 3 files changed, 7 insertions(+) diff --git a/test/jdk/tools/jpackage/share/RuntimeImageSymbolicLinksTest.java b/test/jdk/tools/jpackage/share/RuntimeImageSymbolicLinksTest.java index 404cd3b6d3a..db74e3456c4 100644 --- a/test/jdk/tools/jpackage/share/RuntimeImageSymbolicLinksTest.java +++ b/test/jdk/tools/jpackage/share/RuntimeImageSymbolicLinksTest.java @@ -51,6 +51,7 @@ public class RuntimeImageSymbolicLinksTest { @Test public static void test() throws Exception { + final Path jmods = Path.of(System.getProperty("java.home"), "jmods"); final Path workDir = TKit.createTempDirectory("runtime").resolve("data"); final Path jlinkOutputDir = workDir.resolve("temp.runtime"); Files.createDirectories(jlinkOutputDir.getParent()); @@ -61,6 +62,7 @@ public static void test() throws Exception { .addArguments( "--output", jlinkOutputDir.toString(), "--add-modules", "ALL-MODULE-PATH", + "--module-path", jmods.toString(), "--strip-debug", "--no-header-files", "--no-man-pages", diff --git a/test/jdk/tools/jpackage/share/RuntimeImageTest.java b/test/jdk/tools/jpackage/share/RuntimeImageTest.java index f3751c9ee47..65e8c448d39 100644 --- a/test/jdk/tools/jpackage/share/RuntimeImageTest.java +++ b/test/jdk/tools/jpackage/share/RuntimeImageTest.java @@ -44,6 +44,7 @@ public class RuntimeImageTest { @Test public static void test() throws Exception { + final Path jmods = Path.of(System.getProperty("java.home"), "jmods"); final Path workDir = TKit.createTempDirectory("runtime").resolve("data"); final Path jlinkOutputDir = workDir.resolve("temp.runtime"); Files.createDirectories(jlinkOutputDir.getParent()); @@ -54,6 +55,7 @@ public static void test() throws Exception { .addArguments( "--output", jlinkOutputDir.toString(), "--add-modules", "ALL-MODULE-PATH", + "--module-path", jmods.toString(), "--strip-debug", "--no-header-files", "--no-man-pages", diff --git a/test/jdk/tools/jpackage/share/RuntimePackageTest.java b/test/jdk/tools/jpackage/share/RuntimePackageTest.java index 0b505babcc5..73f1c525654 100644 --- a/test/jdk/tools/jpackage/share/RuntimePackageTest.java +++ b/test/jdk/tools/jpackage/share/RuntimePackageTest.java @@ -101,6 +101,8 @@ private static PackageTest init(Set types) { .forTypes(types) .addInitializer(cmd -> { final Path runtimeImageDir; + final Path jmods = Path.of(System.getProperty("java.home"), "jmods"); + if (JPackageCommand.DEFAULT_RUNTIME_IMAGE != null) { runtimeImageDir = JPackageCommand.DEFAULT_RUNTIME_IMAGE; } else { @@ -112,6 +114,7 @@ private static PackageTest init(Set types) { .addArguments( "--output", runtimeImageDir.toString(), "--add-modules", "ALL-MODULE-PATH", + "--module-path", jmods.toString(), "--strip-debug", "--no-header-files", "--no-man-pages") From d562d3c7a9e1e857c095ef908b0957b033972949 Mon Sep 17 00:00:00 2001 From: Liam Miller-Cushon Date: Fri, 20 Dec 2024 20:52:48 +0000 Subject: [PATCH 17/36] 8343882: BasicAnnoTests doesn't handle multiple annotations at the same position Reviewed-by: darcy --- .../processing/model/type/BasicAnnoTests.java | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/test/langtools/tools/javac/processing/model/type/BasicAnnoTests.java b/test/langtools/tools/javac/processing/model/type/BasicAnnoTests.java index 904e4e78cad..f94ba461a45 100644 --- a/test/langtools/tools/javac/processing/model/type/BasicAnnoTests.java +++ b/test/langtools/tools/javac/processing/model/type/BasicAnnoTests.java @@ -163,7 +163,7 @@ public Void scan(Element elem, Void ignore) { */ class TestTypeScanner extends TypeScanner { Element elem; - NavigableMap toBeFound; + NavigableMap> toBeFound; int count = 0; Set seen = new HashSet<>(); @@ -171,10 +171,10 @@ class TestTypeScanner extends TypeScanner { super(types); this.elem = elem; - NavigableMap testByPos = new TreeMap<>(); + NavigableMap> testByPos = new TreeMap<>(); for (AnnotationMirror test : tests) { for (int pos : getPosn(test)) { - testByPos.put(pos, test); + testByPos.computeIfAbsent(pos, ArrayList::new).add(test); } } this.toBeFound = testByPos; @@ -196,17 +196,18 @@ Void scan(TypeMirror t, Void ignore) { out.println("scan " + count + ": " + t); if (toBeFound.size() > 0) { if (toBeFound.firstKey().equals(count)) { - AnnotationMirror test = toBeFound.pollFirstEntry().getValue(); - String annoType = getAnnoType(test); - AnnotationMirror anno = getAnnotation(t, annoType); - if (anno == null) { - error(elem, "annotation not found on " + count + ": " + t); - } else { - String v = getValue(anno, "value").toString(); - if (v.equals(getExpect(test))) { - out.println("found " + anno + " as expected"); + for (AnnotationMirror test : toBeFound.pollFirstEntry().getValue()) { + String annoType = getAnnoType(test); + AnnotationMirror anno = getAnnotation(t, annoType); + if (anno == null) { + error(elem, "annotation not found on " + count + ": " + t); } else { - error(elem, "Unexpected value: " + v + ", expected: " + getExpect(test)); + String v = getValue(anno, "value").toString(); + if (v.equals(getExpect(test))) { + out.println("found " + anno + " as expected"); + } else { + error(elem, "Unexpected value: " + v + ", expected: " + getExpect(test)); + } } } } else if (count > toBeFound.firstKey()) { From 249f141211c94afcce70d9d536d84e108e07b4e5 Mon Sep 17 00:00:00 2001 From: William Kemper Date: Fri, 20 Dec 2024 23:51:49 +0000 Subject: [PATCH 18/36] 8346737: GenShen: Generational memory pools should not report zero for maximum capacity Reviewed-by: kdnilsen, ysr --- src/hotspot/share/gc/shenandoah/shenandoahMemoryPool.cpp | 5 ----- src/hotspot/share/gc/shenandoah/shenandoahMemoryPool.hpp | 1 - 2 files changed, 6 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMemoryPool.cpp b/src/hotspot/share/gc/shenandoah/shenandoahMemoryPool.cpp index 6cbb5454ac1..9350f44585f 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMemoryPool.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMemoryPool.cpp @@ -93,11 +93,6 @@ size_t ShenandoahGenerationalMemoryPool::used_in_bytes() { return _generation->used(); } -size_t ShenandoahGenerationalMemoryPool::max_size() const { - return _generation->max_capacity(); -} - - ShenandoahYoungGenMemoryPool::ShenandoahYoungGenMemoryPool(ShenandoahHeap* heap) : ShenandoahGenerationalMemoryPool(heap, "Shenandoah Young Gen", diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMemoryPool.hpp b/src/hotspot/share/gc/shenandoah/shenandoahMemoryPool.hpp index e26d61a3a6c..ccdfdddede9 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMemoryPool.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMemoryPool.hpp @@ -55,7 +55,6 @@ class ShenandoahGenerationalMemoryPool: public ShenandoahMemoryPool { explicit ShenandoahGenerationalMemoryPool(ShenandoahHeap* heap, const char* name, ShenandoahGeneration* generation); MemoryUsage get_memory_usage() override; size_t used_in_bytes() override; - size_t max_size() const override; }; class ShenandoahYoungGenMemoryPool : public ShenandoahGenerationalMemoryPool { From 43b7e9f54776ec7ed98d2e2f717c3d9663268ef2 Mon Sep 17 00:00:00 2001 From: Jan Kratochvil Date: Sat, 21 Dec 2024 03:40:48 +0000 Subject: [PATCH 19/36] 8346713: [testsuite] NeverActAsServerClassMachine breaks TestPLABAdaptToMinTLABSize.java TestPinnedHumongousFragmentation.java TestPinnedObjectContents.java Reviewed-by: stefank, tschatzl --- .../jtreg/gc/TestPLABAdaptToMinTLABSize.java | 25 ++++++++++++++----- .../TestPinnedHumongousFragmentation.java | 2 +- .../pinnedobjs/TestPinnedObjectContents.java | 3 ++- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/test/hotspot/jtreg/gc/TestPLABAdaptToMinTLABSize.java b/test/hotspot/jtreg/gc/TestPLABAdaptToMinTLABSize.java index 73d3c475335..e1e29432f53 100644 --- a/test/hotspot/jtreg/gc/TestPLABAdaptToMinTLABSize.java +++ b/test/hotspot/jtreg/gc/TestPLABAdaptToMinTLABSize.java @@ -24,17 +24,29 @@ package gc; /* - * @test TestPLABAdaptToMinTLABSize + * @test TestPLABAdaptToMinTLABSizeG1 * @bug 8289137 * @summary Make sure that Young/OldPLABSize adapt to MinTLABSize setting. - * @requires vm.gc.Parallel | vm.gc.G1 + * @requires vm.gc.G1 * @library /test/lib * @modules java.base/jdk.internal.misc * java.management - * @run driver gc.TestPLABAdaptToMinTLABSize + * @run driver gc.TestPLABAdaptToMinTLABSize -XX:+UseG1GC + */ + +/* + * @test TestPLABAdaptToMinTLABSizeParallel + * @bug 8289137 + * @summary Make sure that Young/OldPLABSize adapt to MinTLABSize setting. + * @requires vm.gc.Parallel + * @library /test/lib + * @modules java.base/jdk.internal.misc + * java.management + * @run driver gc.TestPLABAdaptToMinTLABSize -XX:+UseParallelGC */ import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import jdk.test.lib.process.OutputAnalyzer; @@ -68,9 +80,10 @@ private static void runTest(boolean shouldSucceed, String... extraArgs) throws E } public static void main(String[] args) throws Exception { - runTest(true, "-XX:MinTLABSize=100k"); + String gc = args[0]; + runTest(true, gc, "-XX:MinTLABSize=100k"); // Should not succeed when explicitly specifying invalid combination. - runTest(false, "-XX:MinTLABSize=100k", "-XX:OldPLABSize=5k"); - runTest(false, "-XX:MinTLABSize=100k", "-XX:YoungPLABSize=5k"); + runTest(false, gc, "-XX:MinTLABSize=100k", "-XX:OldPLABSize=5k"); + runTest(false, gc, "-XX:MinTLABSize=100k", "-XX:YoungPLABSize=5k"); } } diff --git a/test/hotspot/jtreg/gc/g1/pinnedobjs/TestPinnedHumongousFragmentation.java b/test/hotspot/jtreg/gc/g1/pinnedobjs/TestPinnedHumongousFragmentation.java index fad01ab0022..f147dcbe62e 100644 --- a/test/hotspot/jtreg/gc/g1/pinnedobjs/TestPinnedHumongousFragmentation.java +++ b/test/hotspot/jtreg/gc/g1/pinnedobjs/TestPinnedHumongousFragmentation.java @@ -36,7 +36,7 @@ * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox * @run main/othervm -Xlog:gc+region=trace -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xmx1g -Xms1g - * -XX:VerifyGCType=full -XX:+VerifyDuringGC -XX:+VerifyAfterGC -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:VerifyGCType=full -XX:+VerifyDuringGC -XX:+VerifyAfterGC -XX:+WhiteBoxAPI -XX:+UseG1GC -Xbootclasspath/a:. * gc.g1.pinnedobjs.TestPinnedHumongousFragmentation */ diff --git a/test/hotspot/jtreg/gc/g1/pinnedobjs/TestPinnedObjectContents.java b/test/hotspot/jtreg/gc/g1/pinnedobjs/TestPinnedObjectContents.java index e0fdc88e2a1..dcc87f811b3 100644 --- a/test/hotspot/jtreg/gc/g1/pinnedobjs/TestPinnedObjectContents.java +++ b/test/hotspot/jtreg/gc/g1/pinnedobjs/TestPinnedObjectContents.java @@ -33,7 +33,8 @@ * java.management * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. -XX:+ZapUnusedHeapArea -Xlog:gc,gc+ergo+cset=trace gc.g1.pinnedobjs.TestPinnedObjectContents + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseG1GC + * -Xbootclasspath/a:. -XX:+ZapUnusedHeapArea -Xlog:gc,gc+ergo+cset=trace gc.g1.pinnedobjs.TestPinnedObjectContents */ package gc.g1.pinnedobjs; From c1b868d27d955b5e219caf8f76e87e5edf4c92df Mon Sep 17 00:00:00 2001 From: Qizheng Xing Date: Sun, 22 Dec 2024 20:53:21 +0000 Subject: [PATCH 20/36] 8346602: Remove unused macro parameters in `jni.cpp` Reviewed-by: dholmes, mli --- src/hotspot/share/prims/jni.cpp | 78 ++++++++++++++++----------------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/src/hotspot/share/prims/jni.cpp b/src/hotspot/share/prims/jni.cpp index 40d3b506258..4787247d722 100644 --- a/src/hotspot/share/prims/jni.cpp +++ b/src/hotspot/share/prims/jni.cpp @@ -2413,7 +2413,7 @@ static char* get_bad_address() { -#define DEFINE_GETSCALARARRAYELEMENTS(ElementTag,ElementType,Result, Tag \ +#define DEFINE_GETSCALARARRAYELEMENTS(ElementType,Result \ , EntryProbe, ReturnProbe) \ \ JNI_ENTRY_NO_PRESERVE(ElementType*, \ @@ -2447,35 +2447,35 @@ JNI_ENTRY_NO_PRESERVE(ElementType*, \ return result; \ JNI_END -DEFINE_GETSCALARARRAYELEMENTS(T_BOOLEAN, jboolean, Boolean, bool +DEFINE_GETSCALARARRAYELEMENTS(jboolean, Boolean , HOTSPOT_JNI_GETBOOLEANARRAYELEMENTS_ENTRY(env, array, (uintptr_t *) isCopy), HOTSPOT_JNI_GETBOOLEANARRAYELEMENTS_RETURN((uintptr_t*)result)) -DEFINE_GETSCALARARRAYELEMENTS(T_BYTE, jbyte, Byte, byte +DEFINE_GETSCALARARRAYELEMENTS(jbyte, Byte , HOTSPOT_JNI_GETBYTEARRAYELEMENTS_ENTRY(env, array, (uintptr_t *) isCopy), HOTSPOT_JNI_GETBYTEARRAYELEMENTS_RETURN((char*)result)) -DEFINE_GETSCALARARRAYELEMENTS(T_SHORT, jshort, Short, short +DEFINE_GETSCALARARRAYELEMENTS(jshort, Short , HOTSPOT_JNI_GETSHORTARRAYELEMENTS_ENTRY(env, (uint16_t*) array, (uintptr_t *) isCopy), HOTSPOT_JNI_GETSHORTARRAYELEMENTS_RETURN((uint16_t*)result)) -DEFINE_GETSCALARARRAYELEMENTS(T_CHAR, jchar, Char, char +DEFINE_GETSCALARARRAYELEMENTS(jchar, Char , HOTSPOT_JNI_GETCHARARRAYELEMENTS_ENTRY(env, (uint16_t*) array, (uintptr_t *) isCopy), HOTSPOT_JNI_GETCHARARRAYELEMENTS_RETURN(result)) -DEFINE_GETSCALARARRAYELEMENTS(T_INT, jint, Int, int +DEFINE_GETSCALARARRAYELEMENTS(jint, Int , HOTSPOT_JNI_GETINTARRAYELEMENTS_ENTRY(env, array, (uintptr_t *) isCopy), HOTSPOT_JNI_GETINTARRAYELEMENTS_RETURN((uint32_t*)result)) -DEFINE_GETSCALARARRAYELEMENTS(T_LONG, jlong, Long, long +DEFINE_GETSCALARARRAYELEMENTS(jlong, Long , HOTSPOT_JNI_GETLONGARRAYELEMENTS_ENTRY(env, array, (uintptr_t *) isCopy), HOTSPOT_JNI_GETLONGARRAYELEMENTS_RETURN(((uintptr_t*)result))) // Float and double probes don't return value because dtrace doesn't currently support it -DEFINE_GETSCALARARRAYELEMENTS(T_FLOAT, jfloat, Float, float +DEFINE_GETSCALARARRAYELEMENTS(jfloat, Float , HOTSPOT_JNI_GETFLOATARRAYELEMENTS_ENTRY(env, array, (uintptr_t *) isCopy), HOTSPOT_JNI_GETFLOATARRAYELEMENTS_RETURN(result)) -DEFINE_GETSCALARARRAYELEMENTS(T_DOUBLE, jdouble, Double, double +DEFINE_GETSCALARARRAYELEMENTS(jdouble, Double , HOTSPOT_JNI_GETDOUBLEARRAYELEMENTS_ENTRY(env, array, (uintptr_t *) isCopy), HOTSPOT_JNI_GETDOUBLEARRAYELEMENTS_RETURN(result)) -#define DEFINE_RELEASESCALARARRAYELEMENTS(ElementTag,ElementType,Result,Tag \ - , EntryProbe, ReturnProbe);\ +#define DEFINE_RELEASESCALARARRAYELEMENTS(ElementType,Result \ + , EntryProbe, ReturnProbe) \ \ JNI_ENTRY_NO_PRESERVE(void, \ jni_Release##Result##ArrayElements(JNIEnv *env, ElementType##Array array, \ @@ -2494,28 +2494,28 @@ JNI_ENTRY_NO_PRESERVE(void, \ ReturnProbe; \ JNI_END -DEFINE_RELEASESCALARARRAYELEMENTS(T_BOOLEAN, jboolean, Boolean, bool +DEFINE_RELEASESCALARARRAYELEMENTS(jboolean, Boolean , HOTSPOT_JNI_RELEASEBOOLEANARRAYELEMENTS_ENTRY(env, array, (uintptr_t *) buf, mode), HOTSPOT_JNI_RELEASEBOOLEANARRAYELEMENTS_RETURN()) -DEFINE_RELEASESCALARARRAYELEMENTS(T_BYTE, jbyte, Byte, byte +DEFINE_RELEASESCALARARRAYELEMENTS(jbyte, Byte , HOTSPOT_JNI_RELEASEBYTEARRAYELEMENTS_ENTRY(env, array, (char *) buf, mode), HOTSPOT_JNI_RELEASEBYTEARRAYELEMENTS_RETURN()) -DEFINE_RELEASESCALARARRAYELEMENTS(T_SHORT, jshort, Short, short +DEFINE_RELEASESCALARARRAYELEMENTS(jshort, Short , HOTSPOT_JNI_RELEASESHORTARRAYELEMENTS_ENTRY(env, array, (uint16_t *) buf, mode), HOTSPOT_JNI_RELEASESHORTARRAYELEMENTS_RETURN()) -DEFINE_RELEASESCALARARRAYELEMENTS(T_CHAR, jchar, Char, char +DEFINE_RELEASESCALARARRAYELEMENTS(jchar, Char , HOTSPOT_JNI_RELEASECHARARRAYELEMENTS_ENTRY(env, array, (uint16_t *) buf, mode), HOTSPOT_JNI_RELEASECHARARRAYELEMENTS_RETURN()) -DEFINE_RELEASESCALARARRAYELEMENTS(T_INT, jint, Int, int +DEFINE_RELEASESCALARARRAYELEMENTS(jint, Int , HOTSPOT_JNI_RELEASEINTARRAYELEMENTS_ENTRY(env, array, (uint32_t *) buf, mode), HOTSPOT_JNI_RELEASEINTARRAYELEMENTS_RETURN()) -DEFINE_RELEASESCALARARRAYELEMENTS(T_LONG, jlong, Long, long +DEFINE_RELEASESCALARARRAYELEMENTS(jlong, Long , HOTSPOT_JNI_RELEASELONGARRAYELEMENTS_ENTRY(env, array, (uintptr_t *) buf, mode), HOTSPOT_JNI_RELEASELONGARRAYELEMENTS_RETURN()) -DEFINE_RELEASESCALARARRAYELEMENTS(T_FLOAT, jfloat, Float, float +DEFINE_RELEASESCALARARRAYELEMENTS(jfloat, Float , HOTSPOT_JNI_RELEASEFLOATARRAYELEMENTS_ENTRY(env, array, (float *) buf, mode), HOTSPOT_JNI_RELEASEFLOATARRAYELEMENTS_RETURN()) -DEFINE_RELEASESCALARARRAYELEMENTS(T_DOUBLE, jdouble, Double, double +DEFINE_RELEASESCALARARRAYELEMENTS(jdouble, Double , HOTSPOT_JNI_RELEASEDOUBLEARRAYELEMENTS_ENTRY(env, array, (double *) buf, mode), HOTSPOT_JNI_RELEASEDOUBLEARRAYELEMENTS_RETURN()) @@ -2533,8 +2533,8 @@ static void check_bounds(jsize start, jsize copy_len, jsize array_len, TRAPS) { } } -#define DEFINE_GETSCALARARRAYREGION(ElementTag,ElementType,Result, Tag \ - , EntryProbe, ReturnProbe); \ +#define DEFINE_GETSCALARARRAYREGION(ElementType,Result \ + , EntryProbe, ReturnProbe) \ DT_VOID_RETURN_MARK_DECL(Get##Result##ArrayRegion \ , ReturnProbe); \ \ @@ -2550,34 +2550,34 @@ jni_Get##Result##ArrayRegion(JNIEnv *env, ElementType##Array array, jsize start, } \ JNI_END -DEFINE_GETSCALARARRAYREGION(T_BOOLEAN, jboolean,Boolean, bool +DEFINE_GETSCALARARRAYREGION(jboolean,Boolean , HOTSPOT_JNI_GETBOOLEANARRAYREGION_ENTRY(env, array, start, len, (uintptr_t *) buf), HOTSPOT_JNI_GETBOOLEANARRAYREGION_RETURN()); -DEFINE_GETSCALARARRAYREGION(T_BYTE, jbyte, Byte, byte +DEFINE_GETSCALARARRAYREGION(jbyte, Byte , HOTSPOT_JNI_GETBYTEARRAYREGION_ENTRY(env, array, start, len, (char *) buf), HOTSPOT_JNI_GETBYTEARRAYREGION_RETURN()); -DEFINE_GETSCALARARRAYREGION(T_SHORT, jshort, Short, short +DEFINE_GETSCALARARRAYREGION(jshort, Short , HOTSPOT_JNI_GETSHORTARRAYREGION_ENTRY(env, array, start, len, (uint16_t *) buf), HOTSPOT_JNI_GETSHORTARRAYREGION_RETURN()); -DEFINE_GETSCALARARRAYREGION(T_CHAR, jchar, Char, char +DEFINE_GETSCALARARRAYREGION(jchar, Char , HOTSPOT_JNI_GETCHARARRAYREGION_ENTRY(env, array, start, len, (uint16_t*) buf), HOTSPOT_JNI_GETCHARARRAYREGION_RETURN()); -DEFINE_GETSCALARARRAYREGION(T_INT, jint, Int, int +DEFINE_GETSCALARARRAYREGION(jint, Int , HOTSPOT_JNI_GETINTARRAYREGION_ENTRY(env, array, start, len, (uint32_t*) buf), HOTSPOT_JNI_GETINTARRAYREGION_RETURN()); -DEFINE_GETSCALARARRAYREGION(T_LONG, jlong, Long, long +DEFINE_GETSCALARARRAYREGION(jlong, Long , HOTSPOT_JNI_GETLONGARRAYREGION_ENTRY(env, array, start, len, (uintptr_t *) buf), HOTSPOT_JNI_GETLONGARRAYREGION_RETURN()); -DEFINE_GETSCALARARRAYREGION(T_FLOAT, jfloat, Float, float +DEFINE_GETSCALARARRAYREGION(jfloat, Float , HOTSPOT_JNI_GETFLOATARRAYREGION_ENTRY(env, array, start, len, (float *) buf), HOTSPOT_JNI_GETFLOATARRAYREGION_RETURN()); -DEFINE_GETSCALARARRAYREGION(T_DOUBLE, jdouble, Double, double +DEFINE_GETSCALARARRAYREGION(jdouble, Double , HOTSPOT_JNI_GETDOUBLEARRAYREGION_ENTRY(env, array, start, len, (double *) buf), HOTSPOT_JNI_GETDOUBLEARRAYREGION_RETURN()); -#define DEFINE_SETSCALARARRAYREGION(ElementTag,ElementType,Result, Tag \ - , EntryProbe, ReturnProbe); \ +#define DEFINE_SETSCALARARRAYREGION(ElementType,Result \ + , EntryProbe, ReturnProbe) \ DT_VOID_RETURN_MARK_DECL(Set##Result##ArrayRegion \ ,ReturnProbe); \ \ @@ -2593,28 +2593,28 @@ jni_Set##Result##ArrayRegion(JNIEnv *env, ElementType##Array array, jsize start, } \ JNI_END -DEFINE_SETSCALARARRAYREGION(T_BOOLEAN, jboolean, Boolean, bool +DEFINE_SETSCALARARRAYREGION(jboolean, Boolean , HOTSPOT_JNI_SETBOOLEANARRAYREGION_ENTRY(env, array, start, len, (uintptr_t *)buf), HOTSPOT_JNI_SETBOOLEANARRAYREGION_RETURN()) -DEFINE_SETSCALARARRAYREGION(T_BYTE, jbyte, Byte, byte +DEFINE_SETSCALARARRAYREGION(jbyte, Byte , HOTSPOT_JNI_SETBYTEARRAYREGION_ENTRY(env, array, start, len, (char *) buf), HOTSPOT_JNI_SETBYTEARRAYREGION_RETURN()) -DEFINE_SETSCALARARRAYREGION(T_SHORT, jshort, Short, short +DEFINE_SETSCALARARRAYREGION(jshort, Short , HOTSPOT_JNI_SETSHORTARRAYREGION_ENTRY(env, array, start, len, (uint16_t *) buf), HOTSPOT_JNI_SETSHORTARRAYREGION_RETURN()) -DEFINE_SETSCALARARRAYREGION(T_CHAR, jchar, Char, char +DEFINE_SETSCALARARRAYREGION(jchar, Char , HOTSPOT_JNI_SETCHARARRAYREGION_ENTRY(env, array, start, len, (uint16_t *) buf), HOTSPOT_JNI_SETCHARARRAYREGION_RETURN()) -DEFINE_SETSCALARARRAYREGION(T_INT, jint, Int, int +DEFINE_SETSCALARARRAYREGION(jint, Int , HOTSPOT_JNI_SETINTARRAYREGION_ENTRY(env, array, start, len, (uint32_t *) buf), HOTSPOT_JNI_SETINTARRAYREGION_RETURN()) -DEFINE_SETSCALARARRAYREGION(T_LONG, jlong, Long, long +DEFINE_SETSCALARARRAYREGION(jlong, Long , HOTSPOT_JNI_SETLONGARRAYREGION_ENTRY(env, array, start, len, (uintptr_t *) buf), HOTSPOT_JNI_SETLONGARRAYREGION_RETURN()) -DEFINE_SETSCALARARRAYREGION(T_FLOAT, jfloat, Float, float +DEFINE_SETSCALARARRAYREGION(jfloat, Float , HOTSPOT_JNI_SETFLOATARRAYREGION_ENTRY(env, array, start, len, (float *) buf), HOTSPOT_JNI_SETFLOATARRAYREGION_RETURN()) -DEFINE_SETSCALARARRAYREGION(T_DOUBLE, jdouble, Double, double +DEFINE_SETSCALARARRAYREGION(jdouble, Double , HOTSPOT_JNI_SETDOUBLEARRAYREGION_ENTRY(env, array, start, len, (double *) buf), HOTSPOT_JNI_SETDOUBLEARRAYREGION_RETURN()) From bffa77bc04219d3b2fd0898f5e62f324503b2b94 Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Mon, 23 Dec 2024 11:27:12 +0000 Subject: [PATCH 21/36] 8346714: [ASAN] compressedKlass.cpp reported applying non-zero offset to null pointer Reviewed-by: mdoerr, coleenp --- src/hotspot/share/oops/compressedKlass.cpp | 2 +- src/hotspot/share/utilities/globalDefinitions.hpp | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/oops/compressedKlass.cpp b/src/hotspot/share/oops/compressedKlass.cpp index 21c28af8766..050314ef813 100644 --- a/src/hotspot/share/oops/compressedKlass.cpp +++ b/src/hotspot/share/oops/compressedKlass.cpp @@ -96,7 +96,7 @@ void CompressedKlassPointers::sanity_check_after_initialization() { // Check that Klass range is fully engulfed in the encoding range const address encoding_start = _base; - const address encoding_end = _base + nth_bit(narrow_klass_pointer_bits() + _shift); + const address encoding_end = (address)(p2u(_base) + (uintptr_t)nth_bit(narrow_klass_pointer_bits() + _shift)); ASSERT_HERE_2(_klass_range_start >= _base && _klass_range_end <= encoding_end, "Resulting encoding range does not fully cover the class range"); diff --git a/src/hotspot/share/utilities/globalDefinitions.hpp b/src/hotspot/share/utilities/globalDefinitions.hpp index ccd3106b471..ce864119d75 100644 --- a/src/hotspot/share/utilities/globalDefinitions.hpp +++ b/src/hotspot/share/utilities/globalDefinitions.hpp @@ -185,6 +185,11 @@ inline intptr_t p2i(const volatile void* p) { return (intptr_t) p; } +// Convert pointer to uintptr_t +inline uintptr_t p2u(const volatile void* p) { + return (uintptr_t) p; +} + #define BOOL_TO_STR(_b_) ((_b_) ? "true" : "false") //---------------------------------------------------------------------------------------------------- From cd15ebb963d4dab079921bf468005896a40ab3b1 Mon Sep 17 00:00:00 2001 From: David Holmes Date: Mon, 23 Dec 2024 11:56:24 +0000 Subject: [PATCH 22/36] 8346477: Clarify the Java manpage in relation to the JVM's OnOutOfMemoryError flags Co-authored-by: Thomas Stuefe Reviewed-by: jpai, stuefe --- src/java.base/share/man/java.md | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/java.base/share/man/java.md b/src/java.base/share/man/java.md index 0beb5bf935c..01f7b3f7e77 100644 --- a/src/java.base/share/man/java.md +++ b/src/java.base/share/man/java.md @@ -1292,10 +1292,15 @@ These `java` options control the runtime behavior of the Java HotSpot VM. `-XX:OnOutOfMemoryError=`*string* : Sets a custom command or a series of semicolon-separated commands to run - when an `OutOfMemoryError` exception is first thrown. If the string + when an `OutOfMemoryError` exception is first thrown by the JVM. + If the string contains spaces, then it must be enclosed in quotation marks. For an example of a command string, see the description of the `-XX:OnError` option. + This applies only to `OutOfMemoryError` exceptions caused by Java Heap + exhaustion; it does not apply to `OutOfMemoryError` exceptions thrown + directly from Java code, nor by the JVM for other types of resource + exhaustion (such as native thread creation errors). `-XX:+PrintCommandLineFlags` : Enables printing of ergonomically selected JVM flags that appeared on the @@ -2189,10 +2194,14 @@ perform extensive debugging. `-XX:+HeapDumpOnOutOfMemoryError` : Enables the dumping of the Java heap to a file in the current directory by using the heap profiler (HPROF) when a `java.lang.OutOfMemoryError` - exception is thrown. You can explicitly set the heap dump file path and + exception is thrown by the JVM. You can explicitly set the heap dump file path and name using the `-XX:HeapDumpPath` option. By default, this option is disabled and the heap isn't dumped when an `OutOfMemoryError` exception is thrown. + This applies only to `OutOfMemoryError` exceptions caused by Java Heap + exhaustion; it does not apply to `OutOfMemoryError` exceptions thrown + directly from Java code, nor by the JVM for other types of resource + exhaustion (such as native thread creation errors). `-XX:HeapDumpPath=`*path* : Sets the path and file name for writing the heap dump provided by the heap From ed292318a98163b3226aa05d06825b48c3d97dbb Mon Sep 17 00:00:00 2001 From: Nizar Benalla Date: Mon, 23 Dec 2024 13:50:39 +0000 Subject: [PATCH 23/36] 8337111: Bad HTML checker for generated documentation 8337113: Bad character checker for generated documentation 8337116: Internal links checker for generated documentation 8337114: DocType checker for generated documentation Reviewed-by: hannesw --- test/docs/jdk/javadoc/doccheck/DocCheck.java | 194 +++++ .../docs/jdk/javadoc/doccheck/ExtLinksJdk.txt | 773 ++++++++++++++++++ .../doccheck/checks/jdkCheckExtlinks.java | 31 + .../javadoc/doccheck/checks/jdkCheckHtml.java | 31 + .../doccheck/checks/jdkCheckLinks.java | 31 + .../checks/jdkDoctypeBadcharsCheck.java} | 23 +- .../doccheck/doccheckutils/Checker.java | 39 + .../doccheck/doccheckutils/FileChecker.java | 30 + .../doccheck/doccheckutils/FileProcessor.java | 64 ++ .../doccheck/doccheckutils/HtmlChecker.java | 94 +++ .../doccheckutils/HtmlFileChecker.java | 389 +++++++++ .../javadoc/doccheck/doccheckutils/Log.java | 95 +++ .../checkers/BadCharacterChecker.java | 158 ++++ .../checkers/DocTypeChecker.java | 159 ++++ .../checkers/ExtLinkChecker.java | 220 +++++ .../doccheckutils/checkers/LinkChecker.java | 440 ++++++++++ .../doccheckutils/checkers/TidyChecker.java | 259 ++++++ 17 files changed, 3012 insertions(+), 18 deletions(-) create mode 100644 test/docs/jdk/javadoc/doccheck/DocCheck.java create mode 100644 test/docs/jdk/javadoc/doccheck/ExtLinksJdk.txt create mode 100644 test/docs/jdk/javadoc/doccheck/checks/jdkCheckExtlinks.java create mode 100644 test/docs/jdk/javadoc/doccheck/checks/jdkCheckHtml.java create mode 100644 test/docs/jdk/javadoc/doccheck/checks/jdkCheckLinks.java rename test/docs/jdk/javadoc/{TestDocs.java => doccheck/checks/jdkDoctypeBadcharsCheck.java} (63%) create mode 100644 test/docs/jdk/javadoc/doccheck/doccheckutils/Checker.java create mode 100644 test/docs/jdk/javadoc/doccheck/doccheckutils/FileChecker.java create mode 100644 test/docs/jdk/javadoc/doccheck/doccheckutils/FileProcessor.java create mode 100644 test/docs/jdk/javadoc/doccheck/doccheckutils/HtmlChecker.java create mode 100644 test/docs/jdk/javadoc/doccheck/doccheckutils/HtmlFileChecker.java create mode 100644 test/docs/jdk/javadoc/doccheck/doccheckutils/Log.java create mode 100644 test/docs/jdk/javadoc/doccheck/doccheckutils/checkers/BadCharacterChecker.java create mode 100644 test/docs/jdk/javadoc/doccheck/doccheckutils/checkers/DocTypeChecker.java create mode 100644 test/docs/jdk/javadoc/doccheck/doccheckutils/checkers/ExtLinkChecker.java create mode 100644 test/docs/jdk/javadoc/doccheck/doccheckutils/checkers/LinkChecker.java create mode 100644 test/docs/jdk/javadoc/doccheck/doccheckutils/checkers/TidyChecker.java diff --git a/test/docs/jdk/javadoc/doccheck/DocCheck.java b/test/docs/jdk/javadoc/doccheck/DocCheck.java new file mode 100644 index 00000000000..acd61b0e76e --- /dev/null +++ b/test/docs/jdk/javadoc/doccheck/DocCheck.java @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import doccheckutils.FileChecker; +import doccheckutils.FileProcessor; +import doccheckutils.HtmlFileChecker; +import doccheckutils.checkers.BadCharacterChecker; +import doccheckutils.checkers.DocTypeChecker; +import doccheckutils.checkers.LinkChecker; +import doccheckutils.checkers.TidyChecker; +import doccheckutils.checkers.ExtLinkChecker; +import toolbox.TestRunner; + +import java.nio.file.Path; +import java.util.*; + +/** + * DocCheck + *

+ * For the sake of brevity, to run all of these checkers use + *

+ * `make test-docs_all TEST_DEPS=docs-jdk` + *

+ * This collection of tests provide a variety of checks for JDK documentation bundle. + *

+ * It is meant to provide a convenient way to alert users of any errors in their documentation + * before a push and verify the quality of the documentation. + * It is not meant to replace more authoritative checkers; instead, + * it is more focused on providing a convenient, easy overview of any possible issues. + *

+ * It supports the following checks: + *

+ * *HTML* -- We use the standard `tidy` utility to check for HTML compliance, + * according to the declared version of HTML. + * The output from `tidy` is analysed to generate a report summarizing any issues that were found. + *

+ * Version `5.9.20` of `tidy` is expected, or the output from the `--version` option should contain the string `version 5`. + * The test warns the user if he is using an earlier version. + *

+ * *Bad Characters* -- We assumee that HTML files are encoded in UTF-8, + * and reports any character encoding issues that it finds. + *

+ * *DocType* -- We assume that HTML files should use HTML5, and reports + * any files for which that is not the case. + *

+ * *Links* -- We check links within a set of files, and reports on links + * to external resources, without otherwise checking them. + *

+ * *External Links* -- We scan the files for URLs that refer to + * external resources, and validates those references using a "golden file" that includes a list of vetted links. + *

+ * Each external reference is only checked once; but if an issue is found, all the files containing the + * reference will be reported. + */ +public class DocCheck extends TestRunner { + + private static final String DOCCHECK_DIR = System.getProperty("doccheck.dir"); + private static final Path DIR = Path.of(DOCCHECK_DIR != null ? DOCCHECK_DIR : ""); + private static final Set CHECKS_LIST = new HashSet<>(); + private static Path DOCS_DIR; + + private static boolean html; + private static boolean links; + private static boolean badchars; + private static boolean doctype; + private static boolean extlinks; + + private List files; + + public DocCheck() { + super(System.err); + init(); + } + + public static void main(String... args) throws Exception { + chooseCheckers(); + DocCheck docCheck = new DocCheck(); + docCheck.runTests(); + } + + private static void chooseCheckers() { + final String checks = System.getProperty("doccheck.checks"); + + if (!checks.isEmpty()) { + if (checks.contains(",")) { + CHECKS_LIST.addAll(Arrays.asList(checks.split(","))); + } else { + CHECKS_LIST.add(checks); + } + } + + if (CHECKS_LIST.contains("all")) { + html = true; + links = true; + badchars = true; + doctype = true; + extlinks = true; + } else { + if (CHECKS_LIST.contains("html")) { + html = true; + } + if (CHECKS_LIST.contains("links")) { + links = true; + } + if (CHECKS_LIST.contains("badchars")) { + badchars = true; + } + if (CHECKS_LIST.contains("doctype")) { + doctype = true; + } + if (CHECKS_LIST.contains("extlinks")) { + extlinks = true; + } + } + } + + public void init() { + var fileTester = new FileProcessor(); + DOCS_DIR = DocTester.resolveDocs(); + var baseDir = DOCS_DIR.resolve(DIR); + fileTester.processFiles(baseDir); + files = fileTester.getFiles(); + } + + public List getCheckers() { + + List checkers = new ArrayList<>(); + if (html) { + checkers.add(new TidyChecker()); + } + if (links) { + var linkChecker = new LinkChecker(); + linkChecker.setBaseDir(DOCS_DIR); + checkers.add(new HtmlFileChecker(linkChecker, DOCS_DIR)); + } + + if (extlinks) { + checkers.add(new HtmlFileChecker(new ExtLinkChecker(), DOCS_DIR)); + } + + // there should be almost nothing reported from these two checkers + // most reports should be broken anchors/links, missing files and errors in html + if (badchars) { + checkers.add(new BadCharacterChecker()); + } + if (doctype) { + checkers.add(new HtmlFileChecker(new DocTypeChecker(), DOCS_DIR)); + } + + return checkers; + } + + @Test + public void test() throws Exception { + List checkers = getCheckers(); + runCheckersSequentially(checkers); + } + + private void runCheckersSequentially(List checkers) throws Exception { + List exceptions = new ArrayList<>(); + + for (FileChecker checker : checkers) { + try (checker) { + checker.checkFiles(files); + } catch (Exception e) { + exceptions.add(e); + } + } + + if (!exceptions.isEmpty()) { + throw new Exception("One or more HTML checkers failed: " + exceptions); + } + } +} diff --git a/test/docs/jdk/javadoc/doccheck/ExtLinksJdk.txt b/test/docs/jdk/javadoc/doccheck/ExtLinksJdk.txt new file mode 100644 index 00000000000..704bdffb283 --- /dev/null +++ b/test/docs/jdk/javadoc/doccheck/ExtLinksJdk.txt @@ -0,0 +1,773 @@ +# This file is used to check external links in the JDK generated documentation +# to prevent broken links from backsliding into the JDK source. +# +# The file serves as a "whitelist" of links that have been checked to be working as intended +# and JDK developers should add external links to this file whenever they add them to their documentation. +# +# +# The links in this file are checked before every release. +# +# +# +http://cldr.unicode.org/ +http://csrc.nist.gov/publications/fips/fips186-3/fips_186-3.pdf +http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf +http://docs.oracle.com/javase/feedback.html +http://docs.oracle.com/javase/jndi/tutorial/index.html +http://docs.oracle.com/javase/specs/jls/se@@JAVASE_VERSION@@/html/jls-12.html +http://docs.oracle.com/javase/tutorial/collections/index.html +http://docs.oracle.com/javase/tutorial/i18n/format/decimalFormat.html +http://docs.oracle.com/javase/tutorial/i18n/format/simpleDateFormat.html +http://docs.oracle.com/javase/tutorial/jdbc/ +http://docs.oracle.com/javase/tutorial/jdbc/basics/index.html +http://docs.oracle.com/javase/tutorial/jdbc/basics/rowset.html +http://docs.oracle.com/javase/tutorial/uiswing/dnd/index.html +http://en.wikipedia.org/wiki/Skip_list +http://jclark.com/xml/xmlns.htm +http://jcp.org/en/jsr/detail?id=173 +http://jcp.org/en/jsr/detail?id=268 +http://relaxng.org/spec-20011203.html +http://sax.sourceforge.net/?selected=get-set +http://standards.iso.org/iso/9075/2002/12/sqlxml.xsd +http://svn.python.org/projects/python/trunk/Objects/listsort.txt +http://tools.ietf.org/html/rfc1421 +http://tools.ietf.org/html/rfc5869 +http://unicode.org/reports/tr35/ +http://unicode.org/reports/tr35/tr35-numbers.html +http://web.archive.org/web/20051219043731/http://archive.ncsa.uiuc.edu/SDG/Software/Mosaic/Demo/url-primer.html +http://www.cl.cam.ac.uk/~mgk25/time/utc-sls/ +http://www.cs.rochester.edu/~scott/papers/1996_PODC_queues.pdf +http://www.iana.org/ +http://www.iana.org/assignments/character-sets +http://www.iana.org/assignments/character-sets/character-sets.xhtml +http://www.iana.org/assignments/media-types/ +http://www.iana.org/assignments/uri-schemes.html +http://www.ietf.org/ +http://www.ietf.org/rfc/rfc0793.txt +http://www.ietf.org/rfc/rfc0822.txt +http://www.ietf.org/rfc/rfc1122.txt +http://www.ietf.org/rfc/rfc1123.txt +http://www.ietf.org/rfc/rfc1323.txt +http://www.ietf.org/rfc/rfc1349.txt +http://www.ietf.org/rfc/rfc1521.txt +http://www.ietf.org/rfc/rfc1522.txt +http://www.ietf.org/rfc/rfc1918.txt +http://www.ietf.org/rfc/rfc1950.txt +http://www.ietf.org/rfc/rfc1950.txt.pdf +http://www.ietf.org/rfc/rfc1951.txt +http://www.ietf.org/rfc/rfc1951.txt.pdf +http://www.ietf.org/rfc/rfc1952.txt +http://www.ietf.org/rfc/rfc1952.txt.pdf +http://www.ietf.org/rfc/rfc1964.txt +http://www.ietf.org/rfc/rfc2045.txt +http://www.ietf.org/rfc/rfc2046.txt +http://www.ietf.org/rfc/rfc2078.txt +http://www.ietf.org/rfc/rfc2104.txt +http://www.ietf.org/rfc/rfc2109.txt +http://www.ietf.org/rfc/rfc2222.txt +http://www.ietf.org/rfc/rfc2236.txt +http://www.ietf.org/rfc/rfc2245.txt +http://www.ietf.org/rfc/rfc2246.txt +http://www.ietf.org/rfc/rfc2251.txt +http://www.ietf.org/rfc/rfc2253.txt +http://www.ietf.org/rfc/rfc2254.txt +http://www.ietf.org/rfc/rfc2255.txt +http://www.ietf.org/rfc/rfc2268.txt +http://www.ietf.org/rfc/rfc2278.txt +http://www.ietf.org/rfc/rfc2279.txt +http://www.ietf.org/rfc/rfc2296.txt +http://www.ietf.org/rfc/rfc2365.txt +http://www.ietf.org/rfc/rfc2373.txt +http://www.ietf.org/rfc/rfc2396.txt +http://www.ietf.org/rfc/rfc2440.txt +http://www.ietf.org/rfc/rfc2474.txt +http://www.ietf.org/rfc/rfc2609.txt +http://www.ietf.org/rfc/rfc2616.txt +http://www.ietf.org/rfc/rfc2696 +http://www.ietf.org/rfc/rfc2696.txt +http://www.ietf.org/rfc/rfc2710.txt +http://www.ietf.org/rfc/rfc2732.txt +http://www.ietf.org/rfc/rfc2743.txt +http://www.ietf.org/rfc/rfc2781.txt +http://www.ietf.org/rfc/rfc2782.txt +http://www.ietf.org/rfc/rfc2830.txt +http://www.ietf.org/rfc/rfc2831.txt +http://www.ietf.org/rfc/rfc2853.txt +http://www.ietf.org/rfc/rfc2891.txt +http://www.ietf.org/rfc/rfc2898.txt +http://www.ietf.org/rfc/rfc2965.txt +http://www.ietf.org/rfc/rfc3023.txt +http://www.ietf.org/rfc/rfc3111.txt +http://www.ietf.org/rfc/rfc3275.txt +http://www.ietf.org/rfc/rfc3279.txt +http://www.ietf.org/rfc/rfc3296.txt +http://www.ietf.org/rfc/rfc3330.txt +http://www.ietf.org/rfc/rfc3376.txt +http://www.ietf.org/rfc/rfc3454.txt +http://www.ietf.org/rfc/rfc3490.txt +http://www.ietf.org/rfc/rfc3491.txt +http://www.ietf.org/rfc/rfc3492.txt +http://www.ietf.org/rfc/rfc3530.txt +http://www.ietf.org/rfc/rfc3720.txt +http://www.ietf.org/rfc/rfc3720.txt.pdf +http://www.ietf.org/rfc/rfc3758.txt +http://www.ietf.org/rfc/rfc3810.txt +http://www.ietf.org/rfc/rfc3986.txt +http://www.ietf.org/rfc/rfc4120.txt +http://www.ietf.org/rfc/rfc4122.txt +http://www.ietf.org/rfc/rfc4366.txt +http://www.ietf.org/rfc/rfc4512.txt +http://www.ietf.org/rfc/rfc4648.txt +http://www.ietf.org/rfc/rfc5116.txt +http://www.ietf.org/rfc/rfc5280.txt +http://www.ietf.org/rfc/rfc5890.txt +http://www.ietf.org/rfc/rfc6066.txt +http://www.ietf.org/rfc/rfc7301.txt +http://www.ietf.org/rfc/rfc790.txt +http://www.ietf.org/rfc/rfc793.txt +http://www.ietf.org/rfc/rfc822.txt +http://www.ietf.org/rfc/rfc919.txt +http://www.info-zip.org/doc/appnote-19970311-iz.zip +http://www.ioplex.com/utilities/keytab.txt +http://www.iso.org/iso/home/standards/currency_codes.htm +http://www.jcp.org +http://www.jcp.org/en/jsr/detail?id=203 +http://www.jpeg.org +http://www.libpng.org/pub/png/spec/ +http://www.microsoft.com/typography/otspec/ +http://www.midi.org +http://www.oasis-open.org/committees/entity/spec-2001-08-06.html +http://www.oasis-open.org/committees/tc_home.php?wg_abbrev=dss +http://www.opengroup.org +http://www.oracle.com/technetwork/articles/java/mixing-components-433992.html +http://www.oracle.com/technetwork/java/architecture-142923.html +http://www.oracle.com/technetwork/java/javase/documentation/serialized-criteria-137781.html +http://www.oracle.com/technetwork/java/javase/documentation/spec-136004.html +http://www.oracle.com/technetwork/java/javase/javasecarootcertsprogram-1876540.html +http://www.oracle.com/technetwork/java/javase/tech/javamanagement-140525.html +http://www.oracle.com/technetwork/java/painting-140037.html +http://www.oracle.com/technetwork/java/persistence2-141443.html +http://www.oracle.com/technetwork/java/persistence3-139471.html +http://www.oracle.com/technetwork/java/persistence4-140124.html +http://www.oreilly.com/catalog/regex/ +http://www.oreilly.com/catalog/regex3/ +http://www.reactive-streams.org/ +http://www.relaxng.org/ +http://www.rfc-editor.org/rfc/bcp/bcp47.txt +http://www.saxproject.org +http://www.saxproject.org/ +http://www.unicode.org +http://www.unicode.org/ +http://www.unicode.org/glossary/ +http://www.unicode.org/reports/tr15/ +http://www.unicode.org/reports/tr18/ +http://www.unicode.org/reports/tr24/ +http://www.unicode.org/reports/tr27/ +http://www.unicode.org/reports/tr36/ +http://www.unicode.org/reports/tr44/ +http://www.unicode.org/standard/standard.html +http://www.w3.org/2000/09/xmldsig +http://www.w3.org/2000/xmlns/ +http://www.w3.org/2001/04/xmldsig-more +http://www.w3.org/2001/04/xmlenc +http://www.w3.org/2001/05/xmlschema-errata +http://www.w3.org/2001/10/xml-exc-c14n +http://www.w3.org/2002/06/xmldsig-filter2 +http://www.w3.org/2007/05/xmldsig-more +http://www.w3.org/2009/xmldsig11 +http://www.w3.org/2021/04/xmldsig-more +http://www.w3.org/Graphics/GIF/spec-gif89a.txt +http://www.w3.org/TR/1998/REC-CSS2-19980512 +http://www.w3.org/TR/1999/REC-html401-19991224/ +http://www.w3.org/TR/1999/REC-xml-names-19990114/ +http://www.w3.org/TR/1999/REC-xpath-19991116 +http://www.w3.org/TR/1999/REC-xslt-19991116 +http://www.w3.org/TR/2000/CR-DOM-Level-2-20000510 +http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113 +http://www.w3.org/TR/2000/REC-DOM-Level-2-Events-20001113 +http://www.w3.org/TR/2000/REC-DOM-Level-2-Style-20001113 +http://www.w3.org/TR/2000/REC-DOM-Level-2-Traversal-Range-20001113 +http://www.w3.org/TR/2000/REC-DOM-Level-2-Views-20001113 +http://www.w3.org/TR/2001/REC-xml-c14n-20010315 +http://www.w3.org/TR/2001/REC-xmlschema-1-20010502/ +http://www.w3.org/TR/2003/NOTE-DOM-Level-3-Events-20031107 +http://www.w3.org/TR/2003/REC-DOM-Level-2-HTML-20030109 +http://www.w3.org/TR/2003/REC-SVG11-20030114/ +http://www.w3.org/TR/2003/REC-xptr-framework-20030325/ +http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407 +http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html +http://www.w3.org/TR/2004/REC-DOM-Level-3-LS-20040407 +http://www.w3.org/TR/2004/REC-DOM-Level-3-Val-20040127/ +http://www.w3.org/TR/2004/REC-xml-20040204 +http://www.w3.org/TR/2004/REC-xml-infoset-20040204 +http://www.w3.org/TR/2004/REC-xml-infoset-20040204/ +http://www.w3.org/TR/2004/REC-xml-names11-20040204/ +http://www.w3.org/TR/2004/REC-xml11-20040204/ +http://www.w3.org/TR/DOM-Level-2 +http://www.w3.org/TR/DOM-Level-2-Core/ +http://www.w3.org/TR/DOM-Level-3-Core +http://www.w3.org/TR/DOM-Level-3-LS +http://www.w3.org/TR/ElementTraversal/ +http://www.w3.org/TR/NOTE-datetime +http://www.w3.org/TR/REC-CSS1 +http://www.w3.org/TR/REC-html32.html +http://www.w3.org/TR/REC-xml +http://www.w3.org/TR/REC-xml-names +http://www.w3.org/TR/REC-xml-names/ +http://www.w3.org/TR/REC-xml/ +http://www.w3.org/TR/html4/ +http://www.w3.org/TR/html40/appendix/notes.html +http://www.w3.org/TR/xinclude/ +http://www.w3.org/TR/xml-exc-c14n/ +http://www.w3.org/TR/xml-names11/ +http://www.w3.org/TR/xml-stylesheet/ +http://www.w3.org/TR/xml11/ +http://www.w3.org/TR/xmldsig-core/ +http://www.w3.org/TR/xmldsig-filter2 +http://www.w3.org/TR/xmldsig-filter2/ +http://www.w3.org/TR/xmlschema-1 +http://www.w3.org/TR/xmlschema-1/ +http://www.w3.org/TR/xmlschema-2/ +http://www.w3.org/TR/xpath +http://www.w3.org/TR/xpath-datamodel +http://www.w3.org/TR/xpath/ +http://www.w3.org/TR/xslt +http://www.w3.org/XML/1998/namespace +http://www.w3.org/XML/Schema +http://www.w3.org/XML/xml-V10-2e-errata +http://www.w3.org/pub/WWW/Graphics/Color/sRGB.html +http://www.w3.org/pub/WWW/Protocols/ +http://xmlns.jcp.org/xml/ns//jdbc/webrowset.xsd +https://bugreport.java.com/bugreport/ +https://bugs.openjdk.org/secure/attachment/75649/JVM_CodeHeap_StateAnalytics_V2.pdf +https://cldr.unicode.org/index/downloads +https://csrc.nist.gov/publications/PubsFIPS.html +https://csrc.nist.gov/publications/fips/archive/fips186-2/fips186-2.pdf +https://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf +https://csrc.nist.gov/publications/fips/fips186-3/fips_186-3.pdf +https://csrc.nist.gov/publications/fips/fips197/fips-197.pdf +https://csrc.nist.gov/publications/fips/fips46-3/fips46-3.pdf +https://csrc.nist.gov/publications/fips/fips81/fips81.htm +https://csrc.nist.gov/publications/nistpubs/800-38C/SP800-38C_updated-July20_2007.pdf +https://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf +https://csrc.nist.gov/pubs/fips/203/final +https://csrc.nist.gov/pubs/fips/204/final +https://datatracker.ietf.org/doc/html/rfc5646 +https://datatracker.ietf.org/doc/html/rfc8017 +https://developer.apple.com/documentation +https://docs.oracle.com/en/java/javase/11/tools/java.html +https://docs.oracle.com/en/java/javase/12/language/index.html +https://docs.oracle.com/en/java/javase/12/tools/java.html +https://docs.oracle.com/en/java/javase/12/vm/compiler-control1.html +https://docs.oracle.com/en/java/javase/13/docs/specs/man/java.html +https://docs.oracle.com/en/java/javase/14/docs/specs/man/java.html +https://docs.oracle.com/en/java/javase/15/docs/specs/man/java.html +https://docs.oracle.com/en/java/javase/16/docs/specs/man/java.html +https://docs.oracle.com/en/java/javase/17/docs/specs/man/java.html +https://docs.oracle.com/en/java/javase/18/docs/specs/man/java.html +https://docs.oracle.com/en/java/javase/19/docs/specs/man/java.html +https://docs.oracle.com/en/java/javase/20/docs/specs/man/java.html +https://docs.oracle.com/en/java/javase/21/docs/specs/man/java.html +https://docs.oracle.com/en/java/javase/22/docs/specs/man/java.html +https://docs.oracle.com/en/java/javase/23/docs/api/java.base/java/lang/Double.html +https://docs.oracle.com/en/java/javase/23/docs/api/java.base/java/math/BigDecimal.html +https://docs.oracle.com/en/java/javase/23/docs/specs/man/java.html +https://docs.oracle.com/en/java/javase/24/docs/specs/man/java.html +https://docs.oracle.com/en/java/javase/@@JAVASE_VERSION@@/docs/api/java.base/java/lang/String.html +https://docs.oracle.com/en/java/javase/@@JAVASE_VERSION@@/docs/specs/javadoc/javadoc-search-spec.html +https://docs.oracle.com/en/java/javase/@@JAVASE_VERSION@@/docs/specs/man/javadoc.html +https://docs.oracle.com/en/java/javase/index.html +https://docs.oracle.com/javase/10/tools/java.htm +https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html +https://docs.oracle.com/javase/8/docs/technotes/tools/windows/java.html +https://docs.oracle.com/javase/9/tools/java.htm +https://docs.oracle.com/javase/specs/ +https://docs.oracle.com/javase/specs/jls/se10/html/index.html +https://docs.oracle.com/javase/specs/jls/se11/html/index.html +https://docs.oracle.com/javase/specs/jls/se12/html/index.html +https://docs.oracle.com/javase/specs/jls/se13/html/index.html +https://docs.oracle.com/javase/specs/jls/se14/html/index.html +https://docs.oracle.com/javase/specs/jls/se15/html/index.html +https://docs.oracle.com/javase/specs/jls/se16/html/index.html +https://docs.oracle.com/javase/specs/jls/se17/html/index.html +https://docs.oracle.com/javase/specs/jls/se18/html/index.html +https://docs.oracle.com/javase/specs/jls/se19/html/index.html +https://docs.oracle.com/javase/specs/jls/se20/html/index.html +https://docs.oracle.com/javase/specs/jls/se21/html/index.html +https://docs.oracle.com/javase/specs/jls/se22/html/index.html +https://docs.oracle.com/javase/specs/jls/se22/html/jls-13.html +https://docs.oracle.com/javase/specs/jls/se22/html/jls-14.html +https://docs.oracle.com/javase/specs/jls/se22/html/jls-15.html +https://docs.oracle.com/javase/specs/jls/se22/html/jls-17.html +https://docs.oracle.com/javase/specs/jls/se22/html/jls-3.html +https://docs.oracle.com/javase/specs/jls/se22/html/jls-4.html +https://docs.oracle.com/javase/specs/jls/se22/html/jls-5.html +https://docs.oracle.com/javase/specs/jls/se22/html/jls-6.html +https://docs.oracle.com/javase/specs/jls/se22/html/jls-8.html +https://docs.oracle.com/javase/specs/jls/se22/html/jls-9.html +https://docs.oracle.com/javase/specs/jls/se23/html +https://docs.oracle.com/javase/specs/jls/se23/html/index.html +https://docs.oracle.com/javase/specs/jls/se23/html/jls-10.html +https://docs.oracle.com/javase/specs/jls/se23/html/jls-11.html +https://docs.oracle.com/javase/specs/jls/se23/html/jls-12.html +https://docs.oracle.com/javase/specs/jls/se23/html/jls-14.html +https://docs.oracle.com/javase/specs/jls/se23/html/jls-15.html +https://docs.oracle.com/javase/specs/jls/se23/html/jls-16.html +https://docs.oracle.com/javase/specs/jls/se23/html/jls-18.html +https://docs.oracle.com/javase/specs/jls/se23/html/jls-2.html +https://docs.oracle.com/javase/specs/jls/se23/html/jls-3.html +https://docs.oracle.com/javase/specs/jls/se23/html/jls-4.html +https://docs.oracle.com/javase/specs/jls/se23/html/jls-5.html +https://docs.oracle.com/javase/specs/jls/se23/html/jls-6.html +https://docs.oracle.com/javase/specs/jls/se23/html/jls-7.html +https://docs.oracle.com/javase/specs/jls/se23/html/jls-8.html +https://docs.oracle.com/javase/specs/jls/se23/html/jls-9.html +https://docs.oracle.com/javase/specs/jls/se24/html/index.html +https://docs.oracle.com/javase/specs/jls/se24/html/jls-9.html +https://docs.oracle.com/javase/specs/jls/se@@JAVASE_VERSION@@/html/ +https://docs.oracle.com/javase/specs/jls/se@@JAVASE_VERSION@@/html/index.html +https://docs.oracle.com/javase/specs/jls/se@@JAVASE_VERSION@@/html/jls-10.html +https://docs.oracle.com/javase/specs/jls/se@@JAVASE_VERSION@@/html/jls-11.html +https://docs.oracle.com/javase/specs/jls/se@@JAVASE_VERSION@@/html/jls-12.html +https://docs.oracle.com/javase/specs/jls/se@@JAVASE_VERSION@@/html/jls-13.html +https://docs.oracle.com/javase/specs/jls/se@@JAVASE_VERSION@@/html/jls-14.html +https://docs.oracle.com/javase/specs/jls/se@@JAVASE_VERSION@@/html/jls-15.html +https://docs.oracle.com/javase/specs/jls/se@@JAVASE_VERSION@@/html/jls-17.html +https://docs.oracle.com/javase/specs/jls/se@@JAVASE_VERSION@@/html/jls-18.html +https://docs.oracle.com/javase/specs/jls/se@@JAVASE_VERSION@@/html/jls-3.html +https://docs.oracle.com/javase/specs/jls/se@@JAVASE_VERSION@@/html/jls-4.html +https://docs.oracle.com/javase/specs/jls/se@@JAVASE_VERSION@@/html/jls-5.html +https://docs.oracle.com/javase/specs/jls/se@@JAVASE_VERSION@@/html/jls-6.html +https://docs.oracle.com/javase/specs/jls/se@@JAVASE_VERSION@@/html/jls-7.html +https://docs.oracle.com/javase/specs/jls/se@@JAVASE_VERSION@@/html/jls-8.html +https://docs.oracle.com/javase/specs/jls/se@@JAVASE_VERSION@@/html/jls-9.html +https://docs.oracle.com/javase/specs/jls/se@@JAVASE_VERSION@@/jls@@JAVASE_VERSION@@.pdf +https://docs.oracle.com/javase/specs/jls/se6/html/j3TOC.html +https://docs.oracle.com/javase/specs/jls/se7/html/index.html +https://docs.oracle.com/javase/specs/jls/se8/html/index.html +https://docs.oracle.com/javase/specs/jls/se9/html/index.html +https://docs.oracle.com/javase/specs/jvms/se10/html/index.html +https://docs.oracle.com/javase/specs/jvms/se11/html/index.html +https://docs.oracle.com/javase/specs/jvms/se12/html/index.html +https://docs.oracle.com/javase/specs/jvms/se13/html/index.html +https://docs.oracle.com/javase/specs/jvms/se14/html/index.html +https://docs.oracle.com/javase/specs/jvms/se15/html/index.html +https://docs.oracle.com/javase/specs/jvms/se16/html/index.html +https://docs.oracle.com/javase/specs/jvms/se17/html/index.html +https://docs.oracle.com/javase/specs/jvms/se18/html/index.html +https://docs.oracle.com/javase/specs/jvms/se19/html/index.html +https://docs.oracle.com/javase/specs/jvms/se20/html/index.html +https://docs.oracle.com/javase/specs/jvms/se21/html/index.html +https://docs.oracle.com/javase/specs/jvms/se22/html/index.html +https://docs.oracle.com/javase/specs/jvms/se23/html +https://docs.oracle.com/javase/specs/jvms/se23/html/index.html +https://docs.oracle.com/javase/specs/jvms/se23/html/jvms-5.html +https://docs.oracle.com/javase/specs/jvms/se24/html/index.html +https://docs.oracle.com/javase/specs/jvms/se24/html/jvms-4.html +https://docs.oracle.com/javase/specs/jvms/se@@JAVASE_VERSION@@/html/index.html +https://docs.oracle.com/javase/specs/jvms/se@@JAVASE_VERSION@@/html/jvms-1.html +https://docs.oracle.com/javase/specs/jvms/se@@JAVASE_VERSION@@/html/jvms-2.html +https://docs.oracle.com/javase/specs/jvms/se@@JAVASE_VERSION@@/html/jvms-3.html +https://docs.oracle.com/javase/specs/jvms/se@@JAVASE_VERSION@@/html/jvms-4.html +https://docs.oracle.com/javase/specs/jvms/se@@JAVASE_VERSION@@/html/jvms-5.html +https://docs.oracle.com/javase/specs/jvms/se@@JAVASE_VERSION@@/html/jvms-6.html +https://docs.oracle.com/javase/specs/jvms/se@@JAVASE_VERSION@@/jvms@@JAVASE_VERSION@@.pdf +https://docs.oracle.com/javase/specs/jvms/se7/html/index.html +https://docs.oracle.com/javase/specs/jvms/se8/html/index.html +https://docs.oracle.com/javase/specs/jvms/se9/html/index.html +https://docs.oracle.com/javase/tutorial/ +https://docs.oracle.com/javase/tutorial/2d/text/fonts.html +https://docs.oracle.com/javase/tutorial/extra/fullscreen/index.html +https://docs.oracle.com/javase/tutorial/index.html +https://docs.oracle.com/javase/tutorial/javabeans/ +https://docs.oracle.com/javase/tutorial/javabeans/writing/properties.html +https://docs.oracle.com/javase/tutorial/sound/ +https://docs.oracle.com/javase/tutorial/uiswing/ +https://docs.oracle.com/javase/tutorial/uiswing/components/applet.html +https://docs.oracle.com/javase/tutorial/uiswing/components/border.html +https://docs.oracle.com/javase/tutorial/uiswing/components/button.html +https://docs.oracle.com/javase/tutorial/uiswing/components/colorchooser.html +https://docs.oracle.com/javase/tutorial/uiswing/components/combobox.html +https://docs.oracle.com/javase/tutorial/uiswing/components/dialog.html +https://docs.oracle.com/javase/tutorial/uiswing/components/filechooser.html +https://docs.oracle.com/javase/tutorial/uiswing/components/frame.html +https://docs.oracle.com/javase/tutorial/uiswing/components/generaltext.html +https://docs.oracle.com/javase/tutorial/uiswing/components/icon.html +https://docs.oracle.com/javase/tutorial/uiswing/components/internalframe.html +https://docs.oracle.com/javase/tutorial/uiswing/components/jcomponent.html +https://docs.oracle.com/javase/tutorial/uiswing/components/label.html +https://docs.oracle.com/javase/tutorial/uiswing/components/layeredpane.html +https://docs.oracle.com/javase/tutorial/uiswing/components/list.html +https://docs.oracle.com/javase/tutorial/uiswing/components/menu.html +https://docs.oracle.com/javase/tutorial/uiswing/components/panel.html +https://docs.oracle.com/javase/tutorial/uiswing/components/progress.html +https://docs.oracle.com/javase/tutorial/uiswing/components/rootpane.html +https://docs.oracle.com/javase/tutorial/uiswing/components/scrollpane.html +https://docs.oracle.com/javase/tutorial/uiswing/components/slider.html +https://docs.oracle.com/javase/tutorial/uiswing/components/spinner.html +https://docs.oracle.com/javase/tutorial/uiswing/components/splitpane.html +https://docs.oracle.com/javase/tutorial/uiswing/components/tabbedpane.html +https://docs.oracle.com/javase/tutorial/uiswing/components/table.html +https://docs.oracle.com/javase/tutorial/uiswing/components/text.html +https://docs.oracle.com/javase/tutorial/uiswing/components/textfield.html +https://docs.oracle.com/javase/tutorial/uiswing/components/toolbar.html +https://docs.oracle.com/javase/tutorial/uiswing/components/tooltip.html +https://docs.oracle.com/javase/tutorial/uiswing/components/toplevel.html +https://docs.oracle.com/javase/tutorial/uiswing/components/tree.html +https://docs.oracle.com/javase/tutorial/uiswing/concurrency/index.html +https://docs.oracle.com/javase/tutorial/uiswing/dnd/index.html +https://docs.oracle.com/javase/tutorial/uiswing/events/actionlistener.html +https://docs.oracle.com/javase/tutorial/uiswing/events/componentlistener.html +https://docs.oracle.com/javase/tutorial/uiswing/events/containerlistener.html +https://docs.oracle.com/javase/tutorial/uiswing/events/focuslistener.html +https://docs.oracle.com/javase/tutorial/uiswing/events/index.html +https://docs.oracle.com/javase/tutorial/uiswing/events/internalframelistener.html +https://docs.oracle.com/javase/tutorial/uiswing/events/itemlistener.html +https://docs.oracle.com/javase/tutorial/uiswing/events/keylistener.html +https://docs.oracle.com/javase/tutorial/uiswing/events/mouselistener.html +https://docs.oracle.com/javase/tutorial/uiswing/events/mousemotionlistener.html +https://docs.oracle.com/javase/tutorial/uiswing/events/treeexpansionlistener.html +https://docs.oracle.com/javase/tutorial/uiswing/events/treemodellistener.html +https://docs.oracle.com/javase/tutorial/uiswing/events/treeselectionlistener.html +https://docs.oracle.com/javase/tutorial/uiswing/events/treewillexpandlistener.html +https://docs.oracle.com/javase/tutorial/uiswing/events/windowlistener.html +https://docs.oracle.com/javase/tutorial/uiswing/index.html +https://docs.oracle.com/javase/tutorial/uiswing/layout/box.html +https://docs.oracle.com/javase/tutorial/uiswing/layout/spring.html +https://docs.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html +https://docs.oracle.com/javase/tutorial/uiswing/misc/action.html +https://docs.oracle.com/javase/tutorial/uiswing/misc/focus.html +https://docs.oracle.com/javase/tutorial/uiswing/misc/keybinding.html +https://docs.oracle.com/javase/tutorial/uiswing/misc/timer.html +https://docs.oracle.com/pls/topic/lookup?ctx=javase@@JAVASE_VERSION@@&id=GUID-FE2D2E28-C991-4EF9-9DBE-2A4982726313 +https://docs.oracle.com/pls/topic/lookup?ctx=javase@@JAVASE_VERSION@@&id=homepage +https://docs.oracle.com/pls/topic/lookup?ctx=javase@@JAVASE_VERSION@@&id=i18n_overview +https://docs.oracle.com/pls/topic/lookup?ctx=javase@@JAVASE_VERSION@@&id=imf_overview +https://docs.oracle.com/pls/topic/lookup?ctx=javase@@JAVASE_VERSION@@&id=jndi_ldap_gl_prop +https://docs.oracle.com/pls/topic/lookup?ctx=javase@@JAVASE_VERSION@@&id=jndi_overview +https://docs.oracle.com/pls/topic/lookup?ctx=javase@@JAVASE_VERSION@@&id=logging_overview +https://docs.oracle.com/pls/topic/lookup?ctx=javase@@JAVASE_VERSION@@&id=monitoring_and_management_using_jmx_technology +https://docs.oracle.com/pls/topic/lookup?ctx=javase@@JAVASE_VERSION@@&id=rmi_guide +https://docs.oracle.com/pls/topic/lookup?ctx=javase@@JAVASE_VERSION@@&id=secure_coding_guidelines_javase +https://docs.oracle.com/pls/topic/lookup?ctx=javase@@JAVASE_VERSION@@&id=security_guide_impl_provider +https://docs.oracle.com/pls/topic/lookup?ctx=javase@@JAVASE_VERSION@@&id=security_guide_jca +https://docs.oracle.com/pls/topic/lookup?ctx=javase@@JAVASE_VERSION@@&id=security_guide_jca_provider +https://docs.oracle.com/pls/topic/lookup?ctx=javase@@JAVASE_VERSION@@&id=security_guide_jdk_providers +https://docs.oracle.com/pls/topic/lookup?ctx=javase@@JAVASE_VERSION@@&id=security_guide_jgss_tutorial +https://docs.oracle.com/pls/topic/lookup?ctx=javase@@JAVASE_VERSION@@&id=security_guide_overview +https://docs.oracle.com/pls/topic/lookup?ctx=javase@@JAVASE_VERSION@@&id=security_guide_pki +https://docs.oracle.com/pls/topic/lookup?ctx=javase@@JAVASE_VERSION@@&id=security_guide_sasl +https://docs.oracle.com/pls/topic/lookup?ctx=javase@@JAVASE_VERSION@@&id=security_guide_tools +https://docs.oracle.com/pls/topic/lookup?ctx=javase@@JAVASE_VERSION@@&id=serialization_filter_guide +https://docs.oracle.com/pls/topic/lookup?ctx=javase@@JAVASE_VERSION@@&id=serialver_tool_reference +https://docs.oracle.com/pls/topic/lookup?ctx=javase@@JAVASE_VERSION@@&id=using_jconsole +https://ftp.pwg.org/pub/pwg/candidates/cs-ippoutputbin10-20010207-5100.2.pdf +https://ftp.pwg.org/pub/pwg/standards/temp_archive/pwg5100.3.pdf +https://github.github.com/gfm/ +https://help.ubuntu.com/community/UnityLaunchersAndDesktopFiles +https://html.spec.whatwg.org +https://html.spec.whatwg.org/multipage/ +https://html.spec.whatwg.org/multipage/introduction.html +https://html.spec.whatwg.org/multipage/sections.html +https://html.spec.whatwg.org/multipage/semantics.html +https://jcp.org/aboutJava/communityprocess/maintenance/jsr924/index.html +https://jcp.org/aboutJava/communityprocess/maintenance/jsr924/index2.html +https://jcp.org/aboutJava/communityprocess/mrel/jsr160/index2.html +https://jcp.org/en/jsr/detail?id=14 +https://jcp.org/en/jsr/detail?id=175 +https://jcp.org/en/jsr/detail?id=201 +https://jcp.org/en/jsr/detail?id=221 +https://jcp.org/en/jsr/detail?id=269 +https://jcp.org/en/jsr/detail?id=334 +https://jcp.org/en/jsr/detail?id=335 +https://jcp.org/en/jsr/detail?id=376 +https://jcp.org/en/jsr/detail?id=41 +https://jcp.org/en/procedures/jcp2 +https://mermaid.js.org +https://msdn.microsoft.com/en-us/library/cc236621.aspx +https://msdn.microsoft.com/en-us/library/dd183391.aspx +https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.140-2.pdf +https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf +https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf +https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-38F.pdf +https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-90Ar1.pdf +https://openjdk.org/jeps/11 +https://openjdk.org/jeps/12 +https://openjdk.org/jeps/181 +https://openjdk.org/jeps/213 +https://openjdk.org/jeps/225 +https://openjdk.org/jeps/261 +https://openjdk.org/jeps/286 +https://openjdk.org/jeps/306 +https://openjdk.org/jeps/323 +https://openjdk.org/jeps/361 +https://openjdk.org/jeps/371 +https://openjdk.org/jeps/378 +https://openjdk.org/jeps/394 +https://openjdk.org/jeps/395 +https://openjdk.org/jeps/396 +https://openjdk.org/jeps/403 +https://openjdk.org/jeps/409 +https://openjdk.org/jeps/421 +https://openjdk.org/jeps/440 +https://openjdk.org/jeps/441 +https://openjdk.org/jeps/454 +https://openjdk.org/jeps/456 +https://openjdk.org/jeps/458 +https://openjdk.org/jeps/467 +https://openjdk.org/jeps/478 +https://openjdk.org/jeps/487 +https://openjdk.org/jeps/488 +https://openjdk.org/jeps/492 +https://openjdk.org/jeps/494 +https://openjdk.org/jeps/495 +https://openjdk.org/jeps/499 +https://prismjs.com +https://pubs.opengroup.org/onlinepubs/9699919799/functions/inet_addr.html +https://relaxng.org/ +https://reproducible-builds.org/ +https://spec.commonmark.org/0.31.2 +https://spec.commonmark.org/0.31.2/ +https://standards.ieee.org/ieee/754/6210/ +https://standards.iso.org/ittf/PubliclyAvailableStandards/c055982_ISO_IEC_19757-3_2016.zip +https://standards.iso.org/ittf/PubliclyAvailableStandards/index.html +https://support.pkware.com/pkzip/appnote +https://tools.ietf.org/html/rfc1319 +https://tools.ietf.org/html/rfc1321 +https://tools.ietf.org/html/rfc1779 +https://tools.ietf.org/html/rfc2040 +https://tools.ietf.org/html/rfc2104 +https://tools.ietf.org/html/rfc2195 +https://tools.ietf.org/html/rfc2222 +https://tools.ietf.org/html/rfc2246 +https://tools.ietf.org/html/rfc2253 +https://tools.ietf.org/html/rfc2595 +https://tools.ietf.org/html/rfc2616 +https://tools.ietf.org/html/rfc2712 +https://tools.ietf.org/html/rfc2818 +https://tools.ietf.org/html/rfc2830 +https://tools.ietf.org/html/rfc2831 +https://tools.ietf.org/html/rfc3217 +https://tools.ietf.org/html/rfc3278 +https://tools.ietf.org/html/rfc3394 +https://tools.ietf.org/html/rfc3986 +https://tools.ietf.org/html/rfc4086 +https://tools.ietf.org/html/rfc4121 +https://tools.ietf.org/html/rfc4162 +https://tools.ietf.org/html/rfc4178 +https://tools.ietf.org/html/rfc4234 +https://tools.ietf.org/html/rfc4279 +https://tools.ietf.org/html/rfc4346 +https://tools.ietf.org/html/rfc4347 +https://tools.ietf.org/html/rfc4492 +https://tools.ietf.org/html/rfc4512 +https://tools.ietf.org/html/rfc4647 +https://tools.ietf.org/html/rfc4785 +https://tools.ietf.org/html/rfc4960 +https://tools.ietf.org/html/rfc5054 +https://tools.ietf.org/html/rfc5061 +https://tools.ietf.org/html/rfc5084 +https://tools.ietf.org/html/rfc5246 +https://tools.ietf.org/html/rfc5280 +https://tools.ietf.org/html/rfc5288 +https://tools.ietf.org/html/rfc5289 +https://tools.ietf.org/html/rfc5469 +https://tools.ietf.org/html/rfc5487 +https://tools.ietf.org/html/rfc5489 +https://tools.ietf.org/html/rfc5639 +https://tools.ietf.org/html/rfc5646 +https://tools.ietf.org/html/rfc5649 +https://tools.ietf.org/html/rfc5746 +https://tools.ietf.org/html/rfc5932 +https://tools.ietf.org/html/rfc6209 +https://tools.ietf.org/html/rfc6347 +https://tools.ietf.org/html/rfc6367 +https://tools.ietf.org/html/rfc6454 +https://tools.ietf.org/html/rfc6455 +https://tools.ietf.org/html/rfc6655 +https://tools.ietf.org/html/rfc6931 +https://tools.ietf.org/html/rfc7230 +https://tools.ietf.org/html/rfc7231 +https://tools.ietf.org/html/rfc7251 +https://tools.ietf.org/html/rfc7292 +https://tools.ietf.org/html/rfc7507 +https://tools.ietf.org/html/rfc7539 +https://tools.ietf.org/html/rfc7540 +https://tools.ietf.org/html/rfc7748 +https://tools.ietf.org/html/rfc7905 +https://tools.ietf.org/html/rfc7919 +https://tools.ietf.org/html/rfc8017 +https://tools.ietf.org/html/rfc8018 +https://tools.ietf.org/html/rfc8032 +https://tools.ietf.org/html/rfc8103 +https://tools.ietf.org/html/rfc8353 +https://tools.ietf.org/html/rfc8422 +https://tools.ietf.org/html/rfc8446 +https://tools.ietf.org/html/rfc8554 +https://tools.ietf.org/id/draft-kaukonen-cipher-arcfour-03.txt +https://tools.ietf.org/rfc/rfc5280.txt +https://tools.ietf.org/rfc/rfc8017.txt +https://unicode.org/reports/tr31/ +https://unicode.org/reports/tr35/ +https://unicode.org/reports/tr35/tr35-dates.html +https://unicode.org/reports/tr35/tr35-numbers.html +https://unicode.org/reports/tr51/ +https://web.mit.edu/kerberos/ +https://webhome.phy.duke.edu/~rgb/General/dieharder.php +https://www.cipa.jp/std/documents/e/DC-008-2012_E.pdf +https://www.color.org +https://www.color.org/ICC1V42.pdf +https://www.iana.org/assignments/kerberos-parameters/kerberos-parameters.xhtml +https://www.iana.org/assignments/language-subtag-registry/language-subtag-registry +https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml +https://www.iana.org/time-zones +https://www.ietf.org/rfc/rfc2616.txt +https://www.ietf.org/rfc/rfc2818.txt +https://www.ietf.org/rfc/rfc6931.txt +https://www.ietf.org/rfc/rfc6943.html +https://www.iso.org/home.html +https://www.iso.org/iso-4217-currency-codes.html +https://www.iso.org/iso-8601-date-and-time-format.html +https://www.iso.org/standard/18114.html +https://www.itu.int/itudoc/itu-t/com16/tiff-fx/docs/tiff6.pdf +https://www.itu.int/rec/T-REC-X.509/en +https://www.netlib.org/fdlibm/ +https://www.oasis-open.org +https://www.oasis-open.org/committees/download.php/14809/xml-catalogs.html +https://www.oracle.com/java/javase/terms/license/java@@JAVASE_VERSION@@speclicense.html +https://www.oracle.com/java/technologies/a-swing-architecture.html +https://www.oracle.com/java/technologies/javase/seccodeguide.html +https://www.oracle.com/java/technologies/javase/training-support.html +https://www.oracle.com/pls/topic/lookup?ctx=en/java/javase&id=security_guide_implement_provider_jca +https://www.oracle.com/technetwork/java/javase/documentation/spec-136004.html +https://www.oracle.com/technetwork/java/javasebusiness/downloads/java-archive-downloads-java-plat-419418.html +https://www.oracle.com/technetwork/java/redist-137594.html +https://www.oracle.com/technetwork/java/seccodeguide-139067.html +https://www.owasp.org +https://www.rfc-editor.org/info/rfc1122 +https://www.rfc-editor.org/info/rfc1123 +https://www.rfc-editor.org/info/rfc1323 +https://www.rfc-editor.org/info/rfc1349 +https://www.rfc-editor.org/info/rfc1738 +https://www.rfc-editor.org/info/rfc1779 +https://www.rfc-editor.org/info/rfc1918 +https://www.rfc-editor.org/info/rfc1950 +https://www.rfc-editor.org/info/rfc1951 +https://www.rfc-editor.org/info/rfc1952 +https://www.rfc-editor.org/info/rfc2040 +https://www.rfc-editor.org/info/rfc2045 +https://www.rfc-editor.org/info/rfc2046 +https://www.rfc-editor.org/info/rfc2109 +https://www.rfc-editor.org/info/rfc2236 +https://www.rfc-editor.org/info/rfc2246 +https://www.rfc-editor.org/info/rfc2253 +https://www.rfc-editor.org/info/rfc2268 +https://www.rfc-editor.org/info/rfc2278 +https://www.rfc-editor.org/info/rfc2279 +https://www.rfc-editor.org/info/rfc2296 +https://www.rfc-editor.org/info/rfc2306 +https://www.rfc-editor.org/info/rfc2365 +https://www.rfc-editor.org/info/rfc2368 +https://www.rfc-editor.org/info/rfc2373 +https://www.rfc-editor.org/info/rfc2396 +https://www.rfc-editor.org/info/rfc2474 +https://www.rfc-editor.org/info/rfc2560 +https://www.rfc-editor.org/info/rfc2616 +https://www.rfc-editor.org/info/rfc2710 +https://www.rfc-editor.org/info/rfc2732 +https://www.rfc-editor.org/info/rfc2781 +https://www.rfc-editor.org/info/rfc2898 +https://www.rfc-editor.org/info/rfc2911 +https://www.rfc-editor.org/info/rfc2965 +https://www.rfc-editor.org/info/rfc3279 +https://www.rfc-editor.org/info/rfc3330 +https://www.rfc-editor.org/info/rfc3376 +https://www.rfc-editor.org/info/rfc3454 +https://www.rfc-editor.org/info/rfc3490 +https://www.rfc-editor.org/info/rfc3491 +https://www.rfc-editor.org/info/rfc3492 +https://www.rfc-editor.org/info/rfc3530 +https://www.rfc-editor.org/info/rfc3720 +https://www.rfc-editor.org/info/rfc3810 +https://www.rfc-editor.org/info/rfc3986 +https://www.rfc-editor.org/info/rfc4007 +https://www.rfc-editor.org/info/rfc4086 +https://www.rfc-editor.org/info/rfc4122 +https://www.rfc-editor.org/info/rfc4234 +https://www.rfc-editor.org/info/rfc4366 +https://www.rfc-editor.org/info/rfc4512 +https://www.rfc-editor.org/info/rfc4647 +https://www.rfc-editor.org/info/rfc4648 +https://www.rfc-editor.org/info/rfc5116 +https://www.rfc-editor.org/info/rfc5280 +https://www.rfc-editor.org/info/rfc5646 +https://www.rfc-editor.org/info/rfc5869 +https://www.rfc-editor.org/info/rfc5890 +https://www.rfc-editor.org/info/rfc6066 +https://www.rfc-editor.org/info/rfc7301 +https://www.rfc-editor.org/info/rfc7539 +https://www.rfc-editor.org/info/rfc790 +https://www.rfc-editor.org/info/rfc793 +https://www.rfc-editor.org/info/rfc8017 +https://www.rfc-editor.org/info/rfc8032 +https://www.rfc-editor.org/info/rfc822 +https://www.rfc-editor.org/info/rfc919 +https://www.rfc-editor.org/info/rfc9231 +https://www.rfc-editor.org/rfc/rfc2315.txt +https://www.rfc-editor.org/rfc/rfc5208.html +https://www.rfc-editor.org/rfc/rfc5280.html +https://www.rfc-editor.org/rfc/rfc5646 +https://www.rfc-editor.org/rfc/rfc5646.html +https://www.rfc-editor.org/rfc/rfc5869 +https://www.rfc-editor.org/rfc/rfc6943.html +https://www.rfc-editor.org/rfc/rfc8017 +https://www.rfc-editor.org/rfc/rfc8017.html +https://www.rfc-editor.org/rfc/rfc9180 +https://www.schneier.com/blowfish.html +https://www.secg.org/sec2-v2.pdf +https://www.unicode.org/reports/tr15 +https://www.unicode.org/reports/tr15/ +https://www.unicode.org/reports/tr18 +https://www.unicode.org/reports/tr24 +https://www.unicode.org/reports/tr27 +https://www.unicode.org/reports/tr29/ +https://www.unicode.org/reports/tr31 +https://www.unicode.org/reports/tr35 +https://www.unicode.org/reports/tr35/ +https://www.unicode.org/reports/tr35/tr35-collation.html +https://www.unicode.org/reports/tr35/tr35-dates.html +https://www.unicode.org/reports/tr35/tr35-general.html +https://www.unicode.org/reports/tr35/tr35.html +https://www.unicode.org/reports/tr36 +https://www.unicode.org/reports/tr44 +https://www.unicode.org/reports/tr44/ +https://www.usno.navy.mil/USNO +https://www.usno.navy.mil/USNO/time/master-clock/systems-of-time +https://www.w3.org +https://www.w3.org/Daemon/User/Config/Logging.html +https://www.w3.org/TR/1998/REC-html40-19980424/ +https://www.w3.org/TR/1999/REC-xpath-19991116/ +https://www.w3.org/TR/2001/REC-xml-c14n-20010315 +https://www.w3.org/TR/2002/REC-xml-exc-c14n-20020718/ +https://www.w3.org/TR/2002/REC-xmldsig-filter2-20021108/ +https://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html +https://www.w3.org/TR/CSS22 +https://www.w3.org/TR/CSS22/syndata.html +https://www.w3.org/TR/DOM-Level-3-XPath/ +https://www.w3.org/TR/NOTE-datetime +https://www.w3.org/TR/REC-CSS1 +https://www.w3.org/TR/REC-html32.html +https://www.w3.org/TR/REC-xml-names/ +https://www.w3.org/TR/html4 +https://www.w3.org/TR/html52 +https://www.w3.org/TR/html52/dom.html +https://www.w3.org/TR/html52/syntax.html +https://www.w3.org/TR/xml +https://www.w3.org/TR/xml-c14n11/ +https://www.w3.org/TR/xml/ +https://www.w3.org/TR/xmldsig-core/ +https://www.w3.org/TR/xmlschema-2 +https://www.w3.org/WAI/standards-guidelines/wcag/ +https://www.w3.org/XML/Schema +https://www.w3.org/XML/xml-names-19990114-errata.html +https://www.wapforum.org/what/technical/SPEC-WAESpec-19990524.pdf diff --git a/test/docs/jdk/javadoc/doccheck/checks/jdkCheckExtlinks.java b/test/docs/jdk/javadoc/doccheck/checks/jdkCheckExtlinks.java new file mode 100644 index 00000000000..846cf917c3a --- /dev/null +++ b/test/docs/jdk/javadoc/doccheck/checks/jdkCheckExtlinks.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8337109 + * @summary Check external links in the generated documentation + * @library /test/langtools/tools/lib ../../doccheck /test/lib ../../../../tools/tester + * @build DocTester toolbox.TestRunner + * @run main/othervm -Ddoccheck.checks=extlinks DocCheck + */ diff --git a/test/docs/jdk/javadoc/doccheck/checks/jdkCheckHtml.java b/test/docs/jdk/javadoc/doccheck/checks/jdkCheckHtml.java new file mode 100644 index 00000000000..3e9f3ab9f82 --- /dev/null +++ b/test/docs/jdk/javadoc/doccheck/checks/jdkCheckHtml.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8337109 + * @summary Check the html in the generated documentation + * @library /test/langtools/tools/lib ../../doccheck /test/lib ../../../../tools/tester + * @build DocTester toolbox.TestRunner + * @run main/othervm -Ddoccheck.checks=html DocCheck + */ diff --git a/test/docs/jdk/javadoc/doccheck/checks/jdkCheckLinks.java b/test/docs/jdk/javadoc/doccheck/checks/jdkCheckLinks.java new file mode 100644 index 00000000000..bd818923d9f --- /dev/null +++ b/test/docs/jdk/javadoc/doccheck/checks/jdkCheckLinks.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8337109 + * @summary Check Links in the generated documentation + * @library /test/langtools/tools/lib ../../doccheck /test/lib ../../../../tools/tester + * @build DocTester toolbox.TestRunner + * @run main/othervm -Ddoccheck.checks=links DocCheck + */ diff --git a/test/docs/jdk/javadoc/TestDocs.java b/test/docs/jdk/javadoc/doccheck/checks/jdkDoctypeBadcharsCheck.java similarity index 63% rename from test/docs/jdk/javadoc/TestDocs.java rename to test/docs/jdk/javadoc/doccheck/checks/jdkDoctypeBadcharsCheck.java index 3ccd89ab2e0..a0c145e2b79 100644 --- a/test/docs/jdk/javadoc/TestDocs.java +++ b/test/docs/jdk/javadoc/doccheck/checks/jdkDoctypeBadcharsCheck.java @@ -23,22 +23,9 @@ /* * @test - * @library /test/lib ../../tools/tester - * @build jtreg.SkippedException - * @summary example of a test on the generated documentation - * @run main TestDocs + * @bug 8337109 + * @summary Check doctype and character encoding in the generated documentation + * @library /test/langtools/tools/lib ../../doccheck /test/lib ../../../../tools/tester + * @build DocTester toolbox.TestRunner + * @run main/othervm -Ddoccheck.checks=doctype,badchars DocCheck */ - -import java.nio.file.Files; - -public class TestDocs { - public static void main(String... args) throws Exception { - var docs = DocTester.resolveDocs(); - System.err.println("Path to the docs is: " + docs); - System.err.println("Do docs exits?"); - System.err.println(Files.exists(docs)); - System.err.println("tidy location"); - System.err.println(System.getProperty("tidy")); - System.err.println("End of test"); - } -} diff --git a/test/docs/jdk/javadoc/doccheck/doccheckutils/Checker.java b/test/docs/jdk/javadoc/doccheck/doccheckutils/Checker.java new file mode 100644 index 00000000000..614c32105a6 --- /dev/null +++ b/test/docs/jdk/javadoc/doccheck/doccheckutils/Checker.java @@ -0,0 +1,39 @@ +/* + * 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 doccheckutils; + +import java.io.Closeable; + +/** + * Base class for {@link FileChecker file checkers} and + */ +public interface Checker extends Closeable { + + /** + * Writes a report at the end of a run, to summarize the results of the + * checking done by this checker. + */ + void report(); + + boolean isOK(); +} diff --git a/test/docs/jdk/javadoc/doccheck/doccheckutils/FileChecker.java b/test/docs/jdk/javadoc/doccheck/doccheckutils/FileChecker.java new file mode 100644 index 00000000000..4577c3b2b26 --- /dev/null +++ b/test/docs/jdk/javadoc/doccheck/doccheckutils/FileChecker.java @@ -0,0 +1,30 @@ +/* + * 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 doccheckutils; + +import java.nio.file.Path; +import java.util.List; + +public interface FileChecker extends Checker { + void checkFiles(List files); +} diff --git a/test/docs/jdk/javadoc/doccheck/doccheckutils/FileProcessor.java b/test/docs/jdk/javadoc/doccheck/doccheckutils/FileProcessor.java new file mode 100644 index 00000000000..6ae3a473bdb --- /dev/null +++ b/test/docs/jdk/javadoc/doccheck/doccheckutils/FileProcessor.java @@ -0,0 +1,64 @@ +/* + * 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 doccheckutils; + +import java.io.IOException; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.ArrayList; +import java.util.List; + +public class FileProcessor { + private final List files; + + public FileProcessor() { + files = new ArrayList<>(); + } + + public List getFiles() { + return files; + } + + public void processFiles(Path directory) { + try { + Files.walkFileTree(directory, new SimpleFileVisitor() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + if (file.toString().endsWith(".html")) + files.add(file); + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { + return FileVisitResult.CONTINUE; + } + }); + } catch (IOException e) { + throw new RuntimeException(); + } + } +} diff --git a/test/docs/jdk/javadoc/doccheck/doccheckutils/HtmlChecker.java b/test/docs/jdk/javadoc/doccheck/doccheckutils/HtmlChecker.java new file mode 100644 index 00000000000..e27c21ea212 --- /dev/null +++ b/test/docs/jdk/javadoc/doccheck/doccheckutils/HtmlChecker.java @@ -0,0 +1,94 @@ +/* + * 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 doccheckutils; + +import java.nio.file.Path; +import java.util.Map; + +/** + * Base class for HTML checkers. + *

+ * For details on HTML syntax and the terms used in this API, see + * W3C The HTML syntax. + */ +public interface HtmlChecker extends Checker { + /** + * Starts checking a new file, + *

+ * The file becomes the current file until {@link #endFile endFile} + * is called. + * + * @param path the file. + */ + void startFile(Path path); + + /** + * Ends checking the current file. + */ + void endFile(); + + /** + * Checks the content of a {@code } declaration in the + * current file. + * + * @param line the line number on which the declaration was found + * @param attrs the content of the declaration + */ + void xml(int line, Map attrs); + + /** + * Checks the content of a {@code } declaration in the + * current file. + * + * @param line the line number on which the declaration was found + * @param docType the content of the declaration + */ + void docType(int line, String docType); + + /** + * Checks the start of an HTML tag in the current file. + * + * @param line the line number on which the start tag for an element was found + * @param name the name of the tag + * @param attrs the attributes of the tag + * @param selfClosing whether the tag is self-closing + */ + void startElement(int line, String name, Map attrs, boolean selfClosing); + + /** + * Checks the end of an HTML tag in the current file. + * + * @param line the line number on which the end tag for an element was found + * @param name the name of the tag + */ + void endElement(int line, String name); + + /** + * Checks the content appearing in between HTML tags. + * + * @param line the line number on which the content was found + * @param content the content + */ + default void content(int line, String content) { + } +} diff --git a/test/docs/jdk/javadoc/doccheck/doccheckutils/HtmlFileChecker.java b/test/docs/jdk/javadoc/doccheck/doccheckutils/HtmlFileChecker.java new file mode 100644 index 00000000000..e9ba1643c50 --- /dev/null +++ b/test/docs/jdk/javadoc/doccheck/doccheckutils/HtmlFileChecker.java @@ -0,0 +1,389 @@ +/* + * 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 doccheckutils; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.charset.CharsetDecoder; +import java.nio.charset.CodingErrorAction; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.regex.Pattern; + +/** + * Reads an HTML file, and calls a series of{@link HtmlChecker HTML checkers} + * for the HTML constructs found therein. + */ +public class HtmlFileChecker implements FileChecker { + private final CharsetDecoder decoder = StandardCharsets.UTF_8.newDecoder() + .onMalformedInput(CodingErrorAction.IGNORE) + .onUnmappableCharacter(CodingErrorAction.IGNORE); + + private final Log log; + private final HtmlChecker htmlChecker; + private Path path; + private BufferedReader in; + private int ch; + private int lineNumber; + private boolean inScript; + private boolean xml; + + public HtmlFileChecker(HtmlChecker htmlChecker, Path BaseDir) { + this.log = new Log(); + log.setBaseDirectory(BaseDir); + this.htmlChecker = htmlChecker; + } + + @Override + public void checkFiles(List files) { + for (Path file : files) { + read(file); + } + } + + @Override + public void report() { + System.err.println(log); + } + + @Override + public void close() throws IOException { +// report(); + htmlChecker.close(); + } + + private void read(Path path) { + try (BufferedReader r = new BufferedReader( + new InputStreamReader(Files.newInputStream(path), decoder))) { + this.path = path; + this.in = r; + StringBuilder content = new StringBuilder(); + + startFile(path); + try { + lineNumber = 1; + xml = false; + nextChar(); + + while (ch != -1) { + if (ch == '<') { + content(content.toString()); + content.setLength(0); + html(); + } else { + content.append((char) ch); + if (ch == '\n') { + content(content.toString()); + content.setLength(0); + } + nextChar(); + } + } + } finally { + endFile(); + } + } catch (IOException e) { + log.log(path, lineNumber, e); + } catch (Throwable t) { + log.log(path, lineNumber, t); + log.log(String.valueOf(t)); + } + } + + private void startFile(Path path) { + htmlChecker.startFile(path); + } + + private void endFile() { + htmlChecker.endFile(); + } + + private void docType(String s) { + htmlChecker.docType(lineNumber, s); + } + + private void startElement(String name, Map attrs, boolean selfClosing) { + htmlChecker.startElement(lineNumber, name, attrs, selfClosing); + } + + private void endElement(String name) { + htmlChecker.endElement(lineNumber, name); + } + + private void content(String s) { + htmlChecker.content(lineNumber, s); + } + + private void nextChar() throws IOException { + ch = in.read(); + if (ch == '\n') + lineNumber++; + } + + /** + * Read the start or end of an HTML tag, or an HTML comment + * {@literal } or {@literal } + * + * @throws IOException if there is a problem reading the file + */ + protected void html() throws IOException { + nextChar(); + if (isIdentifierStart((char) ch)) { + String name = readIdentifier().toLowerCase(Locale.US); + Map attrs = htmlAttrs(); + if (attrs != null) { + boolean selfClosing = false; + if (ch == '/') { + nextChar(); + selfClosing = true; + } + if (ch == '>') { + nextChar(); + startElement(name, attrs, selfClosing); + if (name.equals("script")) { + inScript = true; + } + return; + } + } + } else if (ch == '/') { + nextChar(); + if (isIdentifierStart((char) ch)) { + String name = readIdentifier().toLowerCase(Locale.US); + skipWhitespace(); + if (ch == '>') { + nextChar(); + endElement(name); + if (name.equals("script")) { + inScript = false; + } + return; + } + } + } else if (ch == '!') { + nextChar(); + if (ch == '-') { + nextChar(); + if (ch == '-') { + nextChar(); + while (ch != -1) { + int dash = 0; + while (ch == '-') { + dash++; + nextChar(); + } + // Strictly speaking, a comment should not contain "--" + // so dash > 2 is an error, dash == 2 implies ch == '>' + // See http://www.w3.org/TR/html-markup/syntax.html#syntax-comments + // for more details. + if (dash >= 2 && ch == '>') { + nextChar(); + return; + } + + nextChar(); + } + } + } else if (ch == '[') { + nextChar(); + if (ch == 'C') { + nextChar(); + if (ch == 'D') { + nextChar(); + if (ch == 'A') { + nextChar(); + if (ch == 'T') { + nextChar(); + if (ch == 'A') { + nextChar(); + if (ch == '[') { + while (true) { + nextChar(); + if (ch == ']') { + nextChar(); + if (ch == ']') { + nextChar(); + if (ch == '>') { + nextChar(); + return; + } + } + } + } + + } + } + } + } + } + } + } else { + StringBuilder sb = new StringBuilder(); + while (ch != -1 && ch != '>') { + sb.append((char) ch); + nextChar(); + } + Pattern p = Pattern.compile("(?is)doctype\\s+html\\s?.*"); + String s = sb.toString(); + if (p.matcher(s).matches()) { + xml = s.contains("XHTML"); + docType(s); + return; + } + } + } else if (ch == '?') { + nextChar(); + if (ch == 'x') { + nextChar(); + if (ch == 'm') { + nextChar(); + if (ch == 'l') { + nextChar(); + if (ch == '?') { + nextChar(); + if (ch == '>') { + nextChar(); + xml = true; + return; + } + } + } + } + + } + } + + if (!inScript) { + log.log(path, lineNumber, "bad html"); + } + } + + /** + * Read a series of HTML attributes, terminated by {@literal > }. + * Each attribute is of the form {@literal identifier[=value] }. + * "value" may be unquoted, single-quoted, or double-quoted. + */ + protected Map htmlAttrs() throws IOException { + Map map = new LinkedHashMap<>(); + skipWhitespace(); + + while (isIdentifierStart((char) ch)) { + String name = readAttributeName().toLowerCase(Locale.US); + skipWhitespace(); + String value = null; + if (ch == '=') { + nextChar(); + skipWhitespace(); + if (ch == '\'' || ch == '"') { + char quote = (char) ch; + nextChar(); + StringBuilder sb = new StringBuilder(); + while (ch != -1 && ch != quote) { +// if (ch == '\n') { +// error(path, lineNumber, "unterminated string"); +// // No point trying to read more. +// // In fact, all attrs get discarded by the caller +// // and superseded by a malformed.html node because +// // the html tag itself is not terminated correctly. +// break loop; +// } + sb.append((char) ch); + nextChar(); + } + value = sb.toString() // hack to replace common entities + .replace("<", "<") + .replace(">", ">") + .replace("&", "&"); + nextChar(); + } else { + StringBuilder sb = new StringBuilder(); + while (ch != -1 && !isUnquotedAttrValueTerminator((char) ch)) { + sb.append((char) ch); + nextChar(); + } + value = sb.toString(); + } + skipWhitespace(); + } + map.put(name, value); + } + + return map; + } + + protected boolean isIdentifierStart(char ch) { + return Character.isUnicodeIdentifierStart(ch); + } + + protected String readIdentifier() throws IOException { + StringBuilder sb = new StringBuilder(); + sb.append((char) ch); + nextChar(); + while (ch != -1 && Character.isUnicodeIdentifierPart(ch)) { + sb.append((char) ch); + nextChar(); + } + return sb.toString(); + } + + protected String readAttributeName() throws IOException { + StringBuilder sb = new StringBuilder(); + sb.append((char) ch); + nextChar(); + while ((ch != -1 && Character.isUnicodeIdentifierPart(ch)) + || ch == '-' + || (xml && ch == ':')) { + sb.append((char) ch); + nextChar(); + } + return sb.toString(); + } + + protected boolean isWhitespace(char ch) { + return Character.isWhitespace(ch); + } + + protected void skipWhitespace() throws IOException { + while (isWhitespace((char) ch)) { + nextChar(); + } + } + + protected boolean isUnquotedAttrValueTerminator(char ch) { + return switch (ch) { + case '\f', '\n', '\r', '\t', ' ', '"', '\'', '`', '=', '<', '>' -> true; + default -> false; + }; + } + + @Override + public boolean isOK() { + throw new UnsupportedOperationException(); + } +} diff --git a/test/docs/jdk/javadoc/doccheck/doccheckutils/Log.java b/test/docs/jdk/javadoc/doccheck/doccheckutils/Log.java new file mode 100644 index 00000000000..9626c59e9ca --- /dev/null +++ b/test/docs/jdk/javadoc/doccheck/doccheckutils/Log.java @@ -0,0 +1,95 @@ +/* + * 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 doccheckutils; + +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; + +public class Log { + private final ArrayList errors; + + private Path baseDir; + + public Log() { + errors = new ArrayList<>(); + } + + public List getErrors() { + return errors; + } + + public void log(Path path, int line, String message, Object... args) { + errors.add(formatErrorMessage(path, line, message, args)); + } + + + public String formatErrorMessage(Path path, int line, String message, Object... args) { + return path + ":" + line + ": " + formatErrorMessage(message, args); + } + + public String formatErrorMessage(Path path, int line, Throwable t) { + return path + ":" + line + ": " + t; + } + + public String formatErrorMessage(Path path, Throwable t) { + return path + ": " + t; + } + + + public String formatErrorMessage(String message, Object... args) { + return String.format(message, args); + } + + public void log(String message) { + errors.add(message); + } + + public void log(Path path, int lineNumber, String s, int errorsOnLine) { + log(formatErrorMessage(path, lineNumber, s, errorsOnLine)); + } + + public void log(Path path, int line, Throwable t) { + log(formatErrorMessage(path, line, t)); + } + + public void log(Path path, Throwable t) { + log(formatErrorMessage(path, t)); + } + + public void log(String message, Object... args) { + log(formatErrorMessage(message, args)); + } + + public void setBaseDirectory(Path baseDir) { + this.baseDir = baseDir.toAbsolutePath(); + } + + public Path relativize(Path path) { + return baseDir != null && path.startsWith(baseDir) ? baseDir.relativize(path) : path; + } + + public boolean noErrors() { + return errors.isEmpty(); + } +} diff --git a/test/docs/jdk/javadoc/doccheck/doccheckutils/checkers/BadCharacterChecker.java b/test/docs/jdk/javadoc/doccheck/doccheckutils/checkers/BadCharacterChecker.java new file mode 100644 index 00000000000..f979c34c9a3 --- /dev/null +++ b/test/docs/jdk/javadoc/doccheck/doccheckutils/checkers/BadCharacterChecker.java @@ -0,0 +1,158 @@ +/* + * 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 doccheckutils.checkers; + +import doccheckutils.FileChecker; +import doccheckutils.Log; + +import java.io.*; +import java.nio.charset.Charset; +import java.nio.charset.CharsetDecoder; +import java.nio.charset.CodingErrorAction; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.text.MessageFormat; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Checks the contents of an HTML file for bad/unmappable characters. + *

+ * The file encoding is determined from the file contents. + */ +public class BadCharacterChecker implements FileChecker, AutoCloseable { + private static final Pattern doctype = Pattern.compile("(?i)"); + private static final Pattern metaCharset = Pattern.compile("(?i)"); + private static final Pattern metaContentType = Pattern.compile("(?i)"); + private final Log errors; + private int files = 0; + private int badFiles = 0; + + public BadCharacterChecker() { + errors = new Log(); + } + + public void checkFile(Path path) { + files++; + boolean ok = true; + try (InputStream in = new BufferedInputStream(Files.newInputStream(path))) { + CharsetDecoder d = getCharset(in).newDecoder() + .onMalformedInput(CodingErrorAction.REPLACE) + .onUnmappableCharacter(CodingErrorAction.REPLACE); + BufferedReader r = new BufferedReader(new InputStreamReader(in, d)); + int lineNumber = 0; + String line; + try { + while ((line = r.readLine()) != null) { + lineNumber++; + int errorsOnLine = 0; + for (int i = 0; i < line.length(); i++) { + char ch = line.charAt(i); + if (ch == 0xFFFD) { + errorsOnLine++; + } + } + if (errorsOnLine > 0) { + errors.log(path, lineNumber, "found %d invalid characters", errorsOnLine); + ok = false; + } + } + } catch (IOException e) { + errors.log(path, lineNumber, e); + ok = false; + + } + } catch (IOException e) { + errors.log(path, e); + ok = false; + } + if (!ok) + badFiles++; + } + + @Override + public void checkFiles(List files) { + for (Path file : files) { + checkFile(file); + } + } + + private Charset getCharset(InputStream in) throws IOException { + CharsetDecoder initial = StandardCharsets.US_ASCII.newDecoder() + .onMalformedInput(CodingErrorAction.REPLACE) + .onUnmappableCharacter(CodingErrorAction.REPLACE); + + in.mark(1024); + try { + BufferedReader r = new BufferedReader(new InputStreamReader(in, initial)); + char[] buf = new char[1024]; + int n = r.read(buf, 0, buf.length); + String head = new String(buf, 0, n); + boolean html5 = doctype.matcher(head).find(); + Matcher m1 = metaCharset.matcher(head); + if (m1.find()) { + return Charset.forName(m1.group(1)); + } + Matcher m2 = metaContentType.matcher(head); + if (m2.find()) { + return Charset.forName(m2.group(1)); + } + return html5 ? StandardCharsets.UTF_8 : StandardCharsets.ISO_8859_1; + } finally { + in.reset(); + } + } + + @Override + public void report() { + if (!errors.noErrors() && files > 0) { + System.err.println("Bad characters found in the generated HTML"); + + System.err.println(MessageFormat.format( + """ + Bad Characters Report + {0} files read + {1} files contained bad characters" + {2} bad characters or other errors found + """, + files, badFiles, files)); + + for (String s : errors.getErrors()) { + System.err.println(s); + } + throw new RuntimeException("Bad character found in the generated HTML"); + } + } + + @Override + public boolean isOK() { + return errors.noErrors(); + } + + @Override + public void close() { + report(); + } +} diff --git a/test/docs/jdk/javadoc/doccheck/doccheckutils/checkers/DocTypeChecker.java b/test/docs/jdk/javadoc/doccheck/doccheckutils/checkers/DocTypeChecker.java new file mode 100644 index 00000000000..1f53318de18 --- /dev/null +++ b/test/docs/jdk/javadoc/doccheck/doccheckutils/checkers/DocTypeChecker.java @@ -0,0 +1,159 @@ +/* + * 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 doccheckutils.checkers; + +import doccheckutils.HtmlChecker; +import doccheckutils.Log; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Checks the DocType declared at the head of an HTML file. + * + * @see + * W3C HTML5 8.1.1 The DOCTYPE + */ +public class DocTypeChecker implements HtmlChecker { + private final Log log; + private final Map counts = new HashMap<>(); + private int html5; + private int html5_legacy; + private int xml; + private int other; + + private Path path; + + public DocTypeChecker() { + log = new Log(); + } + + @Override + public void startFile(Path path) { + this.path = path; + } + + @Override + public void endFile() { + } + + @Override + public void xml(int line, Map attrs) { + xml++; + } + + @Override + public void docType(int line, String docType) { + if (docType.equalsIgnoreCase("doctype html")) { + html5++; + } else { + Pattern p = Pattern.compile("(?i)doctype" + + "\\s+html" + + "\\s+([a-z]+)" + + "\\s+(?:\"([^\"]+)\"|'([^']+)')" + + "(?:\\s+(?:\"([^\"]+)\"|'([^']+)'))?" + + "\\s*"); + Matcher m = p.matcher(docType); + if (m.matches()) { + // See http://www.w3.org/tr/html52/syntax.html#the-doctype + if (m.group(1).equalsIgnoreCase("system") + && m.group(2).equals("about:legacy-compat")) { + html5_legacy++; + } else { + String version = m.group(2); + List allowedVersions = List.of( + "-//W3C//DTD XHTML 1.0 Strict//EN" + ); + if (allowedVersions.stream().noneMatch(v -> v.equals(version))) { + log.log(path, line, "unexpected doctype: " + version); + } + counts.put(version, counts.getOrDefault(version, 0) + 1); + } + } else { + log.log(path, line, "doctype not recognized: " + docType); + other++; + } + } + } + + @Override + public void startElement(int line, String name, Map attrs, boolean selfClosing) { + } + + @Override + public void endElement(int line, String name) { + } + + @Override + public void report() { + log.log("DocType Report"); + if (xml > 0) { + log.log("%6d: XHTML%n", xml); + } + if (html5 > 0) { + log.log("%6d: HTML5%n", html5); + } + if (html5_legacy > 0) { + log.log("%6d: HTML5 (legacy)%n", html5_legacy); + } + + Map> sortedCounts = new TreeMap<>(Comparator.reverseOrder()); + + for (Map.Entry e : counts.entrySet()) { + String s = e.getKey(); + Integer n = e.getValue(); + Set set = sortedCounts.computeIfAbsent(n, k -> new TreeSet<>()); + set.add(s); + } + + for (Map.Entry> e : sortedCounts.entrySet()) { + for (String p : e.getValue()) { + log.log("%6d: %s%n", e.getKey(), p); + } + } + + if (other > 0) { + log.log("%6d: other/unrecognized%n", other); + } + + for (var line : log.getErrors()) { + System.err.println(line); + } + } + + @Override + public boolean isOK() { + return counts.isEmpty() && (other == 0); + } + + @Override + public void close() { + if (!isOK()) { + report(); + throw new RuntimeException("Found HTML files with missing doctype declaration"); + } + } +} diff --git a/test/docs/jdk/javadoc/doccheck/doccheckutils/checkers/ExtLinkChecker.java b/test/docs/jdk/javadoc/doccheck/doccheckutils/checkers/ExtLinkChecker.java new file mode 100644 index 00000000000..7e6c5a8ed5a --- /dev/null +++ b/test/docs/jdk/javadoc/doccheck/doccheckutils/checkers/ExtLinkChecker.java @@ -0,0 +1,220 @@ +/* + * 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 doccheckutils.checkers; + + +import doccheckutils.HtmlChecker; +import doccheckutils.Log; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.text.MessageFormat; +import java.util.*; +import java.util.stream.Collectors; + +/** + * Checks the external links referenced in HTML files. + */ +public class ExtLinkChecker implements HtmlChecker, AutoCloseable { + private static final Path testBasePath = Path.of(System.getProperty("test.src")); + private static final Set extLinks = new HashSet<>(); + + private static final String currentVersion = String.valueOf(Runtime.version().feature()); + + static { + String input = null; + try { + input = Files.readString(testBasePath.getParent().resolve("ExtLinksJdk.txt")); + } catch (IOException e) { + throw new RuntimeException(e); + } + extLinks.addAll(input.lines() + .filter(line -> !line.startsWith("#")) + .map(line -> line.replaceAll("\\@\\@JAVASE_VERSION\\@\\@", currentVersion)) + .collect(Collectors.toUnmodifiableSet())); + } + + private final Log log; + private final Map> allURIs; + private int badURIs; + private Path currFile; + + public ExtLinkChecker() { + this.log = new Log(); + allURIs = new TreeMap<>(); + } + + @Override + public void startFile(Path path) { + currFile = path.toAbsolutePath().normalize(); + } + + @Override + public void endFile() { + } + + @Override + public void xml(int line, Map attrs) { + } + + @Override + public void docType(int line, String doctype) { + } + + @Override + @SuppressWarnings("fallthrough") + public void startElement(int line, String name, Map attrs, boolean selfClosing) { + switch (name) { + case "a": + case "link": + String href = attrs.get("href"); + if (href != null) { + foundReference(line, href); + } + break; + } + } + + @Override + public void endElement(int line, String name) { + } + + private void foundReference(int line, String ref) { + try { + String uriPath = ref; + String fragment = null; + + // The checker runs into a problem with links that have more than one hash character. + // You cannot create a URI unless the second hash is escaped. + + int firstHashIndex = ref.indexOf('#'); + int lastHashIndex = ref.lastIndexOf('#'); + if (firstHashIndex != -1 && firstHashIndex != lastHashIndex) { + uriPath = ref.substring(0, firstHashIndex); + fragment = ref.substring(firstHashIndex + 1).replace("#", "%23"); + } else if (firstHashIndex != -1) { + uriPath = ref.substring(0, firstHashIndex); + fragment = ref.substring(firstHashIndex + 1); + } + + URI uri = new URI(uriPath); + if (fragment != null) { + uri = new URI(uri + "#" + fragment); + } + + if (uri.isAbsolute()) { + if (Objects.equals(uri.getScheme(), "javascript")) { + // ignore JavaScript URIs + return; + } + String rawFragment = uri.getRawFragment(); + URI noFrag = new URI(uri.toString().replaceAll("#\\Q" + rawFragment + "\\E$", "")); + allURIs.computeIfAbsent(noFrag, _ -> new LinkedHashSet<>()).add(currFile); + } + } catch (URISyntaxException e) { + log.log(currFile, line, "invalid URI: " + e); + } + } + + @Override + public void report() { + checkURIs(); + } + + @Override + public boolean isOK() { + return badURIs == 0; + } + + @Override + public void close() { + report(); + } + + private void checkURIs() { + System.err.println("ExtLinkChecker: checking external links"); + allURIs.forEach(this::checkURI); + System.err.println("ExtLinkChecker: finished checking external links"); + } + + private void checkURI(URI uri, Set files) { + try { + switch (uri.getScheme()) { + case "ftp": + case "http": + case "https": + isVettedLink(uri, files); + break; + default: + warning(files, uri); + } + } catch (Throwable t) { + badURIs++; + error(files, uri, t); + } + } + + private void isVettedLink(URI uri, Set files) { + if (!extLinks.contains(uri.toString())) { + System.err.println(MessageFormat.format(""" + The external link {0} needs to be added to the whitelist test/docs/jdk/javadoc/doccheck/ExtLinksJdk.txt in order to be checked regularly\s + The link is present in: + {1}\n + """, uri, files.stream().map(Path::toString).collect(Collectors.joining("\n ")))); + } + } + + private void warning(Set files, Object... args) { + Iterator iter = files.iterator(); + Path first = iter.next(); + log.log(String.valueOf(first), "URI not supported: %s", args); + reportAlsoFoundIn(iter); + } + + private void error(Set files, Object... args) { + Iterator iter = files.iterator(); + Path first = iter.next(); + log.log(String.valueOf(first), "Exception accessing uri: %s%n [%s]", args); + reportAlsoFoundIn(iter); + } + + private void reportAlsoFoundIn(Iterator iter) { + int MAX_EXTRA = 10; + int n = 0; + while (iter.hasNext()) { + log.log(" Also found in %s", log.relativize(iter.next())); + if (n++ == MAX_EXTRA) { + int rest = 0; + while (iter.hasNext()) { + iter.next(); + rest++; + } + log.log(" ... and %d more", rest); + } + } + } +} diff --git a/test/docs/jdk/javadoc/doccheck/doccheckutils/checkers/LinkChecker.java b/test/docs/jdk/javadoc/doccheck/doccheckutils/checkers/LinkChecker.java new file mode 100644 index 00000000000..62ead5a25d3 --- /dev/null +++ b/test/docs/jdk/javadoc/doccheck/doccheckutils/checkers/LinkChecker.java @@ -0,0 +1,440 @@ +/* + * 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 doccheckutils.checkers; + + +import doccheckutils.HtmlChecker; +import doccheckutils.Log; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.*; + +/** + * Checks the links defined by and referenced in HTML files. + */ +public class LinkChecker implements HtmlChecker { + + private final Log log; + private final Map allFiles; + private final Map allURIs; + // left for debugging + private final boolean checkInwardReferencesOnly = false; + private int files; + private int links; + private int duplicateIds; + private int missingFiles; + private int missingIds; + private int badSchemes; + private Path currFile; + private IDTable currTable; + private boolean html5; + public LinkChecker() { + this.log = new Log(); + allFiles = new HashMap<>(); + allURIs = new HashMap<>(); + } + + public void setBaseDir(Path dir) { + log.setBaseDirectory(dir); + } + + @Override + public void startFile(Path path) { + currFile = path.toAbsolutePath().normalize(); + currTable = allFiles.computeIfAbsent(currFile, p -> new IDTable(log.relativize(p))); + html5 = false; + files++; + } + + @Override + public void endFile() { + currTable.check(); + } + + + //unused + public List getUncheckedFiles() { + return allFiles.entrySet().stream() + .filter(e -> !e.getValue().checked + && e.getKey().toString().endsWith(".html") + && Files.exists(e.getKey())) + .map(Map.Entry::getKey) + .toList(); + } + + public List getMissingFiles() { + return allFiles.keySet().stream() + .filter(idTable -> !Files.exists(idTable)).toList(); + } + + @Override + public void xml(int line, Map attrs) { + } + + @Override + public void docType(int line, String doctype) { + html5 = doctype.matches("(?i)<\\?doctype\\s+html>"); + } + + @Override + @SuppressWarnings("fallthrough") + public void startElement(int line, String name, Map attrs, boolean selfClosing) { + switch (name) { + case "a": + String nameAttr = html5 ? null : attrs.get("name"); + if (nameAttr != null) { + foundAnchor(line, nameAttr); + } + // fallthrough + case "link": + String href = attrs.get("href"); + if (href != null && !checkInwardReferencesOnly) { + foundReference(line, href); + } + break; + } + + String idAttr = attrs.get("id"); + if (idAttr != null) { + foundAnchor(line, idAttr); + } + } + + @Override + public void endElement(int line, String name) { + } + + @Override + public void content(int line, String content) { + HtmlChecker.super.content(line, content); + } + + @Override + public void report() { + List pathList = getMissingFiles(); + log.log(""); + log.log("Link Checker Report"); + + if (!pathList.isEmpty()) { + log.log(""); + log.log("Missing files: (" + pathList.size() + ")"); + pathList.stream() + .sorted() + .forEach(this::reportMissingFile); + } + + int anchors = 0; + for (IDTable t : allFiles.values()) { + anchors += (int) t.map.values().stream() + .filter(e -> !e.getReferences().isEmpty()) + .count(); + } + for (IDTable t : allURIs.values()) { + anchors += (int) t.map.values().stream() + .filter(e -> !e.references.isEmpty()) + .count(); + } + + log.log("Checked " + files + " files."); + log.log("Found " + links + " references to " + anchors + " anchors " + + "in " + allFiles.size() + " files and " + allURIs.size() + " other URIs."); + if (!pathList.isEmpty()) { + log.log("%6d missing files", pathList.size()); + } + if (duplicateIds > 0) { + log.log("%6d duplicate ids", duplicateIds); + + } + if (missingIds > 0) { + log.log("%6d missing ids", missingIds); + + } + + Map hostCounts = new TreeMap<>(new HostComparator()); + for (URI uri : allURIs.keySet()) { + String host = uri.getHost(); + if (host != null) { + hostCounts.put(host, hostCounts.computeIfAbsent(host, h -> 0) + 1); + } + } + +// if (hostCounts.size() > 0) { +// log.log(""); +// log.log("Hosts"); +// hostCounts.forEach((h, n) -> log.log("%6d %s", n, h)); +// } + + + for (String message : log.getErrors()) { + System.err.println(message); + } + + } + + private void reportMissingFile(Path file) { + log.log(log.relativize(file).toString()); + IDTable table = allFiles.get(file); + Set refs = new TreeSet<>(); + for (IDInfo id : table.map.values()) { + if (id.references != null) { + for (Position ref : id.references) { + refs.add(ref.path); + } + } + } + int n = 0; + int MAX_REFS = 10; + for (Path ref : refs) { + log.log(" in " + log.relativize(ref)); + if (++n == MAX_REFS) { + log.log(" ... and %d more", refs.size() - n); + break; + } + } + missingFiles++; + } + + @Override + public boolean isOK() { + return duplicateIds == 0 + && missingIds == 0 + && missingFiles == 0 + && badSchemes == 0; + } + + @Override + public void close() { + report(); + if (!isOK()) { + throw new RuntimeException( + "LinkChecker encountered errors. Duplicate IDs: " + + duplicateIds + ", Missing IDs: " + missingIds + + ", Missing Files: " + missingFiles + ", Bad Schemes: " + badSchemes); + } + } + + private void foundAnchor(int line, String name) { + currTable.addID(line, name); + } + + private void foundReference(int line, String ref) { + links++; + try { + String uriPath = ref; + String fragment = null; + + // The checker runs into a problem with links that have more than one hash character. + // You cannot create a URI unless the second hash is escaped. + + int firstHashIndex = ref.indexOf('#'); + int lastHashIndex = ref.lastIndexOf('#'); + if (firstHashIndex != -1 && firstHashIndex != lastHashIndex) { + uriPath = ref.substring(0, firstHashIndex); + fragment = ref.substring(firstHashIndex + 1).replace("#", "%23"); + } else if (firstHashIndex != -1) { + uriPath = ref.substring(0, firstHashIndex); + fragment = ref.substring(firstHashIndex + 1); + } + + URI uri = new URI(uriPath); + if (fragment != null) { + uri = new URI(uri + "#" + fragment); + } + + if (uri.isAbsolute()) { + foundReference(line, uri); + } else { + Path p; + String resolvedUriPath = uri.getPath(); + if (resolvedUriPath == null || resolvedUriPath.isEmpty()) { + p = currFile; + } else { + p = currFile.getParent().resolve(resolvedUriPath).normalize(); + } + + if (fragment != null && !fragment.isEmpty()) { + foundReference(line, p, fragment); + } + } + } catch (URISyntaxException e) { + System.err.println("Failed to create URI: " + ref); + log.log(currFile, line, "invalid URI: " + e); + } + } + + + private void foundReference(int line, Path p, String fragment) { + IDTable t = allFiles.computeIfAbsent(p, key -> new IDTable(log.relativize(key))); + t.addReference(fragment, currFile, line); + } + + private void foundReference(int line, URI uri) { + if (!isSchemeOK(uri.getScheme()) && !checkInwardReferencesOnly) { + log.log(currFile, line, "bad scheme in URI"); + badSchemes++; + } + + String fragment = uri.getRawFragment(); + if (fragment != null && !fragment.isEmpty()) { + try { + URI noFrag = new URI(uri.toString().replaceAll("#\\Q" + fragment + "\\E$", "")); + IDTable t = allURIs.computeIfAbsent(noFrag, IDTable::new); + t.addReference(fragment, currFile, line); + } catch (URISyntaxException e) { + throw new Error(e); + } + } + } + + private boolean isSchemeOK(String uriScheme) { + if (uriScheme == null) { + return true; + } + + return switch (uriScheme) { + case "ftp", "http", "https", "javascript" -> true; + default -> false; + }; + } + + static class Position implements Comparable { + Path path; + int line; + + Position(Path path, int line) { + this.path = path; + this.line = line; + } + + @Override + public int compareTo(Position o) { + int v = path.compareTo(o.path); + return v != 0 ? v : Integer.compare(line, o.line); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } else if (obj == null || getClass() != obj.getClass()) { + return false; + } else { + final Position other = (Position) obj; + return Objects.equals(this.path, other.path) + && this.line == other.line; + } + } + + @Override + public int hashCode() { + return Objects.hashCode(path) * 37 + line; + } + } + + static class IDInfo { + boolean declared; + Set references; + + Set getReferences() { + return references == null ? Collections.emptySet() : references; + } + } + + static class HostComparator implements Comparator { + @Override + public int compare(String h1, String h2) { + List l1 = new ArrayList<>(Arrays.asList(h1.split("\\."))); + Collections.reverse(l1); + String r1 = String.join(".", l1); + List l2 = new ArrayList<>(Arrays.asList(h2.split("\\."))); + Collections.reverse(l2); + String r2 = String.join(".", l2); + return r1.compareTo(r2); + } + } + + class IDTable { + private final Map map = new HashMap<>(); + private final String pathOrURI; + private boolean checked; + + IDTable(Path path) { + this.pathOrURI = path.toString(); + } + + IDTable(URI uri) { + this.pathOrURI = uri.toString(); + } + + void addID(int line, String name) { + if (checked) { + throw new IllegalStateException("Adding ID after file has been"); + } + Objects.requireNonNull(name); + IDInfo info = map.computeIfAbsent(name, _ -> new IDInfo()); + if (info.declared) { + if (info.references != null || !checkInwardReferencesOnly) { + // don't report error if we're only checking inbound references + // and there are no references to this ID. + log.log(log.relativize(currFile), line, "name already declared: " + name); + duplicateIds++; + } + } else { + info.declared = true; + } + } + + void addReference(String name, Path from, int line) { + if (checked) { + if (name != null) { + IDInfo id = map.get(name); + if (id == null || !id.declared) { + log.log(log.relativize(from), line, "id not found: " + this.pathOrURI + "#" + name); + } + } + } else { + IDInfo id = map.computeIfAbsent(name, x -> new IDInfo()); + if (id.references == null) { + id.references = new TreeSet<>(); + } + id.references.add(new Position(from, line)); + } + } + + void check() { + map.forEach((name, id) -> { + if (name != null && !id.declared) { + for (Position ref : id.references) { + log.log(log.relativize(ref.path), ref.line, "id not found: " + this.pathOrURI + "#" + name); + } + missingIds++; + } + }); + checked = true; + } + } +} diff --git a/test/docs/jdk/javadoc/doccheck/doccheckutils/checkers/TidyChecker.java b/test/docs/jdk/javadoc/doccheck/doccheckutils/checkers/TidyChecker.java new file mode 100644 index 00000000000..727e90a76e3 --- /dev/null +++ b/test/docs/jdk/javadoc/doccheck/doccheckutils/checkers/TidyChecker.java @@ -0,0 +1,259 @@ +/* + * 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 doccheckutils.checkers; + + +import doccheckutils.FileChecker; +import doccheckutils.Log; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class TidyChecker implements FileChecker, AutoCloseable { + private final Path TIDY; + final Map counts = new HashMap<>(); + final Pattern okPattern = Pattern.compile("No warnings or errors were found."); + final Pattern countPattern = Pattern.compile("([0-9]+) warnings, ([0-9]+) errors were found!.*?(Not all warnings/errors were shown.)?"); + final Pattern countPattern2 = Pattern.compile("Tidy found ([0-9]+) warning[s]? and ([0-9]+) error[s]?!.*?(Not all warnings/errors were shown.)?"); + final Pattern cssPattern = Pattern.compile("You are recommended to use CSS.*"); + final Pattern guardPattern = Pattern.compile("(line [0-9]+ column [0-9]+ - |[^:]+:[0-9]+:[0-9]+: )(Error|Warning):.*"); + + final Pattern[] patterns = { + Pattern.compile(".*Error: <.*> is not recognized!"), + Pattern.compile(".*Error: missing quote mark for attribute value"), + Pattern.compile(".*Warning: '<' \\+ '/' \\+ letter not allowed here"), + Pattern.compile(".*Warning: <.*> anchor \".*\" already defined"), + Pattern.compile(".*Warning: <.*> attribute \".*\" has invalid value \".*\""), + Pattern.compile(".*Warning: <.*> attribute \".*\" lacks value"), + Pattern.compile(".*Warning: <.*> attribute \".*\" lacks value"), + Pattern.compile(".*Warning: <.*> attribute with missing trailing quote mark"), + Pattern.compile(".*Warning: <.*> dropping value \".*\" for repeated attribute \".*\""), + Pattern.compile(".*Warning: <.*> inserting \".*\" attribute"), + Pattern.compile(".*Warning: <.*> is probably intended as "), + Pattern.compile(".*Warning: <.*> isn't allowed in <.*> elements"), + Pattern.compile(".*Warning: <.*> lacks \".*\" attribute"), + Pattern.compile(".*Warning: <.*> missing '>' for end of tag"), + Pattern.compile(".*Warning: <.*> proprietary attribute \".*\""), + Pattern.compile(".*Warning: <.*> unexpected or duplicate quote mark"), + Pattern.compile(".*Warning: id and name attribute value mismatch"), + Pattern.compile(".*Warning: cannot copy name attribute to id"), + Pattern.compile(".*Warning: escaping malformed URI reference"), + Pattern.compile(".*Warning:

proprietary attribute \"pre\""), + Pattern.compile(".*Warning: discarding unexpected <.*>"), + Pattern.compile(".*Warning: discarding unexpected "), + Pattern.compile(".*Warning: entity \".*\" doesn't end in ';'"), + Pattern.compile(".*Warning: inserting implicit <.*>"), + Pattern.compile(".*Warning: inserting missing 'title' element"), + Pattern.compile(".*Warning: missing declaration"), + Pattern.compile(".*Warning: missing <.*>"), + Pattern.compile(".*Warning: missing before <.*>"), + Pattern.compile(".*Warning: nested emphasis <.*>"), + Pattern.compile(".*Warning: plain text isn't allowed in <.*> elements"), + Pattern.compile(".*Warning: removing whitespace preceding XML Declaration"), + Pattern.compile(".*Warning: replacing

(by|with)
"), + Pattern.compile(".*Warning: replacing invalid numeric character reference .*"), + Pattern.compile(".*Warning: replacing obsolete element

with <pre>"), + Pattern.compile(".*Warning: replacing unexpected .* (by|with) </.*>"), + Pattern.compile(".*Warning: trimming empty <.*>"), + Pattern.compile(".*Warning: unescaped & or unknown entity \".*\""), + Pattern.compile(".*Warning: unescaped & which should be written as &amp;"), + Pattern.compile(".*Warning: using <br> in place of <p>"), + Pattern.compile(".*Warning: <.*> element removed from HTML5"), + Pattern.compile(".*Warning: <.*> attribute \".*\" not allowed for HTML5"), + Pattern.compile(".*Warning: The summary attribute on the <table> element is obsolete in HTML5"), + Pattern.compile(".*Warning: replacing invalid UTF-8 bytes \\(char. code U\\+.*\\)") + }; + private final Log errors; + private int files = 0; + private int ok; + private int warns; + private int errs; + private int css; + private int overflow; + + public TidyChecker() { + TIDY = initTidy(); + errors = new Log(); + } + + @Override + public void checkFiles(List<Path> sb) { + files += sb.size(); + try { + for (int i = 0; i < sb.size(); i += 1024) { + List<String> command = new ArrayList<>(); + command.add(TIDY.toString()); + command.add("-q"); + command.add("-e"); + command.add("--gnu-emacs"); + command.add("true"); + List<Path> sublist = sb.subList(i, Math.min(i + 1024, sb.size())); + for (Path p : sublist) { + command.add(p.toString()); + } + Process p = new ProcessBuilder() + .command(command) + .redirectErrorStream(true) + .start(); + try (BufferedReader r = + new BufferedReader(new InputStreamReader(p.getInputStream(), StandardCharsets.UTF_8))) { + String line; + while ((line = r.readLine()) != null) { + checkLine(line); + } + } + } + } catch (IOException e) { + throw new RuntimeException(); + } + } + + private Path initTidy() { + Path tidyExePath; + String tidyProperty = System.getProperty("tidy"); + if (tidyProperty != null) { + tidyExePath = Path.of(tidyProperty); + if (!Files.exists(tidyExePath)) { + System.err.println("tidy not found: " + tidyExePath); + } + if (!Files.isExecutable(tidyExePath)) { + System.err.println("tidy not executable: " + tidyExePath); + } + } else { + boolean isWindows = System.getProperty("os.name") + .toLowerCase(Locale.US) + .startsWith("windows"); + String tidyExe = isWindows ? "tidy.exe" : "tidy"; + Optional<Path> p = Stream.of(System.getenv("PATH") + .split(File.pathSeparator)) + .map(Path::of) + .map(d -> d.resolve(tidyExe)) + .filter(Files::exists) + .filter(Files::isExecutable) + .findFirst(); + if (p.isPresent()) { + tidyExePath = p.get(); + } else { + System.err.println("tidy not found on PATH"); + return Path.of("tidy"); //non-null placeholder return; exception would be better + } + } + + try { + Process p = new ProcessBuilder() + .command(tidyExePath.toString(), "-version") + .redirectErrorStream(true) + .start(); + try (BufferedReader r = + new BufferedReader(new InputStreamReader(p.getInputStream(), StandardCharsets.UTF_8))) { + List<String> lines = r.lines().collect(Collectors.toList()); + // Look for a line containing "version" and a dotted identifier beginning 5. + // If not found, look for known old/bad versions, to report in error message + Pattern version = Pattern.compile("version.* [5678]\\.\\d+(\\.\\d+)"); + if (lines.stream().noneMatch(line -> version.matcher(line).find())) { + Pattern oldVersion = Pattern.compile("2006"); // 2006 implies old macOS version + String lineSep = System.lineSeparator(); + String message = lines.stream().anyMatch(line -> oldVersion.matcher(line).find()) + ? "old version of 'tidy' found on the PATH\n" + : "could not determine the version of 'tidy' on the PATH\n"; + System.err.println(message + String.join(lineSep, lines)); + } + } + } catch (IOException e) { + System.err.println("Could not execute 'tidy -version': " + e); + } + + return tidyExePath; + } + + @Override + public void report() { + if (files > 0) { + System.err.println("Tidy found errors in the generated HTML"); + if (!errors.noErrors()) { + for (String s : errors.getErrors()) { + System.err.println(s); + } + System.err.println("Tidy output end."); + System.err.println(); + System.err.println(); + throw new RuntimeException("Tidy found errors in the generated HTML"); + } + } + } + + @Override + public boolean isOK() { + return (ok == files) + && (overflow == 0) + && (errs == 0) + && (warns == 0) + && (css == 0); + } + + void checkLine(String line) { + Matcher m; + if (okPattern.matcher(line).matches()) { + ok++; + } else if ((m = countPattern.matcher(line)).matches() || (m = countPattern2.matcher(line)).matches()) { + warns += Integer.parseInt(m.group(1)); + errs += Integer.parseInt(m.group(2)); + if (m.group(3) != null) + overflow++; + } else if (guardPattern.matcher(line).matches()) { + boolean found = false; + for (Pattern p : patterns) { + if (p.matcher(line).matches()) { + errors.log("%s", line); + found = true; + count(p); + break; + } + } + if (!found) + errors.log("unrecognized line: " + line); + } else if (cssPattern.matcher(line).matches()) { + css++; + } + } + + void count(Pattern p) { + Integer i = counts.get(p); + counts.put(p, (i == null) ? 1 : i + 1); + } + + @Override + public void close() { + report(); + } +} From 68c6623d384dad8f9f436336e80530c351ae2a38 Mon Sep 17 00:00:00 2001 From: Bradford Wetmore <wetmore@openjdk.org> Date: Mon, 23 Dec 2024 19:05:07 +0000 Subject: [PATCH 24/36] 8345840: Add missing TLS handshake messages to SSLHandshake.java Reviewed-by: jnimeh --- .../sun/security/ssl/SSLHandshake.java | 30 ++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/src/java.base/share/classes/sun/security/ssl/SSLHandshake.java b/src/java.base/share/classes/sun/security/ssl/SSLHandshake.java index 4c931c93fea..7c78f6c3005 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLHandshake.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLHandshake.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,15 @@ import java.util.Map; import javax.net.ssl.SSLException; +/** + * An enum of the defined TLS handshake message types. + * <p> + * These are defined in the IANA TLS Parameters. + * https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-7 + * <p> + * Most of these come from the SLS/TLS specs in RFCs 6601/2246/4346/8446 and + * friends. Others are called out where defined. + */ enum SSLHandshake implements SSLConsumer, HandshakeProducer { @SuppressWarnings({"unchecked", "rawtypes"}) HELLO_REQUEST ((byte)0x00, "hello_request", @@ -81,6 +90,10 @@ enum SSLHandshake implements SSLConsumer, HandshakeProducer { ) }), + // Even though there is a TLS HandshakeType entry for + // hello_retry_request_RESERVED (0x06), the TLSv1.3 (RFC 8446) + // HelloRetryRequest is actually a ServerHello with a specific Random value + // (Section 4.1.3). @SuppressWarnings({"unchecked", "rawtypes"}) HELLO_RETRY_REQUEST ((byte)0x02, "hello_retry_request", new Map.Entry[] { @@ -130,6 +143,7 @@ enum SSLHandshake implements SSLConsumer, HandshakeProducer { ProtocolVersion.PROTOCOLS_TO_12 ) }), + END_OF_EARLY_DATA ((byte)0x05, "end_of_early_data"), @SuppressWarnings({"unchecked", "rawtypes"}) @@ -147,6 +161,10 @@ enum SSLHandshake implements SSLConsumer, HandshakeProducer { ) }), + // RFC 9147 - DTLS 1.3 + REQUEST_CONNECTION_ID ((byte)0x09, "request_connection_id"), + NEW_CONNECTION_ID ((byte)0x0a, "new_connection_id"), + @SuppressWarnings({"unchecked", "rawtypes"}) CERTIFICATE ((byte)0x0B, "certificate", new Map.Entry[] { @@ -285,6 +303,9 @@ enum SSLHandshake implements SSLConsumer, HandshakeProducer { ) }), + // RFC 9261 - Exported Authenticators + CLIENT_CERTIFICATE_REQUEST ((byte)0x11, "client_certificate_request"), + @SuppressWarnings({"unchecked", "rawtypes"}) FINISHED ((byte)0x14, "finished", new Map.Entry[] { @@ -347,6 +368,13 @@ enum SSLHandshake implements SSLConsumer, HandshakeProducer { ProtocolVersion.PROTOCOLS_OF_13 ) }), + + // RFC 8879 - TLS Certificate Compression + COMPRESSED_CERTIFICATE ((byte)0x19, "compressed_certificate"), + + // RFC 8870 - Encrypted Key Transport for DTLS/Secure RTP + EKT_KEY ((byte)0x1A, "ekt_key"), + MESSAGE_HASH ((byte)0xFE, "message_hash"), NOT_APPLICABLE ((byte)0xFF, "not_applicable"); From 62a4544bb76aa339a8129f81d2527405a1b1e7e3 Mon Sep 17 00:00:00 2001 From: Swati Sharma <swati.sharma@intel.com> Date: Mon, 23 Dec 2024 19:16:18 +0000 Subject: [PATCH 25/36] 8205051: Poor Performance with UseNUMA when cpu and memory nodes are misaligned Co-authored-by: Derek White <drwhite@openjdk.org> Reviewed-by: sjohanss, tschatzl --- src/hotspot/os/linux/os_linux.cpp | 34 +++++++++++++++++++++------- src/hotspot/os/linux/os_linux.hpp | 37 ++++++++++++++++++++++++++----- 2 files changed, 58 insertions(+), 13 deletions(-) diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index ac943096917..094ca2bf2fc 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -3247,6 +3247,8 @@ bool os::Linux::libnuma_init() { libnuma_dlsym(handle, "numa_set_bind_policy"))); set_numa_bitmask_isbitset(CAST_TO_FN_PTR(numa_bitmask_isbitset_func_t, libnuma_dlsym(handle, "numa_bitmask_isbitset"))); + set_numa_bitmask_equal(CAST_TO_FN_PTR(numa_bitmask_equal_func_t, + libnuma_dlsym(handle, "numa_bitmask_equal"))); set_numa_distance(CAST_TO_FN_PTR(numa_distance_func_t, libnuma_dlsym(handle, "numa_distance"))); set_numa_get_membind(CAST_TO_FN_PTR(numa_get_membind_func_t, @@ -3257,6 +3259,8 @@ bool os::Linux::libnuma_init() { libnuma_dlsym(handle, "numa_move_pages"))); set_numa_set_preferred(CAST_TO_FN_PTR(numa_set_preferred_func_t, libnuma_dlsym(handle, "numa_set_preferred"))); + set_numa_get_run_node_mask(CAST_TO_FN_PTR(numa_get_run_node_mask_func_t, + libnuma_v2_dlsym(handle, "numa_get_run_node_mask"))); if (numa_available() != -1) { set_numa_all_nodes((unsigned long*)libnuma_dlsym(handle, "numa_all_nodes")); @@ -3264,6 +3268,7 @@ bool os::Linux::libnuma_init() { set_numa_nodes_ptr((struct bitmask **)libnuma_dlsym(handle, "numa_nodes_ptr")); set_numa_interleave_bitmask(_numa_get_interleave_mask()); set_numa_membind_bitmask(_numa_get_membind()); + set_numa_cpunodebind_bitmask(_numa_get_run_node_mask()); // Create an index -> node mapping, since nodes are not always consecutive _nindex_to_node = new (mtInternal) GrowableArray<int>(0, mtInternal); rebuild_nindex_to_node_map(); @@ -3440,9 +3445,11 @@ os::Linux::numa_interleave_memory_func_t os::Linux::_numa_interleave_memory; os::Linux::numa_interleave_memory_v2_func_t os::Linux::_numa_interleave_memory_v2; os::Linux::numa_set_bind_policy_func_t os::Linux::_numa_set_bind_policy; os::Linux::numa_bitmask_isbitset_func_t os::Linux::_numa_bitmask_isbitset; +os::Linux::numa_bitmask_equal_func_t os::Linux::_numa_bitmask_equal; os::Linux::numa_distance_func_t os::Linux::_numa_distance; os::Linux::numa_get_membind_func_t os::Linux::_numa_get_membind; os::Linux::numa_get_interleave_mask_func_t os::Linux::_numa_get_interleave_mask; +os::Linux::numa_get_run_node_mask_func_t os::Linux::_numa_get_run_node_mask; os::Linux::numa_move_pages_func_t os::Linux::_numa_move_pages; os::Linux::numa_set_preferred_func_t os::Linux::_numa_set_preferred; os::Linux::NumaAllocationPolicy os::Linux::_current_numa_policy; @@ -3451,6 +3458,7 @@ struct bitmask* os::Linux::_numa_all_nodes_ptr; struct bitmask* os::Linux::_numa_nodes_ptr; struct bitmask* os::Linux::_numa_interleave_bitmask; struct bitmask* os::Linux::_numa_membind_bitmask; +struct bitmask* os::Linux::_numa_cpunodebind_bitmask; bool os::pd_uncommit_memory(char* addr, size_t size, bool exec) { uintptr_t res = (uintptr_t) ::mmap(addr, size, PROT_NONE, @@ -4475,19 +4483,19 @@ void os::Linux::numa_init() { // bitmask when externally configured to run on all or fewer nodes. if (!Linux::libnuma_init()) { - FLAG_SET_ERGO(UseNUMA, false); - FLAG_SET_ERGO(UseNUMAInterleaving, false); // Also depends on libnuma. + disable_numa("Failed to initialize libnuma"); } else { - if ((Linux::numa_max_node() < 1) || Linux::is_bound_to_single_node()) { - // If there's only one node (they start from 0) or if the process - // is bound explicitly to a single node using membind, disable NUMA - UseNUMA = false; + Linux::set_configured_numa_policy(Linux::identify_numa_policy()); + if (Linux::numa_max_node() < 1) { + disable_numa("Only a single NUMA node is available"); + } else if (Linux::is_bound_to_single_mem_node()) { + disable_numa("The process is bound to a single NUMA node"); + } else if (Linux::mem_and_cpu_node_mismatch()) { + disable_numa("The process memory and cpu node configuration does not match"); } else { LogTarget(Info,os) log; LogStream ls(log); - Linux::set_configured_numa_policy(Linux::identify_numa_policy()); - struct bitmask* bmp = Linux::_numa_membind_bitmask; const char* numa_mode = "membind"; @@ -4525,6 +4533,16 @@ void os::Linux::numa_init() { } } +void os::Linux::disable_numa(const char* reason) { + if ((UseNUMA && FLAG_IS_CMDLINE(UseNUMA)) || + (UseNUMAInterleaving && FLAG_IS_CMDLINE(UseNUMAInterleaving))) { + // Only issue a warning if the user explicitly asked for NUMA support + log_warning(os)("NUMA support disabled: %s", reason); + } + FLAG_SET_ERGO(UseNUMA, false); + FLAG_SET_ERGO(UseNUMAInterleaving, false); +} + #if defined(IA32) && !defined(ZERO) /* * Work-around (execute code at a high address) for broken NX emulation using CS limit, diff --git a/src/hotspot/os/linux/os_linux.hpp b/src/hotspot/os/linux/os_linux.hpp index a2a13baa24f..1cd44513889 100644 --- a/src/hotspot/os/linux/os_linux.hpp +++ b/src/hotspot/os/linux/os_linux.hpp @@ -193,6 +193,7 @@ class os::Linux { private: static void numa_init(); + static void disable_numa(const char* reason); typedef int (*sched_getcpu_func_t)(void); typedef int (*numa_node_to_cpus_func_t)(int node, unsigned long *buffer, int bufferlen); typedef int (*numa_node_to_cpus_v2_func_t)(int node, void *mask); @@ -204,10 +205,12 @@ class os::Linux { typedef void (*numa_interleave_memory_v2_func_t)(void *start, size_t size, struct bitmask* mask); typedef struct bitmask* (*numa_get_membind_func_t)(void); typedef struct bitmask* (*numa_get_interleave_mask_func_t)(void); + typedef struct bitmask* (*numa_get_run_node_mask_func_t)(void); typedef long (*numa_move_pages_func_t)(int pid, unsigned long count, void **pages, const int *nodes, int *status, int flags); typedef void (*numa_set_preferred_func_t)(int node); typedef void (*numa_set_bind_policy_func_t)(int policy); typedef int (*numa_bitmask_isbitset_func_t)(struct bitmask *bmp, unsigned int n); + typedef int (*numa_bitmask_equal_func_t)(struct bitmask *bmp1, struct bitmask *bmp2); typedef int (*numa_distance_func_t)(int node1, int node2); static sched_getcpu_func_t _sched_getcpu; @@ -221,8 +224,10 @@ class os::Linux { static numa_interleave_memory_v2_func_t _numa_interleave_memory_v2; static numa_set_bind_policy_func_t _numa_set_bind_policy; static numa_bitmask_isbitset_func_t _numa_bitmask_isbitset; + static numa_bitmask_equal_func_t _numa_bitmask_equal; static numa_distance_func_t _numa_distance; static numa_get_membind_func_t _numa_get_membind; + static numa_get_run_node_mask_func_t _numa_get_run_node_mask; static numa_get_interleave_mask_func_t _numa_get_interleave_mask; static numa_move_pages_func_t _numa_move_pages; static numa_set_preferred_func_t _numa_set_preferred; @@ -231,6 +236,7 @@ class os::Linux { static struct bitmask* _numa_nodes_ptr; static struct bitmask* _numa_interleave_bitmask; static struct bitmask* _numa_membind_bitmask; + static struct bitmask* _numa_cpunodebind_bitmask; static void set_sched_getcpu(sched_getcpu_func_t func) { _sched_getcpu = func; } static void set_numa_node_to_cpus(numa_node_to_cpus_func_t func) { _numa_node_to_cpus = func; } @@ -243,8 +249,10 @@ class os::Linux { static void set_numa_interleave_memory_v2(numa_interleave_memory_v2_func_t func) { _numa_interleave_memory_v2 = func; } static void set_numa_set_bind_policy(numa_set_bind_policy_func_t func) { _numa_set_bind_policy = func; } static void set_numa_bitmask_isbitset(numa_bitmask_isbitset_func_t func) { _numa_bitmask_isbitset = func; } + static void set_numa_bitmask_equal(numa_bitmask_equal_func_t func) { _numa_bitmask_equal = func; } static void set_numa_distance(numa_distance_func_t func) { _numa_distance = func; } static void set_numa_get_membind(numa_get_membind_func_t func) { _numa_get_membind = func; } + static void set_numa_get_run_node_mask(numa_get_run_node_mask_func_t func) { _numa_get_run_node_mask = func; } static void set_numa_get_interleave_mask(numa_get_interleave_mask_func_t func) { _numa_get_interleave_mask = func; } static void set_numa_move_pages(numa_move_pages_func_t func) { _numa_move_pages = func; } static void set_numa_set_preferred(numa_set_preferred_func_t func) { _numa_set_preferred = func; } @@ -253,6 +261,7 @@ class os::Linux { static void set_numa_nodes_ptr(struct bitmask **ptr) { _numa_nodes_ptr = (ptr == nullptr ? nullptr : *ptr); } static void set_numa_interleave_bitmask(struct bitmask* ptr) { _numa_interleave_bitmask = ptr ; } static void set_numa_membind_bitmask(struct bitmask* ptr) { _numa_membind_bitmask = ptr ; } + static void set_numa_cpunodebind_bitmask(struct bitmask* ptr) { _numa_cpunodebind_bitmask = ptr ; } static int sched_getcpu_syscall(void); enum NumaAllocationPolicy{ @@ -358,21 +367,26 @@ class os::Linux { } return false; } - // Check if bound to only one numa node. - // Returns true if bound to a single numa node, otherwise returns false. - static bool is_bound_to_single_node() { + // Check if memory is bound to only one numa node. + // Returns true if memory is bound to a single numa node, otherwise returns false. + static bool is_bound_to_single_mem_node() { int nodes = 0; unsigned int node = 0; unsigned int highest_node_number = 0; - if (_numa_membind_bitmask != nullptr && _numa_max_node != nullptr && _numa_bitmask_isbitset != nullptr) { + struct bitmask* mem_nodes_bitmask = Linux::_numa_membind_bitmask; + if (Linux::is_running_in_interleave_mode()) { + mem_nodes_bitmask = Linux::_numa_interleave_bitmask; + } + + if (mem_nodes_bitmask != nullptr && _numa_max_node != nullptr && _numa_bitmask_isbitset != nullptr) { highest_node_number = _numa_max_node(); } else { return false; } for (node = 0; node <= highest_node_number; node++) { - if (_numa_bitmask_isbitset(_numa_membind_bitmask, node)) { + if (_numa_bitmask_isbitset(mem_nodes_bitmask, node)) { nodes++; } } @@ -383,6 +397,19 @@ class os::Linux { return false; } } + // Check if cpu and memory nodes are aligned, returns true if nodes misalign + static bool mem_and_cpu_node_mismatch() { + struct bitmask* mem_nodes_bitmask = Linux::_numa_membind_bitmask; + if (Linux::is_running_in_interleave_mode()) { + mem_nodes_bitmask = Linux::_numa_interleave_bitmask; + } + + if (mem_nodes_bitmask == nullptr || Linux::_numa_cpunodebind_bitmask == nullptr) { + return false; + } + + return !_numa_bitmask_equal(mem_nodes_bitmask, Linux::_numa_cpunodebind_bitmask); + } static const GrowableArray<int>* numa_nindex_to_node() { return _nindex_to_node; From 1a32654faf6f6f0256fd7f42e6351adf914d8337 Mon Sep 17 00:00:00 2001 From: Nizar Benalla <nbenalla@openjdk.org> Date: Tue, 24 Dec 2024 18:23:14 +0000 Subject: [PATCH 26/36] 8346295: Update --release 24 symbol information for JDK 24 build 29 Reviewed-by: liach --- src/jdk.compiler/share/data/symbols/java.base-O.sym.txt | 4 +++- src/jdk.compiler/share/data/symbols/java.se-O.sym.txt | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/jdk.compiler/share/data/symbols/java.base-O.sym.txt b/src/jdk.compiler/share/data/symbols/java.base-O.sym.txt index dae8317f73b..e3a1eb04b46 100644 --- a/src/jdk.compiler/share/data/symbols/java.base-O.sym.txt +++ b/src/jdk.compiler/share/data/symbols/java.base-O.sym.txt @@ -27,7 +27,7 @@ # ########################################################## # module name java.base -header exports java/io,java/lang,java/lang/annotation,java/lang/classfile,java/lang/classfile/attribute,java/lang/classfile/constantpool,java/lang/classfile/instruction,java/lang/constant,java/lang/foreign,java/lang/invoke,java/lang/module,java/lang/ref,java/lang/reflect,java/lang/runtime,java/math,java/net,java/net/spi,java/nio,java/nio/channels,java/nio/channels/spi,java/nio/charset,java/nio/charset/spi,java/nio/file,java/nio/file/attribute,java/nio/file/spi,java/security,java/security/cert,java/security/interfaces,java/security/spec,java/text,java/text/spi,java/time,java/time/chrono,java/time/format,java/time/temporal,java/time/zone,java/util,java/util/concurrent,java/util/concurrent/atomic,java/util/concurrent/locks,java/util/function,java/util/jar,java/util/random,java/util/regex,java/util/spi,java/util/stream,java/util/zip,javax/crypto,javax/crypto/interfaces,javax/crypto/spec,javax/net,javax/net/ssl,javax/security/auth,javax/security/auth/callback,javax/security/auth/login,javax/security/auth/spi,javax/security/auth/x500,javax/security/cert,jdk/internal/event[jdk.jfr],jdk/internal/javac[java.compiler\u005C;u002C;java.desktop\u005C;u002C;java.se\u005C;u002C;jdk.compiler\u005C;u002C;jdk.incubator.vector\u005C;u002C;jdk.jartool\u005C;u002C;jdk.jdeps\u005C;u002C;jdk.jfr\u005C;u002C;jdk.jlink\u005C;u002C;jdk.jshell],jdk/internal/vm/vector[jdk.incubator.vector] extraModulePackages jdk/internal/access/foreign,jdk/internal/classfile/impl,jdk/internal/constant,jdk/internal/foreign/abi,jdk/internal/foreign/abi/aarch64/linux,jdk/internal/foreign/abi/aarch64/macos,jdk/internal/foreign/abi/aarch64/windows,jdk/internal/foreign/abi/fallback,jdk/internal/foreign/abi/ppc64/aix,jdk/internal/foreign/abi/ppc64/linux,jdk/internal/foreign/abi/riscv64/linux,jdk/internal/foreign/abi/s390/linux,jdk/internal/foreign/abi/x64/sysv,jdk/internal/foreign/abi/x64/windows,jdk/internal/foreign/layout,sun/nio/ch,sun/net,jdk/internal/foreign,jdk/internal/foreign,sun/net,sun/nio/ch uses java/lang/System$LoggerFinder,java/net/ContentHandlerFactory,java/net/spi/InetAddressResolverProvider,java/net/spi/URLStreamHandlerProvider,java/nio/channels/spi/AsynchronousChannelProvider,java/nio/channels/spi/SelectorProvider,java/nio/charset/spi/CharsetProvider,java/nio/file/spi/FileSystemProvider,java/nio/file/spi/FileTypeDetector,java/security/Provider,java/text/spi/BreakIteratorProvider,java/text/spi/CollatorProvider,java/text/spi/DateFormatProvider,java/text/spi/DateFormatSymbolsProvider,java/text/spi/DecimalFormatSymbolsProvider,java/text/spi/NumberFormatProvider,java/time/chrono/AbstractChronology,java/time/chrono/Chronology,java/time/zone/ZoneRulesProvider,java/util/spi/CalendarDataProvider,java/util/spi/CalendarNameProvider,java/util/spi/CurrencyNameProvider,java/util/spi/LocaleNameProvider,java/util/spi/ResourceBundleControlProvider,java/util/spi/ResourceBundleProvider,java/util/spi/TimeZoneNameProvider,java/util/spi/ToolProvider,javax/security/auth/spi/LoginModule,jdk/internal/io/JdkConsoleProvider,jdk/internal/logger/DefaultLoggerFinder,sun/text/spi/JavaTimeDateTimePatternProvider,sun/util/locale/provider/LocaleDataMetaInfo,sun/util/resources/LocaleData$CommonResourceBundleProvider,sun/util/resources/LocaleData$SupplementaryResourceBundleProvider,sun/util/spi/CalendarProvider provides interface\u0020;java/nio/file/spi/FileSystemProvider\u0020;impls\u0020;jdk/internal/jrtfs/JrtFileSystemProvider target macos-aarch64 flags 8000 +header exports java/io,java/lang,java/lang/annotation,java/lang/classfile,java/lang/classfile/attribute,java/lang/classfile/constantpool,java/lang/classfile/instruction,java/lang/constant,java/lang/foreign,java/lang/invoke,java/lang/module,java/lang/ref,java/lang/reflect,java/lang/runtime,java/math,java/net,java/net/spi,java/nio,java/nio/channels,java/nio/channels/spi,java/nio/charset,java/nio/charset/spi,java/nio/file,java/nio/file/attribute,java/nio/file/spi,java/security,java/security/cert,java/security/interfaces,java/security/spec,java/text,java/text/spi,java/time,java/time/chrono,java/time/format,java/time/temporal,java/time/zone,java/util,java/util/concurrent,java/util/concurrent/atomic,java/util/concurrent/locks,java/util/function,java/util/jar,java/util/random,java/util/regex,java/util/spi,java/util/stream,java/util/zip,javax/crypto,javax/crypto/interfaces,javax/crypto/spec,javax/net,javax/net/ssl,javax/security/auth,javax/security/auth/callback,javax/security/auth/login,javax/security/auth/spi,javax/security/auth/x500,javax/security/cert,jdk/internal/event[jdk.jfr],jdk/internal/javac[java.compiler\u005C;u002C;java.desktop\u005C;u002C;jdk.compiler\u005C;u002C;jdk.incubator.vector\u005C;u002C;jdk.jartool\u005C;u002C;jdk.jdeps\u005C;u002C;jdk.jfr\u005C;u002C;jdk.jlink\u005C;u002C;jdk.jshell],jdk/internal/vm/vector[jdk.incubator.vector] extraModulePackages jdk/internal/access/foreign,jdk/internal/classfile/impl,jdk/internal/constant,jdk/internal/foreign/abi,jdk/internal/foreign/abi/aarch64/linux,jdk/internal/foreign/abi/aarch64/macos,jdk/internal/foreign/abi/aarch64/windows,jdk/internal/foreign/abi/fallback,jdk/internal/foreign/abi/ppc64/aix,jdk/internal/foreign/abi/ppc64/linux,jdk/internal/foreign/abi/riscv64/linux,jdk/internal/foreign/abi/s390/linux,jdk/internal/foreign/abi/x64/sysv,jdk/internal/foreign/abi/x64/windows,jdk/internal/foreign/layout,sun/nio/ch,sun/net,jdk/internal/foreign,jdk/internal/foreign,sun/net,sun/nio/ch uses java/lang/System$LoggerFinder,java/net/ContentHandlerFactory,java/net/spi/InetAddressResolverProvider,java/net/spi/URLStreamHandlerProvider,java/nio/channels/spi/AsynchronousChannelProvider,java/nio/channels/spi/SelectorProvider,java/nio/charset/spi/CharsetProvider,java/nio/file/spi/FileSystemProvider,java/nio/file/spi/FileTypeDetector,java/security/Provider,java/text/spi/BreakIteratorProvider,java/text/spi/CollatorProvider,java/text/spi/DateFormatProvider,java/text/spi/DateFormatSymbolsProvider,java/text/spi/DecimalFormatSymbolsProvider,java/text/spi/NumberFormatProvider,java/time/chrono/AbstractChronology,java/time/chrono/Chronology,java/time/zone/ZoneRulesProvider,java/util/spi/CalendarDataProvider,java/util/spi/CalendarNameProvider,java/util/spi/CurrencyNameProvider,java/util/spi/LocaleNameProvider,java/util/spi/ResourceBundleControlProvider,java/util/spi/ResourceBundleProvider,java/util/spi/TimeZoneNameProvider,java/util/spi/ToolProvider,javax/security/auth/spi/LoginModule,jdk/internal/io/JdkConsoleProvider,jdk/internal/logger/DefaultLoggerFinder,sun/text/spi/JavaTimeDateTimePatternProvider,sun/util/locale/provider/LocaleDataMetaInfo,sun/util/resources/LocaleData$CommonResourceBundleProvider,sun/util/resources/LocaleData$SupplementaryResourceBundleProvider,sun/util/spi/CalendarProvider provides interface\u0020;java/nio/file/spi/FileSystemProvider\u0020;impls\u0020;jdk/internal/jrtfs/JrtFileSystemProvider target macos-aarch64 flags 8000 class name java/io/BufferedInputStream -method name read descriptor ()I @@ -970,9 +970,11 @@ header extends java/lang/Object implements java/lang/classfile/ClassFileTransfor class name java/lang/classfile/CompoundElement header extends java/lang/Object implements java/lang/classfile/ClassFileElement,java/lang/Iterable sealed true permittedSubclasses java/lang/classfile/ClassModel,java/lang/classfile/CodeModel,java/lang/classfile/FieldModel,java/lang/classfile/MethodModel,jdk/internal/classfile/impl/AbstractUnboundModel flags 601 signature <E::Ljava/lang/classfile/ClassFileElement;>Ljava/lang/Object;Ljava/lang/classfile/ClassFileElement;Ljava/lang/Iterable<TE;>; +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 -method name forEachElement descriptor (Ljava/util/function/Consumer;)V -method name elements descriptor ()Ljava/lang/Iterable; method name forEach descriptor (Ljava/util/function/Consumer;)V flags 401 signature (Ljava/util/function/Consumer<-TE;>;)V +method name toDebugString descriptor ()Ljava/lang/String; flags 1 class name java/lang/classfile/CustomAttribute header extends java/lang/Object implements java/lang/classfile/Attribute,java/lang/classfile/CodeElement,java/lang/classfile/ClassElement,java/lang/classfile/MethodElement,java/lang/classfile/FieldElement flags 421 signature <T:Ljava/lang/classfile/CustomAttribute<TT;>;>Ljava/lang/Object;Ljava/lang/classfile/Attribute<TT;>;Ljava/lang/classfile/CodeElement;Ljava/lang/classfile/ClassElement;Ljava/lang/classfile/MethodElement;Ljava/lang/classfile/FieldElement; diff --git a/src/jdk.compiler/share/data/symbols/java.se-O.sym.txt b/src/jdk.compiler/share/data/symbols/java.se-O.sym.txt index 65b19c089fe..e6caf5dac14 100644 --- a/src/jdk.compiler/share/data/symbols/java.se-O.sym.txt +++ b/src/jdk.compiler/share/data/symbols/java.se-O.sym.txt @@ -27,5 +27,5 @@ # ########################################################## # module name java.se -header requires name\u0020;java.base\u0020;flags\u0020;20,name\u0020;java.compiler\u0020;flags\u0020;20,name\u0020;java.datatransfer\u0020;flags\u0020;20,name\u0020;java.desktop\u0020;flags\u0020;20,name\u0020;java.instrument\u0020;flags\u0020;20,name\u0020;java.logging\u0020;flags\u0020;20,name\u0020;java.management\u0020;flags\u0020;20,name\u0020;java.management.rmi\u0020;flags\u0020;20,name\u0020;java.naming\u0020;flags\u0020;20,name\u0020;java.net.http\u0020;flags\u0020;20,name\u0020;java.prefs\u0020;flags\u0020;20,name\u0020;java.rmi\u0020;flags\u0020;20,name\u0020;java.scripting\u0020;flags\u0020;20,name\u0020;java.security.jgss\u0020;flags\u0020;20,name\u0020;java.security.sasl\u0020;flags\u0020;20,name\u0020;java.sql\u0020;flags\u0020;20,name\u0020;java.sql.rowset\u0020;flags\u0020;20,name\u0020;java.transaction.xa\u0020;flags\u0020;20,name\u0020;java.xml\u0020;flags\u0020;20,name\u0020;java.xml.crypto\u0020;flags\u0020;20 target macos-aarch64 flags 8000 classAnnotations @Ljdk/internal/javac/ParticipatesInPreview; +header requires name\u0020;java.base\u0020;flags\u0020;20,name\u0020;java.compiler\u0020;flags\u0020;20,name\u0020;java.datatransfer\u0020;flags\u0020;20,name\u0020;java.desktop\u0020;flags\u0020;20,name\u0020;java.instrument\u0020;flags\u0020;20,name\u0020;java.logging\u0020;flags\u0020;20,name\u0020;java.management\u0020;flags\u0020;20,name\u0020;java.management.rmi\u0020;flags\u0020;20,name\u0020;java.naming\u0020;flags\u0020;20,name\u0020;java.net.http\u0020;flags\u0020;20,name\u0020;java.prefs\u0020;flags\u0020;20,name\u0020;java.rmi\u0020;flags\u0020;20,name\u0020;java.scripting\u0020;flags\u0020;20,name\u0020;java.security.jgss\u0020;flags\u0020;20,name\u0020;java.security.sasl\u0020;flags\u0020;20,name\u0020;java.sql\u0020;flags\u0020;20,name\u0020;java.sql.rowset\u0020;flags\u0020;20,name\u0020;java.transaction.xa\u0020;flags\u0020;20,name\u0020;java.xml\u0020;flags\u0020;20,name\u0020;java.xml.crypto\u0020;flags\u0020;20 target macos-aarch64 flags 8000 From 4fc445d12b4dabd5ce3a6deb23ca6e4fea323620 Mon Sep 17 00:00:00 2001 From: Phil Race <prr@openjdk.org> Date: Wed, 25 Dec 2024 00:40:18 +0000 Subject: [PATCH 27/36] 8346829: Problem list com/sun/jdi/ReattachStressTest.java & ProcessAttachTest.java on Linux Reviewed-by: lmesnik --- test/jdk/ProblemList.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 0d737d3f727..e9d7c769523 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -727,6 +727,8 @@ javax/swing/plaf/synth/7158712/bug7158712.java 8324782 macosx-all # jdk_jdi +com/sun/jdi/ProcessAttachTest.java 8346827 linux-all +com/sun/jdi/ReattachStressTest.java 8346827 linux-all com/sun/jdi/RepStep.java 8043571 generic-all com/sun/jdi/InvokeHangTest.java 8218463 linux-all From 6c59185475eeca83153f085eba27cc0b3acf9bb4 Mon Sep 17 00:00:00 2001 From: SendaoYan <syan@openjdk.org> Date: Wed, 25 Dec 2024 01:27:35 +0000 Subject: [PATCH 28/36] 8345757: [ASAN] clang17 report 'dprintf' macro redefined Reviewed-by: kbarrett, valeriep --- .../share/native/libj2pcsc/pcsc.c | 38 ++++++++----------- .../share/native/libj2pkcs11/j2secmod.c | 26 ++++++------- .../share/native/libj2pkcs11/j2secmod.h | 12 ++---- .../unix/native/libj2pkcs11/j2secmod_md.c | 8 ++-- .../windows/native/libj2pkcs11/j2secmod_md.c | 8 ++-- 5 files changed, 40 insertions(+), 52 deletions(-) diff --git a/src/java.smartcardio/share/native/libj2pcsc/pcsc.c b/src/java.smartcardio/share/native/libj2pcsc/pcsc.c index 733c28a159a..4d2cfc5f86c 100644 --- a/src/java.smartcardio/share/native/libj2pcsc/pcsc.c +++ b/src/java.smartcardio/share/native/libj2pcsc/pcsc.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,15 +40,9 @@ // #define J2PCSC_DEBUG #ifdef J2PCSC_DEBUG -#define dprintf(s) printf(s) -#define dprintf1(s, p1) printf(s, p1) -#define dprintf2(s, p1, p2) printf(s, p1, p2) -#define dprintf3(s, p1, p2, p3) printf(s, p1, p2, p3) +#define debug_printf(format, ...) printf(format, ##__VA_ARGS__) #else -#define dprintf(s) -#define dprintf1(s, p1) -#define dprintf2(s, p1, p2) -#define dprintf3(s, p1, p2, p3) +#define debug_printf(format, ...) #endif #include "sun_security_smartcardio_PCSC.h" @@ -112,7 +106,7 @@ JNIEXPORT jlong JNICALL Java_sun_security_smartcardio_PCSC_SCardEstablishContext { SCARDCONTEXT context = 0; LONG rv; - dprintf("-establishContext\n"); + debug_printf("-establishContext\n"); rv = CALL_SCardEstablishContext(dwScope, NULL, NULL, &context); if (handleRV(env, rv)) { return 0; @@ -185,12 +179,12 @@ JNIEXPORT jobjectArray JNICALL Java_sun_security_smartcardio_PCSC_SCardListReade DWORD size = 0; jobjectArray result; - dprintf1("-context: %x\n", context); + debug_printf("-context: %x\n", context); rv = CALL_SCardListReaders(context, NULL, NULL, &size); if (handleRV(env, rv)) { return NULL; } - dprintf1("-size: %d\n", size); + debug_printf("-size: %d\n", size); if (size != 0) { mszReaders = malloc(size); @@ -204,7 +198,7 @@ JNIEXPORT jobjectArray JNICALL Java_sun_security_smartcardio_PCSC_SCardListReade free(mszReaders); return NULL; } - dprintf1("-String: %s\n", mszReaders); + debug_printf("-String: %s\n", mszReaders); } else { return NULL; } @@ -230,8 +224,8 @@ JNIEXPORT jlong JNICALL Java_sun_security_smartcardio_PCSC_SCardConnect } rv = CALL_SCardConnect(context, readerName, jShareMode, jPreferredProtocols, &card, &proto); (*env)->ReleaseStringUTFChars(env, jReaderName, readerName); - dprintf1("-cardhandle: %x\n", card); - dprintf1("-protocol: %d\n", proto); + debug_printf("-cardhandle: %x\n", card); + debug_printf("-protocol: %d\n", proto); if (handleRV(env, rv)) { return 0; } @@ -295,9 +289,9 @@ JNIEXPORT jbyteArray JNICALL Java_sun_security_smartcardio_PCSC_SCardStatus if (handleRV(env, rv)) { return NULL; } - dprintf1("-reader: %s\n", readerName); - dprintf1("-status: %d\n", state); - dprintf1("-protocol: %d\n", protocol); + debug_printf("-reader: %s\n", readerName); + debug_printf("-status: %d\n", state); + debug_printf("-protocol: %d\n", protocol); jArray = (*env)->NewByteArray(env, atrLen); if (jArray == NULL) { @@ -323,7 +317,7 @@ JNIEXPORT void JNICALL Java_sun_security_smartcardio_PCSC_SCardDisconnect LONG rv; rv = CALL_SCardDisconnect(card, jDisposition); - dprintf1("-disconnect: 0x%X\n", rv); + debug_printf("-disconnect: 0x%X\n", rv); handleRV(env, rv); return; } @@ -392,7 +386,7 @@ JNIEXPORT jintArray JNICALL Java_sun_security_smartcardio_PCSC_SCardGetStatusCha } for (i = 0; i < readers; i++) { jint eventStateTmp; - dprintf3("-reader status %s: 0x%X, 0x%X\n", readerState[i].szReader, + debug_printf("-reader status %s: 0x%X, 0x%X\n", readerState[i].szReader, readerState[i].dwCurrentState, readerState[i].dwEventState); eventStateTmp = (jint)readerState[i].dwEventState; (*env)->SetIntArrayRegion(env, jEventState, i, 1, &eventStateTmp); @@ -417,7 +411,7 @@ JNIEXPORT void JNICALL Java_sun_security_smartcardio_PCSC_SCardBeginTransaction LONG rv; rv = CALL_SCardBeginTransaction(card); - dprintf1("-beginTransaction: 0x%X\n", rv); + debug_printf("-beginTransaction: 0x%X\n", rv); handleRV(env, rv); return; } @@ -429,7 +423,7 @@ JNIEXPORT void JNICALL Java_sun_security_smartcardio_PCSC_SCardEndTransaction LONG rv; rv = CALL_SCardEndTransaction(card, jDisposition); - dprintf1("-endTransaction: 0x%X\n", rv); + debug_printf("-endTransaction: 0x%X\n", rv); handleRV(env, rv); return; } diff --git a/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/j2secmod.c b/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/j2secmod.c index fe87c924f28..92a83a3276c 100644 --- a/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/j2secmod.c +++ b/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/j2secmod.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,7 +52,7 @@ JNIEXPORT jboolean JNICALL Java_sun_security_pkcs11_Secmod_nssVersionCheck } res = versionCheck(requiredVersion); - dprintf2("-version >=%s: %d\n", requiredVersion, res); + debug_printf("-version >=%s: %d\n", requiredVersion, res); (*env)->ReleaseStringUTFChars(env, jVersion, requiredVersion); return (res == 0) ? JNI_FALSE : JNI_TRUE; @@ -146,11 +146,11 @@ JNIEXPORT jboolean JNICALL Java_sun_security_pkcs11_Secmod_nssInitialize if (configDir != NULL) { (*env)->ReleaseStringUTFChars(env, jConfigDir, configDir); } - dprintf1("-res: %d\n", res); + debug_printf("-res: %d\n", res); #ifdef SECMOD_DEBUG if (res == -1) { if (getError != NULL) { - dprintf1("-NSS error: %d\n", getError()); + debug_printf("-NSS error: %d\n", getError()); } } #endif // SECMOD_DEBUG @@ -173,12 +173,12 @@ JNIEXPORT jobject JNICALL Java_sun_security_pkcs11_Secmod_nssGetModuleList jint i, jSlotID; if (getModuleList == NULL) { - dprintf("-getmodulelist function not found\n"); + debug_printf("-getmodulelist function not found\n"); return NULL; } list = getModuleList(); if (list == NULL) { - dprintf("-module list is null\n"); + debug_printf("-module list is null\n"); return NULL; } @@ -211,12 +211,12 @@ JNIEXPORT jobject JNICALL Java_sun_security_pkcs11_Secmod_nssGetModuleList while (list != NULL) { module = list->module; // assert module != null - dprintf1("-commonname: %s\n", module->commonName); - dprintf1("-dllname: %s\n", (module->dllName != NULL) ? module->dllName : "NULL"); - dprintf1("-slots: %d\n", module->slotCount); - dprintf1("-loaded: %d\n", module->loaded); - dprintf1("-internal: %d\n", module->internal); - dprintf1("-fips: %d\n", module->isFIPS); + debug_printf("-commonname: %s\n", module->commonName); + debug_printf("-dllname: %s\n", (module->dllName != NULL) ? module->dllName : "NULL"); + debug_printf("-slots: %d\n", module->slotCount); + debug_printf("-loaded: %d\n", module->loaded); + debug_printf("-internal: %d\n", module->internal); + debug_printf("-fips: %d\n", module->isFIPS); jCommonName = (*env)->NewStringUTF(env, module->commonName); if (jCommonName == NULL) { return NULL; @@ -248,7 +248,7 @@ JNIEXPORT jobject JNICALL Java_sun_security_pkcs11_Secmod_nssGetModuleList } list = list->next; } - dprintf("-ok\n"); + debug_printf("-ok\n"); return jList; } diff --git a/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/j2secmod.h b/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/j2secmod.h index 4cdb7ba37ee..71d2008d0cd 100644 --- a/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/j2secmod.h +++ b/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/j2secmod.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,15 +37,9 @@ void *p11FindFunction(JNIEnv *env, jlong jHandle, const char *functionName); #ifdef SECMOD_DEBUG -#define dprintf(s) printf(s) -#define dprintf1(s, p1) printf(s, p1) -#define dprintf2(s, p1, p2) printf(s, p1, p2) -#define dprintf3(s, p1, p2, p3) printf(s, p1, p2, p3) +#define debug_printf(format, ...) printf(format, ##__VA_ARGS__) #else -#define dprintf(s) -#define dprintf1(s, p1) -#define dprintf2(s, p1, p2) -#define dprintf3(s, p1, p2, p3) +#define debug_printf(format, ...) #endif // NSS types diff --git a/src/jdk.crypto.cryptoki/unix/native/libj2pkcs11/j2secmod_md.c b/src/jdk.crypto.cryptoki/unix/native/libj2pkcs11/j2secmod_md.c index 46cef13fd2d..b1d2d5ee4e8 100644 --- a/src/jdk.crypto.cryptoki/unix/native/libj2pkcs11/j2secmod_md.c +++ b/src/jdk.crypto.cryptoki/unix/native/libj2pkcs11/j2secmod_md.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -61,7 +61,7 @@ JNIEXPORT jlong JNICALL Java_sun_security_pkcs11_Secmod_nssGetLibraryHandle #else hModule = dlopen(libName, RTLD_NOLOAD); #endif - dprintf2("-handle for %s: %u\n", libName, hModule); + debug_printf("-handle for %s: %u\n", libName, hModule); (*env)->ReleaseStringUTFChars(env, jLibName, libName); return ptr_to_jlong(hModule); } @@ -75,10 +75,10 @@ JNIEXPORT jlong JNICALL Java_sun_security_pkcs11_Secmod_nssLoadLibrary return 0L; } - dprintf1("-lib %s\n", libName); + debug_printf("-lib %s\n", libName); hModule = dlopen(libName, RTLD_LAZY); (*env)->ReleaseStringUTFChars(env, jLibName, libName); - dprintf2("-handle: %u (0X%X)\n", hModule, hModule); + debug_printf("-handle: %u (0X%X)\n", hModule, hModule); if (hModule == NULL) { p11ThrowIOException(env, dlerror()); diff --git a/src/jdk.crypto.cryptoki/windows/native/libj2pkcs11/j2secmod_md.c b/src/jdk.crypto.cryptoki/windows/native/libj2pkcs11/j2secmod_md.c index a5cd5e63d02..5009b8a280f 100644 --- a/src/jdk.crypto.cryptoki/windows/native/libj2pkcs11/j2secmod_md.c +++ b/src/jdk.crypto.cryptoki/windows/native/libj2pkcs11/j2secmod_md.c @@ -51,7 +51,7 @@ JNIEXPORT jlong JNICALL Java_sun_security_pkcs11_Secmod_nssGetLibraryHandle { const char *libName = (*env)->GetStringUTFChars(env, jLibName, NULL); HMODULE hModule = GetModuleHandle(libName); - dprintf2("-handle for %s: %d\n", libName, hModule); + debug_printf("-handle for %s: %d\n", libName, hModule); (*env)->ReleaseStringUTFChars(env, jLibName, libName); return (jlong)hModule; } @@ -63,7 +63,7 @@ JNIEXPORT jlong JNICALL Java_sun_security_pkcs11_Secmod_nssLoadLibrary LPVOID lpMsgBuf; const char *libName = (*env)->GetStringUTFChars(env, jName, NULL); - dprintf1("-lib %s\n", libName); + debug_printf("-lib %s\n", libName); hModule = LoadLibrary(libName); (*env)->ReleaseStringUTFChars(env, jName, libName); @@ -80,11 +80,11 @@ JNIEXPORT jlong JNICALL Java_sun_security_pkcs11_Secmod_nssLoadLibrary 0, NULL ); - dprintf1("-error: %s\n", lpMsgBuf); + debug_printf("-error: %s\n", lpMsgBuf); p11ThrowIOException(env, (char*)lpMsgBuf); LocalFree(lpMsgBuf); return 0; } - dprintf2("-handle: %d (0X%X)\n", hModule, hModule); + debug_printf("-handle: %d (0X%X)\n", hModule, hModule); return (jlong)hModule; } From 807f6f7fb868240cba5ba117c7059216f69a53f9 Mon Sep 17 00:00:00 2001 From: Amit Kumar <amitkumar@openjdk.org> Date: Fri, 27 Dec 2024 10:05:41 +0000 Subject: [PATCH 29/36] 8346847: [s390x] minimal build failure Reviewed-by: stuefe --- src/hotspot/cpu/s390/vm_version_s390.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/hotspot/cpu/s390/vm_version_s390.cpp b/src/hotspot/cpu/s390/vm_version_s390.cpp index a5195e753bb..f7f21c4c5ac 100644 --- a/src/hotspot/cpu/s390/vm_version_s390.cpp +++ b/src/hotspot/cpu/s390/vm_version_s390.cpp @@ -308,6 +308,12 @@ void VM_Version::initialize() { if (FLAG_IS_DEFAULT(UseMontgomerySquareIntrinsic)) { FLAG_SET_DEFAULT(UseMontgomerySquareIntrinsic, true); } + + // The OptoScheduling information is not maintained in s390.ad. + if (OptoScheduling) { + warning("OptoScheduling is not supported on this CPU."); + FLAG_SET_DEFAULT(OptoScheduling, false); + } #endif if (FLAG_IS_DEFAULT(UsePopCountInstruction)) { FLAG_SET_DEFAULT(UsePopCountInstruction, true); @@ -323,12 +329,6 @@ void VM_Version::initialize() { if (FLAG_IS_DEFAULT(UseUnalignedAccesses)) { FLAG_SET_DEFAULT(UseUnalignedAccesses, true); } - - // The OptoScheduling information is not maintained in s390.ad. - if (OptoScheduling) { - warning("OptoScheduling is not supported on this CPU."); - FLAG_SET_DEFAULT(OptoScheduling, false); - } } From 60e0730a3ba26180d0eb2cd278e389c3e70fec5f Mon Sep 17 00:00:00 2001 From: Matthias Baesken <mbaesken@openjdk.org> Date: Sat, 28 Dec 2024 15:45:26 +0000 Subject: [PATCH 30/36] 8346712: Remove com/sun/net/httpserver/TcpNoDelayNotRequired.java test Reviewed-by: djelinski, lucy, jpai --- .../net/httpserver/TcpNoDelayNotRequired.java | 145 ------------------ 1 file changed, 145 deletions(-) delete mode 100644 test/jdk/com/sun/net/httpserver/TcpNoDelayNotRequired.java diff --git a/test/jdk/com/sun/net/httpserver/TcpNoDelayNotRequired.java b/test/jdk/com/sun/net/httpserver/TcpNoDelayNotRequired.java deleted file mode 100644 index a66f25dd487..00000000000 --- a/test/jdk/com/sun/net/httpserver/TcpNoDelayNotRequired.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/** - * @test - * @bug 6968351 - * @summary tcp no delay not required for small payloads - * @requires vm.compMode != "Xcomp" - * @library /test/lib - * @run main/othervm/timeout=5 -Dsun.net.httpserver.nodelay=false TcpNoDelayNotRequired - */ - -import com.sun.net.httpserver.Headers; -import com.sun.net.httpserver.HttpContext; -import com.sun.net.httpserver.HttpExchange; -import com.sun.net.httpserver.HttpHandler; -import com.sun.net.httpserver.HttpServer; - -import com.sun.net.httpserver.HttpsConfigurator; -import com.sun.net.httpserver.HttpsServer; -import jdk.test.lib.net.SimpleSSLContext; -import jdk.test.lib.net.URIBuilder; - -import javax.net.ssl.SSLContext; -import java.io.IOException; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.http.HttpClient; -import java.net.http.HttpRequest; -import java.net.http.HttpResponse; -import java.nio.charset.StandardCharsets; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.util.logging.SimpleFormatter; -import java.util.logging.StreamHandler; - -public class TcpNoDelayNotRequired { - - public static final Logger LOGGER = Logger.getLogger("sun.net.www.protocol.http"); - - public static void main (String[] args) throws Exception { - - java.util.logging.Handler outHandler = new StreamHandler(System.out, - new SimpleFormatter()); - outHandler.setLevel(Level.FINEST); - LOGGER.setLevel(Level.FINEST); - LOGGER.addHandler(outHandler); - - InetAddress loopback = InetAddress.getLoopbackAddress(); - InetSocketAddress addr = new InetSocketAddress (loopback, 0); - - SSLContext sslContext = new SimpleSSLContext().get(); - - HttpServer httpServer = HttpServer.create (addr, 0); - testHttpServer("http",httpServer,sslContext); - - HttpsServer httpsServer = HttpsServer.create (addr, 0); - httpsServer.setHttpsConfigurator(new HttpsConfigurator(sslContext)); - - testHttpServer("https",httpsServer,sslContext); - } - - private static void testHttpServer(String scheme,HttpServer server,SSLContext sslContext) throws Exception { - HttpContext ctx = server.createContext ("/test", new Handler()); - HttpContext ctx2 = server.createContext ("/chunked", new ChunkedHandler()); - ExecutorService executor = Executors.newCachedThreadPool(); - server.setExecutor (executor); - server.start (); - try { - try (HttpClient client = HttpClient.newBuilder().sslContext(sslContext).build()) { - long start = System.currentTimeMillis(); - for (int i = 0; i < 1000; i++) { - var uri = URIBuilder.newBuilder().scheme(scheme).loopback().port(server.getAddress().getPort()).path("/test").build(); - var response = client.send(HttpRequest.newBuilder(uri).build(), HttpResponse.BodyHandlers.ofString()); - if (!response.body().equals("hello")) - throw new IllegalStateException("incorrect body " + response.body()); - } - for (int i = 0; i < 1000; i++) { - var uri = URIBuilder.newBuilder().scheme(scheme).loopback().port(server.getAddress().getPort()).path("/chunked").build(); - var response = client.send(HttpRequest.newBuilder(uri).build(), HttpResponse.BodyHandlers.ofString()); - if (!response.body().equals("hello")) - throw new IllegalStateException("incorrect body " + response.body()); - } - long time = System.currentTimeMillis() - start; - System.out.println("time " + time); - } - } finally { - server.stop(0); - } - executor.shutdown(); - } - - static class Handler implements HttpHandler { - public void handle (HttpExchange t) - throws IOException - { - Headers rmap = t.getResponseHeaders(); - try (var is = t.getRequestBody()) { - is.readAllBytes(); - } - rmap.add("content-type","text/plain"); - t.sendResponseHeaders(200,5); - try (var os = t.getResponseBody()) { - os.write("hello".getBytes(StandardCharsets.ISO_8859_1)); - } - } - } - static class ChunkedHandler implements HttpHandler { - public void handle (HttpExchange t) - throws IOException - { - Headers rmap = t.getResponseHeaders(); - try (var is = t.getRequestBody()) { - is.readAllBytes(); - } - rmap.add("content-type","text/plain"); - t.sendResponseHeaders(200,0); - try (var os = t.getResponseBody()) { - os.write("hello".getBytes(StandardCharsets.ISO_8859_1)); - } - } - } -} From b3e63631c735862ba00270636b4ef51c0e48a1af Mon Sep 17 00:00:00 2001 From: GennadiyKrivoshein <164895822+GennadiyKrivoshein@users.noreply.github.com> Date: Sat, 28 Dec 2024 20:48:57 +0000 Subject: [PATCH 31/36] 8343224: print/Dialog/PaperSizeError.java fails with MediaSizeName is not A4: A4 Reviewed-by: azvegint, alexsch, psadhukhan, achung --- .../classes/sun/print/CustomMediaSizeName.java | 17 +++++++++-------- .../java/awt/print/Dialog/PaperSizeError.java | 18 ++++++++++++------ 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/src/java.desktop/share/classes/sun/print/CustomMediaSizeName.java b/src/java.desktop/share/classes/sun/print/CustomMediaSizeName.java index b8d3ec723b8..04772f29858 100644 --- a/src/java.desktop/share/classes/sun/print/CustomMediaSizeName.java +++ b/src/java.desktop/share/classes/sun/print/CustomMediaSizeName.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -203,16 +203,17 @@ public static CustomMediaSizeName create(String name, String choice, if (value == null) { value = new CustomMediaSizeName(name, choice, width, length); customMap.put(key, value); - - // add this new custom media size name to MediaSize array - if ((width > 0.0) && (length > 0.0)) { - try { - new MediaSize(width, length, Size2DSyntax.INCH, value); - } catch (IllegalArgumentException e) { + if (value.getStandardMedia() == null) { + // add this new custom media size name to MediaSize array + if ((width > 0.0) && (length > 0.0)) { + try { + new MediaSize(width, length, Size2DSyntax.INCH, value); + } catch (IllegalArgumentException e) { /* PDF printer in Linux for Ledger paper causes "IllegalArgumentException: X dimension > Y dimension". We rotate based on IPP spec. */ - new MediaSize(length, width, Size2DSyntax.INCH, value); + new MediaSize(length, width, Size2DSyntax.INCH, value); + } } } } diff --git a/test/jdk/java/awt/print/Dialog/PaperSizeError.java b/test/jdk/java/awt/print/Dialog/PaperSizeError.java index fea7bb85af8..18f33704a06 100644 --- a/test/jdk/java/awt/print/Dialog/PaperSizeError.java +++ b/test/jdk/java/awt/print/Dialog/PaperSizeError.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,16 +23,22 @@ /** * @test - * @bug 6360339 + * @bug 6360339 8343224 * @key printer * @summary Test for fp error in paper size calculations. * @run main/manual PaperSizeError */ -import java.awt.print.*; -import javax.print.*; -import javax.print.attribute.*; -import javax.print.attribute.standard.*; +import javax.print.PrintService; +import javax.print.attribute.HashPrintRequestAttributeSet; +import javax.print.attribute.PrintRequestAttributeSet; +import javax.print.attribute.Size2DSyntax; +import javax.print.attribute.standard.MediaSize; +import javax.print.attribute.standard.MediaSizeName; +import javax.print.attribute.standard.OrientationRequested; +import java.awt.print.PageFormat; +import java.awt.print.Paper; +import java.awt.print.PrinterJob; public class PaperSizeError { From 79958470e08ade2d3584748e020bd2e18092c0cf Mon Sep 17 00:00:00 2001 From: Qizheng Xing <qxing@openjdk.org> Date: Sun, 29 Dec 2024 08:32:38 +0000 Subject: [PATCH 32/36] 8346831: Remove the extra closing parenthesis in CTW Makefile Reviewed-by: liach, kbarrett, lmesnik, jwaters --- test/hotspot/jtreg/testlibrary/ctw/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/testlibrary/ctw/Makefile b/test/hotspot/jtreg/testlibrary/ctw/Makefile index 4cf20b12e52..5c64c67d828 100644 --- a/test/hotspot/jtreg/testlibrary/ctw/Makefile +++ b/test/hotspot/jtreg/testlibrary/ctw/Makefile @@ -47,7 +47,7 @@ LIB_FILES = $(shell find $(TESTLIBRARY_DIR)/jdk/test/lib/ \ $(TESTLIBRARY_DIR)/jdk/test/lib/process \ $(TESTLIBRARY_DIR)/jdk/test/lib/util \ $(TESTLIBRARY_DIR)/jtreg \ - -maxdepth 1 -name '*.java')) + -maxdepth 1 -name '*.java') WB_SRC_FILES = $(shell find $(TESTLIBRARY_DIR)/jdk/test/lib/compiler $(TESTLIBRARY_DIR)/jdk/test/whitebox -name '*.java') WB_CLASS_FILES := $(subst $(TESTLIBRARY_DIR)/,,$(WB_SRC_FILES)) WB_CLASS_FILES := $(patsubst %.java,%.class,$(WB_CLASS_FILES)) From bd0fde71d9113bad902e71b61f0ca44c650809ef Mon Sep 17 00:00:00 2001 From: Jaikiran Pai <jpai@openjdk.org> Date: Sun, 29 Dec 2024 08:37:25 +0000 Subject: [PATCH 33/36] 8302293: jar --create fails with IllegalArgumentException if archive name is shorter than 3 characters Reviewed-by: lancea --- .../share/classes/sun/tools/jar/Main.java | 13 ++-- test/jdk/tools/jar/JarCreateFileNameTest.java | 70 +++++++++++++++++++ 2 files changed, 78 insertions(+), 5 deletions(-) create mode 100644 test/jdk/tools/jar/JarCreateFileNameTest.java diff --git a/src/jdk.jartool/share/classes/sun/tools/jar/Main.java b/src/jdk.jartool/share/classes/sun/tools/jar/Main.java index 02afd5fdbcb..ae6893c021b 100644 --- a/src/jdk.jartool/share/classes/sun/tools/jar/Main.java +++ b/src/jdk.jartool/share/classes/sun/tools/jar/Main.java @@ -315,11 +315,13 @@ public synchronized boolean run(String[] args) { // error("Warning: -v option ignored"); vflag = false; } - final String tmpbase = (fname == null) + String tmpFilePrefix = (fname == null) ? "tmpjar" : fname.substring(fname.indexOf(File.separatorChar) + 1); - - tmpFile = createTemporaryFile(tmpbase, ".jar"); + if (tmpFilePrefix.length() < 3) { + tmpFilePrefix = "tmpjar" + tmpFilePrefix; + } + tmpFile = createTemporaryFile(tmpFilePrefix, ".jar"); try (OutputStream out = new FileOutputStream(tmpFile)) { create(new BufferedOutputStream(out, 4096), manifest); } @@ -1775,11 +1777,12 @@ private File createTemporaryFile(String tmpbase, String suffix) { // Unable to create file due to permission violation or security exception } if (tmpfile == null) { - // Were unable to create temporary file, fall back to temporary file in the same folder + // We were unable to create temporary file, fall back to temporary file in the + // same folder as the JAR file if (fname != null) { try { File tmpfolder = new File(fname).getAbsoluteFile().getParentFile(); - tmpfile = File.createTempFile(fname, ".tmp" + suffix, tmpfolder); + tmpfile = File.createTempFile(tmpbase, ".tmp" + suffix, tmpfolder); } catch (IOException ioe) { // Last option failed - fall gracefully fatalError(ioe); diff --git a/test/jdk/tools/jar/JarCreateFileNameTest.java b/test/jdk/tools/jar/JarCreateFileNameTest.java new file mode 100644 index 00000000000..fb2b6a2e732 --- /dev/null +++ b/test/jdk/tools/jar/JarCreateFileNameTest.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.jar.JarFile; +import java.util.spi.ToolProvider; +import java.util.zip.ZipEntry; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +/* + * @test + * @bug 8302293 + * @summary verify that a JAR file creation through "jar --create" operation + * works fine if the JAR file name is less than 3 characters in length + * @run junit JarCreateFileNameTest + */ +public class JarCreateFileNameTest { + + private static final ToolProvider JAR_TOOL = ToolProvider.findFirst("jar") + .orElseThrow(() -> + new RuntimeException("jar tool not found") + ); + + /* + * Launches "jar --create --file" with file names of varying lengths and verifies + * that the JAR file was successfully created. + */ + @ParameterizedTest + @ValueSource(strings = {"abcd", "abc", "ab", "a", "d.jar", "ef.jar"}) + void testCreate(final String targetJarFileName) throws Exception { + final Path cwd = Path.of("."); + final Path tmpFile = Files.createTempFile(cwd, "8302293", ".txt"); + final String fileName = tmpFile.getFileName().toString(); + final int exitCode = JAR_TOOL.run(System.out, System.err, + "--create", "--file", targetJarFileName, fileName); + assertEquals(0, exitCode, "jar command failed"); + // verify the JAR file is created and contains the expected entry + try (final JarFile jarFile = new JarFile(new File(targetJarFileName))) { + final ZipEntry entry = jarFile.getEntry(fileName); + assertNotNull(entry, "missing " + fileName + " entry in JAR file " + targetJarFileName); + } + } +} + From 24c5ff7ba58cb7cf93df07f81484cd8fae60e31e Mon Sep 17 00:00:00 2001 From: Jaikiran Pai <jpai@openjdk.org> Date: Mon, 30 Dec 2024 00:53:15 +0000 Subject: [PATCH 34/36] 8346871: Improve robustness of java/util/zip/EntryCount64k.java test Reviewed-by: lancea --- test/jdk/java/util/zip/EntryCount64k.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/test/jdk/java/util/zip/EntryCount64k.java b/test/jdk/java/util/zip/EntryCount64k.java index d8c46d22364..8830a87ea64 100644 --- a/test/jdk/java/util/zip/EntryCount64k.java +++ b/test/jdk/java/util/zip/EntryCount64k.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2013 Google Inc. All rights reserved. + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,9 +48,12 @@ import jdk.test.lib.process.ProcessTools; public class EntryCount64k { + + private static final String MAIN_CLASS_MSG = "foo bar hello world Main"; + public static class Main { public static void main(String[] args) { - System.out.print("Main"); + System.out.println(MAIN_CLASS_MSG); } } @@ -162,7 +166,10 @@ static void checkCanRead(File zipFile, int entryCount) throws Throwable { // Check java -jar OutputAnalyzer a = ProcessTools.executeTestJava("-jar", zipFile.getName()); a.shouldHaveExitValue(0); - a.stdoutShouldMatch("\\AMain\\Z"); + // expect the message from the application on stdout + a.stdoutContains(MAIN_CLASS_MSG); + // nothing is expected on stderr (apart from any probable deprecation + // warnings from the launcher/JVM) a.stderrShouldMatchIgnoreDeprecatedWarnings("\\A\\Z"); } } From d3abf01c3e8236d37ec369429e17f35afeb7ab88 Mon Sep 17 00:00:00 2001 From: Volker Simonis <simonis@openjdk.org> Date: Wed, 1 Jan 2025 17:20:27 +0000 Subject: [PATCH 35/36] 8346101: [JVMCI] Export jdk.internal.misc to jdk.graal.compiler Reviewed-by: dnsimon, phh --- src/java.base/share/classes/module-info.java | 3 ++- src/jdk.graal.compiler/share/classes/module-info.java | 4 ++-- test/jdk/jdk/modules/etc/JdkQualifiedExportTest.java | 5 +++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/java.base/share/classes/module-info.java b/src/java.base/share/classes/module-info.java index 614842e064c..2904f665732 100644 --- a/src/java.base/share/classes/module-info.java +++ b/src/java.base/share/classes/module-info.java @@ -226,7 +226,8 @@ jdk.jshell, jdk.nio.mapmode, jdk.unsupported, - jdk.internal.vm.ci; + jdk.internal.vm.ci, + jdk.graal.compiler; exports jdk.internal.module to java.instrument, java.management.rmi, diff --git a/src/jdk.graal.compiler/share/classes/module-info.java b/src/jdk.graal.compiler/share/classes/module-info.java index bc8987ee919..f2bc1ae9842 100644 --- a/src/jdk.graal.compiler/share/classes/module-info.java +++ b/src/jdk.graal.compiler/share/classes/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,7 @@ * external implementation of a JVMCI compiler. It must be upgradeable so * that it can be replaced when jlinking a new JDK image without failing * the hash check for the qualified exports in jdk.internal.vm.ci's - * module descriptor. + * and java.base's module descriptors. * * @moduleGraph * @since 22 diff --git a/test/jdk/jdk/modules/etc/JdkQualifiedExportTest.java b/test/jdk/jdk/modules/etc/JdkQualifiedExportTest.java index 4718e10e862..551e3792fc2 100644 --- a/test/jdk/jdk/modules/etc/JdkQualifiedExportTest.java +++ b/test/jdk/jdk/modules/etc/JdkQualifiedExportTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2019, 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 @@ -74,7 +74,8 @@ static void check(ModuleDescriptor md) { "jdk.internal.vm.ci/jdk.vm.ci.hotspot", "jdk.internal.vm.ci/jdk.vm.ci.meta", "jdk.internal.vm.ci/jdk.vm.ci.code", - "java.base/jdk.internal.javac"); + "java.base/jdk.internal.javac", + "java.base/jdk.internal.misc"); static void checkExports(ModuleDescriptor md) { // build a map of upgradeable module to Exports that are qualified to it From a87bc7e4f0e797a108f447a1c9801abe39b700da Mon Sep 17 00:00:00 2001 From: Kim Barrett <kbarrett@openjdk.org> Date: Thu, 2 Jan 2025 08:11:55 +0000 Subject: [PATCH 36/36] 8345374: Ubsan: runtime error: division by zero Reviewed-by: jwaters, ayang, amitkumar --- src/hotspot/share/gc/g1/g1HeapSizingPolicy.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/hotspot/share/gc/g1/g1HeapSizingPolicy.cpp b/src/hotspot/share/gc/g1/g1HeapSizingPolicy.cpp index 0b7db7836d6..e8642e59cb4 100644 --- a/src/hotspot/share/gc/g1/g1HeapSizingPolicy.cpp +++ b/src/hotspot/share/gc/g1/g1HeapSizingPolicy.cpp @@ -198,6 +198,14 @@ size_t G1HeapSizingPolicy::young_collection_expansion_amount() { } static size_t target_heap_capacity(size_t used_bytes, uintx free_ratio) { + assert(free_ratio <= 100, "precondition"); + if (free_ratio == 100) { + // If 100 then below calculations will divide by zero and return min of + // resulting infinity and MaxHeapSize. Avoid issues of UB vs is_iec559 + // and ubsan warnings, and just immediately return MaxHeapSize. + return MaxHeapSize; + } + const double desired_free_percentage = (double) free_ratio / 100.0; const double desired_used_percentage = 1.0 - desired_free_percentage;